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