blob: 2437fed81bda73bb37682437bd1acd76cce1cd4c [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
Daniel Veillard9a2724d2005-12-15 11:12:26 +000067#ifdef HAVE_ZLIB_H
68#include <zlib.h>
69#endif
70
Owen Taylor3473f882001-02-23 17:55:21 +000071
72#ifdef VMS
73#include <stropts>
Daniel Veillardc284c642005-03-31 10:24:24 +000074#define XML_SOCKLEN_T unsigned int
Owen Taylor3473f882001-02-23 17:55:21 +000075#endif
76
Daniel Veillard59d3ed82007-04-17 12:44:58 +000077#if defined(__MINGW32__) || defined(_WIN32_WCE)
Ozkan Sezerf99d2222010-11-04 12:08:08 +010078#ifndef _WINSOCKAPI_
Daniel Veillard1638a472003-08-14 01:23:25 +000079#define _WINSOCKAPI_
Ozkan Sezerf99d2222010-11-04 12:08:08 +010080#endif
Daniel Veillard1638a472003-08-14 01:23:25 +000081#include <wsockcompat.h>
82#include <winsock2.h>
Daniel Veillardc284c642005-03-31 10:24:24 +000083#undef XML_SOCKLEN_T
84#define XML_SOCKLEN_T unsigned int
Daniel Veillard1638a472003-08-14 01:23:25 +000085#endif
86
Daniel Veillardd0463562001-10-13 09:15:48 +000087#include <libxml/globals.h>
Daniel Veillardf012a642001-07-23 19:10:52 +000088#include <libxml/xmlerror.h>
Owen Taylor3473f882001-02-23 17:55:21 +000089#include <libxml/xmlmemory.h>
90#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
91#include <libxml/nanohttp.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000092#include <libxml/globals.h>
Daniel Veillard8efff672002-12-04 11:44:48 +000093#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000094
95/**
96 * A couple portability macros
97 */
98#ifndef _WINSOCKAPI_
Daniel Veillardcba68392008-08-29 12:43:40 +000099#if !defined(__BEOS__) || defined(__HAIKU__)
Owen Taylor3473f882001-02-23 17:55:21 +0000100#define closesocket(s) close(s)
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000101#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000102#define SOCKET int
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100103#define INVALID_SOCKET (-1)
Owen Taylor3473f882001-02-23 17:55:21 +0000104#endif
105
Daniel Veillard89f7f272003-09-29 13:29:09 +0000106#ifdef __BEOS__
107#ifndef PF_INET
108#define PF_INET AF_INET
109#endif
110#endif
111
Daniel Veillardc284c642005-03-31 10:24:24 +0000112#ifndef XML_SOCKLEN_T
113#define XML_SOCKLEN_T unsigned int
Daniel Veillard75be0132002-03-13 10:03:35 +0000114#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000115
Owen Taylor3473f882001-02-23 17:55:21 +0000116#ifdef STANDALONE
117#define DEBUG_HTTP
118#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
119#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
120#endif
121
122#define XML_NANO_HTTP_MAX_REDIR 10
123
124#define XML_NANO_HTTP_CHUNK 4096
125
126#define XML_NANO_HTTP_CLOSED 0
127#define XML_NANO_HTTP_WRITE 1
128#define XML_NANO_HTTP_READ 2
129#define XML_NANO_HTTP_NONE 4
130
131typedef struct xmlNanoHTTPCtxt {
132 char *protocol; /* the protocol name */
133 char *hostname; /* the host name */
134 int port; /* the port */
135 char *path; /* the path within the URL */
Daniel Veillard351f2d62005-04-13 02:55:12 +0000136 char *query; /* the query string */
Owen Taylor3473f882001-02-23 17:55:21 +0000137 SOCKET fd; /* the file descriptor for the socket */
138 int state; /* WRITE / READ / CLOSED */
139 char *out; /* buffer sent (zero terminated) */
140 char *outptr; /* index within the buffer sent */
141 char *in; /* the receiving buffer */
142 char *content; /* the start of the content */
143 char *inptr; /* the next byte to read from network */
144 char *inrptr; /* the next byte to give back to the client */
145 int inlen; /* len of the input buffer */
146 int last; /* return code for last operation */
147 int returnValue; /* the protocol return value */
Daniel Veillard13cee4e2009-09-05 14:52:55 +0200148 int version; /* the protocol version */
Daniel Veillardf012a642001-07-23 19:10:52 +0000149 int ContentLength; /* specified content length from HTTP header */
Owen Taylor3473f882001-02-23 17:55:21 +0000150 char *contentType; /* the MIME type for the input */
151 char *location; /* the new URL in case of redirect */
152 char *authHeader; /* contents of {WWW,Proxy}-Authenticate header */
Daniel Veillard847332a2003-10-18 11:29:40 +0000153 char *encoding; /* encoding extracted from the contentType */
Daniel Veillarda840b692003-10-19 13:35:37 +0000154 char *mimeType; /* Mime-Type extracted from the contentType */
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000155#ifdef HAVE_ZLIB_H
156 z_stream *strm; /* Zlib stream object */
157 int usesGzip; /* "Content-Encoding: gzip" was detected */
158#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000159} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
160
161static int initialized = 0;
162static char *proxy = NULL; /* the proxy name if any */
163static int proxyPort; /* the proxy port if any */
164static unsigned int timeout = 60;/* the select() timeout in seconds */
165
Daniel Veillarda2351322004-06-27 12:08:10 +0000166static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
Daniel Veillardf012a642001-07-23 19:10:52 +0000167
Owen Taylor3473f882001-02-23 17:55:21 +0000168/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000169 * xmlHTTPErrMemory:
170 * @extra: extra informations
171 *
172 * Handle an out of memory condition
173 */
174static void
175xmlHTTPErrMemory(const char *extra)
176{
177 __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
178}
179
180/**
Owen Taylor3473f882001-02-23 17:55:21 +0000181 * A portability function
182 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000183static int socket_errno(void) {
Owen Taylor3473f882001-02-23 17:55:21 +0000184#ifdef _WINSOCKAPI_
185 return(WSAGetLastError());
186#else
187 return(errno);
188#endif
189}
190
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000191#ifdef SUPPORT_IP6
Daniel Veillard2db8c122003-07-08 12:16:59 +0000192static
193int have_ipv6(void) {
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100194 SOCKET s;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000195
196 s = socket (AF_INET6, SOCK_STREAM, 0);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100197 if (s != INVALID_SOCKET) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000198 close (s);
199 return (1);
200 }
201 return (0);
202}
203#endif
204
Owen Taylor3473f882001-02-23 17:55:21 +0000205/**
206 * xmlNanoHTTPInit:
207 *
208 * Initialize the HTTP protocol layer.
209 * Currently it just checks for proxy informations
210 */
211
212void
213xmlNanoHTTPInit(void) {
214 const char *env;
215#ifdef _WINSOCKAPI_
216 WSADATA wsaData;
217#endif
218
219 if (initialized)
220 return;
221
222#ifdef _WINSOCKAPI_
223 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
224 return;
225#endif
226
227 if (proxy == NULL) {
228 proxyPort = 80;
229 env = getenv("no_proxy");
Daniel Veillard29b17482004-08-16 00:39:03 +0000230 if (env && ((env[0] == '*') && (env[1] == 0)))
Owen Taylor3473f882001-02-23 17:55:21 +0000231 goto done;
232 env = getenv("http_proxy");
233 if (env != NULL) {
234 xmlNanoHTTPScanProxy(env);
235 goto done;
236 }
237 env = getenv("HTTP_PROXY");
238 if (env != NULL) {
239 xmlNanoHTTPScanProxy(env);
240 goto done;
241 }
242 }
243done:
244 initialized = 1;
245}
246
247/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000248 * xmlNanoHTTPCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +0000249 *
250 * Cleanup the HTTP protocol layer.
251 */
252
253void
254xmlNanoHTTPCleanup(void) {
Daniel Veillard744acff2005-07-12 15:09:53 +0000255 if (proxy != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000256 xmlFree(proxy);
Daniel Veillard744acff2005-07-12 15:09:53 +0000257 proxy = NULL;
258 }
Owen Taylor3473f882001-02-23 17:55:21 +0000259#ifdef _WINSOCKAPI_
260 if (initialized)
261 WSACleanup();
262#endif
263 initialized = 0;
264 return;
265}
266
267/**
Owen Taylor3473f882001-02-23 17:55:21 +0000268 * xmlNanoHTTPScanURL:
269 * @ctxt: an HTTP context
270 * @URL: The URL used to initialize the context
271 *
272 * (Re)Initialize an HTTP context by parsing the URL and finding
273 * the protocol host port and path it indicates.
274 */
275
276static void
277xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
William M. Brack015ccb22005-02-13 08:18:52 +0000278 xmlURIPtr uri;
279 /*
280 * Clear any existing data from the context
281 */
Owen Taylor3473f882001-02-23 17:55:21 +0000282 if (ctxt->protocol != NULL) {
283 xmlFree(ctxt->protocol);
284 ctxt->protocol = NULL;
285 }
286 if (ctxt->hostname != NULL) {
287 xmlFree(ctxt->hostname);
288 ctxt->hostname = NULL;
289 }
290 if (ctxt->path != NULL) {
291 xmlFree(ctxt->path);
292 ctxt->path = NULL;
293 }
Daniel Veillard351f2d62005-04-13 02:55:12 +0000294 if (ctxt->query != NULL) {
295 xmlFree(ctxt->query);
296 ctxt->query = NULL;
297 }
Owen Taylor3473f882001-02-23 17:55:21 +0000298 if (URL == NULL) return;
William M. Brack015ccb22005-02-13 08:18:52 +0000299
Daniel Veillard336a8e12005-08-07 10:46:19 +0000300 uri = xmlParseURIRaw(URL, 1);
William M. Brack015ccb22005-02-13 08:18:52 +0000301 if (uri == NULL)
302 return;
303
304 if ((uri->scheme == NULL) || (uri->server == NULL)) {
305 xmlFreeURI(uri);
306 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000307 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000308
William M. Brack015ccb22005-02-13 08:18:52 +0000309 ctxt->protocol = xmlMemStrdup(uri->scheme);
310 ctxt->hostname = xmlMemStrdup(uri->server);
311 if (uri->path != NULL)
312 ctxt->path = xmlMemStrdup(uri->path);
313 else
314 ctxt->path = xmlMemStrdup("/");
Daniel Veillard351f2d62005-04-13 02:55:12 +0000315 if (uri->query != NULL)
316 ctxt->query = xmlMemStrdup(uri->query);
William M. Brack015ccb22005-02-13 08:18:52 +0000317 if (uri->port != 0)
318 ctxt->port = uri->port;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000319
William M. Brack015ccb22005-02-13 08:18:52 +0000320 xmlFreeURI(uri);
Owen Taylor3473f882001-02-23 17:55:21 +0000321}
322
323/**
324 * xmlNanoHTTPScanProxy:
325 * @URL: The proxy URL used to initialize the proxy context
326 *
327 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
328 * the protocol host port it indicates.
329 * Should be like http://myproxy/ or http://myproxy:3128/
330 * A NULL URL cleans up proxy informations.
331 */
332
333void
334xmlNanoHTTPScanProxy(const char *URL) {
William M. Brack015ccb22005-02-13 08:18:52 +0000335 xmlURIPtr uri;
Owen Taylor3473f882001-02-23 17:55:21 +0000336
337 if (proxy != NULL) {
338 xmlFree(proxy);
339 proxy = NULL;
340 }
William M. Brack015ccb22005-02-13 08:18:52 +0000341 proxyPort = 0;
342
Owen Taylor3473f882001-02-23 17:55:21 +0000343#ifdef DEBUG_HTTP
344 if (URL == NULL)
345 xmlGenericError(xmlGenericErrorContext,
346 "Removing HTTP proxy info\n");
347 else
348 xmlGenericError(xmlGenericErrorContext,
349 "Using HTTP proxy %s\n", URL);
350#endif
351 if (URL == NULL) return;
William M. Brack015ccb22005-02-13 08:18:52 +0000352
Daniel Veillard336a8e12005-08-07 10:46:19 +0000353 uri = xmlParseURIRaw(URL, 1);
William M. Brack015ccb22005-02-13 08:18:52 +0000354 if ((uri == NULL) || (uri->scheme == NULL) ||
355 (strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
356 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
357 if (uri != NULL)
358 xmlFreeURI(uri);
359 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000360 }
William M. Brack015ccb22005-02-13 08:18:52 +0000361
362 proxy = xmlMemStrdup(uri->server);
363 if (uri->port != 0)
364 proxyPort = uri->port;
Owen Taylor3473f882001-02-23 17:55:21 +0000365
William M. Brack015ccb22005-02-13 08:18:52 +0000366 xmlFreeURI(uri);
Owen Taylor3473f882001-02-23 17:55:21 +0000367}
368
369/**
370 * xmlNanoHTTPNewCtxt:
371 * @URL: The URL used to initialize the context
372 *
373 * Allocate and initialize a new HTTP context.
374 *
375 * Returns an HTTP context or NULL in case of error.
376 */
377
378static xmlNanoHTTPCtxtPtr
379xmlNanoHTTPNewCtxt(const char *URL) {
380 xmlNanoHTTPCtxtPtr ret;
381
382 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000383 if (ret == NULL) {
384 xmlHTTPErrMemory("allocating context");
385 return(NULL);
386 }
Owen Taylor3473f882001-02-23 17:55:21 +0000387
388 memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
389 ret->port = 80;
390 ret->returnValue = 0;
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100391 ret->fd = INVALID_SOCKET;
Daniel Veillardf012a642001-07-23 19:10:52 +0000392 ret->ContentLength = -1;
Owen Taylor3473f882001-02-23 17:55:21 +0000393
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000394 xmlNanoHTTPScanURL(ret, URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000395
396 return(ret);
397}
398
399/**
400 * xmlNanoHTTPFreeCtxt:
401 * @ctxt: an HTTP context
402 *
403 * Frees the context after closing the connection.
404 */
405
406static void
407xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
408 if (ctxt == NULL) return;
409 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
410 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
411 if (ctxt->path != NULL) xmlFree(ctxt->path);
Daniel Veillard351f2d62005-04-13 02:55:12 +0000412 if (ctxt->query != NULL) xmlFree(ctxt->query);
Owen Taylor3473f882001-02-23 17:55:21 +0000413 if (ctxt->out != NULL) xmlFree(ctxt->out);
414 if (ctxt->in != NULL) xmlFree(ctxt->in);
415 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
Daniel Veillard847332a2003-10-18 11:29:40 +0000416 if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
Daniel Veillarda840b692003-10-19 13:35:37 +0000417 if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
Owen Taylor3473f882001-02-23 17:55:21 +0000418 if (ctxt->location != NULL) xmlFree(ctxt->location);
419 if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000420#ifdef HAVE_ZLIB_H
421 if (ctxt->strm != NULL) {
422 inflateEnd(ctxt->strm);
423 xmlFree(ctxt->strm);
424 }
425#endif
426
Owen Taylor3473f882001-02-23 17:55:21 +0000427 ctxt->state = XML_NANO_HTTP_NONE;
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100428 if (ctxt->fd != INVALID_SOCKET) closesocket(ctxt->fd);
429 ctxt->fd = INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000430 xmlFree(ctxt);
431}
432
433/**
434 * xmlNanoHTTPSend:
435 * @ctxt: an HTTP context
436 *
437 * Send the input needed to initiate the processing on the server side
Daniel Veillardf012a642001-07-23 19:10:52 +0000438 * Returns number of bytes sent or -1 on error.
Owen Taylor3473f882001-02-23 17:55:21 +0000439 */
440
Daniel Veillardf012a642001-07-23 19:10:52 +0000441static int
Raphael Prevost48b60c32009-08-23 13:11:01 +0200442xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
443{
444 int total_sent = 0;
445#ifdef HAVE_POLL_H
446 struct pollfd p;
447#else
448 struct timeval tv;
449 fd_set wfd;
450#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000451
Raphael Prevost48b60c32009-08-23 13:11:01 +0200452 if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000453 while (total_sent < outlen) {
454 int nsent = send(ctxt->fd, xmt_ptr + total_sent,
Raphael Prevost48b60c32009-08-23 13:11:01 +0200455 outlen - total_sent, 0);
456
457 if (nsent > 0)
Owen Taylor3473f882001-02-23 17:55:21 +0000458 total_sent += nsent;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200459 else if ((nsent == -1) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000460#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200461 (socket_errno() != EAGAIN) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000462#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200463 (socket_errno() != EWOULDBLOCK)) {
464 __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
465 if (total_sent == 0)
466 total_sent = -1;
467 break;
468 } else {
469 /*
470 * No data sent
471 * Since non-blocking sockets are used, wait for
472 * socket to be writable or default timeout prior
473 * to retrying.
474 */
475#ifndef HAVE_POLL_H
spadixd29a5c82009-10-19 14:03:25 +0200476#ifndef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200477 if (ctxt->fd > FD_SETSIZE)
478 return -1;
spadixd29a5c82009-10-19 14:03:25 +0200479#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000480
Raphael Prevost48b60c32009-08-23 13:11:01 +0200481 tv.tv_sec = timeout;
482 tv.tv_usec = 0;
483 FD_ZERO(&wfd);
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000484#ifdef _MSC_VER
485#pragma warning(push)
486#pragma warning(disable: 4018)
487#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200488 FD_SET(ctxt->fd, &wfd);
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000489#ifdef _MSC_VER
490#pragma warning(pop)
491#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200492 (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
493#else
494 p.fd = ctxt->fd;
495 p.events = POLLOUT;
496 (void) poll(&p, 1, timeout * 1000);
497#endif /* !HAVE_POLL_H */
498 }
499 }
Owen Taylor3473f882001-02-23 17:55:21 +0000500 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000501
502 return total_sent;
Owen Taylor3473f882001-02-23 17:55:21 +0000503}
504
505/**
506 * xmlNanoHTTPRecv:
507 * @ctxt: an HTTP context
508 *
509 * Read information coming from the HTTP connection.
510 * This is a blocking call (but it blocks in select(), not read()).
511 *
512 * Returns the number of byte read or -1 in case of error.
513 */
514
515static int
Raphael Prevost48b60c32009-08-23 13:11:01 +0200516xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
517{
518#ifdef HAVE_POLL_H
519 struct pollfd p;
520#else
Owen Taylor3473f882001-02-23 17:55:21 +0000521 fd_set rfd;
522 struct timeval tv;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200523#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000524
525
526 while (ctxt->state & XML_NANO_HTTP_READ) {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200527 if (ctxt->in == NULL) {
528 ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
529 if (ctxt->in == NULL) {
530 xmlHTTPErrMemory("allocating input");
531 ctxt->last = -1;
532 return (-1);
533 }
534 ctxt->inlen = 65000;
535 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
536 }
537 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
538 int delta = ctxt->inrptr - ctxt->in;
539 int len = ctxt->inptr - ctxt->inrptr;
Owen Taylor3473f882001-02-23 17:55:21 +0000540
Raphael Prevost48b60c32009-08-23 13:11:01 +0200541 memmove(ctxt->in, ctxt->inrptr, len);
542 ctxt->inrptr -= delta;
543 ctxt->content -= delta;
544 ctxt->inptr -= delta;
545 }
546 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
547 int d_inptr = ctxt->inptr - ctxt->in;
548 int d_content = ctxt->content - ctxt->in;
549 int d_inrptr = ctxt->inrptr - ctxt->in;
550 char *tmp_ptr = ctxt->in;
551
552 ctxt->inlen *= 2;
Daniel Veillardf012a642001-07-23 19:10:52 +0000553 ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
Raphael Prevost48b60c32009-08-23 13:11:01 +0200554 if (ctxt->in == NULL) {
555 xmlHTTPErrMemory("allocating input buffer");
556 xmlFree(tmp_ptr);
557 ctxt->last = -1;
558 return (-1);
559 }
Owen Taylor3473f882001-02-23 17:55:21 +0000560 ctxt->inptr = ctxt->in + d_inptr;
561 ctxt->content = ctxt->in + d_content;
562 ctxt->inrptr = ctxt->in + d_inrptr;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200563 }
564 ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
565 if (ctxt->last > 0) {
566 ctxt->inptr += ctxt->last;
567 return (ctxt->last);
568 }
569 if (ctxt->last == 0) {
570 return (0);
571 }
572 if (ctxt->last == -1) {
573 switch (socket_errno()) {
574 case EINPROGRESS:
575 case EWOULDBLOCK:
Owen Taylor3473f882001-02-23 17:55:21 +0000576#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200577 case EAGAIN:
Owen Taylor3473f882001-02-23 17:55:21 +0000578#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200579 break;
Daniel Veillardf012a642001-07-23 19:10:52 +0000580
Raphael Prevost48b60c32009-08-23 13:11:01 +0200581 case ECONNRESET:
582 case ESHUTDOWN:
583 return (0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000584
Raphael Prevost48b60c32009-08-23 13:11:01 +0200585 default:
586 __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
587 return (-1);
588 }
589 }
590#ifdef HAVE_POLL_H
591 p.fd = ctxt->fd;
592 p.events = POLLIN;
593 if ((poll(&p, 1, timeout * 1000) < 1)
594#if defined(EINTR)
595 && (errno != EINTR)
596#endif
597 )
598 return (0);
599#else /* !HAVE_POLL_H */
spadixd29a5c82009-10-19 14:03:25 +0200600#ifndef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200601 if (ctxt->fd > FD_SETSIZE)
602 return 0;
spadixd29a5c82009-10-19 14:03:25 +0200603#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000604
Raphael Prevost48b60c32009-08-23 13:11:01 +0200605 tv.tv_sec = timeout;
606 tv.tv_usec = 0;
607 FD_ZERO(&rfd);
608
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000609#ifdef _MSC_VER
610#pragma warning(push)
611#pragma warning(disable: 4018)
612#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200613
614 FD_SET(ctxt->fd, &rfd);
615
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000616#ifdef _MSC_VER
617#pragma warning(pop)
618#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200619
620 if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
Daniel Veillard50f34372001-08-03 12:06:36 +0000621#if defined(EINTR)
Raphael Prevost48b60c32009-08-23 13:11:01 +0200622 && (errno != EINTR)
Daniel Veillard50f34372001-08-03 12:06:36 +0000623#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200624 )
625 return (0);
626#endif /* !HAVE_POLL_H */
Owen Taylor3473f882001-02-23 17:55:21 +0000627 }
Raphael Prevost48b60c32009-08-23 13:11:01 +0200628 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +0000629}
630
631/**
632 * xmlNanoHTTPReadLine:
633 * @ctxt: an HTTP context
634 *
635 * Read one line in the HTTP server output, usually for extracting
636 * the HTTP protocol informations from the answer header.
637 *
638 * Returns a newly allocated string with a copy of the line, or NULL
639 * which indicate the end of the input.
640 */
641
642static char *
643xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
644 char buf[4096];
645 char *bp = buf;
Daniel Veillardf012a642001-07-23 19:10:52 +0000646 int rc;
Owen Taylor3473f882001-02-23 17:55:21 +0000647
648 while (bp - buf < 4095) {
649 if (ctxt->inrptr == ctxt->inptr) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000650 if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000651 if (bp == buf)
652 return(NULL);
653 else
654 *bp = 0;
655 return(xmlMemStrdup(buf));
656 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000657 else if ( rc == -1 ) {
658 return ( NULL );
659 }
Owen Taylor3473f882001-02-23 17:55:21 +0000660 }
661 *bp = *ctxt->inrptr++;
662 if (*bp == '\n') {
663 *bp = 0;
664 return(xmlMemStrdup(buf));
665 }
666 if (*bp != '\r')
667 bp++;
668 }
669 buf[4095] = 0;
670 return(xmlMemStrdup(buf));
671}
672
673
674/**
675 * xmlNanoHTTPScanAnswer:
676 * @ctxt: an HTTP context
677 * @line: an HTTP header line
678 *
679 * Try to extract useful informations from the server answer.
680 * We currently parse and process:
681 * - The HTTP revision/ return code
Daniel Veillarda840b692003-10-19 13:35:37 +0000682 * - The Content-Type, Mime-Type and charset used
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000683 * - The Location for redirect processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000684 *
685 * Returns -1 in case of failure, the file descriptor number otherwise
686 */
687
688static void
689xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
690 const char *cur = line;
691
692 if (line == NULL) return;
693
694 if (!strncmp(line, "HTTP/", 5)) {
695 int version = 0;
696 int ret = 0;
697
698 cur += 5;
699 while ((*cur >= '0') && (*cur <= '9')) {
700 version *= 10;
701 version += *cur - '0';
702 cur++;
703 }
704 if (*cur == '.') {
705 cur++;
706 if ((*cur >= '0') && (*cur <= '9')) {
707 version *= 10;
708 version += *cur - '0';
709 cur++;
710 }
711 while ((*cur >= '0') && (*cur <= '9'))
712 cur++;
713 } else
714 version *= 10;
715 if ((*cur != ' ') && (*cur != '\t')) return;
716 while ((*cur == ' ') || (*cur == '\t')) cur++;
717 if ((*cur < '0') || (*cur > '9')) return;
718 while ((*cur >= '0') && (*cur <= '9')) {
719 ret *= 10;
720 ret += *cur - '0';
721 cur++;
722 }
723 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
724 ctxt->returnValue = ret;
Daniel Veillard13cee4e2009-09-05 14:52:55 +0200725 ctxt->version = version;
Owen Taylor3473f882001-02-23 17:55:21 +0000726 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
Daniel Veillarda840b692003-10-19 13:35:37 +0000727 const xmlChar *charset, *last, *mime;
Owen Taylor3473f882001-02-23 17:55:21 +0000728 cur += 13;
729 while ((*cur == ' ') || (*cur == '\t')) cur++;
730 if (ctxt->contentType != NULL)
731 xmlFree(ctxt->contentType);
732 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillarda840b692003-10-19 13:35:37 +0000733 mime = (const xmlChar *) cur;
734 last = mime;
735 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
736 (*last != ';') && (*last != ','))
737 last++;
738 if (ctxt->mimeType != NULL)
739 xmlFree(ctxt->mimeType);
740 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
741 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
742 if (charset != NULL) {
743 charset += 8;
744 last = charset;
745 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
746 (*last != ';') && (*last != ','))
747 last++;
748 if (ctxt->encoding != NULL)
749 xmlFree(ctxt->encoding);
750 ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
751 }
Owen Taylor3473f882001-02-23 17:55:21 +0000752 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
Daniel Veillarda840b692003-10-19 13:35:37 +0000753 const xmlChar *charset, *last, *mime;
Owen Taylor3473f882001-02-23 17:55:21 +0000754 cur += 12;
755 if (ctxt->contentType != NULL) return;
756 while ((*cur == ' ') || (*cur == '\t')) cur++;
757 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillarda840b692003-10-19 13:35:37 +0000758 mime = (const xmlChar *) cur;
759 last = mime;
760 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
761 (*last != ';') && (*last != ','))
762 last++;
763 if (ctxt->mimeType != NULL)
764 xmlFree(ctxt->mimeType);
765 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
766 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
767 if (charset != NULL) {
768 charset += 8;
769 last = charset;
770 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
771 (*last != ';') && (*last != ','))
772 last++;
773 if (ctxt->encoding != NULL)
774 xmlFree(ctxt->encoding);
775 ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
776 }
Owen Taylor3473f882001-02-23 17:55:21 +0000777 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
778 cur += 9;
779 while ((*cur == ' ') || (*cur == '\t')) cur++;
780 if (ctxt->location != NULL)
781 xmlFree(ctxt->location);
William M. Brack7e29c0a2004-04-02 09:07:22 +0000782 if (*cur == '/') {
783 xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
784 xmlChar *tmp_loc =
785 xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
786 ctxt->location =
787 (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
788 } else {
789 ctxt->location = xmlMemStrdup(cur);
790 }
Owen Taylor3473f882001-02-23 17:55:21 +0000791 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
792 cur += 17;
793 while ((*cur == ' ') || (*cur == '\t')) cur++;
794 if (ctxt->authHeader != NULL)
795 xmlFree(ctxt->authHeader);
796 ctxt->authHeader = xmlMemStrdup(cur);
797 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
798 cur += 19;
799 while ((*cur == ' ') || (*cur == '\t')) cur++;
800 if (ctxt->authHeader != NULL)
801 xmlFree(ctxt->authHeader);
802 ctxt->authHeader = xmlMemStrdup(cur);
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000803#ifdef HAVE_ZLIB_H
804 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
805 cur += 17;
806 while ((*cur == ' ') || (*cur == '\t')) cur++;
807 if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
808 ctxt->usesGzip = 1;
809
810 ctxt->strm = xmlMalloc(sizeof(z_stream));
811
812 if (ctxt->strm != NULL) {
813 ctxt->strm->zalloc = Z_NULL;
814 ctxt->strm->zfree = Z_NULL;
815 ctxt->strm->opaque = Z_NULL;
816 ctxt->strm->avail_in = 0;
817 ctxt->strm->next_in = Z_NULL;
818
819 inflateInit2( ctxt->strm, 31 );
820 }
821 }
822#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000823 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
824 cur += 15;
825 ctxt->ContentLength = strtol( cur, NULL, 10 );
Owen Taylor3473f882001-02-23 17:55:21 +0000826 }
827}
828
829/**
830 * xmlNanoHTTPConnectAttempt:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000831 * @addr: a socket address structure
Owen Taylor3473f882001-02-23 17:55:21 +0000832 *
833 * Attempt a connection to the given IP:port endpoint. It forces
834 * non-blocking semantic on the socket, and allow 60 seconds for
835 * the host to answer.
836 *
837 * Returns -1 in case of failure, the file descriptor number otherwise
838 */
839
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100840static SOCKET
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000841xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
Owen Taylor3473f882001-02-23 17:55:21 +0000842{
Raphael Prevost48b60c32009-08-23 13:11:01 +0200843#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +0000844 fd_set wfd;
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000845#ifdef _WINSOCKAPI_
846 fd_set xfd;
847#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000848 struct timeval tv;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200849#else /* !HAVE_POLL_H */
850 struct pollfd p;
851#endif /* !HAVE_POLL_H */
Owen Taylor3473f882001-02-23 17:55:21 +0000852 int status;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200853
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000854 int addrlen;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200855
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000856 SOCKET s;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200857
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000858#ifdef SUPPORT_IP6
859 if (addr->sa_family == AF_INET6) {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200860 s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
861 addrlen = sizeof(struct sockaddr_in6);
862 } else
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000863#endif
864 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200865 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
866 addrlen = sizeof(struct sockaddr_in);
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000867 }
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100868 if (s == INVALID_SOCKET) {
Owen Taylor3473f882001-02-23 17:55:21 +0000869#ifdef DEBUG_HTTP
Raphael Prevost48b60c32009-08-23 13:11:01 +0200870 perror("socket");
Owen Taylor3473f882001-02-23 17:55:21 +0000871#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200872 __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100873 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000874 }
Owen Taylor3473f882001-02-23 17:55:21 +0000875#ifdef _WINSOCKAPI_
876 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200877 u_long one = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000878
Raphael Prevost48b60c32009-08-23 13:11:01 +0200879 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000880 }
881#else /* _WINSOCKAPI_ */
882#if defined(VMS)
883 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200884 int enable = 1;
885
886 status = ioctl(s, FIONBIO, &enable);
Owen Taylor3473f882001-02-23 17:55:21 +0000887 }
888#else /* VMS */
Daniel Veillardcba68392008-08-29 12:43:40 +0000889#if defined(__BEOS__) && !defined(__HAIKU__)
Raphael Prevost48b60c32009-08-23 13:11:01 +0200890 {
891 bool noblock = true;
892
893 status =
894 setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
895 sizeof(noblock));
896 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000897#else /* __BEOS__ */
Owen Taylor3473f882001-02-23 17:55:21 +0000898 if ((status = fcntl(s, F_GETFL, 0)) != -1) {
899#ifdef O_NONBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200900 status |= O_NONBLOCK;
Owen Taylor3473f882001-02-23 17:55:21 +0000901#else /* O_NONBLOCK */
902#ifdef F_NDELAY
Raphael Prevost48b60c32009-08-23 13:11:01 +0200903 status |= F_NDELAY;
Owen Taylor3473f882001-02-23 17:55:21 +0000904#endif /* F_NDELAY */
905#endif /* !O_NONBLOCK */
Raphael Prevost48b60c32009-08-23 13:11:01 +0200906 status = fcntl(s, F_SETFL, status);
Owen Taylor3473f882001-02-23 17:55:21 +0000907 }
908 if (status < 0) {
909#ifdef DEBUG_HTTP
Raphael Prevost48b60c32009-08-23 13:11:01 +0200910 perror("nonblocking");
Owen Taylor3473f882001-02-23 17:55:21 +0000911#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200912 __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
913 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100914 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000915 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000916#endif /* !__BEOS__ */
Owen Taylor3473f882001-02-23 17:55:21 +0000917#endif /* !VMS */
918#endif /* !_WINSOCKAPI_ */
919
Raphael Prevost48b60c32009-08-23 13:11:01 +0200920 if (connect(s, addr, addrlen) == -1) {
921 switch (socket_errno()) {
922 case EINPROGRESS:
923 case EWOULDBLOCK:
924 break;
925 default:
926 __xmlIOErr(XML_FROM_HTTP, 0,
927 "error connecting to HTTP server");
928 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100929 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200930 }
931 }
932#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +0000933 tv.tv_sec = timeout;
934 tv.tv_usec = 0;
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000935
936#ifdef _MSC_VER
937#pragma warning(push)
938#pragma warning(disable: 4018)
939#endif
spadixd29a5c82009-10-19 14:03:25 +0200940#ifndef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200941 if (s > FD_SETSIZE)
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100942 return INVALID_SOCKET;
spadixd29a5c82009-10-19 14:03:25 +0200943#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000944 FD_ZERO(&wfd);
945 FD_SET(s, &wfd);
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000946
Raphael Prevost48b60c32009-08-23 13:11:01 +0200947#ifdef _WINSOCKAPI_
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000948 FD_ZERO(&xfd);
949 FD_SET(s, &xfd);
Raphael Prevost48b60c32009-08-23 13:11:01 +0200950
951 switch (select(s + 1, NULL, &wfd, &xfd, &tv))
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000952#else
Raphael Prevost48b60c32009-08-23 13:11:01 +0200953 switch (select(s + 1, NULL, &wfd, NULL, &tv))
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000954#endif
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000955#ifdef _MSC_VER
956#pragma warning(pop)
957#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200958
959#else /* !HAVE_POLL_H */
960 p.fd = s;
961 p.events = POLLOUT;
962 switch (poll(&p, 1, timeout * 1000))
963#endif /* !HAVE_POLL_H */
964
Owen Taylor3473f882001-02-23 17:55:21 +0000965 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200966 case 0:
967 /* Time out */
968 __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
969 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100970 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200971 case -1:
972 /* Ermm.. ?? */
973 __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
974 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100975 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000976 }
977
Raphael Prevost48b60c32009-08-23 13:11:01 +0200978#ifndef HAVE_POLL_H
979 if (FD_ISSET(s, &wfd)
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000980#ifdef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200981 || FD_ISSET(s, &xfd)
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000982#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200983 )
984#else /* !HAVE_POLL_H */
985 if (p.revents == POLLOUT)
986#endif /* !HAVE_POLL_H */
987 {
988 XML_SOCKLEN_T len;
989
990 len = sizeof(status);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000991#ifdef SO_ERROR
Raphael Prevost48b60c32009-08-23 13:11:01 +0200992 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
993 0) {
994 /* Solaris error code */
995 __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100996 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200997 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000998#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200999 if (status) {
1000 __xmlIOErr(XML_FROM_HTTP, 0,
1001 "Error connecting to remote host");
1002 closesocket(s);
1003 errno = status;
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001004 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +02001005 }
Owen Taylor3473f882001-02-23 17:55:21 +00001006 } else {
Raphael Prevost48b60c32009-08-23 13:11:01 +02001007 /* pbm */
1008 __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
1009 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001010 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +00001011 }
Raphael Prevost48b60c32009-08-23 13:11:01 +02001012
1013 return (s);
Owen Taylor3473f882001-02-23 17:55:21 +00001014}
Raphael Prevost48b60c32009-08-23 13:11:01 +02001015
Owen Taylor3473f882001-02-23 17:55:21 +00001016/**
1017 * xmlNanoHTTPConnectHost:
1018 * @host: the host name
1019 * @port: the port number
1020 *
1021 * Attempt a connection to the given host:port endpoint. It tries
1022 * the multiple IP provided by the DNS if available.
1023 *
1024 * Returns -1 in case of failure, the file descriptor number otherwise
1025 */
1026
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001027static SOCKET
Owen Taylor3473f882001-02-23 17:55:21 +00001028xmlNanoHTTPConnectHost(const char *host, int port)
1029{
1030 struct hostent *h;
Daniel Veillard2db8c122003-07-08 12:16:59 +00001031 struct sockaddr *addr = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001032 struct in_addr ia;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001033 struct sockaddr_in sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001034
Owen Taylor3473f882001-02-23 17:55:21 +00001035#ifdef SUPPORT_IP6
1036 struct in6_addr ia6;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001037 struct sockaddr_in6 sockin6;
Owen Taylor3473f882001-02-23 17:55:21 +00001038#endif
1039 int i;
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001040 SOCKET s;
Daniel Veillard5c396542002-03-15 07:57:50 +00001041
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001042 memset (&sockin, 0, sizeof(sockin));
1043#ifdef SUPPORT_IP6
1044 memset (&sockin6, 0, sizeof(sockin6));
Rob Richardscb418de2005-10-13 23:12:42 +00001045#endif
1046
1047#if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001048 if (have_ipv6 ())
Daniel Veillard560c2a42003-07-06 21:13:49 +00001049 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001050 if (!(_res.options & RES_INIT))
1051 res_init();
1052 _res.options |= RES_USE_INET6;
1053 }
Rob Richardscb418de2005-10-13 23:12:42 +00001054#endif
1055
1056#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1057 if (have_ipv6 ())
1058#endif
1059#if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
Daniel Veillard560c2a42003-07-06 21:13:49 +00001060 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001061 int status;
1062 struct addrinfo hints, *res, *result;
1063
1064 result = NULL;
1065 memset (&hints, 0,sizeof(hints));
1066 hints.ai_socktype = SOCK_STREAM;
1067
1068 status = getaddrinfo (host, NULL, &hints, &result);
1069 if (status) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001070 __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001071 return INVALID_SOCKET;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001072 }
1073
1074 for (res = result; res; res = res->ai_next) {
Rob Richardscb418de2005-10-13 23:12:42 +00001075 if (res->ai_family == AF_INET) {
1076 if (res->ai_addrlen > sizeof(sockin)) {
1077 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001078 freeaddrinfo (result);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001079 return INVALID_SOCKET;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001080 }
Rob Richardscb418de2005-10-13 23:12:42 +00001081 memcpy (&sockin, res->ai_addr, res->ai_addrlen);
1082 sockin.sin_port = htons (port);
1083 addr = (struct sockaddr *)&sockin;
1084#ifdef SUPPORT_IP6
1085 } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
1086 if (res->ai_addrlen > sizeof(sockin6)) {
1087 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1088 freeaddrinfo (result);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001089 return INVALID_SOCKET;
Rob Richardscb418de2005-10-13 23:12:42 +00001090 }
1091 memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
1092 sockin6.sin6_port = htons (port);
1093 addr = (struct sockaddr *)&sockin6;
1094#endif
1095 } else
1096 continue; /* for */
1097
1098 s = xmlNanoHTTPConnectAttempt (addr);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001099 if (s != INVALID_SOCKET) {
Rob Richardscb418de2005-10-13 23:12:42 +00001100 freeaddrinfo (result);
1101 return (s);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001102 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001103 }
Rob Richardscb418de2005-10-13 23:12:42 +00001104
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001105 if (result)
1106 freeaddrinfo (result);
Rob Richardscb418de2005-10-13 23:12:42 +00001107 }
Owen Taylor3473f882001-02-23 17:55:21 +00001108#endif
Rob Richardscb418de2005-10-13 23:12:42 +00001109#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1110 else
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001111#endif
Rob Richardscb418de2005-10-13 23:12:42 +00001112#if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
1113 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001114 h = gethostbyname (host);
1115 if (h == NULL) {
Daniel Veillard56b2db72002-03-25 16:35:28 +00001116
1117/*
1118 * Okay, I got fed up by the non-portability of this error message
1119 * extraction code. it work on Linux, if it work on your platform
1120 * and one want to enable it, send me the defined(foobar) needed
1121 */
1122#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001123 const char *h_err_txt = "";
Daniel Veillardf012a642001-07-23 19:10:52 +00001124
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001125 switch (h_errno) {
1126 case HOST_NOT_FOUND:
1127 h_err_txt = "Authoritive host not found";
1128 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001129
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001130 case TRY_AGAIN:
1131 h_err_txt =
1132 "Non-authoritive host not found or server failure.";
1133 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001134
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001135 case NO_RECOVERY:
1136 h_err_txt =
1137 "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
1138 break;
Daniel Veillard5c396542002-03-15 07:57:50 +00001139
Daniel Veillardd95b6892012-04-02 17:48:53 +08001140#ifdef NO_ADDRESS
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001141 case NO_ADDRESS:
1142 h_err_txt =
1143 "Valid name, no data record of requested type.";
1144 break;
Daniel Veillardd95b6892012-04-02 17:48:53 +08001145#endif
Daniel Veillard5c396542002-03-15 07:57:50 +00001146
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001147 default:
1148 h_err_txt = "No error text defined.";
1149 break;
1150 }
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001151 __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
Daniel Veillard5c396542002-03-15 07:57:50 +00001152#else
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001153 __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
Owen Taylor3473f882001-02-23 17:55:21 +00001154#endif
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001155 return INVALID_SOCKET;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001156 }
Daniel Veillard5c396542002-03-15 07:57:50 +00001157
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001158 for (i = 0; h->h_addr_list[i]; i++) {
1159 if (h->h_addrtype == AF_INET) {
1160 /* A records (IPv4) */
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001161 if ((unsigned int) h->h_length > sizeof(ia)) {
1162 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001163 return INVALID_SOCKET;
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001164 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001165 memcpy (&ia, h->h_addr_list[i], h->h_length);
1166 sockin.sin_family = h->h_addrtype;
1167 sockin.sin_addr = ia;
Daniel Veillardac17e592012-04-02 15:45:13 +08001168 sockin.sin_port = (unsigned short)htons ((unsigned short)port);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001169 addr = (struct sockaddr *) &sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001170#ifdef SUPPORT_IP6
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001171 } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
1172 /* AAAA records (IPv6) */
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001173 if ((unsigned int) h->h_length > sizeof(ia6)) {
1174 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001175 return INVALID_SOCKET;
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001176 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001177 memcpy (&ia6, h->h_addr_list[i], h->h_length);
1178 sockin6.sin6_family = h->h_addrtype;
1179 sockin6.sin6_addr = ia6;
1180 sockin6.sin6_port = htons (port);
1181 addr = (struct sockaddr *) &sockin6;
Daniel Veillard5c396542002-03-15 07:57:50 +00001182#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001183 } else
1184 break; /* for */
Daniel Veillard5c396542002-03-15 07:57:50 +00001185
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001186 s = xmlNanoHTTPConnectAttempt (addr);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001187 if (s != INVALID_SOCKET)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001188 return (s);
1189 }
Owen Taylor3473f882001-02-23 17:55:21 +00001190 }
Rob Richardscb418de2005-10-13 23:12:42 +00001191#endif
1192
Owen Taylor3473f882001-02-23 17:55:21 +00001193#ifdef DEBUG_HTTP
1194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard5c396542002-03-15 07:57:50 +00001195 "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",
1196 host);
Owen Taylor3473f882001-02-23 17:55:21 +00001197#endif
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001198 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +00001199}
1200
1201
1202/**
1203 * xmlNanoHTTPOpen:
1204 * @URL: The URL to load
1205 * @contentType: if available the Content-Type information will be
1206 * returned at that location
1207 *
1208 * This function try to open a connection to the indicated resource
1209 * via HTTP GET.
1210 *
1211 * Returns NULL in case of failure, otherwise a request handler.
1212 * The contentType, if provided must be freed by the caller
1213 */
1214
1215void*
1216xmlNanoHTTPOpen(const char *URL, char **contentType) {
1217 if (contentType != NULL) *contentType = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001218 return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
Daniel Veillard9403a042001-05-28 11:00:53 +00001219}
1220
1221/**
1222 * xmlNanoHTTPOpenRedir:
1223 * @URL: The URL to load
1224 * @contentType: if available the Content-Type information will be
1225 * returned at that location
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001226 * @redir: if available the redirected URL will be returned
Daniel Veillard9403a042001-05-28 11:00:53 +00001227 *
1228 * This function try to open a connection to the indicated resource
1229 * via HTTP GET.
1230 *
1231 * Returns NULL in case of failure, otherwise a request handler.
1232 * The contentType, if provided must be freed by the caller
1233 */
1234
1235void*
1236xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
1237 if (contentType != NULL) *contentType = NULL;
1238 if (redir != NULL) *redir = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001239 return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
Owen Taylor3473f882001-02-23 17:55:21 +00001240}
1241
1242/**
1243 * xmlNanoHTTPRead:
1244 * @ctx: the HTTP context
1245 * @dest: a buffer
1246 * @len: the buffer length
1247 *
1248 * This function tries to read @len bytes from the existing HTTP connection
1249 * and saves them in @dest. This is a blocking call.
1250 *
1251 * Returns the number of byte read. 0 is an indication of an end of connection.
1252 * -1 indicates a parameter error.
1253 */
1254int
1255xmlNanoHTTPRead(void *ctx, void *dest, int len) {
1256 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001257#ifdef HAVE_ZLIB_H
1258 int bytes_read = 0;
1259 int orig_avail_in;
1260 int z_ret;
1261#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001262
1263 if (ctx == NULL) return(-1);
1264 if (dest == NULL) return(-1);
1265 if (len <= 0) return(0);
1266
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001267#ifdef HAVE_ZLIB_H
1268 if (ctxt->usesGzip == 1) {
1269 if (ctxt->strm == NULL) return(0);
1270
1271 ctxt->strm->next_out = dest;
1272 ctxt->strm->avail_out = len;
William M. Bracke8827652007-05-16 05:19:13 +00001273 ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001274
William M. Bracke8827652007-05-16 05:19:13 +00001275 while (ctxt->strm->avail_out > 0 &&
1276 (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
William M. Brackd2f682a2007-05-15 19:42:08 +00001277 orig_avail_in = ctxt->strm->avail_in =
1278 ctxt->inptr - ctxt->inrptr - bytes_read;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001279 ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
1280
1281 z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
1282 bytes_read += orig_avail_in - ctxt->strm->avail_in;
1283
1284 if (z_ret != Z_OK) break;
William M. Brackd2f682a2007-05-15 19:42:08 +00001285 }
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001286
1287 ctxt->inrptr += bytes_read;
1288 return(len - ctxt->strm->avail_out);
1289 }
1290#endif
1291
Owen Taylor3473f882001-02-23 17:55:21 +00001292 while (ctxt->inptr - ctxt->inrptr < len) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001293 if (xmlNanoHTTPRecv(ctxt) <= 0) break;
Owen Taylor3473f882001-02-23 17:55:21 +00001294 }
1295 if (ctxt->inptr - ctxt->inrptr < len)
1296 len = ctxt->inptr - ctxt->inrptr;
1297 memcpy(dest, ctxt->inrptr, len);
1298 ctxt->inrptr += len;
1299 return(len);
1300}
1301
1302/**
1303 * xmlNanoHTTPClose:
1304 * @ctx: the HTTP context
1305 *
1306 * This function closes an HTTP context, it ends up the connection and
1307 * free all data related to it.
1308 */
1309void
1310xmlNanoHTTPClose(void *ctx) {
1311 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1312
1313 if (ctx == NULL) return;
1314
1315 xmlNanoHTTPFreeCtxt(ctxt);
1316}
1317
1318/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001319 * xmlNanoHTTPMethodRedir:
Owen Taylor3473f882001-02-23 17:55:21 +00001320 * @URL: The URL to load
1321 * @method: the HTTP method to use
1322 * @input: the input string if any
1323 * @contentType: the Content-Type information IN and OUT
Daniel Veillard9403a042001-05-28 11:00:53 +00001324 * @redir: the redirected URL OUT
Owen Taylor3473f882001-02-23 17:55:21 +00001325 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001326 * @ilen: input length
Owen Taylor3473f882001-02-23 17:55:21 +00001327 *
1328 * This function try to open a connection to the indicated resource
1329 * via HTTP using the given @method, adding the given extra headers
1330 * and the input buffer for the request content.
1331 *
1332 * Returns NULL in case of failure, otherwise a request handler.
Daniel Veillard9403a042001-05-28 11:00:53 +00001333 * The contentType, or redir, if provided must be freed by the caller
Owen Taylor3473f882001-02-23 17:55:21 +00001334 */
1335
1336void*
Daniel Veillard9403a042001-05-28 11:00:53 +00001337xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001338 char **contentType, char **redir,
1339 const char *headers, int ilen ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001340 xmlNanoHTTPCtxtPtr ctxt;
1341 char *bp, *p;
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001342 int blen;
1343 SOCKET ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001344 int nbRedirects = 0;
1345 char *redirURL = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001346#ifdef DEBUG_HTTP
1347 int xmt_bytes;
1348#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001349
1350 if (URL == NULL) return(NULL);
1351 if (method == NULL) method = "GET";
1352 xmlNanoHTTPInit();
1353
1354retry:
1355 if (redirURL == NULL)
1356 ctxt = xmlNanoHTTPNewCtxt(URL);
1357 else {
1358 ctxt = xmlNanoHTTPNewCtxt(redirURL);
Daniel Veillarda840b692003-10-19 13:35:37 +00001359 ctxt->location = xmlMemStrdup(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001360 }
1361
Daniel Veillardf012a642001-07-23 19:10:52 +00001362 if ( ctxt == NULL ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001363 return ( NULL );
1364 }
1365
Owen Taylor3473f882001-02-23 17:55:21 +00001366 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001367 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
Owen Taylor3473f882001-02-23 17:55:21 +00001368 xmlNanoHTTPFreeCtxt(ctxt);
1369 if (redirURL != NULL) xmlFree(redirURL);
1370 return(NULL);
1371 }
1372 if (ctxt->hostname == NULL) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001373 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
1374 "Failed to identify host in URI");
Owen Taylor3473f882001-02-23 17:55:21 +00001375 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001376 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001377 return(NULL);
1378 }
1379 if (proxy) {
1380 blen = strlen(ctxt->hostname) * 2 + 16;
1381 ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
1382 }
1383 else {
1384 blen = strlen(ctxt->hostname);
1385 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1386 }
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001387 if (ret == INVALID_SOCKET) {
Owen Taylor3473f882001-02-23 17:55:21 +00001388 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001389 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001390 return(NULL);
1391 }
1392 ctxt->fd = ret;
1393
Daniel Veillardf012a642001-07-23 19:10:52 +00001394 if (input == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001395 ilen = 0;
Daniel Veillardf012a642001-07-23 19:10:52 +00001396 else
1397 blen += 36;
1398
Owen Taylor3473f882001-02-23 17:55:21 +00001399 if (headers != NULL)
Daniel Veillardf012a642001-07-23 19:10:52 +00001400 blen += strlen(headers) + 2;
Owen Taylor3473f882001-02-23 17:55:21 +00001401 if (contentType && *contentType)
William M. Brackead35832008-02-06 04:12:46 +00001402 /* reserve for string plus 'Content-Type: \r\n" */
Owen Taylor3473f882001-02-23 17:55:21 +00001403 blen += strlen(*contentType) + 16;
Daniel Veillard351f2d62005-04-13 02:55:12 +00001404 if (ctxt->query != NULL)
William M. Brackead35832008-02-06 04:12:46 +00001405 /* 1 for '?' */
Daniel Veillard351f2d62005-04-13 02:55:12 +00001406 blen += strlen(ctxt->query) + 1;
Daniel Veillardf012a642001-07-23 19:10:52 +00001407 blen += strlen(method) + strlen(ctxt->path) + 24;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001408#ifdef HAVE_ZLIB_H
William M. Brackead35832008-02-06 04:12:46 +00001409 /* reserve for possible 'Accept-Encoding: gzip' string */
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001410 blen += 23;
1411#endif
William M. Brackead35832008-02-06 04:12:46 +00001412 if (ctxt->port != 80) {
1413 /* reserve space for ':xxxxx', incl. potential proxy */
1414 if (proxy)
1415 blen += 12;
1416 else
1417 blen += 6;
1418 }
Daniel Veillard82cb3192003-10-29 13:39:15 +00001419 bp = (char*)xmlMallocAtomic(blen);
Daniel Veillardf012a642001-07-23 19:10:52 +00001420 if ( bp == NULL ) {
1421 xmlNanoHTTPFreeCtxt( ctxt );
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001422 xmlHTTPErrMemory("allocating header buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001423 return ( NULL );
1424 }
1425
1426 p = bp;
1427
Owen Taylor3473f882001-02-23 17:55:21 +00001428 if (proxy) {
1429 if (ctxt->port != 80) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001430 p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s",
1431 method, ctxt->hostname,
Daniel Veillardf012a642001-07-23 19:10:52 +00001432 ctxt->port, ctxt->path );
Owen Taylor3473f882001-02-23 17:55:21 +00001433 }
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001434 else
1435 p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
Daniel Veillardf012a642001-07-23 19:10:52 +00001436 ctxt->hostname, ctxt->path);
Owen Taylor3473f882001-02-23 17:55:21 +00001437 }
1438 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001439 p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
Daniel Veillardf012a642001-07-23 19:10:52 +00001440
Daniel Veillard351f2d62005-04-13 02:55:12 +00001441 if (ctxt->query != NULL)
1442 p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
1443
William M. Brackec720082007-08-24 02:57:38 +00001444 if (ctxt->port == 80) {
1445 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001446 ctxt->hostname);
William M. Brackec720082007-08-24 02:57:38 +00001447 } else {
1448 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
1449 ctxt->hostname, ctxt->port);
1450 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001451
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001452#ifdef HAVE_ZLIB_H
1453 p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
1454#endif
1455
Daniel Veillardf012a642001-07-23 19:10:52 +00001456 if (contentType != NULL && *contentType)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001457 p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
Daniel Veillardf012a642001-07-23 19:10:52 +00001458
1459 if (headers != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001460 p += snprintf( p, blen - (p - bp), "%s", headers );
Daniel Veillardf012a642001-07-23 19:10:52 +00001461
Owen Taylor3473f882001-02-23 17:55:21 +00001462 if (input != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001463 snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
Owen Taylor3473f882001-02-23 17:55:21 +00001464 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001465 snprintf(p, blen - (p - bp), "\r\n");
Daniel Veillardf012a642001-07-23 19:10:52 +00001466
Owen Taylor3473f882001-02-23 17:55:21 +00001467#ifdef DEBUG_HTTP
1468 xmlGenericError(xmlGenericErrorContext,
1469 "-> %s%s", proxy? "(Proxy) " : "", bp);
1470 if ((blen -= strlen(bp)+1) < 0)
1471 xmlGenericError(xmlGenericErrorContext,
1472 "ERROR: overflowed buffer by %d bytes\n", -blen);
1473#endif
1474 ctxt->outptr = ctxt->out = bp;
1475 ctxt->state = XML_NANO_HTTP_WRITE;
Daniel Veillardf012a642001-07-23 19:10:52 +00001476 blen = strlen( ctxt->out );
Daniel Veillardf012a642001-07-23 19:10:52 +00001477#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001478 xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001479 if ( xmt_bytes != blen )
1480 xmlGenericError( xmlGenericErrorContext,
1481 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1482 xmt_bytes, blen,
1483 "bytes of HTTP headers sent to host",
1484 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001485#else
1486 xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001487#endif
1488
1489 if ( input != NULL ) {
William M. Brack78637da2003-07-31 14:47:38 +00001490#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001491 xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
1492
Daniel Veillardf012a642001-07-23 19:10:52 +00001493 if ( xmt_bytes != ilen )
1494 xmlGenericError( xmlGenericErrorContext,
1495 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1496 xmt_bytes, ilen,
1497 "bytes of HTTP content sent to host",
1498 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001499#else
1500 xmlNanoHTTPSend( ctxt, input, ilen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001501#endif
1502 }
1503
Owen Taylor3473f882001-02-23 17:55:21 +00001504 ctxt->state = XML_NANO_HTTP_READ;
Owen Taylor3473f882001-02-23 17:55:21 +00001505
1506 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
Daniel Veillard594e5df2009-09-07 14:58:47 +02001507 if (*p == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00001508 ctxt->content = ctxt->inrptr;
1509 xmlFree(p);
1510 break;
1511 }
1512 xmlNanoHTTPScanAnswer(ctxt, p);
1513
1514#ifdef DEBUG_HTTP
1515 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
1516#endif
1517 xmlFree(p);
1518 }
1519
1520 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1521 (ctxt->returnValue < 400)) {
1522#ifdef DEBUG_HTTP
1523 xmlGenericError(xmlGenericErrorContext,
1524 "\nRedirect to: %s\n", ctxt->location);
1525#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001526 while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
Owen Taylor3473f882001-02-23 17:55:21 +00001527 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1528 nbRedirects++;
Daniel Veillard9403a042001-05-28 11:00:53 +00001529 if (redirURL != NULL)
1530 xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001531 redirURL = xmlMemStrdup(ctxt->location);
1532 xmlNanoHTTPFreeCtxt(ctxt);
1533 goto retry;
1534 }
1535 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001536 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001537#ifdef DEBUG_HTTP
1538 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00001539 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001540#endif
1541 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001542 }
1543
1544 if (contentType != NULL) {
1545 if (ctxt->contentType != NULL)
1546 *contentType = xmlMemStrdup(ctxt->contentType);
1547 else
1548 *contentType = NULL;
1549 }
1550
Daniel Veillard9403a042001-05-28 11:00:53 +00001551 if ((redir != NULL) && (redirURL != NULL)) {
1552 *redir = redirURL;
1553 } else {
1554 if (redirURL != NULL)
1555 xmlFree(redirURL);
1556 if (redir != NULL)
1557 *redir = NULL;
1558 }
1559
Owen Taylor3473f882001-02-23 17:55:21 +00001560#ifdef DEBUG_HTTP
1561 if (ctxt->contentType != NULL)
1562 xmlGenericError(xmlGenericErrorContext,
1563 "\nCode %d, content-type '%s'\n\n",
1564 ctxt->returnValue, ctxt->contentType);
1565 else
1566 xmlGenericError(xmlGenericErrorContext,
1567 "\nCode %d, no content-type\n\n",
1568 ctxt->returnValue);
1569#endif
1570
1571 return((void *) ctxt);
1572}
1573
1574/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001575 * xmlNanoHTTPMethod:
1576 * @URL: The URL to load
1577 * @method: the HTTP method to use
1578 * @input: the input string if any
1579 * @contentType: the Content-Type information IN and OUT
1580 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001581 * @ilen: input length
Daniel Veillard9403a042001-05-28 11:00:53 +00001582 *
1583 * This function try to open a connection to the indicated resource
1584 * via HTTP using the given @method, adding the given extra headers
1585 * and the input buffer for the request content.
1586 *
1587 * Returns NULL in case of failure, otherwise a request handler.
1588 * The contentType, if provided must be freed by the caller
1589 */
1590
1591void*
1592xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001593 char **contentType, const char *headers, int ilen) {
Daniel Veillard9403a042001-05-28 11:00:53 +00001594 return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
Daniel Veillardf012a642001-07-23 19:10:52 +00001595 NULL, headers, ilen));
Daniel Veillard9403a042001-05-28 11:00:53 +00001596}
1597
1598/**
Owen Taylor3473f882001-02-23 17:55:21 +00001599 * xmlNanoHTTPFetch:
1600 * @URL: The URL to load
1601 * @filename: the filename where the content should be saved
1602 * @contentType: if available the Content-Type information will be
1603 * returned at that location
1604 *
1605 * This function try to fetch the indicated resource via HTTP GET
1606 * and save it's content in the file.
1607 *
1608 * Returns -1 in case of failure, 0 incase of success. The contentType,
1609 * if provided must be freed by the caller
1610 */
1611int
1612xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001613 void *ctxt = NULL;
1614 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001615 int fd;
1616 int len;
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001617 int ret = 0;
1618
William M. Brack015ccb22005-02-13 08:18:52 +00001619 if (filename == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001620 ctxt = xmlNanoHTTPOpen(URL, contentType);
1621 if (ctxt == NULL) return(-1);
1622
1623 if (!strcmp(filename, "-"))
1624 fd = 0;
1625 else {
1626 fd = open(filename, O_CREAT | O_WRONLY, 00644);
1627 if (fd < 0) {
1628 xmlNanoHTTPClose(ctxt);
1629 if ((contentType != NULL) && (*contentType != NULL)) {
1630 xmlFree(*contentType);
1631 *contentType = NULL;
1632 }
1633 return(-1);
1634 }
1635 }
1636
Daniel Veillardf012a642001-07-23 19:10:52 +00001637 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1638 if ( len > 0 ) {
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001639 if (write(fd, buf, len) == -1) {
1640 ret = -1;
1641 }
Owen Taylor3473f882001-02-23 17:55:21 +00001642 }
1643
1644 xmlNanoHTTPClose(ctxt);
1645 close(fd);
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001646 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001647}
1648
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001649#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001650/**
1651 * xmlNanoHTTPSave:
1652 * @ctxt: the HTTP context
1653 * @filename: the filename where the content should be saved
1654 *
1655 * This function saves the output of the HTTP transaction to a file
1656 * It closes and free the context at the end
1657 *
1658 * Returns -1 in case of failure, 0 incase of success.
1659 */
1660int
1661xmlNanoHTTPSave(void *ctxt, const char *filename) {
Daniel Veillarde3924972001-07-25 20:25:21 +00001662 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001663 int fd;
1664 int len;
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001665 int ret = 0;
1666
William M. Brack015ccb22005-02-13 08:18:52 +00001667 if ((ctxt == NULL) || (filename == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001668
1669 if (!strcmp(filename, "-"))
1670 fd = 0;
1671 else {
Daniel Veillardcd2ebab2007-08-23 20:47:33 +00001672 fd = open(filename, O_CREAT | O_WRONLY, 0666);
Owen Taylor3473f882001-02-23 17:55:21 +00001673 if (fd < 0) {
1674 xmlNanoHTTPClose(ctxt);
1675 return(-1);
1676 }
1677 }
1678
Daniel Veillardf012a642001-07-23 19:10:52 +00001679 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1680 if ( len > 0 ) {
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001681 if (write(fd, buf, len) == -1) {
1682 ret = -1;
1683 }
Owen Taylor3473f882001-02-23 17:55:21 +00001684 }
1685
1686 xmlNanoHTTPClose(ctxt);
William M. Brack20d82362004-03-17 08:44:46 +00001687 close(fd);
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001688 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001689}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001690#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001691
1692/**
1693 * xmlNanoHTTPReturnCode:
1694 * @ctx: the HTTP context
1695 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001696 * Get the latest HTTP return code received
1697 *
Owen Taylor3473f882001-02-23 17:55:21 +00001698 * Returns the HTTP return code for the request.
1699 */
1700int
1701xmlNanoHTTPReturnCode(void *ctx) {
1702 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1703
1704 if (ctxt == NULL) return(-1);
1705
1706 return(ctxt->returnValue);
1707}
1708
1709/**
1710 * xmlNanoHTTPAuthHeader:
1711 * @ctx: the HTTP context
1712 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001713 * Get the authentication header of an HTTP context
1714 *
Owen Taylor3473f882001-02-23 17:55:21 +00001715 * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
1716 * header.
1717 */
1718const char *
1719xmlNanoHTTPAuthHeader(void *ctx) {
1720 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1721
1722 if (ctxt == NULL) return(NULL);
1723
1724 return(ctxt->authHeader);
1725}
1726
Daniel Veillardf012a642001-07-23 19:10:52 +00001727/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001728 * xmlNanoHTTPContentLength:
Daniel Veillardf012a642001-07-23 19:10:52 +00001729 * @ctx: the HTTP context
1730 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001731 * Provides the specified content length from the HTTP header.
1732 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001733 * Return the specified content length from the HTTP header. Note that
1734 * a value of -1 indicates that the content length element was not included in
1735 * the response header.
1736 */
1737int
1738xmlNanoHTTPContentLength( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001739 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillardf012a642001-07-23 19:10:52 +00001740
1741 return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
1742}
1743
1744/**
Daniel Veillard847332a2003-10-18 11:29:40 +00001745 * xmlNanoHTTPRedir:
1746 * @ctx: the HTTP context
1747 *
1748 * Provides the specified redirection URL if available from the HTTP header.
1749 *
1750 * Return the specified redirection URL or NULL if not redirected.
1751 */
1752const char *
1753xmlNanoHTTPRedir( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001754 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillard847332a2003-10-18 11:29:40 +00001755
1756 return ( ( ctxt == NULL ) ? NULL : ctxt->location );
1757}
1758
1759/**
1760 * xmlNanoHTTPEncoding:
1761 * @ctx: the HTTP context
1762 *
1763 * Provides the specified encoding if specified in the HTTP headers.
1764 *
1765 * Return the specified encoding or NULL if not available
1766 */
1767const char *
1768xmlNanoHTTPEncoding( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001769 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillard847332a2003-10-18 11:29:40 +00001770
1771 return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
1772}
1773
1774/**
Daniel Veillarda840b692003-10-19 13:35:37 +00001775 * xmlNanoHTTPMimeType:
1776 * @ctx: the HTTP context
1777 *
1778 * Provides the specified Mime-Type if specified in the HTTP headers.
1779 *
1780 * Return the specified Mime-Type or NULL if not available
1781 */
1782const char *
1783xmlNanoHTTPMimeType( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001784 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillarda840b692003-10-19 13:35:37 +00001785
1786 return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
1787}
1788
1789/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001790 * xmlNanoHTTPFetchContent:
Daniel Veillardf012a642001-07-23 19:10:52 +00001791 * @ctx: the HTTP context
1792 * @ptr: pointer to set to the content buffer.
1793 * @len: integer pointer to hold the length of the content
1794 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001795 * Check if all the content was read
1796 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001797 * Returns 0 if all the content was read and available, returns
1798 * -1 if received content length was less than specified or an error
1799 * occurred.
1800 */
Daniel Veillarda2351322004-06-27 12:08:10 +00001801static int
Daniel Veillardf012a642001-07-23 19:10:52 +00001802xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001803 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillardf012a642001-07-23 19:10:52 +00001804
1805 int rc = 0;
1806 int cur_lgth;
1807 int rcvd_lgth;
1808 int dummy_int;
1809 char * dummy_ptr = NULL;
1810
1811 /* Dummy up return input parameters if not provided */
1812
1813 if ( len == NULL )
1814 len = &dummy_int;
1815
1816 if ( ptr == NULL )
1817 ptr = &dummy_ptr;
1818
1819 /* But can't work without the context pointer */
1820
1821 if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
1822 *len = 0;
1823 *ptr = NULL;
1824 return ( -1 );
1825 }
1826
1827 rcvd_lgth = ctxt->inptr - ctxt->content;
1828
1829 while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
1830
1831 rcvd_lgth += cur_lgth;
1832 if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
1833 break;
1834 }
1835
1836 *ptr = ctxt->content;
1837 *len = rcvd_lgth;
1838
1839 if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
1840 rc = -1;
1841 else if ( rcvd_lgth == 0 )
1842 rc = -1;
1843
1844 return ( rc );
1845}
1846
Owen Taylor3473f882001-02-23 17:55:21 +00001847#ifdef STANDALONE
1848int main(int argc, char **argv) {
1849 char *contentType = NULL;
1850
1851 if (argv[1] != NULL) {
1852 if (argv[2] != NULL)
1853 xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1854 else
1855 xmlNanoHTTPFetch(argv[1], "-", &contentType);
1856 if (contentType != NULL) xmlFree(contentType);
1857 } else {
1858 xmlGenericError(xmlGenericErrorContext,
1859 "%s: minimal HTTP GET implementation\n", argv[0]);
1860 xmlGenericError(xmlGenericErrorContext,
1861 "\tusage %s [ URL [ filename ] ]\n", argv[0]);
1862 }
1863 xmlNanoHTTPCleanup();
1864 xmlMemoryDump();
1865 return(0);
1866}
1867#endif /* STANDALONE */
1868#else /* !LIBXML_HTTP_ENABLED */
1869#ifdef STANDALONE
1870#include <stdio.h>
1871int main(int argc, char **argv) {
1872 xmlGenericError(xmlGenericErrorContext,
1873 "%s : HTTP support not compiled in\n", argv[0]);
1874 return(0);
1875}
1876#endif /* STANDALONE */
1877#endif /* LIBXML_HTTP_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001878#define bottom_nanohttp
1879#include "elfgcchack.h"