Annotation of XML/nanohttp.c, revision 1.25

1.1       daniel      1: /*
1.5       daniel      2:  * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets.
                      3:  *             focuses on size, streamability, reentrancy and portability
                      4:  *
                      5:  * This is clearly not a general purpose HTTP implementation
                      6:  * If you look for one, check:
                      7:  *         http://www.w3.org/Library/
1.1       daniel      8:  *
                      9:  * See Copyright for the status of this software.
                     10:  *
                     11:  * Daniel.Veillard@w3.org
                     12:  */
                     13:  
1.5       daniel     14: /* TODO add compression support, Send the Accept- , and decompress on the
                     15:         fly with ZLIB if found at compile-time */
                     16: 
1.9       daniel     17: #ifdef WIN32
1.11      daniel     18: #define INCLUDE_WINSOCK
1.9       daniel     19: #include "win32config.h"
                     20: #else
1.4       daniel     21: #include "config.h"
                     22: #endif
1.9       daniel     23: 
1.25    ! veillard   24: #include <libxml/xmlversion.h>
1.4       daniel     25: 
1.17      daniel     26: #ifdef LIBXML_HTTP_ENABLED
1.1       daniel     27: #include <stdio.h>
                     28: #include <string.h>
1.4       daniel     29: 
                     30: #ifdef HAVE_STDLIB_H
1.1       daniel     31: #include <stdlib.h>
1.4       daniel     32: #endif
                     33: #ifdef HAVE_UNISTD_H
1.1       daniel     34: #include <unistd.h>
1.4       daniel     35: #endif
                     36: #ifdef HAVE_SYS_SOCKET_H
1.1       daniel     37: #include <sys/socket.h>
1.4       daniel     38: #endif
                     39: #ifdef HAVE_NETINET_IN_H
1.1       daniel     40: #include <netinet/in.h>
1.4       daniel     41: #endif
                     42: #ifdef HAVE_ARPA_INET_H
1.1       daniel     43: #include <arpa/inet.h>
1.4       daniel     44: #endif
                     45: #ifdef HAVE_NETDB_H
1.1       daniel     46: #include <netdb.h>
1.4       daniel     47: #endif
                     48: #ifdef HAVE_FCNTL_H
1.1       daniel     49: #include <fcntl.h> 
1.4       daniel     50: #endif
                     51: #ifdef HAVE_ERRNO_H
1.1       daniel     52: #include <errno.h>
1.4       daniel     53: #endif
                     54: #ifdef HAVE_SYS_TIME_H
1.1       daniel     55: #include <sys/time.h>
1.4       daniel     56: #endif
                     57: #ifdef HAVE_SYS_SELECT_H
1.1       daniel     58: #include <sys/select.h>
1.4       daniel     59: #endif
1.15      daniel     60: #ifdef HAVE_STRINGS_H
                     61: #include <strings.h>
                     62: #endif
1.1       daniel     63: 
1.17      daniel     64: #include <libxml/xmlmemory.h>
1.23      veillard   65: #include <libxml/parser.h> /* for xmlStr(n)casecmp() */
1.17      daniel     66: #include <libxml/nanohttp.h>
1.7       daniel     67: 
1.5       daniel     68: #ifdef STANDALONE
                     69: #define DEBUG_HTTP
1.23      veillard   70: #define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
                     71: #define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
1.5       daniel     72: #endif
                     73: 
1.1       daniel     74: #define XML_NANO_HTTP_MAX_REDIR        10
                     75: 
                     76: #define XML_NANO_HTTP_CHUNK    4096
                     77: 
                     78: #define XML_NANO_HTTP_CLOSED   0
                     79: #define XML_NANO_HTTP_WRITE    1
                     80: #define XML_NANO_HTTP_READ     2
                     81: #define XML_NANO_HTTP_NONE     4
                     82: 
                     83: typedef struct xmlNanoHTTPCtxt {
                     84:     char *protocol;    /* the protocol name */
                     85:     char *hostname;    /* the host name */
                     86:     int port;          /* the port */
                     87:     char *path;                /* the path within the URL */
                     88:     int fd;            /* the file descriptor for the socket */
                     89:     int state;         /* WRITE / READ / CLOSED */
                     90:     char *out;         /* buffer sent (zero terminated) */
                     91:     char *outptr;      /* index within the buffer sent */
                     92:     char *in;          /* the receiving buffer */
                     93:     char *content;     /* the start of the content */
                     94:     char *inptr;       /* the next byte to read from network */
                     95:     char *inrptr;      /* the next byte to give back to the client */
                     96:     int inlen;         /* len of the input buffer */
                     97:     int last;          /* return code for last operation */
                     98:     int returnValue;   /* the protocol return value */
                     99:     char *contentType; /* the MIME type for the input */
                    100:     char *location;    /* the new URL in case of redirect */
                    101: } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
                    102: 
1.12      daniel    103: static int initialized = 0;
                    104: static char *proxy = NULL;     /* the proxy name if any */
                    105: static int proxyPort;  /* the proxy port if any */
                    106: 
                    107: /**
                    108:  * xmlNanoHTTPInit:
                    109:  *
                    110:  * Initialize the HTTP protocol layer.
                    111:  * Currently it just checks for proxy informations
                    112:  */
                    113: 
                    114: void
                    115: xmlNanoHTTPInit(void) {
                    116:     const char *env;
                    117: 
                    118:     if (initialized)
                    119:        return;
                    120: 
1.13      daniel    121:     if (proxy == NULL) {
                    122:        proxyPort = 80;
                    123:        env = getenv("no_proxy");
                    124:        if (env != NULL)
                    125:            goto done;
                    126:        env = getenv("http_proxy");
                    127:        if (env != NULL) {
                    128:            xmlNanoHTTPScanProxy(env);
                    129:            goto done;
                    130:        }
                    131:        env = getenv("HTTP_PROXY");
                    132:        if (env != NULL) {
                    133:            xmlNanoHTTPScanProxy(env);
                    134:            goto done;
                    135:        }
1.12      daniel    136:     }
1.13      daniel    137: done:
1.12      daniel    138:     initialized = 1;
                    139: }
                    140: 
                    141: /**
                    142:  * xmlNanoHTTPClenup:
                    143:  *
                    144:  * Cleanup the HTTP protocol layer.
                    145:  */
                    146: 
                    147: void
                    148: xmlNanoHTTPCleanup(void) {
                    149:     if (proxy != NULL)
                    150:        xmlFree(proxy);
                    151:     initialized = 0;
                    152:     return;
                    153: }
                    154: 
1.5       daniel    155: /**
                    156:  * xmlNanoHTTPScanURL:
                    157:  * @ctxt:  an HTTP context
                    158:  * @URL:  The URL used to initialize the context
                    159:  *
                    160:  * (Re)Initialize an HTTP context by parsing the URL and finding
                    161:  * the protocol host port and path it indicates.
                    162:  */
                    163: 
                    164: static void
                    165: xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
1.1       daniel    166:     const char *cur = URL;
                    167:     char buf[4096];
                    168:     int index = 0;
                    169:     int port = 0;
                    170: 
                    171:     if (ctxt->protocol != NULL) { 
1.7       daniel    172:         xmlFree(ctxt->protocol);
1.1       daniel    173:        ctxt->protocol = NULL;
                    174:     }
                    175:     if (ctxt->hostname != NULL) { 
1.7       daniel    176:         xmlFree(ctxt->hostname);
1.1       daniel    177:        ctxt->hostname = NULL;
                    178:     }
                    179:     if (ctxt->path != NULL) { 
1.7       daniel    180:         xmlFree(ctxt->path);
1.1       daniel    181:        ctxt->path = NULL;
                    182:     }
1.12      daniel    183:     if (URL == NULL) return;
1.1       daniel    184:     buf[index] = 0;
                    185:     while (*cur != 0) {
                    186:         if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
                    187:            buf[index] = 0;
1.7       daniel    188:            ctxt->protocol = xmlMemStrdup(buf);
1.1       daniel    189:            index = 0;
                    190:             cur += 3;
                    191:            break;
                    192:        }
                    193:        buf[index++] = *cur++;
                    194:     }
                    195:     if (*cur == 0) return;
                    196: 
                    197:     buf[index] = 0;
                    198:     while (1) {
                    199:         if (cur[0] == ':') {
                    200:            buf[index] = 0;
1.7       daniel    201:            ctxt->hostname = xmlMemStrdup(buf);
1.1       daniel    202:            index = 0;
                    203:            cur += 1;
                    204:            while ((*cur >= '0') && (*cur <= '9')) {
                    205:                port *= 10;
                    206:                port += *cur - '0';
                    207:                cur++;
                    208:            }
                    209:            if (port != 0) ctxt->port = port;
                    210:            while ((cur[0] != '/') && (*cur != 0)) 
                    211:                cur++;
                    212:            break;
                    213:        }
                    214:         if ((*cur == '/') || (*cur == 0)) {
                    215:            buf[index] = 0;
1.7       daniel    216:            ctxt->hostname = xmlMemStrdup(buf);
1.1       daniel    217:            index = 0;
                    218:            break;
                    219:        }
                    220:        buf[index++] = *cur++;
                    221:     }
                    222:     if (*cur == 0) 
1.7       daniel    223:         ctxt->path = xmlMemStrdup("/");
1.5       daniel    224:     else {
1.14      daniel    225:         index = 0;
1.5       daniel    226:         buf[index] = 0;
1.14      daniel    227:        while (*cur != 0)
1.5       daniel    228:            buf[index++] = *cur++;
                    229:        buf[index] = 0;
1.7       daniel    230:        ctxt->path = xmlMemStrdup(buf);
1.5       daniel    231:     }  
1.1       daniel    232: }
                    233: 
1.5       daniel    234: /**
1.12      daniel    235:  * xmlNanoHTTPScanProxy:
                    236:  * @URL:  The proxy URL used to initialize the proxy context
                    237:  *
                    238:  * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
                    239:  * the protocol host port it indicates.
                    240:  * Should be like http://myproxy/ or http://myproxy:3128/
                    241:  * A NULL URL cleans up proxy informations.
                    242:  */
                    243: 
                    244: void
                    245: xmlNanoHTTPScanProxy(const char *URL) {
                    246:     const char *cur = URL;
                    247:     char buf[4096];
                    248:     int index = 0;
                    249:     int port = 0;
                    250: 
                    251:     if (proxy != NULL) { 
                    252:         xmlFree(proxy);
                    253:        proxy = NULL;
                    254:     }
                    255:     if (proxyPort != 0) { 
                    256:        proxyPort = 0;
                    257:     }
                    258: #ifdef DEBUG_HTTP
                    259:     if (URL == NULL)
                    260:        printf("Removing HTTP proxy info\n");
                    261:     else
                    262:        printf("Using HTTP proxy %s\n", URL);
                    263: #endif
                    264:     if (URL == NULL) return;
                    265:     buf[index] = 0;
                    266:     while (*cur != 0) {
                    267:         if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
                    268:            buf[index] = 0;
                    269:            index = 0;
                    270:             cur += 3;
                    271:            break;
                    272:        }
                    273:        buf[index++] = *cur++;
                    274:     }
                    275:     if (*cur == 0) return;
                    276: 
                    277:     buf[index] = 0;
                    278:     while (1) {
                    279:         if (cur[0] == ':') {
                    280:            buf[index] = 0;
                    281:            proxy = xmlMemStrdup(buf);
                    282:            index = 0;
                    283:            cur += 1;
                    284:            while ((*cur >= '0') && (*cur <= '9')) {
                    285:                port *= 10;
                    286:                port += *cur - '0';
                    287:                cur++;
                    288:            }
                    289:            if (port != 0) proxyPort = port;
                    290:            while ((cur[0] != '/') && (*cur != 0)) 
                    291:                cur++;
                    292:            break;
                    293:        }
                    294:         if ((*cur == '/') || (*cur == 0)) {
                    295:            buf[index] = 0;
                    296:            proxy = xmlMemStrdup(buf);
                    297:            index = 0;
                    298:            break;
                    299:        }
                    300:        buf[index++] = *cur++;
                    301:     }
                    302: }
                    303: 
                    304: /**
1.5       daniel    305:  * xmlNanoHTTPNewCtxt:
                    306:  * @URL:  The URL used to initialize the context
                    307:  *
                    308:  * Allocate and initialize a new HTTP context.
                    309:  *
                    310:  * Returns an HTTP context or NULL in case of error.
                    311:  */
                    312: 
                    313: static xmlNanoHTTPCtxtPtr
                    314: xmlNanoHTTPNewCtxt(const char *URL) {
1.1       daniel    315:     xmlNanoHTTPCtxtPtr ret;
                    316: 
1.7       daniel    317:     ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
1.1       daniel    318:     if (ret == NULL) return(NULL);
                    319: 
                    320:     memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
                    321:     ret->port = 80;
                    322:     ret->returnValue = 0;
                    323: 
                    324:     xmlNanoHTTPScanURL(ret, URL);
                    325: 
                    326:     return(ret);
                    327: }
                    328: 
1.5       daniel    329: /**
                    330:  * xmlNanoHTTPFreeCtxt:
                    331:  * @ctxt:  an HTTP context
                    332:  *
                    333:  * Frees the context after closing the connection.
                    334:  */
                    335: 
                    336: static void
                    337: xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
                    338:     if (ctxt == NULL) return;
1.7       daniel    339:     if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
                    340:     if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
                    341:     if (ctxt->path != NULL) xmlFree(ctxt->path);
                    342:     if (ctxt->out != NULL) xmlFree(ctxt->out);
                    343:     if (ctxt->in != NULL) xmlFree(ctxt->in);
                    344:     if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
                    345:     if (ctxt->location != NULL) xmlFree(ctxt->location);
1.1       daniel    346:     ctxt->state = XML_NANO_HTTP_NONE;
                    347:     if (ctxt->fd >= 0) close(ctxt->fd);
                    348:     ctxt->fd = -1;
1.7       daniel    349:     xmlFree(ctxt);
1.1       daniel    350: }
                    351: 
1.5       daniel    352: /**
                    353:  * xmlNanoHTTPSend:
                    354:  * @ctxt:  an HTTP context
                    355:  *
                    356:  * Send the input needed to initiate the processing on the server side
                    357:  */
                    358: 
                    359: static void
                    360: xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
1.1       daniel    361:     if (ctxt->state & XML_NANO_HTTP_WRITE)
                    362:        ctxt->last = write(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr));
                    363: }
                    364: 
1.5       daniel    365: /**
                    366:  * xmlNanoHTTPRecv:
                    367:  * @ctxt:  an HTTP context
                    368:  *
                    369:  * Read information coming from the HTTP connection.
                    370:  * This is a blocking call (but it blocks in select(), not read()).
                    371:  *
                    372:  * Returns the number of byte read or -1 in case of error.
                    373:  */
                    374: 
                    375: static int
                    376: xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
1.1       daniel    377:     fd_set rfd;
                    378:     struct timeval tv;
                    379: 
                    380: 
                    381:     while (ctxt->state & XML_NANO_HTTP_READ) {
                    382:        if (ctxt->in == NULL) {
1.7       daniel    383:            ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
1.1       daniel    384:            if (ctxt->in == NULL) {
                    385:                ctxt->last = -1;
                    386:                return(-1);
                    387:            }
                    388:            ctxt->inlen = 65000;
                    389:            ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
                    390:        }
                    391:        if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
                    392:            int delta = ctxt->inrptr - ctxt->in;
                    393:            int len = ctxt->inptr - ctxt->inrptr;
                    394:            
                    395:            memmove(ctxt->in, ctxt->inrptr, len);
                    396:            ctxt->inrptr -= delta;
                    397:            ctxt->content -= delta;
                    398:            ctxt->inptr -= delta;
                    399:        }
                    400:         if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
                    401:            int d_inptr = ctxt->inptr - ctxt->in;
                    402:            int d_content = ctxt->content - ctxt->in;
                    403:            int d_inrptr = ctxt->inrptr - ctxt->in;
                    404: 
                    405:            ctxt->inlen *= 2;
1.7       daniel    406:             ctxt->in = (char *) xmlRealloc(ctxt->in, ctxt->inlen);
1.1       daniel    407:            if (ctxt->in == NULL) {
                    408:                ctxt->last = -1;
                    409:                return(-1);
                    410:            }
                    411:             ctxt->inptr = ctxt->in + d_inptr;
                    412:             ctxt->content = ctxt->in + d_content;
                    413:             ctxt->inrptr = ctxt->in + d_inrptr;
                    414:        }
                    415:        ctxt->last = read(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK);
                    416:        if (ctxt->last > 0) {
                    417:            ctxt->inptr += ctxt->last;
                    418:            return(ctxt->last);
                    419:        }
                    420:        if (ctxt->last == 0) {
                    421:            return(0);
                    422:        }
                    423: #ifdef EWOULDBLOCK
                    424:        if ((ctxt->last == -1) && (errno != EWOULDBLOCK)) {
1.5       daniel    425:            return(0);
1.1       daniel    426:        }
                    427: #endif
                    428:        tv.tv_sec=10;
                    429:        tv.tv_usec=0;
                    430:        FD_ZERO(&rfd);
                    431:        FD_SET(ctxt->fd, &rfd);
                    432:        
                    433:        if(select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
1.5       daniel    434:                return(0);
1.1       daniel    435:     }
                    436:     return(0);
                    437: }
                    438: 
1.5       daniel    439: /**
                    440:  * xmlNanoHTTPReadLine:
                    441:  * @ctxt:  an HTTP context
                    442:  *
                    443:  * Read one line in the HTTP server output, usually for extracting
                    444:  * the HTTP protocol informations from the answer header.
                    445:  *
                    446:  * Returns a newly allocated string with a copy of the line, or NULL
                    447:  *         which indicate the end of the input.
                    448:  */
                    449: 
                    450: static char *
                    451: xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
                    452:     char buf[4096];
1.1       daniel    453:     char *bp=buf;
                    454:     
                    455:     while(bp - buf < 4095) {
                    456:        if(ctxt->inrptr == ctxt->inptr) {
                    457:            if (xmlNanoHTTPRecv(ctxt) == 0) {
                    458:                if (bp == buf)
1.5       daniel    459:                    return(NULL);
1.1       daniel    460:                else
                    461:                    *bp = 0;
1.7       daniel    462:                return(xmlMemStrdup(buf));
1.1       daniel    463:            }
                    464:        }
                    465:        *bp = *ctxt->inrptr++;
                    466:        if(*bp == '\n') {
                    467:            *bp = 0;
1.7       daniel    468:            return(xmlMemStrdup(buf));
1.1       daniel    469:        }
                    470:        if(*bp != '\r')
                    471:            bp++;
                    472:     }
                    473:     buf[4095] = 0;
1.7       daniel    474:     return(xmlMemStrdup(buf));
1.1       daniel    475: }
                    476: 
1.5       daniel    477: 
                    478: /**
                    479:  * xmlNanoHTTPScanAnswer:
                    480:  * @ctxt:  an HTTP context
                    481:  * @line:  an HTTP header line
                    482:  *
                    483:  * Try to extract useful informations from the server answer.
                    484:  * We currently parse and process:
                    485:  *  - The HTTP revision/ return code
                    486:  *  - The Content-Type
                    487:  *  - The Location for redirrect processing.
                    488:  *
                    489:  * Returns -1 in case of failure, the file descriptor number otherwise
                    490:  */
                    491: 
                    492: static void
                    493: xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
1.1       daniel    494:     const char *cur = line;
                    495: 
                    496:     if (line == NULL) return;
                    497: 
                    498:     if (!strncmp(line, "HTTP/", 5)) {
                    499:         int version = 0;
                    500:        int ret = 0;
                    501: 
                    502:        cur += 5;
                    503:        while ((*cur >= '0') && (*cur <= '9')) {
                    504:            version *= 10;
                    505:            version += *cur - '0';
                    506:            cur++;
                    507:        }
                    508:        if (*cur == '.') {
                    509:            cur++;
                    510:            if ((*cur >= '0') && (*cur <= '9')) {
                    511:                version *= 10;
                    512:                version += *cur - '0';
                    513:                cur++;
                    514:            }
                    515:            while ((*cur >= '0') && (*cur <= '9'))
                    516:                cur++;
                    517:        } else
                    518:            version *= 10;
                    519:        if ((*cur != ' ') && (*cur != '\t')) return;
                    520:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    521:        if ((*cur < '0') || (*cur > '9')) return;
                    522:        while ((*cur >= '0') && (*cur <= '9')) {
                    523:            ret *= 10;
                    524:            ret += *cur - '0';
                    525:            cur++;
                    526:        }
                    527:        if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
                    528:        ctxt->returnValue = ret;
1.23      veillard  529:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
1.1       daniel    530:         cur += 13;
                    531:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    532:        if (ctxt->contentType != NULL)
1.7       daniel    533:            xmlFree(ctxt->contentType);
                    534:        ctxt->contentType = xmlMemStrdup(cur);
1.23      veillard  535:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
1.1       daniel    536:         cur += 12;
                    537:        if (ctxt->contentType != NULL) return;
                    538:        while ((*cur == ' ') || (*cur == '\t')) cur++;
1.7       daniel    539:        ctxt->contentType = xmlMemStrdup(cur);
1.23      veillard  540:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
1.1       daniel    541:         cur += 9;
                    542:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    543:        if (ctxt->location != NULL)
1.7       daniel    544:            xmlFree(ctxt->location);
                    545:        ctxt->location = xmlMemStrdup(cur);
1.1       daniel    546:     }
                    547: }
                    548: 
1.5       daniel    549: /**
                    550:  * xmlNanoHTTPConnectAttempt:
                    551:  * @ia:  an internet adress structure
                    552:  * @port:  the port number
                    553:  *
                    554:  * Attempt a connection to the given IP:port endpoint. It forces
                    555:  * non-blocking semantic on the socket, and allow 60 seconds for
                    556:  * the host to answer.
                    557:  *
                    558:  * Returns -1 in case of failure, the file descriptor number otherwise
                    559:  */
                    560: 
                    561: static int
                    562: xmlNanoHTTPConnectAttempt(struct in_addr ia, int port)
1.1       daniel    563: {
                    564:     int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
                    565:     struct sockaddr_in sin;
                    566:     fd_set wfd;
                    567:     struct timeval tv;
1.2       daniel    568:     int status;
1.1       daniel    569:     
                    570:     if(s==-1) {
1.5       daniel    571: #ifdef DEBUG_HTTP
1.1       daniel    572:        perror("socket");
1.5       daniel    573: #endif
1.1       daniel    574:        return(-1);
                    575:     }
                    576:     
1.2       daniel    577: #ifdef _WINSOCKAPI_
                    578:     {
                    579:        long levents = FD_READ | FD_WRITE | FD_ACCEPT |
                    580:                       FD_CONNECT | FD_CLOSE ;
                    581:        int rv = 0 ;
                    582:        u_long one = 1;
                    583: 
1.3       daniel    584:        status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
1.2       daniel    585:     }
                    586: #else /* _WINSOCKAPI_ */
                    587: #if defined(VMS)
                    588:     {
                    589:        int enable = 1;
1.3       daniel    590:        status = IOCTL(s, FIONBIO, &enable);
1.2       daniel    591:     }
                    592: #else /* VMS */
1.3       daniel    593:     if((status = fcntl(s, F_GETFL, 0)) != -1) {
1.2       daniel    594: #ifdef O_NONBLOCK
                    595:        status |= O_NONBLOCK;
                    596: #else /* O_NONBLOCK */
                    597: #ifdef F_NDELAY
                    598:        status |= F_NDELAY;
                    599: #endif /* F_NDELAY */
                    600: #endif /* !O_NONBLOCK */
1.3       daniel    601:        status = fcntl(s, F_SETFL, status);
1.2       daniel    602:     }
                    603:     if(status < 0) {
1.5       daniel    604: #ifdef DEBUG_HTTP
1.1       daniel    605:        perror("nonblocking");
1.5       daniel    606: #endif
1.1       daniel    607:        close(s);
                    608:        return(-1);
                    609:     }
1.2       daniel    610: #endif /* !VMS */
                    611: #endif /* !_WINSOCKAPI_ */
                    612: 
1.1       daniel    613: 
                    614:     sin.sin_family = AF_INET;  
                    615:     sin.sin_addr   = ia;
                    616:     sin.sin_port   = htons(port);
                    617:     
                    618:     if((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1) &&
                    619:        (errno != EINPROGRESS)) {
                    620:        perror("connect");
                    621:        close(s);
                    622:        return(-1);
                    623:     }  
                    624:     
                    625:     tv.tv_sec = 60;            /* We use 60 second timeouts for now */
                    626:     tv.tv_usec = 0;
                    627:     
                    628:     FD_ZERO(&wfd);
                    629:     FD_SET(s, &wfd);
                    630:     
                    631:     switch(select(s+1, NULL, &wfd, NULL, &tv))
                    632:     {
                    633:        case 0:
                    634:            /* Time out */
                    635:            close(s);
                    636:            return(-1);
                    637:        case -1:
                    638:            /* Ermm.. ?? */
1.5       daniel    639: #ifdef DEBUG_HTTP
1.1       daniel    640:            perror("select");
1.5       daniel    641: #endif
1.1       daniel    642:            close(s);
                    643:            return(-1);
                    644:     }
1.19      daniel    645: 
                    646:     if ( FD_ISSET(s, &wfd) ) {
1.24      veillard  647: #ifdef HAVE_SOCKLEN_T
                    648:        socklen_t len;
                    649: #else
                    650:        unsigned int len;
                    651: #endif
1.19      daniel    652:        len = sizeof(status);
                    653:        if (getsockopt(s, SOL_SOCKET, SO_ERROR, &status, &len) < 0 ) {
                    654:            /* Solaris error code */
                    655:            return (-1);
                    656:        }
                    657:        if ( status ) {
                    658:            close (s);
                    659:            errno = status;
                    660:            return (-1);
                    661:        }
                    662:     } else {
                    663:        /* pbm */
                    664:        return (-1);
                    665:     }
1.1       daniel    666:     
1.5       daniel    667:     return(s);
1.1       daniel    668: }
                    669:  
1.5       daniel    670: /**
                    671:  * xmlNanoHTTPConnectHost:
                    672:  * @host:  the host name
                    673:  * @port:  the port number
                    674:  *
                    675:  * Attempt a connection to the given host:port endpoint. It tries
                    676:  * the multiple IP provided by the DNS if available.
                    677:  *
                    678:  * Returns -1 in case of failure, the file descriptor number otherwise
                    679:  */
                    680: 
                    681: static int
                    682: xmlNanoHTTPConnectHost(const char *host, int port)
1.1       daniel    683: {
                    684:     struct hostent *h;
                    685:     int i;
                    686:     int s;
                    687:     
                    688:     h=gethostbyname(host);
                    689:     if(h==NULL)
                    690:     {
1.5       daniel    691: #ifdef DEBUG_HTTP
1.1       daniel    692:        fprintf(stderr,"unable to resolve '%s'.\n", host);
1.5       daniel    693: #endif
1.1       daniel    694:        return(-1);
                    695:     }
                    696:     
                    697:     for(i=0; h->h_addr_list[i]; i++)
                    698:     {
                    699:        struct in_addr ia;
                    700:        memcpy(&ia, h->h_addr_list[i],4);
                    701:        s = xmlNanoHTTPConnectAttempt(ia, port);
                    702:        if(s != -1)
1.5       daniel    703:            return(s);
1.1       daniel    704:     }
1.5       daniel    705: 
                    706: #ifdef DEBUG_HTTP
1.1       daniel    707:     fprintf(stderr, "unable to connect to '%s'.\n", host);
1.5       daniel    708: #endif
1.1       daniel    709:     return(-1);
                    710: }
                    711: 
                    712: 
1.5       daniel    713: /**
                    714:  * xmlNanoHTTPOpen:
                    715:  * @URL:  The URL to load
                    716:  * @contentType:  if available the Content-Type information will be
                    717:  *                returned at that location
                    718:  *
                    719:  * This function try to open a connection to the indicated resource
                    720:  * via HTTP GET.
                    721:  *
1.6       daniel    722:  * Returns NULL in case of failure, otherwise a request handler.
                    723:  *     The contentType, if provided must be freed by the caller
1.5       daniel    724:  */
1.1       daniel    725: 
1.18      daniel    726: void*
1.1       daniel    727: xmlNanoHTTPOpen(const char *URL, char **contentType) {
                    728:     xmlNanoHTTPCtxtPtr ctxt;
                    729:     char buf[4096];
                    730:     int ret;
                    731:     char *p;
                    732:     int head;
                    733:     int nbRedirects = 0;
                    734:     char *redirURL = NULL;
                    735:     
1.12      daniel    736:     xmlNanoHTTPInit();
1.5       daniel    737:     if (contentType != NULL) *contentType = NULL;
                    738: 
1.1       daniel    739: retry:
                    740:     if (redirURL == NULL)
                    741:        ctxt = xmlNanoHTTPNewCtxt(URL);
                    742:     else {
                    743:        ctxt = xmlNanoHTTPNewCtxt(redirURL);
1.7       daniel    744:        xmlFree(redirURL);
1.1       daniel    745:        redirURL = NULL;
                    746:     }
                    747: 
                    748:     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
                    749:         xmlNanoHTTPFreeCtxt(ctxt);
1.7       daniel    750:        if (redirURL != NULL) xmlFree(redirURL);
1.1       daniel    751:         return(NULL);
                    752:     }
                    753:     if (ctxt->hostname == NULL) {
                    754:         xmlNanoHTTPFreeCtxt(ctxt);
                    755:         return(NULL);
                    756:     }
1.12      daniel    757:     if (proxy)
                    758:        ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
                    759:     else
                    760:        ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1.1       daniel    761:     if (ret < 0) {
                    762:         xmlNanoHTTPFreeCtxt(ctxt);
                    763:         return(NULL);
                    764:     }
                    765:     ctxt->fd = ret;
1.12      daniel    766:     if (proxy) {
1.22      veillard  767:        if (ctxt->port != 80)
1.16      daniel    768: #ifdef HAVE_SNPRINTF
1.12      daniel    769:            snprintf(buf, sizeof(buf),
                    770:                     "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    771:                 ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
                    772: #else
                    773:            sprintf(buf, 
                    774:                     "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    775:                 ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
1.22      veillard  776: #endif
1.12      daniel    777:        else 
1.22      veillard  778: #ifdef HAVE_SNPRINTF
                    779:            snprintf(buf, sizeof(buf),"GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    780:                 ctxt->hostname, ctxt->path, ctxt->hostname);
                    781: #else
1.12      daniel    782:            sprintf(buf, "GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    783:                 ctxt->hostname, ctxt->path, ctxt->hostname);
                    784: #endif
                    785: #ifdef DEBUG_HTTP
                    786:        if (ctxt->port != 80)
                    787:            printf("-> Proxy GET http://%s:%d%s HTTP/1.0\n-> Host: %s\n\n",
                    788:                   ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
                    789:        else
                    790:            printf("-> Proxy GET http://%s%s HTTP/1.0\n-> Host: %s\n\n",
                    791:                   ctxt->hostname, ctxt->path, ctxt->hostname);
                    792: #endif
                    793:     } else {
1.7       daniel    794: #ifdef HAVE_SNPRINTF
1.12      daniel    795:        snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    796:                 ctxt->path, ctxt->hostname);
1.7       daniel    797: #else
1.12      daniel    798:        sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    799:                 ctxt->path, ctxt->hostname);
1.7       daniel    800: #endif
1.5       daniel    801: #ifdef DEBUG_HTTP
1.12      daniel    802:        printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n",
                    803:               ctxt->path, ctxt->hostname);
1.5       daniel    804: #endif
1.12      daniel    805:     }
1.22      veillard  806:     buf[sizeof(buf) - 1] = 0;
1.7       daniel    807:     ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
1.1       daniel    808:     ctxt->state = XML_NANO_HTTP_WRITE;
                    809:     xmlNanoHTTPSend(ctxt);
                    810:     ctxt->state = XML_NANO_HTTP_READ;
                    811:     head = 1;
                    812: 
                    813:     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
                    814:         if (head && (*p == 0)) {
                    815:            head = 0;
                    816:            ctxt->content = ctxt->inrptr;
1.12      daniel    817:            xmlFree(p);
1.1       daniel    818:            break;
                    819:        }
                    820:        xmlNanoHTTPScanAnswer(ctxt, p);
                    821: 
1.5       daniel    822: #ifdef DEBUG_HTTP
                    823:        if (p != NULL) printf("<- %s\n", p);
                    824: #endif
1.7       daniel    825:         if (p != NULL) xmlFree(p);
1.1       daniel    826:     }
                    827: 
                    828:     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
                    829:         (ctxt->returnValue < 400)) {
1.5       daniel    830: #ifdef DEBUG_HTTP
                    831:        printf("\nRedirect to: %s\n", ctxt->location);
                    832: #endif
1.1       daniel    833:        while (xmlNanoHTTPRecv(ctxt)) ;
                    834:         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
                    835:            nbRedirects++;
1.7       daniel    836:            redirURL = xmlMemStrdup(ctxt->location);
1.1       daniel    837:            xmlNanoHTTPFreeCtxt(ctxt);
                    838:            goto retry;
                    839:        }
                    840:        xmlNanoHTTPFreeCtxt(ctxt);
1.5       daniel    841: #ifdef DEBUG_HTTP
                    842:        printf("Too many redirrects, aborting ...\n");
                    843: #endif
1.1       daniel    844:        return(NULL);
                    845: 
                    846:     }
                    847: 
1.5       daniel    848:     if ((contentType != NULL) && (ctxt->contentType != NULL))
1.7       daniel    849:         *contentType = xmlMemStrdup(ctxt->contentType);
1.5       daniel    850: 
                    851: #ifdef DEBUG_HTTP
                    852:     if (ctxt->contentType != NULL)
                    853:        printf("\nCode %d, content-type '%s'\n\n",
                    854:               ctxt->returnValue, ctxt->contentType);
                    855:     else
                    856:        printf("\nCode %d, no content-type\n\n",
                    857:               ctxt->returnValue);
                    858: #endif
1.1       daniel    859: 
                    860:     return((void *) ctxt);
                    861: }
                    862: 
1.5       daniel    863: /**
                    864:  * xmlNanoHTTPRead:
                    865:  * @ctx:  the HTTP context
                    866:  * @dest:  a buffer
                    867:  * @len:  the buffer length
                    868:  *
                    869:  * This function tries to read @len bytes from the existing HTTP connection
                    870:  * and saves them in @dest. This is a blocking call.
                    871:  *
                    872:  * Returns the number of byte read. 0 is an indication of an end of connection.
                    873:  *         -1 indicates a parameter error.
                    874:  */
1.1       daniel    875: int
                    876: xmlNanoHTTPRead(void *ctx, void *dest, int len) {
                    877:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                    878: 
                    879:     if (ctx == NULL) return(-1);
                    880:     if (dest == NULL) return(-1);
                    881:     if (len <= 0) return(0);
                    882: 
                    883:     while (ctxt->inptr - ctxt->inrptr < len) {
                    884:         if (xmlNanoHTTPRecv(ctxt) == 0) break;
                    885:     }
                    886:     if (ctxt->inptr - ctxt->inrptr < len)
                    887:         len = ctxt->inptr - ctxt->inrptr;
                    888:     memcpy(dest, ctxt->inrptr, len);
                    889:     ctxt->inrptr += len;
                    890:     return(len);
                    891: }
                    892: 
1.5       daniel    893: /**
                    894:  * xmlNanoHTTPClose:
                    895:  * @ctx:  the HTTP context
                    896:  *
                    897:  * This function closes an HTTP context, it ends up the connection and
                    898:  * free all data related to it.
                    899:  */
1.1       daniel    900: void
                    901: xmlNanoHTTPClose(void *ctx) {
                    902:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                    903: 
                    904:     if (ctx == NULL) return;
                    905: 
                    906:     xmlNanoHTTPFreeCtxt(ctxt);
                    907: }
                    908: 
1.8       daniel    909: #ifndef DEBUG_HTTP
                    910: #define DEBUG_HTTP
                    911: #endif
1.5       daniel    912: /**
1.6       daniel    913:  * xmlNanoHTTPMethod:
                    914:  * @URL:  The URL to load
                    915:  * @method:  the HTTP method to use
                    916:  * @input:  the input string if any
                    917:  * @contentType:  the Content-Type information IN and OUT
                    918:  * @headers:  the extra headers
                    919:  *
                    920:  * This function try to open a connection to the indicated resource
                    921:  * via HTTP using the given @method, adding the given extra headers
                    922:  * and the input buffer for the request content.
                    923:  *
                    924:  * Returns NULL in case of failure, otherwise a request handler.
                    925:  *     The contentType, if provided must be freed by the caller
                    926:  */
                    927: 
1.18      daniel    928: void*
1.6       daniel    929: xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
                    930:                   char **contentType, const char *headers) {
                    931:     xmlNanoHTTPCtxtPtr ctxt;
                    932:     char buf[20000];
                    933:     int ret;
                    934:     char *p;
                    935:     int head;
                    936:     int nbRedirects = 0;
                    937:     char *redirURL = NULL;
                    938:     
                    939:     if (URL == NULL) return(NULL);
                    940:     if (method == NULL) method = "GET";
                    941:     if (contentType != NULL) *contentType = NULL;
                    942: 
                    943: retry:
                    944:     if (redirURL == NULL)
                    945:        ctxt = xmlNanoHTTPNewCtxt(URL);
                    946:     else {
                    947:        ctxt = xmlNanoHTTPNewCtxt(redirURL);
1.7       daniel    948:        xmlFree(redirURL);
1.6       daniel    949:        redirURL = NULL;
                    950:     }
                    951: 
                    952:     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
                    953:         xmlNanoHTTPFreeCtxt(ctxt);
1.7       daniel    954:        if (redirURL != NULL) xmlFree(redirURL);
1.6       daniel    955:         return(NULL);
                    956:     }
                    957:     if (ctxt->hostname == NULL) {
                    958:         xmlNanoHTTPFreeCtxt(ctxt);
                    959:         return(NULL);
                    960:     }
                    961:     ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
                    962:     if (ret < 0) {
                    963:         xmlNanoHTTPFreeCtxt(ctxt);
                    964:         return(NULL);
                    965:     }
                    966:     ctxt->fd = ret;
                    967: 
                    968:     if (input == NULL) {
                    969:         if (headers == NULL) {
                    970:            if ((contentType == NULL) || (*contentType == NULL)) {
1.7       daniel    971: #ifdef HAVE_SNPRINTF
1.6       daniel    972:                snprintf(buf, sizeof(buf),
                    973:                         "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    974:                         method, ctxt->path, ctxt->hostname);
1.7       daniel    975: #else
                    976:                sprintf(buf,
                    977:                         "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
                    978:                         method, ctxt->path, ctxt->hostname);
                    979: #endif
1.6       daniel    980:            } else {
1.7       daniel    981: #ifdef HAVE_SNPRINTF
1.6       daniel    982:                snprintf(buf, sizeof(buf),
                    983:                     "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n",
                    984:                         method, ctxt->path, ctxt->hostname, *contentType);
1.7       daniel    985: #else
                    986:                sprintf(buf,
                    987:                     "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n",
                    988:                         method, ctxt->path, ctxt->hostname, *contentType);
                    989: #endif
1.6       daniel    990:            }
                    991:        } else {
                    992:            if ((contentType == NULL) || (*contentType == NULL)) {
1.7       daniel    993: #ifdef HAVE_SNPRINTF
1.6       daniel    994:                snprintf(buf, sizeof(buf),
                    995:                         "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n",
                    996:                         method, ctxt->path, ctxt->hostname, headers);
1.7       daniel    997: #else
                    998:                sprintf(buf,
                    999:                         "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n",
                   1000:                         method, ctxt->path, ctxt->hostname, headers);
                   1001: #endif
1.6       daniel   1002:            } else {
1.7       daniel   1003: #ifdef HAVE_SNPRINTF
1.6       daniel   1004:                snprintf(buf, sizeof(buf),
                   1005:                 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n",
                   1006:                         method, ctxt->path, ctxt->hostname, *contentType,
                   1007:                         headers);
1.7       daniel   1008: #else
                   1009:                sprintf(buf,
                   1010:                 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n",
                   1011:                         method, ctxt->path, ctxt->hostname, *contentType,
                   1012:                         headers);
                   1013: #endif
1.6       daniel   1014:            }
                   1015:        }
                   1016:     } else {
                   1017:         int len = strlen(input);
                   1018:         if (headers == NULL) {
                   1019:            if ((contentType == NULL) || (*contentType == NULL)) {
1.7       daniel   1020: #ifdef HAVE_SNPRINTF
1.6       daniel   1021:                snprintf(buf, sizeof(buf),
                   1022:                 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s",
                   1023:                         method, ctxt->path, ctxt->hostname, len, input);
1.7       daniel   1024: #else
                   1025:                sprintf(buf,
                   1026:                 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s",
                   1027:                         method, ctxt->path, ctxt->hostname, len, input);
                   1028: #endif
1.6       daniel   1029:            } else {
1.7       daniel   1030: #ifdef HAVE_SNPRINTF
1.6       daniel   1031:                snprintf(buf, sizeof(buf),
                   1032: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
                   1033:                         method, ctxt->path, ctxt->hostname, *contentType, len,
                   1034:                         input);
1.7       daniel   1035: #else
                   1036:                sprintf(buf,
                   1037: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
                   1038:                         method, ctxt->path, ctxt->hostname, *contentType, len,
                   1039:                         input);
                   1040: #endif
1.6       daniel   1041:            }
                   1042:        } else {
                   1043:            if ((contentType == NULL) || (*contentType == NULL)) {
1.7       daniel   1044: #ifdef HAVE_SNPRINTF
1.6       daniel   1045:                snprintf(buf, sizeof(buf),
                   1046:             "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s",
                   1047:                         method, ctxt->path, ctxt->hostname, len,
                   1048:                         headers, input);
1.7       daniel   1049: #else
                   1050:                sprintf(buf,
                   1051:             "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s",
                   1052:                         method, ctxt->path, ctxt->hostname, len,
                   1053:                         headers, input);
                   1054: #endif
1.6       daniel   1055:            } else {
1.7       daniel   1056: #ifdef HAVE_SNPRINTF
1.6       daniel   1057:                snprintf(buf, sizeof(buf),
                   1058: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s",
                   1059:                         method, ctxt->path, ctxt->hostname, *contentType,
                   1060:                         len, headers, input);
1.7       daniel   1061: #else
                   1062:                sprintf(buf,
                   1063: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s",
                   1064:                         method, ctxt->path, ctxt->hostname, *contentType,
                   1065:                         len, headers, input);
                   1066: #endif
1.6       daniel   1067:            }
                   1068:        }
                   1069:     }
1.22      veillard 1070:     buf[sizeof(buf) - 1] = 0;
1.6       daniel   1071: #ifdef DEBUG_HTTP
                   1072:     printf("-> %s", buf);
                   1073: #endif
1.7       daniel   1074:     ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
1.6       daniel   1075:     ctxt->state = XML_NANO_HTTP_WRITE;
                   1076:     xmlNanoHTTPSend(ctxt);
                   1077:     ctxt->state = XML_NANO_HTTP_READ;
                   1078:     head = 1;
                   1079: 
                   1080:     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
                   1081:         if (head && (*p == 0)) {
                   1082:            head = 0;
                   1083:            ctxt->content = ctxt->inrptr;
1.7       daniel   1084:            if (p != NULL) xmlFree(p);
1.6       daniel   1085:            break;
                   1086:        }
                   1087:        xmlNanoHTTPScanAnswer(ctxt, p);
                   1088: 
                   1089: #ifdef DEBUG_HTTP
                   1090:        if (p != NULL) printf("<- %s\n", p);
                   1091: #endif
1.7       daniel   1092:         if (p != NULL) xmlFree(p);
1.6       daniel   1093:     }
                   1094: 
                   1095:     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
                   1096:         (ctxt->returnValue < 400)) {
                   1097: #ifdef DEBUG_HTTP
                   1098:        printf("\nRedirect to: %s\n", ctxt->location);
                   1099: #endif
                   1100:        while (xmlNanoHTTPRecv(ctxt)) ;
                   1101:         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
                   1102:            nbRedirects++;
1.7       daniel   1103:            redirURL = xmlMemStrdup(ctxt->location);
1.6       daniel   1104:            xmlNanoHTTPFreeCtxt(ctxt);
                   1105:            goto retry;
                   1106:        }
                   1107:        xmlNanoHTTPFreeCtxt(ctxt);
                   1108: #ifdef DEBUG_HTTP
                   1109:        printf("Too many redirrects, aborting ...\n");
                   1110: #endif
                   1111:        return(NULL);
                   1112: 
                   1113:     }
                   1114: 
                   1115:     if ((contentType != NULL) && (ctxt->contentType != NULL))
1.7       daniel   1116:         *contentType = xmlMemStrdup(ctxt->contentType);
                   1117:     else if (contentType != NULL)
                   1118:         *contentType = NULL;
1.6       daniel   1119: 
                   1120: #ifdef DEBUG_HTTP
                   1121:     if (ctxt->contentType != NULL)
                   1122:        printf("\nCode %d, content-type '%s'\n\n",
                   1123:               ctxt->returnValue, ctxt->contentType);
                   1124:     else
                   1125:        printf("\nCode %d, no content-type\n\n",
                   1126:               ctxt->returnValue);
                   1127: #endif
                   1128: 
                   1129:     return((void *) ctxt);
                   1130: }
                   1131: 
                   1132: /**
1.5       daniel   1133:  * xmlNanoHTTPFetch:
                   1134:  * @URL:  The URL to load
                   1135:  * @filename:  the filename where the content should be saved
                   1136:  * @contentType:  if available the Content-Type information will be
                   1137:  *                returned at that location
                   1138:  *
                   1139:  * This function try to fetch the indicated resource via HTTP GET
                   1140:  * and save it's content in the file.
                   1141:  *
                   1142:  * Returns -1 in case of failure, 0 incase of success. The contentType,
                   1143:  *     if provided must be freed by the caller
                   1144:  */
                   1145: int
                   1146: xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
1.1       daniel   1147:     void *ctxt;
                   1148:     char buf[4096];
                   1149:     int fd;
                   1150:     int len;
                   1151:     
                   1152:     ctxt = xmlNanoHTTPOpen(URL, contentType);
                   1153:     if (ctxt == NULL) return(-1);
                   1154: 
                   1155:     if (!strcmp(filename, "-")) 
                   1156:         fd = 0;
                   1157:     else {
1.13      daniel   1158:         fd = open(filename, O_CREAT | O_WRONLY, 00644);
1.1       daniel   1159:        if (fd < 0) {
                   1160:            xmlNanoHTTPClose(ctxt);
1.5       daniel   1161:            if ((contentType != NULL) && (*contentType != NULL)) {
1.7       daniel   1162:                xmlFree(*contentType);
1.5       daniel   1163:                *contentType = NULL;
                   1164:            }
1.1       daniel   1165:            return(-1);
                   1166:        }
                   1167:     }
                   1168: 
                   1169:     while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
                   1170:        write(fd, buf, len);
                   1171:     }
                   1172: 
                   1173:     xmlNanoHTTPClose(ctxt);
1.13      daniel   1174:     close(fd);
1.1       daniel   1175:     return(0);
1.6       daniel   1176: }
                   1177: 
                   1178: /**
                   1179:  * xmlNanoHTTPSave:
1.8       daniel   1180:  * @ctxt:  the HTTP context
1.6       daniel   1181:  * @filename:  the filename where the content should be saved
                   1182:  *
                   1183:  * This function saves the output of the HTTP transaction to a file
                   1184:  * It closes and free the context at the end
                   1185:  *
                   1186:  * Returns -1 in case of failure, 0 incase of success.
                   1187:  */
                   1188: int
                   1189: xmlNanoHTTPSave(void *ctxt, const char *filename) {
                   1190:     char buf[4096];
                   1191:     int fd;
                   1192:     int len;
                   1193:     
                   1194:     if (ctxt == NULL) return(-1);
                   1195: 
                   1196:     if (!strcmp(filename, "-")) 
                   1197:         fd = 0;
                   1198:     else {
                   1199:         fd = open(filename, O_CREAT | O_WRONLY);
                   1200:        if (fd < 0) {
                   1201:            xmlNanoHTTPClose(ctxt);
                   1202:            return(-1);
                   1203:        }
                   1204:     }
                   1205: 
                   1206:     while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
                   1207:        write(fd, buf, len);
                   1208:     }
                   1209: 
                   1210:     xmlNanoHTTPClose(ctxt);
                   1211:     return(0);
                   1212: }
                   1213: 
                   1214: /**
                   1215:  * xmlNanoHTTPReturnCode:
                   1216:  * @ctx:  the HTTP context
                   1217:  *
                   1218:  * Returns the HTTP return code for the request.
                   1219:  */
                   1220: int
                   1221: xmlNanoHTTPReturnCode(void *ctx) {
                   1222:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                   1223: 
                   1224:     if (ctxt == NULL) return(-1);
                   1225: 
                   1226:     return(ctxt->returnValue);
1.1       daniel   1227: }
                   1228: 
                   1229: #ifdef STANDALONE
                   1230: int main(int argc, char **argv) {
                   1231:     char *contentType = NULL;
                   1232: 
                   1233:     if (argv[1] != NULL) {
                   1234:        if (argv[2] != NULL) 
                   1235:            xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
                   1236:         else
                   1237:            xmlNanoHTTPFetch(argv[1], "-", &contentType);
1.7       daniel   1238:        if (contentType != NULL) xmlFree(contentType);
1.1       daniel   1239:     } else {
                   1240:         printf("%s: minimal HTTP GET implementation\n", argv[0]);
                   1241:         printf("\tusage %s [ URL [ filename ] ]\n", argv[0]);
                   1242:     }
1.12      daniel   1243:     xmlNanoHTTPCleanup();
                   1244:     xmlMemoryDump();
1.1       daniel   1245:     return(0);
                   1246: }
                   1247: #endif /* STANDALONE */
1.17      daniel   1248: #else /* !LIBXML_HTTP_ENABLED */
                   1249: #ifdef STANDALONE
                   1250: #include <stdio.h>
                   1251: int main(int argc, char **argv) {
                   1252:     printf("%s : HTTP support not compiled in\n", argv[0]);
                   1253:     return(0);
                   1254: }
                   1255: #endif /* STANDALONE */
                   1256: #endif /* LIBXML_HTTP_ENABLED */

Webmaster