blob: 9df7a97c3defe7fbe38c0eb415f9a2948df5234e [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000011 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000012 */
13
Daniel Veillardf3afa7d2001-06-09 13:52:58 +000014#define NEED_SOCKETS
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000016#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000017
18#ifdef LIBXML_HTTP_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000019#include <string.h>
20
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
Daniel Veillard75eb1ad2003-07-07 14:42:44 +000027#ifdef HAVE_SYS_TYPES_H
28#include <sys/types.h>
29#endif
Owen Taylor3473f882001-02-23 17:55:21 +000030#ifdef HAVE_SYS_SOCKET_H
31#include <sys/socket.h>
32#endif
33#ifdef HAVE_NETINET_IN_H
34#include <netinet/in.h>
35#endif
36#ifdef HAVE_ARPA_INET_H
37#include <arpa/inet.h>
38#endif
39#ifdef HAVE_NETDB_H
40#include <netdb.h>
41#endif
Daniel Veillardd85f4f42002-03-25 10:48:46 +000042#ifdef HAVE_RESOLV_H
Daniel Veillard9b731d72002-04-14 12:56:08 +000043#ifdef HAVE_ARPA_NAMESER_H
44#include <arpa/nameser.h>
45#endif
Daniel Veillardd85f4f42002-03-25 10:48:46 +000046#include <resolv.h>
47#endif
Owen Taylor3473f882001-02-23 17:55:21 +000048#ifdef HAVE_FCNTL_H
49#include <fcntl.h>
50#endif
51#ifdef HAVE_ERRNO_H
52#include <errno.h>
53#endif
54#ifdef HAVE_SYS_TIME_H
55#include <sys/time.h>
56#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +020057#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +000058#ifdef HAVE_SYS_SELECT_H
59#include <sys/select.h>
60#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +020061#else
62#include <poll.h>
63#endif
Owen Taylor3473f882001-02-23 17:55:21 +000064#ifdef HAVE_STRINGS_H
65#include <strings.h>
66#endif
67#ifdef SUPPORT_IP6
68#include <resolv.h>
69#endif
Daniel Veillard9a2724d2005-12-15 11:12:26 +000070#ifdef HAVE_ZLIB_H
71#include <zlib.h>
72#endif
73
Owen Taylor3473f882001-02-23 17:55:21 +000074
75#ifdef VMS
76#include <stropts>
Daniel Veillardc284c642005-03-31 10:24:24 +000077#define XML_SOCKLEN_T unsigned int
Owen Taylor3473f882001-02-23 17:55:21 +000078#define SOCKET int
79#endif
80
Daniel Veillard59d3ed82007-04-17 12:44:58 +000081#if defined(__MINGW32__) || defined(_WIN32_WCE)
Daniel Veillard1638a472003-08-14 01:23:25 +000082#define _WINSOCKAPI_
83#include <wsockcompat.h>
84#include <winsock2.h>
Daniel Veillardc284c642005-03-31 10:24:24 +000085#undef XML_SOCKLEN_T
86#define XML_SOCKLEN_T unsigned int
Daniel Veillard1638a472003-08-14 01:23:25 +000087#endif
88
89
Daniel Veillardd0463562001-10-13 09:15:48 +000090#include <libxml/globals.h>
Daniel Veillardf012a642001-07-23 19:10:52 +000091#include <libxml/xmlerror.h>
Owen Taylor3473f882001-02-23 17:55:21 +000092#include <libxml/xmlmemory.h>
93#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
94#include <libxml/nanohttp.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000095#include <libxml/globals.h>
Daniel Veillard8efff672002-12-04 11:44:48 +000096#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000097
98/**
99 * A couple portability macros
100 */
101#ifndef _WINSOCKAPI_
Daniel Veillardcba68392008-08-29 12:43:40 +0000102#if !defined(__BEOS__) || defined(__HAIKU__)
Owen Taylor3473f882001-02-23 17:55:21 +0000103#define closesocket(s) close(s)
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000104#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000105#define SOCKET int
106#endif
107
Daniel Veillard89f7f272003-09-29 13:29:09 +0000108#ifdef __BEOS__
109#ifndef PF_INET
110#define PF_INET AF_INET
111#endif
112#endif
113
Daniel Veillardc284c642005-03-31 10:24:24 +0000114#ifndef XML_SOCKLEN_T
115#define XML_SOCKLEN_T unsigned int
Daniel Veillard75be0132002-03-13 10:03:35 +0000116#endif
117#ifndef SOCKET
118#define SOCKET int
119#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121#ifdef STANDALONE
122#define DEBUG_HTTP
123#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
124#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
125#endif
126
127#define XML_NANO_HTTP_MAX_REDIR 10
128
129#define XML_NANO_HTTP_CHUNK 4096
130
131#define XML_NANO_HTTP_CLOSED 0
132#define XML_NANO_HTTP_WRITE 1
133#define XML_NANO_HTTP_READ 2
134#define XML_NANO_HTTP_NONE 4
135
136typedef struct xmlNanoHTTPCtxt {
137 char *protocol; /* the protocol name */
138 char *hostname; /* the host name */
139 int port; /* the port */
140 char *path; /* the path within the URL */
Daniel Veillard351f2d62005-04-13 02:55:12 +0000141 char *query; /* the query string */
Owen Taylor3473f882001-02-23 17:55:21 +0000142 SOCKET fd; /* the file descriptor for the socket */
143 int state; /* WRITE / READ / CLOSED */
144 char *out; /* buffer sent (zero terminated) */
145 char *outptr; /* index within the buffer sent */
146 char *in; /* the receiving buffer */
147 char *content; /* the start of the content */
148 char *inptr; /* the next byte to read from network */
149 char *inrptr; /* the next byte to give back to the client */
150 int inlen; /* len of the input buffer */
151 int last; /* return code for last operation */
152 int returnValue; /* the protocol return value */
Daniel Veillard13cee4e2009-09-05 14:52:55 +0200153 int version; /* the protocol version */
Daniel Veillardf012a642001-07-23 19:10:52 +0000154 int ContentLength; /* specified content length from HTTP header */
Owen Taylor3473f882001-02-23 17:55:21 +0000155 char *contentType; /* the MIME type for the input */
156 char *location; /* the new URL in case of redirect */
157 char *authHeader; /* contents of {WWW,Proxy}-Authenticate header */
Daniel Veillard847332a2003-10-18 11:29:40 +0000158 char *encoding; /* encoding extracted from the contentType */
Daniel Veillarda840b692003-10-19 13:35:37 +0000159 char *mimeType; /* Mime-Type extracted from the contentType */
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000160#ifdef HAVE_ZLIB_H
161 z_stream *strm; /* Zlib stream object */
162 int usesGzip; /* "Content-Encoding: gzip" was detected */
163#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000164} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
165
166static int initialized = 0;
167static char *proxy = NULL; /* the proxy name if any */
168static int proxyPort; /* the proxy port if any */
169static unsigned int timeout = 60;/* the select() timeout in seconds */
170
Daniel Veillarda2351322004-06-27 12:08:10 +0000171static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
Daniel Veillardf012a642001-07-23 19:10:52 +0000172
Owen Taylor3473f882001-02-23 17:55:21 +0000173/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000174 * xmlHTTPErrMemory:
175 * @extra: extra informations
176 *
177 * Handle an out of memory condition
178 */
179static void
180xmlHTTPErrMemory(const char *extra)
181{
182 __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
183}
184
185/**
Owen Taylor3473f882001-02-23 17:55:21 +0000186 * A portability function
187 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000188static int socket_errno(void) {
Owen Taylor3473f882001-02-23 17:55:21 +0000189#ifdef _WINSOCKAPI_
190 return(WSAGetLastError());
191#else
192 return(errno);
193#endif
194}
195
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000196#ifdef SUPPORT_IP6
Daniel Veillard2db8c122003-07-08 12:16:59 +0000197static
198int have_ipv6(void) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000199 int s;
200
201 s = socket (AF_INET6, SOCK_STREAM, 0);
202 if (s != -1) {
203 close (s);
204 return (1);
205 }
206 return (0);
207}
208#endif
209
Owen Taylor3473f882001-02-23 17:55:21 +0000210/**
211 * xmlNanoHTTPInit:
212 *
213 * Initialize the HTTP protocol layer.
214 * Currently it just checks for proxy informations
215 */
216
217void
218xmlNanoHTTPInit(void) {
219 const char *env;
220#ifdef _WINSOCKAPI_
221 WSADATA wsaData;
222#endif
223
224 if (initialized)
225 return;
226
227#ifdef _WINSOCKAPI_
228 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
229 return;
230#endif
231
232 if (proxy == NULL) {
233 proxyPort = 80;
234 env = getenv("no_proxy");
Daniel Veillard29b17482004-08-16 00:39:03 +0000235 if (env && ((env[0] == '*') && (env[1] == 0)))
Owen Taylor3473f882001-02-23 17:55:21 +0000236 goto done;
237 env = getenv("http_proxy");
238 if (env != NULL) {
239 xmlNanoHTTPScanProxy(env);
240 goto done;
241 }
242 env = getenv("HTTP_PROXY");
243 if (env != NULL) {
244 xmlNanoHTTPScanProxy(env);
245 goto done;
246 }
247 }
248done:
249 initialized = 1;
250}
251
252/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000253 * xmlNanoHTTPCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +0000254 *
255 * Cleanup the HTTP protocol layer.
256 */
257
258void
259xmlNanoHTTPCleanup(void) {
Daniel Veillard744acff2005-07-12 15:09:53 +0000260 if (proxy != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000261 xmlFree(proxy);
Daniel Veillard744acff2005-07-12 15:09:53 +0000262 proxy = NULL;
263 }
Owen Taylor3473f882001-02-23 17:55:21 +0000264#ifdef _WINSOCKAPI_
265 if (initialized)
266 WSACleanup();
267#endif
268 initialized = 0;
269 return;
270}
271
272/**
Owen Taylor3473f882001-02-23 17:55:21 +0000273 * xmlNanoHTTPScanURL:
274 * @ctxt: an HTTP context
275 * @URL: The URL used to initialize the context
276 *
277 * (Re)Initialize an HTTP context by parsing the URL and finding
278 * the protocol host port and path it indicates.
279 */
280
281static void
282xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
William M. Brack015ccb22005-02-13 08:18:52 +0000283 xmlURIPtr uri;
284 /*
285 * Clear any existing data from the context
286 */
Owen Taylor3473f882001-02-23 17:55:21 +0000287 if (ctxt->protocol != NULL) {
288 xmlFree(ctxt->protocol);
289 ctxt->protocol = NULL;
290 }
291 if (ctxt->hostname != NULL) {
292 xmlFree(ctxt->hostname);
293 ctxt->hostname = NULL;
294 }
295 if (ctxt->path != NULL) {
296 xmlFree(ctxt->path);
297 ctxt->path = NULL;
298 }
Daniel Veillard351f2d62005-04-13 02:55:12 +0000299 if (ctxt->query != NULL) {
300 xmlFree(ctxt->query);
301 ctxt->query = NULL;
302 }
Owen Taylor3473f882001-02-23 17:55:21 +0000303 if (URL == NULL) return;
William M. Brack015ccb22005-02-13 08:18:52 +0000304
Daniel Veillard336a8e12005-08-07 10:46:19 +0000305 uri = xmlParseURIRaw(URL, 1);
William M. Brack015ccb22005-02-13 08:18:52 +0000306 if (uri == NULL)
307 return;
308
309 if ((uri->scheme == NULL) || (uri->server == NULL)) {
310 xmlFreeURI(uri);
311 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000312 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000313
William M. Brack015ccb22005-02-13 08:18:52 +0000314 ctxt->protocol = xmlMemStrdup(uri->scheme);
315 ctxt->hostname = xmlMemStrdup(uri->server);
316 if (uri->path != NULL)
317 ctxt->path = xmlMemStrdup(uri->path);
318 else
319 ctxt->path = xmlMemStrdup("/");
Daniel Veillard351f2d62005-04-13 02:55:12 +0000320 if (uri->query != NULL)
321 ctxt->query = xmlMemStrdup(uri->query);
William M. Brack015ccb22005-02-13 08:18:52 +0000322 if (uri->port != 0)
323 ctxt->port = uri->port;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000324
William M. Brack015ccb22005-02-13 08:18:52 +0000325 xmlFreeURI(uri);
Owen Taylor3473f882001-02-23 17:55:21 +0000326}
327
328/**
329 * xmlNanoHTTPScanProxy:
330 * @URL: The proxy URL used to initialize the proxy context
331 *
332 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
333 * the protocol host port it indicates.
334 * Should be like http://myproxy/ or http://myproxy:3128/
335 * A NULL URL cleans up proxy informations.
336 */
337
338void
339xmlNanoHTTPScanProxy(const char *URL) {
William M. Brack015ccb22005-02-13 08:18:52 +0000340 xmlURIPtr uri;
Owen Taylor3473f882001-02-23 17:55:21 +0000341
342 if (proxy != NULL) {
343 xmlFree(proxy);
344 proxy = NULL;
345 }
William M. Brack015ccb22005-02-13 08:18:52 +0000346 proxyPort = 0;
347
Owen Taylor3473f882001-02-23 17:55:21 +0000348#ifdef DEBUG_HTTP
349 if (URL == NULL)
350 xmlGenericError(xmlGenericErrorContext,
351 "Removing HTTP proxy info\n");
352 else
353 xmlGenericError(xmlGenericErrorContext,
354 "Using HTTP proxy %s\n", URL);
355#endif
356 if (URL == NULL) return;
William M. Brack015ccb22005-02-13 08:18:52 +0000357
Daniel Veillard336a8e12005-08-07 10:46:19 +0000358 uri = xmlParseURIRaw(URL, 1);
William M. Brack015ccb22005-02-13 08:18:52 +0000359 if ((uri == NULL) || (uri->scheme == NULL) ||
360 (strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
361 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
362 if (uri != NULL)
363 xmlFreeURI(uri);
364 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000365 }
William M. Brack015ccb22005-02-13 08:18:52 +0000366
367 proxy = xmlMemStrdup(uri->server);
368 if (uri->port != 0)
369 proxyPort = uri->port;
Owen Taylor3473f882001-02-23 17:55:21 +0000370
William M. Brack015ccb22005-02-13 08:18:52 +0000371 xmlFreeURI(uri);
Owen Taylor3473f882001-02-23 17:55:21 +0000372}
373
374/**
375 * xmlNanoHTTPNewCtxt:
376 * @URL: The URL used to initialize the context
377 *
378 * Allocate and initialize a new HTTP context.
379 *
380 * Returns an HTTP context or NULL in case of error.
381 */
382
383static xmlNanoHTTPCtxtPtr
384xmlNanoHTTPNewCtxt(const char *URL) {
385 xmlNanoHTTPCtxtPtr ret;
386
387 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000388 if (ret == NULL) {
389 xmlHTTPErrMemory("allocating context");
390 return(NULL);
391 }
Owen Taylor3473f882001-02-23 17:55:21 +0000392
393 memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
394 ret->port = 80;
395 ret->returnValue = 0;
396 ret->fd = -1;
Daniel Veillardf012a642001-07-23 19:10:52 +0000397 ret->ContentLength = -1;
Owen Taylor3473f882001-02-23 17:55:21 +0000398
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000399 xmlNanoHTTPScanURL(ret, URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000400
401 return(ret);
402}
403
404/**
405 * xmlNanoHTTPFreeCtxt:
406 * @ctxt: an HTTP context
407 *
408 * Frees the context after closing the connection.
409 */
410
411static void
412xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
413 if (ctxt == NULL) return;
414 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
415 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
416 if (ctxt->path != NULL) xmlFree(ctxt->path);
Daniel Veillard351f2d62005-04-13 02:55:12 +0000417 if (ctxt->query != NULL) xmlFree(ctxt->query);
Owen Taylor3473f882001-02-23 17:55:21 +0000418 if (ctxt->out != NULL) xmlFree(ctxt->out);
419 if (ctxt->in != NULL) xmlFree(ctxt->in);
420 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
Daniel Veillard847332a2003-10-18 11:29:40 +0000421 if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
Daniel Veillarda840b692003-10-19 13:35:37 +0000422 if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
Owen Taylor3473f882001-02-23 17:55:21 +0000423 if (ctxt->location != NULL) xmlFree(ctxt->location);
424 if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000425#ifdef HAVE_ZLIB_H
426 if (ctxt->strm != NULL) {
427 inflateEnd(ctxt->strm);
428 xmlFree(ctxt->strm);
429 }
430#endif
431
Owen Taylor3473f882001-02-23 17:55:21 +0000432 ctxt->state = XML_NANO_HTTP_NONE;
433 if (ctxt->fd >= 0) closesocket(ctxt->fd);
434 ctxt->fd = -1;
435 xmlFree(ctxt);
436}
437
438/**
439 * xmlNanoHTTPSend:
440 * @ctxt: an HTTP context
441 *
442 * Send the input needed to initiate the processing on the server side
Daniel Veillardf012a642001-07-23 19:10:52 +0000443 * Returns number of bytes sent or -1 on error.
Owen Taylor3473f882001-02-23 17:55:21 +0000444 */
445
Daniel Veillardf012a642001-07-23 19:10:52 +0000446static int
Raphael Prevost48b60c32009-08-23 13:11:01 +0200447xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
448{
449 int total_sent = 0;
450#ifdef HAVE_POLL_H
451 struct pollfd p;
452#else
453 struct timeval tv;
454 fd_set wfd;
455#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000456
Raphael Prevost48b60c32009-08-23 13:11:01 +0200457 if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000458 while (total_sent < outlen) {
459 int nsent = send(ctxt->fd, xmt_ptr + total_sent,
Raphael Prevost48b60c32009-08-23 13:11:01 +0200460 outlen - total_sent, 0);
461
462 if (nsent > 0)
Owen Taylor3473f882001-02-23 17:55:21 +0000463 total_sent += nsent;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200464 else if ((nsent == -1) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000465#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200466 (socket_errno() != EAGAIN) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000467#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200468 (socket_errno() != EWOULDBLOCK)) {
469 __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
470 if (total_sent == 0)
471 total_sent = -1;
472 break;
473 } else {
474 /*
475 * No data sent
476 * Since non-blocking sockets are used, wait for
477 * socket to be writable or default timeout prior
478 * to retrying.
479 */
480#ifndef HAVE_POLL_H
481 if (ctxt->fd > FD_SETSIZE)
482 return -1;
Daniel Veillardf012a642001-07-23 19:10:52 +0000483
Raphael Prevost48b60c32009-08-23 13:11:01 +0200484 tv.tv_sec = timeout;
485 tv.tv_usec = 0;
486 FD_ZERO(&wfd);
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000487#ifdef _MSC_VER
488#pragma warning(push)
489#pragma warning(disable: 4018)
490#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200491 FD_SET(ctxt->fd, &wfd);
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000492#ifdef _MSC_VER
493#pragma warning(pop)
494#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200495 (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
496#else
497 p.fd = ctxt->fd;
498 p.events = POLLOUT;
499 (void) poll(&p, 1, timeout * 1000);
500#endif /* !HAVE_POLL_H */
501 }
502 }
Owen Taylor3473f882001-02-23 17:55:21 +0000503 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000504
505 return total_sent;
Owen Taylor3473f882001-02-23 17:55:21 +0000506}
507
508/**
509 * xmlNanoHTTPRecv:
510 * @ctxt: an HTTP context
511 *
512 * Read information coming from the HTTP connection.
513 * This is a blocking call (but it blocks in select(), not read()).
514 *
515 * Returns the number of byte read or -1 in case of error.
516 */
517
518static int
Raphael Prevost48b60c32009-08-23 13:11:01 +0200519xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
520{
521#ifdef HAVE_POLL_H
522 struct pollfd p;
523#else
Owen Taylor3473f882001-02-23 17:55:21 +0000524 fd_set rfd;
525 struct timeval tv;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200526#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000527
528
529 while (ctxt->state & XML_NANO_HTTP_READ) {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200530 if (ctxt->in == NULL) {
531 ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
532 if (ctxt->in == NULL) {
533 xmlHTTPErrMemory("allocating input");
534 ctxt->last = -1;
535 return (-1);
536 }
537 ctxt->inlen = 65000;
538 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
539 }
540 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
541 int delta = ctxt->inrptr - ctxt->in;
542 int len = ctxt->inptr - ctxt->inrptr;
Owen Taylor3473f882001-02-23 17:55:21 +0000543
Raphael Prevost48b60c32009-08-23 13:11:01 +0200544 memmove(ctxt->in, ctxt->inrptr, len);
545 ctxt->inrptr -= delta;
546 ctxt->content -= delta;
547 ctxt->inptr -= delta;
548 }
549 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
550 int d_inptr = ctxt->inptr - ctxt->in;
551 int d_content = ctxt->content - ctxt->in;
552 int d_inrptr = ctxt->inrptr - ctxt->in;
553 char *tmp_ptr = ctxt->in;
554
555 ctxt->inlen *= 2;
Daniel Veillardf012a642001-07-23 19:10:52 +0000556 ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
Raphael Prevost48b60c32009-08-23 13:11:01 +0200557 if (ctxt->in == NULL) {
558 xmlHTTPErrMemory("allocating input buffer");
559 xmlFree(tmp_ptr);
560 ctxt->last = -1;
561 return (-1);
562 }
Owen Taylor3473f882001-02-23 17:55:21 +0000563 ctxt->inptr = ctxt->in + d_inptr;
564 ctxt->content = ctxt->in + d_content;
565 ctxt->inrptr = ctxt->in + d_inrptr;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200566 }
567 ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
568 if (ctxt->last > 0) {
569 ctxt->inptr += ctxt->last;
570 return (ctxt->last);
571 }
572 if (ctxt->last == 0) {
573 return (0);
574 }
575 if (ctxt->last == -1) {
576 switch (socket_errno()) {
577 case EINPROGRESS:
578 case EWOULDBLOCK:
Owen Taylor3473f882001-02-23 17:55:21 +0000579#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200580 case EAGAIN:
Owen Taylor3473f882001-02-23 17:55:21 +0000581#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200582 break;
Daniel Veillardf012a642001-07-23 19:10:52 +0000583
Raphael Prevost48b60c32009-08-23 13:11:01 +0200584 case ECONNRESET:
585 case ESHUTDOWN:
586 return (0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000587
Raphael Prevost48b60c32009-08-23 13:11:01 +0200588 default:
589 __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
590 return (-1);
591 }
592 }
593#ifdef HAVE_POLL_H
594 p.fd = ctxt->fd;
595 p.events = POLLIN;
596 if ((poll(&p, 1, timeout * 1000) < 1)
597#if defined(EINTR)
598 && (errno != EINTR)
599#endif
600 )
601 return (0);
602#else /* !HAVE_POLL_H */
603 if (ctxt->fd > FD_SETSIZE)
604 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000605
Raphael Prevost48b60c32009-08-23 13:11:01 +0200606 tv.tv_sec = timeout;
607 tv.tv_usec = 0;
608 FD_ZERO(&rfd);
609
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000610#ifdef _MSC_VER
611#pragma warning(push)
612#pragma warning(disable: 4018)
613#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200614
615 FD_SET(ctxt->fd, &rfd);
616
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000617#ifdef _MSC_VER
618#pragma warning(pop)
619#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200620
621 if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
Daniel Veillard50f34372001-08-03 12:06:36 +0000622#if defined(EINTR)
Raphael Prevost48b60c32009-08-23 13:11:01 +0200623 && (errno != EINTR)
Daniel Veillard50f34372001-08-03 12:06:36 +0000624#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200625 )
626 return (0);
627#endif /* !HAVE_POLL_H */
Owen Taylor3473f882001-02-23 17:55:21 +0000628 }
Raphael Prevost48b60c32009-08-23 13:11:01 +0200629 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +0000630}
631
632/**
633 * xmlNanoHTTPReadLine:
634 * @ctxt: an HTTP context
635 *
636 * Read one line in the HTTP server output, usually for extracting
637 * the HTTP protocol informations from the answer header.
638 *
639 * Returns a newly allocated string with a copy of the line, or NULL
640 * which indicate the end of the input.
641 */
642
643static char *
644xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
645 char buf[4096];
646 char *bp = buf;
Daniel Veillardf012a642001-07-23 19:10:52 +0000647 int rc;
Owen Taylor3473f882001-02-23 17:55:21 +0000648
649 while (bp - buf < 4095) {
650 if (ctxt->inrptr == ctxt->inptr) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000651 if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000652 if (bp == buf)
653 return(NULL);
654 else
655 *bp = 0;
656 return(xmlMemStrdup(buf));
657 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000658 else if ( rc == -1 ) {
659 return ( NULL );
660 }
Owen Taylor3473f882001-02-23 17:55:21 +0000661 }
662 *bp = *ctxt->inrptr++;
663 if (*bp == '\n') {
664 *bp = 0;
665 return(xmlMemStrdup(buf));
666 }
667 if (*bp != '\r')
668 bp++;
669 }
670 buf[4095] = 0;
671 return(xmlMemStrdup(buf));
672}
673
674
675/**
676 * xmlNanoHTTPScanAnswer:
677 * @ctxt: an HTTP context
678 * @line: an HTTP header line
679 *
680 * Try to extract useful informations from the server answer.
681 * We currently parse and process:
682 * - The HTTP revision/ return code
Daniel Veillarda840b692003-10-19 13:35:37 +0000683 * - The Content-Type, Mime-Type and charset used
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000684 * - The Location for redirect processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000685 *
686 * Returns -1 in case of failure, the file descriptor number otherwise
687 */
688
689static void
690xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
691 const char *cur = line;
692
693 if (line == NULL) return;
694
695 if (!strncmp(line, "HTTP/", 5)) {
696 int version = 0;
697 int ret = 0;
698
699 cur += 5;
700 while ((*cur >= '0') && (*cur <= '9')) {
701 version *= 10;
702 version += *cur - '0';
703 cur++;
704 }
705 if (*cur == '.') {
706 cur++;
707 if ((*cur >= '0') && (*cur <= '9')) {
708 version *= 10;
709 version += *cur - '0';
710 cur++;
711 }
712 while ((*cur >= '0') && (*cur <= '9'))
713 cur++;
714 } else
715 version *= 10;
716 if ((*cur != ' ') && (*cur != '\t')) return;
717 while ((*cur == ' ') || (*cur == '\t')) cur++;
718 if ((*cur < '0') || (*cur > '9')) return;
719 while ((*cur >= '0') && (*cur <= '9')) {
720 ret *= 10;
721 ret += *cur - '0';
722 cur++;
723 }
724 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
725 ctxt->returnValue = ret;
Daniel Veillard13cee4e2009-09-05 14:52:55 +0200726 ctxt->version = version;
Owen Taylor3473f882001-02-23 17:55:21 +0000727 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
Daniel Veillarda840b692003-10-19 13:35:37 +0000728 const xmlChar *charset, *last, *mime;
Owen Taylor3473f882001-02-23 17:55:21 +0000729 cur += 13;
730 while ((*cur == ' ') || (*cur == '\t')) cur++;
731 if (ctxt->contentType != NULL)
732 xmlFree(ctxt->contentType);
733 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillarda840b692003-10-19 13:35:37 +0000734 mime = (const xmlChar *) cur;
735 last = mime;
736 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
737 (*last != ';') && (*last != ','))
738 last++;
739 if (ctxt->mimeType != NULL)
740 xmlFree(ctxt->mimeType);
741 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
742 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
743 if (charset != NULL) {
744 charset += 8;
745 last = charset;
746 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
747 (*last != ';') && (*last != ','))
748 last++;
749 if (ctxt->encoding != NULL)
750 xmlFree(ctxt->encoding);
751 ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
752 }
Owen Taylor3473f882001-02-23 17:55:21 +0000753 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
Daniel Veillarda840b692003-10-19 13:35:37 +0000754 const xmlChar *charset, *last, *mime;
Owen Taylor3473f882001-02-23 17:55:21 +0000755 cur += 12;
756 if (ctxt->contentType != NULL) return;
757 while ((*cur == ' ') || (*cur == '\t')) cur++;
758 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillarda840b692003-10-19 13:35:37 +0000759 mime = (const xmlChar *) cur;
760 last = mime;
761 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
762 (*last != ';') && (*last != ','))
763 last++;
764 if (ctxt->mimeType != NULL)
765 xmlFree(ctxt->mimeType);
766 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
767 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
768 if (charset != NULL) {
769 charset += 8;
770 last = charset;
771 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
772 (*last != ';') && (*last != ','))
773 last++;
774 if (ctxt->encoding != NULL)
775 xmlFree(ctxt->encoding);
776 ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
777 }
Owen Taylor3473f882001-02-23 17:55:21 +0000778 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
779 cur += 9;
780 while ((*cur == ' ') || (*cur == '\t')) cur++;
781 if (ctxt->location != NULL)
782 xmlFree(ctxt->location);
William M. Brack7e29c0a2004-04-02 09:07:22 +0000783 if (*cur == '/') {
784 xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
785 xmlChar *tmp_loc =
786 xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
787 ctxt->location =
788 (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
789 } else {
790 ctxt->location = xmlMemStrdup(cur);
791 }
Owen Taylor3473f882001-02-23 17:55:21 +0000792 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
793 cur += 17;
794 while ((*cur == ' ') || (*cur == '\t')) cur++;
795 if (ctxt->authHeader != NULL)
796 xmlFree(ctxt->authHeader);
797 ctxt->authHeader = xmlMemStrdup(cur);
798 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
799 cur += 19;
800 while ((*cur == ' ') || (*cur == '\t')) cur++;
801 if (ctxt->authHeader != NULL)
802 xmlFree(ctxt->authHeader);
803 ctxt->authHeader = xmlMemStrdup(cur);
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000804#ifdef HAVE_ZLIB_H
805 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
806 cur += 17;
807 while ((*cur == ' ') || (*cur == '\t')) cur++;
808 if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
809 ctxt->usesGzip = 1;
810
811 ctxt->strm = xmlMalloc(sizeof(z_stream));
812
813 if (ctxt->strm != NULL) {
814 ctxt->strm->zalloc = Z_NULL;
815 ctxt->strm->zfree = Z_NULL;
816 ctxt->strm->opaque = Z_NULL;
817 ctxt->strm->avail_in = 0;
818 ctxt->strm->next_in = Z_NULL;
819
820 inflateInit2( ctxt->strm, 31 );
821 }
822 }
823#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000824 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
825 cur += 15;
826 ctxt->ContentLength = strtol( cur, NULL, 10 );
Owen Taylor3473f882001-02-23 17:55:21 +0000827 }
828}
829
830/**
831 * xmlNanoHTTPConnectAttempt:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000832 * @addr: a socket address structure
Owen Taylor3473f882001-02-23 17:55:21 +0000833 *
834 * Attempt a connection to the given IP:port endpoint. It forces
835 * non-blocking semantic on the socket, and allow 60 seconds for
836 * the host to answer.
837 *
838 * Returns -1 in case of failure, the file descriptor number otherwise
839 */
840
841static int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000842xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
Owen Taylor3473f882001-02-23 17:55:21 +0000843{
Raphael Prevost48b60c32009-08-23 13:11:01 +0200844#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +0000845 fd_set wfd;
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000846#ifdef _WINSOCKAPI_
847 fd_set xfd;
848#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000849 struct timeval tv;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200850#else /* !HAVE_POLL_H */
851 struct pollfd p;
852#endif /* !HAVE_POLL_H */
Owen Taylor3473f882001-02-23 17:55:21 +0000853 int status;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200854
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000855 int addrlen;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200856
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000857 SOCKET s;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200858
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000859#ifdef SUPPORT_IP6
860 if (addr->sa_family == AF_INET6) {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200861 s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
862 addrlen = sizeof(struct sockaddr_in6);
863 } else
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000864#endif
865 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200866 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
867 addrlen = sizeof(struct sockaddr_in);
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000868 }
Raphael Prevost48b60c32009-08-23 13:11:01 +0200869 if (s == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +0000870#ifdef DEBUG_HTTP
Raphael Prevost48b60c32009-08-23 13:11:01 +0200871 perror("socket");
Owen Taylor3473f882001-02-23 17:55:21 +0000872#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200873 __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
874 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000875 }
Owen Taylor3473f882001-02-23 17:55:21 +0000876#ifdef _WINSOCKAPI_
877 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200878 u_long one = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000879
Raphael Prevost48b60c32009-08-23 13:11:01 +0200880 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000881 }
882#else /* _WINSOCKAPI_ */
883#if defined(VMS)
884 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200885 int enable = 1;
886
887 status = ioctl(s, FIONBIO, &enable);
Owen Taylor3473f882001-02-23 17:55:21 +0000888 }
889#else /* VMS */
Daniel Veillardcba68392008-08-29 12:43:40 +0000890#if defined(__BEOS__) && !defined(__HAIKU__)
Raphael Prevost48b60c32009-08-23 13:11:01 +0200891 {
892 bool noblock = true;
893
894 status =
895 setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
896 sizeof(noblock));
897 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000898#else /* __BEOS__ */
Owen Taylor3473f882001-02-23 17:55:21 +0000899 if ((status = fcntl(s, F_GETFL, 0)) != -1) {
900#ifdef O_NONBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200901 status |= O_NONBLOCK;
Owen Taylor3473f882001-02-23 17:55:21 +0000902#else /* O_NONBLOCK */
903#ifdef F_NDELAY
Raphael Prevost48b60c32009-08-23 13:11:01 +0200904 status |= F_NDELAY;
Owen Taylor3473f882001-02-23 17:55:21 +0000905#endif /* F_NDELAY */
906#endif /* !O_NONBLOCK */
Raphael Prevost48b60c32009-08-23 13:11:01 +0200907 status = fcntl(s, F_SETFL, status);
Owen Taylor3473f882001-02-23 17:55:21 +0000908 }
909 if (status < 0) {
910#ifdef DEBUG_HTTP
Raphael Prevost48b60c32009-08-23 13:11:01 +0200911 perror("nonblocking");
Owen Taylor3473f882001-02-23 17:55:21 +0000912#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200913 __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
914 closesocket(s);
915 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000916 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000917#endif /* !__BEOS__ */
Owen Taylor3473f882001-02-23 17:55:21 +0000918#endif /* !VMS */
919#endif /* !_WINSOCKAPI_ */
920
Raphael Prevost48b60c32009-08-23 13:11:01 +0200921 if (connect(s, addr, addrlen) == -1) {
922 switch (socket_errno()) {
923 case EINPROGRESS:
924 case EWOULDBLOCK:
925 break;
926 default:
927 __xmlIOErr(XML_FROM_HTTP, 0,
928 "error connecting to HTTP server");
929 closesocket(s);
930 return (-1);
931 }
932 }
933#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +0000934 tv.tv_sec = timeout;
935 tv.tv_usec = 0;
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000936
937#ifdef _MSC_VER
938#pragma warning(push)
939#pragma warning(disable: 4018)
940#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200941 if (s > FD_SETSIZE)
942 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +0000943 FD_ZERO(&wfd);
944 FD_SET(s, &wfd);
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000945
Raphael Prevost48b60c32009-08-23 13:11:01 +0200946#ifdef _WINSOCKAPI_
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000947 FD_ZERO(&xfd);
948 FD_SET(s, &xfd);
Raphael Prevost48b60c32009-08-23 13:11:01 +0200949
950 switch (select(s + 1, NULL, &wfd, &xfd, &tv))
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000951#else
Raphael Prevost48b60c32009-08-23 13:11:01 +0200952 switch (select(s + 1, NULL, &wfd, NULL, &tv))
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000953#endif
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000954#ifdef _MSC_VER
955#pragma warning(pop)
956#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200957
958#else /* !HAVE_POLL_H */
959 p.fd = s;
960 p.events = POLLOUT;
961 switch (poll(&p, 1, timeout * 1000))
962#endif /* !HAVE_POLL_H */
963
Owen Taylor3473f882001-02-23 17:55:21 +0000964 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200965 case 0:
966 /* Time out */
967 __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
968 closesocket(s);
969 return (-1);
970 case -1:
971 /* Ermm.. ?? */
972 __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
973 closesocket(s);
974 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000975 }
976
Raphael Prevost48b60c32009-08-23 13:11:01 +0200977#ifndef HAVE_POLL_H
978 if (FD_ISSET(s, &wfd)
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000979#ifdef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200980 || FD_ISSET(s, &xfd)
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000981#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200982 )
983#else /* !HAVE_POLL_H */
984 if (p.revents == POLLOUT)
985#endif /* !HAVE_POLL_H */
986 {
987 XML_SOCKLEN_T len;
988
989 len = sizeof(status);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000990#ifdef SO_ERROR
Raphael Prevost48b60c32009-08-23 13:11:01 +0200991 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
992 0) {
993 /* Solaris error code */
994 __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
995 return (-1);
996 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000997#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200998 if (status) {
999 __xmlIOErr(XML_FROM_HTTP, 0,
1000 "Error connecting to remote host");
1001 closesocket(s);
1002 errno = status;
1003 return (-1);
1004 }
Owen Taylor3473f882001-02-23 17:55:21 +00001005 } else {
Raphael Prevost48b60c32009-08-23 13:11:01 +02001006 /* pbm */
1007 __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
1008 closesocket(s);
1009 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001010 }
Raphael Prevost48b60c32009-08-23 13:11:01 +02001011
1012 return (s);
Owen Taylor3473f882001-02-23 17:55:21 +00001013}
Raphael Prevost48b60c32009-08-23 13:11:01 +02001014
Owen Taylor3473f882001-02-23 17:55:21 +00001015/**
1016 * xmlNanoHTTPConnectHost:
1017 * @host: the host name
1018 * @port: the port number
1019 *
1020 * Attempt a connection to the given host:port endpoint. It tries
1021 * the multiple IP provided by the DNS if available.
1022 *
1023 * Returns -1 in case of failure, the file descriptor number otherwise
1024 */
1025
1026static int
1027xmlNanoHTTPConnectHost(const char *host, int port)
1028{
1029 struct hostent *h;
Daniel Veillard2db8c122003-07-08 12:16:59 +00001030 struct sockaddr *addr = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001031 struct in_addr ia;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001032 struct sockaddr_in sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001033
Owen Taylor3473f882001-02-23 17:55:21 +00001034#ifdef SUPPORT_IP6
1035 struct in6_addr ia6;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001036 struct sockaddr_in6 sockin6;
Owen Taylor3473f882001-02-23 17:55:21 +00001037#endif
1038 int i;
1039 int s;
Daniel Veillard5c396542002-03-15 07:57:50 +00001040
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001041 memset (&sockin, 0, sizeof(sockin));
1042#ifdef SUPPORT_IP6
1043 memset (&sockin6, 0, sizeof(sockin6));
Rob Richardscb418de2005-10-13 23:12:42 +00001044#endif
1045
1046#if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001047 if (have_ipv6 ())
Daniel Veillard560c2a42003-07-06 21:13:49 +00001048 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001049 if (!(_res.options & RES_INIT))
1050 res_init();
1051 _res.options |= RES_USE_INET6;
1052 }
Rob Richardscb418de2005-10-13 23:12:42 +00001053#endif
1054
1055#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1056 if (have_ipv6 ())
1057#endif
1058#if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
Daniel Veillard560c2a42003-07-06 21:13:49 +00001059 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001060 int status;
1061 struct addrinfo hints, *res, *result;
1062
1063 result = NULL;
1064 memset (&hints, 0,sizeof(hints));
1065 hints.ai_socktype = SOCK_STREAM;
1066
1067 status = getaddrinfo (host, NULL, &hints, &result);
1068 if (status) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001069 __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001070 return (-1);
1071 }
1072
1073 for (res = result; res; res = res->ai_next) {
Rob Richardscb418de2005-10-13 23:12:42 +00001074 if (res->ai_family == AF_INET) {
1075 if (res->ai_addrlen > sizeof(sockin)) {
1076 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001077 freeaddrinfo (result);
Rob Richardscb418de2005-10-13 23:12:42 +00001078 return (-1);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001079 }
Rob Richardscb418de2005-10-13 23:12:42 +00001080 memcpy (&sockin, res->ai_addr, res->ai_addrlen);
1081 sockin.sin_port = htons (port);
1082 addr = (struct sockaddr *)&sockin;
1083#ifdef SUPPORT_IP6
1084 } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
1085 if (res->ai_addrlen > sizeof(sockin6)) {
1086 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1087 freeaddrinfo (result);
1088 return (-1);
1089 }
1090 memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
1091 sockin6.sin6_port = htons (port);
1092 addr = (struct sockaddr *)&sockin6;
1093#endif
1094 } else
1095 continue; /* for */
1096
1097 s = xmlNanoHTTPConnectAttempt (addr);
1098 if (s != -1) {
1099 freeaddrinfo (result);
1100 return (s);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001101 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001102 }
Rob Richardscb418de2005-10-13 23:12:42 +00001103
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001104 if (result)
1105 freeaddrinfo (result);
Rob Richardscb418de2005-10-13 23:12:42 +00001106 }
Owen Taylor3473f882001-02-23 17:55:21 +00001107#endif
Rob Richardscb418de2005-10-13 23:12:42 +00001108#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1109 else
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001110#endif
Rob Richardscb418de2005-10-13 23:12:42 +00001111#if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
1112 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001113 h = gethostbyname (host);
1114 if (h == NULL) {
Daniel Veillard56b2db72002-03-25 16:35:28 +00001115
1116/*
1117 * Okay, I got fed up by the non-portability of this error message
1118 * extraction code. it work on Linux, if it work on your platform
1119 * and one want to enable it, send me the defined(foobar) needed
1120 */
1121#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001122 const char *h_err_txt = "";
Daniel Veillardf012a642001-07-23 19:10:52 +00001123
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001124 switch (h_errno) {
1125 case HOST_NOT_FOUND:
1126 h_err_txt = "Authoritive host not found";
1127 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001128
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001129 case TRY_AGAIN:
1130 h_err_txt =
1131 "Non-authoritive host not found or server failure.";
1132 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001133
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001134 case NO_RECOVERY:
1135 h_err_txt =
1136 "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
1137 break;
Daniel Veillard5c396542002-03-15 07:57:50 +00001138
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001139 case NO_ADDRESS:
1140 h_err_txt =
1141 "Valid name, no data record of requested type.";
1142 break;
Daniel Veillard5c396542002-03-15 07:57:50 +00001143
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001144 default:
1145 h_err_txt = "No error text defined.";
1146 break;
1147 }
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001148 __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
Daniel Veillard5c396542002-03-15 07:57:50 +00001149#else
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001150 __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
Owen Taylor3473f882001-02-23 17:55:21 +00001151#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001152 return (-1);
1153 }
Daniel Veillard5c396542002-03-15 07:57:50 +00001154
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001155 for (i = 0; h->h_addr_list[i]; i++) {
1156 if (h->h_addrtype == AF_INET) {
1157 /* A records (IPv4) */
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001158 if ((unsigned int) h->h_length > sizeof(ia)) {
1159 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1160 return (-1);
1161 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001162 memcpy (&ia, h->h_addr_list[i], h->h_length);
1163 sockin.sin_family = h->h_addrtype;
1164 sockin.sin_addr = ia;
Daniel Veillard9e2110b2005-08-08 20:33:54 +00001165 sockin.sin_port = (u_short)htons ((unsigned short)port);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001166 addr = (struct sockaddr *) &sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001167#ifdef SUPPORT_IP6
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001168 } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
1169 /* AAAA records (IPv6) */
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001170 if ((unsigned int) h->h_length > sizeof(ia6)) {
1171 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1172 return (-1);
1173 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001174 memcpy (&ia6, h->h_addr_list[i], h->h_length);
1175 sockin6.sin6_family = h->h_addrtype;
1176 sockin6.sin6_addr = ia6;
1177 sockin6.sin6_port = htons (port);
1178 addr = (struct sockaddr *) &sockin6;
Daniel Veillard5c396542002-03-15 07:57:50 +00001179#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001180 } else
1181 break; /* for */
Daniel Veillard5c396542002-03-15 07:57:50 +00001182
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001183 s = xmlNanoHTTPConnectAttempt (addr);
1184 if (s != -1)
1185 return (s);
1186 }
Owen Taylor3473f882001-02-23 17:55:21 +00001187 }
Rob Richardscb418de2005-10-13 23:12:42 +00001188#endif
1189
Owen Taylor3473f882001-02-23 17:55:21 +00001190#ifdef DEBUG_HTTP
1191 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard5c396542002-03-15 07:57:50 +00001192 "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",
1193 host);
Owen Taylor3473f882001-02-23 17:55:21 +00001194#endif
Daniel Veillard5c396542002-03-15 07:57:50 +00001195 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001196}
1197
1198
1199/**
1200 * xmlNanoHTTPOpen:
1201 * @URL: The URL to load
1202 * @contentType: if available the Content-Type information will be
1203 * returned at that location
1204 *
1205 * This function try to open a connection to the indicated resource
1206 * via HTTP GET.
1207 *
1208 * Returns NULL in case of failure, otherwise a request handler.
1209 * The contentType, if provided must be freed by the caller
1210 */
1211
1212void*
1213xmlNanoHTTPOpen(const char *URL, char **contentType) {
1214 if (contentType != NULL) *contentType = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001215 return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
Daniel Veillard9403a042001-05-28 11:00:53 +00001216}
1217
1218/**
1219 * xmlNanoHTTPOpenRedir:
1220 * @URL: The URL to load
1221 * @contentType: if available the Content-Type information will be
1222 * returned at that location
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001223 * @redir: if available the redirected URL will be returned
Daniel Veillard9403a042001-05-28 11:00:53 +00001224 *
1225 * This function try to open a connection to the indicated resource
1226 * via HTTP GET.
1227 *
1228 * Returns NULL in case of failure, otherwise a request handler.
1229 * The contentType, if provided must be freed by the caller
1230 */
1231
1232void*
1233xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
1234 if (contentType != NULL) *contentType = NULL;
1235 if (redir != NULL) *redir = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001236 return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
Owen Taylor3473f882001-02-23 17:55:21 +00001237}
1238
1239/**
1240 * xmlNanoHTTPRead:
1241 * @ctx: the HTTP context
1242 * @dest: a buffer
1243 * @len: the buffer length
1244 *
1245 * This function tries to read @len bytes from the existing HTTP connection
1246 * and saves them in @dest. This is a blocking call.
1247 *
1248 * Returns the number of byte read. 0 is an indication of an end of connection.
1249 * -1 indicates a parameter error.
1250 */
1251int
1252xmlNanoHTTPRead(void *ctx, void *dest, int len) {
1253 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001254#ifdef HAVE_ZLIB_H
1255 int bytes_read = 0;
1256 int orig_avail_in;
1257 int z_ret;
1258#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001259
1260 if (ctx == NULL) return(-1);
1261 if (dest == NULL) return(-1);
1262 if (len <= 0) return(0);
1263
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001264#ifdef HAVE_ZLIB_H
1265 if (ctxt->usesGzip == 1) {
1266 if (ctxt->strm == NULL) return(0);
1267
1268 ctxt->strm->next_out = dest;
1269 ctxt->strm->avail_out = len;
William M. Bracke8827652007-05-16 05:19:13 +00001270 ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001271
William M. Bracke8827652007-05-16 05:19:13 +00001272 while (ctxt->strm->avail_out > 0 &&
1273 (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
William M. Brackd2f682a2007-05-15 19:42:08 +00001274 orig_avail_in = ctxt->strm->avail_in =
1275 ctxt->inptr - ctxt->inrptr - bytes_read;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001276 ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
1277
1278 z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
1279 bytes_read += orig_avail_in - ctxt->strm->avail_in;
1280
1281 if (z_ret != Z_OK) break;
William M. Brackd2f682a2007-05-15 19:42:08 +00001282 }
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001283
1284 ctxt->inrptr += bytes_read;
1285 return(len - ctxt->strm->avail_out);
1286 }
1287#endif
1288
Owen Taylor3473f882001-02-23 17:55:21 +00001289 while (ctxt->inptr - ctxt->inrptr < len) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001290 if (xmlNanoHTTPRecv(ctxt) <= 0) break;
Owen Taylor3473f882001-02-23 17:55:21 +00001291 }
1292 if (ctxt->inptr - ctxt->inrptr < len)
1293 len = ctxt->inptr - ctxt->inrptr;
1294 memcpy(dest, ctxt->inrptr, len);
1295 ctxt->inrptr += len;
1296 return(len);
1297}
1298
1299/**
1300 * xmlNanoHTTPClose:
1301 * @ctx: the HTTP context
1302 *
1303 * This function closes an HTTP context, it ends up the connection and
1304 * free all data related to it.
1305 */
1306void
1307xmlNanoHTTPClose(void *ctx) {
1308 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1309
1310 if (ctx == NULL) return;
1311
1312 xmlNanoHTTPFreeCtxt(ctxt);
1313}
1314
1315/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001316 * xmlNanoHTTPMethodRedir:
Owen Taylor3473f882001-02-23 17:55:21 +00001317 * @URL: The URL to load
1318 * @method: the HTTP method to use
1319 * @input: the input string if any
1320 * @contentType: the Content-Type information IN and OUT
Daniel Veillard9403a042001-05-28 11:00:53 +00001321 * @redir: the redirected URL OUT
Owen Taylor3473f882001-02-23 17:55:21 +00001322 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001323 * @ilen: input length
Owen Taylor3473f882001-02-23 17:55:21 +00001324 *
1325 * This function try to open a connection to the indicated resource
1326 * via HTTP using the given @method, adding the given extra headers
1327 * and the input buffer for the request content.
1328 *
1329 * Returns NULL in case of failure, otherwise a request handler.
Daniel Veillard9403a042001-05-28 11:00:53 +00001330 * The contentType, or redir, if provided must be freed by the caller
Owen Taylor3473f882001-02-23 17:55:21 +00001331 */
1332
1333void*
Daniel Veillard9403a042001-05-28 11:00:53 +00001334xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001335 char **contentType, char **redir,
1336 const char *headers, int ilen ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001337 xmlNanoHTTPCtxtPtr ctxt;
1338 char *bp, *p;
Daniel Veillardf012a642001-07-23 19:10:52 +00001339 int blen, ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001340 int head;
1341 int nbRedirects = 0;
1342 char *redirURL = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001343#ifdef DEBUG_HTTP
1344 int xmt_bytes;
1345#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001346
1347 if (URL == NULL) return(NULL);
1348 if (method == NULL) method = "GET";
1349 xmlNanoHTTPInit();
1350
1351retry:
1352 if (redirURL == NULL)
1353 ctxt = xmlNanoHTTPNewCtxt(URL);
1354 else {
1355 ctxt = xmlNanoHTTPNewCtxt(redirURL);
Daniel Veillarda840b692003-10-19 13:35:37 +00001356 ctxt->location = xmlMemStrdup(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001357 }
1358
Daniel Veillardf012a642001-07-23 19:10:52 +00001359 if ( ctxt == NULL ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001360 return ( NULL );
1361 }
1362
Owen Taylor3473f882001-02-23 17:55:21 +00001363 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001364 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
Owen Taylor3473f882001-02-23 17:55:21 +00001365 xmlNanoHTTPFreeCtxt(ctxt);
1366 if (redirURL != NULL) xmlFree(redirURL);
1367 return(NULL);
1368 }
1369 if (ctxt->hostname == NULL) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001370 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
1371 "Failed to identify host in URI");
Owen Taylor3473f882001-02-23 17:55:21 +00001372 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001373 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001374 return(NULL);
1375 }
1376 if (proxy) {
1377 blen = strlen(ctxt->hostname) * 2 + 16;
1378 ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
1379 }
1380 else {
1381 blen = strlen(ctxt->hostname);
1382 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1383 }
1384 if (ret < 0) {
1385 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001386 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001387 return(NULL);
1388 }
1389 ctxt->fd = ret;
1390
Daniel Veillardf012a642001-07-23 19:10:52 +00001391 if (input == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001392 ilen = 0;
Daniel Veillardf012a642001-07-23 19:10:52 +00001393 else
1394 blen += 36;
1395
Owen Taylor3473f882001-02-23 17:55:21 +00001396 if (headers != NULL)
Daniel Veillardf012a642001-07-23 19:10:52 +00001397 blen += strlen(headers) + 2;
Owen Taylor3473f882001-02-23 17:55:21 +00001398 if (contentType && *contentType)
William M. Brackead35832008-02-06 04:12:46 +00001399 /* reserve for string plus 'Content-Type: \r\n" */
Owen Taylor3473f882001-02-23 17:55:21 +00001400 blen += strlen(*contentType) + 16;
Daniel Veillard351f2d62005-04-13 02:55:12 +00001401 if (ctxt->query != NULL)
William M. Brackead35832008-02-06 04:12:46 +00001402 /* 1 for '?' */
Daniel Veillard351f2d62005-04-13 02:55:12 +00001403 blen += strlen(ctxt->query) + 1;
Daniel Veillardf012a642001-07-23 19:10:52 +00001404 blen += strlen(method) + strlen(ctxt->path) + 24;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001405#ifdef HAVE_ZLIB_H
William M. Brackead35832008-02-06 04:12:46 +00001406 /* reserve for possible 'Accept-Encoding: gzip' string */
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001407 blen += 23;
1408#endif
William M. Brackead35832008-02-06 04:12:46 +00001409 if (ctxt->port != 80) {
1410 /* reserve space for ':xxxxx', incl. potential proxy */
1411 if (proxy)
1412 blen += 12;
1413 else
1414 blen += 6;
1415 }
Daniel Veillard82cb3192003-10-29 13:39:15 +00001416 bp = (char*)xmlMallocAtomic(blen);
Daniel Veillardf012a642001-07-23 19:10:52 +00001417 if ( bp == NULL ) {
1418 xmlNanoHTTPFreeCtxt( ctxt );
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001419 xmlHTTPErrMemory("allocating header buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001420 return ( NULL );
1421 }
1422
1423 p = bp;
1424
Owen Taylor3473f882001-02-23 17:55:21 +00001425 if (proxy) {
1426 if (ctxt->port != 80) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001427 p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s",
1428 method, ctxt->hostname,
Daniel Veillardf012a642001-07-23 19:10:52 +00001429 ctxt->port, ctxt->path );
Owen Taylor3473f882001-02-23 17:55:21 +00001430 }
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001431 else
1432 p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
Daniel Veillardf012a642001-07-23 19:10:52 +00001433 ctxt->hostname, ctxt->path);
Owen Taylor3473f882001-02-23 17:55:21 +00001434 }
1435 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001436 p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
Daniel Veillardf012a642001-07-23 19:10:52 +00001437
Daniel Veillard351f2d62005-04-13 02:55:12 +00001438 if (ctxt->query != NULL)
1439 p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
1440
William M. Brackec720082007-08-24 02:57:38 +00001441 if (ctxt->port == 80) {
1442 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001443 ctxt->hostname);
William M. Brackec720082007-08-24 02:57:38 +00001444 } else {
1445 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
1446 ctxt->hostname, ctxt->port);
1447 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001448
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001449#ifdef HAVE_ZLIB_H
1450 p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
1451#endif
1452
Daniel Veillardf012a642001-07-23 19:10:52 +00001453 if (contentType != NULL && *contentType)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001454 p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
Daniel Veillardf012a642001-07-23 19:10:52 +00001455
1456 if (headers != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001457 p += snprintf( p, blen - (p - bp), "%s", headers );
Daniel Veillardf012a642001-07-23 19:10:52 +00001458
Owen Taylor3473f882001-02-23 17:55:21 +00001459 if (input != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001460 snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
Owen Taylor3473f882001-02-23 17:55:21 +00001461 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001462 snprintf(p, blen - (p - bp), "\r\n");
Daniel Veillardf012a642001-07-23 19:10:52 +00001463
Owen Taylor3473f882001-02-23 17:55:21 +00001464#ifdef DEBUG_HTTP
1465 xmlGenericError(xmlGenericErrorContext,
1466 "-> %s%s", proxy? "(Proxy) " : "", bp);
1467 if ((blen -= strlen(bp)+1) < 0)
1468 xmlGenericError(xmlGenericErrorContext,
1469 "ERROR: overflowed buffer by %d bytes\n", -blen);
1470#endif
1471 ctxt->outptr = ctxt->out = bp;
1472 ctxt->state = XML_NANO_HTTP_WRITE;
Daniel Veillardf012a642001-07-23 19:10:52 +00001473 blen = strlen( ctxt->out );
Daniel Veillardf012a642001-07-23 19:10:52 +00001474#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001475 xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001476 if ( xmt_bytes != blen )
1477 xmlGenericError( xmlGenericErrorContext,
1478 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1479 xmt_bytes, blen,
1480 "bytes of HTTP headers sent to host",
1481 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001482#else
1483 xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001484#endif
1485
1486 if ( input != NULL ) {
William M. Brack78637da2003-07-31 14:47:38 +00001487#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001488 xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
1489
Daniel Veillardf012a642001-07-23 19:10:52 +00001490 if ( xmt_bytes != ilen )
1491 xmlGenericError( xmlGenericErrorContext,
1492 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1493 xmt_bytes, ilen,
1494 "bytes of HTTP content sent to host",
1495 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001496#else
1497 xmlNanoHTTPSend( ctxt, input, ilen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001498#endif
1499 }
1500
Owen Taylor3473f882001-02-23 17:55:21 +00001501 ctxt->state = XML_NANO_HTTP_READ;
1502 head = 1;
1503
1504 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
1505 if (head && (*p == 0)) {
1506 head = 0;
1507 ctxt->content = ctxt->inrptr;
1508 xmlFree(p);
1509 break;
1510 }
1511 xmlNanoHTTPScanAnswer(ctxt, p);
1512
1513#ifdef DEBUG_HTTP
1514 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
1515#endif
1516 xmlFree(p);
1517 }
1518
1519 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1520 (ctxt->returnValue < 400)) {
1521#ifdef DEBUG_HTTP
1522 xmlGenericError(xmlGenericErrorContext,
1523 "\nRedirect to: %s\n", ctxt->location);
1524#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001525 while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
Owen Taylor3473f882001-02-23 17:55:21 +00001526 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1527 nbRedirects++;
Daniel Veillard9403a042001-05-28 11:00:53 +00001528 if (redirURL != NULL)
1529 xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001530 redirURL = xmlMemStrdup(ctxt->location);
1531 xmlNanoHTTPFreeCtxt(ctxt);
1532 goto retry;
1533 }
1534 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001535 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001536#ifdef DEBUG_HTTP
1537 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00001538 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001539#endif
1540 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001541 }
1542
1543 if (contentType != NULL) {
1544 if (ctxt->contentType != NULL)
1545 *contentType = xmlMemStrdup(ctxt->contentType);
1546 else
1547 *contentType = NULL;
1548 }
1549
Daniel Veillard9403a042001-05-28 11:00:53 +00001550 if ((redir != NULL) && (redirURL != NULL)) {
1551 *redir = redirURL;
1552 } else {
1553 if (redirURL != NULL)
1554 xmlFree(redirURL);
1555 if (redir != NULL)
1556 *redir = NULL;
1557 }
1558
Owen Taylor3473f882001-02-23 17:55:21 +00001559#ifdef DEBUG_HTTP
1560 if (ctxt->contentType != NULL)
1561 xmlGenericError(xmlGenericErrorContext,
1562 "\nCode %d, content-type '%s'\n\n",
1563 ctxt->returnValue, ctxt->contentType);
1564 else
1565 xmlGenericError(xmlGenericErrorContext,
1566 "\nCode %d, no content-type\n\n",
1567 ctxt->returnValue);
1568#endif
1569
1570 return((void *) ctxt);
1571}
1572
1573/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001574 * xmlNanoHTTPMethod:
1575 * @URL: The URL to load
1576 * @method: the HTTP method to use
1577 * @input: the input string if any
1578 * @contentType: the Content-Type information IN and OUT
1579 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001580 * @ilen: input length
Daniel Veillard9403a042001-05-28 11:00:53 +00001581 *
1582 * This function try to open a connection to the indicated resource
1583 * via HTTP using the given @method, adding the given extra headers
1584 * and the input buffer for the request content.
1585 *
1586 * Returns NULL in case of failure, otherwise a request handler.
1587 * The contentType, if provided must be freed by the caller
1588 */
1589
1590void*
1591xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001592 char **contentType, const char *headers, int ilen) {
Daniel Veillard9403a042001-05-28 11:00:53 +00001593 return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
Daniel Veillardf012a642001-07-23 19:10:52 +00001594 NULL, headers, ilen));
Daniel Veillard9403a042001-05-28 11:00:53 +00001595}
1596
1597/**
Owen Taylor3473f882001-02-23 17:55:21 +00001598 * xmlNanoHTTPFetch:
1599 * @URL: The URL to load
1600 * @filename: the filename where the content should be saved
1601 * @contentType: if available the Content-Type information will be
1602 * returned at that location
1603 *
1604 * This function try to fetch the indicated resource via HTTP GET
1605 * and save it's content in the file.
1606 *
1607 * Returns -1 in case of failure, 0 incase of success. The contentType,
1608 * if provided must be freed by the caller
1609 */
1610int
1611xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001612 void *ctxt = NULL;
1613 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001614 int fd;
1615 int len;
1616
William M. Brack015ccb22005-02-13 08:18:52 +00001617 if (filename == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001618 ctxt = xmlNanoHTTPOpen(URL, contentType);
1619 if (ctxt == NULL) return(-1);
1620
1621 if (!strcmp(filename, "-"))
1622 fd = 0;
1623 else {
1624 fd = open(filename, O_CREAT | O_WRONLY, 00644);
1625 if (fd < 0) {
1626 xmlNanoHTTPClose(ctxt);
1627 if ((contentType != NULL) && (*contentType != NULL)) {
1628 xmlFree(*contentType);
1629 *contentType = NULL;
1630 }
1631 return(-1);
1632 }
1633 }
1634
Daniel Veillardf012a642001-07-23 19:10:52 +00001635 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1636 if ( len > 0 ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001637 write(fd, buf, len);
1638 }
1639
1640 xmlNanoHTTPClose(ctxt);
1641 close(fd);
1642 return(0);
1643}
1644
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001645#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001646/**
1647 * xmlNanoHTTPSave:
1648 * @ctxt: the HTTP context
1649 * @filename: the filename where the content should be saved
1650 *
1651 * This function saves the output of the HTTP transaction to a file
1652 * It closes and free the context at the end
1653 *
1654 * Returns -1 in case of failure, 0 incase of success.
1655 */
1656int
1657xmlNanoHTTPSave(void *ctxt, const char *filename) {
Daniel Veillarde3924972001-07-25 20:25:21 +00001658 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001659 int fd;
1660 int len;
1661
William M. Brack015ccb22005-02-13 08:18:52 +00001662 if ((ctxt == NULL) || (filename == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001663
1664 if (!strcmp(filename, "-"))
1665 fd = 0;
1666 else {
Daniel Veillardcd2ebab2007-08-23 20:47:33 +00001667 fd = open(filename, O_CREAT | O_WRONLY, 0666);
Owen Taylor3473f882001-02-23 17:55:21 +00001668 if (fd < 0) {
1669 xmlNanoHTTPClose(ctxt);
1670 return(-1);
1671 }
1672 }
1673
Daniel Veillardf012a642001-07-23 19:10:52 +00001674 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1675 if ( len > 0 ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001676 write(fd, buf, len);
1677 }
1678
1679 xmlNanoHTTPClose(ctxt);
William M. Brack20d82362004-03-17 08:44:46 +00001680 close(fd);
Owen Taylor3473f882001-02-23 17:55:21 +00001681 return(0);
1682}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001683#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001684
1685/**
1686 * xmlNanoHTTPReturnCode:
1687 * @ctx: the HTTP context
1688 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001689 * Get the latest HTTP return code received
1690 *
Owen Taylor3473f882001-02-23 17:55:21 +00001691 * Returns the HTTP return code for the request.
1692 */
1693int
1694xmlNanoHTTPReturnCode(void *ctx) {
1695 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1696
1697 if (ctxt == NULL) return(-1);
1698
1699 return(ctxt->returnValue);
1700}
1701
1702/**
1703 * xmlNanoHTTPAuthHeader:
1704 * @ctx: the HTTP context
1705 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001706 * Get the authentication header of an HTTP context
1707 *
Owen Taylor3473f882001-02-23 17:55:21 +00001708 * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
1709 * header.
1710 */
1711const char *
1712xmlNanoHTTPAuthHeader(void *ctx) {
1713 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1714
1715 if (ctxt == NULL) return(NULL);
1716
1717 return(ctxt->authHeader);
1718}
1719
Daniel Veillardf012a642001-07-23 19:10:52 +00001720/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001721 * xmlNanoHTTPContentLength:
Daniel Veillardf012a642001-07-23 19:10:52 +00001722 * @ctx: the HTTP context
1723 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001724 * Provides the specified content length from the HTTP header.
1725 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001726 * Return the specified content length from the HTTP header. Note that
1727 * a value of -1 indicates that the content length element was not included in
1728 * the response header.
1729 */
1730int
1731xmlNanoHTTPContentLength( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001732 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillardf012a642001-07-23 19:10:52 +00001733
1734 return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
1735}
1736
1737/**
Daniel Veillard847332a2003-10-18 11:29:40 +00001738 * xmlNanoHTTPRedir:
1739 * @ctx: the HTTP context
1740 *
1741 * Provides the specified redirection URL if available from the HTTP header.
1742 *
1743 * Return the specified redirection URL or NULL if not redirected.
1744 */
1745const char *
1746xmlNanoHTTPRedir( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001747 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillard847332a2003-10-18 11:29:40 +00001748
1749 return ( ( ctxt == NULL ) ? NULL : ctxt->location );
1750}
1751
1752/**
1753 * xmlNanoHTTPEncoding:
1754 * @ctx: the HTTP context
1755 *
1756 * Provides the specified encoding if specified in the HTTP headers.
1757 *
1758 * Return the specified encoding or NULL if not available
1759 */
1760const char *
1761xmlNanoHTTPEncoding( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001762 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillard847332a2003-10-18 11:29:40 +00001763
1764 return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
1765}
1766
1767/**
Daniel Veillarda840b692003-10-19 13:35:37 +00001768 * xmlNanoHTTPMimeType:
1769 * @ctx: the HTTP context
1770 *
1771 * Provides the specified Mime-Type if specified in the HTTP headers.
1772 *
1773 * Return the specified Mime-Type or NULL if not available
1774 */
1775const char *
1776xmlNanoHTTPMimeType( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001777 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillarda840b692003-10-19 13:35:37 +00001778
1779 return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
1780}
1781
1782/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001783 * xmlNanoHTTPFetchContent:
Daniel Veillardf012a642001-07-23 19:10:52 +00001784 * @ctx: the HTTP context
1785 * @ptr: pointer to set to the content buffer.
1786 * @len: integer pointer to hold the length of the content
1787 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001788 * Check if all the content was read
1789 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001790 * Returns 0 if all the content was read and available, returns
1791 * -1 if received content length was less than specified or an error
1792 * occurred.
1793 */
Daniel Veillarda2351322004-06-27 12:08:10 +00001794static int
Daniel Veillardf012a642001-07-23 19:10:52 +00001795xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001796 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillardf012a642001-07-23 19:10:52 +00001797
1798 int rc = 0;
1799 int cur_lgth;
1800 int rcvd_lgth;
1801 int dummy_int;
1802 char * dummy_ptr = NULL;
1803
1804 /* Dummy up return input parameters if not provided */
1805
1806 if ( len == NULL )
1807 len = &dummy_int;
1808
1809 if ( ptr == NULL )
1810 ptr = &dummy_ptr;
1811
1812 /* But can't work without the context pointer */
1813
1814 if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
1815 *len = 0;
1816 *ptr = NULL;
1817 return ( -1 );
1818 }
1819
1820 rcvd_lgth = ctxt->inptr - ctxt->content;
1821
1822 while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
1823
1824 rcvd_lgth += cur_lgth;
1825 if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
1826 break;
1827 }
1828
1829 *ptr = ctxt->content;
1830 *len = rcvd_lgth;
1831
1832 if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
1833 rc = -1;
1834 else if ( rcvd_lgth == 0 )
1835 rc = -1;
1836
1837 return ( rc );
1838}
1839
Owen Taylor3473f882001-02-23 17:55:21 +00001840#ifdef STANDALONE
1841int main(int argc, char **argv) {
1842 char *contentType = NULL;
1843
1844 if (argv[1] != NULL) {
1845 if (argv[2] != NULL)
1846 xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1847 else
1848 xmlNanoHTTPFetch(argv[1], "-", &contentType);
1849 if (contentType != NULL) xmlFree(contentType);
1850 } else {
1851 xmlGenericError(xmlGenericErrorContext,
1852 "%s: minimal HTTP GET implementation\n", argv[0]);
1853 xmlGenericError(xmlGenericErrorContext,
1854 "\tusage %s [ URL [ filename ] ]\n", argv[0]);
1855 }
1856 xmlNanoHTTPCleanup();
1857 xmlMemoryDump();
1858 return(0);
1859}
1860#endif /* STANDALONE */
1861#else /* !LIBXML_HTTP_ENABLED */
1862#ifdef STANDALONE
1863#include <stdio.h>
1864int main(int argc, char **argv) {
1865 xmlGenericError(xmlGenericErrorContext,
1866 "%s : HTTP support not compiled in\n", argv[0]);
1867 return(0);
1868}
1869#endif /* STANDALONE */
1870#endif /* LIBXML_HTTP_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001871#define bottom_nanohttp
1872#include "elfgcchack.h"