nanohttp.c 46 KB

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