blob: e80b88b84407de631f61cbc65720636bc4bd679a [file] [log] [blame]
Daniel Veillard4ecf39f1999-09-22 12:14:03 +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 *
11 * Daniel.Veillard@w3.org
12 */
13
14/* TODO add compression support, Send the Accept- , and decompress on the
15 fly with ZLIB if found at compile-time */
16
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#ifdef WIN32
Daniel Veillard0142b842000-01-14 14:45:24 +000018#define INCLUDE_WINSOCK
Daniel Veillard3c558c31999-12-22 11:30:41 +000019#include "win32config.h"
20#else
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000021#include "config.h"
22#endif
23
Daniel Veillardb71379b2000-10-09 12:30:39 +000024#include <libxml/xmlversion.h>
Daniel Veillard3c558c31999-12-22 11:30:41 +000025
Daniel Veillard361d8452000-04-03 19:48:13 +000026#ifdef LIBXML_HTTP_ENABLED
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000027#include <stdio.h>
28#include <string.h>
29
30#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36#ifdef HAVE_SYS_SOCKET_H
37#include <sys/socket.h>
38#endif
39#ifdef HAVE_NETINET_IN_H
40#include <netinet/in.h>
41#endif
42#ifdef HAVE_ARPA_INET_H
43#include <arpa/inet.h>
44#endif
45#ifdef HAVE_NETDB_H
46#include <netdb.h>
47#endif
48#ifdef HAVE_FCNTL_H
49#include <fcntl.h>
50#endif
51#ifdef HAVE_ERRNO_H
52#include <errno.h>
53#endif
54#ifdef HAVE_SYS_TIME_H
55#include <sys/time.h>
56#endif
57#ifdef HAVE_SYS_SELECT_H
58#include <sys/select.h>
59#endif
Daniel Veillard5feb8492000-02-02 17:15:36 +000060#ifdef HAVE_STRINGS_H
61#include <strings.h>
62#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000063
Daniel Veillardce6e98d2000-11-25 09:54:49 +000064#ifdef VMS
65#include <stropts>
66#define SOCKLEN_T unsigned int
67#define SOCKET int
68#endif
69
Daniel Veillard361d8452000-04-03 19:48:13 +000070#include <libxml/xmlmemory.h>
Daniel Veillardb656ebe2000-09-22 13:51:48 +000071#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
Daniel Veillard361d8452000-04-03 19:48:13 +000072#include <libxml/nanohttp.h>
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000073
Daniel Veillard2f971a22000-10-12 23:26:32 +000074/**
75 * A couple portability macros
76 */
77#ifndef _WINSOCKAPI_
78#define closesocket(s) close(s)
79#define SOCKET int
80#endif
81
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000082#ifdef STANDALONE
83#define DEBUG_HTTP
Daniel Veillardb656ebe2000-09-22 13:51:48 +000084#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
Daniel Veillard8ddb5a72000-09-23 10:28:52 +000085#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000086#endif
87
88#define XML_NANO_HTTP_MAX_REDIR 10
89
90#define XML_NANO_HTTP_CHUNK 4096
91
92#define XML_NANO_HTTP_CLOSED 0
93#define XML_NANO_HTTP_WRITE 1
94#define XML_NANO_HTTP_READ 2
95#define XML_NANO_HTTP_NONE 4
96
97typedef struct xmlNanoHTTPCtxt {
98 char *protocol; /* the protocol name */
99 char *hostname; /* the host name */
100 int port; /* the port */
101 char *path; /* the path within the URL */
Daniel Veillard2f971a22000-10-12 23:26:32 +0000102 SOCKET fd; /* the file descriptor for the socket */
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000103 int state; /* WRITE / READ / CLOSED */
104 char *out; /* buffer sent (zero terminated) */
105 char *outptr; /* index within the buffer sent */
106 char *in; /* the receiving buffer */
107 char *content; /* the start of the content */
108 char *inptr; /* the next byte to read from network */
109 char *inrptr; /* the next byte to give back to the client */
110 int inlen; /* len of the input buffer */
111 int last; /* return code for last operation */
112 int returnValue; /* the protocol return value */
113 char *contentType; /* the MIME type for the input */
114 char *location; /* the new URL in case of redirect */
Daniel Veillardc2def842000-11-07 14:21:01 +0000115 char *authHeader; /* contents of {WWW,Proxy}-Authenticate header */
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000116} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
117
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000118static int initialized = 0;
Daniel Veillard19d61112000-10-11 23:50:35 +0000119static char *proxy = NULL; /* the proxy name if any */
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000120static int proxyPort; /* the proxy port if any */
Daniel Veillard19d61112000-10-11 23:50:35 +0000121static unsigned int timeout = 60;/* the select() timeout in seconds */
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000122
123/**
Daniel Veillard2f971a22000-10-12 23:26:32 +0000124 * A portability function
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000125 */
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000126int socket_errno(void) {
127#ifdef _WINSOCKAPI_
128 return(WSAGetLastError());
129#else
130 return(errno);
131#endif
132}
133
134/**
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000135 * xmlNanoHTTPInit:
136 *
137 * Initialize the HTTP protocol layer.
138 * Currently it just checks for proxy informations
139 */
140
141void
142xmlNanoHTTPInit(void) {
143 const char *env;
Daniel Veillard2f971a22000-10-12 23:26:32 +0000144#ifdef _WINSOCKAPI_
145 WSADATA wsaData;
146#endif
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000147
148 if (initialized)
149 return;
150
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000151#ifdef _WINSOCKAPI_
Daniel Veillard2f971a22000-10-12 23:26:32 +0000152 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
153 return;
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000154#endif
155
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000156 if (proxy == NULL) {
157 proxyPort = 80;
158 env = getenv("no_proxy");
159 if (env != NULL)
160 goto done;
161 env = getenv("http_proxy");
162 if (env != NULL) {
163 xmlNanoHTTPScanProxy(env);
164 goto done;
165 }
166 env = getenv("HTTP_PROXY");
167 if (env != NULL) {
168 xmlNanoHTTPScanProxy(env);
169 goto done;
170 }
171 }
172done:
173 initialized = 1;
174}
175
176/**
177 * xmlNanoHTTPClenup:
178 *
179 * Cleanup the HTTP protocol layer.
180 */
181
182void
183xmlNanoHTTPCleanup(void) {
184 if (proxy != NULL)
185 xmlFree(proxy);
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000186#ifdef _WINSOCKAPI_
Daniel Veillard2f971a22000-10-12 23:26:32 +0000187 if (initialized)
188 WSACleanup();
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000189#endif
Daniel Veillard2f971a22000-10-12 23:26:32 +0000190 initialized = 0;
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000191 return;
192}
193
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000194/**
Daniel Veillard19d61112000-10-11 23:50:35 +0000195 * xmlNanoHTTPTimeout:
196 * @delay: the delay in seconds
197 *
198 * Set the HTTP timeout, (default is 60secs). 0 means immediate
199 * return, while -1 infinite.
200 */
201
202void
203xmlNanoHTTPTimeout(int delay) {
204 timeout = (unsigned int) delay;
205}
206
207/**
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000208 * xmlNanoHTTPScanURL:
209 * @ctxt: an HTTP context
210 * @URL: The URL used to initialize the context
211 *
212 * (Re)Initialize an HTTP context by parsing the URL and finding
213 * the protocol host port and path it indicates.
214 */
215
216static void
217xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
218 const char *cur = URL;
219 char buf[4096];
220 int index = 0;
221 int port = 0;
222
223 if (ctxt->protocol != NULL) {
224 xmlFree(ctxt->protocol);
225 ctxt->protocol = NULL;
226 }
227 if (ctxt->hostname != NULL) {
228 xmlFree(ctxt->hostname);
229 ctxt->hostname = NULL;
230 }
231 if (ctxt->path != NULL) {
232 xmlFree(ctxt->path);
233 ctxt->path = NULL;
234 }
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000235 if (URL == NULL) return;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000236 buf[index] = 0;
237 while (*cur != 0) {
238 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
239 buf[index] = 0;
240 ctxt->protocol = xmlMemStrdup(buf);
241 index = 0;
242 cur += 3;
243 break;
244 }
245 buf[index++] = *cur++;
246 }
247 if (*cur == 0) return;
248
249 buf[index] = 0;
250 while (1) {
251 if (cur[0] == ':') {
252 buf[index] = 0;
253 ctxt->hostname = xmlMemStrdup(buf);
254 index = 0;
255 cur += 1;
256 while ((*cur >= '0') && (*cur <= '9')) {
257 port *= 10;
258 port += *cur - '0';
259 cur++;
260 }
261 if (port != 0) ctxt->port = port;
262 while ((cur[0] != '/') && (*cur != 0))
263 cur++;
264 break;
265 }
266 if ((*cur == '/') || (*cur == 0)) {
267 buf[index] = 0;
268 ctxt->hostname = xmlMemStrdup(buf);
269 index = 0;
270 break;
271 }
272 buf[index++] = *cur++;
273 }
274 if (*cur == 0)
275 ctxt->path = xmlMemStrdup("/");
276 else {
Daniel Veillard726e8792000-01-30 20:04:29 +0000277 index = 0;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000278 buf[index] = 0;
Daniel Veillard726e8792000-01-30 20:04:29 +0000279 while (*cur != 0)
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000280 buf[index++] = *cur++;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000281 buf[index] = 0;
282 ctxt->path = xmlMemStrdup(buf);
283 }
284}
285
286/**
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000287 * xmlNanoHTTPScanProxy:
288 * @URL: The proxy URL used to initialize the proxy context
289 *
290 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
291 * the protocol host port it indicates.
292 * Should be like http://myproxy/ or http://myproxy:3128/
293 * A NULL URL cleans up proxy informations.
294 */
295
296void
297xmlNanoHTTPScanProxy(const char *URL) {
298 const char *cur = URL;
299 char buf[4096];
300 int index = 0;
301 int port = 0;
302
303 if (proxy != NULL) {
304 xmlFree(proxy);
305 proxy = NULL;
306 }
307 if (proxyPort != 0) {
308 proxyPort = 0;
309 }
310#ifdef DEBUG_HTTP
311 if (URL == NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000312 xmlGenericError(xmlGenericErrorContext,
313 "Removing HTTP proxy info\n");
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000314 else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000315 xmlGenericError(xmlGenericErrorContext,
316 "Using HTTP proxy %s\n", URL);
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000317#endif
318 if (URL == NULL) return;
319 buf[index] = 0;
320 while (*cur != 0) {
321 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
322 buf[index] = 0;
323 index = 0;
324 cur += 3;
325 break;
326 }
327 buf[index++] = *cur++;
328 }
329 if (*cur == 0) return;
330
331 buf[index] = 0;
332 while (1) {
333 if (cur[0] == ':') {
334 buf[index] = 0;
335 proxy = xmlMemStrdup(buf);
336 index = 0;
337 cur += 1;
338 while ((*cur >= '0') && (*cur <= '9')) {
339 port *= 10;
340 port += *cur - '0';
341 cur++;
342 }
343 if (port != 0) proxyPort = port;
344 while ((cur[0] != '/') && (*cur != 0))
345 cur++;
346 break;
347 }
348 if ((*cur == '/') || (*cur == 0)) {
349 buf[index] = 0;
350 proxy = xmlMemStrdup(buf);
351 index = 0;
352 break;
353 }
354 buf[index++] = *cur++;
355 }
356}
357
358/**
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000359 * xmlNanoHTTPNewCtxt:
360 * @URL: The URL used to initialize the context
361 *
362 * Allocate and initialize a new HTTP context.
363 *
364 * Returns an HTTP context or NULL in case of error.
365 */
366
367static xmlNanoHTTPCtxtPtr
368xmlNanoHTTPNewCtxt(const char *URL) {
369 xmlNanoHTTPCtxtPtr ret;
370
371 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
372 if (ret == NULL) return(NULL);
373
374 memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
375 ret->port = 80;
376 ret->returnValue = 0;
377
378 xmlNanoHTTPScanURL(ret, URL);
379
380 return(ret);
381}
382
383/**
384 * xmlNanoHTTPFreeCtxt:
385 * @ctxt: an HTTP context
386 *
387 * Frees the context after closing the connection.
388 */
389
390static void
391xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
392 if (ctxt == NULL) return;
393 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
394 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
395 if (ctxt->path != NULL) xmlFree(ctxt->path);
396 if (ctxt->out != NULL) xmlFree(ctxt->out);
397 if (ctxt->in != NULL) xmlFree(ctxt->in);
398 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
399 if (ctxt->location != NULL) xmlFree(ctxt->location);
Daniel Veillardc2def842000-11-07 14:21:01 +0000400 if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000401 ctxt->state = XML_NANO_HTTP_NONE;
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000402 if (ctxt->fd >= 0) closesocket(ctxt->fd);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000403 ctxt->fd = -1;
404 xmlFree(ctxt);
405}
406
407/**
408 * xmlNanoHTTPSend:
409 * @ctxt: an HTTP context
410 *
411 * Send the input needed to initiate the processing on the server side
412 */
413
414static void
415xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
Daniel Veillard683cb022000-10-22 12:04:13 +0000416 if (ctxt->state & XML_NANO_HTTP_WRITE) {
417 int total_sent = 0;
418 while (total_sent <strlen(ctxt->outptr)) {
419 int nsent = send(ctxt->fd, ctxt->outptr+total_sent,
420 strlen(ctxt->outptr)-total_sent, 0);
421 if (nsent>0)
422 total_sent += nsent;
423}
424
425 ctxt->last = total_sent;
426 }
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000427}
428
429/**
430 * xmlNanoHTTPRecv:
431 * @ctxt: an HTTP context
432 *
433 * Read information coming from the HTTP connection.
434 * This is a blocking call (but it blocks in select(), not read()).
435 *
436 * Returns the number of byte read or -1 in case of error.
437 */
438
439static int
440xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
441 fd_set rfd;
442 struct timeval tv;
443
444
445 while (ctxt->state & XML_NANO_HTTP_READ) {
446 if (ctxt->in == NULL) {
447 ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
448 if (ctxt->in == NULL) {
449 ctxt->last = -1;
450 return(-1);
451 }
452 ctxt->inlen = 65000;
453 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
454 }
455 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
456 int delta = ctxt->inrptr - ctxt->in;
457 int len = ctxt->inptr - ctxt->inrptr;
458
459 memmove(ctxt->in, ctxt->inrptr, len);
460 ctxt->inrptr -= delta;
461 ctxt->content -= delta;
462 ctxt->inptr -= delta;
463 }
464 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
465 int d_inptr = ctxt->inptr - ctxt->in;
466 int d_content = ctxt->content - ctxt->in;
467 int d_inrptr = ctxt->inrptr - ctxt->in;
468
469 ctxt->inlen *= 2;
470 ctxt->in = (char *) xmlRealloc(ctxt->in, ctxt->inlen);
471 if (ctxt->in == NULL) {
472 ctxt->last = -1;
473 return(-1);
474 }
475 ctxt->inptr = ctxt->in + d_inptr;
476 ctxt->content = ctxt->in + d_content;
477 ctxt->inrptr = ctxt->in + d_inrptr;
478 }
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000479 ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000480 if (ctxt->last > 0) {
481 ctxt->inptr += ctxt->last;
482 return(ctxt->last);
483 }
484 if (ctxt->last == 0) {
485 return(0);
486 }
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000487 if (ctxt->last == -1) {
488 switch (socket_errno()) {
489 case EINPROGRESS:
490 case EWOULDBLOCK:
491#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
492 case EAGAIN:
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000493#endif
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000494 break;
495 default:
496 return(0);
497 }
498 }
499
Daniel Veillard19d61112000-10-11 23:50:35 +0000500 tv.tv_sec = timeout;
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000501 tv.tv_usec = 0;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000502 FD_ZERO(&rfd);
503 FD_SET(ctxt->fd, &rfd);
504
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000505 if (select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000506 return(0);
507 }
508 return(0);
509}
510
511/**
512 * xmlNanoHTTPReadLine:
513 * @ctxt: an HTTP context
514 *
515 * Read one line in the HTTP server output, usually for extracting
516 * the HTTP protocol informations from the answer header.
517 *
518 * Returns a newly allocated string with a copy of the line, or NULL
519 * which indicate the end of the input.
520 */
521
522static char *
523xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
524 char buf[4096];
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000525 char *bp = buf;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000526
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000527 while (bp - buf < 4095) {
528 if (ctxt->inrptr == ctxt->inptr) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000529 if (xmlNanoHTTPRecv(ctxt) == 0) {
530 if (bp == buf)
531 return(NULL);
532 else
533 *bp = 0;
534 return(xmlMemStrdup(buf));
535 }
536 }
537 *bp = *ctxt->inrptr++;
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000538 if (*bp == '\n') {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000539 *bp = 0;
540 return(xmlMemStrdup(buf));
541 }
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000542 if (*bp != '\r')
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000543 bp++;
544 }
545 buf[4095] = 0;
546 return(xmlMemStrdup(buf));
547}
548
549
550/**
551 * xmlNanoHTTPScanAnswer:
552 * @ctxt: an HTTP context
553 * @line: an HTTP header line
554 *
555 * Try to extract useful informations from the server answer.
556 * We currently parse and process:
557 * - The HTTP revision/ return code
558 * - The Content-Type
559 * - The Location for redirrect processing.
560 *
561 * Returns -1 in case of failure, the file descriptor number otherwise
562 */
563
564static void
565xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
566 const char *cur = line;
567
568 if (line == NULL) return;
569
570 if (!strncmp(line, "HTTP/", 5)) {
571 int version = 0;
572 int ret = 0;
573
574 cur += 5;
575 while ((*cur >= '0') && (*cur <= '9')) {
576 version *= 10;
577 version += *cur - '0';
578 cur++;
579 }
580 if (*cur == '.') {
581 cur++;
582 if ((*cur >= '0') && (*cur <= '9')) {
583 version *= 10;
584 version += *cur - '0';
585 cur++;
586 }
587 while ((*cur >= '0') && (*cur <= '9'))
588 cur++;
589 } else
590 version *= 10;
591 if ((*cur != ' ') && (*cur != '\t')) return;
592 while ((*cur == ' ') || (*cur == '\t')) cur++;
593 if ((*cur < '0') || (*cur > '9')) return;
594 while ((*cur >= '0') && (*cur <= '9')) {
595 ret *= 10;
596 ret += *cur - '0';
597 cur++;
598 }
599 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
600 ctxt->returnValue = ret;
Daniel Veillardb656ebe2000-09-22 13:51:48 +0000601 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000602 cur += 13;
603 while ((*cur == ' ') || (*cur == '\t')) cur++;
604 if (ctxt->contentType != NULL)
605 xmlFree(ctxt->contentType);
606 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillardb656ebe2000-09-22 13:51:48 +0000607 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000608 cur += 12;
609 if (ctxt->contentType != NULL) return;
610 while ((*cur == ' ') || (*cur == '\t')) cur++;
611 ctxt->contentType = xmlMemStrdup(cur);
Daniel Veillardb656ebe2000-09-22 13:51:48 +0000612 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000613 cur += 9;
614 while ((*cur == ' ') || (*cur == '\t')) cur++;
615 if (ctxt->location != NULL)
616 xmlFree(ctxt->location);
617 ctxt->location = xmlMemStrdup(cur);
Daniel Veillardc2def842000-11-07 14:21:01 +0000618 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
619 cur += 17;
620 while ((*cur == ' ') || (*cur == '\t')) cur++;
621 if (ctxt->authHeader != NULL)
622 xmlFree(ctxt->authHeader);
623 ctxt->authHeader = xmlMemStrdup(cur);
624 } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
625 cur += 19;
626 while ((*cur == ' ') || (*cur == '\t')) cur++;
627 if (ctxt->authHeader != NULL)
628 xmlFree(ctxt->authHeader);
629 ctxt->authHeader = xmlMemStrdup(cur);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000630 }
631}
632
633/**
634 * xmlNanoHTTPConnectAttempt:
635 * @ia: an internet adress structure
636 * @port: the port number
637 *
638 * Attempt a connection to the given IP:port endpoint. It forces
639 * non-blocking semantic on the socket, and allow 60 seconds for
640 * the host to answer.
641 *
642 * Returns -1 in case of failure, the file descriptor number otherwise
643 */
644
645static int
646xmlNanoHTTPConnectAttempt(struct in_addr ia, int port)
647{
Daniel Veillard2f971a22000-10-12 23:26:32 +0000648 SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000649 struct sockaddr_in sin;
650 fd_set wfd;
651 struct timeval tv;
652 int status;
653
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000654 if (s==-1) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000655#ifdef DEBUG_HTTP
656 perror("socket");
657#endif
658 return(-1);
659 }
660
661#ifdef _WINSOCKAPI_
662 {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000663 u_long one = 1;
664
665 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
666 }
667#else /* _WINSOCKAPI_ */
668#if defined(VMS)
669 {
670 int enable = 1;
Daniel Veillardce6e98d2000-11-25 09:54:49 +0000671 status = ioctl(s, FIONBIO, &enable);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000672 }
673#else /* VMS */
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000674 if ((status = fcntl(s, F_GETFL, 0)) != -1) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000675#ifdef O_NONBLOCK
676 status |= O_NONBLOCK;
677#else /* O_NONBLOCK */
678#ifdef F_NDELAY
679 status |= F_NDELAY;
680#endif /* F_NDELAY */
681#endif /* !O_NONBLOCK */
682 status = fcntl(s, F_SETFL, status);
683 }
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000684 if (status < 0) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000685#ifdef DEBUG_HTTP
686 perror("nonblocking");
687#endif
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000688 closesocket(s);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000689 return(-1);
690 }
691#endif /* !VMS */
692#endif /* !_WINSOCKAPI_ */
693
694
695 sin.sin_family = AF_INET;
696 sin.sin_addr = ia;
697 sin.sin_port = htons(port);
698
Daniel Veillard2f971a22000-10-12 23:26:32 +0000699 if ((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1)) {
700 switch (socket_errno()) {
701 case EINPROGRESS:
702 case EWOULDBLOCK:
703 break;
704 default:
705 perror("connect");
706 closesocket(s);
707 return(-1);
708 }
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000709 }
710
Daniel Veillard19d61112000-10-11 23:50:35 +0000711 tv.tv_sec = timeout;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000712 tv.tv_usec = 0;
713
714 FD_ZERO(&wfd);
715 FD_SET(s, &wfd);
716
717 switch(select(s+1, NULL, &wfd, NULL, &tv))
718 {
719 case 0:
720 /* Time out */
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000721 closesocket(s);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000722 return(-1);
723 case -1:
724 /* Ermm.. ?? */
725#ifdef DEBUG_HTTP
726 perror("select");
727#endif
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000728 closesocket(s);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000729 return(-1);
730 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000731
732 if ( FD_ISSET(s, &wfd) ) {
Daniel Veillardb0426ca2000-10-11 23:39:43 +0000733 SOCKLEN_T len;
Daniel Veillardbe803962000-06-28 23:40:59 +0000734 len = sizeof(status);
Daniel Veillard2f971a22000-10-12 23:26:32 +0000735 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0 ) {
Daniel Veillardbe803962000-06-28 23:40:59 +0000736 /* Solaris error code */
737 return (-1);
738 }
739 if ( status ) {
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000740 closesocket(s);
Daniel Veillardbe803962000-06-28 23:40:59 +0000741 errno = status;
742 return (-1);
743 }
744 } else {
745 /* pbm */
746 return (-1);
747 }
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000748
749 return(s);
750}
751
752/**
753 * xmlNanoHTTPConnectHost:
754 * @host: the host name
755 * @port: the port number
756 *
757 * Attempt a connection to the given host:port endpoint. It tries
758 * the multiple IP provided by the DNS if available.
759 *
760 * Returns -1 in case of failure, the file descriptor number otherwise
761 */
762
763static int
764xmlNanoHTTPConnectHost(const char *host, int port)
765{
766 struct hostent *h;
767 int i;
768 int s;
769
770 h=gethostbyname(host);
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000771 if (h==NULL)
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000772 {
773#ifdef DEBUG_HTTP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000774 xmlGenericError(xmlGenericErrorContext,"unable to resolve '%s'.\n", host);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000775#endif
776 return(-1);
777 }
778
779 for(i=0; h->h_addr_list[i]; i++)
780 {
781 struct in_addr ia;
782 memcpy(&ia, h->h_addr_list[i],4);
783 s = xmlNanoHTTPConnectAttempt(ia, port);
Daniel Veillarde8282ed2000-10-10 23:01:31 +0000784 if (s != -1)
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000785 return(s);
786 }
787
788#ifdef DEBUG_HTTP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000789 xmlGenericError(xmlGenericErrorContext,
790 "unable to connect to '%s'.\n", host);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000791#endif
792 return(-1);
793}
794
795
796/**
797 * xmlNanoHTTPOpen:
798 * @URL: The URL to load
799 * @contentType: if available the Content-Type information will be
800 * returned at that location
801 *
802 * This function try to open a connection to the indicated resource
803 * via HTTP GET.
804 *
805 * Returns NULL in case of failure, otherwise a request handler.
806 * The contentType, if provided must be freed by the caller
807 */
808
Daniel Veillard06047432000-04-24 11:33:38 +0000809void*
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000810xmlNanoHTTPOpen(const char *URL, char **contentType) {
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000811 if (contentType != NULL) *contentType = NULL;
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000812 return xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000813}
814
815/**
816 * xmlNanoHTTPRead:
817 * @ctx: the HTTP context
818 * @dest: a buffer
819 * @len: the buffer length
820 *
821 * This function tries to read @len bytes from the existing HTTP connection
822 * and saves them in @dest. This is a blocking call.
823 *
824 * Returns the number of byte read. 0 is an indication of an end of connection.
825 * -1 indicates a parameter error.
826 */
827int
828xmlNanoHTTPRead(void *ctx, void *dest, int len) {
829 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
830
831 if (ctx == NULL) return(-1);
832 if (dest == NULL) return(-1);
833 if (len <= 0) return(0);
834
835 while (ctxt->inptr - ctxt->inrptr < len) {
836 if (xmlNanoHTTPRecv(ctxt) == 0) break;
837 }
838 if (ctxt->inptr - ctxt->inrptr < len)
839 len = ctxt->inptr - ctxt->inrptr;
840 memcpy(dest, ctxt->inrptr, len);
841 ctxt->inrptr += len;
842 return(len);
843}
844
845/**
846 * xmlNanoHTTPClose:
847 * @ctx: the HTTP context
848 *
849 * This function closes an HTTP context, it ends up the connection and
850 * free all data related to it.
851 */
852void
853xmlNanoHTTPClose(void *ctx) {
854 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
855
856 if (ctx == NULL) return;
857
858 xmlNanoHTTPFreeCtxt(ctxt);
859}
860
861/**
862 * xmlNanoHTTPMethod:
863 * @URL: The URL to load
864 * @method: the HTTP method to use
865 * @input: the input string if any
866 * @contentType: the Content-Type information IN and OUT
867 * @headers: the extra headers
868 *
869 * This function try to open a connection to the indicated resource
870 * via HTTP using the given @method, adding the given extra headers
871 * and the input buffer for the request content.
872 *
873 * Returns NULL in case of failure, otherwise a request handler.
874 * The contentType, if provided must be freed by the caller
875 */
876
Daniel Veillard06047432000-04-24 11:33:38 +0000877void*
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000878xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
879 char **contentType, const char *headers) {
880 xmlNanoHTTPCtxtPtr ctxt;
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000881 char *bp, *p;
882 int blen, ilen, ret;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000883 int head;
884 int nbRedirects = 0;
885 char *redirURL = NULL;
886
887 if (URL == NULL) return(NULL);
888 if (method == NULL) method = "GET";
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000889 xmlNanoHTTPInit();
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000890
891retry:
892 if (redirURL == NULL)
893 ctxt = xmlNanoHTTPNewCtxt(URL);
894 else {
895 ctxt = xmlNanoHTTPNewCtxt(redirURL);
896 xmlFree(redirURL);
897 redirURL = NULL;
898 }
899
900 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
901 xmlNanoHTTPFreeCtxt(ctxt);
902 if (redirURL != NULL) xmlFree(redirURL);
903 return(NULL);
904 }
905 if (ctxt->hostname == NULL) {
906 xmlNanoHTTPFreeCtxt(ctxt);
907 return(NULL);
908 }
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000909 if (proxy) {
910 blen = strlen(ctxt->hostname) * 2 + 16;
911 ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
912 }
913 else {
914 blen = strlen(ctxt->hostname);
915 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
916 }
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000917 if (ret < 0) {
918 xmlNanoHTTPFreeCtxt(ctxt);
919 return(NULL);
920 }
921 ctxt->fd = ret;
922
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000923 if (input != NULL) {
924 ilen = strlen(input);
925 blen += ilen + 32;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000926 }
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000927 else
928 ilen = 0;
929 if (headers != NULL)
930 blen += strlen(headers);
931 if (contentType && *contentType)
932 blen += strlen(*contentType) + 16;
933 blen += strlen(method) + strlen(ctxt->path) + 23;
934 bp = xmlMalloc(blen);
935 if (proxy) {
936 if (ctxt->port != 80) {
937 sprintf(bp, "%s http://%s:%d%s", method, ctxt->hostname,
938 ctxt->port, ctxt->path);
939 }
940 else
941 sprintf(bp, "%s http://%s%s", method, ctxt->hostname, ctxt->path);
942 }
943 else
944 sprintf(bp, "%s %s", method, ctxt->path);
945 p = bp + strlen(bp);
946 sprintf(p, " HTTP/1.0\r\nHost: %s\r\n", ctxt->hostname);
947 p += strlen(p);
948 if (contentType != NULL && *contentType) {
949 sprintf(p, "Content-Type: %s\r\n", *contentType);
950 p += strlen(p);
951 }
952 if (headers != NULL) {
953 strcpy(p, headers);
954 p += strlen(p);
955 }
956 if (input != NULL)
957 sprintf(p, "Content-Length: %d\r\n\r\n%s", ilen, input);
958 else
959 strcpy(p, "\r\n");
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000960#ifdef DEBUG_HTTP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000961 xmlGenericError(xmlGenericErrorContext,
962 "-> %s%s", proxy? "(Proxy) " : "", bp);
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000963 if ((blen -= strlen(bp)+1) < 0)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000964 xmlGenericError(xmlGenericErrorContext,
965 "ERROR: overflowed buffer by %d bytes\n", -blen);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000966#endif
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000967 ctxt->outptr = ctxt->out = bp;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000968 ctxt->state = XML_NANO_HTTP_WRITE;
969 xmlNanoHTTPSend(ctxt);
970 ctxt->state = XML_NANO_HTTP_READ;
971 head = 1;
972
973 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
974 if (head && (*p == 0)) {
975 head = 0;
976 ctxt->content = ctxt->inrptr;
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000977 xmlFree(p);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000978 break;
979 }
980 xmlNanoHTTPScanAnswer(ctxt, p);
981
982#ifdef DEBUG_HTTP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000983 xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000984#endif
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +0000985 xmlFree(p);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000986 }
987
988 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
989 (ctxt->returnValue < 400)) {
990#ifdef DEBUG_HTTP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000991 xmlGenericError(xmlGenericErrorContext,
992 "\nRedirect to: %s\n", ctxt->location);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000993#endif
994 while (xmlNanoHTTPRecv(ctxt)) ;
995 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
996 nbRedirects++;
997 redirURL = xmlMemStrdup(ctxt->location);
998 xmlNanoHTTPFreeCtxt(ctxt);
999 goto retry;
1000 }
1001 xmlNanoHTTPFreeCtxt(ctxt);
1002#ifdef DEBUG_HTTP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001003 xmlGenericError(xmlGenericErrorContext,
1004 "Too many redirects, aborting ...\n");
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001005#endif
1006 return(NULL);
1007
1008 }
1009
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00001010 if (contentType != NULL) {
1011 if (ctxt->contentType != NULL)
1012 *contentType = xmlMemStrdup(ctxt->contentType);
1013 else
1014 *contentType = NULL;
1015 }
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001016
1017#ifdef DEBUG_HTTP
1018 if (ctxt->contentType != NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001019 xmlGenericError(xmlGenericErrorContext,
1020 "\nCode %d, content-type '%s'\n\n",
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001021 ctxt->returnValue, ctxt->contentType);
1022 else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001023 xmlGenericError(xmlGenericErrorContext,
1024 "\nCode %d, no content-type\n\n",
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001025 ctxt->returnValue);
1026#endif
1027
1028 return((void *) ctxt);
1029}
1030
1031/**
1032 * xmlNanoHTTPFetch:
1033 * @URL: The URL to load
1034 * @filename: the filename where the content should be saved
1035 * @contentType: if available the Content-Type information will be
1036 * returned at that location
1037 *
1038 * This function try to fetch the indicated resource via HTTP GET
1039 * and save it's content in the file.
1040 *
1041 * Returns -1 in case of failure, 0 incase of success. The contentType,
1042 * if provided must be freed by the caller
1043 */
1044int
1045xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
1046 void *ctxt;
1047 char buf[4096];
1048 int fd;
1049 int len;
1050
1051 ctxt = xmlNanoHTTPOpen(URL, contentType);
1052 if (ctxt == NULL) return(-1);
1053
1054 if (!strcmp(filename, "-"))
1055 fd = 0;
1056 else {
Daniel Veillarde41f2b72000-01-30 20:00:07 +00001057 fd = open(filename, O_CREAT | O_WRONLY, 00644);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001058 if (fd < 0) {
1059 xmlNanoHTTPClose(ctxt);
1060 if ((contentType != NULL) && (*contentType != NULL)) {
1061 xmlFree(*contentType);
1062 *contentType = NULL;
1063 }
1064 return(-1);
1065 }
1066 }
1067
1068 while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
1069 write(fd, buf, len);
1070 }
1071
1072 xmlNanoHTTPClose(ctxt);
Daniel Veillarde41f2b72000-01-30 20:00:07 +00001073 close(fd);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001074 return(0);
1075}
1076
1077/**
1078 * xmlNanoHTTPSave:
Daniel Veillard00fdf371999-10-08 09:40:39 +00001079 * @ctxt: the HTTP context
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001080 * @filename: the filename where the content should be saved
1081 *
1082 * This function saves the output of the HTTP transaction to a file
1083 * It closes and free the context at the end
1084 *
1085 * Returns -1 in case of failure, 0 incase of success.
1086 */
1087int
1088xmlNanoHTTPSave(void *ctxt, const char *filename) {
1089 char buf[4096];
1090 int fd;
1091 int len;
1092
1093 if (ctxt == NULL) return(-1);
1094
1095 if (!strcmp(filename, "-"))
1096 fd = 0;
1097 else {
1098 fd = open(filename, O_CREAT | O_WRONLY);
1099 if (fd < 0) {
1100 xmlNanoHTTPClose(ctxt);
1101 return(-1);
1102 }
1103 }
1104
1105 while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
1106 write(fd, buf, len);
1107 }
1108
1109 xmlNanoHTTPClose(ctxt);
1110 return(0);
1111}
1112
1113/**
1114 * xmlNanoHTTPReturnCode:
1115 * @ctx: the HTTP context
1116 *
1117 * Returns the HTTP return code for the request.
1118 */
1119int
1120xmlNanoHTTPReturnCode(void *ctx) {
1121 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1122
1123 if (ctxt == NULL) return(-1);
1124
1125 return(ctxt->returnValue);
1126}
1127
Daniel Veillardc2def842000-11-07 14:21:01 +00001128/**
1129 * xmlNanoHTTPAuthHeader:
1130 * @ctx: the HTTP context
1131 *
1132 * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
1133 * header.
1134 */
1135const char *
1136xmlNanoHTTPAuthHeader(void *ctx) {
1137 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1138
1139 if (ctxt == NULL) return(NULL);
1140
1141 return(ctxt->authHeader);
1142}
1143
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001144#ifdef STANDALONE
1145int main(int argc, char **argv) {
1146 char *contentType = NULL;
1147
1148 if (argv[1] != NULL) {
1149 if (argv[2] != NULL)
1150 xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1151 else
1152 xmlNanoHTTPFetch(argv[1], "-", &contentType);
1153 if (contentType != NULL) xmlFree(contentType);
1154 } else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001155 xmlGenericError(xmlGenericErrorContext,
1156 "%s: minimal HTTP GET implementation\n", argv[0]);
1157 xmlGenericError(xmlGenericErrorContext,
1158 "\tusage %s [ URL [ filename ] ]\n", argv[0]);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001159 }
Daniel Veillarde41f2b72000-01-30 20:00:07 +00001160 xmlNanoHTTPCleanup();
1161 xmlMemoryDump();
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001162 return(0);
1163}
1164#endif /* STANDALONE */
Daniel Veillard361d8452000-04-03 19:48:13 +00001165#else /* !LIBXML_HTTP_ENABLED */
1166#ifdef STANDALONE
1167#include <stdio.h>
1168int main(int argc, char **argv) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001169 xmlGenericError(xmlGenericErrorContext,
1170 "%s : HTTP support not compiled in\n", argv[0]);
Daniel Veillard361d8452000-04-03 19:48:13 +00001171 return(0);
1172}
1173#endif /* STANDALONE */
1174#endif /* LIBXML_HTTP_ENABLED */