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