Annotation of XML/nanohttp.c, revision 1.22

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

Webmaster