Annotation of embedaddon/libxml2/nanohttp.c, revision 1.1.1.2

1.1       misho       1: /*
                      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/
                      8:  *
                      9:  * See Copyright for the status of this software.
                     10:  *
                     11:  * daniel@veillard.com
                     12:  */
                     13:  
                     14: #define NEED_SOCKETS
                     15: #define IN_LIBXML
                     16: #include "libxml.h"
                     17: 
                     18: #ifdef LIBXML_HTTP_ENABLED
                     19: #include <string.h>
                     20: 
                     21: #ifdef HAVE_STDLIB_H
                     22: #include <stdlib.h>
                     23: #endif
                     24: #ifdef HAVE_UNISTD_H
                     25: #include <unistd.h>
                     26: #endif
                     27: #ifdef HAVE_SYS_TYPES_H
                     28: #include <sys/types.h>
                     29: #endif
                     30: #ifdef HAVE_SYS_SOCKET_H
                     31: #include <sys/socket.h>
                     32: #endif
                     33: #ifdef HAVE_NETINET_IN_H
                     34: #include <netinet/in.h>
                     35: #endif
                     36: #ifdef HAVE_ARPA_INET_H
                     37: #include <arpa/inet.h>
                     38: #endif
                     39: #ifdef HAVE_NETDB_H
                     40: #include <netdb.h>
                     41: #endif
                     42: #ifdef HAVE_RESOLV_H
                     43: #ifdef HAVE_ARPA_NAMESER_H
                     44: #include <arpa/nameser.h>
                     45: #endif
                     46: #include <resolv.h>
                     47: #endif
                     48: #ifdef HAVE_FCNTL_H
                     49: #include <fcntl.h> 
                     50: #endif
                     51: #ifdef HAVE_ERRNO_H
                     52: #include <errno.h>
                     53: #endif
                     54: #ifdef HAVE_SYS_TIME_H
                     55: #include <sys/time.h>
                     56: #endif
                     57: #ifndef HAVE_POLL_H
                     58: #ifdef HAVE_SYS_SELECT_H
                     59: #include <sys/select.h>
                     60: #endif
                     61: #else
                     62: #include <poll.h>
                     63: #endif
                     64: #ifdef HAVE_STRINGS_H
                     65: #include <strings.h>
                     66: #endif
                     67: #ifdef HAVE_ZLIB_H
                     68: #include <zlib.h>
                     69: #endif
                     70: 
                     71: 
                     72: #ifdef VMS
                     73: #include <stropts>
                     74: #define XML_SOCKLEN_T unsigned int
                     75: #endif
                     76: 
                     77: #if defined(__MINGW32__) || defined(_WIN32_WCE)
                     78: #ifndef _WINSOCKAPI_
                     79: #define _WINSOCKAPI_
                     80: #endif
                     81: #include <wsockcompat.h>
                     82: #include <winsock2.h>
                     83: #undef XML_SOCKLEN_T
                     84: #define XML_SOCKLEN_T unsigned int
                     85: #endif
                     86: 
                     87: #include <libxml/globals.h>
                     88: #include <libxml/xmlerror.h>
                     89: #include <libxml/xmlmemory.h>
                     90: #include <libxml/parser.h> /* for xmlStr(n)casecmp() */
                     91: #include <libxml/nanohttp.h>
                     92: #include <libxml/globals.h>
                     93: #include <libxml/uri.h>
                     94: 
                     95: /**
                     96:  * A couple portability macros
                     97:  */
                     98: #ifndef _WINSOCKAPI_
                     99: #if !defined(__BEOS__) || defined(__HAIKU__)
                    100: #define closesocket(s) close(s)
                    101: #endif
                    102: #define SOCKET int
                    103: #define INVALID_SOCKET (-1)
                    104: #endif
                    105: 
                    106: #ifdef __BEOS__
                    107: #ifndef PF_INET
                    108: #define PF_INET AF_INET
                    109: #endif
                    110: #endif
                    111: 
                    112: #ifndef XML_SOCKLEN_T
                    113: #define XML_SOCKLEN_T unsigned int
                    114: #endif
                    115: 
                    116: #ifdef STANDALONE
                    117: #define DEBUG_HTTP
                    118: #define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
                    119: #define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
                    120: #endif
                    121: 
                    122: #define XML_NANO_HTTP_MAX_REDIR        10
                    123: 
                    124: #define XML_NANO_HTTP_CHUNK    4096
                    125: 
                    126: #define XML_NANO_HTTP_CLOSED   0
                    127: #define XML_NANO_HTTP_WRITE    1
                    128: #define XML_NANO_HTTP_READ     2
                    129: #define XML_NANO_HTTP_NONE     4
                    130: 
                    131: typedef struct xmlNanoHTTPCtxt {
                    132:     char *protocol;    /* the protocol name */
                    133:     char *hostname;    /* the host name */
                    134:     int port;          /* the port */
                    135:     char *path;                /* the path within the URL */
                    136:     char *query;       /* the query string */
                    137:     SOCKET fd;         /* the file descriptor for the socket */
                    138:     int state;         /* WRITE / READ / CLOSED */
                    139:     char *out;         /* buffer sent (zero terminated) */
                    140:     char *outptr;      /* index within the buffer sent */
                    141:     char *in;          /* the receiving buffer */
                    142:     char *content;     /* the start of the content */
                    143:     char *inptr;       /* the next byte to read from network */
                    144:     char *inrptr;      /* the next byte to give back to the client */
                    145:     int inlen;         /* len of the input buffer */
                    146:     int last;          /* return code for last operation */
                    147:     int returnValue;   /* the protocol return value */
                    148:     int version;        /* the protocol version */
                    149:     int ContentLength;  /* specified content length from HTTP header */
                    150:     char *contentType; /* the MIME type for the input */
                    151:     char *location;    /* the new URL in case of redirect */
                    152:     char *authHeader;  /* contents of {WWW,Proxy}-Authenticate header */
                    153:     char *encoding;    /* encoding extracted from the contentType */
                    154:     char *mimeType;    /* Mime-Type extracted from the contentType */
                    155: #ifdef HAVE_ZLIB_H
                    156:     z_stream *strm;    /* Zlib stream object */
                    157:     int usesGzip;      /* "Content-Encoding: gzip" was detected */
                    158: #endif
                    159: } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
                    160: 
                    161: static int initialized = 0;
                    162: static char *proxy = NULL;      /* the proxy name if any */
                    163: static int proxyPort;  /* the proxy port if any */
                    164: static unsigned int timeout = 60;/* the select() timeout in seconds */
                    165: 
                    166: static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
                    167: 
                    168: /**
                    169:  * xmlHTTPErrMemory:
                    170:  * @extra:  extra informations
                    171:  *
                    172:  * Handle an out of memory condition
                    173:  */
                    174: static void
                    175: xmlHTTPErrMemory(const char *extra)
                    176: {
                    177:     __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
                    178: }
                    179: 
                    180: /**
                    181:  * A portability function
                    182:  */
                    183: static int socket_errno(void) {
                    184: #ifdef _WINSOCKAPI_
                    185:     return(WSAGetLastError());
                    186: #else
                    187:     return(errno);
                    188: #endif
                    189: }
                    190: 
                    191: #ifdef SUPPORT_IP6
                    192: static
                    193: int have_ipv6(void) {
                    194:     SOCKET s;
                    195: 
                    196:     s = socket (AF_INET6, SOCK_STREAM, 0);
                    197:     if (s != INVALID_SOCKET) {
                    198:        close (s);
                    199:        return (1);
                    200:     }
                    201:     return (0);
                    202: }
                    203: #endif
                    204: 
                    205: /**
                    206:  * xmlNanoHTTPInit:
                    207:  *
                    208:  * Initialize the HTTP protocol layer.
                    209:  * Currently it just checks for proxy informations
                    210:  */
                    211: 
                    212: void
                    213: xmlNanoHTTPInit(void) {
                    214:     const char *env;
                    215: #ifdef _WINSOCKAPI_
                    216:     WSADATA wsaData;    
                    217: #endif
                    218: 
                    219:     if (initialized)
                    220:        return;
                    221: 
                    222: #ifdef _WINSOCKAPI_
                    223:     if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
                    224:        return;
                    225: #endif
                    226: 
                    227:     if (proxy == NULL) {
                    228:        proxyPort = 80;
                    229:        env = getenv("no_proxy");
                    230:        if (env && ((env[0] == '*') && (env[1] == 0)))
                    231:            goto done;
                    232:        env = getenv("http_proxy");
                    233:        if (env != NULL) {
                    234:            xmlNanoHTTPScanProxy(env);
                    235:            goto done;
                    236:        }
                    237:        env = getenv("HTTP_PROXY");
                    238:        if (env != NULL) {
                    239:            xmlNanoHTTPScanProxy(env);
                    240:            goto done;
                    241:        }
                    242:     }
                    243: done:
                    244:     initialized = 1;
                    245: }
                    246: 
                    247: /**
                    248:  * xmlNanoHTTPCleanup:
                    249:  *
                    250:  * Cleanup the HTTP protocol layer.
                    251:  */
                    252: 
                    253: void
                    254: xmlNanoHTTPCleanup(void) {
                    255:     if (proxy != NULL) {
                    256:        xmlFree(proxy);
                    257:        proxy = NULL;
                    258:     }
                    259: #ifdef _WINSOCKAPI_
                    260:     if (initialized)
                    261:        WSACleanup();
                    262: #endif
                    263:     initialized = 0;
                    264:     return;
                    265: }
                    266: 
                    267: /**
                    268:  * xmlNanoHTTPScanURL:
                    269:  * @ctxt:  an HTTP context
                    270:  * @URL:  The URL used to initialize the context
                    271:  *
                    272:  * (Re)Initialize an HTTP context by parsing the URL and finding
                    273:  * the protocol host port and path it indicates.
                    274:  */
                    275: 
                    276: static void
                    277: xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
                    278:     xmlURIPtr uri;
                    279:     /*
                    280:      * Clear any existing data from the context
                    281:      */
                    282:     if (ctxt->protocol != NULL) { 
                    283:         xmlFree(ctxt->protocol);
                    284:        ctxt->protocol = NULL;
                    285:     }
                    286:     if (ctxt->hostname != NULL) { 
                    287:         xmlFree(ctxt->hostname);
                    288:        ctxt->hostname = NULL;
                    289:     }
                    290:     if (ctxt->path != NULL) { 
                    291:         xmlFree(ctxt->path);
                    292:        ctxt->path = NULL;
                    293:     }
                    294:     if (ctxt->query != NULL) { 
                    295:         xmlFree(ctxt->query);
                    296:        ctxt->query = NULL;
                    297:     }
                    298:     if (URL == NULL) return;
                    299: 
                    300:     uri = xmlParseURIRaw(URL, 1);
                    301:     if (uri == NULL)
                    302:        return;
                    303: 
                    304:     if ((uri->scheme == NULL) || (uri->server == NULL)) {
                    305:        xmlFreeURI(uri);
                    306:        return;
                    307:     }
                    308:     
                    309:     ctxt->protocol = xmlMemStrdup(uri->scheme);
                    310:     ctxt->hostname = xmlMemStrdup(uri->server);
                    311:     if (uri->path != NULL)
                    312:        ctxt->path = xmlMemStrdup(uri->path);
                    313:     else
                    314:        ctxt->path = xmlMemStrdup("/");
                    315:     if (uri->query != NULL)
                    316:        ctxt->query = xmlMemStrdup(uri->query);
                    317:     if (uri->port != 0)
                    318:        ctxt->port = uri->port;
                    319: 
                    320:     xmlFreeURI(uri);
                    321: }
                    322: 
                    323: /**
                    324:  * xmlNanoHTTPScanProxy:
                    325:  * @URL:  The proxy URL used to initialize the proxy context
                    326:  *
                    327:  * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
                    328:  * the protocol host port it indicates.
                    329:  * Should be like http://myproxy/ or http://myproxy:3128/
                    330:  * A NULL URL cleans up proxy informations.
                    331:  */
                    332: 
                    333: void
                    334: xmlNanoHTTPScanProxy(const char *URL) {
                    335:     xmlURIPtr uri;
                    336: 
                    337:     if (proxy != NULL) { 
                    338:         xmlFree(proxy);
                    339:        proxy = NULL;
                    340:     }
                    341:     proxyPort = 0;
                    342: 
                    343: #ifdef DEBUG_HTTP
                    344:     if (URL == NULL)
                    345:        xmlGenericError(xmlGenericErrorContext,
                    346:                "Removing HTTP proxy info\n");
                    347:     else
                    348:        xmlGenericError(xmlGenericErrorContext,
                    349:                "Using HTTP proxy %s\n", URL);
                    350: #endif
                    351:     if (URL == NULL) return;
                    352: 
                    353:     uri = xmlParseURIRaw(URL, 1);
                    354:     if ((uri == NULL) || (uri->scheme == NULL) ||
                    355:        (strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
                    356:        __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
                    357:        if (uri != NULL)
                    358:            xmlFreeURI(uri);
                    359:        return;
                    360:     }
                    361:     
                    362:     proxy = xmlMemStrdup(uri->server);
                    363:     if (uri->port != 0)
                    364:        proxyPort = uri->port;
                    365: 
                    366:     xmlFreeURI(uri);
                    367: }
                    368: 
                    369: /**
                    370:  * xmlNanoHTTPNewCtxt:
                    371:  * @URL:  The URL used to initialize the context
                    372:  *
                    373:  * Allocate and initialize a new HTTP context.
                    374:  *
                    375:  * Returns an HTTP context or NULL in case of error.
                    376:  */
                    377: 
                    378: static xmlNanoHTTPCtxtPtr
                    379: xmlNanoHTTPNewCtxt(const char *URL) {
                    380:     xmlNanoHTTPCtxtPtr ret;
                    381: 
                    382:     ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
                    383:     if (ret == NULL) {
                    384:         xmlHTTPErrMemory("allocating context");
                    385:         return(NULL);
                    386:     }
                    387: 
                    388:     memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
                    389:     ret->port = 80;
                    390:     ret->returnValue = 0;
                    391:     ret->fd = INVALID_SOCKET;
                    392:     ret->ContentLength = -1;
                    393: 
                    394:     xmlNanoHTTPScanURL(ret, URL);
                    395: 
                    396:     return(ret);
                    397: }
                    398: 
                    399: /**
                    400:  * xmlNanoHTTPFreeCtxt:
                    401:  * @ctxt:  an HTTP context
                    402:  *
                    403:  * Frees the context after closing the connection.
                    404:  */
                    405: 
                    406: static void
                    407: xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
                    408:     if (ctxt == NULL) return;
                    409:     if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
                    410:     if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
                    411:     if (ctxt->path != NULL) xmlFree(ctxt->path);
                    412:     if (ctxt->query != NULL) xmlFree(ctxt->query);
                    413:     if (ctxt->out != NULL) xmlFree(ctxt->out);
                    414:     if (ctxt->in != NULL) xmlFree(ctxt->in);
                    415:     if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
                    416:     if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
                    417:     if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
                    418:     if (ctxt->location != NULL) xmlFree(ctxt->location);
                    419:     if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
                    420: #ifdef HAVE_ZLIB_H
                    421:     if (ctxt->strm != NULL) {
                    422:        inflateEnd(ctxt->strm);
                    423:        xmlFree(ctxt->strm);
                    424:     }
                    425: #endif
                    426: 
                    427:     ctxt->state = XML_NANO_HTTP_NONE;
                    428:     if (ctxt->fd != INVALID_SOCKET) closesocket(ctxt->fd);
                    429:     ctxt->fd = INVALID_SOCKET;
                    430:     xmlFree(ctxt);
                    431: }
                    432: 
                    433: /**
                    434:  * xmlNanoHTTPSend:
                    435:  * @ctxt:  an HTTP context
                    436:  *
                    437:  * Send the input needed to initiate the processing on the server side
                    438:  * Returns number of bytes sent or -1 on error.
                    439:  */
                    440: 
                    441: static int
                    442: xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
                    443: {
                    444:     int total_sent = 0;
                    445: #ifdef HAVE_POLL_H
                    446:     struct pollfd p;
                    447: #else
                    448:     struct timeval tv;
                    449:     fd_set wfd;
                    450: #endif
                    451: 
                    452:     if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
                    453:         while (total_sent < outlen) {
                    454:             int nsent = send(ctxt->fd, xmt_ptr + total_sent,
                    455:                              outlen - total_sent, 0);
                    456: 
                    457:             if (nsent > 0)
                    458:                 total_sent += nsent;
                    459:             else if ((nsent == -1) &&
                    460: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
                    461:                      (socket_errno() != EAGAIN) &&
                    462: #endif
                    463:                      (socket_errno() != EWOULDBLOCK)) {
                    464:                 __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
                    465:                 if (total_sent == 0)
                    466:                     total_sent = -1;
                    467:                 break;
                    468:             } else {
                    469:                 /*
                    470:                  * No data sent
                    471:                  * Since non-blocking sockets are used, wait for
                    472:                  * socket to be writable or default timeout prior
                    473:                  * to retrying.
                    474:                  */
                    475: #ifndef HAVE_POLL_H
                    476: #ifndef _WINSOCKAPI_
                    477:                 if (ctxt->fd > FD_SETSIZE)
                    478:                     return -1;
                    479: #endif
                    480: 
                    481:                 tv.tv_sec = timeout;
                    482:                 tv.tv_usec = 0;
                    483:                 FD_ZERO(&wfd);
                    484: #ifdef _MSC_VER
                    485: #pragma warning(push)
                    486: #pragma warning(disable: 4018)
                    487: #endif
                    488:                 FD_SET(ctxt->fd, &wfd);
                    489: #ifdef _MSC_VER
                    490: #pragma warning(pop)
                    491: #endif
                    492:                 (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
                    493: #else
                    494:                 p.fd = ctxt->fd;
                    495:                 p.events = POLLOUT;
                    496:                 (void) poll(&p, 1, timeout * 1000);
                    497: #endif /* !HAVE_POLL_H */
                    498:             }
                    499:         }
                    500:     }
                    501: 
                    502:     return total_sent;
                    503: }
                    504: 
                    505: /**
                    506:  * xmlNanoHTTPRecv:
                    507:  * @ctxt:  an HTTP context
                    508:  *
                    509:  * Read information coming from the HTTP connection.
                    510:  * This is a blocking call (but it blocks in select(), not read()).
                    511:  *
                    512:  * Returns the number of byte read or -1 in case of error.
                    513:  */
                    514: 
                    515: static int
                    516: xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
                    517: {
                    518: #ifdef HAVE_POLL_H
                    519:     struct pollfd p;
                    520: #else
                    521:     fd_set rfd;
                    522:     struct timeval tv;
                    523: #endif
                    524: 
                    525: 
                    526:     while (ctxt->state & XML_NANO_HTTP_READ) {
                    527:         if (ctxt->in == NULL) {
                    528:             ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
                    529:             if (ctxt->in == NULL) {
                    530:                 xmlHTTPErrMemory("allocating input");
                    531:                 ctxt->last = -1;
                    532:                 return (-1);
                    533:             }
                    534:             ctxt->inlen = 65000;
                    535:             ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
                    536:         }
                    537:         if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
                    538:             int delta = ctxt->inrptr - ctxt->in;
                    539:             int len = ctxt->inptr - ctxt->inrptr;
                    540: 
                    541:             memmove(ctxt->in, ctxt->inrptr, len);
                    542:             ctxt->inrptr -= delta;
                    543:             ctxt->content -= delta;
                    544:             ctxt->inptr -= delta;
                    545:         }
                    546:         if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
                    547:             int d_inptr = ctxt->inptr - ctxt->in;
                    548:             int d_content = ctxt->content - ctxt->in;
                    549:             int d_inrptr = ctxt->inrptr - ctxt->in;
                    550:             char *tmp_ptr = ctxt->in;
                    551: 
                    552:             ctxt->inlen *= 2;
                    553:             ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
                    554:             if (ctxt->in == NULL) {
                    555:                 xmlHTTPErrMemory("allocating input buffer");
                    556:                 xmlFree(tmp_ptr);
                    557:                 ctxt->last = -1;
                    558:                 return (-1);
                    559:             }
                    560:             ctxt->inptr = ctxt->in + d_inptr;
                    561:             ctxt->content = ctxt->in + d_content;
                    562:             ctxt->inrptr = ctxt->in + d_inrptr;
                    563:         }
                    564:         ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
                    565:         if (ctxt->last > 0) {
                    566:             ctxt->inptr += ctxt->last;
                    567:             return (ctxt->last);
                    568:         }
                    569:         if (ctxt->last == 0) {
                    570:             return (0);
                    571:         }
                    572:         if (ctxt->last == -1) {
                    573:             switch (socket_errno()) {
                    574:                 case EINPROGRESS:
                    575:                 case EWOULDBLOCK:
                    576: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
                    577:                 case EAGAIN:
                    578: #endif
                    579:                     break;
                    580: 
                    581:                 case ECONNRESET:
                    582:                 case ESHUTDOWN:
                    583:                     return (0);
                    584: 
                    585:                 default:
                    586:                     __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
                    587:                     return (-1);
                    588:             }
                    589:         }
                    590: #ifdef HAVE_POLL_H
                    591:         p.fd = ctxt->fd;
                    592:         p.events = POLLIN;
                    593:         if ((poll(&p, 1, timeout * 1000) < 1)
                    594: #if defined(EINTR)
                    595:             && (errno != EINTR)
                    596: #endif
                    597:             )
                    598:             return (0);
                    599: #else /* !HAVE_POLL_H */
                    600: #ifndef _WINSOCKAPI_
                    601:         if (ctxt->fd > FD_SETSIZE)
                    602:             return 0;
                    603: #endif
                    604: 
                    605:         tv.tv_sec = timeout;
                    606:         tv.tv_usec = 0;
                    607:         FD_ZERO(&rfd);
                    608: 
                    609: #ifdef _MSC_VER
                    610: #pragma warning(push)
                    611: #pragma warning(disable: 4018)
                    612: #endif
                    613: 
                    614:         FD_SET(ctxt->fd, &rfd);
                    615: 
                    616: #ifdef _MSC_VER
                    617: #pragma warning(pop)
                    618: #endif
                    619: 
                    620:         if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
                    621: #if defined(EINTR)
                    622:             && (errno != EINTR)
                    623: #endif
                    624:             )
                    625:             return (0);
                    626: #endif /* !HAVE_POLL_H */
                    627:     }
                    628:     return (0);
                    629: }
                    630: 
                    631: /**
                    632:  * xmlNanoHTTPReadLine:
                    633:  * @ctxt:  an HTTP context
                    634:  *
                    635:  * Read one line in the HTTP server output, usually for extracting
                    636:  * the HTTP protocol informations from the answer header.
                    637:  *
                    638:  * Returns a newly allocated string with a copy of the line, or NULL
                    639:  *         which indicate the end of the input.
                    640:  */
                    641: 
                    642: static char *
                    643: xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
                    644:     char buf[4096];
                    645:     char *bp = buf;
                    646:     int        rc;
                    647:     
                    648:     while (bp - buf < 4095) {
                    649:        if (ctxt->inrptr == ctxt->inptr) {
                    650:            if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
                    651:                if (bp == buf)
                    652:                    return(NULL);
                    653:                else
                    654:                    *bp = 0;
                    655:                return(xmlMemStrdup(buf));
                    656:            }
                    657:            else if ( rc == -1 ) {
                    658:                return ( NULL );
                    659:            }
                    660:        }
                    661:        *bp = *ctxt->inrptr++;
                    662:        if (*bp == '\n') {
                    663:            *bp = 0;
                    664:            return(xmlMemStrdup(buf));
                    665:        }
                    666:        if (*bp != '\r')
                    667:            bp++;
                    668:     }
                    669:     buf[4095] = 0;
                    670:     return(xmlMemStrdup(buf));
                    671: }
                    672: 
                    673: 
                    674: /**
                    675:  * xmlNanoHTTPScanAnswer:
                    676:  * @ctxt:  an HTTP context
                    677:  * @line:  an HTTP header line
                    678:  *
                    679:  * Try to extract useful informations from the server answer.
                    680:  * We currently parse and process:
                    681:  *  - The HTTP revision/ return code
                    682:  *  - The Content-Type, Mime-Type and charset used
                    683:  *  - The Location for redirect processing.
                    684:  *
                    685:  * Returns -1 in case of failure, the file descriptor number otherwise
                    686:  */
                    687: 
                    688: static void
                    689: xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
                    690:     const char *cur = line;
                    691: 
                    692:     if (line == NULL) return;
                    693: 
                    694:     if (!strncmp(line, "HTTP/", 5)) {
                    695:         int version = 0;
                    696:        int ret = 0;
                    697: 
                    698:        cur += 5;
                    699:        while ((*cur >= '0') && (*cur <= '9')) {
                    700:            version *= 10;
                    701:            version += *cur - '0';
                    702:            cur++;
                    703:        }
                    704:        if (*cur == '.') {
                    705:            cur++;
                    706:            if ((*cur >= '0') && (*cur <= '9')) {
                    707:                version *= 10;
                    708:                version += *cur - '0';
                    709:                cur++;
                    710:            }
                    711:            while ((*cur >= '0') && (*cur <= '9'))
                    712:                cur++;
                    713:        } else
                    714:            version *= 10;
                    715:        if ((*cur != ' ') && (*cur != '\t')) return;
                    716:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    717:        if ((*cur < '0') || (*cur > '9')) return;
                    718:        while ((*cur >= '0') && (*cur <= '9')) {
                    719:            ret *= 10;
                    720:            ret += *cur - '0';
                    721:            cur++;
                    722:        }
                    723:        if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
                    724:        ctxt->returnValue = ret;
                    725:         ctxt->version = version;
                    726:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
                    727:         const xmlChar *charset, *last, *mime;
                    728:         cur += 13;
                    729:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    730:        if (ctxt->contentType != NULL)
                    731:            xmlFree(ctxt->contentType);
                    732:        ctxt->contentType = xmlMemStrdup(cur);
                    733:        mime = (const xmlChar *) cur;
                    734:        last = mime;
                    735:        while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
                    736:               (*last != ';') && (*last != ','))
                    737:            last++;
                    738:        if (ctxt->mimeType != NULL)
                    739:            xmlFree(ctxt->mimeType);
                    740:        ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
                    741:        charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
                    742:        if (charset != NULL) {
                    743:            charset += 8;
                    744:            last = charset;
                    745:            while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
                    746:                   (*last != ';') && (*last != ','))
                    747:                last++;
                    748:            if (ctxt->encoding != NULL)
                    749:                xmlFree(ctxt->encoding);
                    750:            ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
                    751:        }
                    752:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
                    753:         const xmlChar *charset, *last, *mime;
                    754:         cur += 12;
                    755:        if (ctxt->contentType != NULL) return;
                    756:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    757:        ctxt->contentType = xmlMemStrdup(cur);
                    758:        mime = (const xmlChar *) cur;
                    759:        last = mime;
                    760:        while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
                    761:               (*last != ';') && (*last != ','))
                    762:            last++;
                    763:        if (ctxt->mimeType != NULL)
                    764:            xmlFree(ctxt->mimeType);
                    765:        ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
                    766:        charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
                    767:        if (charset != NULL) {
                    768:            charset += 8;
                    769:            last = charset;
                    770:            while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
                    771:                   (*last != ';') && (*last != ','))
                    772:                last++;
                    773:            if (ctxt->encoding != NULL)
                    774:                xmlFree(ctxt->encoding);
                    775:            ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
                    776:        }
                    777:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
                    778:         cur += 9;
                    779:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    780:        if (ctxt->location != NULL)
                    781:            xmlFree(ctxt->location);
                    782:        if (*cur == '/') {
                    783:            xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
                    784:            xmlChar *tmp_loc = 
                    785:                xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
                    786:            ctxt->location = 
                    787:                (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
                    788:        } else {
                    789:            ctxt->location = xmlMemStrdup(cur);
                    790:        }
                    791:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
                    792:         cur += 17;
                    793:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    794:        if (ctxt->authHeader != NULL)
                    795:            xmlFree(ctxt->authHeader);
                    796:        ctxt->authHeader = xmlMemStrdup(cur);
                    797:     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
                    798:         cur += 19;
                    799:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    800:        if (ctxt->authHeader != NULL)
                    801:            xmlFree(ctxt->authHeader);
                    802:        ctxt->authHeader = xmlMemStrdup(cur);
                    803: #ifdef HAVE_ZLIB_H
                    804:     } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
                    805:        cur += 17;
                    806:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                    807:        if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
                    808:            ctxt->usesGzip = 1;
                    809: 
                    810:            ctxt->strm = xmlMalloc(sizeof(z_stream));
                    811: 
                    812:            if (ctxt->strm != NULL) {
                    813:                ctxt->strm->zalloc = Z_NULL;
                    814:                ctxt->strm->zfree = Z_NULL;
                    815:                ctxt->strm->opaque = Z_NULL;
                    816:                ctxt->strm->avail_in = 0;
                    817:                ctxt->strm->next_in = Z_NULL;
                    818: 
                    819:                inflateInit2( ctxt->strm, 31 );
                    820:            }
                    821:        }
                    822: #endif
                    823:     } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
                    824:        cur += 15;
                    825:        ctxt->ContentLength = strtol( cur, NULL, 10 );
                    826:     }
                    827: }
                    828: 
                    829: /**
                    830:  * xmlNanoHTTPConnectAttempt:
                    831:  * @addr:  a socket address structure
                    832:  *
                    833:  * Attempt a connection to the given IP:port endpoint. It forces
                    834:  * non-blocking semantic on the socket, and allow 60 seconds for
                    835:  * the host to answer.
                    836:  *
                    837:  * Returns -1 in case of failure, the file descriptor number otherwise
                    838:  */
                    839: 
                    840: static SOCKET
                    841: xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
                    842: {
                    843: #ifndef HAVE_POLL_H
                    844:     fd_set wfd;
                    845: #ifdef _WINSOCKAPI_
                    846:     fd_set xfd;
                    847: #endif
                    848:     struct timeval tv;
                    849: #else /* !HAVE_POLL_H */
                    850:     struct pollfd p;
                    851: #endif /* !HAVE_POLL_H */
                    852:     int status;
                    853: 
                    854:     int addrlen;
                    855: 
                    856:     SOCKET s;
                    857: 
                    858: #ifdef SUPPORT_IP6
                    859:     if (addr->sa_family == AF_INET6) {
                    860:         s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
                    861:         addrlen = sizeof(struct sockaddr_in6);
                    862:     } else
                    863: #endif
                    864:     {
                    865:         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
                    866:         addrlen = sizeof(struct sockaddr_in);
                    867:     }
                    868:     if (s == INVALID_SOCKET) {
                    869: #ifdef DEBUG_HTTP
                    870:         perror("socket");
                    871: #endif
                    872:         __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
                    873:         return INVALID_SOCKET;
                    874:     }
                    875: #ifdef _WINSOCKAPI_
                    876:     {
                    877:         u_long one = 1;
                    878: 
                    879:         status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
                    880:     }
                    881: #else /* _WINSOCKAPI_ */
                    882: #if defined(VMS)
                    883:     {
                    884:         int enable = 1;
                    885: 
                    886:         status = ioctl(s, FIONBIO, &enable);
                    887:     }
                    888: #else /* VMS */
                    889: #if defined(__BEOS__) && !defined(__HAIKU__)
                    890:     {
                    891:         bool noblock = true;
                    892: 
                    893:         status =
                    894:             setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
                    895:                        sizeof(noblock));
                    896:     }
                    897: #else /* __BEOS__ */
                    898:     if ((status = fcntl(s, F_GETFL, 0)) != -1) {
                    899: #ifdef O_NONBLOCK
                    900:         status |= O_NONBLOCK;
                    901: #else /* O_NONBLOCK */
                    902: #ifdef F_NDELAY
                    903:         status |= F_NDELAY;
                    904: #endif /* F_NDELAY */
                    905: #endif /* !O_NONBLOCK */
                    906:         status = fcntl(s, F_SETFL, status);
                    907:     }
                    908:     if (status < 0) {
                    909: #ifdef DEBUG_HTTP
                    910:         perror("nonblocking");
                    911: #endif
                    912:         __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
                    913:         closesocket(s);
                    914:         return INVALID_SOCKET;
                    915:     }
                    916: #endif /* !__BEOS__ */
                    917: #endif /* !VMS */
                    918: #endif /* !_WINSOCKAPI_ */
                    919: 
                    920:     if (connect(s, addr, addrlen) == -1) {
                    921:         switch (socket_errno()) {
                    922:             case EINPROGRESS:
                    923:             case EWOULDBLOCK:
                    924:                 break;
                    925:             default:
                    926:                 __xmlIOErr(XML_FROM_HTTP, 0,
                    927:                            "error connecting to HTTP server");
                    928:                 closesocket(s);
                    929:                 return INVALID_SOCKET;
                    930:         }
                    931:     }
                    932: #ifndef HAVE_POLL_H
                    933:     tv.tv_sec = timeout;
                    934:     tv.tv_usec = 0;
                    935: 
                    936: #ifdef _MSC_VER
                    937: #pragma warning(push)
                    938: #pragma warning(disable: 4018)
                    939: #endif
                    940: #ifndef _WINSOCKAPI_
                    941:     if (s > FD_SETSIZE)
                    942:         return INVALID_SOCKET;
                    943: #endif
                    944:     FD_ZERO(&wfd);
                    945:     FD_SET(s, &wfd);
                    946: 
                    947: #ifdef _WINSOCKAPI_
                    948:     FD_ZERO(&xfd);
                    949:     FD_SET(s, &xfd);
                    950: 
                    951:     switch (select(s + 1, NULL, &wfd, &xfd, &tv))
                    952: #else
                    953:     switch (select(s + 1, NULL, &wfd, NULL, &tv))
                    954: #endif
                    955: #ifdef _MSC_VER
                    956: #pragma warning(pop)
                    957: #endif
                    958: 
                    959: #else /* !HAVE_POLL_H */
                    960:     p.fd = s;
                    961:     p.events = POLLOUT;
                    962:     switch (poll(&p, 1, timeout * 1000))
                    963: #endif /* !HAVE_POLL_H */
                    964: 
                    965:     {
                    966:         case 0:
                    967:             /* Time out */
                    968:             __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
                    969:             closesocket(s);
                    970:             return INVALID_SOCKET;
                    971:         case -1:
                    972:             /* Ermm.. ?? */
                    973:             __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
                    974:             closesocket(s);
                    975:             return INVALID_SOCKET;
                    976:     }
                    977: 
                    978: #ifndef HAVE_POLL_H
                    979:     if (FD_ISSET(s, &wfd)
                    980: #ifdef _WINSOCKAPI_
                    981:         || FD_ISSET(s, &xfd)
                    982: #endif
                    983:         )
                    984: #else /* !HAVE_POLL_H */
                    985:     if (p.revents == POLLOUT)
                    986: #endif /* !HAVE_POLL_H */
                    987:     {
                    988:         XML_SOCKLEN_T len;
                    989: 
                    990:         len = sizeof(status);
                    991: #ifdef SO_ERROR
                    992:         if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
                    993:             0) {
                    994:             /* Solaris error code */
                    995:             __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
                    996:             return INVALID_SOCKET;
                    997:         }
                    998: #endif
                    999:         if (status) {
                   1000:             __xmlIOErr(XML_FROM_HTTP, 0,
                   1001:                        "Error connecting to remote host");
                   1002:             closesocket(s);
                   1003:             errno = status;
                   1004:             return INVALID_SOCKET;
                   1005:         }
                   1006:     } else {
                   1007:         /* pbm */
                   1008:         __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
                   1009:         closesocket(s);
                   1010:         return INVALID_SOCKET;
                   1011:     }
                   1012: 
                   1013:     return (s);
                   1014: }
                   1015: 
                   1016: /**
                   1017:  * xmlNanoHTTPConnectHost:
                   1018:  * @host:  the host name
                   1019:  * @port:  the port number
                   1020:  *
                   1021:  * Attempt a connection to the given host:port endpoint. It tries
                   1022:  * the multiple IP provided by the DNS if available.
                   1023:  *
                   1024:  * Returns -1 in case of failure, the file descriptor number otherwise
                   1025:  */
                   1026: 
                   1027: static SOCKET
                   1028: xmlNanoHTTPConnectHost(const char *host, int port)
                   1029: {
                   1030:     struct hostent *h;
                   1031:     struct sockaddr *addr = NULL;
                   1032:     struct in_addr ia;
                   1033:     struct sockaddr_in sockin;
                   1034: 
                   1035: #ifdef SUPPORT_IP6
                   1036:     struct in6_addr ia6;
                   1037:     struct sockaddr_in6 sockin6;
                   1038: #endif
                   1039:     int i;
                   1040:     SOCKET s;
                   1041: 
                   1042:     memset (&sockin, 0, sizeof(sockin));
                   1043: #ifdef SUPPORT_IP6
                   1044:     memset (&sockin6, 0, sizeof(sockin6));
                   1045: #endif
                   1046: 
                   1047: #if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
                   1048:     if (have_ipv6 ())
                   1049:     {
                   1050:        if (!(_res.options & RES_INIT))
                   1051:            res_init();
                   1052:        _res.options |= RES_USE_INET6;
                   1053:     }
                   1054: #endif
                   1055: 
                   1056: #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
                   1057:     if (have_ipv6 ())
                   1058: #endif
                   1059: #if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
                   1060:     {
                   1061:        int status;
                   1062:        struct addrinfo hints, *res, *result;
                   1063: 
                   1064:        result = NULL;
                   1065:        memset (&hints, 0,sizeof(hints));
                   1066:        hints.ai_socktype = SOCK_STREAM;
                   1067: 
                   1068:        status = getaddrinfo (host, NULL, &hints, &result);
                   1069:        if (status) {
                   1070:            __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
                   1071:            return INVALID_SOCKET;
                   1072:        }
                   1073: 
                   1074:        for (res = result; res; res = res->ai_next) {
                   1075:            if (res->ai_family == AF_INET) {
                   1076:                if (res->ai_addrlen > sizeof(sockin)) {
                   1077:                    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
                   1078:                    freeaddrinfo (result);
                   1079:                    return INVALID_SOCKET;
                   1080:                }
                   1081:                memcpy (&sockin, res->ai_addr, res->ai_addrlen);
                   1082:                sockin.sin_port = htons (port);
                   1083:                addr = (struct sockaddr *)&sockin;
                   1084: #ifdef SUPPORT_IP6
                   1085:            } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
                   1086:                if (res->ai_addrlen > sizeof(sockin6)) {
                   1087:                    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
                   1088:                    freeaddrinfo (result);
                   1089:                    return INVALID_SOCKET;
                   1090:                }
                   1091:                memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
                   1092:                sockin6.sin6_port = htons (port);
                   1093:                addr = (struct sockaddr *)&sockin6;
                   1094: #endif
                   1095:            } else
                   1096:                continue;              /* for */
                   1097: 
                   1098:            s = xmlNanoHTTPConnectAttempt (addr);
                   1099:            if (s != INVALID_SOCKET) {
                   1100:                freeaddrinfo (result);
                   1101:                return (s);
                   1102:            }
                   1103:        }
                   1104: 
                   1105:        if (result)
                   1106:            freeaddrinfo (result);
                   1107:     }
                   1108: #endif
                   1109: #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
                   1110:     else
                   1111: #endif
                   1112: #if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
                   1113:     {
                   1114:        h = gethostbyname (host);
                   1115:        if (h == NULL) {
                   1116: 
                   1117: /*
                   1118:  * Okay, I got fed up by the non-portability of this error message
                   1119:  * extraction code. it work on Linux, if it work on your platform
                   1120:  * and one want to enable it, send me the defined(foobar) needed
                   1121:  */
                   1122: #if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
                   1123:            const char *h_err_txt = "";
                   1124: 
                   1125:            switch (h_errno) {
                   1126:                case HOST_NOT_FOUND:
                   1127:                    h_err_txt = "Authoritive host not found";
                   1128:                    break;
                   1129: 
                   1130:                case TRY_AGAIN:
                   1131:                    h_err_txt =
                   1132:                        "Non-authoritive host not found or server failure.";
                   1133:                    break;
                   1134: 
                   1135:                case NO_RECOVERY:
                   1136:                    h_err_txt =
                   1137:                        "Non-recoverable errors:  FORMERR, REFUSED, or NOTIMP.";
                   1138:                    break;
                   1139: 
1.1.1.2 ! misho    1140: #ifdef NO_ADDRESS
1.1       misho    1141:                case NO_ADDRESS:
                   1142:                    h_err_txt =
                   1143:                        "Valid name, no data record of requested type.";
                   1144:                    break;
1.1.1.2 ! misho    1145: #endif
1.1       misho    1146: 
                   1147:                default:
                   1148:                    h_err_txt = "No error text defined.";
                   1149:                    break;
                   1150:            }
                   1151:            __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
                   1152: #else
                   1153:            __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
                   1154: #endif
                   1155:            return INVALID_SOCKET;
                   1156:        }
                   1157: 
                   1158:        for (i = 0; h->h_addr_list[i]; i++) {
                   1159:            if (h->h_addrtype == AF_INET) {
                   1160:                /* A records (IPv4) */
                   1161:                if ((unsigned int) h->h_length > sizeof(ia)) {
                   1162:                    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
                   1163:                    return INVALID_SOCKET;
                   1164:                }
                   1165:                memcpy (&ia, h->h_addr_list[i], h->h_length);
                   1166:                sockin.sin_family = h->h_addrtype;
                   1167:                sockin.sin_addr = ia;
1.1.1.2 ! misho    1168:                sockin.sin_port = (unsigned short)htons ((unsigned short)port);
1.1       misho    1169:                addr = (struct sockaddr *) &sockin;
                   1170: #ifdef SUPPORT_IP6
                   1171:            } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
                   1172:                /* AAAA records (IPv6) */
                   1173:                if ((unsigned int) h->h_length > sizeof(ia6)) {
                   1174:                    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
                   1175:                    return INVALID_SOCKET;
                   1176:                }
                   1177:                memcpy (&ia6, h->h_addr_list[i], h->h_length);
                   1178:                sockin6.sin6_family = h->h_addrtype;
                   1179:                sockin6.sin6_addr = ia6;
                   1180:                sockin6.sin6_port = htons (port);
                   1181:                addr = (struct sockaddr *) &sockin6;
                   1182: #endif
                   1183:            } else
                   1184:                break;              /* for */
                   1185: 
                   1186:            s = xmlNanoHTTPConnectAttempt (addr);
                   1187:            if (s != INVALID_SOCKET)
                   1188:                return (s);
                   1189:        }
                   1190:     }
                   1191: #endif
                   1192: 
                   1193: #ifdef DEBUG_HTTP
                   1194:     xmlGenericError(xmlGenericErrorContext,
                   1195:                     "xmlNanoHTTPConnectHost:  unable to connect to '%s'.\n",
                   1196:                     host);
                   1197: #endif
                   1198:     return INVALID_SOCKET;
                   1199: }
                   1200: 
                   1201: 
                   1202: /**
                   1203:  * xmlNanoHTTPOpen:
                   1204:  * @URL:  The URL to load
                   1205:  * @contentType:  if available the Content-Type information will be
                   1206:  *                returned at that location
                   1207:  *
                   1208:  * This function try to open a connection to the indicated resource
                   1209:  * via HTTP GET.
                   1210:  *
                   1211:  * Returns NULL in case of failure, otherwise a request handler.
                   1212:  *     The contentType, if provided must be freed by the caller
                   1213:  */
                   1214: 
                   1215: void*
                   1216: xmlNanoHTTPOpen(const char *URL, char **contentType) {
                   1217:     if (contentType != NULL) *contentType = NULL;
                   1218:     return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
                   1219: }
                   1220: 
                   1221: /**
                   1222:  * xmlNanoHTTPOpenRedir:
                   1223:  * @URL:  The URL to load
                   1224:  * @contentType:  if available the Content-Type information will be
                   1225:  *                returned at that location
                   1226:  * @redir: if available the redirected URL will be returned
                   1227:  *
                   1228:  * This function try to open a connection to the indicated resource
                   1229:  * via HTTP GET.
                   1230:  *
                   1231:  * Returns NULL in case of failure, otherwise a request handler.
                   1232:  *     The contentType, if provided must be freed by the caller
                   1233:  */
                   1234: 
                   1235: void*
                   1236: xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
                   1237:     if (contentType != NULL) *contentType = NULL;
                   1238:     if (redir != NULL) *redir = NULL;
                   1239:     return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
                   1240: }
                   1241: 
                   1242: /**
                   1243:  * xmlNanoHTTPRead:
                   1244:  * @ctx:  the HTTP context
                   1245:  * @dest:  a buffer
                   1246:  * @len:  the buffer length
                   1247:  *
                   1248:  * This function tries to read @len bytes from the existing HTTP connection
                   1249:  * and saves them in @dest. This is a blocking call.
                   1250:  *
                   1251:  * Returns the number of byte read. 0 is an indication of an end of connection.
                   1252:  *         -1 indicates a parameter error.
                   1253:  */
                   1254: int
                   1255: xmlNanoHTTPRead(void *ctx, void *dest, int len) {
                   1256:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                   1257: #ifdef HAVE_ZLIB_H
                   1258:     int bytes_read = 0;
                   1259:     int orig_avail_in;
                   1260:     int z_ret;
                   1261: #endif
                   1262: 
                   1263:     if (ctx == NULL) return(-1);
                   1264:     if (dest == NULL) return(-1);
                   1265:     if (len <= 0) return(0);
                   1266: 
                   1267: #ifdef HAVE_ZLIB_H
                   1268:     if (ctxt->usesGzip == 1) {
                   1269:         if (ctxt->strm == NULL) return(0);
                   1270:  
                   1271:         ctxt->strm->next_out = dest;
                   1272:         ctxt->strm->avail_out = len;
                   1273:        ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
                   1274: 
                   1275:         while (ctxt->strm->avail_out > 0 &&
                   1276:               (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
                   1277:             orig_avail_in = ctxt->strm->avail_in =
                   1278:                            ctxt->inptr - ctxt->inrptr - bytes_read;
                   1279:             ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
                   1280: 
                   1281:             z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
                   1282:             bytes_read += orig_avail_in - ctxt->strm->avail_in;
                   1283: 
                   1284:             if (z_ret != Z_OK) break;
                   1285:        }
                   1286: 
                   1287:         ctxt->inrptr += bytes_read;
                   1288:         return(len - ctxt->strm->avail_out);
                   1289:     }
                   1290: #endif
                   1291: 
                   1292:     while (ctxt->inptr - ctxt->inrptr < len) {
                   1293:         if (xmlNanoHTTPRecv(ctxt) <= 0) break;
                   1294:     }
                   1295:     if (ctxt->inptr - ctxt->inrptr < len)
                   1296:         len = ctxt->inptr - ctxt->inrptr;
                   1297:     memcpy(dest, ctxt->inrptr, len);
                   1298:     ctxt->inrptr += len;
                   1299:     return(len);
                   1300: }
                   1301: 
                   1302: /**
                   1303:  * xmlNanoHTTPClose:
                   1304:  * @ctx:  the HTTP context
                   1305:  *
                   1306:  * This function closes an HTTP context, it ends up the connection and
                   1307:  * free all data related to it.
                   1308:  */
                   1309: void
                   1310: xmlNanoHTTPClose(void *ctx) {
                   1311:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                   1312: 
                   1313:     if (ctx == NULL) return;
                   1314: 
                   1315:     xmlNanoHTTPFreeCtxt(ctxt);
                   1316: }
                   1317: 
                   1318: /**
                   1319:  * xmlNanoHTTPMethodRedir:
                   1320:  * @URL:  The URL to load
                   1321:  * @method:  the HTTP method to use
                   1322:  * @input:  the input string if any
                   1323:  * @contentType:  the Content-Type information IN and OUT
                   1324:  * @redir:  the redirected URL OUT
                   1325:  * @headers:  the extra headers
                   1326:  * @ilen:  input length
                   1327:  *
                   1328:  * This function try to open a connection to the indicated resource
                   1329:  * via HTTP using the given @method, adding the given extra headers
                   1330:  * and the input buffer for the request content.
                   1331:  *
                   1332:  * Returns NULL in case of failure, otherwise a request handler.
                   1333:  *     The contentType, or redir, if provided must be freed by the caller
                   1334:  */
                   1335: 
                   1336: void*
                   1337: xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
                   1338:                   char **contentType, char **redir,
                   1339:                  const char *headers, int ilen ) {
                   1340:     xmlNanoHTTPCtxtPtr ctxt;
                   1341:     char *bp, *p;
                   1342:     int blen;
                   1343:     SOCKET ret;
                   1344:     int nbRedirects = 0;
                   1345:     char *redirURL = NULL;
                   1346: #ifdef DEBUG_HTTP
                   1347:     int xmt_bytes;
                   1348: #endif
                   1349:     
                   1350:     if (URL == NULL) return(NULL);
                   1351:     if (method == NULL) method = "GET";
                   1352:     xmlNanoHTTPInit();
                   1353: 
                   1354: retry:
                   1355:     if (redirURL == NULL)
                   1356:        ctxt = xmlNanoHTTPNewCtxt(URL);
                   1357:     else {
                   1358:        ctxt = xmlNanoHTTPNewCtxt(redirURL);
                   1359:        ctxt->location = xmlMemStrdup(redirURL);
                   1360:     }
                   1361: 
                   1362:     if ( ctxt == NULL ) {
                   1363:        return ( NULL );
                   1364:     }
                   1365: 
                   1366:     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
                   1367:        __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
                   1368:         xmlNanoHTTPFreeCtxt(ctxt);
                   1369:        if (redirURL != NULL) xmlFree(redirURL);
                   1370:         return(NULL);
                   1371:     }
                   1372:     if (ctxt->hostname == NULL) {
                   1373:        __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
                   1374:                   "Failed to identify host in URI");
                   1375:         xmlNanoHTTPFreeCtxt(ctxt);
                   1376:        if (redirURL != NULL) xmlFree(redirURL);
                   1377:         return(NULL);
                   1378:     }
                   1379:     if (proxy) {
                   1380:        blen = strlen(ctxt->hostname) * 2 + 16;
                   1381:        ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
                   1382:     }
                   1383:     else {
                   1384:        blen = strlen(ctxt->hostname);
                   1385:        ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
                   1386:     }
                   1387:     if (ret == INVALID_SOCKET) {
                   1388:         xmlNanoHTTPFreeCtxt(ctxt);
                   1389:        if (redirURL != NULL) xmlFree(redirURL);
                   1390:         return(NULL);
                   1391:     }
                   1392:     ctxt->fd = ret;
                   1393: 
                   1394:     if (input == NULL)
                   1395:        ilen = 0;
                   1396:     else
                   1397:        blen += 36;
                   1398: 
                   1399:     if (headers != NULL)
                   1400:        blen += strlen(headers) + 2;
                   1401:     if (contentType && *contentType)
                   1402:        /* reserve for string plus 'Content-Type: \r\n" */
                   1403:        blen += strlen(*contentType) + 16;
                   1404:     if (ctxt->query != NULL)
                   1405:        /* 1 for '?' */
                   1406:        blen += strlen(ctxt->query) + 1;
                   1407:     blen += strlen(method) + strlen(ctxt->path) + 24;
                   1408: #ifdef HAVE_ZLIB_H
                   1409:     /* reserve for possible 'Accept-Encoding: gzip' string */
                   1410:     blen += 23;
                   1411: #endif
                   1412:     if (ctxt->port != 80) {
                   1413:        /* reserve space for ':xxxxx', incl. potential proxy */
                   1414:        if (proxy)
                   1415:            blen += 12;
                   1416:        else
                   1417:            blen += 6;
                   1418:     }
                   1419:     bp = (char*)xmlMallocAtomic(blen);
                   1420:     if ( bp == NULL ) {
                   1421:         xmlNanoHTTPFreeCtxt( ctxt );
                   1422:        xmlHTTPErrMemory("allocating header buffer");
                   1423:        return ( NULL );
                   1424:     }
                   1425: 
                   1426:     p = bp;
                   1427: 
                   1428:     if (proxy) {
                   1429:        if (ctxt->port != 80) {
                   1430:            p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 
                   1431:                        method, ctxt->hostname,
                   1432:                        ctxt->port, ctxt->path );
                   1433:        }
                   1434:        else 
                   1435:            p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
                   1436:                        ctxt->hostname, ctxt->path);
                   1437:     }
                   1438:     else
                   1439:        p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
                   1440: 
                   1441:     if (ctxt->query != NULL)
                   1442:        p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
                   1443: 
                   1444:     if (ctxt->port == 80) {
                   1445:         p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n", 
                   1446:                    ctxt->hostname);
                   1447:     } else {
                   1448:         p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
                   1449:                    ctxt->hostname, ctxt->port);
                   1450:     }
                   1451: 
                   1452: #ifdef HAVE_ZLIB_H
                   1453:     p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
                   1454: #endif
                   1455: 
                   1456:     if (contentType != NULL && *contentType) 
                   1457:        p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
                   1458: 
                   1459:     if (headers != NULL)
                   1460:        p += snprintf( p, blen - (p - bp), "%s", headers );
                   1461: 
                   1462:     if (input != NULL)
                   1463:        snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
                   1464:     else
                   1465:        snprintf(p, blen - (p - bp), "\r\n");
                   1466: 
                   1467: #ifdef DEBUG_HTTP
                   1468:     xmlGenericError(xmlGenericErrorContext,
                   1469:            "-> %s%s", proxy? "(Proxy) " : "", bp);
                   1470:     if ((blen -= strlen(bp)+1) < 0)
                   1471:        xmlGenericError(xmlGenericErrorContext,
                   1472:                "ERROR: overflowed buffer by %d bytes\n", -blen);
                   1473: #endif
                   1474:     ctxt->outptr = ctxt->out = bp;
                   1475:     ctxt->state = XML_NANO_HTTP_WRITE;
                   1476:     blen = strlen( ctxt->out );
                   1477: #ifdef DEBUG_HTTP
                   1478:     xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
                   1479:     if ( xmt_bytes != blen )
                   1480:         xmlGenericError( xmlGenericErrorContext,
                   1481:                        "xmlNanoHTTPMethodRedir:  Only %d of %d %s %s\n",
                   1482:                        xmt_bytes, blen,
                   1483:                        "bytes of HTTP headers sent to host",
                   1484:                        ctxt->hostname );
                   1485: #else
                   1486:     xmlNanoHTTPSend(ctxt, ctxt->out, blen );
                   1487: #endif
                   1488: 
                   1489:     if ( input != NULL ) {
                   1490: #ifdef DEBUG_HTTP
                   1491:         xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
                   1492: 
                   1493:        if ( xmt_bytes != ilen )
                   1494:            xmlGenericError( xmlGenericErrorContext,
                   1495:                        "xmlNanoHTTPMethodRedir:  Only %d of %d %s %s\n",
                   1496:                        xmt_bytes, ilen,
                   1497:                        "bytes of HTTP content sent to host",
                   1498:                        ctxt->hostname );
                   1499: #else
                   1500:        xmlNanoHTTPSend( ctxt, input, ilen );
                   1501: #endif
                   1502:     }
                   1503: 
                   1504:     ctxt->state = XML_NANO_HTTP_READ;
                   1505: 
                   1506:     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
                   1507:         if (*p == 0) {
                   1508:            ctxt->content = ctxt->inrptr;
                   1509:            xmlFree(p);
                   1510:            break;
                   1511:        }
                   1512:        xmlNanoHTTPScanAnswer(ctxt, p);
                   1513: 
                   1514: #ifdef DEBUG_HTTP
                   1515:        xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
                   1516: #endif
                   1517:         xmlFree(p);
                   1518:     }
                   1519: 
                   1520:     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
                   1521:         (ctxt->returnValue < 400)) {
                   1522: #ifdef DEBUG_HTTP
                   1523:        xmlGenericError(xmlGenericErrorContext,
                   1524:                "\nRedirect to: %s\n", ctxt->location);
                   1525: #endif
                   1526:        while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
                   1527:         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
                   1528:            nbRedirects++;
                   1529:            if (redirURL != NULL)
                   1530:                xmlFree(redirURL);
                   1531:            redirURL = xmlMemStrdup(ctxt->location);
                   1532:            xmlNanoHTTPFreeCtxt(ctxt);
                   1533:            goto retry;
                   1534:        }
                   1535:        xmlNanoHTTPFreeCtxt(ctxt);
                   1536:        if (redirURL != NULL) xmlFree(redirURL);
                   1537: #ifdef DEBUG_HTTP
                   1538:        xmlGenericError(xmlGenericErrorContext,
                   1539:                "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
                   1540: #endif
                   1541:        return(NULL);
                   1542:     }
                   1543: 
                   1544:     if (contentType != NULL) {
                   1545:        if (ctxt->contentType != NULL)
                   1546:            *contentType = xmlMemStrdup(ctxt->contentType);
                   1547:        else
                   1548:            *contentType = NULL;
                   1549:     }
                   1550: 
                   1551:     if ((redir != NULL) && (redirURL != NULL)) {
                   1552:        *redir = redirURL;
                   1553:     } else {
                   1554:        if (redirURL != NULL)
                   1555:            xmlFree(redirURL);
                   1556:        if (redir != NULL)
                   1557:            *redir = NULL;
                   1558:     }
                   1559: 
                   1560: #ifdef DEBUG_HTTP
                   1561:     if (ctxt->contentType != NULL)
                   1562:        xmlGenericError(xmlGenericErrorContext,
                   1563:                "\nCode %d, content-type '%s'\n\n",
                   1564:               ctxt->returnValue, ctxt->contentType);
                   1565:     else
                   1566:        xmlGenericError(xmlGenericErrorContext,
                   1567:                "\nCode %d, no content-type\n\n",
                   1568:               ctxt->returnValue);
                   1569: #endif
                   1570: 
                   1571:     return((void *) ctxt);
                   1572: }
                   1573: 
                   1574: /**
                   1575:  * xmlNanoHTTPMethod:
                   1576:  * @URL:  The URL to load
                   1577:  * @method:  the HTTP method to use
                   1578:  * @input:  the input string if any
                   1579:  * @contentType:  the Content-Type information IN and OUT
                   1580:  * @headers:  the extra headers
                   1581:  * @ilen:  input length
                   1582:  *
                   1583:  * This function try to open a connection to the indicated resource
                   1584:  * via HTTP using the given @method, adding the given extra headers
                   1585:  * and the input buffer for the request content.
                   1586:  *
                   1587:  * Returns NULL in case of failure, otherwise a request handler.
                   1588:  *     The contentType, if provided must be freed by the caller
                   1589:  */
                   1590: 
                   1591: void*
                   1592: xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
                   1593:                   char **contentType, const char *headers, int ilen) {
                   1594:     return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
                   1595:                                  NULL, headers, ilen));
                   1596: }
                   1597: 
                   1598: /**
                   1599:  * xmlNanoHTTPFetch:
                   1600:  * @URL:  The URL to load
                   1601:  * @filename:  the filename where the content should be saved
                   1602:  * @contentType:  if available the Content-Type information will be
                   1603:  *                returned at that location
                   1604:  *
                   1605:  * This function try to fetch the indicated resource via HTTP GET
                   1606:  * and save it's content in the file.
                   1607:  *
                   1608:  * Returns -1 in case of failure, 0 incase of success. The contentType,
                   1609:  *     if provided must be freed by the caller
                   1610:  */
                   1611: int
                   1612: xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
                   1613:     void *ctxt = NULL;
                   1614:     char *buf = NULL;
                   1615:     int fd;
                   1616:     int len;
1.1.1.2 ! misho    1617:     int ret = 0;
        !          1618: 
1.1       misho    1619:     if (filename == NULL) return(-1);
                   1620:     ctxt = xmlNanoHTTPOpen(URL, contentType);
                   1621:     if (ctxt == NULL) return(-1);
                   1622: 
                   1623:     if (!strcmp(filename, "-")) 
                   1624:         fd = 0;
                   1625:     else {
                   1626:         fd = open(filename, O_CREAT | O_WRONLY, 00644);
                   1627:        if (fd < 0) {
                   1628:            xmlNanoHTTPClose(ctxt);
                   1629:            if ((contentType != NULL) && (*contentType != NULL)) {
                   1630:                xmlFree(*contentType);
                   1631:                *contentType = NULL;
                   1632:            }
                   1633:            return(-1);
                   1634:        }
                   1635:     }
                   1636: 
                   1637:     xmlNanoHTTPFetchContent( ctxt, &buf, &len );
                   1638:     if ( len > 0 ) {
1.1.1.2 ! misho    1639:        if (write(fd, buf, len) == -1) {
        !          1640:            ret = -1;
        !          1641:        }
1.1       misho    1642:     }
                   1643: 
                   1644:     xmlNanoHTTPClose(ctxt);
                   1645:     close(fd);
1.1.1.2 ! misho    1646:     return(ret);
1.1       misho    1647: }
                   1648: 
                   1649: #ifdef LIBXML_OUTPUT_ENABLED
                   1650: /**
                   1651:  * xmlNanoHTTPSave:
                   1652:  * @ctxt:  the HTTP context
                   1653:  * @filename:  the filename where the content should be saved
                   1654:  *
                   1655:  * This function saves the output of the HTTP transaction to a file
                   1656:  * It closes and free the context at the end
                   1657:  *
                   1658:  * Returns -1 in case of failure, 0 incase of success.
                   1659:  */
                   1660: int
                   1661: xmlNanoHTTPSave(void *ctxt, const char *filename) {
                   1662:     char *buf = NULL;
                   1663:     int fd;
                   1664:     int len;
1.1.1.2 ! misho    1665:     int ret = 0;
        !          1666: 
1.1       misho    1667:     if ((ctxt == NULL) || (filename == NULL)) return(-1);
                   1668: 
                   1669:     if (!strcmp(filename, "-")) 
                   1670:         fd = 0;
                   1671:     else {
                   1672:         fd = open(filename, O_CREAT | O_WRONLY, 0666);
                   1673:        if (fd < 0) {
                   1674:            xmlNanoHTTPClose(ctxt);
                   1675:            return(-1);
                   1676:        }
                   1677:     }
                   1678: 
                   1679:     xmlNanoHTTPFetchContent( ctxt, &buf, &len );
                   1680:     if ( len > 0 ) {
1.1.1.2 ! misho    1681:        if (write(fd, buf, len) == -1) {
        !          1682:            ret = -1;
        !          1683:        }
1.1       misho    1684:     }
                   1685: 
                   1686:     xmlNanoHTTPClose(ctxt);
                   1687:     close(fd);
1.1.1.2 ! misho    1688:     return(ret);
1.1       misho    1689: }
                   1690: #endif /* LIBXML_OUTPUT_ENABLED */
                   1691: 
                   1692: /**
                   1693:  * xmlNanoHTTPReturnCode:
                   1694:  * @ctx:  the HTTP context
                   1695:  *
                   1696:  * Get the latest HTTP return code received
                   1697:  *
                   1698:  * Returns the HTTP return code for the request.
                   1699:  */
                   1700: int
                   1701: xmlNanoHTTPReturnCode(void *ctx) {
                   1702:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                   1703: 
                   1704:     if (ctxt == NULL) return(-1);
                   1705: 
                   1706:     return(ctxt->returnValue);
                   1707: }
                   1708: 
                   1709: /**
                   1710:  * xmlNanoHTTPAuthHeader:
                   1711:  * @ctx:  the HTTP context
                   1712:  *
                   1713:  * Get the authentication header of an HTTP context
                   1714:  *
                   1715:  * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
                   1716:  * header.
                   1717:  */
                   1718: const char *
                   1719: xmlNanoHTTPAuthHeader(void *ctx) {
                   1720:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
                   1721: 
                   1722:     if (ctxt == NULL) return(NULL);
                   1723: 
                   1724:     return(ctxt->authHeader);
                   1725: }
                   1726: 
                   1727: /**
                   1728:  * xmlNanoHTTPContentLength:
                   1729:  * @ctx:  the HTTP context
                   1730:  *
                   1731:  * Provides the specified content length from the HTTP header.
                   1732:  *
                   1733:  * Return the specified content length from the HTTP header.  Note that
                   1734:  * a value of -1 indicates that the content length element was not included in
                   1735:  * the response header.
                   1736:  */
                   1737: int
                   1738: xmlNanoHTTPContentLength( void * ctx ) {
                   1739:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
                   1740: 
                   1741:     return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
                   1742: }
                   1743: 
                   1744: /**
                   1745:  * xmlNanoHTTPRedir:
                   1746:  * @ctx:  the HTTP context
                   1747:  *
                   1748:  * Provides the specified redirection URL if available from the HTTP header.
                   1749:  *
                   1750:  * Return the specified redirection URL or NULL if not redirected.
                   1751:  */
                   1752: const char *
                   1753: xmlNanoHTTPRedir( void * ctx ) {
                   1754:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
                   1755: 
                   1756:     return ( ( ctxt == NULL ) ? NULL : ctxt->location );
                   1757: }
                   1758: 
                   1759: /**
                   1760:  * xmlNanoHTTPEncoding:
                   1761:  * @ctx:  the HTTP context
                   1762:  *
                   1763:  * Provides the specified encoding if specified in the HTTP headers.
                   1764:  *
                   1765:  * Return the specified encoding or NULL if not available
                   1766:  */
                   1767: const char *
                   1768: xmlNanoHTTPEncoding( void * ctx ) {
                   1769:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
                   1770: 
                   1771:     return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
                   1772: }
                   1773: 
                   1774: /**
                   1775:  * xmlNanoHTTPMimeType:
                   1776:  * @ctx:  the HTTP context
                   1777:  *
                   1778:  * Provides the specified Mime-Type if specified in the HTTP headers.
                   1779:  *
                   1780:  * Return the specified Mime-Type or NULL if not available
                   1781:  */
                   1782: const char *
                   1783: xmlNanoHTTPMimeType( void * ctx ) {
                   1784:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
                   1785: 
                   1786:     return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
                   1787: }
                   1788: 
                   1789: /**
                   1790:  * xmlNanoHTTPFetchContent:
                   1791:  * @ctx:  the HTTP context
                   1792:  * @ptr:  pointer to set to the content buffer.
                   1793:  * @len:  integer pointer to hold the length of the content
                   1794:  *
                   1795:  * Check if all the content was read
                   1796:  *
                   1797:  * Returns 0 if all the content was read and available, returns
                   1798:  * -1 if received content length was less than specified or an error 
                   1799:  * occurred.
                   1800:  */
                   1801: static int
                   1802: xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
                   1803:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
                   1804: 
                   1805:     int                        rc = 0;
                   1806:     int                        cur_lgth;
                   1807:     int                        rcvd_lgth;
                   1808:     int                        dummy_int;
                   1809:     char *             dummy_ptr = NULL;
                   1810: 
                   1811:     /*  Dummy up return input parameters if not provided  */
                   1812: 
                   1813:     if ( len == NULL )
                   1814:         len = &dummy_int;
                   1815: 
                   1816:     if ( ptr == NULL )
                   1817:         ptr = &dummy_ptr;
                   1818: 
                   1819:     /*  But can't work without the context pointer  */
                   1820: 
                   1821:     if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
                   1822:         *len = 0;
                   1823:        *ptr = NULL;
                   1824:        return ( -1 );
                   1825:     }
                   1826: 
                   1827:     rcvd_lgth = ctxt->inptr - ctxt->content;
                   1828: 
                   1829:     while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
                   1830: 
                   1831:        rcvd_lgth += cur_lgth;
                   1832:        if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
                   1833:            break;
                   1834:     }
                   1835: 
                   1836:     *ptr = ctxt->content;
                   1837:     *len = rcvd_lgth;
                   1838: 
                   1839:     if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
                   1840:         rc = -1;
                   1841:     else if ( rcvd_lgth == 0 )
                   1842:        rc = -1;
                   1843: 
                   1844:     return ( rc );
                   1845: }
                   1846: 
                   1847: #ifdef STANDALONE
                   1848: int main(int argc, char **argv) {
                   1849:     char *contentType = NULL;
                   1850: 
                   1851:     if (argv[1] != NULL) {
                   1852:        if (argv[2] != NULL) 
                   1853:            xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
                   1854:         else
                   1855:            xmlNanoHTTPFetch(argv[1], "-", &contentType);
                   1856:        if (contentType != NULL) xmlFree(contentType);
                   1857:     } else {
                   1858:         xmlGenericError(xmlGenericErrorContext,
                   1859:                "%s: minimal HTTP GET implementation\n", argv[0]);
                   1860:         xmlGenericError(xmlGenericErrorContext,
                   1861:                "\tusage %s [ URL [ filename ] ]\n", argv[0]);
                   1862:     }
                   1863:     xmlNanoHTTPCleanup();
                   1864:     xmlMemoryDump();
                   1865:     return(0);
                   1866: }
                   1867: #endif /* STANDALONE */
                   1868: #else /* !LIBXML_HTTP_ENABLED */
                   1869: #ifdef STANDALONE
                   1870: #include <stdio.h>
                   1871: int main(int argc, char **argv) {
                   1872:     xmlGenericError(xmlGenericErrorContext,
                   1873:            "%s : HTTP support not compiled in\n", argv[0]);
                   1874:     return(0);
                   1875: }
                   1876: #endif /* STANDALONE */
                   1877: #endif /* LIBXML_HTTP_ENABLED */
                   1878: #define bottom_nanohttp
                   1879: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>