blob: 5072d37f40f91254a6aff11b020f8cc67dc2f5a9 [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
14/* TODO add compression support, Send the Accept- , and decompress on the
15 fly with ZLIB if found at compile-time */
16
Daniel Veillardf3afa7d2001-06-09 13:52:58 +000017#define NEED_SOCKETS
Daniel Veillard34ce8be2002-03-18 19:37:11 +000018#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020
21#ifdef LIBXML_HTTP_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_STDLIB_H
25#include <stdlib.h>
26#endif
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
Daniel Veillard75eb1ad2003-07-07 14:42:44 +000030#ifdef HAVE_SYS_TYPES_H
31#include <sys/types.h>
32#endif
Owen Taylor3473f882001-02-23 17:55:21 +000033#ifdef HAVE_SYS_SOCKET_H
34#include <sys/socket.h>
35#endif
36#ifdef HAVE_NETINET_IN_H
37#include <netinet/in.h>
38#endif
39#ifdef HAVE_ARPA_INET_H
40#include <arpa/inet.h>
41#endif
42#ifdef HAVE_NETDB_H
43#include <netdb.h>
44#endif
Daniel Veillardd85f4f42002-03-25 10:48:46 +000045#ifdef HAVE_RESOLV_H
Daniel Veillard9b731d72002-04-14 12:56:08 +000046#ifdef HAVE_ARPA_NAMESER_H
47#include <arpa/nameser.h>
48#endif
Daniel Veillardd85f4f42002-03-25 10:48:46 +000049#include <resolv.h>
50#endif
Owen Taylor3473f882001-02-23 17:55:21 +000051#ifdef HAVE_FCNTL_H
52#include <fcntl.h>
53#endif
54#ifdef HAVE_ERRNO_H
55#include <errno.h>
56#endif
57#ifdef HAVE_SYS_TIME_H
58#include <sys/time.h>
59#endif
60#ifdef HAVE_SYS_SELECT_H
61#include <sys/select.h>
62#endif
63#ifdef HAVE_STRINGS_H
64#include <strings.h>
65#endif
66#ifdef SUPPORT_IP6
67#include <resolv.h>
68#endif
69
70#ifdef VMS
71#include <stropts>
72#define SOCKLEN_T unsigned int
73#define SOCKET int
74#endif
75
Daniel Veillard1638a472003-08-14 01:23:25 +000076
77#ifdef __MINGW32__
78#define _WINSOCKAPI_
79#include <wsockcompat.h>
80#include <winsock2.h>
81#undef SOCKLEN_T
82#define SOCKLEN_T unsigned int
83#endif
84
85
Daniel Veillardd0463562001-10-13 09:15:48 +000086#include <libxml/globals.h>
Daniel Veillardf012a642001-07-23 19:10:52 +000087#include <libxml/xmlerror.h>
Owen Taylor3473f882001-02-23 17:55:21 +000088#include <libxml/xmlmemory.h>
89#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
90#include <libxml/nanohttp.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000091#include <libxml/globals.h>
Daniel Veillard8efff672002-12-04 11:44:48 +000092#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000093
94/**
95 * A couple portability macros
96 */
97#ifndef _WINSOCKAPI_
Daniel Veillarda9cce9c2003-09-29 13:20:24 +000098#ifndef __BEOS__
Owen Taylor3473f882001-02-23 17:55:21 +000099#define closesocket(s) close(s)
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000100#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000101#define SOCKET int
102#endif
103
Daniel Veillard75be0132002-03-13 10:03:35 +0000104#ifndef SOCKLEN_T
105#define SOCKLEN_T unsigned int
106#endif
107#ifndef SOCKET
108#define SOCKET int
109#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000110
Owen Taylor3473f882001-02-23 17:55:21 +0000111#ifdef STANDALONE
112#define DEBUG_HTTP
113#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
114#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
115#endif
116
117#define XML_NANO_HTTP_MAX_REDIR 10
118
119#define XML_NANO_HTTP_CHUNK 4096
120
121#define XML_NANO_HTTP_CLOSED 0
122#define XML_NANO_HTTP_WRITE 1
123#define XML_NANO_HTTP_READ 2
124#define XML_NANO_HTTP_NONE 4
125
126typedef struct xmlNanoHTTPCtxt {
127 char *protocol; /* the protocol name */
128 char *hostname; /* the host name */
129 int port; /* the port */
130 char *path; /* the path within the URL */
131 SOCKET fd; /* the file descriptor for the socket */
132 int state; /* WRITE / READ / CLOSED */
133 char *out; /* buffer sent (zero terminated) */
134 char *outptr; /* index within the buffer sent */
135 char *in; /* the receiving buffer */
136 char *content; /* the start of the content */
137 char *inptr; /* the next byte to read from network */
138 char *inrptr; /* the next byte to give back to the client */
139 int inlen; /* len of the input buffer */
140 int last; /* return code for last operation */
141 int returnValue; /* the protocol return value */
Daniel Veillardf012a642001-07-23 19:10:52 +0000142 int ContentLength; /* specified content length from HTTP header */
Owen Taylor3473f882001-02-23 17:55:21 +0000143 char *contentType; /* the MIME type for the input */
144 char *location; /* the new URL in case of redirect */
145 char *authHeader; /* contents of {WWW,Proxy}-Authenticate header */
146} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
147
148static int initialized = 0;
149static char *proxy = NULL; /* the proxy name if any */
150static int proxyPort; /* the proxy port if any */
151static unsigned int timeout = 60;/* the select() timeout in seconds */
152
Daniel Veillardf012a642001-07-23 19:10:52 +0000153int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
154int xmlNanoHTTPContentLength( void * ctx );
155
Owen Taylor3473f882001-02-23 17:55:21 +0000156/**
157 * A portability function
158 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000159static int socket_errno(void) {
Owen Taylor3473f882001-02-23 17:55:21 +0000160#ifdef _WINSOCKAPI_
161 return(WSAGetLastError());
162#else
163 return(errno);
164#endif
165}
166
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000167#ifdef SUPPORT_IP6
Daniel Veillard2db8c122003-07-08 12:16:59 +0000168static
169int have_ipv6(void) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000170 int s;
171
172 s = socket (AF_INET6, SOCK_STREAM, 0);
173 if (s != -1) {
174 close (s);
175 return (1);
176 }
177 return (0);
178}
179#endif
180
Owen Taylor3473f882001-02-23 17:55:21 +0000181/**
182 * xmlNanoHTTPInit:
183 *
184 * Initialize the HTTP protocol layer.
185 * Currently it just checks for proxy informations
186 */
187
188void
189xmlNanoHTTPInit(void) {
190 const char *env;
191#ifdef _WINSOCKAPI_
192 WSADATA wsaData;
193#endif
194
195 if (initialized)
196 return;
197
198#ifdef _WINSOCKAPI_
199 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
200 return;
201#endif
202
203 if (proxy == NULL) {
204 proxyPort = 80;
205 env = getenv("no_proxy");
206 if (env != NULL)
207 goto done;
208 env = getenv("http_proxy");
209 if (env != NULL) {
210 xmlNanoHTTPScanProxy(env);
211 goto done;
212 }
213 env = getenv("HTTP_PROXY");
214 if (env != NULL) {
215 xmlNanoHTTPScanProxy(env);
216 goto done;
217 }
218 }
219done:
220 initialized = 1;
221}
222
223/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000224 * xmlNanoHTTPCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +0000225 *
226 * Cleanup the HTTP protocol layer.
227 */
228
229void
230xmlNanoHTTPCleanup(void) {
231 if (proxy != NULL)
232 xmlFree(proxy);
233#ifdef _WINSOCKAPI_
234 if (initialized)
235 WSACleanup();
236#endif
237 initialized = 0;
238 return;
239}
240
241/**
Owen Taylor3473f882001-02-23 17:55:21 +0000242 * xmlNanoHTTPScanURL:
243 * @ctxt: an HTTP context
244 * @URL: The URL used to initialize the context
245 *
246 * (Re)Initialize an HTTP context by parsing the URL and finding
247 * the protocol host port and path it indicates.
248 */
249
250static void
251xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
252 const char *cur = URL;
253 char buf[4096];
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000254 int indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000255 int port = 0;
256
257 if (ctxt->protocol != NULL) {
258 xmlFree(ctxt->protocol);
259 ctxt->protocol = NULL;
260 }
261 if (ctxt->hostname != NULL) {
262 xmlFree(ctxt->hostname);
263 ctxt->hostname = NULL;
264 }
265 if (ctxt->path != NULL) {
266 xmlFree(ctxt->path);
267 ctxt->path = NULL;
268 }
269 if (URL == NULL) return;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000270 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000271 while (*cur != 0) {
272 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000274 ctxt->protocol = xmlMemStrdup(buf);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000275 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000276 cur += 3;
277 break;
278 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000279 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000280 }
281 if (*cur == 0) return;
282
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000283 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000284 while (1) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000285 if ((strchr (cur, '[') && !strchr (cur, ']')) ||
286 (!strchr (cur, '[') && strchr (cur, ']'))) {
287 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanURL: %s",
288 "Syntax Error\n");
289 return;
290 }
291
292 if (cur[0] == '[') {
293 cur++;
294 while (cur[0] != ']')
295 buf[indx++] = *cur++;
296
297 if (!strchr (buf, ':')) {
298 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanURL: %s",
299 "Use [IPv6]/IPv4 format\n");
300 return;
301 }
302
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000303 buf[indx] = 0;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000304 ctxt->hostname = xmlMemStrdup (buf);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000305 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000306 cur += 1;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000307 if (cur[0] == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +0000308 cur++;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000309 while (*cur >= '0' && *cur <= '9') {
310 port *= 10;
311 port += *cur - '0';
312 cur++;
313 }
314
315 if (port != 0) ctxt->port = port;
316 while ((cur[0] != '/') && (*cur != 0))
317 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000318 }
Owen Taylor3473f882001-02-23 17:55:21 +0000319 break;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000320 }
321 else {
322 if (cur[0] == ':') {
323 buf[indx] = 0;
324 ctxt->hostname = xmlMemStrdup (buf);
325 indx = 0;
326 cur += 1;
327 while ((*cur >= '0') && (*cur <= '9')) {
328 port *= 10;
329 port += *cur - '0';
330 cur++;
331 }
332 if (port != 0) ctxt->port = port;
333 while ((cur[0] != '/') && (*cur != 0))
334 cur++;
335 break;
336 }
337 if ((*cur == '/') || (*cur == 0)) {
338 buf[indx] = 0;
339 ctxt->hostname = xmlMemStrdup (buf);
340 indx = 0;
341 break;
342 }
Owen Taylor3473f882001-02-23 17:55:21 +0000343 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000344 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000345 }
346 if (*cur == 0)
347 ctxt->path = xmlMemStrdup("/");
348 else {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000349 indx = 0;
350 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000351 while (*cur != 0)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000352 buf[indx++] = *cur++;
353 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000354 ctxt->path = xmlMemStrdup(buf);
355 }
356}
357
358/**
359 * xmlNanoHTTPScanProxy:
360 * @URL: The proxy URL used to initialize the proxy context
361 *
362 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
363 * the protocol host port it indicates.
364 * Should be like http://myproxy/ or http://myproxy:3128/
365 * A NULL URL cleans up proxy informations.
366 */
367
368void
369xmlNanoHTTPScanProxy(const char *URL) {
370 const char *cur = URL;
371 char buf[4096];
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000372 int indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000373 int port = 0;
374
375 if (proxy != NULL) {
376 xmlFree(proxy);
377 proxy = NULL;
378 }
379 if (proxyPort != 0) {
380 proxyPort = 0;
381 }
382#ifdef DEBUG_HTTP
383 if (URL == NULL)
384 xmlGenericError(xmlGenericErrorContext,
385 "Removing HTTP proxy info\n");
386 else
387 xmlGenericError(xmlGenericErrorContext,
388 "Using HTTP proxy %s\n", URL);
389#endif
390 if (URL == NULL) return;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000391 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000392 while (*cur != 0) {
393 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000394 buf[indx] = 0;
395 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000396 cur += 3;
397 break;
398 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000399 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000400 }
401 if (*cur == 0) return;
402
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000403 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000404 while (1) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000405 if ((strchr (cur, '[') && !strchr (cur, ']')) ||
406 (!strchr (cur, '[') && strchr (cur, ']'))) {
407 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanProxy: %s",
408 "Syntax error\n");
409 return;
410 }
411
412 if (cur[0] == '[') {
413 cur++;
414 while (cur[0] != ']')
415 buf[indx++] = *cur++;
416
417 if (!strchr (buf, ':')) {
418 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanProxy: %s",
419 "Use [IPv6]/IPv4 format\n");
420 return;
421 }
422
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000423 buf[indx] = 0;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000424 proxy = xmlMemStrdup (buf);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000425 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000426 cur += 1;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000427 if (cur[0] == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +0000428 cur++;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000429 while (*cur >= '0' && *cur <= '9') {
430 port *= 10;
431 port += *cur - '0';
432 cur++;
433 }
434
435 if (port != 0) proxyPort = port;
436 while ((cur[0] != '/') && (*cur != 0))
437 cur ++;
438 }
Owen Taylor3473f882001-02-23 17:55:21 +0000439 break;
440 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000441 else {
442 if (cur[0] == ':') {
443 buf[indx] = 0;
444 proxy = xmlMemStrdup (buf);
445 indx = 0;
446 cur += 1;
447 while ((*cur >= '0') && (*cur <= '9')) {
448 port *= 10;
449 port += *cur - '0';
450 cur++;
451 }
452 if (port != 0) proxyPort = port;
453 while ((cur[0] != '/') && (*cur != 0))
454 cur++;
455 break;
456 }
457 if ((*cur == '/') || (*cur == 0)) {
458 buf[indx] = 0;
459 proxy = xmlMemStrdup (buf);
460 indx = 0;
461 break;
462 }
Owen Taylor3473f882001-02-23 17:55:21 +0000463 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000464 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000465 }
466}
467
468/**
469 * xmlNanoHTTPNewCtxt:
470 * @URL: The URL used to initialize the context
471 *
472 * Allocate and initialize a new HTTP context.
473 *
474 * Returns an HTTP context or NULL in case of error.
475 */
476
477static xmlNanoHTTPCtxtPtr
478xmlNanoHTTPNewCtxt(const char *URL) {
479 xmlNanoHTTPCtxtPtr ret;
480
481 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
482 if (ret == NULL) return(NULL);
483
484 memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
485 ret->port = 80;
486 ret->returnValue = 0;
487 ret->fd = -1;
Daniel Veillardf012a642001-07-23 19:10:52 +0000488 ret->ContentLength = -1;
Owen Taylor3473f882001-02-23 17:55:21 +0000489
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000490 xmlNanoHTTPScanURL(ret, URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000491
492 return(ret);
493}
494
495/**
496 * xmlNanoHTTPFreeCtxt:
497 * @ctxt: an HTTP context
498 *
499 * Frees the context after closing the connection.
500 */
501
502static void
503xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
504 if (ctxt == NULL) return;
505 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
506 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
507 if (ctxt->path != NULL) xmlFree(ctxt->path);
508 if (ctxt->out != NULL) xmlFree(ctxt->out);
509 if (ctxt->in != NULL) xmlFree(ctxt->in);
510 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
511 if (ctxt->location != NULL) xmlFree(ctxt->location);
512 if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
513 ctxt->state = XML_NANO_HTTP_NONE;
514 if (ctxt->fd >= 0) closesocket(ctxt->fd);
515 ctxt->fd = -1;
516 xmlFree(ctxt);
517}
518
519/**
520 * xmlNanoHTTPSend:
521 * @ctxt: an HTTP context
522 *
523 * Send the input needed to initiate the processing on the server side
Daniel Veillardf012a642001-07-23 19:10:52 +0000524 * Returns number of bytes sent or -1 on error.
Owen Taylor3473f882001-02-23 17:55:21 +0000525 */
526
Daniel Veillardf012a642001-07-23 19:10:52 +0000527static int
528xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char * xmt_ptr, int outlen) {
529
530 int total_sent = 0;
531
532 if ( (ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL ) ) {
533 while (total_sent < outlen) {
534 int nsent = send(ctxt->fd, xmt_ptr + total_sent,
535 outlen - total_sent, 0);
Owen Taylor3473f882001-02-23 17:55:21 +0000536 if (nsent>0)
537 total_sent += nsent;
Daniel Veillardf012a642001-07-23 19:10:52 +0000538 else if ( ( nsent == -1 ) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000539#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
Daniel Veillardf012a642001-07-23 19:10:52 +0000540 ( socket_errno( ) != EAGAIN ) &&
Daniel Veillardba6db032001-07-31 16:25:45 +0000541#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000542 ( socket_errno( ) != EWOULDBLOCK ) ) {
543 xmlGenericError( xmlGenericErrorContext,
544 "xmlNanoHTTPSend error: %s",
545 strerror( socket_errno( ) ) );
546
547 if ( total_sent == 0 )
548 total_sent = -1;
549 break;
550 }
551 else {
552 /*
553 ** No data sent
554 ** Since non-blocking sockets are used, wait for
555 ** socket to be writable or default timeout prior
556 ** to retrying.
557 */
558
559 struct timeval tv;
560 fd_set wfd;
561
562 tv.tv_sec = timeout;
563 tv.tv_usec = 0;
564 FD_ZERO( &wfd );
565 FD_SET( ctxt->fd, &wfd );
566 (void)select( ctxt->fd + 1, NULL, &wfd, NULL, &tv );
567 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000568 }
Owen Taylor3473f882001-02-23 17:55:21 +0000569 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000570
571 return total_sent;
Owen Taylor3473f882001-02-23 17:55:21 +0000572}
573
574/**
575 * xmlNanoHTTPRecv:
576 * @ctxt: an HTTP context
577 *
578 * Read information coming from the HTTP connection.
579 * This is a blocking call (but it blocks in select(), not read()).
580 *
581 * Returns the number of byte read or -1 in case of error.
582 */
583
584static int
585xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
586 fd_set rfd;
587 struct timeval tv;
588
589
590 while (ctxt->state & XML_NANO_HTTP_READ) {
591 if (ctxt->in == NULL) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000592 ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
Owen Taylor3473f882001-02-23 17:55:21 +0000593 if (ctxt->in == NULL) {
594 ctxt->last = -1;
Daniel Veillardf012a642001-07-23 19:10:52 +0000595 xmlGenericError( xmlGenericErrorContext,
596 "xmlNanoHTTPRecv: Error allocating input memory." );
Owen Taylor3473f882001-02-23 17:55:21 +0000597 return(-1);
598 }
599 ctxt->inlen = 65000;
600 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
601 }
602 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
603 int delta = ctxt->inrptr - ctxt->in;
604 int len = ctxt->inptr - ctxt->inrptr;
605
606 memmove(ctxt->in, ctxt->inrptr, len);
607 ctxt->inrptr -= delta;
608 ctxt->content -= delta;
609 ctxt->inptr -= delta;
610 }
611 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
612 int d_inptr = ctxt->inptr - ctxt->in;
613 int d_content = ctxt->content - ctxt->in;
614 int d_inrptr = ctxt->inrptr - ctxt->in;
Daniel Veillardf012a642001-07-23 19:10:52 +0000615 char * tmp_ptr = ctxt->in;
Owen Taylor3473f882001-02-23 17:55:21 +0000616
617 ctxt->inlen *= 2;
Daniel Veillardf012a642001-07-23 19:10:52 +0000618 ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
Owen Taylor3473f882001-02-23 17:55:21 +0000619 if (ctxt->in == NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000620 xmlGenericError( xmlGenericErrorContext,
621 "xmlNanoHTTPRecv: %s %d bytes.",
622 "Failed to realloc input buffer to",
623 ctxt->inlen );
624 xmlFree( tmp_ptr );
Owen Taylor3473f882001-02-23 17:55:21 +0000625 ctxt->last = -1;
626 return(-1);
627 }
628 ctxt->inptr = ctxt->in + d_inptr;
629 ctxt->content = ctxt->in + d_content;
630 ctxt->inrptr = ctxt->in + d_inrptr;
631 }
632 ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
633 if (ctxt->last > 0) {
634 ctxt->inptr += ctxt->last;
635 return(ctxt->last);
636 }
637 if (ctxt->last == 0) {
638 return(0);
639 }
640 if (ctxt->last == -1) {
641 switch (socket_errno()) {
642 case EINPROGRESS:
643 case EWOULDBLOCK:
644#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
645 case EAGAIN:
646#endif
647 break;
Daniel Veillardf012a642001-07-23 19:10:52 +0000648
649 case ECONNRESET:
650 case ESHUTDOWN:
651 return ( 0 );
652
Owen Taylor3473f882001-02-23 17:55:21 +0000653 default:
Daniel Veillardf012a642001-07-23 19:10:52 +0000654 xmlGenericError( xmlGenericErrorContext,
655 "xmlNanoHTTPRecv: recv( ) failure - %s",
656 strerror( socket_errno( ) ) );
657 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000658 }
659 }
660
661 tv.tv_sec = timeout;
662 tv.tv_usec = 0;
663 FD_ZERO(&rfd);
664 FD_SET(ctxt->fd, &rfd);
665
Daniel Veillard50f34372001-08-03 12:06:36 +0000666 if ( (select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
667#if defined(EINTR)
668 && (errno != EINTR)
669#endif
670 )
Owen Taylor3473f882001-02-23 17:55:21 +0000671 return(0);
672 }
673 return(0);
674}
675
676/**
677 * xmlNanoHTTPReadLine:
678 * @ctxt: an HTTP context
679 *
680 * Read one line in the HTTP server output, usually for extracting
681 * the HTTP protocol informations from the answer header.
682 *
683 * Returns a newly allocated string with a copy of the line, or NULL
684 * which indicate the end of the input.
685 */
686
687static char *
688xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
689 char buf[4096];
690 char *bp = buf;
Daniel Veillardf012a642001-07-23 19:10:52 +0000691 int rc;
Owen Taylor3473f882001-02-23 17:55:21 +0000692
693 while (bp - buf < 4095) {
694 if (ctxt->inrptr == ctxt->inptr) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000695 if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000696 if (bp == buf)
697 return(NULL);
698 else
699 *bp = 0;
700 return(xmlMemStrdup(buf));
701 }
Daniel Veillardf012a642001-07-23 19:10:52 +0000702 else if ( rc == -1 ) {
703 return ( NULL );
704 }
Owen Taylor3473f882001-02-23 17:55:21 +0000705 }
706 *bp = *ctxt->inrptr++;
707 if (*bp == '\n') {
708 *bp = 0;
709 return(xmlMemStrdup(buf));
710 }
711 if (*bp != '\r')
712 bp++;
713 }
714 buf[4095] = 0;
715 return(xmlMemStrdup(buf));
716}
717
718
719/**
720 * xmlNanoHTTPScanAnswer:
721 * @ctxt: an HTTP context
722 * @line: an HTTP header line
723 *
724 * Try to extract useful informations from the server answer.
725 * We currently parse and process:
726 * - The HTTP revision/ return code
727 * - The Content-Type
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000728 * - The Location for redirect processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000729 *
730 * Returns -1 in case of failure, the file descriptor number otherwise
731 */
732
733static void
734xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
735 const char *cur = line;
736
737 if (line == NULL) return;
738
739 if (!strncmp(line, "HTTP/", 5)) {
740 int version = 0;
741 int ret = 0;
742
743 cur += 5;
744 while ((*cur >= '0') && (*cur <= '9')) {
745 version *= 10;
746 version += *cur - '0';
747 cur++;
748 }
749 if (*cur == '.') {
750 cur++;
751 if ((*cur >= '0') && (*cur <= '9')) {
752 version *= 10;
753 version += *cur - '0';
754 cur++;
755 }
756 while ((*cur >= '0') && (*cur <= '9'))
757 cur++;
758 } else
759 version *= 10;
760 if ((*cur != ' ') && (*cur != '\t')) return;
761 while ((*cur == ' ') || (*cur == '\t')) cur++;
762 if ((*cur < '0') || (*cur > '9')) return;
763 while ((*cur >= '0') && (*cur <= '9')) {
764 ret *= 10;
765 ret += *cur - '0';
766 cur++;
767 }
768 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
769 ctxt->returnValue = ret;
770 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
771 cur += 13;
772 while ((*cur == ' ') || (*cur == '\t')) cur++;
773 if (ctxt->contentType != NULL)
774 xmlFree(ctxt->contentType);
775 ctxt->contentType = xmlMemStrdup(cur);
776 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
777 cur += 12;
778 if (ctxt->contentType != NULL) return;
779 while ((*cur == ' ') || (*cur == '\t')) cur++;
780 ctxt->contentType = xmlMemStrdup(cur);
781 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
782 cur += 9;
783 while ((*cur == ' ') || (*cur == '\t')) cur++;
784 if (ctxt->location != NULL)
785 xmlFree(ctxt->location);
786 ctxt->location = xmlMemStrdup(cur);
787 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
788 cur += 17;
789 while ((*cur == ' ') || (*cur == '\t')) cur++;
790 if (ctxt->authHeader != NULL)
791 xmlFree(ctxt->authHeader);
792 ctxt->authHeader = xmlMemStrdup(cur);
793 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
794 cur += 19;
795 while ((*cur == ' ') || (*cur == '\t')) cur++;
796 if (ctxt->authHeader != NULL)
797 xmlFree(ctxt->authHeader);
798 ctxt->authHeader = xmlMemStrdup(cur);
Daniel Veillardf012a642001-07-23 19:10:52 +0000799 } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
800 cur += 15;
801 ctxt->ContentLength = strtol( cur, NULL, 10 );
Owen Taylor3473f882001-02-23 17:55:21 +0000802 }
803}
804
805/**
806 * xmlNanoHTTPConnectAttempt:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000807 * @addr: a socket address structure
Owen Taylor3473f882001-02-23 17:55:21 +0000808 *
809 * Attempt a connection to the given IP:port endpoint. It forces
810 * non-blocking semantic on the socket, and allow 60 seconds for
811 * the host to answer.
812 *
813 * Returns -1 in case of failure, the file descriptor number otherwise
814 */
815
816static int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000817xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
Owen Taylor3473f882001-02-23 17:55:21 +0000818{
Owen Taylor3473f882001-02-23 17:55:21 +0000819 fd_set wfd;
820 struct timeval tv;
821 int status;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000822 int addrlen;
823 SOCKET s;
Owen Taylor3473f882001-02-23 17:55:21 +0000824
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000825#ifdef SUPPORT_IP6
826 if (addr->sa_family == AF_INET6) {
827 s = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
828 addrlen = sizeof (struct sockaddr_in6);
829 }
830 else
831#endif
832 {
833 s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
834 addrlen = sizeof (struct sockaddr_in);
835 }
Owen Taylor3473f882001-02-23 17:55:21 +0000836 if (s==-1) {
837#ifdef DEBUG_HTTP
838 perror("socket");
839#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000840 xmlGenericError( xmlGenericErrorContext,
841 "xmlNanoHTTPConnectAttempt: %s - %s",
842 "socket creation failure",
843 strerror( socket_errno( ) ) );
Owen Taylor3473f882001-02-23 17:55:21 +0000844 return(-1);
845 }
846
847#ifdef _WINSOCKAPI_
848 {
849 u_long one = 1;
850
851 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
852 }
853#else /* _WINSOCKAPI_ */
854#if defined(VMS)
855 {
856 int enable = 1;
857 status = ioctl(s, FIONBIO, &enable);
858 }
859#else /* VMS */
860 if ((status = fcntl(s, F_GETFL, 0)) != -1) {
861#ifdef O_NONBLOCK
862 status |= O_NONBLOCK;
863#else /* O_NONBLOCK */
864#ifdef F_NDELAY
865 status |= F_NDELAY;
866#endif /* F_NDELAY */
867#endif /* !O_NONBLOCK */
868 status = fcntl(s, F_SETFL, status);
869 }
870 if (status < 0) {
871#ifdef DEBUG_HTTP
872 perror("nonblocking");
873#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000874 xmlGenericError( xmlGenericErrorContext,
875 "xmlNanoHTTPConnectAttempt: %s - %s",
876 "error setting non-blocking IO",
877 strerror( socket_errno( ) ) );
Owen Taylor3473f882001-02-23 17:55:21 +0000878 closesocket(s);
879 return(-1);
880 }
881#endif /* !VMS */
882#endif /* !_WINSOCKAPI_ */
883
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000884 if (connect (s, addr, addrlen) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +0000885 switch (socket_errno()) {
886 case EINPROGRESS:
887 case EWOULDBLOCK:
888 break;
889 default:
Daniel Veillardf012a642001-07-23 19:10:52 +0000890 xmlGenericError( xmlGenericErrorContext,
891 "xmlNanoHTTPConnectAttempt: %s - %s",
892 "error connecting to HTTP server",
893 strerror( socket_errno( ) ) );
Owen Taylor3473f882001-02-23 17:55:21 +0000894 closesocket(s);
895 return(-1);
896 }
897 }
898
899 tv.tv_sec = timeout;
900 tv.tv_usec = 0;
901
902 FD_ZERO(&wfd);
903 FD_SET(s, &wfd);
904
905 switch(select(s+1, NULL, &wfd, NULL, &tv))
906 {
907 case 0:
908 /* Time out */
Daniel Veillardf012a642001-07-23 19:10:52 +0000909 xmlGenericError( xmlGenericErrorContext,
910 "xmlNanoHTTPConnectAttempt: %s",
911 "Connect attempt timed out." );
Owen Taylor3473f882001-02-23 17:55:21 +0000912 closesocket(s);
913 return(-1);
914 case -1:
915 /* Ermm.. ?? */
Daniel Veillardf012a642001-07-23 19:10:52 +0000916 xmlGenericError( xmlGenericErrorContext,
917 "xmlNanoHTTPConnectAttempt: %s - %s",
918 "Error connecting to host",
919 strerror( socket_errno( ) ) );
Owen Taylor3473f882001-02-23 17:55:21 +0000920 closesocket(s);
921 return(-1);
922 }
923
924 if ( FD_ISSET(s, &wfd) ) {
925 SOCKLEN_T len;
926 len = sizeof(status);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000927#ifdef SO_ERROR
Owen Taylor3473f882001-02-23 17:55:21 +0000928 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0 ) {
929 /* Solaris error code */
Daniel Veillardf012a642001-07-23 19:10:52 +0000930 xmlGenericError( xmlGenericErrorContext,
931 "xmlNanoHTTPConnectAttempt: %s - %s",
932 "Error retrieving pending socket errors",
933 strerror( socket_errno( ) ) );
Owen Taylor3473f882001-02-23 17:55:21 +0000934 return (-1);
935 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000936#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000937 if ( status ) {
938 closesocket(s);
939 errno = status;
Daniel Veillardf012a642001-07-23 19:10:52 +0000940 xmlGenericError( xmlGenericErrorContext,
941 "xmlNanoHTTPConnectAttempt: %s - %s",
942 "Error connecting to remote host",
943 strerror( status ) );
Owen Taylor3473f882001-02-23 17:55:21 +0000944 return (-1);
945 }
946 } else {
947 /* pbm */
Daniel Veillardf012a642001-07-23 19:10:52 +0000948 xmlGenericError( xmlGenericErrorContext,
949 "xmlNanoHTTPConnectAttempt: %s\n",
950 "Select returned, but descriptor not set for connection.\n" );
951 closesocket(s);
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return (-1);
953 }
954
955 return(s);
956}
957
958/**
959 * xmlNanoHTTPConnectHost:
960 * @host: the host name
961 * @port: the port number
962 *
963 * Attempt a connection to the given host:port endpoint. It tries
964 * the multiple IP provided by the DNS if available.
965 *
966 * Returns -1 in case of failure, the file descriptor number otherwise
967 */
968
969static int
970xmlNanoHTTPConnectHost(const char *host, int port)
971{
972 struct hostent *h;
Daniel Veillard2db8c122003-07-08 12:16:59 +0000973 struct sockaddr *addr = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000974 struct in_addr ia;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000975 struct sockaddr_in sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +0000976
Owen Taylor3473f882001-02-23 17:55:21 +0000977#ifdef SUPPORT_IP6
978 struct in6_addr ia6;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000979 struct sockaddr_in6 sockin6;
Owen Taylor3473f882001-02-23 17:55:21 +0000980#endif
981 int i;
982 int s;
Daniel Veillard5c396542002-03-15 07:57:50 +0000983
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000984 memset (&sockin, 0, sizeof(sockin));
985#ifdef SUPPORT_IP6
986 memset (&sockin6, 0, sizeof(sockin6));
987 if (have_ipv6 ())
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000988#if !defined(HAVE_GETADDRINFO) && defined(RES_USE_INET6)
Daniel Veillard560c2a42003-07-06 21:13:49 +0000989 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000990 if (!(_res.options & RES_INIT))
991 res_init();
992 _res.options |= RES_USE_INET6;
993 }
994#elif defined(HAVE_GETADDRINFO)
Daniel Veillard560c2a42003-07-06 21:13:49 +0000995 {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000996 int status;
997 struct addrinfo hints, *res, *result;
998
999 result = NULL;
1000 memset (&hints, 0,sizeof(hints));
1001 hints.ai_socktype = SOCK_STREAM;
1002
1003 status = getaddrinfo (host, NULL, &hints, &result);
1004 if (status) {
1005 xmlGenericError (xmlGenericErrorContext,
1006 "xmlNanoHTTPConnectHost: %s '%s' - %s",
1007 "Failed to resolve host", host, gai_strerror (status));
1008
1009 return (-1);
1010 }
1011
1012 for (res = result; res; res = res->ai_next) {
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001013 if (res->ai_family == AF_INET || res->ai_family == AF_INET6) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001014 if (res->ai_family == AF_INET6) {
1015 memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
1016 sockin6.sin6_port = htons (port);
1017 addr = (struct sockaddr *)&sockin6;
1018 }
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001019 else {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001020 memcpy (&sockin, res->ai_addr, res->ai_addrlen);
1021 sockin.sin_port = htons (port);
1022 addr = (struct sockaddr *)&sockin;
1023 }
1024
1025 s = xmlNanoHTTPConnectAttempt (addr);
1026 if (s != -1) {
1027 freeaddrinfo (result);
1028 return (s);
1029 }
1030 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001031 }
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001032 if (result)
1033 freeaddrinfo (result);
1034 return (-1);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001035 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001036#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001037#endif
1038 {
1039 h = gethostbyname (host);
1040 if (h == NULL) {
Daniel Veillard56b2db72002-03-25 16:35:28 +00001041
1042/*
1043 * Okay, I got fed up by the non-portability of this error message
1044 * extraction code. it work on Linux, if it work on your platform
1045 * and one want to enable it, send me the defined(foobar) needed
1046 */
1047#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001048 const char *h_err_txt = "";
Daniel Veillardf012a642001-07-23 19:10:52 +00001049
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001050 switch (h_errno) {
1051 case HOST_NOT_FOUND:
1052 h_err_txt = "Authoritive host not found";
1053 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001054
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001055 case TRY_AGAIN:
1056 h_err_txt =
1057 "Non-authoritive host not found or server failure.";
1058 break;
Daniel Veillardf012a642001-07-23 19:10:52 +00001059
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001060 case NO_RECOVERY:
1061 h_err_txt =
1062 "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
1063 break;
Daniel Veillard5c396542002-03-15 07:57:50 +00001064
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001065 case NO_ADDRESS:
1066 h_err_txt =
1067 "Valid name, no data record of requested type.";
1068 break;
Daniel Veillard5c396542002-03-15 07:57:50 +00001069
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001070 default:
1071 h_err_txt = "No error text defined.";
1072 break;
1073 }
1074 xmlGenericError (xmlGenericErrorContext,
1075 "xmlNanoHTTPConnectHost: %s '%s' - %s",
1076 "Failed to resolve host", host, h_err_txt);
Daniel Veillard5c396542002-03-15 07:57:50 +00001077#else
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001078 xmlGenericError (xmlGenericErrorContext,
1079 "xmlNanoHTTPConnectHost: %s '%s'",
1080 "Failed to resolve host", host);
Owen Taylor3473f882001-02-23 17:55:21 +00001081#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001082 return (-1);
1083 }
Daniel Veillard5c396542002-03-15 07:57:50 +00001084
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001085 for (i = 0; h->h_addr_list[i]; i++) {
1086 if (h->h_addrtype == AF_INET) {
1087 /* A records (IPv4) */
1088 memcpy (&ia, h->h_addr_list[i], h->h_length);
1089 sockin.sin_family = h->h_addrtype;
1090 sockin.sin_addr = ia;
1091 sockin.sin_port = htons (port);
1092 addr = (struct sockaddr *) &sockin;
Daniel Veillard5c396542002-03-15 07:57:50 +00001093#ifdef SUPPORT_IP6
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001094 } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
1095 /* AAAA records (IPv6) */
1096 memcpy (&ia6, h->h_addr_list[i], h->h_length);
1097 sockin6.sin6_family = h->h_addrtype;
1098 sockin6.sin6_addr = ia6;
1099 sockin6.sin6_port = htons (port);
1100 addr = (struct sockaddr *) &sockin6;
Daniel Veillard5c396542002-03-15 07:57:50 +00001101#endif
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001102 } else
1103 break; /* for */
Daniel Veillard5c396542002-03-15 07:57:50 +00001104
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001105 s = xmlNanoHTTPConnectAttempt (addr);
1106 if (s != -1)
1107 return (s);
1108 }
Owen Taylor3473f882001-02-23 17:55:21 +00001109 }
Owen Taylor3473f882001-02-23 17:55:21 +00001110#ifdef DEBUG_HTTP
1111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard5c396542002-03-15 07:57:50 +00001112 "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",
1113 host);
Owen Taylor3473f882001-02-23 17:55:21 +00001114#endif
Daniel Veillard5c396542002-03-15 07:57:50 +00001115 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001116}
1117
1118
1119/**
1120 * xmlNanoHTTPOpen:
1121 * @URL: The URL to load
1122 * @contentType: if available the Content-Type information will be
1123 * returned at that location
1124 *
1125 * This function try to open a connection to the indicated resource
1126 * via HTTP GET.
1127 *
1128 * Returns NULL in case of failure, otherwise a request handler.
1129 * The contentType, if provided must be freed by the caller
1130 */
1131
1132void*
1133xmlNanoHTTPOpen(const char *URL, char **contentType) {
1134 if (contentType != NULL) *contentType = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001135 return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
Daniel Veillard9403a042001-05-28 11:00:53 +00001136}
1137
1138/**
1139 * xmlNanoHTTPOpenRedir:
1140 * @URL: The URL to load
1141 * @contentType: if available the Content-Type information will be
1142 * returned at that location
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001143 * @redir: if available the redirected URL will be returned
Daniel Veillard9403a042001-05-28 11:00:53 +00001144 *
1145 * This function try to open a connection to the indicated resource
1146 * via HTTP GET.
1147 *
1148 * Returns NULL in case of failure, otherwise a request handler.
1149 * The contentType, if provided must be freed by the caller
1150 */
1151
1152void*
1153xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
1154 if (contentType != NULL) *contentType = NULL;
1155 if (redir != NULL) *redir = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001156 return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
Owen Taylor3473f882001-02-23 17:55:21 +00001157}
1158
1159/**
1160 * xmlNanoHTTPRead:
1161 * @ctx: the HTTP context
1162 * @dest: a buffer
1163 * @len: the buffer length
1164 *
1165 * This function tries to read @len bytes from the existing HTTP connection
1166 * and saves them in @dest. This is a blocking call.
1167 *
1168 * Returns the number of byte read. 0 is an indication of an end of connection.
1169 * -1 indicates a parameter error.
1170 */
1171int
1172xmlNanoHTTPRead(void *ctx, void *dest, int len) {
1173 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1174
1175 if (ctx == NULL) return(-1);
1176 if (dest == NULL) return(-1);
1177 if (len <= 0) return(0);
1178
1179 while (ctxt->inptr - ctxt->inrptr < len) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001180 if (xmlNanoHTTPRecv(ctxt) <= 0) break;
Owen Taylor3473f882001-02-23 17:55:21 +00001181 }
1182 if (ctxt->inptr - ctxt->inrptr < len)
1183 len = ctxt->inptr - ctxt->inrptr;
1184 memcpy(dest, ctxt->inrptr, len);
1185 ctxt->inrptr += len;
1186 return(len);
1187}
1188
1189/**
1190 * xmlNanoHTTPClose:
1191 * @ctx: the HTTP context
1192 *
1193 * This function closes an HTTP context, it ends up the connection and
1194 * free all data related to it.
1195 */
1196void
1197xmlNanoHTTPClose(void *ctx) {
1198 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1199
1200 if (ctx == NULL) return;
1201
1202 xmlNanoHTTPFreeCtxt(ctxt);
1203}
1204
1205/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001206 * xmlNanoHTTPMethodRedir:
Owen Taylor3473f882001-02-23 17:55:21 +00001207 * @URL: The URL to load
1208 * @method: the HTTP method to use
1209 * @input: the input string if any
1210 * @contentType: the Content-Type information IN and OUT
Daniel Veillard9403a042001-05-28 11:00:53 +00001211 * @redir: the redirected URL OUT
Owen Taylor3473f882001-02-23 17:55:21 +00001212 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001213 * @ilen: input length
Owen Taylor3473f882001-02-23 17:55:21 +00001214 *
1215 * This function try to open a connection to the indicated resource
1216 * via HTTP using the given @method, adding the given extra headers
1217 * and the input buffer for the request content.
1218 *
1219 * Returns NULL in case of failure, otherwise a request handler.
Daniel Veillard9403a042001-05-28 11:00:53 +00001220 * The contentType, or redir, if provided must be freed by the caller
Owen Taylor3473f882001-02-23 17:55:21 +00001221 */
1222
1223void*
Daniel Veillard9403a042001-05-28 11:00:53 +00001224xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001225 char **contentType, char **redir,
1226 const char *headers, int ilen ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001227 xmlNanoHTTPCtxtPtr ctxt;
1228 char *bp, *p;
Daniel Veillardf012a642001-07-23 19:10:52 +00001229 int blen, ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001230 int head;
1231 int nbRedirects = 0;
1232 char *redirURL = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001233#ifdef DEBUG_HTTP
1234 int xmt_bytes;
1235#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001236
1237 if (URL == NULL) return(NULL);
1238 if (method == NULL) method = "GET";
1239 xmlNanoHTTPInit();
1240
1241retry:
1242 if (redirURL == NULL)
1243 ctxt = xmlNanoHTTPNewCtxt(URL);
1244 else {
1245 ctxt = xmlNanoHTTPNewCtxt(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001246 }
1247
Daniel Veillardf012a642001-07-23 19:10:52 +00001248 if ( ctxt == NULL ) {
1249 xmlGenericError( xmlGenericErrorContext,
1250 "xmlNanoHTTPMethodRedir: %s %s.",
1251 "Unable to allocate HTTP context to URI",
1252 ( ( redirURL == NULL ) ? URL : redirURL ) );
1253 return ( NULL );
1254 }
1255
Owen Taylor3473f882001-02-23 17:55:21 +00001256 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001257 xmlGenericError( xmlGenericErrorContext,
1258 "xmlNanoHTTPMethodRedir: %s - %s.",
1259 "Not a valid HTTP URI",
1260 ( ( redirURL == NULL ) ? URL : redirURL ) );
Owen Taylor3473f882001-02-23 17:55:21 +00001261 xmlNanoHTTPFreeCtxt(ctxt);
1262 if (redirURL != NULL) xmlFree(redirURL);
1263 return(NULL);
1264 }
1265 if (ctxt->hostname == NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001266 xmlGenericError( xmlGenericErrorContext,
1267 "xmlNanoHTTPMethodRedir: %s - %s",
1268 "Failed to identify host in URI",
1269 ( ( redirURL == NULL ) ? URL : redirURL ) );
Owen Taylor3473f882001-02-23 17:55:21 +00001270 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001271 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001272 return(NULL);
1273 }
1274 if (proxy) {
1275 blen = strlen(ctxt->hostname) * 2 + 16;
1276 ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
1277 }
1278 else {
1279 blen = strlen(ctxt->hostname);
1280 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1281 }
1282 if (ret < 0) {
1283 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001284 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001285 return(NULL);
1286 }
1287 ctxt->fd = ret;
1288
Daniel Veillardf012a642001-07-23 19:10:52 +00001289 if (input == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001290 ilen = 0;
Daniel Veillardf012a642001-07-23 19:10:52 +00001291 else
1292 blen += 36;
1293
Owen Taylor3473f882001-02-23 17:55:21 +00001294 if (headers != NULL)
Daniel Veillardf012a642001-07-23 19:10:52 +00001295 blen += strlen(headers) + 2;
Owen Taylor3473f882001-02-23 17:55:21 +00001296 if (contentType && *contentType)
1297 blen += strlen(*contentType) + 16;
Daniel Veillardf012a642001-07-23 19:10:52 +00001298 blen += strlen(method) + strlen(ctxt->path) + 24;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001299 bp = xmlMallocAtomic(blen);
Daniel Veillardf012a642001-07-23 19:10:52 +00001300 if ( bp == NULL ) {
1301 xmlNanoHTTPFreeCtxt( ctxt );
1302 xmlGenericError( xmlGenericErrorContext,
1303 "xmlNanoHTTPMethodRedir: %s",
1304 "Error allocating HTTP header buffer." );
1305 return ( NULL );
1306 }
1307
1308 p = bp;
1309
Owen Taylor3473f882001-02-23 17:55:21 +00001310 if (proxy) {
1311 if (ctxt->port != 80) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001312 p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s",
1313 method, ctxt->hostname,
Daniel Veillardf012a642001-07-23 19:10:52 +00001314 ctxt->port, ctxt->path );
Owen Taylor3473f882001-02-23 17:55:21 +00001315 }
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001316 else
1317 p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
Daniel Veillardf012a642001-07-23 19:10:52 +00001318 ctxt->hostname, ctxt->path);
Owen Taylor3473f882001-02-23 17:55:21 +00001319 }
1320 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001321 p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
Daniel Veillardf012a642001-07-23 19:10:52 +00001322
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001323 p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
1324 ctxt->hostname);
Daniel Veillardf012a642001-07-23 19:10:52 +00001325
1326 if (contentType != NULL && *contentType)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001327 p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
Daniel Veillardf012a642001-07-23 19:10:52 +00001328
1329 if (headers != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001330 p += snprintf( p, blen - (p - bp), "%s", headers );
Daniel Veillardf012a642001-07-23 19:10:52 +00001331
Owen Taylor3473f882001-02-23 17:55:21 +00001332 if (input != NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001333 snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
Owen Taylor3473f882001-02-23 17:55:21 +00001334 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001335 snprintf(p, blen - (p - bp), "\r\n");
Daniel Veillardf012a642001-07-23 19:10:52 +00001336
Owen Taylor3473f882001-02-23 17:55:21 +00001337#ifdef DEBUG_HTTP
1338 xmlGenericError(xmlGenericErrorContext,
1339 "-> %s%s", proxy? "(Proxy) " : "", bp);
1340 if ((blen -= strlen(bp)+1) < 0)
1341 xmlGenericError(xmlGenericErrorContext,
1342 "ERROR: overflowed buffer by %d bytes\n", -blen);
1343#endif
1344 ctxt->outptr = ctxt->out = bp;
1345 ctxt->state = XML_NANO_HTTP_WRITE;
Daniel Veillardf012a642001-07-23 19:10:52 +00001346 blen = strlen( ctxt->out );
Daniel Veillardf012a642001-07-23 19:10:52 +00001347#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001348 xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001349 if ( xmt_bytes != blen )
1350 xmlGenericError( xmlGenericErrorContext,
1351 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1352 xmt_bytes, blen,
1353 "bytes of HTTP headers sent to host",
1354 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001355#else
1356 xmlNanoHTTPSend(ctxt, ctxt->out, blen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001357#endif
1358
1359 if ( input != NULL ) {
William M. Brack78637da2003-07-31 14:47:38 +00001360#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001361 xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
1362
Daniel Veillardf012a642001-07-23 19:10:52 +00001363 if ( xmt_bytes != ilen )
1364 xmlGenericError( xmlGenericErrorContext,
1365 "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n",
1366 xmt_bytes, ilen,
1367 "bytes of HTTP content sent to host",
1368 ctxt->hostname );
William M. Brack78637da2003-07-31 14:47:38 +00001369#else
1370 xmlNanoHTTPSend( ctxt, input, ilen );
Daniel Veillardf012a642001-07-23 19:10:52 +00001371#endif
1372 }
1373
Owen Taylor3473f882001-02-23 17:55:21 +00001374 ctxt->state = XML_NANO_HTTP_READ;
1375 head = 1;
1376
1377 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
1378 if (head && (*p == 0)) {
1379 head = 0;
1380 ctxt->content = ctxt->inrptr;
1381 xmlFree(p);
1382 break;
1383 }
1384 xmlNanoHTTPScanAnswer(ctxt, p);
1385
1386#ifdef DEBUG_HTTP
1387 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
1388#endif
1389 xmlFree(p);
1390 }
1391
1392 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1393 (ctxt->returnValue < 400)) {
1394#ifdef DEBUG_HTTP
1395 xmlGenericError(xmlGenericErrorContext,
1396 "\nRedirect to: %s\n", ctxt->location);
1397#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001398 while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
Owen Taylor3473f882001-02-23 17:55:21 +00001399 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1400 nbRedirects++;
Daniel Veillard9403a042001-05-28 11:00:53 +00001401 if (redirURL != NULL)
1402 xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001403 redirURL = xmlMemStrdup(ctxt->location);
1404 xmlNanoHTTPFreeCtxt(ctxt);
1405 goto retry;
1406 }
1407 xmlNanoHTTPFreeCtxt(ctxt);
Daniel Veillard9403a042001-05-28 11:00:53 +00001408 if (redirURL != NULL) xmlFree(redirURL);
Owen Taylor3473f882001-02-23 17:55:21 +00001409#ifdef DEBUG_HTTP
1410 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00001411 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001412#endif
1413 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001414 }
1415
1416 if (contentType != NULL) {
1417 if (ctxt->contentType != NULL)
1418 *contentType = xmlMemStrdup(ctxt->contentType);
1419 else
1420 *contentType = NULL;
1421 }
1422
Daniel Veillard9403a042001-05-28 11:00:53 +00001423 if ((redir != NULL) && (redirURL != NULL)) {
1424 *redir = redirURL;
1425 } else {
1426 if (redirURL != NULL)
1427 xmlFree(redirURL);
1428 if (redir != NULL)
1429 *redir = NULL;
1430 }
1431
Owen Taylor3473f882001-02-23 17:55:21 +00001432#ifdef DEBUG_HTTP
1433 if (ctxt->contentType != NULL)
1434 xmlGenericError(xmlGenericErrorContext,
1435 "\nCode %d, content-type '%s'\n\n",
1436 ctxt->returnValue, ctxt->contentType);
1437 else
1438 xmlGenericError(xmlGenericErrorContext,
1439 "\nCode %d, no content-type\n\n",
1440 ctxt->returnValue);
1441#endif
1442
1443 return((void *) ctxt);
1444}
1445
1446/**
Daniel Veillard9403a042001-05-28 11:00:53 +00001447 * xmlNanoHTTPMethod:
1448 * @URL: The URL to load
1449 * @method: the HTTP method to use
1450 * @input: the input string if any
1451 * @contentType: the Content-Type information IN and OUT
1452 * @headers: the extra headers
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001453 * @ilen: input length
Daniel Veillard9403a042001-05-28 11:00:53 +00001454 *
1455 * This function try to open a connection to the indicated resource
1456 * via HTTP using the given @method, adding the given extra headers
1457 * and the input buffer for the request content.
1458 *
1459 * Returns NULL in case of failure, otherwise a request handler.
1460 * The contentType, if provided must be freed by the caller
1461 */
1462
1463void*
1464xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
Daniel Veillardf012a642001-07-23 19:10:52 +00001465 char **contentType, const char *headers, int ilen) {
Daniel Veillard9403a042001-05-28 11:00:53 +00001466 return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
Daniel Veillardf012a642001-07-23 19:10:52 +00001467 NULL, headers, ilen));
Daniel Veillard9403a042001-05-28 11:00:53 +00001468}
1469
1470/**
Owen Taylor3473f882001-02-23 17:55:21 +00001471 * xmlNanoHTTPFetch:
1472 * @URL: The URL to load
1473 * @filename: the filename where the content should be saved
1474 * @contentType: if available the Content-Type information will be
1475 * returned at that location
1476 *
1477 * This function try to fetch the indicated resource via HTTP GET
1478 * and save it's content in the file.
1479 *
1480 * Returns -1 in case of failure, 0 incase of success. The contentType,
1481 * if provided must be freed by the caller
1482 */
1483int
1484xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001485 void *ctxt = NULL;
1486 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001487 int fd;
1488 int len;
1489
1490 ctxt = xmlNanoHTTPOpen(URL, contentType);
1491 if (ctxt == NULL) return(-1);
1492
1493 if (!strcmp(filename, "-"))
1494 fd = 0;
1495 else {
1496 fd = open(filename, O_CREAT | O_WRONLY, 00644);
1497 if (fd < 0) {
1498 xmlNanoHTTPClose(ctxt);
1499 if ((contentType != NULL) && (*contentType != NULL)) {
1500 xmlFree(*contentType);
1501 *contentType = NULL;
1502 }
1503 return(-1);
1504 }
1505 }
1506
Daniel Veillardf012a642001-07-23 19:10:52 +00001507 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1508 if ( len > 0 ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001509 write(fd, buf, len);
1510 }
1511
1512 xmlNanoHTTPClose(ctxt);
1513 close(fd);
1514 return(0);
1515}
1516
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001517#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001518/**
1519 * xmlNanoHTTPSave:
1520 * @ctxt: the HTTP context
1521 * @filename: the filename where the content should be saved
1522 *
1523 * This function saves the output of the HTTP transaction to a file
1524 * It closes and free the context at the end
1525 *
1526 * Returns -1 in case of failure, 0 incase of success.
1527 */
1528int
1529xmlNanoHTTPSave(void *ctxt, const char *filename) {
Daniel Veillarde3924972001-07-25 20:25:21 +00001530 char *buf = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001531 int fd;
1532 int len;
1533
1534 if (ctxt == NULL) return(-1);
1535
1536 if (!strcmp(filename, "-"))
1537 fd = 0;
1538 else {
1539 fd = open(filename, O_CREAT | O_WRONLY);
1540 if (fd < 0) {
1541 xmlNanoHTTPClose(ctxt);
1542 return(-1);
1543 }
1544 }
1545
Daniel Veillardf012a642001-07-23 19:10:52 +00001546 xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1547 if ( len > 0 ) {
Owen Taylor3473f882001-02-23 17:55:21 +00001548 write(fd, buf, len);
1549 }
1550
1551 xmlNanoHTTPClose(ctxt);
1552 return(0);
1553}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001554#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001555
1556/**
1557 * xmlNanoHTTPReturnCode:
1558 * @ctx: the HTTP context
1559 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001560 * Get the latest HTTP return code received
1561 *
Owen Taylor3473f882001-02-23 17:55:21 +00001562 * Returns the HTTP return code for the request.
1563 */
1564int
1565xmlNanoHTTPReturnCode(void *ctx) {
1566 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1567
1568 if (ctxt == NULL) return(-1);
1569
1570 return(ctxt->returnValue);
1571}
1572
1573/**
1574 * xmlNanoHTTPAuthHeader:
1575 * @ctx: the HTTP context
1576 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001577 * Get the authentication header of an HTTP context
1578 *
Owen Taylor3473f882001-02-23 17:55:21 +00001579 * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
1580 * header.
1581 */
1582const char *
1583xmlNanoHTTPAuthHeader(void *ctx) {
1584 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1585
1586 if (ctxt == NULL) return(NULL);
1587
1588 return(ctxt->authHeader);
1589}
1590
Daniel Veillardf012a642001-07-23 19:10:52 +00001591/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001592 * xmlNanoHTTPContentLength:
Daniel Veillardf012a642001-07-23 19:10:52 +00001593 * @ctx: the HTTP context
1594 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001595 * Provides the specified content length from the HTTP header.
1596 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001597 * Return the specified content length from the HTTP header. Note that
1598 * a value of -1 indicates that the content length element was not included in
1599 * the response header.
1600 */
1601int
1602xmlNanoHTTPContentLength( void * ctx ) {
1603 xmlNanoHTTPCtxtPtr ctxt = ctx;
1604
1605 return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
1606}
1607
1608/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001609 * xmlNanoHTTPFetchContent:
Daniel Veillardf012a642001-07-23 19:10:52 +00001610 * @ctx: the HTTP context
1611 * @ptr: pointer to set to the content buffer.
1612 * @len: integer pointer to hold the length of the content
1613 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001614 * Check if all the content was read
1615 *
Daniel Veillardf012a642001-07-23 19:10:52 +00001616 * Returns 0 if all the content was read and available, returns
1617 * -1 if received content length was less than specified or an error
1618 * occurred.
1619 */
1620int
1621xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
1622 xmlNanoHTTPCtxtPtr ctxt = ctx;
1623
1624 int rc = 0;
1625 int cur_lgth;
1626 int rcvd_lgth;
1627 int dummy_int;
1628 char * dummy_ptr = NULL;
1629
1630 /* Dummy up return input parameters if not provided */
1631
1632 if ( len == NULL )
1633 len = &dummy_int;
1634
1635 if ( ptr == NULL )
1636 ptr = &dummy_ptr;
1637
1638 /* But can't work without the context pointer */
1639
1640 if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
1641 *len = 0;
1642 *ptr = NULL;
1643 return ( -1 );
1644 }
1645
1646 rcvd_lgth = ctxt->inptr - ctxt->content;
1647
1648 while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
1649
1650 rcvd_lgth += cur_lgth;
1651 if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
1652 break;
1653 }
1654
1655 *ptr = ctxt->content;
1656 *len = rcvd_lgth;
1657
1658 if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
1659 rc = -1;
1660 else if ( rcvd_lgth == 0 )
1661 rc = -1;
1662
1663 return ( rc );
1664}
1665
Owen Taylor3473f882001-02-23 17:55:21 +00001666#ifdef STANDALONE
1667int main(int argc, char **argv) {
1668 char *contentType = NULL;
1669
1670 if (argv[1] != NULL) {
1671 if (argv[2] != NULL)
1672 xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1673 else
1674 xmlNanoHTTPFetch(argv[1], "-", &contentType);
1675 if (contentType != NULL) xmlFree(contentType);
1676 } else {
1677 xmlGenericError(xmlGenericErrorContext,
1678 "%s: minimal HTTP GET implementation\n", argv[0]);
1679 xmlGenericError(xmlGenericErrorContext,
1680 "\tusage %s [ URL [ filename ] ]\n", argv[0]);
1681 }
1682 xmlNanoHTTPCleanup();
1683 xmlMemoryDump();
1684 return(0);
1685}
1686#endif /* STANDALONE */
1687#else /* !LIBXML_HTTP_ENABLED */
1688#ifdef STANDALONE
1689#include <stdio.h>
1690int main(int argc, char **argv) {
1691 xmlGenericError(xmlGenericErrorContext,
1692 "%s : HTTP support not compiled in\n", argv[0]);
1693 return(0);
1694}
1695#endif /* STANDALONE */
1696#endif /* LIBXML_HTTP_ENABLED */