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