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