blob: 4c63f3716cdccb5acd0c4ebb9db5a6fa6e7cf4c5 [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 Veillard361d8452000-04-03 19:48:13 +000024#include "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 Veillard361d8452000-04-03 19:48:13 +000064#include <libxml/xmlmemory.h>
65#include <libxml/nanohttp.h>
Daniel Veillard4ecf39f1999-09-22 12:14:03 +000066
67#ifdef STANDALONE
68#define DEBUG_HTTP
69#endif
70
71#define XML_NANO_HTTP_MAX_REDIR 10
72
73#define XML_NANO_HTTP_CHUNK 4096
74
75#define XML_NANO_HTTP_CLOSED 0
76#define XML_NANO_HTTP_WRITE 1
77#define XML_NANO_HTTP_READ 2
78#define XML_NANO_HTTP_NONE 4
79
80typedef struct xmlNanoHTTPCtxt {
81 char *protocol; /* the protocol name */
82 char *hostname; /* the host name */
83 int port; /* the port */
84 char *path; /* the path within the URL */
85 int fd; /* the file descriptor for the socket */
86 int state; /* WRITE / READ / CLOSED */
87 char *out; /* buffer sent (zero terminated) */
88 char *outptr; /* index within the buffer sent */
89 char *in; /* the receiving buffer */
90 char *content; /* the start of the content */
91 char *inptr; /* the next byte to read from network */
92 char *inrptr; /* the next byte to give back to the client */
93 int inlen; /* len of the input buffer */
94 int last; /* return code for last operation */
95 int returnValue; /* the protocol return value */
96 char *contentType; /* the MIME type for the input */
97 char *location; /* the new URL in case of redirect */
98} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
99
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000100static int initialized = 0;
101static char *proxy = NULL; /* the proxy name if any */
102static int proxyPort; /* the proxy port if any */
103
104/**
105 * xmlNanoHTTPInit:
106 *
107 * Initialize the HTTP protocol layer.
108 * Currently it just checks for proxy informations
109 */
110
111void
112xmlNanoHTTPInit(void) {
113 const char *env;
114
115 if (initialized)
116 return;
117
118 if (proxy == NULL) {
119 proxyPort = 80;
120 env = getenv("no_proxy");
121 if (env != NULL)
122 goto done;
123 env = getenv("http_proxy");
124 if (env != NULL) {
125 xmlNanoHTTPScanProxy(env);
126 goto done;
127 }
128 env = getenv("HTTP_PROXY");
129 if (env != NULL) {
130 xmlNanoHTTPScanProxy(env);
131 goto done;
132 }
133 }
134done:
135 initialized = 1;
136}
137
138/**
139 * xmlNanoHTTPClenup:
140 *
141 * Cleanup the HTTP protocol layer.
142 */
143
144void
145xmlNanoHTTPCleanup(void) {
146 if (proxy != NULL)
147 xmlFree(proxy);
148 initialized = 0;
149 return;
150}
151
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000152/**
153 * xmlNanoHTTPScanURL:
154 * @ctxt: an HTTP context
155 * @URL: The URL used to initialize the context
156 *
157 * (Re)Initialize an HTTP context by parsing the URL and finding
158 * the protocol host port and path it indicates.
159 */
160
161static void
162xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
163 const char *cur = URL;
164 char buf[4096];
165 int index = 0;
166 int port = 0;
167
168 if (ctxt->protocol != NULL) {
169 xmlFree(ctxt->protocol);
170 ctxt->protocol = NULL;
171 }
172 if (ctxt->hostname != NULL) {
173 xmlFree(ctxt->hostname);
174 ctxt->hostname = NULL;
175 }
176 if (ctxt->path != NULL) {
177 xmlFree(ctxt->path);
178 ctxt->path = NULL;
179 }
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000180 if (URL == NULL) return;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000181 buf[index] = 0;
182 while (*cur != 0) {
183 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
184 buf[index] = 0;
185 ctxt->protocol = xmlMemStrdup(buf);
186 index = 0;
187 cur += 3;
188 break;
189 }
190 buf[index++] = *cur++;
191 }
192 if (*cur == 0) return;
193
194 buf[index] = 0;
195 while (1) {
196 if (cur[0] == ':') {
197 buf[index] = 0;
198 ctxt->hostname = xmlMemStrdup(buf);
199 index = 0;
200 cur += 1;
201 while ((*cur >= '0') && (*cur <= '9')) {
202 port *= 10;
203 port += *cur - '0';
204 cur++;
205 }
206 if (port != 0) ctxt->port = port;
207 while ((cur[0] != '/') && (*cur != 0))
208 cur++;
209 break;
210 }
211 if ((*cur == '/') || (*cur == 0)) {
212 buf[index] = 0;
213 ctxt->hostname = xmlMemStrdup(buf);
214 index = 0;
215 break;
216 }
217 buf[index++] = *cur++;
218 }
219 if (*cur == 0)
220 ctxt->path = xmlMemStrdup("/");
221 else {
Daniel Veillard726e8792000-01-30 20:04:29 +0000222 index = 0;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000223 buf[index] = 0;
Daniel Veillard726e8792000-01-30 20:04:29 +0000224 while (*cur != 0)
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000225 buf[index++] = *cur++;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000226 buf[index] = 0;
227 ctxt->path = xmlMemStrdup(buf);
228 }
229}
230
231/**
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000232 * xmlNanoHTTPScanProxy:
233 * @URL: The proxy URL used to initialize the proxy context
234 *
235 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
236 * the protocol host port it indicates.
237 * Should be like http://myproxy/ or http://myproxy:3128/
238 * A NULL URL cleans up proxy informations.
239 */
240
241void
242xmlNanoHTTPScanProxy(const char *URL) {
243 const char *cur = URL;
244 char buf[4096];
245 int index = 0;
246 int port = 0;
247
248 if (proxy != NULL) {
249 xmlFree(proxy);
250 proxy = NULL;
251 }
252 if (proxyPort != 0) {
253 proxyPort = 0;
254 }
255#ifdef DEBUG_HTTP
256 if (URL == NULL)
257 printf("Removing HTTP proxy info\n");
258 else
259 printf("Using HTTP proxy %s\n", URL);
260#endif
261 if (URL == NULL) return;
262 buf[index] = 0;
263 while (*cur != 0) {
264 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
265 buf[index] = 0;
266 index = 0;
267 cur += 3;
268 break;
269 }
270 buf[index++] = *cur++;
271 }
272 if (*cur == 0) return;
273
274 buf[index] = 0;
275 while (1) {
276 if (cur[0] == ':') {
277 buf[index] = 0;
278 proxy = xmlMemStrdup(buf);
279 index = 0;
280 cur += 1;
281 while ((*cur >= '0') && (*cur <= '9')) {
282 port *= 10;
283 port += *cur - '0';
284 cur++;
285 }
286 if (port != 0) proxyPort = port;
287 while ((cur[0] != '/') && (*cur != 0))
288 cur++;
289 break;
290 }
291 if ((*cur == '/') || (*cur == 0)) {
292 buf[index] = 0;
293 proxy = xmlMemStrdup(buf);
294 index = 0;
295 break;
296 }
297 buf[index++] = *cur++;
298 }
299}
300
301/**
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000302 * xmlNanoHTTPNewCtxt:
303 * @URL: The URL used to initialize the context
304 *
305 * Allocate and initialize a new HTTP context.
306 *
307 * Returns an HTTP context or NULL in case of error.
308 */
309
310static xmlNanoHTTPCtxtPtr
311xmlNanoHTTPNewCtxt(const char *URL) {
312 xmlNanoHTTPCtxtPtr ret;
313
314 ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
315 if (ret == NULL) return(NULL);
316
317 memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
318 ret->port = 80;
319 ret->returnValue = 0;
320
321 xmlNanoHTTPScanURL(ret, URL);
322
323 return(ret);
324}
325
326/**
327 * xmlNanoHTTPFreeCtxt:
328 * @ctxt: an HTTP context
329 *
330 * Frees the context after closing the connection.
331 */
332
333static void
334xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
335 if (ctxt == NULL) return;
336 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
337 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
338 if (ctxt->path != NULL) xmlFree(ctxt->path);
339 if (ctxt->out != NULL) xmlFree(ctxt->out);
340 if (ctxt->in != NULL) xmlFree(ctxt->in);
341 if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
342 if (ctxt->location != NULL) xmlFree(ctxt->location);
343 ctxt->state = XML_NANO_HTTP_NONE;
344 if (ctxt->fd >= 0) close(ctxt->fd);
345 ctxt->fd = -1;
346 xmlFree(ctxt);
347}
348
349/**
350 * xmlNanoHTTPSend:
351 * @ctxt: an HTTP context
352 *
353 * Send the input needed to initiate the processing on the server side
354 */
355
356static void
357xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
358 if (ctxt->state & XML_NANO_HTTP_WRITE)
359 ctxt->last = write(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr));
360}
361
362/**
363 * xmlNanoHTTPRecv:
364 * @ctxt: an HTTP context
365 *
366 * Read information coming from the HTTP connection.
367 * This is a blocking call (but it blocks in select(), not read()).
368 *
369 * Returns the number of byte read or -1 in case of error.
370 */
371
372static int
373xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
374 fd_set rfd;
375 struct timeval tv;
376
377
378 while (ctxt->state & XML_NANO_HTTP_READ) {
379 if (ctxt->in == NULL) {
380 ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
381 if (ctxt->in == NULL) {
382 ctxt->last = -1;
383 return(-1);
384 }
385 ctxt->inlen = 65000;
386 ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
387 }
388 if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
389 int delta = ctxt->inrptr - ctxt->in;
390 int len = ctxt->inptr - ctxt->inrptr;
391
392 memmove(ctxt->in, ctxt->inrptr, len);
393 ctxt->inrptr -= delta;
394 ctxt->content -= delta;
395 ctxt->inptr -= delta;
396 }
397 if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
398 int d_inptr = ctxt->inptr - ctxt->in;
399 int d_content = ctxt->content - ctxt->in;
400 int d_inrptr = ctxt->inrptr - ctxt->in;
401
402 ctxt->inlen *= 2;
403 ctxt->in = (char *) xmlRealloc(ctxt->in, ctxt->inlen);
404 if (ctxt->in == NULL) {
405 ctxt->last = -1;
406 return(-1);
407 }
408 ctxt->inptr = ctxt->in + d_inptr;
409 ctxt->content = ctxt->in + d_content;
410 ctxt->inrptr = ctxt->in + d_inrptr;
411 }
412 ctxt->last = read(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK);
413 if (ctxt->last > 0) {
414 ctxt->inptr += ctxt->last;
415 return(ctxt->last);
416 }
417 if (ctxt->last == 0) {
418 return(0);
419 }
420#ifdef EWOULDBLOCK
421 if ((ctxt->last == -1) && (errno != EWOULDBLOCK)) {
422 return(0);
423 }
424#endif
425 tv.tv_sec=10;
426 tv.tv_usec=0;
427 FD_ZERO(&rfd);
428 FD_SET(ctxt->fd, &rfd);
429
430 if(select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
431 return(0);
432 }
433 return(0);
434}
435
436/**
437 * xmlNanoHTTPReadLine:
438 * @ctxt: an HTTP context
439 *
440 * Read one line in the HTTP server output, usually for extracting
441 * the HTTP protocol informations from the answer header.
442 *
443 * Returns a newly allocated string with a copy of the line, or NULL
444 * which indicate the end of the input.
445 */
446
447static char *
448xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
449 char buf[4096];
450 char *bp=buf;
451
452 while(bp - buf < 4095) {
453 if(ctxt->inrptr == ctxt->inptr) {
454 if (xmlNanoHTTPRecv(ctxt) == 0) {
455 if (bp == buf)
456 return(NULL);
457 else
458 *bp = 0;
459 return(xmlMemStrdup(buf));
460 }
461 }
462 *bp = *ctxt->inrptr++;
463 if(*bp == '\n') {
464 *bp = 0;
465 return(xmlMemStrdup(buf));
466 }
467 if(*bp != '\r')
468 bp++;
469 }
470 buf[4095] = 0;
471 return(xmlMemStrdup(buf));
472}
473
474
475/**
476 * xmlNanoHTTPScanAnswer:
477 * @ctxt: an HTTP context
478 * @line: an HTTP header line
479 *
480 * Try to extract useful informations from the server answer.
481 * We currently parse and process:
482 * - The HTTP revision/ return code
483 * - The Content-Type
484 * - The Location for redirrect processing.
485 *
486 * Returns -1 in case of failure, the file descriptor number otherwise
487 */
488
489static void
490xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
491 const char *cur = line;
492
493 if (line == NULL) return;
494
495 if (!strncmp(line, "HTTP/", 5)) {
496 int version = 0;
497 int ret = 0;
498
499 cur += 5;
500 while ((*cur >= '0') && (*cur <= '9')) {
501 version *= 10;
502 version += *cur - '0';
503 cur++;
504 }
505 if (*cur == '.') {
506 cur++;
507 if ((*cur >= '0') && (*cur <= '9')) {
508 version *= 10;
509 version += *cur - '0';
510 cur++;
511 }
512 while ((*cur >= '0') && (*cur <= '9'))
513 cur++;
514 } else
515 version *= 10;
516 if ((*cur != ' ') && (*cur != '\t')) return;
517 while ((*cur == ' ') || (*cur == '\t')) cur++;
518 if ((*cur < '0') || (*cur > '9')) return;
519 while ((*cur >= '0') && (*cur <= '9')) {
520 ret *= 10;
521 ret += *cur - '0';
522 cur++;
523 }
524 if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
525 ctxt->returnValue = ret;
526 } else if (!strncmp(line, "Content-Type:", 13)) {
527 cur += 13;
528 while ((*cur == ' ') || (*cur == '\t')) cur++;
529 if (ctxt->contentType != NULL)
530 xmlFree(ctxt->contentType);
531 ctxt->contentType = xmlMemStrdup(cur);
532 } else if (!strncmp(line, "ContentType:", 12)) {
533 cur += 12;
534 if (ctxt->contentType != NULL) return;
535 while ((*cur == ' ') || (*cur == '\t')) cur++;
536 ctxt->contentType = xmlMemStrdup(cur);
537 } else if (!strncmp(line, "content-type:", 13)) {
538 cur += 13;
539 if (ctxt->contentType != NULL) return;
540 while ((*cur == ' ') || (*cur == '\t')) cur++;
541 ctxt->contentType = xmlMemStrdup(cur);
542 } else if (!strncmp(line, "contenttype:", 12)) {
543 cur += 12;
544 if (ctxt->contentType != NULL) return;
545 while ((*cur == ' ') || (*cur == '\t')) cur++;
546 ctxt->contentType = xmlMemStrdup(cur);
547 } else if (!strncmp(line, "Location:", 9)) {
548 cur += 9;
549 while ((*cur == ' ') || (*cur == '\t')) cur++;
550 if (ctxt->location != NULL)
551 xmlFree(ctxt->location);
552 ctxt->location = xmlMemStrdup(cur);
553 } else if (!strncmp(line, "location:", 9)) {
554 cur += 9;
555 if (ctxt->location != NULL) return;
556 while ((*cur == ' ') || (*cur == '\t')) cur++;
557 ctxt->location = xmlMemStrdup(cur);
558 }
559}
560
561/**
562 * xmlNanoHTTPConnectAttempt:
563 * @ia: an internet adress structure
564 * @port: the port number
565 *
566 * Attempt a connection to the given IP:port endpoint. It forces
567 * non-blocking semantic on the socket, and allow 60 seconds for
568 * the host to answer.
569 *
570 * Returns -1 in case of failure, the file descriptor number otherwise
571 */
572
573static int
574xmlNanoHTTPConnectAttempt(struct in_addr ia, int port)
575{
576 int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
577 struct sockaddr_in sin;
578 fd_set wfd;
579 struct timeval tv;
580 int status;
581
582 if(s==-1) {
583#ifdef DEBUG_HTTP
584 perror("socket");
585#endif
586 return(-1);
587 }
588
589#ifdef _WINSOCKAPI_
590 {
591 long levents = FD_READ | FD_WRITE | FD_ACCEPT |
592 FD_CONNECT | FD_CLOSE ;
593 int rv = 0 ;
594 u_long one = 1;
595
596 status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
597 }
598#else /* _WINSOCKAPI_ */
599#if defined(VMS)
600 {
601 int enable = 1;
602 status = IOCTL(s, FIONBIO, &enable);
603 }
604#else /* VMS */
605 if((status = fcntl(s, F_GETFL, 0)) != -1) {
606#ifdef O_NONBLOCK
607 status |= O_NONBLOCK;
608#else /* O_NONBLOCK */
609#ifdef F_NDELAY
610 status |= F_NDELAY;
611#endif /* F_NDELAY */
612#endif /* !O_NONBLOCK */
613 status = fcntl(s, F_SETFL, status);
614 }
615 if(status < 0) {
616#ifdef DEBUG_HTTP
617 perror("nonblocking");
618#endif
619 close(s);
620 return(-1);
621 }
622#endif /* !VMS */
623#endif /* !_WINSOCKAPI_ */
624
625
626 sin.sin_family = AF_INET;
627 sin.sin_addr = ia;
628 sin.sin_port = htons(port);
629
630 if((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1) &&
631 (errno != EINPROGRESS)) {
632 perror("connect");
633 close(s);
634 return(-1);
635 }
636
637 tv.tv_sec = 60; /* We use 60 second timeouts for now */
638 tv.tv_usec = 0;
639
640 FD_ZERO(&wfd);
641 FD_SET(s, &wfd);
642
643 switch(select(s+1, NULL, &wfd, NULL, &tv))
644 {
645 case 0:
646 /* Time out */
647 close(s);
648 return(-1);
649 case -1:
650 /* Ermm.. ?? */
651#ifdef DEBUG_HTTP
652 perror("select");
653#endif
654 close(s);
655 return(-1);
656 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000657
658 if ( FD_ISSET(s, &wfd) ) {
Daniel Veillard2f2bf412000-08-20 15:11:02 +0000659 unsigned int len; /* was socklen_t barfed on some systems :-( */
Daniel Veillardbe803962000-06-28 23:40:59 +0000660 len = sizeof(status);
661 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &status, &len) < 0 ) {
662 /* Solaris error code */
663 return (-1);
664 }
665 if ( status ) {
666 close (s);
667 errno = status;
668 return (-1);
669 }
670 } else {
671 /* pbm */
672 return (-1);
673 }
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000674
675 return(s);
676}
677
678/**
679 * xmlNanoHTTPConnectHost:
680 * @host: the host name
681 * @port: the port number
682 *
683 * Attempt a connection to the given host:port endpoint. It tries
684 * the multiple IP provided by the DNS if available.
685 *
686 * Returns -1 in case of failure, the file descriptor number otherwise
687 */
688
689static int
690xmlNanoHTTPConnectHost(const char *host, int port)
691{
692 struct hostent *h;
693 int i;
694 int s;
695
696 h=gethostbyname(host);
697 if(h==NULL)
698 {
699#ifdef DEBUG_HTTP
700 fprintf(stderr,"unable to resolve '%s'.\n", host);
701#endif
702 return(-1);
703 }
704
705 for(i=0; h->h_addr_list[i]; i++)
706 {
707 struct in_addr ia;
708 memcpy(&ia, h->h_addr_list[i],4);
709 s = xmlNanoHTTPConnectAttempt(ia, port);
710 if(s != -1)
711 return(s);
712 }
713
714#ifdef DEBUG_HTTP
715 fprintf(stderr, "unable to connect to '%s'.\n", host);
716#endif
717 return(-1);
718}
719
720
721/**
722 * xmlNanoHTTPOpen:
723 * @URL: The URL to load
724 * @contentType: if available the Content-Type information will be
725 * returned at that location
726 *
727 * This function try to open a connection to the indicated resource
728 * via HTTP GET.
729 *
730 * Returns NULL in case of failure, otherwise a request handler.
731 * The contentType, if provided must be freed by the caller
732 */
733
Daniel Veillard06047432000-04-24 11:33:38 +0000734void*
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000735xmlNanoHTTPOpen(const char *URL, char **contentType) {
736 xmlNanoHTTPCtxtPtr ctxt;
737 char buf[4096];
738 int ret;
739 char *p;
740 int head;
741 int nbRedirects = 0;
742 char *redirURL = NULL;
743
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000744 xmlNanoHTTPInit();
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000745 if (contentType != NULL) *contentType = NULL;
746
747retry:
748 if (redirURL == NULL)
749 ctxt = xmlNanoHTTPNewCtxt(URL);
750 else {
751 ctxt = xmlNanoHTTPNewCtxt(redirURL);
752 xmlFree(redirURL);
753 redirURL = NULL;
754 }
755
756 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
757 xmlNanoHTTPFreeCtxt(ctxt);
758 if (redirURL != NULL) xmlFree(redirURL);
759 return(NULL);
760 }
761 if (ctxt->hostname == NULL) {
762 xmlNanoHTTPFreeCtxt(ctxt);
763 return(NULL);
764 }
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000765 if (proxy)
766 ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
767 else
768 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000769 if (ret < 0) {
770 xmlNanoHTTPFreeCtxt(ctxt);
771 return(NULL);
772 }
773 ctxt->fd = ret;
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000774 if (proxy) {
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000775 if (ctxt->port != 80)
Daniel Veillard39c7d712000-09-10 16:14:55 +0000776#ifdef HAVE_SNPRINTF
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000777 snprintf(buf, sizeof(buf),
778 "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n",
779 ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
Daniel Veillard335849b1999-09-23 23:08:42 +0000780#else
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000781 sprintf(buf,
782 "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n",
783 ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
Daniel Veillard39c7d712000-09-10 16:14:55 +0000784#endif
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000785 else
Daniel Veillard39c7d712000-09-10 16:14:55 +0000786#ifdef HAVE_SNPRINTF
787 snprintf(buf, sizeof(buf),"GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n",
788 ctxt->hostname, ctxt->path, ctxt->hostname);
789#else
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000790 sprintf(buf, "GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n",
791 ctxt->hostname, ctxt->path, ctxt->hostname);
Daniel Veillard335849b1999-09-23 23:08:42 +0000792#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000793#ifdef DEBUG_HTTP
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000794 if (ctxt->port != 80)
795 printf("-> Proxy GET http://%s:%d%s HTTP/1.0\n-> Host: %s\n\n",
796 ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
797 else
798 printf("-> Proxy GET http://%s%s HTTP/1.0\n-> Host: %s\n\n",
799 ctxt->hostname, ctxt->path, ctxt->hostname);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000800#endif
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000801 } else {
802#ifdef HAVE_SNPRINTF
803 snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
804 ctxt->path, ctxt->hostname);
805#else
806 sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
807 ctxt->path, ctxt->hostname);
808#endif
809#ifdef DEBUG_HTTP
810 printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n",
811 ctxt->path, ctxt->hostname);
812#endif
813 }
Daniel Veillard39c7d712000-09-10 16:14:55 +0000814 buf[sizeof(buf) - 1] = 0;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000815 ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
816 ctxt->state = XML_NANO_HTTP_WRITE;
817 xmlNanoHTTPSend(ctxt);
818 ctxt->state = XML_NANO_HTTP_READ;
819 head = 1;
820
821 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
822 if (head && (*p == 0)) {
823 head = 0;
824 ctxt->content = ctxt->inrptr;
Daniel Veillarde41f2b72000-01-30 20:00:07 +0000825 xmlFree(p);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000826 break;
827 }
828 xmlNanoHTTPScanAnswer(ctxt, p);
829
830#ifdef DEBUG_HTTP
831 if (p != NULL) printf("<- %s\n", p);
832#endif
833 if (p != NULL) xmlFree(p);
834 }
835
836 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
837 (ctxt->returnValue < 400)) {
838#ifdef DEBUG_HTTP
839 printf("\nRedirect to: %s\n", ctxt->location);
840#endif
841 while (xmlNanoHTTPRecv(ctxt)) ;
842 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
843 nbRedirects++;
844 redirURL = xmlMemStrdup(ctxt->location);
845 xmlNanoHTTPFreeCtxt(ctxt);
846 goto retry;
847 }
848 xmlNanoHTTPFreeCtxt(ctxt);
849#ifdef DEBUG_HTTP
850 printf("Too many redirrects, aborting ...\n");
851#endif
852 return(NULL);
853
854 }
855
856 if ((contentType != NULL) && (ctxt->contentType != NULL))
857 *contentType = xmlMemStrdup(ctxt->contentType);
858
859#ifdef DEBUG_HTTP
860 if (ctxt->contentType != NULL)
861 printf("\nCode %d, content-type '%s'\n\n",
862 ctxt->returnValue, ctxt->contentType);
863 else
864 printf("\nCode %d, no content-type\n\n",
865 ctxt->returnValue);
866#endif
867
868 return((void *) ctxt);
869}
870
871/**
872 * xmlNanoHTTPRead:
873 * @ctx: the HTTP context
874 * @dest: a buffer
875 * @len: the buffer length
876 *
877 * This function tries to read @len bytes from the existing HTTP connection
878 * and saves them in @dest. This is a blocking call.
879 *
880 * Returns the number of byte read. 0 is an indication of an end of connection.
881 * -1 indicates a parameter error.
882 */
883int
884xmlNanoHTTPRead(void *ctx, void *dest, int len) {
885 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
886
887 if (ctx == NULL) return(-1);
888 if (dest == NULL) return(-1);
889 if (len <= 0) return(0);
890
891 while (ctxt->inptr - ctxt->inrptr < len) {
892 if (xmlNanoHTTPRecv(ctxt) == 0) break;
893 }
894 if (ctxt->inptr - ctxt->inrptr < len)
895 len = ctxt->inptr - ctxt->inrptr;
896 memcpy(dest, ctxt->inrptr, len);
897 ctxt->inrptr += len;
898 return(len);
899}
900
901/**
902 * xmlNanoHTTPClose:
903 * @ctx: the HTTP context
904 *
905 * This function closes an HTTP context, it ends up the connection and
906 * free all data related to it.
907 */
908void
909xmlNanoHTTPClose(void *ctx) {
910 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
911
912 if (ctx == NULL) return;
913
914 xmlNanoHTTPFreeCtxt(ctxt);
915}
916
Daniel Veillard00fdf371999-10-08 09:40:39 +0000917#ifndef DEBUG_HTTP
918#define DEBUG_HTTP
919#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000920/**
921 * xmlNanoHTTPMethod:
922 * @URL: The URL to load
923 * @method: the HTTP method to use
924 * @input: the input string if any
925 * @contentType: the Content-Type information IN and OUT
926 * @headers: the extra headers
927 *
928 * This function try to open a connection to the indicated resource
929 * via HTTP using the given @method, adding the given extra headers
930 * and the input buffer for the request content.
931 *
932 * Returns NULL in case of failure, otherwise a request handler.
933 * The contentType, if provided must be freed by the caller
934 */
935
Daniel Veillard06047432000-04-24 11:33:38 +0000936void*
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000937xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
938 char **contentType, const char *headers) {
939 xmlNanoHTTPCtxtPtr ctxt;
940 char buf[20000];
941 int ret;
942 char *p;
943 int head;
944 int nbRedirects = 0;
945 char *redirURL = NULL;
946
947 if (URL == NULL) return(NULL);
948 if (method == NULL) method = "GET";
949 if (contentType != NULL) *contentType = NULL;
950
951retry:
952 if (redirURL == NULL)
953 ctxt = xmlNanoHTTPNewCtxt(URL);
954 else {
955 ctxt = xmlNanoHTTPNewCtxt(redirURL);
956 xmlFree(redirURL);
957 redirURL = NULL;
958 }
959
960 if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
961 xmlNanoHTTPFreeCtxt(ctxt);
962 if (redirURL != NULL) xmlFree(redirURL);
963 return(NULL);
964 }
965 if (ctxt->hostname == NULL) {
966 xmlNanoHTTPFreeCtxt(ctxt);
967 return(NULL);
968 }
969 ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
970 if (ret < 0) {
971 xmlNanoHTTPFreeCtxt(ctxt);
972 return(NULL);
973 }
974 ctxt->fd = ret;
975
976 if (input == NULL) {
977 if (headers == NULL) {
978 if ((contentType == NULL) || (*contentType == NULL)) {
Daniel Veillard335849b1999-09-23 23:08:42 +0000979#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000980 snprintf(buf, sizeof(buf),
981 "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
982 method, ctxt->path, ctxt->hostname);
Daniel Veillard335849b1999-09-23 23:08:42 +0000983#else
984 sprintf(buf,
985 "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
986 method, ctxt->path, ctxt->hostname);
987#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000988 } else {
Daniel Veillard335849b1999-09-23 23:08:42 +0000989#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000990 snprintf(buf, sizeof(buf),
991 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n",
992 method, ctxt->path, ctxt->hostname, *contentType);
Daniel Veillard335849b1999-09-23 23:08:42 +0000993#else
994 sprintf(buf,
995 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n",
996 method, ctxt->path, ctxt->hostname, *contentType);
997#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +0000998 }
999 } else {
1000 if ((contentType == NULL) || (*contentType == NULL)) {
Daniel Veillard335849b1999-09-23 23:08:42 +00001001#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001002 snprintf(buf, sizeof(buf),
1003 "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n",
1004 method, ctxt->path, ctxt->hostname, headers);
Daniel Veillard335849b1999-09-23 23:08:42 +00001005#else
1006 sprintf(buf,
1007 "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n",
1008 method, ctxt->path, ctxt->hostname, headers);
1009#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001010 } else {
Daniel Veillard335849b1999-09-23 23:08:42 +00001011#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001012 snprintf(buf, sizeof(buf),
1013 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n",
1014 method, ctxt->path, ctxt->hostname, *contentType,
1015 headers);
Daniel Veillard335849b1999-09-23 23:08:42 +00001016#else
1017 sprintf(buf,
1018 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n",
1019 method, ctxt->path, ctxt->hostname, *contentType,
1020 headers);
1021#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001022 }
1023 }
1024 } else {
1025 int len = strlen(input);
1026 if (headers == NULL) {
1027 if ((contentType == NULL) || (*contentType == NULL)) {
Daniel Veillard335849b1999-09-23 23:08:42 +00001028#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001029 snprintf(buf, sizeof(buf),
1030 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s",
1031 method, ctxt->path, ctxt->hostname, len, input);
Daniel Veillard335849b1999-09-23 23:08:42 +00001032#else
1033 sprintf(buf,
1034 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s",
1035 method, ctxt->path, ctxt->hostname, len, input);
1036#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001037 } else {
Daniel Veillard335849b1999-09-23 23:08:42 +00001038#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001039 snprintf(buf, sizeof(buf),
1040"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
1041 method, ctxt->path, ctxt->hostname, *contentType, len,
1042 input);
Daniel Veillard335849b1999-09-23 23:08:42 +00001043#else
1044 sprintf(buf,
1045"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
1046 method, ctxt->path, ctxt->hostname, *contentType, len,
1047 input);
1048#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001049 }
1050 } else {
1051 if ((contentType == NULL) || (*contentType == NULL)) {
Daniel Veillard335849b1999-09-23 23:08:42 +00001052#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001053 snprintf(buf, sizeof(buf),
1054 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1055 method, ctxt->path, ctxt->hostname, len,
1056 headers, input);
Daniel Veillard335849b1999-09-23 23:08:42 +00001057#else
1058 sprintf(buf,
1059 "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1060 method, ctxt->path, ctxt->hostname, len,
1061 headers, input);
1062#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001063 } else {
Daniel Veillard335849b1999-09-23 23:08:42 +00001064#ifdef HAVE_SNPRINTF
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001065 snprintf(buf, sizeof(buf),
1066"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1067 method, ctxt->path, ctxt->hostname, *contentType,
1068 len, headers, input);
Daniel Veillard335849b1999-09-23 23:08:42 +00001069#else
1070 sprintf(buf,
1071"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1072 method, ctxt->path, ctxt->hostname, *contentType,
1073 len, headers, input);
1074#endif
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001075 }
1076 }
1077 }
Daniel Veillard39c7d712000-09-10 16:14:55 +00001078 buf[sizeof(buf) - 1] = 0;
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001079#ifdef DEBUG_HTTP
1080 printf("-> %s", buf);
1081#endif
1082 ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
1083 ctxt->state = XML_NANO_HTTP_WRITE;
1084 xmlNanoHTTPSend(ctxt);
1085 ctxt->state = XML_NANO_HTTP_READ;
1086 head = 1;
1087
1088 while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
1089 if (head && (*p == 0)) {
1090 head = 0;
1091 ctxt->content = ctxt->inrptr;
1092 if (p != NULL) xmlFree(p);
1093 break;
1094 }
1095 xmlNanoHTTPScanAnswer(ctxt, p);
1096
1097#ifdef DEBUG_HTTP
1098 if (p != NULL) printf("<- %s\n", p);
1099#endif
1100 if (p != NULL) xmlFree(p);
1101 }
1102
1103 if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1104 (ctxt->returnValue < 400)) {
1105#ifdef DEBUG_HTTP
1106 printf("\nRedirect to: %s\n", ctxt->location);
1107#endif
1108 while (xmlNanoHTTPRecv(ctxt)) ;
1109 if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1110 nbRedirects++;
1111 redirURL = xmlMemStrdup(ctxt->location);
1112 xmlNanoHTTPFreeCtxt(ctxt);
1113 goto retry;
1114 }
1115 xmlNanoHTTPFreeCtxt(ctxt);
1116#ifdef DEBUG_HTTP
1117 printf("Too many redirrects, aborting ...\n");
1118#endif
1119 return(NULL);
1120
1121 }
1122
1123 if ((contentType != NULL) && (ctxt->contentType != NULL))
1124 *contentType = xmlMemStrdup(ctxt->contentType);
1125 else if (contentType != NULL)
1126 *contentType = NULL;
1127
1128#ifdef DEBUG_HTTP
1129 if (ctxt->contentType != NULL)
1130 printf("\nCode %d, content-type '%s'\n\n",
1131 ctxt->returnValue, ctxt->contentType);
1132 else
1133 printf("\nCode %d, no content-type\n\n",
1134 ctxt->returnValue);
1135#endif
1136
1137 return((void *) ctxt);
1138}
1139
1140/**
1141 * xmlNanoHTTPFetch:
1142 * @URL: The URL to load
1143 * @filename: the filename where the content should be saved
1144 * @contentType: if available the Content-Type information will be
1145 * returned at that location
1146 *
1147 * This function try to fetch the indicated resource via HTTP GET
1148 * and save it's content in the file.
1149 *
1150 * Returns -1 in case of failure, 0 incase of success. The contentType,
1151 * if provided must be freed by the caller
1152 */
1153int
1154xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
1155 void *ctxt;
1156 char buf[4096];
1157 int fd;
1158 int len;
1159
1160 ctxt = xmlNanoHTTPOpen(URL, contentType);
1161 if (ctxt == NULL) return(-1);
1162
1163 if (!strcmp(filename, "-"))
1164 fd = 0;
1165 else {
Daniel Veillarde41f2b72000-01-30 20:00:07 +00001166 fd = open(filename, O_CREAT | O_WRONLY, 00644);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001167 if (fd < 0) {
1168 xmlNanoHTTPClose(ctxt);
1169 if ((contentType != NULL) && (*contentType != NULL)) {
1170 xmlFree(*contentType);
1171 *contentType = NULL;
1172 }
1173 return(-1);
1174 }
1175 }
1176
1177 while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
1178 write(fd, buf, len);
1179 }
1180
1181 xmlNanoHTTPClose(ctxt);
Daniel Veillarde41f2b72000-01-30 20:00:07 +00001182 close(fd);
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001183 return(0);
1184}
1185
1186/**
1187 * xmlNanoHTTPSave:
Daniel Veillard00fdf371999-10-08 09:40:39 +00001188 * @ctxt: the HTTP context
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001189 * @filename: the filename where the content should be saved
1190 *
1191 * This function saves the output of the HTTP transaction to a file
1192 * It closes and free the context at the end
1193 *
1194 * Returns -1 in case of failure, 0 incase of success.
1195 */
1196int
1197xmlNanoHTTPSave(void *ctxt, const char *filename) {
1198 char buf[4096];
1199 int fd;
1200 int len;
1201
1202 if (ctxt == NULL) return(-1);
1203
1204 if (!strcmp(filename, "-"))
1205 fd = 0;
1206 else {
1207 fd = open(filename, O_CREAT | O_WRONLY);
1208 if (fd < 0) {
1209 xmlNanoHTTPClose(ctxt);
1210 return(-1);
1211 }
1212 }
1213
1214 while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
1215 write(fd, buf, len);
1216 }
1217
1218 xmlNanoHTTPClose(ctxt);
1219 return(0);
1220}
1221
1222/**
1223 * xmlNanoHTTPReturnCode:
1224 * @ctx: the HTTP context
1225 *
1226 * Returns the HTTP return code for the request.
1227 */
1228int
1229xmlNanoHTTPReturnCode(void *ctx) {
1230 xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1231
1232 if (ctxt == NULL) return(-1);
1233
1234 return(ctxt->returnValue);
1235}
1236
1237#ifdef STANDALONE
1238int main(int argc, char **argv) {
1239 char *contentType = NULL;
1240
1241 if (argv[1] != NULL) {
1242 if (argv[2] != NULL)
1243 xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1244 else
1245 xmlNanoHTTPFetch(argv[1], "-", &contentType);
1246 if (contentType != NULL) xmlFree(contentType);
1247 } else {
1248 printf("%s: minimal HTTP GET implementation\n", argv[0]);
1249 printf("\tusage %s [ URL [ filename ] ]\n", argv[0]);
1250 }
Daniel Veillarde41f2b72000-01-30 20:00:07 +00001251 xmlNanoHTTPCleanup();
1252 xmlMemoryDump();
Daniel Veillard4ecf39f1999-09-22 12:14:03 +00001253 return(0);
1254}
1255#endif /* STANDALONE */
Daniel Veillard361d8452000-04-03 19:48:13 +00001256#else /* !LIBXML_HTTP_ENABLED */
1257#ifdef STANDALONE
1258#include <stdio.h>
1259int main(int argc, char **argv) {
1260 printf("%s : HTTP support not compiled in\n", argv[0]);
1261 return(0);
1262}
1263#endif /* STANDALONE */
1264#endif /* LIBXML_HTTP_ENABLED */