Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygennanohttp.c
Go to the documentation of this file.
00001 /* 00002 * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets. 00003 * focuses on size, streamability, reentrancy and portability 00004 * 00005 * This is clearly not a general purpose HTTP implementation 00006 * If you look for one, check: 00007 * http://www.w3.org/Library/ 00008 * 00009 * See Copyright for the status of this software. 00010 * 00011 * daniel@veillard.com 00012 */ 00013 00014 #define NEED_SOCKETS 00015 #define IN_LIBXML 00016 #include "libxml.h" 00017 00018 #ifdef LIBXML_HTTP_ENABLED 00019 #include <string.h> 00020 00021 #ifdef HAVE_STDLIB_H 00022 #include <stdlib.h> 00023 #endif 00024 #ifdef HAVE_UNISTD_H 00025 #include <unistd.h> 00026 #endif 00027 #ifdef HAVE_SYS_TYPES_H 00028 #include <sys/types.h> 00029 #endif 00030 #ifdef HAVE_SYS_SOCKET_H 00031 #include <sys/socket.h> 00032 #endif 00033 #ifdef HAVE_NETINET_IN_H 00034 #include <netinet/in.h> 00035 #endif 00036 #ifdef HAVE_ARPA_INET_H 00037 #include <arpa/inet.h> 00038 #endif 00039 #ifdef HAVE_NETDB_H 00040 #include <netdb.h> 00041 #endif 00042 #ifdef HAVE_RESOLV_H 00043 #ifdef HAVE_ARPA_NAMESER_H 00044 #include <arpa/nameser.h> 00045 #endif 00046 #include <resolv.h> 00047 #endif 00048 #ifdef HAVE_FCNTL_H 00049 #include <fcntl.h> 00050 #endif 00051 #ifdef HAVE_ERRNO_H 00052 #include <errno.h> 00053 #endif 00054 #ifdef HAVE_SYS_TIME_H 00055 #include <sys/time.h> 00056 #endif 00057 #ifndef HAVE_POLL_H 00058 #ifdef HAVE_SYS_SELECT_H 00059 #include <sys/select.h> 00060 #endif 00061 #else 00062 #include <poll.h> 00063 #endif 00064 #ifdef HAVE_STRINGS_H 00065 #include <strings.h> 00066 #endif 00067 #ifdef SUPPORT_IP6 00068 #include <resolv.h> 00069 #endif 00070 #ifdef HAVE_ZLIB_H 00071 #include <zlib.h> 00072 #endif 00073 00074 00075 #ifdef VMS 00076 #include <stropts> 00077 #define XML_SOCKLEN_T unsigned int 00078 #endif 00079 00080 #if defined(__MINGW32__) || defined(_WIN32_WCE) 00081 #ifndef _WINSOCKAPI_ 00082 #define _WINSOCKAPI_ 00083 #endif 00084 #include <wsockcompat.h> 00085 #include <winsock2.h> 00086 #undef XML_SOCKLEN_T 00087 #define XML_SOCKLEN_T unsigned int 00088 #endif 00089 00090 #include <libxml/globals.h> 00091 #include <libxml/xmlerror.h> 00092 #include <libxml/xmlmemory.h> 00093 #include <libxml/parser.h> /* for xmlStr(n)casecmp() */ 00094 #include <libxml/nanohttp.h> 00095 #include <libxml/globals.h> 00096 #include <libxml/uri.h> 00097 00101 #ifndef _WINSOCKAPI_ 00102 #if !defined(__BEOS__) || defined(__HAIKU__) 00103 #define closesocket(s) close(s) 00104 #endif 00105 #define SOCKET int 00106 #define INVALID_SOCKET (-1) 00107 #endif 00108 00109 #ifdef __BEOS__ 00110 #ifndef PF_INET 00111 #define PF_INET AF_INET 00112 #endif 00113 #endif 00114 00115 #ifndef XML_SOCKLEN_T 00116 #define XML_SOCKLEN_T unsigned int 00117 #endif 00118 00119 #ifdef STANDALONE 00120 #define DEBUG_HTTP 00121 #define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n) 00122 #define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b) 00123 #endif 00124 00125 #define XML_NANO_HTTP_MAX_REDIR 10 00126 00127 #define XML_NANO_HTTP_CHUNK 4096 00128 00129 #define XML_NANO_HTTP_CLOSED 0 00130 #define XML_NANO_HTTP_WRITE 1 00131 #define XML_NANO_HTTP_READ 2 00132 #define XML_NANO_HTTP_NONE 4 00133 00134 typedef struct xmlNanoHTTPCtxt { 00135 char *protocol; /* the protocol name */ 00136 char *hostname; /* the host name */ 00137 int port; /* the port */ 00138 char *path; /* the path within the URL */ 00139 char *query; /* the query string */ 00140 SOCKET fd; /* the file descriptor for the socket */ 00141 int state; /* WRITE / READ / CLOSED */ 00142 char *out; /* buffer sent (zero terminated) */ 00143 char *outptr; /* index within the buffer sent */ 00144 char *in; /* the receiving buffer */ 00145 char *content; /* the start of the content */ 00146 char *inptr; /* the next byte to read from network */ 00147 char *inrptr; /* the next byte to give back to the client */ 00148 int inlen; /* len of the input buffer */ 00149 int last; /* return code for last operation */ 00150 int returnValue; /* the protocol return value */ 00151 int version; /* the protocol version */ 00152 int ContentLength; /* specified content length from HTTP header */ 00153 char *contentType; /* the MIME type for the input */ 00154 char *location; /* the new URL in case of redirect */ 00155 char *authHeader; /* contents of {WWW,Proxy}-Authenticate header */ 00156 char *encoding; /* encoding extracted from the contentType */ 00157 char *mimeType; /* Mime-Type extracted from the contentType */ 00158 #ifdef HAVE_ZLIB_H 00159 z_stream *strm; /* Zlib stream object */ 00160 int usesGzip; /* "Content-Encoding: gzip" was detected */ 00161 #endif 00162 } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr; 00163 00164 static int initialized = 0; 00165 static char *proxy = NULL; /* the proxy name if any */ 00166 static int proxyPort; /* the proxy port if any */ 00167 static unsigned int timeout = 60;/* the select() timeout in seconds */ 00168 00169 static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ); 00170 00177 static void 00178 xmlHTTPErrMemory(const char *extra) 00179 { 00180 __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra); 00181 } 00182 00186 static int socket_errno(void) { 00187 #ifdef _WINSOCKAPI_ 00188 return(WSAGetLastError()); 00189 #else 00190 return(errno); 00191 #endif 00192 } 00193 00194 #ifdef SUPPORT_IP6 00195 static 00196 int have_ipv6(void) { 00197 SOCKET s; 00198 00199 s = socket (AF_INET6, SOCK_STREAM, 0); 00200 if (s != INVALID_SOCKET) { 00201 close (s); 00202 return (1); 00203 } 00204 return (0); 00205 } 00206 #endif 00207 00215 void 00216 xmlNanoHTTPInit(void) { 00217 const char *env; 00218 #ifdef _WINSOCKAPI_ 00219 WSADATA wsaData; 00220 #endif 00221 00222 if (initialized) 00223 return; 00224 00225 #ifdef _WINSOCKAPI_ 00226 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) 00227 return; 00228 #endif 00229 00230 if (proxy == NULL) { 00231 proxyPort = 80; 00232 env = getenv("no_proxy"); 00233 if (env && ((env[0] == '*') && (env[1] == 0))) 00234 goto done; 00235 env = getenv("http_proxy"); 00236 if (env != NULL) { 00237 xmlNanoHTTPScanProxy(env); 00238 goto done; 00239 } 00240 env = getenv("HTTP_PROXY"); 00241 if (env != NULL) { 00242 xmlNanoHTTPScanProxy(env); 00243 goto done; 00244 } 00245 } 00246 done: 00247 initialized = 1; 00248 } 00249 00256 void 00257 xmlNanoHTTPCleanup(void) { 00258 if (proxy != NULL) { 00259 xmlFree(proxy); 00260 proxy = NULL; 00261 } 00262 #ifdef _WINSOCKAPI_ 00263 if (initialized) 00264 WSACleanup(); 00265 #endif 00266 initialized = 0; 00267 return; 00268 } 00269 00279 static void 00280 xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) { 00281 xmlURIPtr uri; 00282 /* 00283 * Clear any existing data from the context 00284 */ 00285 if (ctxt->protocol != NULL) { 00286 xmlFree(ctxt->protocol); 00287 ctxt->protocol = NULL; 00288 } 00289 if (ctxt->hostname != NULL) { 00290 xmlFree(ctxt->hostname); 00291 ctxt->hostname = NULL; 00292 } 00293 if (ctxt->path != NULL) { 00294 xmlFree(ctxt->path); 00295 ctxt->path = NULL; 00296 } 00297 if (ctxt->query != NULL) { 00298 xmlFree(ctxt->query); 00299 ctxt->query = NULL; 00300 } 00301 if (URL == NULL) return; 00302 00303 uri = xmlParseURIRaw(URL, 1); 00304 if (uri == NULL) 00305 return; 00306 00307 if ((uri->scheme == NULL) || (uri->server == NULL)) { 00308 xmlFreeURI(uri); 00309 return; 00310 } 00311 00312 ctxt->protocol = xmlMemStrdup(uri->scheme); 00313 ctxt->hostname = xmlMemStrdup(uri->server); 00314 if (uri->path != NULL) 00315 ctxt->path = xmlMemStrdup(uri->path); 00316 else 00317 ctxt->path = xmlMemStrdup("/"); 00318 if (uri->query != NULL) 00319 ctxt->query = xmlMemStrdup(uri->query); 00320 if (uri->port != 0) 00321 ctxt->port = uri->port; 00322 00323 xmlFreeURI(uri); 00324 } 00325 00336 void 00337 xmlNanoHTTPScanProxy(const char *URL) { 00338 xmlURIPtr uri; 00339 00340 if (proxy != NULL) { 00341 xmlFree(proxy); 00342 proxy = NULL; 00343 } 00344 proxyPort = 0; 00345 00346 #ifdef DEBUG_HTTP 00347 if (URL == NULL) 00348 xmlGenericError(xmlGenericErrorContext, 00349 "Removing HTTP proxy info\n"); 00350 else 00351 xmlGenericError(xmlGenericErrorContext, 00352 "Using HTTP proxy %s\n", URL); 00353 #endif 00354 if (URL == NULL) return; 00355 00356 uri = xmlParseURIRaw(URL, 1); 00357 if ((uri == NULL) || (uri->scheme == NULL) || 00358 (strcmp(uri->scheme, "http")) || (uri->server == NULL)) { 00359 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n"); 00360 if (uri != NULL) 00361 xmlFreeURI(uri); 00362 return; 00363 } 00364 00365 proxy = xmlMemStrdup(uri->server); 00366 if (uri->port != 0) 00367 proxyPort = uri->port; 00368 00369 xmlFreeURI(uri); 00370 } 00371 00381 static xmlNanoHTTPCtxtPtr 00382 xmlNanoHTTPNewCtxt(const char *URL) { 00383 xmlNanoHTTPCtxtPtr ret; 00384 00385 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt)); 00386 if (ret == NULL) { 00387 xmlHTTPErrMemory("allocating context"); 00388 return(NULL); 00389 } 00390 00391 memset(ret, 0, sizeof(xmlNanoHTTPCtxt)); 00392 ret->port = 80; 00393 ret->returnValue = 0; 00394 ret->fd = INVALID_SOCKET; 00395 ret->ContentLength = -1; 00396 00397 xmlNanoHTTPScanURL(ret, URL); 00398 00399 return(ret); 00400 } 00401 00409 static void 00410 xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) { 00411 if (ctxt == NULL) return; 00412 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname); 00413 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol); 00414 if (ctxt->path != NULL) xmlFree(ctxt->path); 00415 if (ctxt->query != NULL) xmlFree(ctxt->query); 00416 if (ctxt->out != NULL) xmlFree(ctxt->out); 00417 if (ctxt->in != NULL) xmlFree(ctxt->in); 00418 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType); 00419 if (ctxt->encoding != NULL) xmlFree(ctxt->encoding); 00420 if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType); 00421 if (ctxt->location != NULL) xmlFree(ctxt->location); 00422 if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader); 00423 #ifdef HAVE_ZLIB_H 00424 if (ctxt->strm != NULL) { 00425 inflateEnd(ctxt->strm); 00426 xmlFree(ctxt->strm); 00427 } 00428 #endif 00429 00430 ctxt->state = XML_NANO_HTTP_NONE; 00431 if (ctxt->fd != INVALID_SOCKET) closesocket(ctxt->fd); 00432 ctxt->fd = INVALID_SOCKET; 00433 xmlFree(ctxt); 00434 } 00435 00444 static int 00445 xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen) 00446 { 00447 int total_sent = 0; 00448 #ifdef HAVE_POLL_H 00449 struct pollfd p; 00450 #else 00451 struct timeval tv; 00452 fd_set wfd; 00453 #endif 00454 00455 if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) { 00456 while (total_sent < outlen) { 00457 int nsent = send(ctxt->fd, xmt_ptr + total_sent, 00458 outlen - total_sent, 0); 00459 00460 if (nsent > 0) 00461 total_sent += nsent; 00462 else if ((nsent == -1) && 00463 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK 00464 (socket_errno() != EAGAIN) && 00465 #endif 00466 (socket_errno() != EWOULDBLOCK)) { 00467 __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n"); 00468 if (total_sent == 0) 00469 total_sent = -1; 00470 break; 00471 } else { 00472 /* 00473 * No data sent 00474 * Since non-blocking sockets are used, wait for 00475 * socket to be writable or default timeout prior 00476 * to retrying. 00477 */ 00478 #ifndef HAVE_POLL_H 00479 #ifndef _WINSOCKAPI_ 00480 if (ctxt->fd > FD_SETSIZE) 00481 return -1; 00482 #endif 00483 00484 tv.tv_sec = timeout; 00485 tv.tv_usec = 0; 00486 FD_ZERO(&wfd); 00487 #ifdef _MSC_VER 00488 #pragma warning(push) 00489 #pragma warning(disable: 4018) 00490 #endif 00491 FD_SET(ctxt->fd, &wfd); 00492 #ifdef _MSC_VER 00493 #pragma warning(pop) 00494 #endif 00495 (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv); 00496 #else 00497 p.fd = ctxt->fd; 00498 p.events = POLLOUT; 00499 (void) poll(&p, 1, timeout * 1000); 00500 #endif /* !HAVE_POLL_H */ 00501 } 00502 } 00503 } 00504 00505 return total_sent; 00506 } 00507 00518 static int 00519 xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) 00520 { 00521 #ifdef HAVE_POLL_H 00522 struct pollfd p; 00523 #else 00524 fd_set rfd; 00525 struct timeval tv; 00526 #endif 00527 00528 00529 while (ctxt->state & XML_NANO_HTTP_READ) { 00530 if (ctxt->in == NULL) { 00531 ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char)); 00532 if (ctxt->in == NULL) { 00533 xmlHTTPErrMemory("allocating input"); 00534 ctxt->last = -1; 00535 return (-1); 00536 } 00537 ctxt->inlen = 65000; 00538 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in; 00539 } 00540 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) { 00541 int delta = ctxt->inrptr - ctxt->in; 00542 int len = ctxt->inptr - ctxt->inrptr; 00543 00544 memmove(ctxt->in, ctxt->inrptr, len); 00545 ctxt->inrptr -= delta; 00546 ctxt->content -= delta; 00547 ctxt->inptr -= delta; 00548 } 00549 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) { 00550 int d_inptr = ctxt->inptr - ctxt->in; 00551 int d_content = ctxt->content - ctxt->in; 00552 int d_inrptr = ctxt->inrptr - ctxt->in; 00553 char *tmp_ptr = ctxt->in; 00554 00555 ctxt->inlen *= 2; 00556 ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen); 00557 if (ctxt->in == NULL) { 00558 xmlHTTPErrMemory("allocating input buffer"); 00559 xmlFree(tmp_ptr); 00560 ctxt->last = -1; 00561 return (-1); 00562 } 00563 ctxt->inptr = ctxt->in + d_inptr; 00564 ctxt->content = ctxt->in + d_content; 00565 ctxt->inrptr = ctxt->in + d_inrptr; 00566 } 00567 ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0); 00568 if (ctxt->last > 0) { 00569 ctxt->inptr += ctxt->last; 00570 return (ctxt->last); 00571 } 00572 if (ctxt->last == 0) { 00573 return (0); 00574 } 00575 if (ctxt->last == -1) { 00576 switch (socket_errno()) { 00577 case EINPROGRESS: 00578 case EWOULDBLOCK: 00579 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK 00580 case EAGAIN: 00581 #endif 00582 break; 00583 00584 case ECONNRESET: 00585 case ESHUTDOWN: 00586 return (0); 00587 00588 default: 00589 __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n"); 00590 return (-1); 00591 } 00592 } 00593 #ifdef HAVE_POLL_H 00594 p.fd = ctxt->fd; 00595 p.events = POLLIN; 00596 if ((poll(&p, 1, timeout * 1000) < 1) 00597 #if defined(EINTR) 00598 && (errno != EINTR) 00599 #endif 00600 ) 00601 return (0); 00602 #else /* !HAVE_POLL_H */ 00603 #ifndef _WINSOCKAPI_ 00604 if (ctxt->fd > FD_SETSIZE) 00605 return 0; 00606 #endif 00607 00608 tv.tv_sec = timeout; 00609 tv.tv_usec = 0; 00610 FD_ZERO(&rfd); 00611 00612 #ifdef _MSC_VER 00613 #pragma warning(push) 00614 #pragma warning(disable: 4018) 00615 #endif 00616 00617 FD_SET(ctxt->fd, &rfd); 00618 00619 #ifdef _MSC_VER 00620 #pragma warning(pop) 00621 #endif 00622 00623 if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1) 00624 #if defined(EINTR) 00625 && (errno != EINTR) 00626 #endif 00627 ) 00628 return (0); 00629 #endif /* !HAVE_POLL_H */ 00630 } 00631 return (0); 00632 } 00633 00645 static char * 00646 xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) { 00647 char buf[4096]; 00648 char *bp = buf; 00649 int rc; 00650 00651 while (bp - buf < 4095) { 00652 if (ctxt->inrptr == ctxt->inptr) { 00653 if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) { 00654 if (bp == buf) 00655 return(NULL); 00656 else 00657 *bp = 0; 00658 return(xmlMemStrdup(buf)); 00659 } 00660 else if ( rc == -1 ) { 00661 return ( NULL ); 00662 } 00663 } 00664 *bp = *ctxt->inrptr++; 00665 if (*bp == '\n') { 00666 *bp = 0; 00667 return(xmlMemStrdup(buf)); 00668 } 00669 if (*bp != '\r') 00670 bp++; 00671 } 00672 buf[4095] = 0; 00673 return(xmlMemStrdup(buf)); 00674 } 00675 00676 00691 static void 00692 xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) { 00693 const char *cur = line; 00694 00695 if (line == NULL) return; 00696 00697 if (!strncmp(line, "HTTP/", 5)) { 00698 int version = 0; 00699 int ret = 0; 00700 00701 cur += 5; 00702 while ((*cur >= '0') && (*cur <= '9')) { 00703 version *= 10; 00704 version += *cur - '0'; 00705 cur++; 00706 } 00707 if (*cur == '.') { 00708 cur++; 00709 if ((*cur >= '0') && (*cur <= '9')) { 00710 version *= 10; 00711 version += *cur - '0'; 00712 cur++; 00713 } 00714 while ((*cur >= '0') && (*cur <= '9')) 00715 cur++; 00716 } else 00717 version *= 10; 00718 if ((*cur != ' ') && (*cur != '\t')) return; 00719 while ((*cur == ' ') || (*cur == '\t')) cur++; 00720 if ((*cur < '0') || (*cur > '9')) return; 00721 while ((*cur >= '0') && (*cur <= '9')) { 00722 ret *= 10; 00723 ret += *cur - '0'; 00724 cur++; 00725 } 00726 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return; 00727 ctxt->returnValue = ret; 00728 ctxt->version = version; 00729 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) { 00730 const xmlChar *charset, *last, *mime; 00731 cur += 13; 00732 while ((*cur == ' ') || (*cur == '\t')) cur++; 00733 if (ctxt->contentType != NULL) 00734 xmlFree(ctxt->contentType); 00735 ctxt->contentType = xmlMemStrdup(cur); 00736 mime = (const xmlChar *) cur; 00737 last = mime; 00738 while ((*last != 0) && (*last != ' ') && (*last != '\t') && 00739 (*last != ';') && (*last != ',')) 00740 last++; 00741 if (ctxt->mimeType != NULL) 00742 xmlFree(ctxt->mimeType); 00743 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime); 00744 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset="); 00745 if (charset != NULL) { 00746 charset += 8; 00747 last = charset; 00748 while ((*last != 0) && (*last != ' ') && (*last != '\t') && 00749 (*last != ';') && (*last != ',')) 00750 last++; 00751 if (ctxt->encoding != NULL) 00752 xmlFree(ctxt->encoding); 00753 ctxt->encoding = (char *) xmlStrndup(charset, last - charset); 00754 } 00755 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) { 00756 const xmlChar *charset, *last, *mime; 00757 cur += 12; 00758 if (ctxt->contentType != NULL) return; 00759 while ((*cur == ' ') || (*cur == '\t')) cur++; 00760 ctxt->contentType = xmlMemStrdup(cur); 00761 mime = (const xmlChar *) cur; 00762 last = mime; 00763 while ((*last != 0) && (*last != ' ') && (*last != '\t') && 00764 (*last != ';') && (*last != ',')) 00765 last++; 00766 if (ctxt->mimeType != NULL) 00767 xmlFree(ctxt->mimeType); 00768 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime); 00769 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset="); 00770 if (charset != NULL) { 00771 charset += 8; 00772 last = charset; 00773 while ((*last != 0) && (*last != ' ') && (*last != '\t') && 00774 (*last != ';') && (*last != ',')) 00775 last++; 00776 if (ctxt->encoding != NULL) 00777 xmlFree(ctxt->encoding); 00778 ctxt->encoding = (char *) xmlStrndup(charset, last - charset); 00779 } 00780 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) { 00781 cur += 9; 00782 while ((*cur == ' ') || (*cur == '\t')) cur++; 00783 if (ctxt->location != NULL) 00784 xmlFree(ctxt->location); 00785 if (*cur == '/') { 00786 xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://"); 00787 xmlChar *tmp_loc = 00788 xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname); 00789 ctxt->location = 00790 (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur); 00791 } else { 00792 ctxt->location = xmlMemStrdup(cur); 00793 } 00794 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) { 00795 cur += 17; 00796 while ((*cur == ' ') || (*cur == '\t')) cur++; 00797 if (ctxt->authHeader != NULL) 00798 xmlFree(ctxt->authHeader); 00799 ctxt->authHeader = xmlMemStrdup(cur); 00800 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) { 00801 cur += 19; 00802 while ((*cur == ' ') || (*cur == '\t')) cur++; 00803 if (ctxt->authHeader != NULL) 00804 xmlFree(ctxt->authHeader); 00805 ctxt->authHeader = xmlMemStrdup(cur); 00806 #ifdef HAVE_ZLIB_H 00807 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) { 00808 cur += 17; 00809 while ((*cur == ' ') || (*cur == '\t')) cur++; 00810 if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) { 00811 ctxt->usesGzip = 1; 00812 00813 ctxt->strm = xmlMalloc(sizeof(z_stream)); 00814 00815 if (ctxt->strm != NULL) { 00816 ctxt->strm->zalloc = Z_NULL; 00817 ctxt->strm->zfree = Z_NULL; 00818 ctxt->strm->opaque = Z_NULL; 00819 ctxt->strm->avail_in = 0; 00820 ctxt->strm->next_in = Z_NULL; 00821 00822 inflateInit2( ctxt->strm, 31 ); 00823 } 00824 } 00825 #endif 00826 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) { 00827 cur += 15; 00828 ctxt->ContentLength = strtol( cur, NULL, 10 ); 00829 } 00830 } 00831 00843 static SOCKET 00844 xmlNanoHTTPConnectAttempt(struct sockaddr *addr) 00845 { 00846 #ifndef HAVE_POLL_H 00847 fd_set wfd; 00848 #ifdef _WINSOCKAPI_ 00849 fd_set xfd; 00850 #endif 00851 struct timeval tv; 00852 #else /* !HAVE_POLL_H */ 00853 struct pollfd p; 00854 #endif /* !HAVE_POLL_H */ 00855 int status; 00856 00857 int addrlen; 00858 00859 SOCKET s; 00860 00861 #ifdef SUPPORT_IP6 00862 if (addr->sa_family == AF_INET6) { 00863 s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); 00864 addrlen = sizeof(struct sockaddr_in6); 00865 } else 00866 #endif 00867 { 00868 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 00869 addrlen = sizeof(struct sockaddr_in); 00870 } 00871 if (s == INVALID_SOCKET) { 00872 #ifdef DEBUG_HTTP 00873 perror("socket"); 00874 #endif 00875 __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n"); 00876 return INVALID_SOCKET; 00877 } 00878 #ifdef _WINSOCKAPI_ 00879 { 00880 u_long one = 1; 00881 00882 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0; 00883 } 00884 #else /* _WINSOCKAPI_ */ 00885 #if defined(VMS) 00886 { 00887 int enable = 1; 00888 00889 status = ioctl(s, FIONBIO, &enable); 00890 } 00891 #else /* VMS */ 00892 #if defined(__BEOS__) && !defined(__HAIKU__) 00893 { 00894 bool noblock = true; 00895 00896 status = 00897 setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock, 00898 sizeof(noblock)); 00899 } 00900 #else /* __BEOS__ */ 00901 if ((status = fcntl(s, F_GETFL, 0)) != -1) { 00902 #ifdef O_NONBLOCK 00903 status |= O_NONBLOCK; 00904 #else /* O_NONBLOCK */ 00905 #ifdef F_NDELAY 00906 status |= F_NDELAY; 00907 #endif /* F_NDELAY */ 00908 #endif /* !O_NONBLOCK */ 00909 status = fcntl(s, F_SETFL, status); 00910 } 00911 if (status < 0) { 00912 #ifdef DEBUG_HTTP 00913 perror("nonblocking"); 00914 #endif 00915 __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n"); 00916 closesocket(s); 00917 return INVALID_SOCKET; 00918 } 00919 #endif /* !__BEOS__ */ 00920 #endif /* !VMS */ 00921 #endif /* !_WINSOCKAPI_ */ 00922 00923 if (connect(s, addr, addrlen) == -1) { 00924 switch (socket_errno()) { 00925 case EINPROGRESS: 00926 case EWOULDBLOCK: 00927 break; 00928 default: 00929 __xmlIOErr(XML_FROM_HTTP, 0, 00930 "error connecting to HTTP server"); 00931 closesocket(s); 00932 return INVALID_SOCKET; 00933 } 00934 } 00935 #ifndef HAVE_POLL_H 00936 tv.tv_sec = timeout; 00937 tv.tv_usec = 0; 00938 00939 #ifdef _MSC_VER 00940 #pragma warning(push) 00941 #pragma warning(disable: 4018) 00942 #endif 00943 #ifndef _WINSOCKAPI_ 00944 if (s > FD_SETSIZE) 00945 return INVALID_SOCKET; 00946 #endif 00947 FD_ZERO(&wfd); 00948 FD_SET(s, &wfd); 00949 00950 #ifdef _WINSOCKAPI_ 00951 FD_ZERO(&xfd); 00952 FD_SET(s, &xfd); 00953 00954 switch (select(s + 1, NULL, &wfd, &xfd, &tv)) 00955 #else 00956 switch (select(s + 1, NULL, &wfd, NULL, &tv)) 00957 #endif 00958 #ifdef _MSC_VER 00959 #pragma warning(pop) 00960 #endif 00961 00962 #else /* !HAVE_POLL_H */ 00963 p.fd = s; 00964 p.events = POLLOUT; 00965 switch (poll(&p, 1, timeout * 1000)) 00966 #endif /* !HAVE_POLL_H */ 00967 00968 { 00969 case 0: 00970 /* Time out */ 00971 __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out"); 00972 closesocket(s); 00973 return INVALID_SOCKET; 00974 case -1: 00975 /* Ermm.. ?? */ 00976 __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed"); 00977 closesocket(s); 00978 return INVALID_SOCKET; 00979 } 00980 00981 #ifndef HAVE_POLL_H 00982 if (FD_ISSET(s, &wfd) 00983 #ifdef _WINSOCKAPI_ 00984 || FD_ISSET(s, &xfd) 00985 #endif 00986 ) 00987 #else /* !HAVE_POLL_H */ 00988 if (p.revents == POLLOUT) 00989 #endif /* !HAVE_POLL_H */ 00990 { 00991 XML_SOCKLEN_T len; 00992 00993 len = sizeof(status); 00994 #ifdef SO_ERROR 00995 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) < 00996 0) { 00997 /* Solaris error code */ 00998 __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n"); 00999 return INVALID_SOCKET; 01000 } 01001 #endif 01002 if (status) { 01003 __xmlIOErr(XML_FROM_HTTP, 0, 01004 "Error connecting to remote host"); 01005 closesocket(s); 01006 errno = status; 01007 return INVALID_SOCKET; 01008 } 01009 } else { 01010 /* pbm */ 01011 __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n"); 01012 closesocket(s); 01013 return INVALID_SOCKET; 01014 } 01015 01016 return (s); 01017 } 01018 01030 static SOCKET 01031 xmlNanoHTTPConnectHost(const char *host, int port) 01032 { 01033 struct hostent *h; 01034 struct sockaddr *addr = NULL; 01035 struct in_addr ia; 01036 struct sockaddr_in sockin; 01037 01038 #ifdef SUPPORT_IP6 01039 struct in6_addr ia6; 01040 struct sockaddr_in6 sockin6; 01041 #endif 01042 int i; 01043 SOCKET s; 01044 01045 memset (&sockin, 0, sizeof(sockin)); 01046 #ifdef SUPPORT_IP6 01047 memset (&sockin6, 0, sizeof(sockin6)); 01048 #endif 01049 01050 #if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6) 01051 if (have_ipv6 ()) 01052 { 01053 if (!(_res.options & RES_INIT)) 01054 res_init(); 01055 _res.options |= RES_USE_INET6; 01056 } 01057 #endif 01058 01059 #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32) 01060 if (have_ipv6 ()) 01061 #endif 01062 #if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32)) 01063 { 01064 int status; 01065 struct addrinfo hints, *res, *result; 01066 01067 result = NULL; 01068 memset (&hints, 0,sizeof(hints)); 01069 hints.ai_socktype = SOCK_STREAM; 01070 01071 status = getaddrinfo (host, NULL, &hints, &result); 01072 if (status) { 01073 __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n"); 01074 return INVALID_SOCKET; 01075 } 01076 01077 for (res = result; res; res = res->ai_next) { 01078 if (res->ai_family == AF_INET) { 01079 if (res->ai_addrlen > sizeof(sockin)) { 01080 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 01081 freeaddrinfo (result); 01082 return INVALID_SOCKET; 01083 } 01084 memcpy (&sockin, res->ai_addr, res->ai_addrlen); 01085 sockin.sin_port = htons (port); 01086 addr = (struct sockaddr *)&sockin; 01087 #ifdef SUPPORT_IP6 01088 } else if (have_ipv6 () && (res->ai_family == AF_INET6)) { 01089 if (res->ai_addrlen > sizeof(sockin6)) { 01090 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 01091 freeaddrinfo (result); 01092 return INVALID_SOCKET; 01093 } 01094 memcpy (&sockin6, res->ai_addr, res->ai_addrlen); 01095 sockin6.sin6_port = htons (port); 01096 addr = (struct sockaddr *)&sockin6; 01097 #endif 01098 } else 01099 continue; /* for */ 01100 01101 s = xmlNanoHTTPConnectAttempt (addr); 01102 if (s != INVALID_SOCKET) { 01103 freeaddrinfo (result); 01104 return (s); 01105 } 01106 } 01107 01108 if (result) 01109 freeaddrinfo (result); 01110 } 01111 #endif 01112 #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32) 01113 else 01114 #endif 01115 #if !defined(HAVE_GETADDRINFO) || !defined(_WIN32) 01116 { 01117 h = gethostbyname (host); 01118 if (h == NULL) { 01119 01120 /* 01121 * Okay, I got fed up by the non-portability of this error message 01122 * extraction code. it work on Linux, if it work on your platform 01123 * and one want to enable it, send me the defined(foobar) needed 01124 */ 01125 #if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux) 01126 const char *h_err_txt = ""; 01127 01128 switch (h_errno) { 01129 case HOST_NOT_FOUND: 01130 h_err_txt = "Authoritive host not found"; 01131 break; 01132 01133 case TRY_AGAIN: 01134 h_err_txt = 01135 "Non-authoritive host not found or server failure."; 01136 break; 01137 01138 case NO_RECOVERY: 01139 h_err_txt = 01140 "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP."; 01141 break; 01142 01143 case NO_ADDRESS: 01144 h_err_txt = 01145 "Valid name, no data record of requested type."; 01146 break; 01147 01148 default: 01149 h_err_txt = "No error text defined."; 01150 break; 01151 } 01152 __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt); 01153 #else 01154 __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host"); 01155 #endif 01156 return INVALID_SOCKET; 01157 } 01158 01159 for (i = 0; h->h_addr_list[i]; i++) { 01160 if (h->h_addrtype == AF_INET) { 01161 /* A records (IPv4) */ 01162 if ((unsigned int) h->h_length > sizeof(ia)) { 01163 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 01164 return INVALID_SOCKET; 01165 } 01166 memcpy (&ia, h->h_addr_list[i], h->h_length); 01167 sockin.sin_family = h->h_addrtype; 01168 sockin.sin_addr = ia; 01169 sockin.sin_port = (u_short)htons ((unsigned short)port); 01170 addr = (struct sockaddr *) &sockin; 01171 #ifdef SUPPORT_IP6 01172 } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) { 01173 /* AAAA records (IPv6) */ 01174 if ((unsigned int) h->h_length > sizeof(ia6)) { 01175 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 01176 return INVALID_SOCKET; 01177 } 01178 memcpy (&ia6, h->h_addr_list[i], h->h_length); 01179 sockin6.sin6_family = h->h_addrtype; 01180 sockin6.sin6_addr = ia6; 01181 sockin6.sin6_port = htons (port); 01182 addr = (struct sockaddr *) &sockin6; 01183 #endif 01184 } else 01185 break; /* for */ 01186 01187 s = xmlNanoHTTPConnectAttempt (addr); 01188 if (s != INVALID_SOCKET) 01189 return (s); 01190 } 01191 } 01192 #endif 01193 01194 #ifdef DEBUG_HTTP 01195 xmlGenericError(xmlGenericErrorContext, 01196 "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n", 01197 host); 01198 #endif 01199 return INVALID_SOCKET; 01200 } 01201 01202 01216 void* 01217 xmlNanoHTTPOpen(const char *URL, char **contentType) { 01218 if (contentType != NULL) *contentType = NULL; 01219 return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0)); 01220 } 01221 01236 void* 01237 xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) { 01238 if (contentType != NULL) *contentType = NULL; 01239 if (redir != NULL) *redir = NULL; 01240 return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0)); 01241 } 01242 01255 int 01256 xmlNanoHTTPRead(void *ctx, void *dest, int len) { 01257 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 01258 #ifdef HAVE_ZLIB_H 01259 int bytes_read = 0; 01260 int orig_avail_in; 01261 int z_ret; 01262 #endif 01263 01264 if (ctx == NULL) return(-1); 01265 if (dest == NULL) return(-1); 01266 if (len <= 0) return(0); 01267 01268 #ifdef HAVE_ZLIB_H 01269 if (ctxt->usesGzip == 1) { 01270 if (ctxt->strm == NULL) return(0); 01271 01272 ctxt->strm->next_out = dest; 01273 ctxt->strm->avail_out = len; 01274 ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr; 01275 01276 while (ctxt->strm->avail_out > 0 && 01277 (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) { 01278 orig_avail_in = ctxt->strm->avail_in = 01279 ctxt->inptr - ctxt->inrptr - bytes_read; 01280 ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read); 01281 01282 z_ret = inflate(ctxt->strm, Z_NO_FLUSH); 01283 bytes_read += orig_avail_in - ctxt->strm->avail_in; 01284 01285 if (z_ret != Z_OK) break; 01286 } 01287 01288 ctxt->inrptr += bytes_read; 01289 return(len - ctxt->strm->avail_out); 01290 } 01291 #endif 01292 01293 while (ctxt->inptr - ctxt->inrptr < len) { 01294 if (xmlNanoHTTPRecv(ctxt) <= 0) break; 01295 } 01296 if (ctxt->inptr - ctxt->inrptr < len) 01297 len = ctxt->inptr - ctxt->inrptr; 01298 memcpy(dest, ctxt->inrptr, len); 01299 ctxt->inrptr += len; 01300 return(len); 01301 } 01302 01310 void 01311 xmlNanoHTTPClose(void *ctx) { 01312 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 01313 01314 if (ctx == NULL) return; 01315 01316 xmlNanoHTTPFreeCtxt(ctxt); 01317 } 01318 01337 void* 01338 xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input, 01339 char **contentType, char **redir, 01340 const char *headers, int ilen ) { 01341 xmlNanoHTTPCtxtPtr ctxt; 01342 char *bp, *p; 01343 int blen; 01344 SOCKET ret; 01345 int nbRedirects = 0; 01346 char *redirURL = NULL; 01347 #ifdef DEBUG_HTTP 01348 int xmt_bytes; 01349 #endif 01350 01351 if (URL == NULL) return(NULL); 01352 if (method == NULL) method = "GET"; 01353 xmlNanoHTTPInit(); 01354 01355 retry: 01356 if (redirURL == NULL) 01357 ctxt = xmlNanoHTTPNewCtxt(URL); 01358 else { 01359 ctxt = xmlNanoHTTPNewCtxt(redirURL); 01360 ctxt->location = xmlMemStrdup(redirURL); 01361 } 01362 01363 if ( ctxt == NULL ) { 01364 return ( NULL ); 01365 } 01366 01367 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) { 01368 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI"); 01369 xmlNanoHTTPFreeCtxt(ctxt); 01370 if (redirURL != NULL) xmlFree(redirURL); 01371 return(NULL); 01372 } 01373 if (ctxt->hostname == NULL) { 01374 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST, 01375 "Failed to identify host in URI"); 01376 xmlNanoHTTPFreeCtxt(ctxt); 01377 if (redirURL != NULL) xmlFree(redirURL); 01378 return(NULL); 01379 } 01380 if (proxy) { 01381 blen = strlen(ctxt->hostname) * 2 + 16; 01382 ret = xmlNanoHTTPConnectHost(proxy, proxyPort); 01383 } 01384 else { 01385 blen = strlen(ctxt->hostname); 01386 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); 01387 } 01388 if (ret == INVALID_SOCKET) { 01389 xmlNanoHTTPFreeCtxt(ctxt); 01390 if (redirURL != NULL) xmlFree(redirURL); 01391 return(NULL); 01392 } 01393 ctxt->fd = ret; 01394 01395 if (input == NULL) 01396 ilen = 0; 01397 else 01398 blen += 36; 01399 01400 if (headers != NULL) 01401 blen += strlen(headers) + 2; 01402 if (contentType && *contentType) 01403 /* reserve for string plus 'Content-Type: \r\n" */ 01404 blen += strlen(*contentType) + 16; 01405 if (ctxt->query != NULL) 01406 /* 1 for '?' */ 01407 blen += strlen(ctxt->query) + 1; 01408 blen += strlen(method) + strlen(ctxt->path) + 24; 01409 #ifdef HAVE_ZLIB_H 01410 /* reserve for possible 'Accept-Encoding: gzip' string */ 01411 blen += 23; 01412 #endif 01413 if (ctxt->port != 80) { 01414 /* reserve space for ':xxxxx', incl. potential proxy */ 01415 if (proxy) 01416 blen += 12; 01417 else 01418 blen += 6; 01419 } 01420 bp = (char*)xmlMallocAtomic(blen); 01421 if ( bp == NULL ) { 01422 xmlNanoHTTPFreeCtxt( ctxt ); 01423 xmlHTTPErrMemory("allocating header buffer"); 01424 return ( NULL ); 01425 } 01426 01427 p = bp; 01428 01429 if (proxy) { 01430 if (ctxt->port != 80) { 01431 p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 01432 method, ctxt->hostname, 01433 ctxt->port, ctxt->path ); 01434 } 01435 else 01436 p += snprintf( p, blen - (p - bp), "%s http://%s%s", method, 01437 ctxt->hostname, ctxt->path); 01438 } 01439 else 01440 p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path); 01441 01442 if (ctxt->query != NULL) 01443 p += snprintf( p, blen - (p - bp), "?%s", ctxt->query); 01444 01445 if (ctxt->port == 80) { 01446 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n", 01447 ctxt->hostname); 01448 } else { 01449 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n", 01450 ctxt->hostname, ctxt->port); 01451 } 01452 01453 #ifdef HAVE_ZLIB_H 01454 p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n"); 01455 #endif 01456 01457 if (contentType != NULL && *contentType) 01458 p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType); 01459 01460 if (headers != NULL) 01461 p += snprintf( p, blen - (p - bp), "%s", headers ); 01462 01463 if (input != NULL) 01464 snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen ); 01465 else 01466 snprintf(p, blen - (p - bp), "\r\n"); 01467 01468 #ifdef DEBUG_HTTP 01469 xmlGenericError(xmlGenericErrorContext, 01470 "-> %s%s", proxy? "(Proxy) " : "", bp); 01471 if ((blen -= strlen(bp)+1) < 0) 01472 xmlGenericError(xmlGenericErrorContext, 01473 "ERROR: overflowed buffer by %d bytes\n", -blen); 01474 #endif 01475 ctxt->outptr = ctxt->out = bp; 01476 ctxt->state = XML_NANO_HTTP_WRITE; 01477 blen = strlen( ctxt->out ); 01478 #ifdef DEBUG_HTTP 01479 xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen ); 01480 if ( xmt_bytes != blen ) 01481 xmlGenericError( xmlGenericErrorContext, 01482 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n", 01483 xmt_bytes, blen, 01484 "bytes of HTTP headers sent to host", 01485 ctxt->hostname ); 01486 #else 01487 xmlNanoHTTPSend(ctxt, ctxt->out, blen ); 01488 #endif 01489 01490 if ( input != NULL ) { 01491 #ifdef DEBUG_HTTP 01492 xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen ); 01493 01494 if ( xmt_bytes != ilen ) 01495 xmlGenericError( xmlGenericErrorContext, 01496 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n", 01497 xmt_bytes, ilen, 01498 "bytes of HTTP content sent to host", 01499 ctxt->hostname ); 01500 #else 01501 xmlNanoHTTPSend( ctxt, input, ilen ); 01502 #endif 01503 } 01504 01505 ctxt->state = XML_NANO_HTTP_READ; 01506 01507 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) { 01508 if (*p == 0) { 01509 ctxt->content = ctxt->inrptr; 01510 xmlFree(p); 01511 break; 01512 } 01513 xmlNanoHTTPScanAnswer(ctxt, p); 01514 01515 #ifdef DEBUG_HTTP 01516 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p); 01517 #endif 01518 xmlFree(p); 01519 } 01520 01521 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && 01522 (ctxt->returnValue < 400)) { 01523 #ifdef DEBUG_HTTP 01524 xmlGenericError(xmlGenericErrorContext, 01525 "\nRedirect to: %s\n", ctxt->location); 01526 #endif 01527 while ( xmlNanoHTTPRecv(ctxt) > 0 ) ; 01528 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { 01529 nbRedirects++; 01530 if (redirURL != NULL) 01531 xmlFree(redirURL); 01532 redirURL = xmlMemStrdup(ctxt->location); 01533 xmlNanoHTTPFreeCtxt(ctxt); 01534 goto retry; 01535 } 01536 xmlNanoHTTPFreeCtxt(ctxt); 01537 if (redirURL != NULL) xmlFree(redirURL); 01538 #ifdef DEBUG_HTTP 01539 xmlGenericError(xmlGenericErrorContext, 01540 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n"); 01541 #endif 01542 return(NULL); 01543 } 01544 01545 if (contentType != NULL) { 01546 if (ctxt->contentType != NULL) 01547 *contentType = xmlMemStrdup(ctxt->contentType); 01548 else 01549 *contentType = NULL; 01550 } 01551 01552 if ((redir != NULL) && (redirURL != NULL)) { 01553 *redir = redirURL; 01554 } else { 01555 if (redirURL != NULL) 01556 xmlFree(redirURL); 01557 if (redir != NULL) 01558 *redir = NULL; 01559 } 01560 01561 #ifdef DEBUG_HTTP 01562 if (ctxt->contentType != NULL) 01563 xmlGenericError(xmlGenericErrorContext, 01564 "\nCode %d, content-type '%s'\n\n", 01565 ctxt->returnValue, ctxt->contentType); 01566 else 01567 xmlGenericError(xmlGenericErrorContext, 01568 "\nCode %d, no content-type\n\n", 01569 ctxt->returnValue); 01570 #endif 01571 01572 return((void *) ctxt); 01573 } 01574 01592 void* 01593 xmlNanoHTTPMethod(const char *URL, const char *method, const char *input, 01594 char **contentType, const char *headers, int ilen) { 01595 return(xmlNanoHTTPMethodRedir(URL, method, input, contentType, 01596 NULL, headers, ilen)); 01597 } 01598 01612 int 01613 xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) { 01614 void *ctxt = NULL; 01615 char *buf = NULL; 01616 int fd; 01617 int len; 01618 01619 if (filename == NULL) return(-1); 01620 ctxt = xmlNanoHTTPOpen(URL, contentType); 01621 if (ctxt == NULL) return(-1); 01622 01623 if (!strcmp(filename, "-")) 01624 fd = 0; 01625 else { 01626 fd = open(filename, O_CREAT | O_WRONLY, 00644); 01627 if (fd < 0) { 01628 xmlNanoHTTPClose(ctxt); 01629 if ((contentType != NULL) && (*contentType != NULL)) { 01630 xmlFree(*contentType); 01631 *contentType = NULL; 01632 } 01633 return(-1); 01634 } 01635 } 01636 01637 xmlNanoHTTPFetchContent( ctxt, &buf, &len ); 01638 if ( len > 0 ) { 01639 write(fd, buf, len); 01640 } 01641 01642 xmlNanoHTTPClose(ctxt); 01643 close(fd); 01644 return(0); 01645 } 01646 01647 #ifdef LIBXML_OUTPUT_ENABLED 01648 01658 int 01659 xmlNanoHTTPSave(void *ctxt, const char *filename) { 01660 char *buf = NULL; 01661 int fd; 01662 int len; 01663 01664 if ((ctxt == NULL) || (filename == NULL)) return(-1); 01665 01666 if (!strcmp(filename, "-")) 01667 fd = 0; 01668 else { 01669 fd = open(filename, O_CREAT | O_WRONLY, 0666); 01670 if (fd < 0) { 01671 xmlNanoHTTPClose(ctxt); 01672 return(-1); 01673 } 01674 } 01675 01676 xmlNanoHTTPFetchContent( ctxt, &buf, &len ); 01677 if ( len > 0 ) { 01678 write(fd, buf, len); 01679 } 01680 01681 xmlNanoHTTPClose(ctxt); 01682 close(fd); 01683 return(0); 01684 } 01685 #endif /* LIBXML_OUTPUT_ENABLED */ 01686 01695 int 01696 xmlNanoHTTPReturnCode(void *ctx) { 01697 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 01698 01699 if (ctxt == NULL) return(-1); 01700 01701 return(ctxt->returnValue); 01702 } 01703 01713 const char * 01714 xmlNanoHTTPAuthHeader(void *ctx) { 01715 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 01716 01717 if (ctxt == NULL) return(NULL); 01718 01719 return(ctxt->authHeader); 01720 } 01721 01732 int 01733 xmlNanoHTTPContentLength( void * ctx ) { 01734 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 01735 01736 return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength ); 01737 } 01738 01747 const char * 01748 xmlNanoHTTPRedir( void * ctx ) { 01749 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 01750 01751 return ( ( ctxt == NULL ) ? NULL : ctxt->location ); 01752 } 01753 01762 const char * 01763 xmlNanoHTTPEncoding( void * ctx ) { 01764 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 01765 01766 return ( ( ctxt == NULL ) ? NULL : ctxt->encoding ); 01767 } 01768 01777 const char * 01778 xmlNanoHTTPMimeType( void * ctx ) { 01779 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 01780 01781 return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType ); 01782 } 01783 01796 static int 01797 xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) { 01798 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 01799 01800 int rc = 0; 01801 int cur_lgth; 01802 int rcvd_lgth; 01803 int dummy_int; 01804 char * dummy_ptr = NULL; 01805 01806 /* Dummy up return input parameters if not provided */ 01807 01808 if ( len == NULL ) 01809 len = &dummy_int; 01810 01811 if ( ptr == NULL ) 01812 ptr = &dummy_ptr; 01813 01814 /* But can't work without the context pointer */ 01815 01816 if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) { 01817 *len = 0; 01818 *ptr = NULL; 01819 return ( -1 ); 01820 } 01821 01822 rcvd_lgth = ctxt->inptr - ctxt->content; 01823 01824 while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) { 01825 01826 rcvd_lgth += cur_lgth; 01827 if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) ) 01828 break; 01829 } 01830 01831 *ptr = ctxt->content; 01832 *len = rcvd_lgth; 01833 01834 if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) ) 01835 rc = -1; 01836 else if ( rcvd_lgth == 0 ) 01837 rc = -1; 01838 01839 return ( rc ); 01840 } 01841 01842 #ifdef STANDALONE 01843 int main(int argc, char **argv) { 01844 char *contentType = NULL; 01845 01846 if (argv[1] != NULL) { 01847 if (argv[2] != NULL) 01848 xmlNanoHTTPFetch(argv[1], argv[2], &contentType); 01849 else 01850 xmlNanoHTTPFetch(argv[1], "-", &contentType); 01851 if (contentType != NULL) xmlFree(contentType); 01852 } else { 01853 xmlGenericError(xmlGenericErrorContext, 01854 "%s: minimal HTTP GET implementation\n", argv[0]); 01855 xmlGenericError(xmlGenericErrorContext, 01856 "\tusage %s [ URL [ filename ] ]\n", argv[0]); 01857 } 01858 xmlNanoHTTPCleanup(); 01859 xmlMemoryDump(); 01860 return(0); 01861 } 01862 #endif /* STANDALONE */ 01863 #else /* !LIBXML_HTTP_ENABLED */ 01864 #ifdef STANDALONE 01865 #include <stdio.h> 01866 int main(int argc, char **argv) { 01867 xmlGenericError(xmlGenericErrorContext, 01868 "%s : HTTP support not compiled in\n", argv[0]); 01869 return(0); 01870 } 01871 #endif /* STANDALONE */ 01872 #endif /* LIBXML_HTTP_ENABLED */ 01873 #define bottom_nanohttp 01874 #include "elfgcchack.h" Generated on Sat May 26 2012 04:33:19 for ReactOS by
1.7.6.1
|