nanohttp.c 47 KB

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