File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / nanohttp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:19 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

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

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