File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / nanohttp.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:57 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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