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