Annotation of XML/nanohttp.c, revision 1.27
1.1 daniel 1: /*
1.5 daniel 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/
1.1 daniel 8: *
9: * See Copyright for the status of this software.
10: *
11: * Daniel.Veillard@w3.org
12: */
13:
1.5 daniel 14: /* TODO add compression support, Send the Accept- , and decompress on the
15: fly with ZLIB if found at compile-time */
16:
1.9 daniel 17: #ifdef WIN32
1.11 daniel 18: #define INCLUDE_WINSOCK
1.9 daniel 19: #include "win32config.h"
20: #else
1.4 daniel 21: #include "config.h"
22: #endif
1.9 daniel 23:
1.25 veillard 24: #include <libxml/xmlversion.h>
1.4 daniel 25:
1.17 daniel 26: #ifdef LIBXML_HTTP_ENABLED
1.1 daniel 27: #include <stdio.h>
28: #include <string.h>
1.4 daniel 29:
30: #ifdef HAVE_STDLIB_H
1.1 daniel 31: #include <stdlib.h>
1.4 daniel 32: #endif
33: #ifdef HAVE_UNISTD_H
1.1 daniel 34: #include <unistd.h>
1.4 daniel 35: #endif
36: #ifdef HAVE_SYS_SOCKET_H
1.1 daniel 37: #include <sys/socket.h>
1.4 daniel 38: #endif
39: #ifdef HAVE_NETINET_IN_H
1.1 daniel 40: #include <netinet/in.h>
1.4 daniel 41: #endif
42: #ifdef HAVE_ARPA_INET_H
1.1 daniel 43: #include <arpa/inet.h>
1.4 daniel 44: #endif
45: #ifdef HAVE_NETDB_H
1.1 daniel 46: #include <netdb.h>
1.4 daniel 47: #endif
48: #ifdef HAVE_FCNTL_H
1.1 daniel 49: #include <fcntl.h>
1.4 daniel 50: #endif
51: #ifdef HAVE_ERRNO_H
1.1 daniel 52: #include <errno.h>
1.4 daniel 53: #endif
54: #ifdef HAVE_SYS_TIME_H
1.1 daniel 55: #include <sys/time.h>
1.4 daniel 56: #endif
57: #ifdef HAVE_SYS_SELECT_H
1.1 daniel 58: #include <sys/select.h>
1.4 daniel 59: #endif
1.15 daniel 60: #ifdef HAVE_STRINGS_H
61: #include <strings.h>
62: #endif
1.1 daniel 63:
1.17 daniel 64: #include <libxml/xmlmemory.h>
1.23 veillard 65: #include <libxml/parser.h> /* for xmlStr(n)casecmp() */
1.17 daniel 66: #include <libxml/nanohttp.h>
1.7 daniel 67:
1.5 daniel 68: #ifdef STANDALONE
69: #define DEBUG_HTTP
1.23 veillard 70: #define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
71: #define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
1.5 daniel 72: #endif
73:
1.1 daniel 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:
83: typedef 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:
1.12 daniel 103: static int initialized = 0;
104: static char *proxy = NULL; /* the proxy name if any */
105: static int proxyPort; /* the proxy port if any */
106:
107: /**
1.26 veillard 108: * A bit of portability macros and functions
109: */
110: #ifdef _WINSOCKAPI_
111:
112: WSADATA wsaData;
113:
114: #else
115:
116: #define closesocket(s) close(s)
117:
118: #endif
119:
120: int socket_errno(void) {
121: #ifdef _WINSOCKAPI_
122: return(WSAGetLastError());
123: #else
124: return(errno);
125: #endif
126: }
127:
128: /**
1.12 daniel 129: * xmlNanoHTTPInit:
130: *
131: * Initialize the HTTP protocol layer.
132: * Currently it just checks for proxy informations
133: */
134:
135: void
136: xmlNanoHTTPInit(void) {
137: const char *env;
138:
139: if (initialized)
140: return;
141:
1.26 veillard 142: #ifdef _WINSOCKAPI_
143: if (WSAStartup(0x0101, &wsaData) != 0)
144: WSACleanup();
145: #endif
146:
1.13 daniel 147: if (proxy == NULL) {
148: proxyPort = 80;
149: env = getenv("no_proxy");
150: if (env != NULL)
151: goto done;
152: env = getenv("http_proxy");
153: if (env != NULL) {
154: xmlNanoHTTPScanProxy(env);
155: goto done;
156: }
157: env = getenv("HTTP_PROXY");
158: if (env != NULL) {
159: xmlNanoHTTPScanProxy(env);
160: goto done;
161: }
1.12 daniel 162: }
1.13 daniel 163: done:
1.12 daniel 164: initialized = 1;
165: }
166:
167: /**
168: * xmlNanoHTTPClenup:
169: *
170: * Cleanup the HTTP protocol layer.
171: */
172:
173: void
174: xmlNanoHTTPCleanup(void) {
175: if (proxy != NULL)
176: xmlFree(proxy);
177: initialized = 0;
1.26 veillard 178: #ifdef _WINSOCKAPI_
179: WSACleanup();
180: #endif
1.12 daniel 181: return;
182: }
183:
1.5 daniel 184: /**
185: * xmlNanoHTTPScanURL:
186: * @ctxt: an HTTP context
187: * @URL: The URL used to initialize the context
188: *
189: * (Re)Initialize an HTTP context by parsing the URL and finding
190: * the protocol host port and path it indicates.
191: */
192:
193: static void
194: xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
1.1 daniel 195: const char *cur = URL;
196: char buf[4096];
197: int index = 0;
198: int port = 0;
199:
200: if (ctxt->protocol != NULL) {
1.7 daniel 201: xmlFree(ctxt->protocol);
1.1 daniel 202: ctxt->protocol = NULL;
203: }
204: if (ctxt->hostname != NULL) {
1.7 daniel 205: xmlFree(ctxt->hostname);
1.1 daniel 206: ctxt->hostname = NULL;
207: }
208: if (ctxt->path != NULL) {
1.7 daniel 209: xmlFree(ctxt->path);
1.1 daniel 210: ctxt->path = NULL;
211: }
1.12 daniel 212: if (URL == NULL) return;
1.1 daniel 213: buf[index] = 0;
214: while (*cur != 0) {
215: if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
216: buf[index] = 0;
1.7 daniel 217: ctxt->protocol = xmlMemStrdup(buf);
1.1 daniel 218: index = 0;
219: cur += 3;
220: break;
221: }
222: buf[index++] = *cur++;
223: }
224: if (*cur == 0) return;
225:
226: buf[index] = 0;
227: while (1) {
228: if (cur[0] == ':') {
229: buf[index] = 0;
1.7 daniel 230: ctxt->hostname = xmlMemStrdup(buf);
1.1 daniel 231: index = 0;
232: cur += 1;
233: while ((*cur >= '0') && (*cur <= '9')) {
234: port *= 10;
235: port += *cur - '0';
236: cur++;
237: }
238: if (port != 0) ctxt->port = port;
239: while ((cur[0] != '/') && (*cur != 0))
240: cur++;
241: break;
242: }
243: if ((*cur == '/') || (*cur == 0)) {
244: buf[index] = 0;
1.7 daniel 245: ctxt->hostname = xmlMemStrdup(buf);
1.1 daniel 246: index = 0;
247: break;
248: }
249: buf[index++] = *cur++;
250: }
251: if (*cur == 0)
1.7 daniel 252: ctxt->path = xmlMemStrdup("/");
1.5 daniel 253: else {
1.14 daniel 254: index = 0;
1.5 daniel 255: buf[index] = 0;
1.14 daniel 256: while (*cur != 0)
1.5 daniel 257: buf[index++] = *cur++;
258: buf[index] = 0;
1.7 daniel 259: ctxt->path = xmlMemStrdup(buf);
1.5 daniel 260: }
1.1 daniel 261: }
262:
1.5 daniel 263: /**
1.12 daniel 264: * xmlNanoHTTPScanProxy:
265: * @URL: The proxy URL used to initialize the proxy context
266: *
267: * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
268: * the protocol host port it indicates.
269: * Should be like http://myproxy/ or http://myproxy:3128/
270: * A NULL URL cleans up proxy informations.
271: */
272:
273: void
274: xmlNanoHTTPScanProxy(const char *URL) {
275: const char *cur = URL;
276: char buf[4096];
277: int index = 0;
278: int port = 0;
279:
280: if (proxy != NULL) {
281: xmlFree(proxy);
282: proxy = NULL;
283: }
284: if (proxyPort != 0) {
285: proxyPort = 0;
286: }
287: #ifdef DEBUG_HTTP
288: if (URL == NULL)
289: printf("Removing HTTP proxy info\n");
290: else
291: printf("Using HTTP proxy %s\n", URL);
292: #endif
293: if (URL == NULL) return;
294: buf[index] = 0;
295: while (*cur != 0) {
296: if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
297: buf[index] = 0;
298: index = 0;
299: cur += 3;
300: break;
301: }
302: buf[index++] = *cur++;
303: }
304: if (*cur == 0) return;
305:
306: buf[index] = 0;
307: while (1) {
308: if (cur[0] == ':') {
309: buf[index] = 0;
310: proxy = xmlMemStrdup(buf);
311: index = 0;
312: cur += 1;
313: while ((*cur >= '0') && (*cur <= '9')) {
314: port *= 10;
315: port += *cur - '0';
316: cur++;
317: }
318: if (port != 0) proxyPort = port;
319: while ((cur[0] != '/') && (*cur != 0))
320: cur++;
321: break;
322: }
323: if ((*cur == '/') || (*cur == 0)) {
324: buf[index] = 0;
325: proxy = xmlMemStrdup(buf);
326: index = 0;
327: break;
328: }
329: buf[index++] = *cur++;
330: }
331: }
332:
333: /**
1.5 daniel 334: * xmlNanoHTTPNewCtxt:
335: * @URL: The URL used to initialize the context
336: *
337: * Allocate and initialize a new HTTP context.
338: *
339: * Returns an HTTP context or NULL in case of error.
340: */
341:
342: static xmlNanoHTTPCtxtPtr
343: xmlNanoHTTPNewCtxt(const char *URL) {
1.1 daniel 344: xmlNanoHTTPCtxtPtr ret;
345:
1.7 daniel 346: ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
1.1 daniel 347: if (ret == NULL) return(NULL);
348:
349: memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
350: ret->port = 80;
351: ret->returnValue = 0;
352:
353: xmlNanoHTTPScanURL(ret, URL);
354:
355: return(ret);
356: }
357:
1.5 daniel 358: /**
359: * xmlNanoHTTPFreeCtxt:
360: * @ctxt: an HTTP context
361: *
362: * Frees the context after closing the connection.
363: */
364:
365: static void
366: xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
367: if (ctxt == NULL) return;
1.7 daniel 368: if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
369: if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
370: if (ctxt->path != NULL) xmlFree(ctxt->path);
371: if (ctxt->out != NULL) xmlFree(ctxt->out);
372: if (ctxt->in != NULL) xmlFree(ctxt->in);
373: if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
374: if (ctxt->location != NULL) xmlFree(ctxt->location);
1.1 daniel 375: ctxt->state = XML_NANO_HTTP_NONE;
1.26 veillard 376: if (ctxt->fd >= 0) closesocket(ctxt->fd);
1.1 daniel 377: ctxt->fd = -1;
1.7 daniel 378: xmlFree(ctxt);
1.1 daniel 379: }
380:
1.5 daniel 381: /**
382: * xmlNanoHTTPSend:
383: * @ctxt: an HTTP context
384: *
385: * Send the input needed to initiate the processing on the server side
386: */
387:
388: static void
389: xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
1.1 daniel 390: if (ctxt->state & XML_NANO_HTTP_WRITE)
1.26 veillard 391: ctxt->last = send(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr), 0);
1.1 daniel 392: }
393:
1.5 daniel 394: /**
395: * xmlNanoHTTPRecv:
396: * @ctxt: an HTTP context
397: *
398: * Read information coming from the HTTP connection.
399: * This is a blocking call (but it blocks in select(), not read()).
400: *
401: * Returns the number of byte read or -1 in case of error.
402: */
403:
404: static int
405: xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
1.1 daniel 406: fd_set rfd;
407: struct timeval tv;
408:
409:
410: while (ctxt->state & XML_NANO_HTTP_READ) {
411: if (ctxt->in == NULL) {
1.7 daniel 412: ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
1.1 daniel 413: if (ctxt->in == NULL) {
414: ctxt->last = -1;
415: return(-1);
416: }
417: ctxt->inlen = 65000;
418: ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
419: }
420: if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
421: int delta = ctxt->inrptr - ctxt->in;
422: int len = ctxt->inptr - ctxt->inrptr;
423:
424: memmove(ctxt->in, ctxt->inrptr, len);
425: ctxt->inrptr -= delta;
426: ctxt->content -= delta;
427: ctxt->inptr -= delta;
428: }
429: if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
430: int d_inptr = ctxt->inptr - ctxt->in;
431: int d_content = ctxt->content - ctxt->in;
432: int d_inrptr = ctxt->inrptr - ctxt->in;
433:
434: ctxt->inlen *= 2;
1.7 daniel 435: ctxt->in = (char *) xmlRealloc(ctxt->in, ctxt->inlen);
1.1 daniel 436: if (ctxt->in == NULL) {
437: ctxt->last = -1;
438: return(-1);
439: }
440: ctxt->inptr = ctxt->in + d_inptr;
441: ctxt->content = ctxt->in + d_content;
442: ctxt->inrptr = ctxt->in + d_inrptr;
443: }
1.26 veillard 444: ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
1.1 daniel 445: if (ctxt->last > 0) {
446: ctxt->inptr += ctxt->last;
447: return(ctxt->last);
448: }
449: if (ctxt->last == 0) {
450: return(0);
451: }
1.26 veillard 452: if (ctxt->last == -1) {
453: switch (socket_errno()) {
454: case EINPROGRESS:
455: case EWOULDBLOCK:
456: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
457: case EAGAIN:
458: #endif
459: break;
460: default:
461: return(0);
462: }
1.1 daniel 463: }
1.26 veillard 464:
465: tv.tv_sec = 10;
466: tv.tv_usec = 0;
1.1 daniel 467: FD_ZERO(&rfd);
468: FD_SET(ctxt->fd, &rfd);
469:
1.26 veillard 470: if (select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
1.5 daniel 471: return(0);
1.1 daniel 472: }
473: return(0);
474: }
475:
1.5 daniel 476: /**
477: * xmlNanoHTTPReadLine:
478: * @ctxt: an HTTP context
479: *
480: * Read one line in the HTTP server output, usually for extracting
481: * the HTTP protocol informations from the answer header.
482: *
483: * Returns a newly allocated string with a copy of the line, or NULL
484: * which indicate the end of the input.
485: */
486:
487: static char *
488: xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
489: char buf[4096];
1.26 veillard 490: char *bp = buf;
1.1 daniel 491:
1.26 veillard 492: while (bp - buf < 4095) {
493: if (ctxt->inrptr == ctxt->inptr) {
1.1 daniel 494: if (xmlNanoHTTPRecv(ctxt) == 0) {
495: if (bp == buf)
1.5 daniel 496: return(NULL);
1.1 daniel 497: else
498: *bp = 0;
1.7 daniel 499: return(xmlMemStrdup(buf));
1.1 daniel 500: }
501: }
502: *bp = *ctxt->inrptr++;
1.26 veillard 503: if (*bp == '\n') {
1.1 daniel 504: *bp = 0;
1.7 daniel 505: return(xmlMemStrdup(buf));
1.1 daniel 506: }
1.26 veillard 507: if (*bp != '\r')
1.1 daniel 508: bp++;
509: }
510: buf[4095] = 0;
1.7 daniel 511: return(xmlMemStrdup(buf));
1.1 daniel 512: }
513:
1.5 daniel 514:
515: /**
516: * xmlNanoHTTPScanAnswer:
517: * @ctxt: an HTTP context
518: * @line: an HTTP header line
519: *
520: * Try to extract useful informations from the server answer.
521: * We currently parse and process:
522: * - The HTTP revision/ return code
523: * - The Content-Type
524: * - The Location for redirrect processing.
525: *
526: * Returns -1 in case of failure, the file descriptor number otherwise
527: */
528:
529: static void
530: xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
1.1 daniel 531: const char *cur = line;
532:
533: if (line == NULL) return;
534:
535: if (!strncmp(line, "HTTP/", 5)) {
536: int version = 0;
537: int ret = 0;
538:
539: cur += 5;
540: while ((*cur >= '0') && (*cur <= '9')) {
541: version *= 10;
542: version += *cur - '0';
543: cur++;
544: }
545: if (*cur == '.') {
546: cur++;
547: if ((*cur >= '0') && (*cur <= '9')) {
548: version *= 10;
549: version += *cur - '0';
550: cur++;
551: }
552: while ((*cur >= '0') && (*cur <= '9'))
553: cur++;
554: } else
555: version *= 10;
556: if ((*cur != ' ') && (*cur != '\t')) return;
557: while ((*cur == ' ') || (*cur == '\t')) cur++;
558: if ((*cur < '0') || (*cur > '9')) return;
559: while ((*cur >= '0') && (*cur <= '9')) {
560: ret *= 10;
561: ret += *cur - '0';
562: cur++;
563: }
564: if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
565: ctxt->returnValue = ret;
1.23 veillard 566: } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
1.1 daniel 567: cur += 13;
568: while ((*cur == ' ') || (*cur == '\t')) cur++;
569: if (ctxt->contentType != NULL)
1.7 daniel 570: xmlFree(ctxt->contentType);
571: ctxt->contentType = xmlMemStrdup(cur);
1.23 veillard 572: } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
1.1 daniel 573: cur += 12;
574: if (ctxt->contentType != NULL) return;
575: while ((*cur == ' ') || (*cur == '\t')) cur++;
1.7 daniel 576: ctxt->contentType = xmlMemStrdup(cur);
1.23 veillard 577: } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
1.1 daniel 578: cur += 9;
579: while ((*cur == ' ') || (*cur == '\t')) cur++;
580: if (ctxt->location != NULL)
1.7 daniel 581: xmlFree(ctxt->location);
582: ctxt->location = xmlMemStrdup(cur);
1.1 daniel 583: }
584: }
585:
1.5 daniel 586: /**
587: * xmlNanoHTTPConnectAttempt:
588: * @ia: an internet adress structure
589: * @port: the port number
590: *
591: * Attempt a connection to the given IP:port endpoint. It forces
592: * non-blocking semantic on the socket, and allow 60 seconds for
593: * the host to answer.
594: *
595: * Returns -1 in case of failure, the file descriptor number otherwise
596: */
597:
598: static int
599: xmlNanoHTTPConnectAttempt(struct in_addr ia, int port)
1.1 daniel 600: {
601: int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
602: struct sockaddr_in sin;
603: fd_set wfd;
604: struct timeval tv;
1.2 daniel 605: int status;
1.1 daniel 606:
1.26 veillard 607: if (s==-1) {
1.5 daniel 608: #ifdef DEBUG_HTTP
1.1 daniel 609: perror("socket");
1.5 daniel 610: #endif
1.1 daniel 611: return(-1);
612: }
613:
1.2 daniel 614: #ifdef _WINSOCKAPI_
615: {
616: u_long one = 1;
617:
1.3 daniel 618: status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
1.2 daniel 619: }
620: #else /* _WINSOCKAPI_ */
621: #if defined(VMS)
622: {
623: int enable = 1;
1.3 daniel 624: status = IOCTL(s, FIONBIO, &enable);
1.2 daniel 625: }
626: #else /* VMS */
1.26 veillard 627: if ((status = fcntl(s, F_GETFL, 0)) != -1) {
1.2 daniel 628: #ifdef O_NONBLOCK
629: status |= O_NONBLOCK;
630: #else /* O_NONBLOCK */
631: #ifdef F_NDELAY
632: status |= F_NDELAY;
633: #endif /* F_NDELAY */
634: #endif /* !O_NONBLOCK */
1.3 daniel 635: status = fcntl(s, F_SETFL, status);
1.2 daniel 636: }
1.26 veillard 637: if (status < 0) {
1.5 daniel 638: #ifdef DEBUG_HTTP
1.1 daniel 639: perror("nonblocking");
1.5 daniel 640: #endif
1.26 veillard 641: closesocket(s);
1.1 daniel 642: return(-1);
643: }
1.2 daniel 644: #endif /* !VMS */
645: #endif /* !_WINSOCKAPI_ */
646:
1.1 daniel 647:
648: sin.sin_family = AF_INET;
649: sin.sin_addr = ia;
650: sin.sin_port = htons(port);
651:
1.26 veillard 652: if ((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1) &&
653: (socket_errno() != EINPROGRESS) && (socket_errno() != EWOULDBLOCK)) {
1.1 daniel 654: perror("connect");
1.26 veillard 655: closesocket(s);
1.1 daniel 656: return(-1);
657: }
658:
659: tv.tv_sec = 60; /* We use 60 second timeouts for now */
660: tv.tv_usec = 0;
661:
662: FD_ZERO(&wfd);
663: FD_SET(s, &wfd);
664:
665: switch(select(s+1, NULL, &wfd, NULL, &tv))
666: {
667: case 0:
668: /* Time out */
1.26 veillard 669: closesocket(s);
1.1 daniel 670: return(-1);
671: case -1:
672: /* Ermm.. ?? */
1.5 daniel 673: #ifdef DEBUG_HTTP
1.1 daniel 674: perror("select");
1.5 daniel 675: #endif
1.26 veillard 676: closesocket(s);
1.1 daniel 677: return(-1);
678: }
1.19 daniel 679:
680: if ( FD_ISSET(s, &wfd) ) {
1.27 ! veillard 681: SOCKLEN_T len;
1.19 daniel 682: len = sizeof(status);
683: if (getsockopt(s, SOL_SOCKET, SO_ERROR, &status, &len) < 0 ) {
684: /* Solaris error code */
685: return (-1);
686: }
687: if ( status ) {
1.26 veillard 688: closesocket(s);
1.19 daniel 689: errno = status;
690: return (-1);
691: }
692: } else {
693: /* pbm */
694: return (-1);
695: }
1.1 daniel 696:
1.5 daniel 697: return(s);
1.1 daniel 698: }
699:
1.5 daniel 700: /**
701: * xmlNanoHTTPConnectHost:
702: * @host: the host name
703: * @port: the port number
704: *
705: * Attempt a connection to the given host:port endpoint. It tries
706: * the multiple IP provided by the DNS if available.
707: *
708: * Returns -1 in case of failure, the file descriptor number otherwise
709: */
710:
711: static int
712: xmlNanoHTTPConnectHost(const char *host, int port)
1.1 daniel 713: {
714: struct hostent *h;
715: int i;
716: int s;
717:
718: h=gethostbyname(host);
1.26 veillard 719: if (h==NULL)
1.1 daniel 720: {
1.5 daniel 721: #ifdef DEBUG_HTTP
1.1 daniel 722: fprintf(stderr,"unable to resolve '%s'.\n", host);
1.5 daniel 723: #endif
1.1 daniel 724: return(-1);
725: }
726:
727: for(i=0; h->h_addr_list[i]; i++)
728: {
729: struct in_addr ia;
730: memcpy(&ia, h->h_addr_list[i],4);
731: s = xmlNanoHTTPConnectAttempt(ia, port);
1.26 veillard 732: if (s != -1)
1.5 daniel 733: return(s);
1.1 daniel 734: }
1.5 daniel 735:
736: #ifdef DEBUG_HTTP
1.1 daniel 737: fprintf(stderr, "unable to connect to '%s'.\n", host);
1.5 daniel 738: #endif
1.1 daniel 739: return(-1);
740: }
741:
742:
1.5 daniel 743: /**
744: * xmlNanoHTTPOpen:
745: * @URL: The URL to load
746: * @contentType: if available the Content-Type information will be
747: * returned at that location
748: *
749: * This function try to open a connection to the indicated resource
750: * via HTTP GET.
751: *
1.6 daniel 752: * Returns NULL in case of failure, otherwise a request handler.
753: * The contentType, if provided must be freed by the caller
1.5 daniel 754: */
1.1 daniel 755:
1.18 daniel 756: void*
1.1 daniel 757: xmlNanoHTTPOpen(const char *URL, char **contentType) {
758: xmlNanoHTTPCtxtPtr ctxt;
759: char buf[4096];
760: int ret;
761: char *p;
762: int head;
763: int nbRedirects = 0;
764: char *redirURL = NULL;
765:
1.12 daniel 766: xmlNanoHTTPInit();
1.5 daniel 767: if (contentType != NULL) *contentType = NULL;
768:
1.1 daniel 769: retry:
770: if (redirURL == NULL)
771: ctxt = xmlNanoHTTPNewCtxt(URL);
772: else {
773: ctxt = xmlNanoHTTPNewCtxt(redirURL);
1.7 daniel 774: xmlFree(redirURL);
1.1 daniel 775: redirURL = NULL;
776: }
777:
778: if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
779: xmlNanoHTTPFreeCtxt(ctxt);
1.7 daniel 780: if (redirURL != NULL) xmlFree(redirURL);
1.1 daniel 781: return(NULL);
782: }
783: if (ctxt->hostname == NULL) {
784: xmlNanoHTTPFreeCtxt(ctxt);
785: return(NULL);
786: }
1.12 daniel 787: if (proxy)
788: ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
789: else
790: ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1.1 daniel 791: if (ret < 0) {
792: xmlNanoHTTPFreeCtxt(ctxt);
793: return(NULL);
794: }
795: ctxt->fd = ret;
1.12 daniel 796: if (proxy) {
1.22 veillard 797: if (ctxt->port != 80)
1.16 daniel 798: #ifdef HAVE_SNPRINTF
1.12 daniel 799: snprintf(buf, sizeof(buf),
800: "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n",
801: ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
802: #else
803: sprintf(buf,
804: "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n",
805: ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
1.22 veillard 806: #endif
1.12 daniel 807: else
1.22 veillard 808: #ifdef HAVE_SNPRINTF
809: snprintf(buf, sizeof(buf),"GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n",
810: ctxt->hostname, ctxt->path, ctxt->hostname);
811: #else
1.12 daniel 812: sprintf(buf, "GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n",
813: ctxt->hostname, ctxt->path, ctxt->hostname);
814: #endif
815: #ifdef DEBUG_HTTP
816: if (ctxt->port != 80)
817: printf("-> Proxy GET http://%s:%d%s HTTP/1.0\n-> Host: %s\n\n",
818: ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname);
819: else
820: printf("-> Proxy GET http://%s%s HTTP/1.0\n-> Host: %s\n\n",
821: ctxt->hostname, ctxt->path, ctxt->hostname);
822: #endif
823: } else {
1.7 daniel 824: #ifdef HAVE_SNPRINTF
1.12 daniel 825: snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
826: ctxt->path, ctxt->hostname);
1.7 daniel 827: #else
1.12 daniel 828: sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
829: ctxt->path, ctxt->hostname);
1.7 daniel 830: #endif
1.5 daniel 831: #ifdef DEBUG_HTTP
1.12 daniel 832: printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n",
833: ctxt->path, ctxt->hostname);
1.5 daniel 834: #endif
1.12 daniel 835: }
1.22 veillard 836: buf[sizeof(buf) - 1] = 0;
1.7 daniel 837: ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
1.1 daniel 838: ctxt->state = XML_NANO_HTTP_WRITE;
839: xmlNanoHTTPSend(ctxt);
840: ctxt->state = XML_NANO_HTTP_READ;
841: head = 1;
842:
843: while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
844: if (head && (*p == 0)) {
845: head = 0;
846: ctxt->content = ctxt->inrptr;
1.12 daniel 847: xmlFree(p);
1.1 daniel 848: break;
849: }
850: xmlNanoHTTPScanAnswer(ctxt, p);
851:
1.5 daniel 852: #ifdef DEBUG_HTTP
853: if (p != NULL) printf("<- %s\n", p);
854: #endif
1.7 daniel 855: if (p != NULL) xmlFree(p);
1.1 daniel 856: }
857:
858: if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
859: (ctxt->returnValue < 400)) {
1.5 daniel 860: #ifdef DEBUG_HTTP
861: printf("\nRedirect to: %s\n", ctxt->location);
862: #endif
1.1 daniel 863: while (xmlNanoHTTPRecv(ctxt)) ;
864: if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
865: nbRedirects++;
1.7 daniel 866: redirURL = xmlMemStrdup(ctxt->location);
1.1 daniel 867: xmlNanoHTTPFreeCtxt(ctxt);
868: goto retry;
869: }
870: xmlNanoHTTPFreeCtxt(ctxt);
1.5 daniel 871: #ifdef DEBUG_HTTP
1.26 veillard 872: printf("Too many redirects, aborting ...\n");
1.5 daniel 873: #endif
1.1 daniel 874: return(NULL);
875:
876: }
877:
1.5 daniel 878: if ((contentType != NULL) && (ctxt->contentType != NULL))
1.7 daniel 879: *contentType = xmlMemStrdup(ctxt->contentType);
1.5 daniel 880:
881: #ifdef DEBUG_HTTP
882: if (ctxt->contentType != NULL)
883: printf("\nCode %d, content-type '%s'\n\n",
884: ctxt->returnValue, ctxt->contentType);
885: else
886: printf("\nCode %d, no content-type\n\n",
887: ctxt->returnValue);
888: #endif
1.1 daniel 889:
890: return((void *) ctxt);
891: }
892:
1.5 daniel 893: /**
894: * xmlNanoHTTPRead:
895: * @ctx: the HTTP context
896: * @dest: a buffer
897: * @len: the buffer length
898: *
899: * This function tries to read @len bytes from the existing HTTP connection
900: * and saves them in @dest. This is a blocking call.
901: *
902: * Returns the number of byte read. 0 is an indication of an end of connection.
903: * -1 indicates a parameter error.
904: */
1.1 daniel 905: int
906: xmlNanoHTTPRead(void *ctx, void *dest, int len) {
907: xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
908:
909: if (ctx == NULL) return(-1);
910: if (dest == NULL) return(-1);
911: if (len <= 0) return(0);
912:
913: while (ctxt->inptr - ctxt->inrptr < len) {
914: if (xmlNanoHTTPRecv(ctxt) == 0) break;
915: }
916: if (ctxt->inptr - ctxt->inrptr < len)
917: len = ctxt->inptr - ctxt->inrptr;
918: memcpy(dest, ctxt->inrptr, len);
919: ctxt->inrptr += len;
920: return(len);
921: }
922:
1.5 daniel 923: /**
924: * xmlNanoHTTPClose:
925: * @ctx: the HTTP context
926: *
927: * This function closes an HTTP context, it ends up the connection and
928: * free all data related to it.
929: */
1.1 daniel 930: void
931: xmlNanoHTTPClose(void *ctx) {
932: xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
933:
934: if (ctx == NULL) return;
935:
936: xmlNanoHTTPFreeCtxt(ctxt);
937: }
938:
1.8 daniel 939: #ifndef DEBUG_HTTP
940: #define DEBUG_HTTP
941: #endif
1.5 daniel 942: /**
1.6 daniel 943: * xmlNanoHTTPMethod:
944: * @URL: The URL to load
945: * @method: the HTTP method to use
946: * @input: the input string if any
947: * @contentType: the Content-Type information IN and OUT
948: * @headers: the extra headers
949: *
950: * This function try to open a connection to the indicated resource
951: * via HTTP using the given @method, adding the given extra headers
952: * and the input buffer for the request content.
953: *
954: * Returns NULL in case of failure, otherwise a request handler.
955: * The contentType, if provided must be freed by the caller
956: */
957:
1.18 daniel 958: void*
1.6 daniel 959: xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
960: char **contentType, const char *headers) {
961: xmlNanoHTTPCtxtPtr ctxt;
962: char buf[20000];
963: int ret;
964: char *p;
965: int head;
966: int nbRedirects = 0;
967: char *redirURL = NULL;
968:
969: if (URL == NULL) return(NULL);
970: if (method == NULL) method = "GET";
971: if (contentType != NULL) *contentType = NULL;
972:
973: retry:
974: if (redirURL == NULL)
975: ctxt = xmlNanoHTTPNewCtxt(URL);
976: else {
977: ctxt = xmlNanoHTTPNewCtxt(redirURL);
1.7 daniel 978: xmlFree(redirURL);
1.6 daniel 979: redirURL = NULL;
980: }
981:
982: if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
983: xmlNanoHTTPFreeCtxt(ctxt);
1.7 daniel 984: if (redirURL != NULL) xmlFree(redirURL);
1.6 daniel 985: return(NULL);
986: }
987: if (ctxt->hostname == NULL) {
988: xmlNanoHTTPFreeCtxt(ctxt);
989: return(NULL);
990: }
991: ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
992: if (ret < 0) {
993: xmlNanoHTTPFreeCtxt(ctxt);
994: return(NULL);
995: }
996: ctxt->fd = ret;
997:
998: if (input == NULL) {
999: if (headers == NULL) {
1000: if ((contentType == NULL) || (*contentType == NULL)) {
1.7 daniel 1001: #ifdef HAVE_SNPRINTF
1.6 daniel 1002: snprintf(buf, sizeof(buf),
1003: "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
1004: method, ctxt->path, ctxt->hostname);
1.7 daniel 1005: #else
1006: sprintf(buf,
1007: "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
1008: method, ctxt->path, ctxt->hostname);
1009: #endif
1.6 daniel 1010: } else {
1.7 daniel 1011: #ifdef HAVE_SNPRINTF
1.6 daniel 1012: snprintf(buf, sizeof(buf),
1013: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n",
1014: method, ctxt->path, ctxt->hostname, *contentType);
1.7 daniel 1015: #else
1016: sprintf(buf,
1017: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n",
1018: method, ctxt->path, ctxt->hostname, *contentType);
1019: #endif
1.6 daniel 1020: }
1021: } else {
1022: if ((contentType == NULL) || (*contentType == NULL)) {
1.7 daniel 1023: #ifdef HAVE_SNPRINTF
1.6 daniel 1024: snprintf(buf, sizeof(buf),
1025: "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n",
1026: method, ctxt->path, ctxt->hostname, headers);
1.7 daniel 1027: #else
1028: sprintf(buf,
1029: "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n",
1030: method, ctxt->path, ctxt->hostname, headers);
1031: #endif
1.6 daniel 1032: } else {
1.7 daniel 1033: #ifdef HAVE_SNPRINTF
1.6 daniel 1034: snprintf(buf, sizeof(buf),
1035: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n",
1036: method, ctxt->path, ctxt->hostname, *contentType,
1037: headers);
1.7 daniel 1038: #else
1039: sprintf(buf,
1040: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n",
1041: method, ctxt->path, ctxt->hostname, *contentType,
1042: headers);
1043: #endif
1.6 daniel 1044: }
1045: }
1046: } else {
1047: int len = strlen(input);
1048: if (headers == NULL) {
1049: if ((contentType == NULL) || (*contentType == NULL)) {
1.7 daniel 1050: #ifdef HAVE_SNPRINTF
1.6 daniel 1051: snprintf(buf, sizeof(buf),
1052: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s",
1053: method, ctxt->path, ctxt->hostname, len, input);
1.7 daniel 1054: #else
1055: sprintf(buf,
1056: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s",
1057: method, ctxt->path, ctxt->hostname, len, input);
1058: #endif
1.6 daniel 1059: } else {
1.7 daniel 1060: #ifdef HAVE_SNPRINTF
1.6 daniel 1061: snprintf(buf, sizeof(buf),
1062: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
1063: method, ctxt->path, ctxt->hostname, *contentType, len,
1064: input);
1.7 daniel 1065: #else
1066: sprintf(buf,
1067: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
1068: method, ctxt->path, ctxt->hostname, *contentType, len,
1069: input);
1070: #endif
1.6 daniel 1071: }
1072: } else {
1073: if ((contentType == NULL) || (*contentType == NULL)) {
1.7 daniel 1074: #ifdef HAVE_SNPRINTF
1.6 daniel 1075: snprintf(buf, sizeof(buf),
1076: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1077: method, ctxt->path, ctxt->hostname, len,
1078: headers, input);
1.7 daniel 1079: #else
1080: sprintf(buf,
1081: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1082: method, ctxt->path, ctxt->hostname, len,
1083: headers, input);
1084: #endif
1.6 daniel 1085: } else {
1.7 daniel 1086: #ifdef HAVE_SNPRINTF
1.6 daniel 1087: snprintf(buf, sizeof(buf),
1088: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1089: method, ctxt->path, ctxt->hostname, *contentType,
1090: len, headers, input);
1.7 daniel 1091: #else
1092: sprintf(buf,
1093: "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s",
1094: method, ctxt->path, ctxt->hostname, *contentType,
1095: len, headers, input);
1096: #endif
1.6 daniel 1097: }
1098: }
1099: }
1.22 veillard 1100: buf[sizeof(buf) - 1] = 0;
1.6 daniel 1101: #ifdef DEBUG_HTTP
1102: printf("-> %s", buf);
1103: #endif
1.7 daniel 1104: ctxt->outptr = ctxt->out = xmlMemStrdup(buf);
1.6 daniel 1105: ctxt->state = XML_NANO_HTTP_WRITE;
1106: xmlNanoHTTPSend(ctxt);
1107: ctxt->state = XML_NANO_HTTP_READ;
1108: head = 1;
1109:
1110: while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
1111: if (head && (*p == 0)) {
1112: head = 0;
1113: ctxt->content = ctxt->inrptr;
1.7 daniel 1114: if (p != NULL) xmlFree(p);
1.6 daniel 1115: break;
1116: }
1117: xmlNanoHTTPScanAnswer(ctxt, p);
1118:
1119: #ifdef DEBUG_HTTP
1120: if (p != NULL) printf("<- %s\n", p);
1121: #endif
1.7 daniel 1122: if (p != NULL) xmlFree(p);
1.6 daniel 1123: }
1124:
1125: if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1126: (ctxt->returnValue < 400)) {
1127: #ifdef DEBUG_HTTP
1128: printf("\nRedirect to: %s\n", ctxt->location);
1129: #endif
1130: while (xmlNanoHTTPRecv(ctxt)) ;
1131: if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1132: nbRedirects++;
1.7 daniel 1133: redirURL = xmlMemStrdup(ctxt->location);
1.6 daniel 1134: xmlNanoHTTPFreeCtxt(ctxt);
1135: goto retry;
1136: }
1137: xmlNanoHTTPFreeCtxt(ctxt);
1138: #ifdef DEBUG_HTTP
1139: printf("Too many redirrects, aborting ...\n");
1140: #endif
1141: return(NULL);
1142:
1143: }
1144:
1145: if ((contentType != NULL) && (ctxt->contentType != NULL))
1.7 daniel 1146: *contentType = xmlMemStrdup(ctxt->contentType);
1147: else if (contentType != NULL)
1148: *contentType = NULL;
1.6 daniel 1149:
1150: #ifdef DEBUG_HTTP
1151: if (ctxt->contentType != NULL)
1152: printf("\nCode %d, content-type '%s'\n\n",
1153: ctxt->returnValue, ctxt->contentType);
1154: else
1155: printf("\nCode %d, no content-type\n\n",
1156: ctxt->returnValue);
1157: #endif
1158:
1159: return((void *) ctxt);
1160: }
1161:
1162: /**
1.5 daniel 1163: * xmlNanoHTTPFetch:
1164: * @URL: The URL to load
1165: * @filename: the filename where the content should be saved
1166: * @contentType: if available the Content-Type information will be
1167: * returned at that location
1168: *
1169: * This function try to fetch the indicated resource via HTTP GET
1170: * and save it's content in the file.
1171: *
1172: * Returns -1 in case of failure, 0 incase of success. The contentType,
1173: * if provided must be freed by the caller
1174: */
1175: int
1176: xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
1.1 daniel 1177: void *ctxt;
1178: char buf[4096];
1179: int fd;
1180: int len;
1181:
1182: ctxt = xmlNanoHTTPOpen(URL, contentType);
1183: if (ctxt == NULL) return(-1);
1184:
1185: if (!strcmp(filename, "-"))
1186: fd = 0;
1187: else {
1.13 daniel 1188: fd = open(filename, O_CREAT | O_WRONLY, 00644);
1.1 daniel 1189: if (fd < 0) {
1190: xmlNanoHTTPClose(ctxt);
1.5 daniel 1191: if ((contentType != NULL) && (*contentType != NULL)) {
1.7 daniel 1192: xmlFree(*contentType);
1.5 daniel 1193: *contentType = NULL;
1194: }
1.1 daniel 1195: return(-1);
1196: }
1197: }
1198:
1199: while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
1200: write(fd, buf, len);
1201: }
1202:
1203: xmlNanoHTTPClose(ctxt);
1.13 daniel 1204: close(fd);
1.1 daniel 1205: return(0);
1.6 daniel 1206: }
1207:
1208: /**
1209: * xmlNanoHTTPSave:
1.8 daniel 1210: * @ctxt: the HTTP context
1.6 daniel 1211: * @filename: the filename where the content should be saved
1212: *
1213: * This function saves the output of the HTTP transaction to a file
1214: * It closes and free the context at the end
1215: *
1216: * Returns -1 in case of failure, 0 incase of success.
1217: */
1218: int
1219: xmlNanoHTTPSave(void *ctxt, const char *filename) {
1220: char buf[4096];
1221: int fd;
1222: int len;
1223:
1224: if (ctxt == NULL) return(-1);
1225:
1226: if (!strcmp(filename, "-"))
1227: fd = 0;
1228: else {
1229: fd = open(filename, O_CREAT | O_WRONLY);
1230: if (fd < 0) {
1231: xmlNanoHTTPClose(ctxt);
1232: return(-1);
1233: }
1234: }
1235:
1236: while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
1237: write(fd, buf, len);
1238: }
1239:
1240: xmlNanoHTTPClose(ctxt);
1241: return(0);
1242: }
1243:
1244: /**
1245: * xmlNanoHTTPReturnCode:
1246: * @ctx: the HTTP context
1247: *
1248: * Returns the HTTP return code for the request.
1249: */
1250: int
1251: xmlNanoHTTPReturnCode(void *ctx) {
1252: xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1253:
1254: if (ctxt == NULL) return(-1);
1255:
1256: return(ctxt->returnValue);
1.1 daniel 1257: }
1258:
1259: #ifdef STANDALONE
1260: int main(int argc, char **argv) {
1261: char *contentType = NULL;
1262:
1263: if (argv[1] != NULL) {
1264: if (argv[2] != NULL)
1265: xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1266: else
1267: xmlNanoHTTPFetch(argv[1], "-", &contentType);
1.7 daniel 1268: if (contentType != NULL) xmlFree(contentType);
1.1 daniel 1269: } else {
1270: printf("%s: minimal HTTP GET implementation\n", argv[0]);
1271: printf("\tusage %s [ URL [ filename ] ]\n", argv[0]);
1272: }
1.12 daniel 1273: xmlNanoHTTPCleanup();
1274: xmlMemoryDump();
1.1 daniel 1275: return(0);
1276: }
1277: #endif /* STANDALONE */
1.17 daniel 1278: #else /* !LIBXML_HTTP_ENABLED */
1279: #ifdef STANDALONE
1280: #include <stdio.h>
1281: int main(int argc, char **argv) {
1282: printf("%s : HTTP support not compiled in\n", argv[0]);
1283: return(0);
1284: }
1285: #endif /* STANDALONE */
1286: #endif /* LIBXML_HTTP_ENABLED */
Webmaster