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

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

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