nanohttp.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:30k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  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@w3.org
  12.  */
  13.  
  14. /* TODO add compression support, Send the Accept- , and decompress on the
  15.         fly with ZLIB if found at compile-time */
  16. #ifdef WIN32
  17. #define INCLUDE_WINSOCK
  18. #include "win32config.h"
  19. #else
  20. #include "config.h"
  21. #endif
  22. #include "xmlversion.h"
  23. #ifdef LIBXML_HTTP_ENABLED
  24. #include <stdio.h>
  25. #include <string.h>
  26. #ifdef HAVE_STDLIB_H
  27. #include <stdlib.h>
  28. #endif
  29. #ifdef HAVE_UNISTD_H
  30. #include <unistd.h>
  31. #endif
  32. #ifdef HAVE_SYS_SOCKET_H
  33. #include <sys/socket.h>
  34. #endif
  35. #ifdef HAVE_NETINET_IN_H
  36. #include <netinet/in.h>
  37. #endif
  38. #ifdef HAVE_ARPA_INET_H
  39. #include <arpa/inet.h>
  40. #endif
  41. #ifdef HAVE_NETDB_H
  42. #include <netdb.h>
  43. #endif
  44. #ifdef HAVE_FCNTL_H
  45. #include <fcntl.h> 
  46. #endif
  47. #ifdef HAVE_ERRNO_H
  48. #include <errno.h>
  49. #endif
  50. #ifdef HAVE_SYS_TIME_H
  51. #include <sys/time.h>
  52. #endif
  53. #ifdef HAVE_SYS_SELECT_H
  54. #include <sys/select.h>
  55. #endif
  56. #ifdef HAVE_STRINGS_H
  57. #include <strings.h>
  58. #endif
  59. #include <libxml/xmlmemory.h>
  60. #include <libxml/nanohttp.h>
  61. #ifdef STANDALONE
  62. #define DEBUG_HTTP
  63. #endif
  64. #define XML_NANO_HTTP_MAX_REDIR 10
  65. #define XML_NANO_HTTP_CHUNK 4096
  66. #define XML_NANO_HTTP_CLOSED 0
  67. #define XML_NANO_HTTP_WRITE 1
  68. #define XML_NANO_HTTP_READ 2
  69. #define XML_NANO_HTTP_NONE 4
  70. typedef struct xmlNanoHTTPCtxt {
  71.     char *protocol; /* the protocol name */
  72.     char *hostname; /* the host name */
  73.     int port; /* the port */
  74.     char *path; /* the path within the URL */
  75.     int fd; /* the file descriptor for the socket */
  76.     int state; /* WRITE / READ / CLOSED */
  77.     char *out; /* buffer sent (zero terminated) */
  78.     char *outptr; /* index within the buffer sent */
  79.     char *in; /* the receiving buffer */
  80.     char *content; /* the start of the content */
  81.     char *inptr; /* the next byte to read from network */
  82.     char *inrptr; /* the next byte to give back to the client */
  83.     int inlen; /* len of the input buffer */
  84.     int last; /* return code for last operation */
  85.     int returnValue; /* the protocol return value */
  86.     char *contentType; /* the MIME type for the input */
  87.     char *location; /* the new URL in case of redirect */
  88. } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
  89. static int initialized = 0;
  90. static char *proxy = NULL; /* the proxy name if any */
  91. static int proxyPort; /* the proxy port if any */
  92. /**
  93.  * xmlNanoHTTPInit:
  94.  *
  95.  * Initialize the HTTP protocol layer.
  96.  * Currently it just checks for proxy informations
  97.  */
  98. void
  99. xmlNanoHTTPInit(void) {
  100.     const char *env;
  101.     if (initialized)
  102. return;
  103.     if (proxy == NULL) {
  104. proxyPort = 80;
  105. env = getenv("no_proxy");
  106. if (env != NULL)
  107.     goto done;
  108. env = getenv("http_proxy");
  109. if (env != NULL) {
  110.     xmlNanoHTTPScanProxy(env);
  111.     goto done;
  112. }
  113. env = getenv("HTTP_PROXY");
  114. if (env != NULL) {
  115.     xmlNanoHTTPScanProxy(env);
  116.     goto done;
  117. }
  118.     }
  119. done:
  120.     initialized = 1;
  121. }
  122. /**
  123.  * xmlNanoHTTPClenup:
  124.  *
  125.  * Cleanup the HTTP protocol layer.
  126.  */
  127. void
  128. xmlNanoHTTPCleanup(void) {
  129.     if (proxy != NULL)
  130. xmlFree(proxy);
  131.     initialized = 0;
  132.     return;
  133. }
  134. /**
  135.  * xmlNanoHTTPScanURL:
  136.  * @ctxt:  an HTTP context
  137.  * @URL:  The URL used to initialize the context
  138.  *
  139.  * (Re)Initialize an HTTP context by parsing the URL and finding
  140.  * the protocol host port and path it indicates.
  141.  */
  142. static void
  143. xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
  144.     const char *cur = URL;
  145.     char buf[4096];
  146.     int index = 0;
  147.     int port = 0;
  148.     if (ctxt->protocol != NULL) { 
  149.         xmlFree(ctxt->protocol);
  150. ctxt->protocol = NULL;
  151.     }
  152.     if (ctxt->hostname != NULL) { 
  153.         xmlFree(ctxt->hostname);
  154. ctxt->hostname = NULL;
  155.     }
  156.     if (ctxt->path != NULL) { 
  157.         xmlFree(ctxt->path);
  158. ctxt->path = NULL;
  159.     }
  160.     if (URL == NULL) return;
  161.     buf[index] = 0;
  162.     while (*cur != 0) {
  163.         if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
  164.     buf[index] = 0;
  165.     ctxt->protocol = xmlMemStrdup(buf);
  166.     index = 0;
  167.             cur += 3;
  168.     break;
  169. }
  170. buf[index++] = *cur++;
  171.     }
  172.     if (*cur == 0) return;
  173.     buf[index] = 0;
  174.     while (1) {
  175.         if (cur[0] == ':') {
  176.     buf[index] = 0;
  177.     ctxt->hostname = xmlMemStrdup(buf);
  178.     index = 0;
  179.     cur += 1;
  180.     while ((*cur >= '0') && (*cur <= '9')) {
  181.         port *= 10;
  182. port += *cur - '0';
  183. cur++;
  184.     }
  185.     if (port != 0) ctxt->port = port;
  186.     while ((cur[0] != '/') && (*cur != 0)) 
  187.         cur++;
  188.     break;
  189. }
  190.         if ((*cur == '/') || (*cur == 0)) {
  191.     buf[index] = 0;
  192.     ctxt->hostname = xmlMemStrdup(buf);
  193.     index = 0;
  194.     break;
  195. }
  196. buf[index++] = *cur++;
  197.     }
  198.     if (*cur == 0) 
  199.         ctxt->path = xmlMemStrdup("/");
  200.     else {
  201.         index = 0;
  202.         buf[index] = 0;
  203. while (*cur != 0)
  204.     buf[index++] = *cur++;
  205. buf[index] = 0;
  206. ctxt->path = xmlMemStrdup(buf);
  207.     }
  208. }
  209. /**
  210.  * xmlNanoHTTPScanProxy:
  211.  * @URL:  The proxy URL used to initialize the proxy context
  212.  *
  213.  * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
  214.  * the protocol host port it indicates.
  215.  * Should be like http://myproxy/ or http://myproxy:3128/
  216.  * A NULL URL cleans up proxy informations.
  217.  */
  218. void
  219. xmlNanoHTTPScanProxy(const char *URL) {
  220.     const char *cur = URL;
  221.     char buf[4096];
  222.     int index = 0;
  223.     int port = 0;
  224.     if (proxy != NULL) { 
  225.         xmlFree(proxy);
  226. proxy = NULL;
  227.     }
  228.     if (proxyPort != 0) { 
  229. proxyPort = 0;
  230.     }
  231. #ifdef DEBUG_HTTP
  232.     if (URL == NULL)
  233. printf("Removing HTTP proxy infon");
  234.     else
  235. printf("Using HTTP proxy %sn", URL);
  236. #endif
  237.     if (URL == NULL) return;
  238.     buf[index] = 0;
  239.     while (*cur != 0) {
  240.         if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
  241.     buf[index] = 0;
  242.     index = 0;
  243.             cur += 3;
  244.     break;
  245. }
  246. buf[index++] = *cur++;
  247.     }
  248.     if (*cur == 0) return;
  249.     buf[index] = 0;
  250.     while (1) {
  251.         if (cur[0] == ':') {
  252.     buf[index] = 0;
  253.     proxy = xmlMemStrdup(buf);
  254.     index = 0;
  255.     cur += 1;
  256.     while ((*cur >= '0') && (*cur <= '9')) {
  257.         port *= 10;
  258. port += *cur - '0';
  259. cur++;
  260.     }
  261.     if (port != 0) proxyPort = port;
  262.     while ((cur[0] != '/') && (*cur != 0)) 
  263.         cur++;
  264.     break;
  265. }
  266.         if ((*cur == '/') || (*cur == 0)) {
  267.     buf[index] = 0;
  268.     proxy = xmlMemStrdup(buf);
  269.     index = 0;
  270.     break;
  271. }
  272. buf[index++] = *cur++;
  273.     }
  274. }
  275. /**
  276.  * xmlNanoHTTPNewCtxt:
  277.  * @URL:  The URL used to initialize the context
  278.  *
  279.  * Allocate and initialize a new HTTP context.
  280.  *
  281.  * Returns an HTTP context or NULL in case of error.
  282.  */
  283. static xmlNanoHTTPCtxtPtr
  284. xmlNanoHTTPNewCtxt(const char *URL) {
  285.     xmlNanoHTTPCtxtPtr ret;
  286.     ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
  287.     if (ret == NULL) return(NULL);
  288.     memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
  289.     ret->port = 80;
  290.     ret->returnValue = 0;
  291.     xmlNanoHTTPScanURL(ret, URL);
  292.     return(ret);
  293. }
  294. /**
  295.  * xmlNanoHTTPFreeCtxt:
  296.  * @ctxt:  an HTTP context
  297.  *
  298.  * Frees the context after closing the connection.
  299.  */
  300. static void
  301. xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
  302.     if (ctxt == NULL) return;
  303.     if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
  304.     if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
  305.     if (ctxt->path != NULL) xmlFree(ctxt->path);
  306.     if (ctxt->out != NULL) xmlFree(ctxt->out);
  307.     if (ctxt->in != NULL) xmlFree(ctxt->in);
  308.     if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
  309.     if (ctxt->location != NULL) xmlFree(ctxt->location);
  310.     ctxt->state = XML_NANO_HTTP_NONE;
  311.     if (ctxt->fd >= 0) close(ctxt->fd);
  312.     ctxt->fd = -1;
  313.     xmlFree(ctxt);
  314. }
  315. /**
  316.  * xmlNanoHTTPSend:
  317.  * @ctxt:  an HTTP context
  318.  *
  319.  * Send the input needed to initiate the processing on the server side
  320.  */
  321. static void
  322. xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
  323.     if (ctxt->state & XML_NANO_HTTP_WRITE)
  324. ctxt->last = write(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr));
  325. }
  326. /**
  327.  * xmlNanoHTTPRecv:
  328.  * @ctxt:  an HTTP context
  329.  *
  330.  * Read information coming from the HTTP connection.
  331.  * This is a blocking call (but it blocks in select(), not read()).
  332.  *
  333.  * Returns the number of byte read or -1 in case of error.
  334.  */
  335. static int
  336. xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
  337.     fd_set rfd;
  338.     struct timeval tv;
  339.     while (ctxt->state & XML_NANO_HTTP_READ) {
  340. if (ctxt->in == NULL) {
  341.     ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
  342.     if (ctxt->in == NULL) {
  343.         ctxt->last = -1;
  344. return(-1);
  345.     }
  346.     ctxt->inlen = 65000;
  347.     ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
  348. }
  349. if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
  350.     int delta = ctxt->inrptr - ctxt->in;
  351.     int len = ctxt->inptr - ctxt->inrptr;
  352.     
  353.     memmove(ctxt->in, ctxt->inrptr, len);
  354.     ctxt->inrptr -= delta;
  355.     ctxt->content -= delta;
  356.     ctxt->inptr -= delta;
  357. }
  358.         if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
  359.     int d_inptr = ctxt->inptr - ctxt->in;
  360.     int d_content = ctxt->content - ctxt->in;
  361.     int d_inrptr = ctxt->inrptr - ctxt->in;
  362.     ctxt->inlen *= 2;
  363.             ctxt->in = (char *) xmlRealloc(ctxt->in, ctxt->inlen);
  364.     if (ctxt->in == NULL) {
  365.         ctxt->last = -1;
  366. return(-1);
  367.     }
  368.             ctxt->inptr = ctxt->in + d_inptr;
  369.             ctxt->content = ctxt->in + d_content;
  370.             ctxt->inrptr = ctxt->in + d_inrptr;
  371. }
  372. ctxt->last = read(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK);
  373. if (ctxt->last > 0) {
  374.     ctxt->inptr += ctxt->last;
  375.     return(ctxt->last);
  376. }
  377. if (ctxt->last == 0) {
  378.     return(0);
  379. }
  380. #ifdef EWOULDBLOCK
  381. if ((ctxt->last == -1) && (errno != EWOULDBLOCK)) {
  382.     return(0);
  383. }
  384. #endif
  385. tv.tv_sec=10;
  386. tv.tv_usec=0;
  387. FD_ZERO(&rfd);
  388. FD_SET(ctxt->fd, &rfd);
  389. if(select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
  390. return(0);
  391.     }
  392.     return(0);
  393. }
  394. /**
  395.  * xmlNanoHTTPReadLine:
  396.  * @ctxt:  an HTTP context
  397.  *
  398.  * Read one line in the HTTP server output, usually for extracting
  399.  * the HTTP protocol informations from the answer header.
  400.  *
  401.  * Returns a newly allocated string with a copy of the line, or NULL
  402.  *         which indicate the end of the input.
  403.  */
  404. static char *
  405. xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
  406.     char buf[4096];
  407.     char *bp=buf;
  408.     
  409.     while(bp - buf < 4095) {
  410. if(ctxt->inrptr == ctxt->inptr) {
  411.     if (xmlNanoHTTPRecv(ctxt) == 0) {
  412. if (bp == buf)
  413.     return(NULL);
  414. else
  415.     *bp = 0;
  416. return(xmlMemStrdup(buf));
  417.     }
  418. }
  419. *bp = *ctxt->inrptr++;
  420. if(*bp == 'n') {
  421.     *bp = 0;
  422.     return(xmlMemStrdup(buf));
  423. }
  424. if(*bp != 'r')
  425.     bp++;
  426.     }
  427.     buf[4095] = 0;
  428.     return(xmlMemStrdup(buf));
  429. }
  430. /**
  431.  * xmlNanoHTTPScanAnswer:
  432.  * @ctxt:  an HTTP context
  433.  * @line:  an HTTP header line
  434.  *
  435.  * Try to extract useful informations from the server answer.
  436.  * We currently parse and process:
  437.  *  - The HTTP revision/ return code
  438.  *  - The Content-Type
  439.  *  - The Location for redirrect processing.
  440.  *
  441.  * Returns -1 in case of failure, the file descriptor number otherwise
  442.  */
  443. static void
  444. xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
  445.     const char *cur = line;
  446.     if (line == NULL) return;
  447.     if (!strncmp(line, "HTTP/", 5)) {
  448.         int version = 0;
  449. int ret = 0;
  450. cur += 5;
  451. while ((*cur >= '0') && (*cur <= '9')) {
  452.     version *= 10;
  453.     version += *cur - '0';
  454.     cur++;
  455. }
  456. if (*cur == '.') {
  457.     cur++;
  458.     if ((*cur >= '0') && (*cur <= '9')) {
  459. version *= 10;
  460. version += *cur - '0';
  461. cur++;
  462.     }
  463.     while ((*cur >= '0') && (*cur <= '9'))
  464. cur++;
  465. } else
  466.     version *= 10;
  467. if ((*cur != ' ') && (*cur != 't')) return;
  468. while ((*cur == ' ') || (*cur == 't')) cur++;
  469. if ((*cur < '0') || (*cur > '9')) return;
  470. while ((*cur >= '0') && (*cur <= '9')) {
  471.     ret *= 10;
  472.     ret += *cur - '0';
  473.     cur++;
  474. }
  475. if ((*cur != 0) && (*cur != ' ') && (*cur != 't')) return;
  476. ctxt->returnValue = ret;
  477.     } else if (!strncmp(line, "Content-Type:", 13)) {
  478.         cur += 13;
  479. while ((*cur == ' ') || (*cur == 't')) cur++;
  480. if (ctxt->contentType != NULL)
  481.     xmlFree(ctxt->contentType);
  482. ctxt->contentType = xmlMemStrdup(cur);
  483.     } else if (!strncmp(line, "ContentType:", 12)) {
  484.         cur += 12;
  485. if (ctxt->contentType != NULL) return;
  486. while ((*cur == ' ') || (*cur == 't')) cur++;
  487. ctxt->contentType = xmlMemStrdup(cur);
  488.     } else if (!strncmp(line, "content-type:", 13)) {
  489.         cur += 13;
  490. if (ctxt->contentType != NULL) return;
  491. while ((*cur == ' ') || (*cur == 't')) cur++;
  492. ctxt->contentType = xmlMemStrdup(cur);
  493.     } else if (!strncmp(line, "contenttype:", 12)) {
  494.         cur += 12;
  495. if (ctxt->contentType != NULL) return;
  496. while ((*cur == ' ') || (*cur == 't')) cur++;
  497. ctxt->contentType = xmlMemStrdup(cur);
  498.     } else if (!strncmp(line, "Location:", 9)) {
  499.         cur += 9;
  500. while ((*cur == ' ') || (*cur == 't')) cur++;
  501. if (ctxt->location != NULL)
  502.     xmlFree(ctxt->location);
  503. ctxt->location = xmlMemStrdup(cur);
  504.     } else if (!strncmp(line, "location:", 9)) {
  505.         cur += 9;
  506. if (ctxt->location != NULL) return;
  507. while ((*cur == ' ') || (*cur == 't')) cur++;
  508. ctxt->location = xmlMemStrdup(cur);
  509.     }
  510. }
  511. /**
  512.  * xmlNanoHTTPConnectAttempt:
  513.  * @ia:  an internet adress structure
  514.  * @port:  the port number
  515.  *
  516.  * Attempt a connection to the given IP:port endpoint. It forces
  517.  * non-blocking semantic on the socket, and allow 60 seconds for
  518.  * the host to answer.
  519.  *
  520.  * Returns -1 in case of failure, the file descriptor number otherwise
  521.  */
  522. static int
  523. xmlNanoHTTPConnectAttempt(struct in_addr ia, int port)
  524. {
  525.     int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  526.     struct sockaddr_in sin;
  527.     fd_set wfd;
  528.     struct timeval tv;
  529.     int status;
  530.     
  531.     if(s==-1) {
  532. #ifdef DEBUG_HTTP
  533. perror("socket");
  534. #endif
  535. return(-1);
  536.     }
  537.     
  538. #ifdef _WINSOCKAPI_
  539.     {
  540. long levents = FD_READ | FD_WRITE | FD_ACCEPT |
  541.        FD_CONNECT | FD_CLOSE ;
  542. int rv = 0 ;
  543. u_long one = 1;
  544. status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
  545.     }
  546. #else /* _WINSOCKAPI_ */
  547. #if defined(VMS)
  548.     {
  549. int enable = 1;
  550. status = IOCTL(s, FIONBIO, &enable);
  551.     }
  552. #else /* VMS */
  553.     if((status = fcntl(s, F_GETFL, 0)) != -1) {
  554. #ifdef O_NONBLOCK
  555. status |= O_NONBLOCK;
  556. #else /* O_NONBLOCK */
  557. #ifdef F_NDELAY
  558. status |= F_NDELAY;
  559. #endif /* F_NDELAY */
  560. #endif /* !O_NONBLOCK */
  561. status = fcntl(s, F_SETFL, status);
  562.     }
  563.     if(status < 0) {
  564. #ifdef DEBUG_HTTP
  565. perror("nonblocking");
  566. #endif
  567. close(s);
  568. return(-1);
  569.     }
  570. #endif /* !VMS */
  571. #endif /* !_WINSOCKAPI_ */
  572.     sin.sin_family = AF_INET;
  573.     sin.sin_addr   = ia;
  574.     sin.sin_port   = htons(port);
  575.     
  576.     if((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1) &&
  577.        (errno != EINPROGRESS)) {
  578. perror("connect");
  579. close(s);
  580. return(-1);
  581.     }
  582.     
  583.     tv.tv_sec = 60; /* We use 60 second timeouts for now */
  584.     tv.tv_usec = 0;
  585.     
  586.     FD_ZERO(&wfd);
  587.     FD_SET(s, &wfd);
  588.     
  589.     switch(select(s+1, NULL, &wfd, NULL, &tv))
  590.     {
  591. case 0:
  592.     /* Time out */
  593.     close(s);
  594.     return(-1);
  595. case -1:
  596.     /* Ermm.. ?? */
  597. #ifdef DEBUG_HTTP
  598.     perror("select");
  599. #endif
  600.     close(s);
  601.     return(-1);
  602.     }
  603.     
  604.     return(s);
  605. }
  606.  
  607. /**
  608.  * xmlNanoHTTPConnectHost:
  609.  * @host:  the host name
  610.  * @port:  the port number
  611.  *
  612.  * Attempt a connection to the given host:port endpoint. It tries
  613.  * the multiple IP provided by the DNS if available.
  614.  *
  615.  * Returns -1 in case of failure, the file descriptor number otherwise
  616.  */
  617. static int
  618. xmlNanoHTTPConnectHost(const char *host, int port)
  619. {
  620.     struct hostent *h;
  621.     int i;
  622.     int s;
  623.     
  624.     h=gethostbyname(host);
  625.     if(h==NULL)
  626.     {
  627. #ifdef DEBUG_HTTP
  628. fprintf(stderr,"unable to resolve '%s'.n", host);
  629. #endif
  630. return(-1);
  631.     }
  632.     
  633.     for(i=0; h->h_addr_list[i]; i++)
  634.     {
  635. struct in_addr ia;
  636. memcpy(&ia, h->h_addr_list[i],4);
  637. s = xmlNanoHTTPConnectAttempt(ia, port);
  638. if(s != -1)
  639.     return(s);
  640.     }
  641. #ifdef DEBUG_HTTP
  642.     fprintf(stderr, "unable to connect to '%s'.n", host);
  643. #endif
  644.     return(-1);
  645. }
  646. /**
  647.  * xmlNanoHTTPOpen:
  648.  * @URL:  The URL to load
  649.  * @contentType:  if available the Content-Type information will be
  650.  *                returned at that location
  651.  *
  652.  * This function try to open a connection to the indicated resource
  653.  * via HTTP GET.
  654.  *
  655.  * Returns NULL in case of failure, otherwise a request handler.
  656.  *     The contentType, if provided must be freed by the caller
  657.  */
  658. void *
  659. xmlNanoHTTPOpen(const char *URL, char **contentType) {
  660.     xmlNanoHTTPCtxtPtr ctxt;
  661.     char buf[4096];
  662.     int ret;
  663.     char *p;
  664.     int head;
  665.     int nbRedirects = 0;
  666.     char *redirURL = NULL;
  667.     
  668.     xmlNanoHTTPInit();
  669.     if (contentType != NULL) *contentType = NULL;
  670. retry:
  671.     if (redirURL == NULL)
  672. ctxt = xmlNanoHTTPNewCtxt(URL);
  673.     else {
  674. ctxt = xmlNanoHTTPNewCtxt(redirURL);
  675. xmlFree(redirURL);
  676. redirURL = NULL;
  677.     }
  678.     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
  679.         xmlNanoHTTPFreeCtxt(ctxt);
  680. if (redirURL != NULL) xmlFree(redirURL);
  681.         return(NULL);
  682.     }
  683.     if (ctxt->hostname == NULL) {
  684.         xmlNanoHTTPFreeCtxt(ctxt);
  685.         return(NULL);
  686.     }
  687.     if (proxy)
  688. ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
  689.     else
  690. ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
  691.     if (ret < 0) {
  692.         xmlNanoHTTPFreeCtxt(ctxt);
  693.         return(NULL);
  694.     }
  695.     ctxt->fd = ret;
  696.     if (proxy) {
  697. #ifdef HAVE_SNPRINTF
  698. if (ctxt->port != 80)
  699.     snprintf(buf, sizeof(buf),
  700.      "GET http://%s:%d%s HTTP/1.0rnHost: %srnrn",
  701.  ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
  702. else 
  703.     snprintf(buf, sizeof(buf),"GET http://%s%s HTTP/1.0rnHost: %srnrn",
  704.  ctxt->hostname, ctxt->path, ctxt->hostname);
  705. #else
  706. if (ctxt->port != 80)
  707.     sprintf(buf, 
  708.      "GET http://%s:%d%s HTTP/1.0rnHost: %srnrn",
  709.  ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
  710. else 
  711.     sprintf(buf, "GET http://%s%s HTTP/1.0rnHost: %srnrn",
  712.  ctxt->hostname, ctxt->path, ctxt->hostname);
  713. #endif
  714. #ifdef DEBUG_HTTP
  715. if (ctxt->port != 80)
  716.     printf("-> Proxy GET http://%s:%d%s HTTP/1.0n-> Host: %snn",
  717.            ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
  718. else
  719.     printf("-> Proxy GET http://%s%s HTTP/1.0n-> Host: %snn",
  720.            ctxt->hostname, ctxt->path, ctxt->hostname);
  721. #endif
  722.     } else {
  723. #ifdef HAVE_SNPRINTF
  724. snprintf(buf, sizeof(buf),"GET %s HTTP/1.0rnHost: %srnrn",
  725.  ctxt->path, ctxt->hostname);
  726. #else
  727. sprintf(buf, "GET %s HTTP/1.0rnHost: %srnrn",
  728.  ctxt->path, ctxt->hostname);
  729. #endif
  730. #ifdef DEBUG_HTTP
  731. printf("-> GET %s HTTP/1.0n-> Host: %snn",
  732.        ctxt->path, ctxt->hostname);
  733. #endif
  734.     }
  735.     ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
  736.     ctxt->state = XML_NANO_HTTP_WRITE;
  737.     xmlNanoHTTPSend(ctxt);
  738.     ctxt->state = XML_NANO_HTTP_READ;
  739.     head = 1;
  740.     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
  741.         if (head && (*p == 0)) {
  742.     head = 0;
  743.     ctxt->content = ctxt->inrptr;
  744.     xmlFree(p);
  745.     break;
  746. }
  747. xmlNanoHTTPScanAnswer(ctxt, p);
  748. #ifdef DEBUG_HTTP
  749. if (p != NULL) printf("<- %sn", p);
  750. #endif
  751.         if (p != NULL) xmlFree(p);
  752.     }
  753.     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
  754.         (ctxt->returnValue < 400)) {
  755. #ifdef DEBUG_HTTP
  756. printf("nRedirect to: %sn", ctxt->location);
  757. #endif
  758. while (xmlNanoHTTPRecv(ctxt)) ;
  759.         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
  760.     nbRedirects++;
  761.     redirURL = xmlMemStrdup(ctxt->location);
  762.     xmlNanoHTTPFreeCtxt(ctxt);
  763.     goto retry;
  764. }
  765. xmlNanoHTTPFreeCtxt(ctxt);
  766. #ifdef DEBUG_HTTP
  767. printf("Too many redirrects, aborting ...n");
  768. #endif
  769. return(NULL);
  770.     }
  771.     if ((contentType != NULL) && (ctxt->contentType != NULL))
  772.         *contentType = xmlMemStrdup(ctxt->contentType);
  773. #ifdef DEBUG_HTTP
  774.     if (ctxt->contentType != NULL)
  775. printf("nCode %d, content-type '%s'nn",
  776.        ctxt->returnValue, ctxt->contentType);
  777.     else
  778. printf("nCode %d, no content-typenn",
  779.        ctxt->returnValue);
  780. #endif
  781.     return((void *) ctxt);
  782. }
  783. /**
  784.  * xmlNanoHTTPRead:
  785.  * @ctx:  the HTTP context
  786.  * @dest:  a buffer
  787.  * @len:  the buffer length
  788.  *
  789.  * This function tries to read @len bytes from the existing HTTP connection
  790.  * and saves them in @dest. This is a blocking call.
  791.  *
  792.  * Returns the number of byte read. 0 is an indication of an end of connection.
  793.  *         -1 indicates a parameter error.
  794.  */
  795. int
  796. xmlNanoHTTPRead(void *ctx, void *dest, int len) {
  797.     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  798.     if (ctx == NULL) return(-1);
  799.     if (dest == NULL) return(-1);
  800.     if (len <= 0) return(0);
  801.     while (ctxt->inptr - ctxt->inrptr < len) {
  802.         if (xmlNanoHTTPRecv(ctxt) == 0) break;
  803.     }
  804.     if (ctxt->inptr - ctxt->inrptr < len)
  805.         len = ctxt->inptr - ctxt->inrptr;
  806.     memcpy(dest, ctxt->inrptr, len);
  807.     ctxt->inrptr += len;
  808.     return(len);
  809. }
  810. /**
  811.  * xmlNanoHTTPClose:
  812.  * @ctx:  the HTTP context
  813.  *
  814.  * This function closes an HTTP context, it ends up the connection and
  815.  * free all data related to it.
  816.  */
  817. void
  818. xmlNanoHTTPClose(void *ctx) {
  819.     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  820.     if (ctx == NULL) return;
  821.     xmlNanoHTTPFreeCtxt(ctxt);
  822. }
  823. #ifndef DEBUG_HTTP
  824. #define DEBUG_HTTP
  825. #endif
  826. /**
  827.  * xmlNanoHTTPMethod:
  828.  * @URL:  The URL to load
  829.  * @method:  the HTTP method to use
  830.  * @input:  the input string if any
  831.  * @contentType:  the Content-Type information IN and OUT
  832.  * @headers:  the extra headers
  833.  *
  834.  * This function try to open a connection to the indicated resource
  835.  * via HTTP using the given @method, adding the given extra headers
  836.  * and the input buffer for the request content.
  837.  *
  838.  * Returns NULL in case of failure, otherwise a request handler.
  839.  *     The contentType, if provided must be freed by the caller
  840.  */
  841. void *
  842. xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
  843.                   char **contentType, const char *headers) {
  844.     xmlNanoHTTPCtxtPtr ctxt;
  845.     char buf[20000];
  846.     int ret;
  847.     char *p;
  848.     int head;
  849.     int nbRedirects = 0;
  850.     char *redirURL = NULL;
  851.     
  852.     if (URL == NULL) return(NULL);
  853.     if (method == NULL) method = "GET";
  854.     if (contentType != NULL) *contentType = NULL;
  855. retry:
  856.     if (redirURL == NULL)
  857. ctxt = xmlNanoHTTPNewCtxt(URL);
  858.     else {
  859. ctxt = xmlNanoHTTPNewCtxt(redirURL);
  860. xmlFree(redirURL);
  861. redirURL = NULL;
  862.     }
  863.     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
  864.         xmlNanoHTTPFreeCtxt(ctxt);
  865. if (redirURL != NULL) xmlFree(redirURL);
  866.         return(NULL);
  867.     }
  868.     if (ctxt->hostname == NULL) {
  869.         xmlNanoHTTPFreeCtxt(ctxt);
  870.         return(NULL);
  871.     }
  872.     ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
  873.     if (ret < 0) {
  874.         xmlNanoHTTPFreeCtxt(ctxt);
  875.         return(NULL);
  876.     }
  877.     ctxt->fd = ret;
  878.     if (input == NULL) {
  879.         if (headers == NULL) {
  880.     if ((contentType == NULL) || (*contentType == NULL)) {
  881. #ifdef HAVE_SNPRINTF
  882. snprintf(buf, sizeof(buf),
  883.          "%s %s HTTP/1.0rnHost: %srnrn",
  884.  method, ctxt->path, ctxt->hostname);
  885. #else
  886. sprintf(buf,
  887.          "%s %s HTTP/1.0rnHost: %srnrn",
  888.  method, ctxt->path, ctxt->hostname);
  889. #endif
  890.     } else {
  891. #ifdef HAVE_SNPRINTF
  892. snprintf(buf, sizeof(buf),
  893.      "%s %s HTTP/1.0rnHost: %srnContent-Type: %srnrn",
  894.  method, ctxt->path, ctxt->hostname, *contentType);
  895. #else
  896. sprintf(buf,
  897.      "%s %s HTTP/1.0rnHost: %srnContent-Type: %srnrn",
  898.  method, ctxt->path, ctxt->hostname, *contentType);
  899. #endif
  900.     }
  901. } else {
  902.     if ((contentType == NULL) || (*contentType == NULL)) {
  903. #ifdef HAVE_SNPRINTF
  904. snprintf(buf, sizeof(buf),
  905.          "%s %s HTTP/1.0rnHost: %srn%srn",
  906.  method, ctxt->path, ctxt->hostname, headers);
  907. #else
  908. sprintf(buf,
  909.          "%s %s HTTP/1.0rnHost: %srn%srn",
  910.  method, ctxt->path, ctxt->hostname, headers);
  911. #endif
  912.     } else {
  913. #ifdef HAVE_SNPRINTF
  914. snprintf(buf, sizeof(buf),
  915.  "%s %s HTTP/1.0rnHost: %srnContent-Type: %srn%srn",
  916.  method, ctxt->path, ctxt->hostname, *contentType,
  917.  headers);
  918. #else
  919. sprintf(buf,
  920.  "%s %s HTTP/1.0rnHost: %srnContent-Type: %srn%srn",
  921.  method, ctxt->path, ctxt->hostname, *contentType,
  922.  headers);
  923. #endif
  924.     }
  925. }
  926.     } else {
  927.         int len = strlen(input);
  928.         if (headers == NULL) {
  929.     if ((contentType == NULL) || (*contentType == NULL)) {
  930. #ifdef HAVE_SNPRINTF
  931. snprintf(buf, sizeof(buf),
  932.  "%s %s HTTP/1.0rnHost: %srnContent-Length: %drnrn%s",
  933.  method, ctxt->path, ctxt->hostname, len, input);
  934. #else
  935. sprintf(buf,
  936.  "%s %s HTTP/1.0rnHost: %srnContent-Length: %drnrn%s",
  937.  method, ctxt->path, ctxt->hostname, len, input);
  938. #endif
  939.     } else {
  940. #ifdef HAVE_SNPRINTF
  941. snprintf(buf, sizeof(buf),
  942. "%s %s HTTP/1.0rnHost: %srnContent-Type: %srnContent-Length: %drnrn%s",
  943.  method, ctxt->path, ctxt->hostname, *contentType, len,
  944.  input);
  945. #else
  946. sprintf(buf,
  947. "%s %s HTTP/1.0rnHost: %srnContent-Type: %srnContent-Length: %drnrn%s",
  948.  method, ctxt->path, ctxt->hostname, *contentType, len,
  949.  input);
  950. #endif
  951.     }
  952. } else {
  953.     if ((contentType == NULL) || (*contentType == NULL)) {
  954. #ifdef HAVE_SNPRINTF
  955. snprintf(buf, sizeof(buf),
  956.      "%s %s HTTP/1.0rnHost: %srnContent-Length: %drn%srn%s",
  957.  method, ctxt->path, ctxt->hostname, len,
  958.  headers, input);
  959. #else
  960. sprintf(buf,
  961.      "%s %s HTTP/1.0rnHost: %srnContent-Length: %drn%srn%s",
  962.  method, ctxt->path, ctxt->hostname, len,
  963.  headers, input);
  964. #endif
  965.     } else {
  966. #ifdef HAVE_SNPRINTF
  967. snprintf(buf, sizeof(buf),
  968. "%s %s HTTP/1.0rnHost: %srnContent-Type: %srnContent-Length: %drn%srn%s",
  969.  method, ctxt->path, ctxt->hostname, *contentType,
  970.  len, headers, input);
  971. #else
  972. sprintf(buf,
  973. "%s %s HTTP/1.0rnHost: %srnContent-Type: %srnContent-Length: %drn%srn%s",
  974.  method, ctxt->path, ctxt->hostname, *contentType,
  975.  len, headers, input);
  976. #endif
  977.     }
  978. }
  979.     }
  980. #ifdef DEBUG_HTTP
  981.     printf("-> %s", buf);
  982. #endif
  983.     ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
  984.     ctxt->state = XML_NANO_HTTP_WRITE;
  985.     xmlNanoHTTPSend(ctxt);
  986.     ctxt->state = XML_NANO_HTTP_READ;
  987.     head = 1;
  988.     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
  989.         if (head && (*p == 0)) {
  990.     head = 0;
  991.     ctxt->content = ctxt->inrptr;
  992.     if (p != NULL) xmlFree(p);
  993.     break;
  994. }
  995. xmlNanoHTTPScanAnswer(ctxt, p);
  996. #ifdef DEBUG_HTTP
  997. if (p != NULL) printf("<- %sn", p);
  998. #endif
  999.         if (p != NULL) xmlFree(p);
  1000.     }
  1001.     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
  1002.         (ctxt->returnValue < 400)) {
  1003. #ifdef DEBUG_HTTP
  1004. printf("nRedirect to: %sn", ctxt->location);
  1005. #endif
  1006. while (xmlNanoHTTPRecv(ctxt)) ;
  1007.         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
  1008.     nbRedirects++;
  1009.     redirURL = xmlMemStrdup(ctxt->location);
  1010.     xmlNanoHTTPFreeCtxt(ctxt);
  1011.     goto retry;
  1012. }
  1013. xmlNanoHTTPFreeCtxt(ctxt);
  1014. #ifdef DEBUG_HTTP
  1015. printf("Too many redirrects, aborting ...n");
  1016. #endif
  1017. return(NULL);
  1018.     }
  1019.     if ((contentType != NULL) && (ctxt->contentType != NULL))
  1020.         *contentType = xmlMemStrdup(ctxt->contentType);
  1021.     else if (contentType != NULL)
  1022.         *contentType = NULL;
  1023. #ifdef DEBUG_HTTP
  1024.     if (ctxt->contentType != NULL)
  1025. printf("nCode %d, content-type '%s'nn",
  1026.        ctxt->returnValue, ctxt->contentType);
  1027.     else
  1028. printf("nCode %d, no content-typenn",
  1029.        ctxt->returnValue);
  1030. #endif
  1031.     return((void *) ctxt);
  1032. }
  1033. /**
  1034.  * xmlNanoHTTPFetch:
  1035.  * @URL:  The URL to load
  1036.  * @filename:  the filename where the content should be saved
  1037.  * @contentType:  if available the Content-Type information will be
  1038.  *                returned at that location
  1039.  *
  1040.  * This function try to fetch the indicated resource via HTTP GET
  1041.  * and save it's content in the file.
  1042.  *
  1043.  * Returns -1 in case of failure, 0 incase of success. The contentType,
  1044.  *     if provided must be freed by the caller
  1045.  */
  1046. int
  1047. xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
  1048.     void *ctxt;
  1049.     char buf[4096];
  1050.     int fd;
  1051.     int len;
  1052.     
  1053.     ctxt = xmlNanoHTTPOpen(URL, contentType);
  1054.     if (ctxt == NULL) return(-1);
  1055.     if (!strcmp(filename, "-")) 
  1056.         fd = 0;
  1057.     else {
  1058.         fd = open(filename, O_CREAT | O_WRONLY, 00644);
  1059. if (fd < 0) {
  1060.     xmlNanoHTTPClose(ctxt);
  1061.     if ((contentType != NULL) && (*contentType != NULL)) {
  1062.         xmlFree(*contentType);
  1063. *contentType = NULL;
  1064.     }
  1065.     return(-1);
  1066. }
  1067.     }
  1068.     while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
  1069. write(fd, buf, len);
  1070.     }
  1071.     xmlNanoHTTPClose(ctxt);
  1072.     close(fd);
  1073.     return(0);
  1074. }
  1075. /**
  1076.  * xmlNanoHTTPSave:
  1077.  * @ctxt:  the HTTP context
  1078.  * @filename:  the filename where the content should be saved
  1079.  *
  1080.  * This function saves the output of the HTTP transaction to a file
  1081.  * It closes and free the context at the end
  1082.  *
  1083.  * Returns -1 in case of failure, 0 incase of success.
  1084.  */
  1085. int
  1086. xmlNanoHTTPSave(void *ctxt, const char *filename) {
  1087.     char buf[4096];
  1088.     int fd;
  1089.     int len;
  1090.     
  1091.     if (ctxt == NULL) return(-1);
  1092.     if (!strcmp(filename, "-")) 
  1093.         fd = 0;
  1094.     else {
  1095.         fd = open(filename, O_CREAT | O_WRONLY);
  1096. if (fd < 0) {
  1097.     xmlNanoHTTPClose(ctxt);
  1098.     return(-1);
  1099. }
  1100.     }
  1101.     while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
  1102. write(fd, buf, len);
  1103.     }
  1104.     xmlNanoHTTPClose(ctxt);
  1105.     return(0);
  1106. }
  1107. /**
  1108.  * xmlNanoHTTPReturnCode:
  1109.  * @ctx:  the HTTP context
  1110.  *
  1111.  * Returns the HTTP return code for the request.
  1112.  */
  1113. int
  1114. xmlNanoHTTPReturnCode(void *ctx) {
  1115.     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  1116.     if (ctxt == NULL) return(-1);
  1117.     return(ctxt->returnValue);
  1118. }
  1119. #ifdef STANDALONE
  1120. int main(int argc, char **argv) {
  1121.     char *contentType = NULL;
  1122.     if (argv[1] != NULL) {
  1123. if (argv[2] != NULL) 
  1124.     xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
  1125.         else
  1126.     xmlNanoHTTPFetch(argv[1], "-", &contentType);
  1127. if (contentType != NULL) xmlFree(contentType);
  1128.     } else {
  1129.         printf("%s: minimal HTTP GET implementationn", argv[0]);
  1130.         printf("tusage %s [ URL [ filename ] ]n", argv[0]);
  1131.     }
  1132.     xmlNanoHTTPCleanup();
  1133.     xmlMemoryDump();
  1134.     return(0);
  1135. }
  1136. #endif /* STANDALONE */
  1137. #else /* !LIBXML_HTTP_ENABLED */
  1138. #ifdef STANDALONE
  1139. #include <stdio.h>
  1140. int main(int argc, char **argv) {
  1141.     printf("%s : HTTP support not compiled inn", argv[0]);
  1142.     return(0);
  1143. }
  1144. #endif /* STANDALONE */
  1145. #endif /* LIBXML_HTTP_ENABLED */