File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / nanohttp.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:29 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

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

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