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 (at) 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, SEND_ARG2_CAST (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 closesocket(s); 1007 return INVALID_SOCKET; 1008 } 1009 #endif 1010 if (status) { 1011 __xmlIOErr(XML_FROM_HTTP, 0, 1012 "Error connecting to remote host"); 1013 closesocket(s); 1014 errno = status; 1015 return INVALID_SOCKET; 1016 } 1017 } else { 1018 /* pbm */ 1019 __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n"); 1020 closesocket(s); 1021 return INVALID_SOCKET; 1022 } 1023 1024 return (s); 1025 } 1026 1027 /** 1028 * xmlNanoHTTPConnectHost: 1029 * @host: the host name 1030 * @port: the port number 1031 * 1032 * Attempt a connection to the given host:port endpoint. It tries 1033 * the multiple IP provided by the DNS if available. 1034 * 1035 * Returns -1 in case of failure, the file descriptor number otherwise 1036 */ 1037 1038 static SOCKET 1039 xmlNanoHTTPConnectHost(const char *host, int port) 1040 { 1041 struct hostent *h; 1042 struct sockaddr *addr = NULL; 1043 struct in_addr ia; 1044 struct sockaddr_in sockin; 1045 1046 #ifdef SUPPORT_IP6 1047 struct in6_addr ia6; 1048 struct sockaddr_in6 sockin6; 1049 #endif 1050 int i; 1051 SOCKET s; 1052 1053 memset (&sockin, 0, sizeof(sockin)); 1054 #ifdef SUPPORT_IP6 1055 memset (&sockin6, 0, sizeof(sockin6)); 1056 #endif 1057 1058 #if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6) 1059 if (have_ipv6 ()) 1060 { 1061 if (!(_res.options & RES_INIT)) 1062 res_init(); 1063 _res.options |= RES_USE_INET6; 1064 } 1065 #endif 1066 1067 #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32) 1068 if (have_ipv6 ()) 1069 #endif 1070 #if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32)) 1071 { 1072 int status; 1073 struct addrinfo hints, *res, *result; 1074 1075 result = NULL; 1076 memset (&hints, 0,sizeof(hints)); 1077 hints.ai_socktype = SOCK_STREAM; 1078 1079 status = getaddrinfo (host, NULL, &hints, &result); 1080 if (status) { 1081 __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n"); 1082 return INVALID_SOCKET; 1083 } 1084 1085 for (res = result; res; res = res->ai_next) { 1086 if (res->ai_family == AF_INET) { 1087 if (res->ai_addrlen > sizeof(sockin)) { 1088 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 1089 freeaddrinfo (result); 1090 return INVALID_SOCKET; 1091 } 1092 memcpy (&sockin, res->ai_addr, res->ai_addrlen); 1093 sockin.sin_port = htons (port); 1094 addr = (struct sockaddr *)&sockin; 1095 #ifdef SUPPORT_IP6 1096 } else if (have_ipv6 () && (res->ai_family == AF_INET6)) { 1097 if (res->ai_addrlen > sizeof(sockin6)) { 1098 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 1099 freeaddrinfo (result); 1100 return INVALID_SOCKET; 1101 } 1102 memcpy (&sockin6, res->ai_addr, res->ai_addrlen); 1103 sockin6.sin6_port = htons (port); 1104 addr = (struct sockaddr *)&sockin6; 1105 #endif 1106 } else 1107 continue; /* for */ 1108 1109 s = xmlNanoHTTPConnectAttempt (addr); 1110 if (s != INVALID_SOCKET) { 1111 freeaddrinfo (result); 1112 return (s); 1113 } 1114 } 1115 1116 if (result) 1117 freeaddrinfo (result); 1118 } 1119 #endif 1120 #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32) 1121 else 1122 #endif 1123 #if !defined(HAVE_GETADDRINFO) || !defined(_WIN32) 1124 { 1125 h = gethostbyname (GETHOSTBYNAME_ARG_CAST host); 1126 if (h == NULL) { 1127 1128 /* 1129 * Okay, I got fed up by the non-portability of this error message 1130 * extraction code. it work on Linux, if it work on your platform 1131 * and one want to enable it, send me the defined(foobar) needed 1132 */ 1133 #if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux) 1134 const char *h_err_txt = ""; 1135 1136 switch (h_errno) { 1137 case HOST_NOT_FOUND: 1138 h_err_txt = "Authoritive host not found"; 1139 break; 1140 1141 case TRY_AGAIN: 1142 h_err_txt = 1143 "Non-authoritive host not found or server failure."; 1144 break; 1145 1146 case NO_RECOVERY: 1147 h_err_txt = 1148 "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP."; 1149 break; 1150 1151 #ifdef NO_ADDRESS 1152 case NO_ADDRESS: 1153 h_err_txt = 1154 "Valid name, no data record of requested type."; 1155 break; 1156 #endif 1157 1158 default: 1159 h_err_txt = "No error text defined."; 1160 break; 1161 } 1162 __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt); 1163 #else 1164 __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host"); 1165 #endif 1166 return INVALID_SOCKET; 1167 } 1168 1169 for (i = 0; h->h_addr_list[i]; i++) { 1170 if (h->h_addrtype == AF_INET) { 1171 /* A records (IPv4) */ 1172 if ((unsigned int) h->h_length > sizeof(ia)) { 1173 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 1174 return INVALID_SOCKET; 1175 } 1176 memcpy (&ia, h->h_addr_list[i], h->h_length); 1177 sockin.sin_family = h->h_addrtype; 1178 sockin.sin_addr = ia; 1179 sockin.sin_port = (unsigned short)htons ((unsigned short)port); 1180 addr = (struct sockaddr *) &sockin; 1181 #ifdef SUPPORT_IP6 1182 } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) { 1183 /* AAAA records (IPv6) */ 1184 if ((unsigned int) h->h_length > sizeof(ia6)) { 1185 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); 1186 return INVALID_SOCKET; 1187 } 1188 memcpy (&ia6, h->h_addr_list[i], h->h_length); 1189 sockin6.sin6_family = h->h_addrtype; 1190 sockin6.sin6_addr = ia6; 1191 sockin6.sin6_port = htons (port); 1192 addr = (struct sockaddr *) &sockin6; 1193 #endif 1194 } else 1195 break; /* for */ 1196 1197 s = xmlNanoHTTPConnectAttempt (addr); 1198 if (s != INVALID_SOCKET) 1199 return (s); 1200 } 1201 } 1202 #endif 1203 1204 #ifdef DEBUG_HTTP 1205 xmlGenericError(xmlGenericErrorContext, 1206 "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n", 1207 host); 1208 #endif 1209 return INVALID_SOCKET; 1210 } 1211 1212 1213 /** 1214 * xmlNanoHTTPOpen: 1215 * @URL: The URL to load 1216 * @contentType: if available the Content-Type information will be 1217 * returned at that location 1218 * 1219 * This function try to open a connection to the indicated resource 1220 * via HTTP GET. 1221 * 1222 * Returns NULL in case of failure, otherwise a request handler. 1223 * The contentType, if provided must be freed by the caller 1224 */ 1225 1226 void* 1227 xmlNanoHTTPOpen(const char *URL, char **contentType) { 1228 if (contentType != NULL) *contentType = NULL; 1229 return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0)); 1230 } 1231 1232 /** 1233 * xmlNanoHTTPOpenRedir: 1234 * @URL: The URL to load 1235 * @contentType: if available the Content-Type information will be 1236 * returned at that location 1237 * @redir: if available the redirected URL will be returned 1238 * 1239 * This function try to open a connection to the indicated resource 1240 * via HTTP GET. 1241 * 1242 * Returns NULL in case of failure, otherwise a request handler. 1243 * The contentType, if provided must be freed by the caller 1244 */ 1245 1246 void* 1247 xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) { 1248 if (contentType != NULL) *contentType = NULL; 1249 if (redir != NULL) *redir = NULL; 1250 return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0)); 1251 } 1252 1253 /** 1254 * xmlNanoHTTPRead: 1255 * @ctx: the HTTP context 1256 * @dest: a buffer 1257 * @len: the buffer length 1258 * 1259 * This function tries to read @len bytes from the existing HTTP connection 1260 * and saves them in @dest. This is a blocking call. 1261 * 1262 * Returns the number of byte read. 0 is an indication of an end of connection. 1263 * -1 indicates a parameter error. 1264 */ 1265 int 1266 xmlNanoHTTPRead(void *ctx, void *dest, int len) { 1267 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 1268 #ifdef HAVE_ZLIB_H 1269 int bytes_read = 0; 1270 int orig_avail_in; 1271 int z_ret; 1272 #endif 1273 1274 if (ctx == NULL) return(-1); 1275 if (dest == NULL) return(-1); 1276 if (len <= 0) return(0); 1277 1278 #ifdef HAVE_ZLIB_H 1279 if (ctxt->usesGzip == 1) { 1280 if (ctxt->strm == NULL) return(0); 1281 1282 ctxt->strm->next_out = dest; 1283 ctxt->strm->avail_out = len; 1284 ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr; 1285 1286 while (ctxt->strm->avail_out > 0 && 1287 (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) { 1288 orig_avail_in = ctxt->strm->avail_in = 1289 ctxt->inptr - ctxt->inrptr - bytes_read; 1290 ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read); 1291 1292 z_ret = inflate(ctxt->strm, Z_NO_FLUSH); 1293 bytes_read += orig_avail_in - ctxt->strm->avail_in; 1294 1295 if (z_ret != Z_OK) break; 1296 } 1297 1298 ctxt->inrptr += bytes_read; 1299 return(len - ctxt->strm->avail_out); 1300 } 1301 #endif 1302 1303 while (ctxt->inptr - ctxt->inrptr < len) { 1304 if (xmlNanoHTTPRecv(ctxt) <= 0) break; 1305 } 1306 if (ctxt->inptr - ctxt->inrptr < len) 1307 len = ctxt->inptr - ctxt->inrptr; 1308 memcpy(dest, ctxt->inrptr, len); 1309 ctxt->inrptr += len; 1310 return(len); 1311 } 1312 1313 /** 1314 * xmlNanoHTTPClose: 1315 * @ctx: the HTTP context 1316 * 1317 * This function closes an HTTP context, it ends up the connection and 1318 * free all data related to it. 1319 */ 1320 void 1321 xmlNanoHTTPClose(void *ctx) { 1322 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 1323 1324 if (ctx == NULL) return; 1325 1326 xmlNanoHTTPFreeCtxt(ctxt); 1327 } 1328 1329 /** 1330 * xmlNanoHTTPMethodRedir: 1331 * @URL: The URL to load 1332 * @method: the HTTP method to use 1333 * @input: the input string if any 1334 * @contentType: the Content-Type information IN and OUT 1335 * @redir: the redirected URL OUT 1336 * @headers: the extra headers 1337 * @ilen: input length 1338 * 1339 * This function try to open a connection to the indicated resource 1340 * via HTTP using the given @method, adding the given extra headers 1341 * and the input buffer for the request content. 1342 * 1343 * Returns NULL in case of failure, otherwise a request handler. 1344 * The contentType, or redir, if provided must be freed by the caller 1345 */ 1346 1347 void* 1348 xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input, 1349 char **contentType, char **redir, 1350 const char *headers, int ilen ) { 1351 xmlNanoHTTPCtxtPtr ctxt; 1352 char *bp, *p; 1353 int blen; 1354 SOCKET ret; 1355 int nbRedirects = 0; 1356 char *redirURL = NULL; 1357 #ifdef DEBUG_HTTP 1358 int xmt_bytes; 1359 #endif 1360 1361 if (URL == NULL) return(NULL); 1362 if (method == NULL) method = "GET"; 1363 xmlNanoHTTPInit(); 1364 1365 retry: 1366 if (redirURL == NULL) { 1367 ctxt = xmlNanoHTTPNewCtxt(URL); 1368 if (ctxt == NULL) 1369 return(NULL); 1370 } else { 1371 ctxt = xmlNanoHTTPNewCtxt(redirURL); 1372 if (ctxt == NULL) 1373 return(NULL); 1374 ctxt->location = xmlMemStrdup(redirURL); 1375 } 1376 1377 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) { 1378 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI"); 1379 xmlNanoHTTPFreeCtxt(ctxt); 1380 if (redirURL != NULL) xmlFree(redirURL); 1381 return(NULL); 1382 } 1383 if (ctxt->hostname == NULL) { 1384 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST, 1385 "Failed to identify host in URI"); 1386 xmlNanoHTTPFreeCtxt(ctxt); 1387 if (redirURL != NULL) xmlFree(redirURL); 1388 return(NULL); 1389 } 1390 if (proxy) { 1391 blen = strlen(ctxt->hostname) * 2 + 16; 1392 ret = xmlNanoHTTPConnectHost(proxy, proxyPort); 1393 } 1394 else { 1395 blen = strlen(ctxt->hostname); 1396 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); 1397 } 1398 if (ret == INVALID_SOCKET) { 1399 xmlNanoHTTPFreeCtxt(ctxt); 1400 if (redirURL != NULL) xmlFree(redirURL); 1401 return(NULL); 1402 } 1403 ctxt->fd = ret; 1404 1405 if (input == NULL) 1406 ilen = 0; 1407 else 1408 blen += 36; 1409 1410 if (headers != NULL) 1411 blen += strlen(headers) + 2; 1412 if (contentType && *contentType) 1413 /* reserve for string plus 'Content-Type: \r\n" */ 1414 blen += strlen(*contentType) + 16; 1415 if (ctxt->query != NULL) 1416 /* 1 for '?' */ 1417 blen += strlen(ctxt->query) + 1; 1418 blen += strlen(method) + strlen(ctxt->path) + 24; 1419 #ifdef HAVE_ZLIB_H 1420 /* reserve for possible 'Accept-Encoding: gzip' string */ 1421 blen += 23; 1422 #endif 1423 if (ctxt->port != 80) { 1424 /* reserve space for ':xxxxx', incl. potential proxy */ 1425 if (proxy) 1426 blen += 12; 1427 else 1428 blen += 6; 1429 } 1430 bp = (char*)xmlMallocAtomic(blen); 1431 if ( bp == NULL ) { 1432 xmlNanoHTTPFreeCtxt( ctxt ); 1433 xmlHTTPErrMemory("allocating header buffer"); 1434 return ( NULL ); 1435 } 1436 1437 p = bp; 1438 1439 if (proxy) { 1440 if (ctxt->port != 80) { 1441 p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 1442 method, ctxt->hostname, 1443 ctxt->port, ctxt->path ); 1444 } 1445 else 1446 p += snprintf( p, blen - (p - bp), "%s http://%s%s", method, 1447 ctxt->hostname, ctxt->path); 1448 } 1449 else 1450 p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path); 1451 1452 if (ctxt->query != NULL) 1453 p += snprintf( p, blen - (p - bp), "?%s", ctxt->query); 1454 1455 if (ctxt->port == 80) { 1456 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n", 1457 ctxt->hostname); 1458 } else { 1459 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n", 1460 ctxt->hostname, ctxt->port); 1461 } 1462 1463 #ifdef HAVE_ZLIB_H 1464 p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n"); 1465 #endif 1466 1467 if (contentType != NULL && *contentType) 1468 p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType); 1469 1470 if (headers != NULL) 1471 p += snprintf( p, blen - (p - bp), "%s", headers ); 1472 1473 if (input != NULL) 1474 snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen ); 1475 else 1476 snprintf(p, blen - (p - bp), "\r\n"); 1477 1478 #ifdef DEBUG_HTTP 1479 xmlGenericError(xmlGenericErrorContext, 1480 "-> %s%s", proxy? "(Proxy) " : "", bp); 1481 if ((blen -= strlen(bp)+1) < 0) 1482 xmlGenericError(xmlGenericErrorContext, 1483 "ERROR: overflowed buffer by %d bytes\n", -blen); 1484 #endif 1485 ctxt->outptr = ctxt->out = bp; 1486 ctxt->state = XML_NANO_HTTP_WRITE; 1487 blen = strlen( ctxt->out ); 1488 #ifdef DEBUG_HTTP 1489 xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen ); 1490 if ( xmt_bytes != blen ) 1491 xmlGenericError( xmlGenericErrorContext, 1492 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n", 1493 xmt_bytes, blen, 1494 "bytes of HTTP headers sent to host", 1495 ctxt->hostname ); 1496 #else 1497 xmlNanoHTTPSend(ctxt, ctxt->out, blen ); 1498 #endif 1499 1500 if ( input != NULL ) { 1501 #ifdef DEBUG_HTTP 1502 xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen ); 1503 1504 if ( xmt_bytes != ilen ) 1505 xmlGenericError( xmlGenericErrorContext, 1506 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n", 1507 xmt_bytes, ilen, 1508 "bytes of HTTP content sent to host", 1509 ctxt->hostname ); 1510 #else 1511 xmlNanoHTTPSend( ctxt, input, ilen ); 1512 #endif 1513 } 1514 1515 ctxt->state = XML_NANO_HTTP_READ; 1516 1517 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) { 1518 if (*p == 0) { 1519 ctxt->content = ctxt->inrptr; 1520 xmlFree(p); 1521 break; 1522 } 1523 xmlNanoHTTPScanAnswer(ctxt, p); 1524 1525 #ifdef DEBUG_HTTP 1526 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p); 1527 #endif 1528 xmlFree(p); 1529 } 1530 1531 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && 1532 (ctxt->returnValue < 400)) { 1533 #ifdef DEBUG_HTTP 1534 xmlGenericError(xmlGenericErrorContext, 1535 "\nRedirect to: %s\n", ctxt->location); 1536 #endif 1537 while ( xmlNanoHTTPRecv(ctxt) > 0 ) ; 1538 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { 1539 nbRedirects++; 1540 if (redirURL != NULL) 1541 xmlFree(redirURL); 1542 redirURL = xmlMemStrdup(ctxt->location); 1543 xmlNanoHTTPFreeCtxt(ctxt); 1544 goto retry; 1545 } 1546 xmlNanoHTTPFreeCtxt(ctxt); 1547 if (redirURL != NULL) xmlFree(redirURL); 1548 #ifdef DEBUG_HTTP 1549 xmlGenericError(xmlGenericErrorContext, 1550 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n"); 1551 #endif 1552 return(NULL); 1553 } 1554 1555 if (contentType != NULL) { 1556 if (ctxt->contentType != NULL) 1557 *contentType = xmlMemStrdup(ctxt->contentType); 1558 else 1559 *contentType = NULL; 1560 } 1561 1562 if ((redir != NULL) && (redirURL != NULL)) { 1563 *redir = redirURL; 1564 } else { 1565 if (redirURL != NULL) 1566 xmlFree(redirURL); 1567 if (redir != NULL) 1568 *redir = NULL; 1569 } 1570 1571 #ifdef DEBUG_HTTP 1572 if (ctxt->contentType != NULL) 1573 xmlGenericError(xmlGenericErrorContext, 1574 "\nCode %d, content-type '%s'\n\n", 1575 ctxt->returnValue, ctxt->contentType); 1576 else 1577 xmlGenericError(xmlGenericErrorContext, 1578 "\nCode %d, no content-type\n\n", 1579 ctxt->returnValue); 1580 #endif 1581 1582 return((void *) ctxt); 1583 } 1584 1585 /** 1586 * xmlNanoHTTPMethod: 1587 * @URL: The URL to load 1588 * @method: the HTTP method to use 1589 * @input: the input string if any 1590 * @contentType: the Content-Type information IN and OUT 1591 * @headers: the extra headers 1592 * @ilen: input length 1593 * 1594 * This function try to open a connection to the indicated resource 1595 * via HTTP using the given @method, adding the given extra headers 1596 * and the input buffer for the request content. 1597 * 1598 * Returns NULL in case of failure, otherwise a request handler. 1599 * The contentType, if provided must be freed by the caller 1600 */ 1601 1602 void* 1603 xmlNanoHTTPMethod(const char *URL, const char *method, const char *input, 1604 char **contentType, const char *headers, int ilen) { 1605 return(xmlNanoHTTPMethodRedir(URL, method, input, contentType, 1606 NULL, headers, ilen)); 1607 } 1608 1609 /** 1610 * xmlNanoHTTPFetch: 1611 * @URL: The URL to load 1612 * @filename: the filename where the content should be saved 1613 * @contentType: if available the Content-Type information will be 1614 * returned at that location 1615 * 1616 * This function try to fetch the indicated resource via HTTP GET 1617 * and save it's content in the file. 1618 * 1619 * Returns -1 in case of failure, 0 incase of success. The contentType, 1620 * if provided must be freed by the caller 1621 */ 1622 int 1623 xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) { 1624 void *ctxt = NULL; 1625 char *buf = NULL; 1626 int fd; 1627 int len; 1628 int ret = 0; 1629 1630 if (filename == NULL) return(-1); 1631 ctxt = xmlNanoHTTPOpen(URL, contentType); 1632 if (ctxt == NULL) return(-1); 1633 1634 if (!strcmp(filename, "-")) 1635 fd = 0; 1636 else { 1637 fd = open(filename, O_CREAT | O_WRONLY, 00644); 1638 if (fd < 0) { 1639 xmlNanoHTTPClose(ctxt); 1640 if ((contentType != NULL) && (*contentType != NULL)) { 1641 xmlFree(*contentType); 1642 *contentType = NULL; 1643 } 1644 return(-1); 1645 } 1646 } 1647 1648 xmlNanoHTTPFetchContent( ctxt, &buf, &len ); 1649 if ( len > 0 ) { 1650 if (write(fd, buf, len) == -1) { 1651 ret = -1; 1652 } 1653 } 1654 1655 xmlNanoHTTPClose(ctxt); 1656 close(fd); 1657 return(ret); 1658 } 1659 1660 #ifdef LIBXML_OUTPUT_ENABLED 1661 /** 1662 * xmlNanoHTTPSave: 1663 * @ctxt: the HTTP context 1664 * @filename: the filename where the content should be saved 1665 * 1666 * This function saves the output of the HTTP transaction to a file 1667 * It closes and free the context at the end 1668 * 1669 * Returns -1 in case of failure, 0 incase of success. 1670 */ 1671 int 1672 xmlNanoHTTPSave(void *ctxt, const char *filename) { 1673 char *buf = NULL; 1674 int fd; 1675 int len; 1676 int ret = 0; 1677 1678 if ((ctxt == NULL) || (filename == NULL)) return(-1); 1679 1680 if (!strcmp(filename, "-")) 1681 fd = 0; 1682 else { 1683 fd = open(filename, O_CREAT | O_WRONLY, 0666); 1684 if (fd < 0) { 1685 xmlNanoHTTPClose(ctxt); 1686 return(-1); 1687 } 1688 } 1689 1690 xmlNanoHTTPFetchContent( ctxt, &buf, &len ); 1691 if ( len > 0 ) { 1692 if (write(fd, buf, len) == -1) { 1693 ret = -1; 1694 } 1695 } 1696 1697 xmlNanoHTTPClose(ctxt); 1698 close(fd); 1699 return(ret); 1700 } 1701 #endif /* LIBXML_OUTPUT_ENABLED */ 1702 1703 /** 1704 * xmlNanoHTTPReturnCode: 1705 * @ctx: the HTTP context 1706 * 1707 * Get the latest HTTP return code received 1708 * 1709 * Returns the HTTP return code for the request. 1710 */ 1711 int 1712 xmlNanoHTTPReturnCode(void *ctx) { 1713 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 1714 1715 if (ctxt == NULL) return(-1); 1716 1717 return(ctxt->returnValue); 1718 } 1719 1720 /** 1721 * xmlNanoHTTPAuthHeader: 1722 * @ctx: the HTTP context 1723 * 1724 * Get the authentication header of an HTTP context 1725 * 1726 * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate 1727 * header. 1728 */ 1729 const char * 1730 xmlNanoHTTPAuthHeader(void *ctx) { 1731 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; 1732 1733 if (ctxt == NULL) return(NULL); 1734 1735 return(ctxt->authHeader); 1736 } 1737 1738 /** 1739 * xmlNanoHTTPContentLength: 1740 * @ctx: the HTTP context 1741 * 1742 * Provides the specified content length from the HTTP header. 1743 * 1744 * Return the specified content length from the HTTP header. Note that 1745 * a value of -1 indicates that the content length element was not included in 1746 * the response header. 1747 */ 1748 int 1749 xmlNanoHTTPContentLength( void * ctx ) { 1750 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 1751 1752 return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength ); 1753 } 1754 1755 /** 1756 * xmlNanoHTTPRedir: 1757 * @ctx: the HTTP context 1758 * 1759 * Provides the specified redirection URL if available from the HTTP header. 1760 * 1761 * Return the specified redirection URL or NULL if not redirected. 1762 */ 1763 const char * 1764 xmlNanoHTTPRedir( void * ctx ) { 1765 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 1766 1767 return ( ( ctxt == NULL ) ? NULL : ctxt->location ); 1768 } 1769 1770 /** 1771 * xmlNanoHTTPEncoding: 1772 * @ctx: the HTTP context 1773 * 1774 * Provides the specified encoding if specified in the HTTP headers. 1775 * 1776 * Return the specified encoding or NULL if not available 1777 */ 1778 const char * 1779 xmlNanoHTTPEncoding( void * ctx ) { 1780 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 1781 1782 return ( ( ctxt == NULL ) ? NULL : ctxt->encoding ); 1783 } 1784 1785 /** 1786 * xmlNanoHTTPMimeType: 1787 * @ctx: the HTTP context 1788 * 1789 * Provides the specified Mime-Type if specified in the HTTP headers. 1790 * 1791 * Return the specified Mime-Type or NULL if not available 1792 */ 1793 const char * 1794 xmlNanoHTTPMimeType( void * ctx ) { 1795 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 1796 1797 return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType ); 1798 } 1799 1800 /** 1801 * xmlNanoHTTPFetchContent: 1802 * @ctx: the HTTP context 1803 * @ptr: pointer to set to the content buffer. 1804 * @len: integer pointer to hold the length of the content 1805 * 1806 * Check if all the content was read 1807 * 1808 * Returns 0 if all the content was read and available, returns 1809 * -1 if received content length was less than specified or an error 1810 * occurred. 1811 */ 1812 static int 1813 xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) { 1814 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx; 1815 1816 int rc = 0; 1817 int cur_lgth; 1818 int rcvd_lgth; 1819 int dummy_int; 1820 char * dummy_ptr = NULL; 1821 1822 /* Dummy up return input parameters if not provided */ 1823 1824 if ( len == NULL ) 1825 len = &dummy_int; 1826 1827 if ( ptr == NULL ) 1828 ptr = &dummy_ptr; 1829 1830 /* But can't work without the context pointer */ 1831 1832 if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) { 1833 *len = 0; 1834 *ptr = NULL; 1835 return ( -1 ); 1836 } 1837 1838 rcvd_lgth = ctxt->inptr - ctxt->content; 1839 1840 while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) { 1841 1842 rcvd_lgth += cur_lgth; 1843 if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) ) 1844 break; 1845 } 1846 1847 *ptr = ctxt->content; 1848 *len = rcvd_lgth; 1849 1850 if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) ) 1851 rc = -1; 1852 else if ( rcvd_lgth == 0 ) 1853 rc = -1; 1854 1855 return ( rc ); 1856 } 1857 1858 #ifdef STANDALONE 1859 int main(int argc, char **argv) { 1860 char *contentType = NULL; 1861 1862 if (argv[1] != NULL) { 1863 if (argv[2] != NULL) 1864 xmlNanoHTTPFetch(argv[1], argv[2], &contentType); 1865 else 1866 xmlNanoHTTPFetch(argv[1], "-", &contentType); 1867 if (contentType != NULL) xmlFree(contentType); 1868 } else { 1869 xmlGenericError(xmlGenericErrorContext, 1870 "%s: minimal HTTP GET implementation\n", argv[0]); 1871 xmlGenericError(xmlGenericErrorContext, 1872 "\tusage %s [ URL [ filename ] ]\n", argv[0]); 1873 } 1874 xmlNanoHTTPCleanup(); 1875 xmlMemoryDump(); 1876 return(0); 1877 } 1878 #endif /* STANDALONE */ 1879 #else /* !LIBXML_HTTP_ENABLED */ 1880 #ifdef STANDALONE 1881 #include <stdio.h> 1882 int main(int argc, char **argv) { 1883 xmlGenericError(xmlGenericErrorContext, 1884 "%s : HTTP support not compiled in\n", argv[0]); 1885 return(0); 1886 } 1887 #endif /* STANDALONE */ 1888 #endif /* LIBXML_HTTP_ENABLED */ 1889 #define bottom_nanohttp 1890 #include "elfgcchack.h" 1891