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