nanohttp.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875
  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. #ifndef _WINSOCKAPI_
  427. if (ctxt->fd > FD_SETSIZE)
  428. return -1;
  429. #endif
  430. tv.tv_sec = timeout;
  431. tv.tv_usec = 0;
  432. FD_ZERO(&wfd);
  433. #ifdef _MSC_VER
  434. #pragma warning(push)
  435. #pragma warning(disable: 4018)
  436. #endif
  437. FD_SET(ctxt->fd, &wfd);
  438. #ifdef _MSC_VER
  439. #pragma warning(pop)
  440. #endif
  441. (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
  442. #else
  443. p.fd = ctxt->fd;
  444. p.events = POLLOUT;
  445. (void) poll(&p, 1, timeout * 1000);
  446. #endif /* !HAVE_POLL_H */
  447. }
  448. }
  449. }
  450. return total_sent;
  451. }
  452. /**
  453. * xmlNanoHTTPRecv:
  454. * @ctxt: an HTTP context
  455. *
  456. * Read information coming from the HTTP connection.
  457. * This is a blocking call (but it blocks in select(), not read()).
  458. *
  459. * Returns the number of byte read or -1 in case of error.
  460. */
  461. static int
  462. xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
  463. {
  464. #ifdef HAVE_POLL_H
  465. struct pollfd p;
  466. #else
  467. fd_set rfd;
  468. struct timeval tv;
  469. #endif
  470. while (ctxt->state & XML_NANO_HTTP_READ) {
  471. if (ctxt->in == NULL) {
  472. ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
  473. if (ctxt->in == NULL) {
  474. xmlHTTPErrMemory("allocating input");
  475. ctxt->last = -1;
  476. return (-1);
  477. }
  478. ctxt->inlen = 65000;
  479. ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
  480. }
  481. if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
  482. int delta = ctxt->inrptr - ctxt->in;
  483. int len = ctxt->inptr - ctxt->inrptr;
  484. memmove(ctxt->in, ctxt->inrptr, len);
  485. ctxt->inrptr -= delta;
  486. ctxt->content -= delta;
  487. ctxt->inptr -= delta;
  488. }
  489. if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
  490. int d_inptr = ctxt->inptr - ctxt->in;
  491. int d_content = ctxt->content - ctxt->in;
  492. int d_inrptr = ctxt->inrptr - ctxt->in;
  493. char *tmp_ptr = ctxt->in;
  494. ctxt->inlen *= 2;
  495. ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
  496. if (ctxt->in == NULL) {
  497. xmlHTTPErrMemory("allocating input buffer");
  498. xmlFree(tmp_ptr);
  499. ctxt->last = -1;
  500. return (-1);
  501. }
  502. ctxt->inptr = ctxt->in + d_inptr;
  503. ctxt->content = ctxt->in + d_content;
  504. ctxt->inrptr = ctxt->in + d_inrptr;
  505. }
  506. ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
  507. if (ctxt->last > 0) {
  508. ctxt->inptr += ctxt->last;
  509. return (ctxt->last);
  510. }
  511. if (ctxt->last == 0) {
  512. return (0);
  513. }
  514. if (ctxt->last == -1) {
  515. switch (socket_errno()) {
  516. case EINPROGRESS:
  517. case EWOULDBLOCK:
  518. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  519. case EAGAIN:
  520. #endif
  521. break;
  522. case ECONNRESET:
  523. case ESHUTDOWN:
  524. return (0);
  525. default:
  526. __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
  527. return (-1);
  528. }
  529. }
  530. #ifdef HAVE_POLL_H
  531. p.fd = ctxt->fd;
  532. p.events = POLLIN;
  533. if ((poll(&p, 1, timeout * 1000) < 1)
  534. #if defined(EINTR)
  535. && (errno != EINTR)
  536. #endif
  537. )
  538. return (0);
  539. #else /* !HAVE_POLL_H */
  540. #ifndef _WINSOCKAPI_
  541. if (ctxt->fd > FD_SETSIZE)
  542. return 0;
  543. #endif
  544. tv.tv_sec = timeout;
  545. tv.tv_usec = 0;
  546. FD_ZERO(&rfd);
  547. #ifdef _MSC_VER
  548. #pragma warning(push)
  549. #pragma warning(disable: 4018)
  550. #endif
  551. FD_SET(ctxt->fd, &rfd);
  552. #ifdef _MSC_VER
  553. #pragma warning(pop)
  554. #endif
  555. if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
  556. #if defined(EINTR)
  557. && (errno != EINTR)
  558. #endif
  559. )
  560. return (0);
  561. #endif /* !HAVE_POLL_H */
  562. }
  563. return (0);
  564. }
  565. /**
  566. * xmlNanoHTTPReadLine:
  567. * @ctxt: an HTTP context
  568. *
  569. * Read one line in the HTTP server output, usually for extracting
  570. * the HTTP protocol informations from the answer header.
  571. *
  572. * Returns a newly allocated string with a copy of the line, or NULL
  573. * which indicate the end of the input.
  574. */
  575. static char *
  576. xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
  577. char buf[4096];
  578. char *bp = buf;
  579. int rc;
  580. while (bp - buf < 4095) {
  581. if (ctxt->inrptr == ctxt->inptr) {
  582. if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
  583. if (bp == buf)
  584. return(NULL);
  585. else
  586. *bp = 0;
  587. return(xmlMemStrdup(buf));
  588. }
  589. else if ( rc == -1 ) {
  590. return ( NULL );
  591. }
  592. }
  593. *bp = *ctxt->inrptr++;
  594. if (*bp == '\n') {
  595. *bp = 0;
  596. return(xmlMemStrdup(buf));
  597. }
  598. if (*bp != '\r')
  599. bp++;
  600. }
  601. buf[4095] = 0;
  602. return(xmlMemStrdup(buf));
  603. }
  604. /**
  605. * xmlNanoHTTPScanAnswer:
  606. * @ctxt: an HTTP context
  607. * @line: an HTTP header line
  608. *
  609. * Try to extract useful informations from the server answer.
  610. * We currently parse and process:
  611. * - The HTTP revision/ return code
  612. * - The Content-Type, Mime-Type and charset used
  613. * - The Location for redirect processing.
  614. *
  615. * Returns -1 in case of failure, the file descriptor number otherwise
  616. */
  617. static void
  618. xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
  619. const char *cur = line;
  620. if (line == NULL) return;
  621. if (!strncmp(line, "HTTP/", 5)) {
  622. int version = 0;
  623. int ret = 0;
  624. cur += 5;
  625. while ((*cur >= '0') && (*cur <= '9')) {
  626. version *= 10;
  627. version += *cur - '0';
  628. cur++;
  629. }
  630. if (*cur == '.') {
  631. cur++;
  632. if ((*cur >= '0') && (*cur <= '9')) {
  633. version *= 10;
  634. version += *cur - '0';
  635. cur++;
  636. }
  637. while ((*cur >= '0') && (*cur <= '9'))
  638. cur++;
  639. } else
  640. version *= 10;
  641. if ((*cur != ' ') && (*cur != '\t')) return;
  642. while ((*cur == ' ') || (*cur == '\t')) cur++;
  643. if ((*cur < '0') || (*cur > '9')) return;
  644. while ((*cur >= '0') && (*cur <= '9')) {
  645. ret *= 10;
  646. ret += *cur - '0';
  647. cur++;
  648. }
  649. if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
  650. ctxt->returnValue = ret;
  651. ctxt->version = version;
  652. } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
  653. const xmlChar *charset, *last, *mime;
  654. cur += 13;
  655. while ((*cur == ' ') || (*cur == '\t')) cur++;
  656. if (ctxt->contentType != NULL)
  657. xmlFree(ctxt->contentType);
  658. ctxt->contentType = xmlMemStrdup(cur);
  659. mime = (const xmlChar *) cur;
  660. last = mime;
  661. while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
  662. (*last != ';') && (*last != ','))
  663. last++;
  664. if (ctxt->mimeType != NULL)
  665. xmlFree(ctxt->mimeType);
  666. ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
  667. charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
  668. if (charset != NULL) {
  669. charset += 8;
  670. last = charset;
  671. while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
  672. (*last != ';') && (*last != ','))
  673. last++;
  674. if (ctxt->encoding != NULL)
  675. xmlFree(ctxt->encoding);
  676. ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
  677. }
  678. } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
  679. const xmlChar *charset, *last, *mime;
  680. cur += 12;
  681. if (ctxt->contentType != NULL) return;
  682. while ((*cur == ' ') || (*cur == '\t')) cur++;
  683. ctxt->contentType = xmlMemStrdup(cur);
  684. mime = (const xmlChar *) cur;
  685. last = mime;
  686. while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
  687. (*last != ';') && (*last != ','))
  688. last++;
  689. if (ctxt->mimeType != NULL)
  690. xmlFree(ctxt->mimeType);
  691. ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
  692. charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
  693. if (charset != NULL) {
  694. charset += 8;
  695. last = charset;
  696. while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
  697. (*last != ';') && (*last != ','))
  698. last++;
  699. if (ctxt->encoding != NULL)
  700. xmlFree(ctxt->encoding);
  701. ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
  702. }
  703. } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
  704. cur += 9;
  705. while ((*cur == ' ') || (*cur == '\t')) cur++;
  706. if (ctxt->location != NULL)
  707. xmlFree(ctxt->location);
  708. if (*cur == '/') {
  709. xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
  710. xmlChar *tmp_loc =
  711. xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
  712. ctxt->location =
  713. (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
  714. } else {
  715. ctxt->location = xmlMemStrdup(cur);
  716. }
  717. } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
  718. cur += 17;
  719. while ((*cur == ' ') || (*cur == '\t')) cur++;
  720. if (ctxt->authHeader != NULL)
  721. xmlFree(ctxt->authHeader);
  722. ctxt->authHeader = xmlMemStrdup(cur);
  723. } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
  724. cur += 19;
  725. while ((*cur == ' ') || (*cur == '\t')) cur++;
  726. if (ctxt->authHeader != NULL)
  727. xmlFree(ctxt->authHeader);
  728. ctxt->authHeader = xmlMemStrdup(cur);
  729. #ifdef HAVE_ZLIB_H
  730. } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
  731. cur += 17;
  732. while ((*cur == ' ') || (*cur == '\t')) cur++;
  733. if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
  734. ctxt->usesGzip = 1;
  735. ctxt->strm = xmlMalloc(sizeof(z_stream));
  736. if (ctxt->strm != NULL) {
  737. ctxt->strm->zalloc = Z_NULL;
  738. ctxt->strm->zfree = Z_NULL;
  739. ctxt->strm->opaque = Z_NULL;
  740. ctxt->strm->avail_in = 0;
  741. ctxt->strm->next_in = Z_NULL;
  742. inflateInit2( ctxt->strm, 31 );
  743. }
  744. }
  745. #endif
  746. } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
  747. cur += 15;
  748. ctxt->ContentLength = strtol( cur, NULL, 10 );
  749. }
  750. }
  751. /**
  752. * xmlNanoHTTPConnectAttempt:
  753. * @addr: a socket address structure
  754. *
  755. * Attempt a connection to the given IP:port endpoint. It forces
  756. * non-blocking semantic on the socket, and allow 60 seconds for
  757. * the host to answer.
  758. *
  759. * Returns -1 in case of failure, the file descriptor number otherwise
  760. */
  761. static int
  762. xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
  763. {
  764. #ifndef HAVE_POLL_H
  765. fd_set wfd;
  766. #ifdef _WINSOCKAPI_
  767. fd_set xfd;
  768. #endif
  769. struct timeval tv;
  770. #else /* !HAVE_POLL_H */
  771. struct pollfd p;
  772. #endif /* !HAVE_POLL_H */
  773. int status;
  774. int addrlen;
  775. SOCKET s;
  776. #ifdef SUPPORT_IP6
  777. if (addr->sa_family == AF_INET6) {
  778. s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
  779. addrlen = sizeof(struct sockaddr_in6);
  780. } else
  781. #endif
  782. {
  783. s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  784. addrlen = sizeof(struct sockaddr_in);
  785. }
  786. if (s == -1) {
  787. #ifdef DEBUG_HTTP
  788. perror("socket");
  789. #endif
  790. __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
  791. return (-1);
  792. }
  793. #ifdef _WINSOCKAPI_
  794. {
  795. u_long one = 1;
  796. status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
  797. }
  798. #else /* _WINSOCKAPI_ */
  799. #if defined(VMS)
  800. {
  801. int enable = 1;
  802. status = ioctl(s, FIONBIO, &enable);
  803. }
  804. #else /* VMS */
  805. #if defined(__BEOS__) && !defined(__HAIKU__)
  806. {
  807. bool noblock = true;
  808. status =
  809. setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
  810. sizeof(noblock));
  811. }
  812. #else /* __BEOS__ */
  813. if ((status = fcntl(s, F_GETFL, 0)) != -1) {
  814. #ifdef O_NONBLOCK
  815. status |= O_NONBLOCK;
  816. #else /* O_NONBLOCK */
  817. #ifdef F_NDELAY
  818. status |= F_NDELAY;
  819. #endif /* F_NDELAY */
  820. #endif /* !O_NONBLOCK */
  821. status = fcntl(s, F_SETFL, status);
  822. }
  823. if (status < 0) {
  824. #ifdef DEBUG_HTTP
  825. perror("nonblocking");
  826. #endif
  827. __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
  828. closesocket(s);
  829. return (-1);
  830. }
  831. #endif /* !__BEOS__ */
  832. #endif /* !VMS */
  833. #endif /* !_WINSOCKAPI_ */
  834. if (connect(s, addr, addrlen) == -1) {
  835. switch (socket_errno()) {
  836. case EINPROGRESS:
  837. case EWOULDBLOCK:
  838. break;
  839. default:
  840. __xmlIOErr(XML_FROM_HTTP, 0,
  841. "error connecting to HTTP server");
  842. closesocket(s);
  843. return (-1);
  844. }
  845. }
  846. #ifndef HAVE_POLL_H
  847. tv.tv_sec = timeout;
  848. tv.tv_usec = 0;
  849. #ifdef _MSC_VER
  850. #pragma warning(push)
  851. #pragma warning(disable: 4018)
  852. #endif
  853. #ifndef _WINSOCKAPI_
  854. if (s > FD_SETSIZE)
  855. return -1;
  856. #endif
  857. FD_ZERO(&wfd);
  858. FD_SET(s, &wfd);
  859. #ifdef _WINSOCKAPI_
  860. FD_ZERO(&xfd);
  861. FD_SET(s, &xfd);
  862. switch (select(s + 1, NULL, &wfd, &xfd, &tv))
  863. #else
  864. switch (select(s + 1, NULL, &wfd, NULL, &tv))
  865. #endif
  866. #ifdef _MSC_VER
  867. #pragma warning(pop)
  868. #endif
  869. #else /* !HAVE_POLL_H */
  870. p.fd = s;
  871. p.events = POLLOUT;
  872. switch (poll(&p, 1, timeout * 1000))
  873. #endif /* !HAVE_POLL_H */
  874. {
  875. case 0:
  876. /* Time out */
  877. __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
  878. closesocket(s);
  879. return (-1);
  880. case -1:
  881. /* Ermm.. ?? */
  882. __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
  883. closesocket(s);
  884. return (-1);
  885. }
  886. #ifndef HAVE_POLL_H
  887. if (FD_ISSET(s, &wfd)
  888. #ifdef _WINSOCKAPI_
  889. || FD_ISSET(s, &xfd)
  890. #endif
  891. )
  892. #else /* !HAVE_POLL_H */
  893. if (p.revents == POLLOUT)
  894. #endif /* !HAVE_POLL_H */
  895. {
  896. XML_SOCKLEN_T len;
  897. len = sizeof(status);
  898. #ifdef SO_ERROR
  899. if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
  900. 0) {
  901. /* Solaris error code */
  902. __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
  903. return (-1);
  904. }
  905. #endif
  906. if (status) {
  907. __xmlIOErr(XML_FROM_HTTP, 0,
  908. "Error connecting to remote host");
  909. closesocket(s);
  910. errno = status;
  911. return (-1);
  912. }
  913. } else {
  914. /* pbm */
  915. __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
  916. closesocket(s);
  917. return (-1);
  918. }
  919. return (s);
  920. }
  921. /**
  922. * xmlNanoHTTPConnectHost:
  923. * @host: the host name
  924. * @port: the port number
  925. *
  926. * Attempt a connection to the given host:port endpoint. It tries
  927. * the multiple IP provided by the DNS if available.
  928. *
  929. * Returns -1 in case of failure, the file descriptor number otherwise
  930. */
  931. static int
  932. xmlNanoHTTPConnectHost(const char *host, int port)
  933. {
  934. struct hostent *h;
  935. struct sockaddr *addr = NULL;
  936. struct in_addr ia;
  937. struct sockaddr_in sockin;
  938. #ifdef SUPPORT_IP6
  939. struct in6_addr ia6;
  940. struct sockaddr_in6 sockin6;
  941. #endif
  942. int i;
  943. int s;
  944. memset (&sockin, 0, sizeof(sockin));
  945. #ifdef SUPPORT_IP6
  946. memset (&sockin6, 0, sizeof(sockin6));
  947. #endif
  948. #if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
  949. if (have_ipv6 ())
  950. {
  951. if (!(_res.options & RES_INIT))
  952. res_init();
  953. _res.options |= RES_USE_INET6;
  954. }
  955. #endif
  956. #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
  957. if (have_ipv6 ())
  958. #endif
  959. #if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
  960. {
  961. int status;
  962. struct addrinfo hints, *res, *result;
  963. result = NULL;
  964. memset (&hints, 0,sizeof(hints));
  965. hints.ai_socktype = SOCK_STREAM;
  966. status = getaddrinfo (host, NULL, &hints, &result);
  967. if (status) {
  968. __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
  969. return (-1);
  970. }
  971. for (res = result; res; res = res->ai_next) {
  972. if (res->ai_family == AF_INET) {
  973. if (res->ai_addrlen > sizeof(sockin)) {
  974. __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
  975. freeaddrinfo (result);
  976. return (-1);
  977. }
  978. memcpy (&sockin, res->ai_addr, res->ai_addrlen);
  979. sockin.sin_port = htons (port);
  980. addr = (struct sockaddr *)&sockin;
  981. #ifdef SUPPORT_IP6
  982. } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
  983. if (res->ai_addrlen > sizeof(sockin6)) {
  984. __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
  985. freeaddrinfo (result);
  986. return (-1);
  987. }
  988. memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
  989. sockin6.sin6_port = htons (port);
  990. addr = (struct sockaddr *)&sockin6;
  991. #endif
  992. } else
  993. continue; /* for */
  994. s = xmlNanoHTTPConnectAttempt (addr);
  995. if (s != -1) {
  996. freeaddrinfo (result);
  997. return (s);
  998. }
  999. }
  1000. if (result)
  1001. freeaddrinfo (result);
  1002. }
  1003. #endif
  1004. #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
  1005. else
  1006. #endif
  1007. #if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
  1008. {
  1009. h = gethostbyname (host);
  1010. if (h == NULL) {
  1011. /*
  1012. * Okay, I got fed up by the non-portability of this error message
  1013. * extraction code. it work on Linux, if it work on your platform
  1014. * and one want to enable it, send me the defined(foobar) needed
  1015. */
  1016. #if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
  1017. const char *h_err_txt = "";
  1018. switch (h_errno) {
  1019. case HOST_NOT_FOUND:
  1020. h_err_txt = "Authoritive host not found";
  1021. break;
  1022. case TRY_AGAIN:
  1023. h_err_txt =
  1024. "Non-authoritive host not found or server failure.";
  1025. break;
  1026. case NO_RECOVERY:
  1027. h_err_txt =
  1028. "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
  1029. break;
  1030. case NO_ADDRESS:
  1031. h_err_txt =
  1032. "Valid name, no data record of requested type.";
  1033. break;
  1034. default:
  1035. h_err_txt = "No error text defined.";
  1036. break;
  1037. }
  1038. __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
  1039. #else
  1040. __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
  1041. #endif
  1042. return (-1);
  1043. }
  1044. for (i = 0; h->h_addr_list[i]; i++) {
  1045. if (h->h_addrtype == AF_INET) {
  1046. /* A records (IPv4) */
  1047. if ((unsigned int) h->h_length > sizeof(ia)) {
  1048. __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
  1049. return (-1);
  1050. }
  1051. memcpy (&ia, h->h_addr_list[i], h->h_length);
  1052. sockin.sin_family = h->h_addrtype;
  1053. sockin.sin_addr = ia;
  1054. sockin.sin_port = (u_short)htons ((unsigned short)port);
  1055. addr = (struct sockaddr *) &sockin;
  1056. #ifdef SUPPORT_IP6
  1057. } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
  1058. /* AAAA records (IPv6) */
  1059. if ((unsigned int) h->h_length > sizeof(ia6)) {
  1060. __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
  1061. return (-1);
  1062. }
  1063. memcpy (&ia6, h->h_addr_list[i], h->h_length);
  1064. sockin6.sin6_family = h->h_addrtype;
  1065. sockin6.sin6_addr = ia6;
  1066. sockin6.sin6_port = htons (port);
  1067. addr = (struct sockaddr *) &sockin6;
  1068. #endif
  1069. } else
  1070. break; /* for */
  1071. s = xmlNanoHTTPConnectAttempt (addr);
  1072. if (s != -1)
  1073. return (s);
  1074. }
  1075. }
  1076. #endif
  1077. #ifdef DEBUG_HTTP
  1078. xmlGenericError(xmlGenericErrorContext,
  1079. "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",
  1080. host);
  1081. #endif
  1082. return (-1);
  1083. }
  1084. /**
  1085. * xmlNanoHTTPOpen:
  1086. * @URL: The URL to load
  1087. * @contentType: if available the Content-Type information will be
  1088. * returned at that location
  1089. *
  1090. * This function try to open a connection to the indicated resource
  1091. * via HTTP GET.
  1092. *
  1093. * Returns NULL in case of failure, otherwise a request handler.
  1094. * The contentType, if provided must be freed by the caller
  1095. */
  1096. void*
  1097. xmlNanoHTTPOpen(const char *URL, char **contentType) {
  1098. if (contentType != NULL) *contentType = NULL;
  1099. return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
  1100. }
  1101. /**
  1102. * xmlNanoHTTPOpenRedir:
  1103. * @URL: The URL to load
  1104. * @contentType: if available the Content-Type information will be
  1105. * returned at that location
  1106. * @redir: if available the redirected URL will be returned
  1107. *
  1108. * This function try to open a connection to the indicated resource
  1109. * via HTTP GET.
  1110. *
  1111. * Returns NULL in case of failure, otherwise a request handler.
  1112. * The contentType, if provided must be freed by the caller
  1113. */
  1114. void*
  1115. xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
  1116. if (contentType != NULL) *contentType = NULL;
  1117. if (redir != NULL) *redir = NULL;
  1118. return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
  1119. }
  1120. /**
  1121. * xmlNanoHTTPRead:
  1122. * @ctx: the HTTP context
  1123. * @dest: a buffer
  1124. * @len: the buffer length
  1125. *
  1126. * This function tries to read @len bytes from the existing HTTP connection
  1127. * and saves them in @dest. This is a blocking call.
  1128. *
  1129. * Returns the number of byte read. 0 is an indication of an end of connection.
  1130. * -1 indicates a parameter error.
  1131. */
  1132. int
  1133. xmlNanoHTTPRead(void *ctx, void *dest, int len) {
  1134. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  1135. #ifdef HAVE_ZLIB_H
  1136. int bytes_read = 0;
  1137. int orig_avail_in;
  1138. int z_ret;
  1139. #endif
  1140. if (ctx == NULL) return(-1);
  1141. if (dest == NULL) return(-1);
  1142. if (len <= 0) return(0);
  1143. #ifdef HAVE_ZLIB_H
  1144. if (ctxt->usesGzip == 1) {
  1145. if (ctxt->strm == NULL) return(0);
  1146. ctxt->strm->next_out = dest;
  1147. ctxt->strm->avail_out = len;
  1148. ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
  1149. while (ctxt->strm->avail_out > 0 &&
  1150. (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
  1151. orig_avail_in = ctxt->strm->avail_in =
  1152. ctxt->inptr - ctxt->inrptr - bytes_read;
  1153. ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
  1154. z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
  1155. bytes_read += orig_avail_in - ctxt->strm->avail_in;
  1156. if (z_ret != Z_OK) break;
  1157. }
  1158. ctxt->inrptr += bytes_read;
  1159. return(len - ctxt->strm->avail_out);
  1160. }
  1161. #endif
  1162. while (ctxt->inptr - ctxt->inrptr < len) {
  1163. if (xmlNanoHTTPRecv(ctxt) <= 0) break;
  1164. }
  1165. if (ctxt->inptr - ctxt->inrptr < len)
  1166. len = ctxt->inptr - ctxt->inrptr;
  1167. memcpy(dest, ctxt->inrptr, len);
  1168. ctxt->inrptr += len;
  1169. return(len);
  1170. }
  1171. /**
  1172. * xmlNanoHTTPClose:
  1173. * @ctx: the HTTP context
  1174. *
  1175. * This function closes an HTTP context, it ends up the connection and
  1176. * free all data related to it.
  1177. */
  1178. void
  1179. xmlNanoHTTPClose(void *ctx) {
  1180. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  1181. if (ctx == NULL) return;
  1182. xmlNanoHTTPFreeCtxt(ctxt);
  1183. }
  1184. /**
  1185. * xmlNanoHTTPMethodRedir:
  1186. * @URL: The URL to load
  1187. * @method: the HTTP method to use
  1188. * @input: the input string if any
  1189. * @contentType: the Content-Type information IN and OUT
  1190. * @redir: the redirected URL OUT
  1191. * @headers: the extra headers
  1192. * @ilen: input length
  1193. *
  1194. * This function try to open a connection to the indicated resource
  1195. * via HTTP using the given @method, adding the given extra headers
  1196. * and the input buffer for the request content.
  1197. *
  1198. * Returns NULL in case of failure, otherwise a request handler.
  1199. * The contentType, or redir, if provided must be freed by the caller
  1200. */
  1201. void*
  1202. xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
  1203. char **contentType, char **redir,
  1204. const char *headers, int ilen ) {
  1205. xmlNanoHTTPCtxtPtr ctxt;
  1206. char *bp, *p;
  1207. int blen, ret;
  1208. int nbRedirects = 0;
  1209. char *redirURL = NULL;
  1210. #ifdef DEBUG_HTTP
  1211. int xmt_bytes;
  1212. #endif
  1213. if (URL == NULL) return(NULL);
  1214. if (method == NULL) method = "GET";
  1215. xmlNanoHTTPInit();
  1216. retry:
  1217. if (redirURL == NULL)
  1218. ctxt = xmlNanoHTTPNewCtxt(URL);
  1219. else {
  1220. ctxt = xmlNanoHTTPNewCtxt(redirURL);
  1221. ctxt->location = xmlMemStrdup(redirURL);
  1222. }
  1223. if ( ctxt == NULL ) {
  1224. return ( NULL );
  1225. }
  1226. if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
  1227. __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
  1228. xmlNanoHTTPFreeCtxt(ctxt);
  1229. if (redirURL != NULL) xmlFree(redirURL);
  1230. return(NULL);
  1231. }
  1232. if (ctxt->hostname == NULL) {
  1233. __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
  1234. "Failed to identify host in URI");
  1235. xmlNanoHTTPFreeCtxt(ctxt);
  1236. if (redirURL != NULL) xmlFree(redirURL);
  1237. return(NULL);
  1238. }
  1239. if (proxy) {
  1240. blen = strlen(ctxt->hostname) * 2 + 16;
  1241. ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
  1242. }
  1243. else {
  1244. blen = strlen(ctxt->hostname);
  1245. ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
  1246. }
  1247. if (ret < 0) {
  1248. xmlNanoHTTPFreeCtxt(ctxt);
  1249. if (redirURL != NULL) xmlFree(redirURL);
  1250. return(NULL);
  1251. }
  1252. ctxt->fd = ret;
  1253. if (input == NULL)
  1254. ilen = 0;
  1255. else
  1256. blen += 36;
  1257. if (headers != NULL)
  1258. blen += strlen(headers) + 2;
  1259. if (contentType && *contentType)
  1260. /* reserve for string plus 'Content-Type: \r\n" */
  1261. blen += strlen(*contentType) + 16;
  1262. if (ctxt->query != NULL)
  1263. /* 1 for '?' */
  1264. blen += strlen(ctxt->query) + 1;
  1265. blen += strlen(method) + strlen(ctxt->path) + 24;
  1266. #ifdef HAVE_ZLIB_H
  1267. /* reserve for possible 'Accept-Encoding: gzip' string */
  1268. blen += 23;
  1269. #endif
  1270. if (ctxt->port != 80) {
  1271. /* reserve space for ':xxxxx', incl. potential proxy */
  1272. if (proxy)
  1273. blen += 12;
  1274. else
  1275. blen += 6;
  1276. }
  1277. bp = (char*)xmlMallocAtomic(blen);
  1278. if ( bp == NULL ) {
  1279. xmlNanoHTTPFreeCtxt( ctxt );
  1280. xmlHTTPErrMemory("allocating header buffer");
  1281. return ( NULL );
  1282. }
  1283. p = bp;
  1284. if (proxy) {
  1285. if (ctxt->port != 80) {
  1286. p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s",
  1287. method, ctxt->hostname,
  1288. ctxt->port, ctxt->path );
  1289. }
  1290. else
  1291. p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
  1292. ctxt->hostname, ctxt->path);
  1293. }
  1294. else
  1295. p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
  1296. if (ctxt->query != NULL)
  1297. p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
  1298. if (ctxt->port == 80) {
  1299. p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
  1300. ctxt->hostname);
  1301. } else {
  1302. p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
  1303. ctxt->hostname, ctxt->port);
  1304. }
  1305. #ifdef HAVE_ZLIB_H
  1306. p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
  1307. #endif
  1308. if (contentType != NULL && *contentType)
  1309. p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
  1310. if (headers != NULL)
  1311. p += snprintf( p, blen - (p - bp), "%s", headers );
  1312. if (input != NULL)
  1313. snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
  1314. else
  1315. snprintf(p, blen - (p - bp), "\r\n");
  1316. #ifdef DEBUG_HTTP
  1317. xmlGenericError(xmlGenericErrorContext,
  1318. "-> %s%s", proxy? "(Proxy) " : "", bp);
  1319. if ((blen -= strlen(bp)+1) < 0)
  1320. xmlGenericError(xmlGenericErrorContext,
  1321. "ERROR: overflowed buffer by %d bytes\n", -blen);
  1322. #endif
  1323. ctxt->outptr = ctxt->out = bp;
  1324. ctxt->state = XML_NANO_HTTP_WRITE;
  1325. blen = strlen( ctxt->out );
  1326. #ifdef DEBUG_HTTP
  1327. xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
  1328. if ( xmt_bytes != blen )
  1329. xmlGenericError( xmlGenericErrorContext,
  1330. "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
  1331. xmt_bytes, blen,
  1332. "bytes of HTTP headers sent to host",
  1333. ctxt->hostname );
  1334. #else
  1335. xmlNanoHTTPSend(ctxt, ctxt->out, blen );
  1336. #endif
  1337. if ( input != NULL ) {
  1338. #ifdef DEBUG_HTTP
  1339. xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
  1340. if ( xmt_bytes != ilen )
  1341. xmlGenericError( xmlGenericErrorContext,
  1342. "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
  1343. xmt_bytes, ilen,
  1344. "bytes of HTTP content sent to host",
  1345. ctxt->hostname );
  1346. #else
  1347. xmlNanoHTTPSend( ctxt, input, ilen );
  1348. #endif
  1349. }
  1350. ctxt->state = XML_NANO_HTTP_READ;
  1351. while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
  1352. if (*p == 0) {
  1353. ctxt->content = ctxt->inrptr;
  1354. xmlFree(p);
  1355. break;
  1356. }
  1357. xmlNanoHTTPScanAnswer(ctxt, p);
  1358. #ifdef DEBUG_HTTP
  1359. xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
  1360. #endif
  1361. xmlFree(p);
  1362. }
  1363. if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
  1364. (ctxt->returnValue < 400)) {
  1365. #ifdef DEBUG_HTTP
  1366. xmlGenericError(xmlGenericErrorContext,
  1367. "\nRedirect to: %s\n", ctxt->location);
  1368. #endif
  1369. while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
  1370. if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
  1371. nbRedirects++;
  1372. if (redirURL != NULL)
  1373. xmlFree(redirURL);
  1374. redirURL = xmlMemStrdup(ctxt->location);
  1375. xmlNanoHTTPFreeCtxt(ctxt);
  1376. goto retry;
  1377. }
  1378. xmlNanoHTTPFreeCtxt(ctxt);
  1379. if (redirURL != NULL) xmlFree(redirURL);
  1380. #ifdef DEBUG_HTTP
  1381. xmlGenericError(xmlGenericErrorContext,
  1382. "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
  1383. #endif
  1384. return(NULL);
  1385. }
  1386. if (contentType != NULL) {
  1387. if (ctxt->contentType != NULL)
  1388. *contentType = xmlMemStrdup(ctxt->contentType);
  1389. else
  1390. *contentType = NULL;
  1391. }
  1392. if ((redir != NULL) && (redirURL != NULL)) {
  1393. *redir = redirURL;
  1394. } else {
  1395. if (redirURL != NULL)
  1396. xmlFree(redirURL);
  1397. if (redir != NULL)
  1398. *redir = NULL;
  1399. }
  1400. #ifdef DEBUG_HTTP
  1401. if (ctxt->contentType != NULL)
  1402. xmlGenericError(xmlGenericErrorContext,
  1403. "\nCode %d, content-type '%s'\n\n",
  1404. ctxt->returnValue, ctxt->contentType);
  1405. else
  1406. xmlGenericError(xmlGenericErrorContext,
  1407. "\nCode %d, no content-type\n\n",
  1408. ctxt->returnValue);
  1409. #endif
  1410. return((void *) ctxt);
  1411. }
  1412. /**
  1413. * xmlNanoHTTPMethod:
  1414. * @URL: The URL to load
  1415. * @method: the HTTP method to use
  1416. * @input: the input string if any
  1417. * @contentType: the Content-Type information IN and OUT
  1418. * @headers: the extra headers
  1419. * @ilen: input length
  1420. *
  1421. * This function try to open a connection to the indicated resource
  1422. * via HTTP using the given @method, adding the given extra headers
  1423. * and the input buffer for the request content.
  1424. *
  1425. * Returns NULL in case of failure, otherwise a request handler.
  1426. * The contentType, if provided must be freed by the caller
  1427. */
  1428. void*
  1429. xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
  1430. char **contentType, const char *headers, int ilen) {
  1431. return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
  1432. NULL, headers, ilen));
  1433. }
  1434. /**
  1435. * xmlNanoHTTPFetch:
  1436. * @URL: The URL to load
  1437. * @filename: the filename where the content should be saved
  1438. * @contentType: if available the Content-Type information will be
  1439. * returned at that location
  1440. *
  1441. * This function try to fetch the indicated resource via HTTP GET
  1442. * and save it's content in the file.
  1443. *
  1444. * Returns -1 in case of failure, 0 incase of success. The contentType,
  1445. * if provided must be freed by the caller
  1446. */
  1447. int
  1448. xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
  1449. void *ctxt = NULL;
  1450. char *buf = NULL;
  1451. int fd;
  1452. int len;
  1453. if (filename == NULL) return(-1);
  1454. ctxt = xmlNanoHTTPOpen(URL, contentType);
  1455. if (ctxt == NULL) return(-1);
  1456. if (!strcmp(filename, "-"))
  1457. fd = 0;
  1458. else {
  1459. fd = open(filename, O_CREAT | O_WRONLY, 00644);
  1460. if (fd < 0) {
  1461. xmlNanoHTTPClose(ctxt);
  1462. if ((contentType != NULL) && (*contentType != NULL)) {
  1463. xmlFree(*contentType);
  1464. *contentType = NULL;
  1465. }
  1466. return(-1);
  1467. }
  1468. }
  1469. xmlNanoHTTPFetchContent( ctxt, &buf, &len );
  1470. if ( len > 0 ) {
  1471. write(fd, buf, len);
  1472. }
  1473. xmlNanoHTTPClose(ctxt);
  1474. close(fd);
  1475. return(0);
  1476. }
  1477. #ifdef LIBXML_OUTPUT_ENABLED
  1478. /**
  1479. * xmlNanoHTTPSave:
  1480. * @ctxt: the HTTP context
  1481. * @filename: the filename where the content should be saved
  1482. *
  1483. * This function saves the output of the HTTP transaction to a file
  1484. * It closes and free the context at the end
  1485. *
  1486. * Returns -1 in case of failure, 0 incase of success.
  1487. */
  1488. int
  1489. xmlNanoHTTPSave(void *ctxt, const char *filename) {
  1490. char *buf = NULL;
  1491. int fd;
  1492. int len;
  1493. if ((ctxt == NULL) || (filename == NULL)) return(-1);
  1494. if (!strcmp(filename, "-"))
  1495. fd = 0;
  1496. else {
  1497. fd = open(filename, O_CREAT | O_WRONLY, 0666);
  1498. if (fd < 0) {
  1499. xmlNanoHTTPClose(ctxt);
  1500. return(-1);
  1501. }
  1502. }
  1503. xmlNanoHTTPFetchContent( ctxt, &buf, &len );
  1504. if ( len > 0 ) {
  1505. write(fd, buf, len);
  1506. }
  1507. xmlNanoHTTPClose(ctxt);
  1508. close(fd);
  1509. return(0);
  1510. }
  1511. #endif /* LIBXML_OUTPUT_ENABLED */
  1512. /**
  1513. * xmlNanoHTTPReturnCode:
  1514. * @ctx: the HTTP context
  1515. *
  1516. * Get the latest HTTP return code received
  1517. *
  1518. * Returns the HTTP return code for the request.
  1519. */
  1520. int
  1521. xmlNanoHTTPReturnCode(void *ctx) {
  1522. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  1523. if (ctxt == NULL) return(-1);
  1524. return(ctxt->returnValue);
  1525. }
  1526. /**
  1527. * xmlNanoHTTPAuthHeader:
  1528. * @ctx: the HTTP context
  1529. *
  1530. * Get the authentication header of an HTTP context
  1531. *
  1532. * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
  1533. * header.
  1534. */
  1535. const char *
  1536. xmlNanoHTTPAuthHeader(void *ctx) {
  1537. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
  1538. if (ctxt == NULL) return(NULL);
  1539. return(ctxt->authHeader);
  1540. }
  1541. /**
  1542. * xmlNanoHTTPContentLength:
  1543. * @ctx: the HTTP context
  1544. *
  1545. * Provides the specified content length from the HTTP header.
  1546. *
  1547. * Return the specified content length from the HTTP header. Note that
  1548. * a value of -1 indicates that the content length element was not included in
  1549. * the response header.
  1550. */
  1551. int
  1552. xmlNanoHTTPContentLength( void * ctx ) {
  1553. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
  1554. return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
  1555. }
  1556. /**
  1557. * xmlNanoHTTPRedir:
  1558. * @ctx: the HTTP context
  1559. *
  1560. * Provides the specified redirection URL if available from the HTTP header.
  1561. *
  1562. * Return the specified redirection URL or NULL if not redirected.
  1563. */
  1564. const char *
  1565. xmlNanoHTTPRedir( void * ctx ) {
  1566. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
  1567. return ( ( ctxt == NULL ) ? NULL : ctxt->location );
  1568. }
  1569. /**
  1570. * xmlNanoHTTPEncoding:
  1571. * @ctx: the HTTP context
  1572. *
  1573. * Provides the specified encoding if specified in the HTTP headers.
  1574. *
  1575. * Return the specified encoding or NULL if not available
  1576. */
  1577. const char *
  1578. xmlNanoHTTPEncoding( void * ctx ) {
  1579. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
  1580. return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
  1581. }
  1582. /**
  1583. * xmlNanoHTTPMimeType:
  1584. * @ctx: the HTTP context
  1585. *
  1586. * Provides the specified Mime-Type if specified in the HTTP headers.
  1587. *
  1588. * Return the specified Mime-Type or NULL if not available
  1589. */
  1590. const char *
  1591. xmlNanoHTTPMimeType( void * ctx ) {
  1592. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
  1593. return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
  1594. }
  1595. /**
  1596. * xmlNanoHTTPFetchContent:
  1597. * @ctx: the HTTP context
  1598. * @ptr: pointer to set to the content buffer.
  1599. * @len: integer pointer to hold the length of the content
  1600. *
  1601. * Check if all the content was read
  1602. *
  1603. * Returns 0 if all the content was read and available, returns
  1604. * -1 if received content length was less than specified or an error
  1605. * occurred.
  1606. */
  1607. static int
  1608. xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
  1609. xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
  1610. int rc = 0;
  1611. int cur_lgth;
  1612. int rcvd_lgth;
  1613. int dummy_int;
  1614. char * dummy_ptr = NULL;
  1615. /* Dummy up return input parameters if not provided */
  1616. if ( len == NULL )
  1617. len = &dummy_int;
  1618. if ( ptr == NULL )
  1619. ptr = &dummy_ptr;
  1620. /* But can't work without the context pointer */
  1621. if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
  1622. *len = 0;
  1623. *ptr = NULL;
  1624. return ( -1 );
  1625. }
  1626. rcvd_lgth = ctxt->inptr - ctxt->content;
  1627. while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
  1628. rcvd_lgth += cur_lgth;
  1629. if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
  1630. break;
  1631. }
  1632. *ptr = ctxt->content;
  1633. *len = rcvd_lgth;
  1634. if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
  1635. rc = -1;
  1636. else if ( rcvd_lgth == 0 )
  1637. rc = -1;
  1638. return ( rc );
  1639. }
  1640. #ifdef STANDALONE
  1641. int main(int argc, char **argv) {
  1642. char *contentType = NULL;
  1643. if (argv[1] != NULL) {
  1644. if (argv[2] != NULL)
  1645. xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
  1646. else
  1647. xmlNanoHTTPFetch(argv[1], "-", &contentType);
  1648. if (contentType != NULL) xmlFree(contentType);
  1649. } else {
  1650. xmlGenericError(xmlGenericErrorContext,
  1651. "%s: minimal HTTP GET implementation\n", argv[0]);
  1652. xmlGenericError(xmlGenericErrorContext,
  1653. "\tusage %s [ URL [ filename ] ]\n", argv[0]);
  1654. }
  1655. xmlNanoHTTPCleanup();
  1656. xmlMemoryDump();
  1657. return(0);
  1658. }
  1659. #endif /* STANDALONE */
  1660. #else /* !LIBXML_HTTP_ENABLED */
  1661. #ifdef STANDALONE
  1662. #include <stdio.h>
  1663. int main(int argc, char **argv) {
  1664. xmlGenericError(xmlGenericErrorContext,
  1665. "%s : HTTP support not compiled in\n", argv[0]);
  1666. return(0);
  1667. }
  1668. #endif /* STANDALONE */
  1669. #endif /* LIBXML_HTTP_ENABLED */
  1670. #define bottom_nanohttp
  1671. #include "elfgcchack.h"