blob: 8a2b4088d0a6f2b6cea31a583a9037df5d0deb9f [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 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +080013
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
Daniel Veillardf8e3db02012-09-11 13:26:36 +080049#include <fcntl.h>
Owen Taylor3473f882001-02-23 17:55:21 +000050#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_
Nick Wellnhofer5b2324b2017-10-09 00:05:04 +0200185 int err = WSAGetLastError();
186 switch(err) {
187 case WSAECONNRESET:
188 return(ECONNRESET);
189 case WSAEINPROGRESS:
190 return(EINPROGRESS);
191 case WSAEINTR:
192 return(EINTR);
193 case WSAESHUTDOWN:
194 return(ESHUTDOWN);
195 case WSAEWOULDBLOCK:
196 return(EWOULDBLOCK);
197 default:
198 return(err);
199 }
Owen Taylor3473f882001-02-23 17:55:21 +0000200#else
201 return(errno);
202#endif
203}
204
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000205#ifdef SUPPORT_IP6
Daniel Veillard2db8c122003-07-08 12:16:59 +0000206static
207int have_ipv6(void) {
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100208 SOCKET s;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000209
210 s = socket (AF_INET6, SOCK_STREAM, 0);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100211 if (s != INVALID_SOCKET) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000212 close (s);
213 return (1);
214 }
215 return (0);
216}
217#endif
218
Owen Taylor3473f882001-02-23 17:55:21 +0000219/**
220 * xmlNanoHTTPInit:
221 *
222 * Initialize the HTTP protocol layer.
223 * Currently it just checks for proxy informations
224 */
225
226void
227xmlNanoHTTPInit(void) {
228 const char *env;
229#ifdef _WINSOCKAPI_
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800230 WSADATA wsaData;
Owen Taylor3473f882001-02-23 17:55:21 +0000231#endif
232
233 if (initialized)
234 return;
235
236#ifdef _WINSOCKAPI_
237 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
238 return;
239#endif
240
241 if (proxy == NULL) {
242 proxyPort = 80;
243 env = getenv("no_proxy");
Daniel Veillard29b17482004-08-16 00:39:03 +0000244 if (env && ((env[0] == '*') && (env[1] == 0)))
Owen Taylor3473f882001-02-23 17:55:21 +0000245 goto done;
246 env = getenv("http_proxy");
247 if (env != NULL) {
248 xmlNanoHTTPScanProxy(env);
249 goto done;
250 }
251 env = getenv("HTTP_PROXY");
252 if (env != NULL) {
253 xmlNanoHTTPScanProxy(env);
254 goto done;
255 }
256 }
257done:
258 initialized = 1;
259}
260
261/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000262 * xmlNanoHTTPCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +0000263 *
264 * Cleanup the HTTP protocol layer.
265 */
266
267void
268xmlNanoHTTPCleanup(void) {
Daniel Veillard744acff2005-07-12 15:09:53 +0000269 if (proxy != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000270 xmlFree(proxy);
Daniel Veillard744acff2005-07-12 15:09:53 +0000271 proxy = NULL;
272 }
Owen Taylor3473f882001-02-23 17:55:21 +0000273#ifdef _WINSOCKAPI_
274 if (initialized)
275 WSACleanup();
276#endif
277 initialized = 0;
278 return;
279}
280
281/**
Owen Taylor3473f882001-02-23 17:55:21 +0000282 * xmlNanoHTTPScanURL:
283 * @ctxt: an HTTP context
284 * @URL: The URL used to initialize the context
285 *
286 * (Re)Initialize an HTTP context by parsing the URL and finding
287 * the protocol host port and path it indicates.
288 */
289
290static void
291xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
William M. Brack015ccb22005-02-13 08:18:52 +0000292 xmlURIPtr uri;
Steve Wolf19d785b2013-02-28 18:22:46 +0800293 int len;
294
William M. Brack015ccb22005-02-13 08:18:52 +0000295 /*
296 * Clear any existing data from the context
297 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800298 if (ctxt->protocol != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000299 xmlFree(ctxt->protocol);
300 ctxt->protocol = NULL;
301 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800302 if (ctxt->hostname != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000303 xmlFree(ctxt->hostname);
304 ctxt->hostname = NULL;
305 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800306 if (ctxt->path != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000307 xmlFree(ctxt->path);
308 ctxt->path = NULL;
309 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800310 if (ctxt->query != NULL) {
Daniel Veillard351f2d62005-04-13 02:55:12 +0000311 xmlFree(ctxt->query);
312 ctxt->query = NULL;
313 }
Owen Taylor3473f882001-02-23 17:55:21 +0000314 if (URL == NULL) return;
William M. Brack015ccb22005-02-13 08:18:52 +0000315
Daniel Veillard336a8e12005-08-07 10:46:19 +0000316 uri = xmlParseURIRaw(URL, 1);
William M. Brack015ccb22005-02-13 08:18:52 +0000317 if (uri == NULL)
318 return;
319
320 if ((uri->scheme == NULL) || (uri->server == NULL)) {
321 xmlFreeURI(uri);
322 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000323 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800324
William M. Brack015ccb22005-02-13 08:18:52 +0000325 ctxt->protocol = xmlMemStrdup(uri->scheme);
Steve Wolf19d785b2013-02-28 18:22:46 +0800326 /* special case of IPv6 addresses, the [] need to be removed */
327 if ((uri->server != NULL) && (*uri->server == '[')) {
328 len = strlen(uri->server);
329 if ((len > 2) && (uri->server[len - 1] == ']')) {
330 ctxt->hostname = (char *) xmlCharStrndup(uri->server + 1, len -2);
331 } else
332 ctxt->hostname = xmlMemStrdup(uri->server);
333 } else
334 ctxt->hostname = xmlMemStrdup(uri->server);
William M. Brack015ccb22005-02-13 08:18:52 +0000335 if (uri->path != NULL)
336 ctxt->path = xmlMemStrdup(uri->path);
337 else
338 ctxt->path = xmlMemStrdup("/");
Daniel Veillard351f2d62005-04-13 02:55:12 +0000339 if (uri->query != NULL)
340 ctxt->query = xmlMemStrdup(uri->query);
William M. Brack015ccb22005-02-13 08:18:52 +0000341 if (uri->port != 0)
342 ctxt->port = uri->port;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000343
William M. Brack015ccb22005-02-13 08:18:52 +0000344 xmlFreeURI(uri);
Owen Taylor3473f882001-02-23 17:55:21 +0000345}
346
347/**
348 * xmlNanoHTTPScanProxy:
349 * @URL: The proxy URL used to initialize the proxy context
350 *
351 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
352 * the protocol host port it indicates.
353 * Should be like http://myproxy/ or http://myproxy:3128/
354 * A NULL URL cleans up proxy informations.
355 */
356
357void
358xmlNanoHTTPScanProxy(const char *URL) {
William M. Brack015ccb22005-02-13 08:18:52 +0000359 xmlURIPtr uri;
Owen Taylor3473f882001-02-23 17:55:21 +0000360
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800361 if (proxy != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000362 xmlFree(proxy);
363 proxy = NULL;
364 }
William M. Brack015ccb22005-02-13 08:18:52 +0000365 proxyPort = 0;
366
Owen Taylor3473f882001-02-23 17:55:21 +0000367#ifdef DEBUG_HTTP
368 if (URL == NULL)
369 xmlGenericError(xmlGenericErrorContext,
370 "Removing HTTP proxy info\n");
371 else
372 xmlGenericError(xmlGenericErrorContext,
373 "Using HTTP proxy %s\n", URL);
374#endif
375 if (URL == NULL) return;
William M. Brack015ccb22005-02-13 08:18:52 +0000376
Daniel Veillard336a8e12005-08-07 10:46:19 +0000377 uri = xmlParseURIRaw(URL, 1);
William M. Brack015ccb22005-02-13 08:18:52 +0000378 if ((uri == NULL) || (uri->scheme == NULL) ||
379 (strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
380 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
381 if (uri != NULL)
382 xmlFreeURI(uri);
383 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000384 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800385
William M. Brack015ccb22005-02-13 08:18:52 +0000386 proxy = xmlMemStrdup(uri->server);
387 if (uri->port != 0)
388 proxyPort = uri->port;
Owen Taylor3473f882001-02-23 17:55:21 +0000389
William M. Brack015ccb22005-02-13 08:18:52 +0000390 xmlFreeURI(uri);
Owen Taylor3473f882001-02-23 17:55:21 +0000391}
392
393/**
394 * xmlNanoHTTPNewCtxt:
395 * @URL: The URL used to initialize the context
396 *
397 * Allocate and initialize a new HTTP context.
398 *
399 * Returns an HTTP context or NULL in case of error.
400 */
401
402static xmlNanoHTTPCtxtPtr
403xmlNanoHTTPNewCtxt(const char *URL) {
404 xmlNanoHTTPCtxtPtr ret;
405
406 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000407 if (ret == NULL) {
408 xmlHTTPErrMemory("allocating context");
409 return(NULL);
410 }
Owen Taylor3473f882001-02-23 17:55:21 +0000411
412 memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
413 ret->port = 80;
414 ret->returnValue = 0;
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100415 ret->fd = INVALID_SOCKET;
Daniel Veillardf012a642001-07-23 19:10:52 +0000416 ret->ContentLength = -1;
Owen Taylor3473f882001-02-23 17:55:21 +0000417
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000418 xmlNanoHTTPScanURL(ret, URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000419
420 return(ret);
421}
422
423/**
424 * xmlNanoHTTPFreeCtxt:
425 * @ctxt: an HTTP context
426 *
427 * Frees the context after closing the connection.
428 */
429
430static void
431xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
432 if (ctxt == NULL) return;
433 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
434 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
435 if (ctxt->path != NULL) xmlFree(ctxt->path);
Daniel Veillard351f2d62005-04-13 02:55:12 +0000436 if (ctxt->query != NULL) xmlFree(ctxt->query);
Owen Taylor3473f882001-02-23 17:55:21 +0000437 if (ctxt->out != NULL) xmlFree(ctxt->out);
438 if (ctxt->in != NULL) xmlFree(ctxt->in);
439 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
Daniel Veillard847332a2003-10-18 11:29:40 +0000440 if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
Daniel Veillarda840b692003-10-19 13:35:37 +0000441 if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
Owen Taylor3473f882001-02-23 17:55:21 +0000442 if (ctxt->location != NULL) xmlFree(ctxt->location);
443 if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000444#ifdef HAVE_ZLIB_H
445 if (ctxt->strm != NULL) {
446 inflateEnd(ctxt->strm);
447 xmlFree(ctxt->strm);
448 }
449#endif
450
Owen Taylor3473f882001-02-23 17:55:21 +0000451 ctxt->state = XML_NANO_HTTP_NONE;
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100452 if (ctxt->fd != INVALID_SOCKET) closesocket(ctxt->fd);
453 ctxt->fd = INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000454 xmlFree(ctxt);
455}
456
457/**
458 * xmlNanoHTTPSend:
459 * @ctxt: an HTTP context
460 *
461 * Send the input needed to initiate the processing on the server side
Daniel Veillardf012a642001-07-23 19:10:52 +0000462 * Returns number of bytes sent or -1 on error.
Owen Taylor3473f882001-02-23 17:55:21 +0000463 */
464
Daniel Veillardf012a642001-07-23 19:10:52 +0000465static int
Raphael Prevost48b60c32009-08-23 13:11:01 +0200466xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
467{
468 int total_sent = 0;
469#ifdef HAVE_POLL_H
470 struct pollfd p;
471#else
472 struct timeval tv;
473 fd_set wfd;
474#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000475
Raphael Prevost48b60c32009-08-23 13:11:01 +0200476 if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000477 while (total_sent < outlen) {
Patrick Monnerat437f4f52013-12-12 15:23:09 +0800478 int nsent = send(ctxt->fd, SEND_ARG2_CAST (xmt_ptr + total_sent),
Raphael Prevost48b60c32009-08-23 13:11:01 +0200479 outlen - total_sent, 0);
480
481 if (nsent > 0)
Owen Taylor3473f882001-02-23 17:55:21 +0000482 total_sent += nsent;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200483 else if ((nsent == -1) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000484#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200485 (socket_errno() != EAGAIN) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000486#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200487 (socket_errno() != EWOULDBLOCK)) {
488 __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
489 if (total_sent == 0)
490 total_sent = -1;
491 break;
492 } else {
493 /*
494 * No data sent
495 * Since non-blocking sockets are used, wait for
496 * socket to be writable or default timeout prior
497 * to retrying.
498 */
499#ifndef HAVE_POLL_H
spadixd29a5c82009-10-19 14:03:25 +0200500#ifndef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200501 if (ctxt->fd > FD_SETSIZE)
502 return -1;
spadixd29a5c82009-10-19 14:03:25 +0200503#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000504
Raphael Prevost48b60c32009-08-23 13:11:01 +0200505 tv.tv_sec = timeout;
506 tv.tv_usec = 0;
507 FD_ZERO(&wfd);
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000508#ifdef _MSC_VER
509#pragma warning(push)
510#pragma warning(disable: 4018)
511#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200512 FD_SET(ctxt->fd, &wfd);
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000513#ifdef _MSC_VER
514#pragma warning(pop)
515#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200516 (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
517#else
518 p.fd = ctxt->fd;
519 p.events = POLLOUT;
520 (void) poll(&p, 1, timeout * 1000);
521#endif /* !HAVE_POLL_H */
522 }
523 }
Owen Taylor3473f882001-02-23 17:55:21 +0000524 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000525
526 return total_sent;
Owen Taylor3473f882001-02-23 17:55:21 +0000527}
528
529/**
530 * xmlNanoHTTPRecv:
531 * @ctxt: an HTTP context
532 *
533 * Read information coming from the HTTP connection.
534 * This is a blocking call (but it blocks in select(), not read()).
535 *
536 * Returns the number of byte read or -1 in case of error.
537 */
538
539static int
Raphael Prevost48b60c32009-08-23 13:11:01 +0200540xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
541{
542#ifdef HAVE_POLL_H
543 struct pollfd p;
544#else
Owen Taylor3473f882001-02-23 17:55:21 +0000545 fd_set rfd;
546 struct timeval tv;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200547#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000548
549
550 while (ctxt->state & XML_NANO_HTTP_READ) {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200551 if (ctxt->in == NULL) {
552 ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
553 if (ctxt->in == NULL) {
554 xmlHTTPErrMemory("allocating input");
555 ctxt->last = -1;
556 return (-1);
557 }
558 ctxt->inlen = 65000;
559 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
560 }
561 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
562 int delta = ctxt->inrptr - ctxt->in;
563 int len = ctxt->inptr - ctxt->inrptr;
Owen Taylor3473f882001-02-23 17:55:21 +0000564
Raphael Prevost48b60c32009-08-23 13:11:01 +0200565 memmove(ctxt->in, ctxt->inrptr, len);
566 ctxt->inrptr -= delta;
567 ctxt->content -= delta;
568 ctxt->inptr -= delta;
569 }
570 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
571 int d_inptr = ctxt->inptr - ctxt->in;
572 int d_content = ctxt->content - ctxt->in;
573 int d_inrptr = ctxt->inrptr - ctxt->in;
574 char *tmp_ptr = ctxt->in;
575
576 ctxt->inlen *= 2;
Daniel Veillardf012a642001-07-23 19:10:52 +0000577 ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
Raphael Prevost48b60c32009-08-23 13:11:01 +0200578 if (ctxt->in == NULL) {
579 xmlHTTPErrMemory("allocating input buffer");
580 xmlFree(tmp_ptr);
581 ctxt->last = -1;
582 return (-1);
583 }
Owen Taylor3473f882001-02-23 17:55:21 +0000584 ctxt->inptr = ctxt->in + d_inptr;
585 ctxt->content = ctxt->in + d_content;
586 ctxt->inrptr = ctxt->in + d_inrptr;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200587 }
588 ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
589 if (ctxt->last > 0) {
590 ctxt->inptr += ctxt->last;
591 return (ctxt->last);
592 }
593 if (ctxt->last == 0) {
594 return (0);
595 }
596 if (ctxt->last == -1) {
597 switch (socket_errno()) {
598 case EINPROGRESS:
599 case EWOULDBLOCK:
Owen Taylor3473f882001-02-23 17:55:21 +0000600#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200601 case EAGAIN:
Owen Taylor3473f882001-02-23 17:55:21 +0000602#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200603 break;
Daniel Veillardf012a642001-07-23 19:10:52 +0000604
Raphael Prevost48b60c32009-08-23 13:11:01 +0200605 case ECONNRESET:
606 case ESHUTDOWN:
607 return (0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000608
Raphael Prevost48b60c32009-08-23 13:11:01 +0200609 default:
610 __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
611 return (-1);
612 }
613 }
614#ifdef HAVE_POLL_H
615 p.fd = ctxt->fd;
616 p.events = POLLIN;
617 if ((poll(&p, 1, timeout * 1000) < 1)
618#if defined(EINTR)
619 && (errno != EINTR)
620#endif
621 )
622 return (0);
623#else /* !HAVE_POLL_H */
spadixd29a5c82009-10-19 14:03:25 +0200624#ifndef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200625 if (ctxt->fd > FD_SETSIZE)
626 return 0;
spadixd29a5c82009-10-19 14:03:25 +0200627#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000628
Raphael Prevost48b60c32009-08-23 13:11:01 +0200629 tv.tv_sec = timeout;
630 tv.tv_usec = 0;
631 FD_ZERO(&rfd);
632
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000633#ifdef _MSC_VER
634#pragma warning(push)
635#pragma warning(disable: 4018)
636#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200637
638 FD_SET(ctxt->fd, &rfd);
639
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000640#ifdef _MSC_VER
641#pragma warning(pop)
642#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200643
644 if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
Daniel Veillard50f34372001-08-03 12:06:36 +0000645#if defined(EINTR)
Nick Wellnhofer5b2324b2017-10-09 00:05:04 +0200646 && (socket_errno() != EINTR)
Daniel Veillard50f34372001-08-03 12:06:36 +0000647#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200648 )
649 return (0);
650#endif /* !HAVE_POLL_H */
Owen Taylor3473f882001-02-23 17:55:21 +0000651 }
Raphael Prevost48b60c32009-08-23 13:11:01 +0200652 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +0000653}
654
655/**
656 * xmlNanoHTTPReadLine:
657 * @ctxt: an HTTP context
658 *
659 * Read one line in the HTTP server output, usually for extracting
660 * the HTTP protocol informations from the answer header.
661 *
662 * Returns a newly allocated string with a copy of the line, or NULL
663 * which indicate the end of the input.
664 */
665
666static char *
667xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
668 char buf[4096];
669 char *bp = buf;
Daniel Veillardf012a642001-07-23 19:10:52 +0000670 int rc;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800671
Owen Taylor3473f882001-02-23 17:55:21 +0000672 while (bp - buf < 4095) {
673 if (ctxt->inrptr == ctxt->inptr) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000674 if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000675 if (bp == buf)
676 return(NULL);
677 else
678 *bp = 0;
679 return(xmlMemStrdup(buf));
680 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000681 else if ( rc == -1 ) {
682 return ( NULL );
683 }
Owen Taylor3473f882001-02-23 17:55:21 +0000684 }
685 *bp = *ctxt->inrptr++;
686 if (*bp == '\n') {
687 *bp = 0;
688 return(xmlMemStrdup(buf));
689 }
690 if (*bp != '\r')
691 bp++;
692 }
693 buf[4095] = 0;
694 return(xmlMemStrdup(buf));
695}
696
697
698/**
699 * xmlNanoHTTPScanAnswer:
700 * @ctxt: an HTTP context
701 * @line: an HTTP header line
702 *
703 * Try to extract useful informations from the server answer.
704 * We currently parse and process:
705 * - The HTTP revision/ return code
Daniel Veillarda840b692003-10-19 13:35:37 +0000706 * - The Content-Type, Mime-Type and charset used
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000707 * - The Location for redirect processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000708 *
709 * Returns -1 in case of failure, the file descriptor number otherwise
710 */
711
712static void
713xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
714 const char *cur = line;
715
716 if (line == NULL) return;
717
718 if (!strncmp(line, "HTTP/", 5)) {
719 int version = 0;
720 int ret = 0;
721
722 cur += 5;
723 while ((*cur >= '0') && (*cur <= '9')) {
724 version *= 10;
725 version += *cur - '0';
726 cur++;
727 }
728 if (*cur == '.') {
729 cur++;
730 if ((*cur >= '0') && (*cur <= '9')) {
731 version *= 10;
732 version += *cur - '0';
733 cur++;
734 }
735 while ((*cur >= '0') && (*cur <= '9'))
736 cur++;
737 } else
738 version *= 10;
739 if ((*cur != ' ') && (*cur != '\t')) return;
740 while ((*cur == ' ') || (*cur == '\t')) cur++;
741 if ((*cur < '0') || (*cur > '9')) return;
742 while ((*cur >= '0') && (*cur <= '9')) {
743 ret *= 10;
744 ret += *cur - '0';
745 cur++;
746 }
747 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
748 ctxt->returnValue = ret;
Daniel Veillard13cee4e2009-09-05 14:52:55 +0200749 ctxt->version = version;
Owen Taylor3473f882001-02-23 17:55:21 +0000750 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
Daniel Veillarda840b692003-10-19 13:35:37 +0000751 const xmlChar *charset, *last, *mime;
Owen Taylor3473f882001-02-23 17:55:21 +0000752 cur += 13;
753 while ((*cur == ' ') || (*cur == '\t')) cur++;
754 if (ctxt->contentType != NULL)
755 xmlFree(ctxt->contentType);
756 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillarda840b692003-10-19 13:35:37 +0000757 mime = (const xmlChar *) cur;
758 last = mime;
759 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
760 (*last != ';') && (*last != ','))
761 last++;
762 if (ctxt->mimeType != NULL)
763 xmlFree(ctxt->mimeType);
764 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
765 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
766 if (charset != NULL) {
767 charset += 8;
768 last = charset;
769 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
770 (*last != ';') && (*last != ','))
771 last++;
772 if (ctxt->encoding != NULL)
773 xmlFree(ctxt->encoding);
774 ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
775 }
Owen Taylor3473f882001-02-23 17:55:21 +0000776 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
Daniel Veillarda840b692003-10-19 13:35:37 +0000777 const xmlChar *charset, *last, *mime;
Owen Taylor3473f882001-02-23 17:55:21 +0000778 cur += 12;
779 if (ctxt->contentType != NULL) return;
780 while ((*cur == ' ') || (*cur == '\t')) cur++;
781 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillarda840b692003-10-19 13:35:37 +0000782 mime = (const xmlChar *) cur;
783 last = mime;
784 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
785 (*last != ';') && (*last != ','))
786 last++;
787 if (ctxt->mimeType != NULL)
788 xmlFree(ctxt->mimeType);
789 ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
790 charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
791 if (charset != NULL) {
792 charset += 8;
793 last = charset;
794 while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
795 (*last != ';') && (*last != ','))
796 last++;
797 if (ctxt->encoding != NULL)
798 xmlFree(ctxt->encoding);
799 ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
800 }
Owen Taylor3473f882001-02-23 17:55:21 +0000801 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
802 cur += 9;
803 while ((*cur == ' ') || (*cur == '\t')) cur++;
804 if (ctxt->location != NULL)
805 xmlFree(ctxt->location);
William M. Brack7e29c0a2004-04-02 09:07:22 +0000806 if (*cur == '/') {
807 xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800808 xmlChar *tmp_loc =
William M. Brack7e29c0a2004-04-02 09:07:22 +0000809 xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800810 ctxt->location =
William M. Brack7e29c0a2004-04-02 09:07:22 +0000811 (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
812 } else {
813 ctxt->location = xmlMemStrdup(cur);
814 }
Owen Taylor3473f882001-02-23 17:55:21 +0000815 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
816 cur += 17;
817 while ((*cur == ' ') || (*cur == '\t')) cur++;
818 if (ctxt->authHeader != NULL)
819 xmlFree(ctxt->authHeader);
820 ctxt->authHeader = xmlMemStrdup(cur);
821 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
822 cur += 19;
823 while ((*cur == ' ') || (*cur == '\t')) cur++;
824 if (ctxt->authHeader != NULL)
825 xmlFree(ctxt->authHeader);
826 ctxt->authHeader = xmlMemStrdup(cur);
Daniel Veillard9a2724d2005-12-15 11:12:26 +0000827#ifdef HAVE_ZLIB_H
828 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
829 cur += 17;
830 while ((*cur == ' ') || (*cur == '\t')) cur++;
831 if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
832 ctxt->usesGzip = 1;
833
834 ctxt->strm = xmlMalloc(sizeof(z_stream));
835
836 if (ctxt->strm != NULL) {
837 ctxt->strm->zalloc = Z_NULL;
838 ctxt->strm->zfree = Z_NULL;
839 ctxt->strm->opaque = Z_NULL;
840 ctxt->strm->avail_in = 0;
841 ctxt->strm->next_in = Z_NULL;
842
843 inflateInit2( ctxt->strm, 31 );
844 }
845 }
846#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000847 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
848 cur += 15;
849 ctxt->ContentLength = strtol( cur, NULL, 10 );
Owen Taylor3473f882001-02-23 17:55:21 +0000850 }
851}
852
853/**
854 * xmlNanoHTTPConnectAttempt:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000855 * @addr: a socket address structure
Owen Taylor3473f882001-02-23 17:55:21 +0000856 *
857 * Attempt a connection to the given IP:port endpoint. It forces
858 * non-blocking semantic on the socket, and allow 60 seconds for
859 * the host to answer.
860 *
861 * Returns -1 in case of failure, the file descriptor number otherwise
862 */
863
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100864static SOCKET
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000865xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
Owen Taylor3473f882001-02-23 17:55:21 +0000866{
Raphael Prevost48b60c32009-08-23 13:11:01 +0200867#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +0000868 fd_set wfd;
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000869#ifdef _WINSOCKAPI_
870 fd_set xfd;
871#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000872 struct timeval tv;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200873#else /* !HAVE_POLL_H */
874 struct pollfd p;
875#endif /* !HAVE_POLL_H */
Owen Taylor3473f882001-02-23 17:55:21 +0000876 int status;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200877
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000878 int addrlen;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200879
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000880 SOCKET s;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200881
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000882#ifdef SUPPORT_IP6
883 if (addr->sa_family == AF_INET6) {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200884 s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
885 addrlen = sizeof(struct sockaddr_in6);
886 } else
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000887#endif
888 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200889 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
890 addrlen = sizeof(struct sockaddr_in);
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000891 }
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100892 if (s == INVALID_SOCKET) {
Owen Taylor3473f882001-02-23 17:55:21 +0000893#ifdef DEBUG_HTTP
Raphael Prevost48b60c32009-08-23 13:11:01 +0200894 perror("socket");
Owen Taylor3473f882001-02-23 17:55:21 +0000895#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200896 __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100897 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000898 }
Owen Taylor3473f882001-02-23 17:55:21 +0000899#ifdef _WINSOCKAPI_
900 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200901 u_long one = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000902
Raphael Prevost48b60c32009-08-23 13:11:01 +0200903 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000904 }
905#else /* _WINSOCKAPI_ */
906#if defined(VMS)
907 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200908 int enable = 1;
909
910 status = ioctl(s, FIONBIO, &enable);
Owen Taylor3473f882001-02-23 17:55:21 +0000911 }
912#else /* VMS */
Daniel Veillardcba68392008-08-29 12:43:40 +0000913#if defined(__BEOS__) && !defined(__HAIKU__)
Raphael Prevost48b60c32009-08-23 13:11:01 +0200914 {
915 bool noblock = true;
916
917 status =
918 setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
919 sizeof(noblock));
920 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000921#else /* __BEOS__ */
Owen Taylor3473f882001-02-23 17:55:21 +0000922 if ((status = fcntl(s, F_GETFL, 0)) != -1) {
923#ifdef O_NONBLOCK
Raphael Prevost48b60c32009-08-23 13:11:01 +0200924 status |= O_NONBLOCK;
Owen Taylor3473f882001-02-23 17:55:21 +0000925#else /* O_NONBLOCK */
926#ifdef F_NDELAY
Raphael Prevost48b60c32009-08-23 13:11:01 +0200927 status |= F_NDELAY;
Owen Taylor3473f882001-02-23 17:55:21 +0000928#endif /* F_NDELAY */
929#endif /* !O_NONBLOCK */
Raphael Prevost48b60c32009-08-23 13:11:01 +0200930 status = fcntl(s, F_SETFL, status);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 }
932 if (status < 0) {
933#ifdef DEBUG_HTTP
Raphael Prevost48b60c32009-08-23 13:11:01 +0200934 perror("nonblocking");
Owen Taylor3473f882001-02-23 17:55:21 +0000935#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200936 __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
937 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100938 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +0000939 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000940#endif /* !__BEOS__ */
Owen Taylor3473f882001-02-23 17:55:21 +0000941#endif /* !VMS */
942#endif /* !_WINSOCKAPI_ */
943
Raphael Prevost48b60c32009-08-23 13:11:01 +0200944 if (connect(s, addr, addrlen) == -1) {
945 switch (socket_errno()) {
946 case EINPROGRESS:
947 case EWOULDBLOCK:
948 break;
949 default:
950 __xmlIOErr(XML_FROM_HTTP, 0,
951 "error connecting to HTTP server");
952 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100953 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200954 }
955 }
956#ifndef HAVE_POLL_H
Owen Taylor3473f882001-02-23 17:55:21 +0000957 tv.tv_sec = timeout;
958 tv.tv_usec = 0;
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000959
960#ifdef _MSC_VER
961#pragma warning(push)
962#pragma warning(disable: 4018)
963#endif
spadixd29a5c82009-10-19 14:03:25 +0200964#ifndef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +0200965 if (s > FD_SETSIZE)
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100966 return INVALID_SOCKET;
spadixd29a5c82009-10-19 14:03:25 +0200967#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000968 FD_ZERO(&wfd);
969 FD_SET(s, &wfd);
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000970
Raphael Prevost48b60c32009-08-23 13:11:01 +0200971#ifdef _WINSOCKAPI_
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000972 FD_ZERO(&xfd);
973 FD_SET(s, &xfd);
Raphael Prevost48b60c32009-08-23 13:11:01 +0200974
975 switch (select(s + 1, NULL, &wfd, &xfd, &tv))
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000976#else
Raphael Prevost48b60c32009-08-23 13:11:01 +0200977 switch (select(s + 1, NULL, &wfd, NULL, &tv))
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +0000978#endif
Daniel Veillard9e2110b2005-08-08 20:33:54 +0000979#ifdef _MSC_VER
980#pragma warning(pop)
981#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +0200982
983#else /* !HAVE_POLL_H */
984 p.fd = s;
985 p.events = POLLOUT;
986 switch (poll(&p, 1, timeout * 1000))
987#endif /* !HAVE_POLL_H */
988
Owen Taylor3473f882001-02-23 17:55:21 +0000989 {
Raphael Prevost48b60c32009-08-23 13:11:01 +0200990 case 0:
991 /* Time out */
992 __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
993 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100994 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +0200995 case -1:
996 /* Ermm.. ?? */
997 __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
998 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +0100999 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +00001000 }
1001
Raphael Prevost48b60c32009-08-23 13:11:01 +02001002#ifndef HAVE_POLL_H
1003 if (FD_ISSET(s, &wfd)
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00001004#ifdef _WINSOCKAPI_
Raphael Prevost48b60c32009-08-23 13:11:01 +02001005 || FD_ISSET(s, &xfd)
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00001006#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +02001007 )
1008#else /* !HAVE_POLL_H */
1009 if (p.revents == POLLOUT)
1010#endif /* !HAVE_POLL_H */
1011 {
1012 XML_SOCKLEN_T len;
1013
1014 len = sizeof(status);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001015#ifdef SO_ERROR
Raphael Prevost48b60c32009-08-23 13:11:01 +02001016 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
1017 0) {
1018 /* Solaris error code */
1019 __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
Denis Pauk283c83e2013-08-06 09:49:42 +03001020 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001021 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +02001022 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001023#endif
Raphael Prevost48b60c32009-08-23 13:11:01 +02001024 if (status) {
1025 __xmlIOErr(XML_FROM_HTTP, 0,
1026 "Error connecting to remote host");
1027 closesocket(s);
1028 errno = status;
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001029 return INVALID_SOCKET;
Raphael Prevost48b60c32009-08-23 13:11:01 +02001030 }
Owen Taylor3473f882001-02-23 17:55:21 +00001031 } else {
Raphael Prevost48b60c32009-08-23 13:11:01 +02001032 /* pbm */
1033 __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
1034 closesocket(s);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001035 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +00001036 }
Raphael Prevost48b60c32009-08-23 13:11:01 +02001037
1038 return (s);
Owen Taylor3473f882001-02-23 17:55:21 +00001039}
Raphael Prevost48b60c32009-08-23 13:11:01 +02001040
Owen Taylor3473f882001-02-23 17:55:21 +00001041/**
1042 * xmlNanoHTTPConnectHost:
1043 * @host: the host name
1044 * @port: the port number
1045 *
1046 * Attempt a connection to the given host:port endpoint. It tries
1047 * the multiple IP provided by the DNS if available.
1048 *
1049 * Returns -1 in case of failure, the file descriptor number otherwise
1050 */
1051
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001052static SOCKET
Owen Taylor3473f882001-02-23 17:55:21 +00001053xmlNanoHTTPConnectHost(const char *host, int port)
1054{
1055 struct hostent *h;
Daniel Veillard2db8c122003-07-08 12:16:59 +00001056 struct sockaddr *addr = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001057 struct in_addr ia;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001058 struct sockaddr_in sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001059
Owen Taylor3473f882001-02-23 17:55:21 +00001060#ifdef SUPPORT_IP6
1061 struct in6_addr ia6;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001062 struct sockaddr_in6 sockin6;
Owen Taylor3473f882001-02-23 17:55:21 +00001063#endif
1064 int i;
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001065 SOCKET s;
Daniel Veillard5c396542002-03-15 07:57:50 +00001066
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001067 memset (&sockin, 0, sizeof(sockin));
1068#ifdef SUPPORT_IP6
1069 memset (&sockin6, 0, sizeof(sockin6));
Rob Richardscb418de2005-10-13 23:12:42 +00001070#endif
1071
1072#if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001073 if (have_ipv6 ())
Daniel Veillard560c2a42003-07-06 21:13:49 +00001074 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001075 if (!(_res.options & RES_INIT))
1076 res_init();
1077 _res.options |= RES_USE_INET6;
1078 }
Rob Richardscb418de2005-10-13 23:12:42 +00001079#endif
1080
1081#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1082 if (have_ipv6 ())
1083#endif
1084#if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
Daniel Veillard560c2a42003-07-06 21:13:49 +00001085 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001086 int status;
1087 struct addrinfo hints, *res, *result;
1088
1089 result = NULL;
1090 memset (&hints, 0,sizeof(hints));
1091 hints.ai_socktype = SOCK_STREAM;
1092
1093 status = getaddrinfo (host, NULL, &hints, &result);
1094 if (status) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001095 __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001096 return INVALID_SOCKET;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001097 }
1098
1099 for (res = result; res; res = res->ai_next) {
Rob Richardscb418de2005-10-13 23:12:42 +00001100 if (res->ai_family == AF_INET) {
1101 if (res->ai_addrlen > sizeof(sockin)) {
1102 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001103 freeaddrinfo (result);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001104 return INVALID_SOCKET;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001105 }
Rob Richardscb418de2005-10-13 23:12:42 +00001106 memcpy (&sockin, res->ai_addr, res->ai_addrlen);
1107 sockin.sin_port = htons (port);
1108 addr = (struct sockaddr *)&sockin;
1109#ifdef SUPPORT_IP6
1110 } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
1111 if (res->ai_addrlen > sizeof(sockin6)) {
1112 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1113 freeaddrinfo (result);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001114 return INVALID_SOCKET;
Rob Richardscb418de2005-10-13 23:12:42 +00001115 }
1116 memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
1117 sockin6.sin6_port = htons (port);
1118 addr = (struct sockaddr *)&sockin6;
1119#endif
1120 } else
1121 continue; /* for */
1122
1123 s = xmlNanoHTTPConnectAttempt (addr);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001124 if (s != INVALID_SOCKET) {
Rob Richardscb418de2005-10-13 23:12:42 +00001125 freeaddrinfo (result);
1126 return (s);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001127 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001128 }
Rob Richardscb418de2005-10-13 23:12:42 +00001129
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001130 if (result)
1131 freeaddrinfo (result);
Rob Richardscb418de2005-10-13 23:12:42 +00001132 }
Owen Taylor3473f882001-02-23 17:55:21 +00001133#endif
Rob Richardscb418de2005-10-13 23:12:42 +00001134#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1135 else
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001136#endif
Rob Richardscb418de2005-10-13 23:12:42 +00001137#if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
1138 {
Patrick Monnerat437f4f52013-12-12 15:23:09 +08001139 h = gethostbyname (GETHOSTBYNAME_ARG_CAST host);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001140 if (h == NULL) {
Daniel Veillard56b2db72002-03-25 16:35:28 +00001141
1142/*
1143 * Okay, I got fed up by the non-portability of this error message
1144 * extraction code. it work on Linux, if it work on your platform
1145 * and one want to enable it, send me the defined(foobar) needed
1146 */
Nick Wellnhofer2cdaaab2017-09-14 21:30:51 +02001147#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(__linux__)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001148 const char *h_err_txt = "";
Daniel Veillardf012a642001-07-23 19:10:52 +00001149
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001150 switch (h_errno) {
1151 case HOST_NOT_FOUND:
1152 h_err_txt = "Authoritive host not found";
1153 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001154
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001155 case TRY_AGAIN:
1156 h_err_txt =
1157 "Non-authoritive host not found or server failure.";
1158 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001159
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001160 case NO_RECOVERY:
1161 h_err_txt =
1162 "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
1163 break;
Daniel Veillard5c396542002-03-15 07:57:50 +00001164
Daniel Veillardd95b6892012-04-02 17:48:53 +08001165#ifdef NO_ADDRESS
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001166 case NO_ADDRESS:
1167 h_err_txt =
1168 "Valid name, no data record of requested type.";
1169 break;
Daniel Veillardd95b6892012-04-02 17:48:53 +08001170#endif
Daniel Veillard5c396542002-03-15 07:57:50 +00001171
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001172 default:
1173 h_err_txt = "No error text defined.";
1174 break;
1175 }
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001176 __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
Daniel Veillard5c396542002-03-15 07:57:50 +00001177#else
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001178 __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
Owen Taylor3473f882001-02-23 17:55:21 +00001179#endif
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001180 return INVALID_SOCKET;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001181 }
Daniel Veillard5c396542002-03-15 07:57:50 +00001182
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001183 for (i = 0; h->h_addr_list[i]; i++) {
1184 if (h->h_addrtype == AF_INET) {
1185 /* A records (IPv4) */
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001186 if ((unsigned int) h->h_length > sizeof(ia)) {
1187 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001188 return INVALID_SOCKET;
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001189 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001190 memcpy (&ia, h->h_addr_list[i], h->h_length);
1191 sockin.sin_family = h->h_addrtype;
1192 sockin.sin_addr = ia;
Daniel Veillardac17e592012-04-02 15:45:13 +08001193 sockin.sin_port = (unsigned short)htons ((unsigned short)port);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001194 addr = (struct sockaddr *) &sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001195#ifdef SUPPORT_IP6
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001196 } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
1197 /* AAAA records (IPv6) */
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001198 if ((unsigned int) h->h_length > sizeof(ia6)) {
1199 __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001200 return INVALID_SOCKET;
Daniel Veillard8e2c9792004-10-27 09:39:50 +00001201 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001202 memcpy (&ia6, h->h_addr_list[i], h->h_length);
1203 sockin6.sin6_family = h->h_addrtype;
1204 sockin6.sin6_addr = ia6;
1205 sockin6.sin6_port = htons (port);
1206 addr = (struct sockaddr *) &sockin6;
Daniel Veillard5c396542002-03-15 07:57:50 +00001207#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001208 } else
1209 break; /* for */
Daniel Veillard5c396542002-03-15 07:57:50 +00001210
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001211 s = xmlNanoHTTPConnectAttempt (addr);
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001212 if (s != INVALID_SOCKET)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001213 return (s);
1214 }
Owen Taylor3473f882001-02-23 17:55:21 +00001215 }
Rob Richardscb418de2005-10-13 23:12:42 +00001216#endif
1217
Owen Taylor3473f882001-02-23 17:55:21 +00001218#ifdef DEBUG_HTTP
1219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard5c396542002-03-15 07:57:50 +00001220 "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",
1221 host);
Owen Taylor3473f882001-02-23 17:55:21 +00001222#endif
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001223 return INVALID_SOCKET;
Owen Taylor3473f882001-02-23 17:55:21 +00001224}
1225
1226
1227/**
1228 * xmlNanoHTTPOpen:
1229 * @URL: The URL to load
1230 * @contentType: if available the Content-Type information will be
1231 * returned at that location
1232 *
1233 * This function try to open a connection to the indicated resource
1234 * via HTTP GET.
1235 *
1236 * Returns NULL in case of failure, otherwise a request handler.
1237 * The contentType, if provided must be freed by the caller
1238 */
1239
1240void*
1241xmlNanoHTTPOpen(const char *URL, char **contentType) {
1242 if (contentType != NULL) *contentType = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001243 return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
Daniel Veillard9403a042001-05-28 11:00:53 +00001244}
1245
1246/**
1247 * xmlNanoHTTPOpenRedir:
1248 * @URL: The URL to load
1249 * @contentType: if available the Content-Type information will be
1250 * returned at that location
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001251 * @redir: if available the redirected URL will be returned
Daniel Veillard9403a042001-05-28 11:00:53 +00001252 *
1253 * This function try to open a connection to the indicated resource
1254 * via HTTP GET.
1255 *
1256 * Returns NULL in case of failure, otherwise a request handler.
1257 * The contentType, if provided must be freed by the caller
1258 */
1259
1260void*
1261xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
1262 if (contentType != NULL) *contentType = NULL;
1263 if (redir != NULL) *redir = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001264 return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
Owen Taylor3473f882001-02-23 17:55:21 +00001265}
1266
1267/**
1268 * xmlNanoHTTPRead:
1269 * @ctx: the HTTP context
1270 * @dest: a buffer
1271 * @len: the buffer length
1272 *
1273 * This function tries to read @len bytes from the existing HTTP connection
1274 * and saves them in @dest. This is a blocking call.
1275 *
1276 * Returns the number of byte read. 0 is an indication of an end of connection.
1277 * -1 indicates a parameter error.
1278 */
1279int
1280xmlNanoHTTPRead(void *ctx, void *dest, int len) {
1281 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001282#ifdef HAVE_ZLIB_H
1283 int bytes_read = 0;
1284 int orig_avail_in;
1285 int z_ret;
1286#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001287
1288 if (ctx == NULL) return(-1);
1289 if (dest == NULL) return(-1);
1290 if (len <= 0) return(0);
1291
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001292#ifdef HAVE_ZLIB_H
1293 if (ctxt->usesGzip == 1) {
1294 if (ctxt->strm == NULL) return(0);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001295
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001296 ctxt->strm->next_out = dest;
1297 ctxt->strm->avail_out = len;
William M. Bracke8827652007-05-16 05:19:13 +00001298 ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001299
William M. Bracke8827652007-05-16 05:19:13 +00001300 while (ctxt->strm->avail_out > 0 &&
1301 (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
William M. Brackd2f682a2007-05-15 19:42:08 +00001302 orig_avail_in = ctxt->strm->avail_in =
1303 ctxt->inptr - ctxt->inrptr - bytes_read;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001304 ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
1305
1306 z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
1307 bytes_read += orig_avail_in - ctxt->strm->avail_in;
1308
1309 if (z_ret != Z_OK) break;
William M. Brackd2f682a2007-05-15 19:42:08 +00001310 }
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001311
1312 ctxt->inrptr += bytes_read;
1313 return(len - ctxt->strm->avail_out);
1314 }
1315#endif
1316
Owen Taylor3473f882001-02-23 17:55:21 +00001317 while (ctxt->inptr - ctxt->inrptr < len) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001318 if (xmlNanoHTTPRecv(ctxt) <= 0) break;
Owen Taylor3473f882001-02-23 17:55:21 +00001319 }
1320 if (ctxt->inptr - ctxt->inrptr < len)
1321 len = ctxt->inptr - ctxt->inrptr;
1322 memcpy(dest, ctxt->inrptr, len);
1323 ctxt->inrptr += len;
1324 return(len);
1325}
1326
1327/**
1328 * xmlNanoHTTPClose:
1329 * @ctx: the HTTP context
1330 *
1331 * This function closes an HTTP context, it ends up the connection and
1332 * free all data related to it.
1333 */
1334void
1335xmlNanoHTTPClose(void *ctx) {
1336 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1337
1338 if (ctx == NULL) return;
1339
1340 xmlNanoHTTPFreeCtxt(ctxt);
1341}
1342
1343/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001344 * xmlNanoHTTPMethodRedir:
Owen Taylor3473f882001-02-23 17:55:21 +00001345 * @URL: The URL to load
1346 * @method: the HTTP method to use
1347 * @input: the input string if any
1348 * @contentType: the Content-Type information IN and OUT
Daniel Veillard9403a042001-05-28 11:00:53 +00001349 * @redir: the redirected URL OUT
Owen Taylor3473f882001-02-23 17:55:21 +00001350 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001351 * @ilen: input length
Owen Taylor3473f882001-02-23 17:55:21 +00001352 *
1353 * This function try to open a connection to the indicated resource
1354 * via HTTP using the given @method, adding the given extra headers
1355 * and the input buffer for the request content.
1356 *
1357 * Returns NULL in case of failure, otherwise a request handler.
Daniel Veillard9403a042001-05-28 11:00:53 +00001358 * The contentType, or redir, if provided must be freed by the caller
Owen Taylor3473f882001-02-23 17:55:21 +00001359 */
1360
1361void*
Daniel Veillard9403a042001-05-28 11:00:53 +00001362xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001363 char **contentType, char **redir,
1364 const char *headers, int ilen ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001365 xmlNanoHTTPCtxtPtr ctxt;
1366 char *bp, *p;
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001367 int blen;
1368 SOCKET ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001369 int nbRedirects = 0;
1370 char *redirURL = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001371#ifdef DEBUG_HTTP
1372 int xmt_bytes;
1373#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001374
Owen Taylor3473f882001-02-23 17:55:21 +00001375 if (URL == NULL) return(NULL);
1376 if (method == NULL) method = "GET";
1377 xmlNanoHTTPInit();
1378
1379retry:
Gaurav Gupta1811add2014-07-14 17:50:27 +08001380 if (redirURL == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001381 ctxt = xmlNanoHTTPNewCtxt(URL);
Gaurav Gupta1811add2014-07-14 17:50:27 +08001382 if (ctxt == NULL)
1383 return(NULL);
1384 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00001385 ctxt = xmlNanoHTTPNewCtxt(redirURL);
Gaurav Gupta1811add2014-07-14 17:50:27 +08001386 if (ctxt == NULL)
1387 return(NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00001388 ctxt->location = xmlMemStrdup(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001389 }
1390
1391 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001392 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
Owen Taylor3473f882001-02-23 17:55:21 +00001393 xmlNanoHTTPFreeCtxt(ctxt);
1394 if (redirURL != NULL) xmlFree(redirURL);
1395 return(NULL);
1396 }
1397 if (ctxt->hostname == NULL) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001398 __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
1399 "Failed to identify host in URI");
Owen Taylor3473f882001-02-23 17:55:21 +00001400 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001401 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001402 return(NULL);
1403 }
1404 if (proxy) {
1405 blen = strlen(ctxt->hostname) * 2 + 16;
1406 ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
1407 }
1408 else {
1409 blen = strlen(ctxt->hostname);
1410 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1411 }
Ozkan Sezerf99d2222010-11-04 12:08:08 +01001412 if (ret == INVALID_SOCKET) {
Owen Taylor3473f882001-02-23 17:55:21 +00001413 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001414 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001415 return(NULL);
1416 }
1417 ctxt->fd = ret;
1418
Daniel Veillardf012a642001-07-23 19:10:52 +00001419 if (input == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001420 ilen = 0;
Daniel Veillardf012a642001-07-23 19:10:52 +00001421 else
1422 blen += 36;
1423
Owen Taylor3473f882001-02-23 17:55:21 +00001424 if (headers != NULL)
Daniel Veillardf012a642001-07-23 19:10:52 +00001425 blen += strlen(headers) + 2;
Owen Taylor3473f882001-02-23 17:55:21 +00001426 if (contentType && *contentType)
William M. Brackead35832008-02-06 04:12:46 +00001427 /* reserve for string plus 'Content-Type: \r\n" */
Owen Taylor3473f882001-02-23 17:55:21 +00001428 blen += strlen(*contentType) + 16;
Daniel Veillard351f2d62005-04-13 02:55:12 +00001429 if (ctxt->query != NULL)
William M. Brackead35832008-02-06 04:12:46 +00001430 /* 1 for '?' */
Daniel Veillard351f2d62005-04-13 02:55:12 +00001431 blen += strlen(ctxt->query) + 1;
Daniel Veillardf012a642001-07-23 19:10:52 +00001432 blen += strlen(method) + strlen(ctxt->path) + 24;
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001433#ifdef HAVE_ZLIB_H
William M. Brackead35832008-02-06 04:12:46 +00001434 /* reserve for possible 'Accept-Encoding: gzip' string */
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001435 blen += 23;
1436#endif
William M. Brackead35832008-02-06 04:12:46 +00001437 if (ctxt->port != 80) {
1438 /* reserve space for ':xxxxx', incl. potential proxy */
1439 if (proxy)
Daniel Veillard5dca9ee2017-04-07 17:13:28 +02001440 blen += 17;
William M. Brackead35832008-02-06 04:12:46 +00001441 else
Daniel Veillard5dca9ee2017-04-07 17:13:28 +02001442 blen += 11;
William M. Brackead35832008-02-06 04:12:46 +00001443 }
Daniel Veillard82cb3192003-10-29 13:39:15 +00001444 bp = (char*)xmlMallocAtomic(blen);
Daniel Veillardf012a642001-07-23 19:10:52 +00001445 if ( bp == NULL ) {
1446 xmlNanoHTTPFreeCtxt( ctxt );
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001447 xmlHTTPErrMemory("allocating header buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001448 return ( NULL );
1449 }
1450
1451 p = bp;
1452
Owen Taylor3473f882001-02-23 17:55:21 +00001453 if (proxy) {
1454 if (ctxt->port != 80) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001455 p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s",
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001456 method, ctxt->hostname,
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001457 ctxt->port, ctxt->path );
Owen Taylor3473f882001-02-23 17:55:21 +00001458 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001459 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001460 p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001461 ctxt->hostname, ctxt->path);
Owen Taylor3473f882001-02-23 17:55:21 +00001462 }
1463 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001464 p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
Daniel Veillardf012a642001-07-23 19:10:52 +00001465
Daniel Veillard351f2d62005-04-13 02:55:12 +00001466 if (ctxt->query != NULL)
1467 p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
1468
William M. Brackec720082007-08-24 02:57:38 +00001469 if (ctxt->port == 80) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001470 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001471 ctxt->hostname);
William M. Brackec720082007-08-24 02:57:38 +00001472 } else {
1473 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
1474 ctxt->hostname, ctxt->port);
1475 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001476
Daniel Veillard9a2724d2005-12-15 11:12:26 +00001477#ifdef HAVE_ZLIB_H
1478 p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
1479#endif
1480
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001481 if (contentType != NULL && *contentType)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001482 p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
Daniel Veillardf012a642001-07-23 19:10:52 +00001483
1484 if (headers != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001485 p += snprintf( p, blen - (p - bp), "%s", headers );
Daniel Veillardf012a642001-07-23 19:10:52 +00001486
Owen Taylor3473f882001-02-23 17:55:21 +00001487 if (input != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001488 snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
Owen Taylor3473f882001-02-23 17:55:21 +00001489 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001490 snprintf(p, blen - (p - bp), "\r\n");
Daniel Veillardf012a642001-07-23 19:10:52 +00001491
Owen Taylor3473f882001-02-23 17:55:21 +00001492#ifdef DEBUG_HTTP
1493 xmlGenericError(xmlGenericErrorContext,
1494 "-> %s%s", proxy? "(Proxy) " : "", bp);
1495 if ((blen -= strlen(bp)+1) < 0)
1496 xmlGenericError(xmlGenericErrorContext,
1497 "ERROR: overflowed buffer by %d bytes\n", -blen);
1498#endif
1499 ctxt->outptr = ctxt->out = bp;
1500 ctxt->state = XML_NANO_HTTP_WRITE;
Daniel Veillardf012a642001-07-23 19:10:52 +00001501 blen = strlen( ctxt->out );
Daniel Veillardf012a642001-07-23 19:10:52 +00001502#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001503 xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001504 if ( xmt_bytes != blen )
1505 xmlGenericError( xmlGenericErrorContext,
1506 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1507 xmt_bytes, blen,
1508 "bytes of HTTP headers sent to host",
1509 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001510#else
1511 xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001512#endif
1513
1514 if ( input != NULL ) {
William M. Brack78637da2003-07-31 14:47:38 +00001515#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001516 xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
1517
Daniel Veillardf012a642001-07-23 19:10:52 +00001518 if ( xmt_bytes != ilen )
1519 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001520 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001521 xmt_bytes, ilen,
1522 "bytes of HTTP content sent to host",
1523 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001524#else
1525 xmlNanoHTTPSend( ctxt, input, ilen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001526#endif
1527 }
1528
Owen Taylor3473f882001-02-23 17:55:21 +00001529 ctxt->state = XML_NANO_HTTP_READ;
Owen Taylor3473f882001-02-23 17:55:21 +00001530
1531 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
Daniel Veillard594e5df2009-09-07 14:58:47 +02001532 if (*p == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00001533 ctxt->content = ctxt->inrptr;
1534 xmlFree(p);
1535 break;
1536 }
1537 xmlNanoHTTPScanAnswer(ctxt, p);
1538
1539#ifdef DEBUG_HTTP
1540 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
1541#endif
1542 xmlFree(p);
1543 }
1544
1545 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1546 (ctxt->returnValue < 400)) {
1547#ifdef DEBUG_HTTP
1548 xmlGenericError(xmlGenericErrorContext,
1549 "\nRedirect to: %s\n", ctxt->location);
1550#endif
Nick Wellnhofer629e47e2017-06-17 14:51:10 +02001551 while ( xmlNanoHTTPRecv(ctxt) > 0 )
1552 ;
Owen Taylor3473f882001-02-23 17:55:21 +00001553 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1554 nbRedirects++;
Daniel Veillard9403a042001-05-28 11:00:53 +00001555 if (redirURL != NULL)
1556 xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001557 redirURL = xmlMemStrdup(ctxt->location);
1558 xmlNanoHTTPFreeCtxt(ctxt);
1559 goto retry;
1560 }
1561 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001562 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001563#ifdef DEBUG_HTTP
1564 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00001565 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001566#endif
1567 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001568 }
1569
1570 if (contentType != NULL) {
1571 if (ctxt->contentType != NULL)
1572 *contentType = xmlMemStrdup(ctxt->contentType);
1573 else
1574 *contentType = NULL;
1575 }
1576
Daniel Veillard9403a042001-05-28 11:00:53 +00001577 if ((redir != NULL) && (redirURL != NULL)) {
1578 *redir = redirURL;
1579 } else {
1580 if (redirURL != NULL)
1581 xmlFree(redirURL);
1582 if (redir != NULL)
1583 *redir = NULL;
1584 }
1585
Owen Taylor3473f882001-02-23 17:55:21 +00001586#ifdef DEBUG_HTTP
1587 if (ctxt->contentType != NULL)
1588 xmlGenericError(xmlGenericErrorContext,
1589 "\nCode %d, content-type '%s'\n\n",
1590 ctxt->returnValue, ctxt->contentType);
1591 else
1592 xmlGenericError(xmlGenericErrorContext,
1593 "\nCode %d, no content-type\n\n",
1594 ctxt->returnValue);
1595#endif
1596
1597 return((void *) ctxt);
1598}
1599
1600/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001601 * xmlNanoHTTPMethod:
1602 * @URL: The URL to load
1603 * @method: the HTTP method to use
1604 * @input: the input string if any
1605 * @contentType: the Content-Type information IN and OUT
1606 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001607 * @ilen: input length
Daniel Veillard9403a042001-05-28 11:00:53 +00001608 *
1609 * This function try to open a connection to the indicated resource
1610 * via HTTP using the given @method, adding the given extra headers
1611 * and the input buffer for the request content.
1612 *
1613 * Returns NULL in case of failure, otherwise a request handler.
1614 * The contentType, if provided must be freed by the caller
1615 */
1616
1617void*
1618xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001619 char **contentType, const char *headers, int ilen) {
Daniel Veillard9403a042001-05-28 11:00:53 +00001620 return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
Daniel Veillardf012a642001-07-23 19:10:52 +00001621 NULL, headers, ilen));
Daniel Veillard9403a042001-05-28 11:00:53 +00001622}
1623
1624/**
Owen Taylor3473f882001-02-23 17:55:21 +00001625 * xmlNanoHTTPFetch:
1626 * @URL: The URL to load
1627 * @filename: the filename where the content should be saved
1628 * @contentType: if available the Content-Type information will be
1629 * returned at that location
1630 *
1631 * This function try to fetch the indicated resource via HTTP GET
1632 * and save it's content in the file.
1633 *
1634 * Returns -1 in case of failure, 0 incase of success. The contentType,
1635 * if provided must be freed by the caller
1636 */
1637int
1638xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001639 void *ctxt = NULL;
1640 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001641 int fd;
1642 int len;
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001643 int ret = 0;
1644
William M. Brack015ccb22005-02-13 08:18:52 +00001645 if (filename == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001646 ctxt = xmlNanoHTTPOpen(URL, contentType);
1647 if (ctxt == NULL) return(-1);
1648
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001649 if (!strcmp(filename, "-"))
Owen Taylor3473f882001-02-23 17:55:21 +00001650 fd = 0;
1651 else {
1652 fd = open(filename, O_CREAT | O_WRONLY, 00644);
1653 if (fd < 0) {
1654 xmlNanoHTTPClose(ctxt);
1655 if ((contentType != NULL) && (*contentType != NULL)) {
1656 xmlFree(*contentType);
1657 *contentType = NULL;
1658 }
1659 return(-1);
1660 }
1661 }
1662
Daniel Veillardf012a642001-07-23 19:10:52 +00001663 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1664 if ( len > 0 ) {
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001665 if (write(fd, buf, len) == -1) {
1666 ret = -1;
1667 }
Owen Taylor3473f882001-02-23 17:55:21 +00001668 }
1669
1670 xmlNanoHTTPClose(ctxt);
1671 close(fd);
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001672 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001673}
1674
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001675#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001676/**
1677 * xmlNanoHTTPSave:
1678 * @ctxt: the HTTP context
1679 * @filename: the filename where the content should be saved
1680 *
1681 * This function saves the output of the HTTP transaction to a file
1682 * It closes and free the context at the end
1683 *
1684 * Returns -1 in case of failure, 0 incase of success.
1685 */
1686int
1687xmlNanoHTTPSave(void *ctxt, const char *filename) {
Daniel Veillarde3924972001-07-25 20:25:21 +00001688 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001689 int fd;
1690 int len;
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001691 int ret = 0;
1692
William M. Brack015ccb22005-02-13 08:18:52 +00001693 if ((ctxt == NULL) || (filename == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001694
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001695 if (!strcmp(filename, "-"))
Owen Taylor3473f882001-02-23 17:55:21 +00001696 fd = 0;
1697 else {
Daniel Veillardcd2ebab2007-08-23 20:47:33 +00001698 fd = open(filename, O_CREAT | O_WRONLY, 0666);
Owen Taylor3473f882001-02-23 17:55:21 +00001699 if (fd < 0) {
1700 xmlNanoHTTPClose(ctxt);
1701 return(-1);
1702 }
1703 }
1704
Daniel Veillardf012a642001-07-23 19:10:52 +00001705 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1706 if ( len > 0 ) {
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001707 if (write(fd, buf, len) == -1) {
1708 ret = -1;
1709 }
Owen Taylor3473f882001-02-23 17:55:21 +00001710 }
1711
1712 xmlNanoHTTPClose(ctxt);
William M. Brack20d82362004-03-17 08:44:46 +00001713 close(fd);
Stefan Kostdff8d0f2011-05-09 12:14:59 +03001714 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001715}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001716#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001717
1718/**
1719 * xmlNanoHTTPReturnCode:
1720 * @ctx: the HTTP context
1721 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001722 * Get the latest HTTP return code received
1723 *
Owen Taylor3473f882001-02-23 17:55:21 +00001724 * Returns the HTTP return code for the request.
1725 */
1726int
1727xmlNanoHTTPReturnCode(void *ctx) {
1728 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1729
1730 if (ctxt == NULL) return(-1);
1731
1732 return(ctxt->returnValue);
1733}
1734
1735/**
1736 * xmlNanoHTTPAuthHeader:
1737 * @ctx: the HTTP context
1738 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001739 * Get the authentication header of an HTTP context
1740 *
Owen Taylor3473f882001-02-23 17:55:21 +00001741 * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
1742 * header.
1743 */
1744const char *
1745xmlNanoHTTPAuthHeader(void *ctx) {
1746 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1747
1748 if (ctxt == NULL) return(NULL);
1749
1750 return(ctxt->authHeader);
1751}
1752
Daniel Veillardf012a642001-07-23 19:10:52 +00001753/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001754 * xmlNanoHTTPContentLength:
Daniel Veillardf012a642001-07-23 19:10:52 +00001755 * @ctx: the HTTP context
1756 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001757 * Provides the specified content length from the HTTP header.
1758 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001759 * Return the specified content length from the HTTP header. Note that
1760 * a value of -1 indicates that the content length element was not included in
1761 * the response header.
1762 */
1763int
1764xmlNanoHTTPContentLength( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001765 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillardf012a642001-07-23 19:10:52 +00001766
1767 return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
1768}
1769
1770/**
Daniel Veillard847332a2003-10-18 11:29:40 +00001771 * xmlNanoHTTPRedir:
1772 * @ctx: the HTTP context
1773 *
1774 * Provides the specified redirection URL if available from the HTTP header.
1775 *
1776 * Return the specified redirection URL or NULL if not redirected.
1777 */
1778const char *
1779xmlNanoHTTPRedir( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001780 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillard847332a2003-10-18 11:29:40 +00001781
1782 return ( ( ctxt == NULL ) ? NULL : ctxt->location );
1783}
1784
1785/**
1786 * xmlNanoHTTPEncoding:
1787 * @ctx: the HTTP context
1788 *
1789 * Provides the specified encoding if specified in the HTTP headers.
1790 *
1791 * Return the specified encoding or NULL if not available
1792 */
1793const char *
1794xmlNanoHTTPEncoding( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001795 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillard847332a2003-10-18 11:29:40 +00001796
1797 return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
1798}
1799
1800/**
Daniel Veillarda840b692003-10-19 13:35:37 +00001801 * xmlNanoHTTPMimeType:
1802 * @ctx: the HTTP context
1803 *
1804 * Provides the specified Mime-Type if specified in the HTTP headers.
1805 *
1806 * Return the specified Mime-Type or NULL if not available
1807 */
1808const char *
1809xmlNanoHTTPMimeType( void * ctx ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001810 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillarda840b692003-10-19 13:35:37 +00001811
1812 return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
1813}
1814
1815/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001816 * xmlNanoHTTPFetchContent:
Daniel Veillardf012a642001-07-23 19:10:52 +00001817 * @ctx: the HTTP context
1818 * @ptr: pointer to set to the content buffer.
1819 * @len: integer pointer to hold the length of the content
1820 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001821 * Check if all the content was read
1822 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001823 * Returns 0 if all the content was read and available, returns
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001824 * -1 if received content length was less than specified or an error
Daniel Veillardf012a642001-07-23 19:10:52 +00001825 * occurred.
1826 */
Daniel Veillarda2351322004-06-27 12:08:10 +00001827static int
Daniel Veillardf012a642001-07-23 19:10:52 +00001828xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00001829 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr)ctx;
Daniel Veillardf012a642001-07-23 19:10:52 +00001830
1831 int rc = 0;
1832 int cur_lgth;
1833 int rcvd_lgth;
1834 int dummy_int;
1835 char * dummy_ptr = NULL;
1836
1837 /* Dummy up return input parameters if not provided */
1838
1839 if ( len == NULL )
1840 len = &dummy_int;
1841
1842 if ( ptr == NULL )
1843 ptr = &dummy_ptr;
1844
1845 /* But can't work without the context pointer */
1846
1847 if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
1848 *len = 0;
1849 *ptr = NULL;
1850 return ( -1 );
1851 }
1852
1853 rcvd_lgth = ctxt->inptr - ctxt->content;
1854
1855 while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
1856
1857 rcvd_lgth += cur_lgth;
1858 if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
1859 break;
1860 }
1861
1862 *ptr = ctxt->content;
1863 *len = rcvd_lgth;
1864
1865 if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
1866 rc = -1;
1867 else if ( rcvd_lgth == 0 )
1868 rc = -1;
1869
1870 return ( rc );
1871}
1872
Owen Taylor3473f882001-02-23 17:55:21 +00001873#ifdef STANDALONE
1874int main(int argc, char **argv) {
1875 char *contentType = NULL;
1876
1877 if (argv[1] != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001878 if (argv[2] != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001879 xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1880 else
1881 xmlNanoHTTPFetch(argv[1], "-", &contentType);
1882 if (contentType != NULL) xmlFree(contentType);
1883 } else {
1884 xmlGenericError(xmlGenericErrorContext,
1885 "%s: minimal HTTP GET implementation\n", argv[0]);
1886 xmlGenericError(xmlGenericErrorContext,
1887 "\tusage %s [ URL [ filename ] ]\n", argv[0]);
1888 }
1889 xmlNanoHTTPCleanup();
1890 xmlMemoryDump();
1891 return(0);
1892}
1893#endif /* STANDALONE */
1894#else /* !LIBXML_HTTP_ENABLED */
1895#ifdef STANDALONE
1896#include <stdio.h>
1897int main(int argc, char **argv) {
1898 xmlGenericError(xmlGenericErrorContext,
1899 "%s : HTTP support not compiled in\n", argv[0]);
1900 return(0);
1901}
1902#endif /* STANDALONE */
1903#endif /* LIBXML_HTTP_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001904#define bottom_nanohttp
1905#include "elfgcchack.h"