fix perl
[platform/upstream/libxml2.git] / nanohttp.c
1 /*
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.com
12  */
13  
14 #define NEED_SOCKETS
15 #define IN_LIBXML
16 #include "libxml.h"
17
18 #ifdef LIBXML_HTTP_ENABLED
19 #include <string.h>
20
21 #ifdef HAVE_STDLIB_H
22 #include <stdlib.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30 #ifdef HAVE_SYS_SOCKET_H
31 #include <sys/socket.h>
32 #endif
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
35 #endif
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
38 #endif
39 #ifdef HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42 #ifdef HAVE_RESOLV_H
43 #ifdef HAVE_ARPA_NAMESER_H
44 #include <arpa/nameser.h>
45 #endif
46 #include <resolv.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 #ifndef HAVE_POLL_H
58 #ifdef HAVE_SYS_SELECT_H
59 #include <sys/select.h>
60 #endif
61 #else
62 #include <poll.h>
63 #endif
64 #ifdef HAVE_STRINGS_H
65 #include <strings.h>
66 #endif
67 #ifdef HAVE_ZLIB_H
68 #include <zlib.h>
69 #endif
70
71
72 #ifdef VMS
73 #include <stropts>
74 #define XML_SOCKLEN_T unsigned int
75 #endif
76
77 #if defined(__MINGW32__) || defined(_WIN32_WCE)
78 #ifndef _WINSOCKAPI_
79 #define _WINSOCKAPI_
80 #endif
81 #include <wsockcompat.h>
82 #include <winsock2.h>
83 #undef XML_SOCKLEN_T
84 #define XML_SOCKLEN_T unsigned int
85 #endif
86
87 #include <libxml/globals.h>
88 #include <libxml/xmlerror.h>
89 #include <libxml/xmlmemory.h>
90 #include <libxml/parser.h> /* for xmlStr(n)casecmp() */
91 #include <libxml/nanohttp.h>
92 #include <libxml/globals.h>
93 #include <libxml/uri.h>
94
95 /**
96  * A couple portability macros
97  */
98 #ifndef _WINSOCKAPI_
99 #if !defined(__BEOS__) || defined(__HAIKU__)
100 #define closesocket(s) close(s)
101 #endif
102 #define SOCKET int
103 #define INVALID_SOCKET (-1)
104 #endif
105
106 #ifdef __BEOS__
107 #ifndef PF_INET
108 #define PF_INET AF_INET
109 #endif
110 #endif
111
112 #ifndef XML_SOCKLEN_T
113 #define XML_SOCKLEN_T unsigned int
114 #endif
115
116 #ifdef STANDALONE
117 #define DEBUG_HTTP
118 #define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
119 #define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
120 #endif
121
122 #define XML_NANO_HTTP_MAX_REDIR 10
123
124 #define XML_NANO_HTTP_CHUNK     4096
125
126 #define XML_NANO_HTTP_CLOSED    0
127 #define XML_NANO_HTTP_WRITE     1
128 #define XML_NANO_HTTP_READ      2
129 #define XML_NANO_HTTP_NONE      4
130
131 typedef struct xmlNanoHTTPCtxt {
132     char *protocol;     /* the protocol name */
133     char *hostname;     /* the host name */
134     int port;           /* the port */
135     char *path;         /* the path within the URL */
136     char *query;        /* the query string */
137     SOCKET fd;          /* the file descriptor for the socket */
138     int state;          /* WRITE / READ / CLOSED */
139     char *out;          /* buffer sent (zero terminated) */
140     char *outptr;       /* index within the buffer sent */
141     char *in;           /* the receiving buffer */
142     char *content;      /* the start of the content */
143     char *inptr;        /* the next byte to read from network */
144     char *inrptr;       /* the next byte to give back to the client */
145     int inlen;          /* len of the input buffer */
146     int last;           /* return code for last operation */
147     int returnValue;    /* the protocol return value */
148     int version;        /* the protocol version */
149     int ContentLength;  /* specified content length from HTTP header */
150     char *contentType;  /* the MIME type for the input */
151     char *location;     /* the new URL in case of redirect */
152     char *authHeader;   /* contents of {WWW,Proxy}-Authenticate header */
153     char *encoding;     /* encoding extracted from the contentType */
154     char *mimeType;     /* Mime-Type extracted from the contentType */
155 #ifdef HAVE_ZLIB_H
156     z_stream *strm;     /* Zlib stream object */
157     int usesGzip;       /* "Content-Encoding: gzip" was detected */
158 #endif
159 } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
160
161 static int initialized = 0;
162 static char *proxy = NULL;       /* the proxy name if any */
163 static int proxyPort;   /* the proxy port if any */
164 static unsigned int timeout = 60;/* the select() timeout in seconds */
165
166 static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
167
168 /**
169  * xmlHTTPErrMemory:
170  * @extra:  extra informations
171  *
172  * Handle an out of memory condition
173  */
174 static void
175 xmlHTTPErrMemory(const char *extra)
176 {
177     __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
178 }
179
180 /**
181  * A portability function
182  */
183 static int socket_errno(void) {
184 #ifdef _WINSOCKAPI_
185     return(WSAGetLastError());
186 #else
187     return(errno);
188 #endif
189 }
190
191 #ifdef SUPPORT_IP6
192 static
193 int have_ipv6(void) {
194     SOCKET s;
195
196     s = socket (AF_INET6, SOCK_STREAM, 0);
197     if (s != INVALID_SOCKET) {
198         close (s);
199         return (1);
200     }
201     return (0);
202 }
203 #endif
204
205 /**
206  * xmlNanoHTTPInit:
207  *
208  * Initialize the HTTP protocol layer.
209  * Currently it just checks for proxy informations
210  */
211
212 void
213 xmlNanoHTTPInit(void) {
214     const char *env;
215 #ifdef _WINSOCKAPI_
216     WSADATA wsaData;    
217 #endif
218
219     if (initialized)
220         return;
221
222 #ifdef _WINSOCKAPI_
223     if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
224         return;
225 #endif
226
227     if (proxy == NULL) {
228         proxyPort = 80;
229         env = getenv("no_proxy");
230         if (env && ((env[0] == '*') && (env[1] == 0)))
231             goto done;
232         env = getenv("http_proxy");
233         if (env != NULL) {
234             xmlNanoHTTPScanProxy(env);
235             goto done;
236         }
237         env = getenv("HTTP_PROXY");
238         if (env != NULL) {
239             xmlNanoHTTPScanProxy(env);
240             goto done;
241         }
242     }
243 done:
244     initialized = 1;
245 }
246
247 /**
248  * xmlNanoHTTPCleanup:
249  *
250  * Cleanup the HTTP protocol layer.
251  */
252
253 void
254 xmlNanoHTTPCleanup(void) {
255     if (proxy != NULL) {
256         xmlFree(proxy);
257         proxy = NULL;
258     }
259 #ifdef _WINSOCKAPI_
260     if (initialized)
261         WSACleanup();
262 #endif
263     initialized = 0;
264     return;
265 }
266
267 /**
268  * xmlNanoHTTPScanURL:
269  * @ctxt:  an HTTP context
270  * @URL:  The URL used to initialize the context
271  *
272  * (Re)Initialize an HTTP context by parsing the URL and finding
273  * the protocol host port and path it indicates.
274  */
275
276 static void
277 xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
278     xmlURIPtr uri;
279     /*
280      * Clear any existing data from the context
281      */
282     if (ctxt->protocol != NULL) { 
283         xmlFree(ctxt->protocol);
284         ctxt->protocol = NULL;
285     }
286     if (ctxt->hostname != NULL) { 
287         xmlFree(ctxt->hostname);
288         ctxt->hostname = NULL;
289     }
290     if (ctxt->path != NULL) { 
291         xmlFree(ctxt->path);
292         ctxt->path = NULL;
293     }
294     if (ctxt->query != NULL) { 
295         xmlFree(ctxt->query);
296         ctxt->query = NULL;
297     }
298     if (URL == NULL) return;
299
300     uri = xmlParseURIRaw(URL, 1);
301     if (uri == NULL)
302         return;
303
304     if ((uri->scheme == NULL) || (uri->server == NULL)) {
305         xmlFreeURI(uri);
306         return;
307     }
308     
309     ctxt->protocol = xmlMemStrdup(uri->scheme);
310     ctxt->hostname = xmlMemStrdup(uri->server);
311     if (uri->path != NULL)
312         ctxt->path = xmlMemStrdup(uri->path);
313     else
314         ctxt->path = xmlMemStrdup("/");
315     if (uri->query != NULL)
316         ctxt->query = xmlMemStrdup(uri->query);
317     if (uri->port != 0)
318         ctxt->port = uri->port;
319
320     xmlFreeURI(uri);
321 }
322
323 /**
324  * xmlNanoHTTPScanProxy:
325  * @URL:  The proxy URL used to initialize the proxy context
326  *
327  * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
328  * the protocol host port it indicates.
329  * Should be like http://myproxy/ or http://myproxy:3128/
330  * A NULL URL cleans up proxy informations.
331  */
332
333 void
334 xmlNanoHTTPScanProxy(const char *URL) {
335     xmlURIPtr uri;
336
337     if (proxy != NULL) { 
338         xmlFree(proxy);
339         proxy = NULL;
340     }
341     proxyPort = 0;
342
343 #ifdef DEBUG_HTTP
344     if (URL == NULL)
345         xmlGenericError(xmlGenericErrorContext,
346                 "Removing HTTP proxy info\n");
347     else
348         xmlGenericError(xmlGenericErrorContext,
349                 "Using HTTP proxy %s\n", URL);
350 #endif
351     if (URL == NULL) return;
352
353     uri = xmlParseURIRaw(URL, 1);
354     if ((uri == NULL) || (uri->scheme == NULL) ||
355         (strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
356         __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
357         if (uri != NULL)
358             xmlFreeURI(uri);
359         return;
360     }
361     
362     proxy = xmlMemStrdup(uri->server);
363     if (uri->port != 0)
364         proxyPort = uri->port;
365
366     xmlFreeURI(uri);
367 }
368
369 /**
370  * xmlNanoHTTPNewCtxt:
371  * @URL:  The URL used to initialize the context
372  *
373  * Allocate and initialize a new HTTP context.
374  *
375  * Returns an HTTP context or NULL in case of error.
376  */
377
378 static xmlNanoHTTPCtxtPtr
379 xmlNanoHTTPNewCtxt(const char *URL) {
380     xmlNanoHTTPCtxtPtr ret;
381
382     ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
383     if (ret == NULL) {
384         xmlHTTPErrMemory("allocating context");
385         return(NULL);
386     }
387
388     memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
389     ret->port = 80;
390     ret->returnValue = 0;
391     ret->fd = INVALID_SOCKET;
392     ret->ContentLength = -1;
393
394     xmlNanoHTTPScanURL(ret, URL);
395
396     return(ret);
397 }
398
399 /**
400  * xmlNanoHTTPFreeCtxt:
401  * @ctxt:  an HTTP context
402  *
403  * Frees the context after closing the connection.
404  */
405
406 static void
407 xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
408     if (ctxt == NULL) return;
409     if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
410     if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
411     if (ctxt->path != NULL) xmlFree(ctxt->path);
412     if (ctxt->query != NULL) xmlFree(ctxt->query);
413     if (ctxt->out != NULL) xmlFree(ctxt->out);
414     if (ctxt->in != NULL) xmlFree(ctxt->in);
415     if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
416     if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
417     if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
418     if (ctxt->location != NULL) xmlFree(ctxt->location);
419     if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
420 #ifdef HAVE_ZLIB_H
421     if (ctxt->strm != NULL) {
422         inflateEnd(ctxt->strm);
423         xmlFree(ctxt->strm);
424     }
425 #endif
426
427     ctxt->state = XML_NANO_HTTP_NONE;
428     if (ctxt->fd != INVALID_SOCKET) closesocket(ctxt->fd);
429     ctxt->fd = INVALID_SOCKET;
430     xmlFree(ctxt);
431 }
432
433 /**
434  * xmlNanoHTTPSend:
435  * @ctxt:  an HTTP context
436  *
437  * Send the input needed to initiate the processing on the server side
438  * Returns number of bytes sent or -1 on error.
439  */
440
441 static int
442 xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
443 {
444     int total_sent = 0;
445 #ifdef HAVE_POLL_H
446     struct pollfd p;
447 #else
448     struct timeval tv;
449     fd_set wfd;
450 #endif
451
452     if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
453         while (total_sent < outlen) {
454             int nsent = send(ctxt->fd, xmt_ptr + total_sent,
455                              outlen - total_sent, 0);
456
457             if (nsent > 0)
458                 total_sent += nsent;
459             else if ((nsent == -1) &&
460 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
461                      (socket_errno() != EAGAIN) &&
462 #endif
463                      (socket_errno() != EWOULDBLOCK)) {
464                 __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
465                 if (total_sent == 0)
466                     total_sent = -1;
467                 break;
468             } else {
469                 /*
470                  * No data sent
471                  * Since non-blocking sockets are used, wait for
472                  * socket to be writable or default timeout prior
473                  * to retrying.
474                  */
475 #ifndef HAVE_POLL_H
476 #ifndef _WINSOCKAPI_
477                 if (ctxt->fd > FD_SETSIZE)
478                     return -1;
479 #endif
480
481                 tv.tv_sec = timeout;
482                 tv.tv_usec = 0;
483                 FD_ZERO(&wfd);
484 #ifdef _MSC_VER
485 #pragma warning(push)
486 #pragma warning(disable: 4018)
487 #endif
488                 FD_SET(ctxt->fd, &wfd);
489 #ifdef _MSC_VER
490 #pragma warning(pop)
491 #endif
492                 (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
493 #else
494                 p.fd = ctxt->fd;
495                 p.events = POLLOUT;
496                 (void) poll(&p, 1, timeout * 1000);
497 #endif /* !HAVE_POLL_H */
498             }
499         }
500     }
501
502     return total_sent;
503 }
504
505 /**
506  * xmlNanoHTTPRecv:
507  * @ctxt:  an HTTP context
508  *
509  * Read information coming from the HTTP connection.
510  * This is a blocking call (but it blocks in select(), not read()).
511  *
512  * Returns the number of byte read or -1 in case of error.
513  */
514
515 static int
516 xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
517 {
518 #ifdef HAVE_POLL_H
519     struct pollfd p;
520 #else
521     fd_set rfd;
522     struct timeval tv;
523 #endif
524
525
526     while (ctxt->state & XML_NANO_HTTP_READ) {
527         if (ctxt->in == NULL) {
528             ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
529             if (ctxt->in == NULL) {
530                 xmlHTTPErrMemory("allocating input");
531                 ctxt->last = -1;
532                 return (-1);
533             }
534             ctxt->inlen = 65000;
535             ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
536         }
537         if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
538             int delta = ctxt->inrptr - ctxt->in;
539             int len = ctxt->inptr - ctxt->inrptr;
540
541             memmove(ctxt->in, ctxt->inrptr, len);
542             ctxt->inrptr -= delta;
543             ctxt->content -= delta;
544             ctxt->inptr -= delta;
545         }
546         if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
547             int d_inptr = ctxt->inptr - ctxt->in;
548             int d_content = ctxt->content - ctxt->in;
549             int d_inrptr = ctxt->inrptr - ctxt->in;
550             char *tmp_ptr = ctxt->in;
551
552             ctxt->inlen *= 2;
553             ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
554             if (ctxt->in == NULL) {
555                 xmlHTTPErrMemory("allocating input buffer");
556                 xmlFree(tmp_ptr);
557                 ctxt->last = -1;
558                 return (-1);
559             }
560             ctxt->inptr = ctxt->in + d_inptr;
561             ctxt->content = ctxt->in + d_content;
562             ctxt->inrptr = ctxt->in + d_inrptr;
563         }
564         ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
565         if (ctxt->last > 0) {
566             ctxt->inptr += ctxt->last;
567             return (ctxt->last);
568         }
569         if (ctxt->last == 0) {
570             return (0);
571         }
572         if (ctxt->last == -1) {
573             switch (socket_errno()) {
574                 case EINPROGRESS:
575                 case EWOULDBLOCK:
576 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
577                 case EAGAIN:
578 #endif
579                     break;
580
581                 case ECONNRESET:
582                 case ESHUTDOWN:
583                     return (0);
584
585                 default:
586                     __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
587                     return (-1);
588             }
589         }
590 #ifdef HAVE_POLL_H
591         p.fd = ctxt->fd;
592         p.events = POLLIN;
593         if ((poll(&p, 1, timeout * 1000) < 1)
594 #if defined(EINTR)
595             && (errno != EINTR)
596 #endif
597             )
598             return (0);
599 #else /* !HAVE_POLL_H */
600 #ifndef _WINSOCKAPI_
601         if (ctxt->fd > FD_SETSIZE)
602             return 0;
603 #endif
604
605         tv.tv_sec = timeout;
606         tv.tv_usec = 0;
607         FD_ZERO(&rfd);
608
609 #ifdef _MSC_VER
610 #pragma warning(push)
611 #pragma warning(disable: 4018)
612 #endif
613
614         FD_SET(ctxt->fd, &rfd);
615
616 #ifdef _MSC_VER
617 #pragma warning(pop)
618 #endif
619
620         if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
621 #if defined(EINTR)
622             && (errno != EINTR)
623 #endif
624             )
625             return (0);
626 #endif /* !HAVE_POLL_H */
627     }
628     return (0);
629 }
630
631 /**
632  * xmlNanoHTTPReadLine:
633  * @ctxt:  an HTTP context
634  *
635  * Read one line in the HTTP server output, usually for extracting
636  * the HTTP protocol informations from the answer header.
637  *
638  * Returns a newly allocated string with a copy of the line, or NULL
639  *         which indicate the end of the input.
640  */
641
642 static char *
643 xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
644     char buf[4096];
645     char *bp = buf;
646     int rc;
647     
648     while (bp - buf < 4095) {
649         if (ctxt->inrptr == ctxt->inptr) {
650             if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
651                 if (bp == buf)
652                     return(NULL);
653                 else
654                     *bp = 0;
655                 return(xmlMemStrdup(buf));
656             }
657             else if ( rc == -1 ) {
658                 return ( NULL );
659             }
660         }
661         *bp = *ctxt->inrptr++;
662         if (*bp == '\n') {
663             *bp = 0;
664             return(xmlMemStrdup(buf));
665         }
666         if (*bp != '\r')
667             bp++;
668     }
669     buf[4095] = 0;
670     return(xmlMemStrdup(buf));
671 }
672
673
674 /**
675  * xmlNanoHTTPScanAnswer:
676  * @ctxt:  an HTTP context
677  * @line:  an HTTP header line
678  *
679  * Try to extract useful informations from the server answer.
680  * We currently parse and process:
681  *  - The HTTP revision/ return code
682  *  - The Content-Type, Mime-Type and charset used
683  *  - The Location for redirect processing.
684  *
685  * Returns -1 in case of failure, the file descriptor number otherwise
686  */
687
688 static void
689 xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
690     const char *cur = line;
691
692     if (line == NULL) return;
693
694     if (!strncmp(line, "HTTP/", 5)) {
695         int version = 0;
696         int ret = 0;
697
698         cur += 5;
699         while ((*cur >= '0') && (*cur <= '9')) {
700             version *= 10;
701             version += *cur - '0';
702             cur++;
703         }
704         if (*cur == '.') {
705             cur++;
706             if ((*cur >= '0') && (*cur <= '9')) {
707                 version *= 10;
708                 version += *cur - '0';
709                 cur++;
710             }
711             while ((*cur >= '0') && (*cur <= '9'))
712                 cur++;
713         } else
714             version *= 10;
715         if ((*cur != ' ') && (*cur != '\t')) return;
716         while ((*cur == ' ') || (*cur == '\t')) cur++;
717         if ((*cur < '0') || (*cur > '9')) return;
718         while ((*cur >= '0') && (*cur <= '9')) {
719             ret *= 10;
720             ret += *cur - '0';
721             cur++;
722         }
723         if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
724         ctxt->returnValue = ret;
725         ctxt->version = version;
726     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
727         const xmlChar *charset, *last, *mime;
728         cur += 13;
729         while ((*cur == ' ') || (*cur == '\t')) cur++;
730         if (ctxt->contentType != NULL)
731             xmlFree(ctxt->contentType);
732         ctxt->contentType = xmlMemStrdup(cur);
733         mime = (const xmlChar *) cur;
734         last = mime;
735         while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
736                (*last != ';') && (*last != ','))
737             last++;
738         if (ctxt->mimeType != NULL)
739             xmlFree(ctxt->mimeType);
740         ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
741         charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
742         if (charset != NULL) {
743             charset += 8;
744             last = charset;
745             while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
746                    (*last != ';') && (*last != ','))
747                 last++;
748             if (ctxt->encoding != NULL)
749                 xmlFree(ctxt->encoding);
750             ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
751         }
752     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
753         const xmlChar *charset, *last, *mime;
754         cur += 12;
755         if (ctxt->contentType != NULL) return;
756         while ((*cur == ' ') || (*cur == '\t')) cur++;
757         ctxt->contentType = xmlMemStrdup(cur);
758         mime = (const xmlChar *) cur;
759         last = mime;
760         while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
761                (*last != ';') && (*last != ','))
762             last++;
763         if (ctxt->mimeType != NULL)
764             xmlFree(ctxt->mimeType);
765         ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
766         charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
767         if (charset != NULL) {
768             charset += 8;
769             last = charset;
770             while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
771                    (*last != ';') && (*last != ','))
772                 last++;
773             if (ctxt->encoding != NULL)
774                 xmlFree(ctxt->encoding);
775             ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
776         }
777     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
778         cur += 9;
779         while ((*cur == ' ') || (*cur == '\t')) cur++;
780         if (ctxt->location != NULL)
781             xmlFree(ctxt->location);
782         if (*cur == '/') {
783             xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
784             xmlChar *tmp_loc = 
785                 xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
786             ctxt->location = 
787                 (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
788         } else {
789             ctxt->location = xmlMemStrdup(cur);
790         }
791     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
792         cur += 17;
793         while ((*cur == ' ') || (*cur == '\t')) cur++;
794         if (ctxt->authHeader != NULL)
795             xmlFree(ctxt->authHeader);
796         ctxt->authHeader = xmlMemStrdup(cur);
797     } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
798         cur += 19;
799         while ((*cur == ' ') || (*cur == '\t')) cur++;
800         if (ctxt->authHeader != NULL)
801             xmlFree(ctxt->authHeader);
802         ctxt->authHeader = xmlMemStrdup(cur);
803 #ifdef HAVE_ZLIB_H
804     } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
805         cur += 17;
806         while ((*cur == ' ') || (*cur == '\t')) cur++;
807         if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
808             ctxt->usesGzip = 1;
809
810             ctxt->strm = xmlMalloc(sizeof(z_stream));
811
812             if (ctxt->strm != NULL) {
813                 ctxt->strm->zalloc = Z_NULL;
814                 ctxt->strm->zfree = Z_NULL;
815                 ctxt->strm->opaque = Z_NULL;
816                 ctxt->strm->avail_in = 0;
817                 ctxt->strm->next_in = Z_NULL;
818
819                 inflateInit2( ctxt->strm, 31 );
820             }
821         }
822 #endif
823     } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
824         cur += 15;
825         ctxt->ContentLength = strtol( cur, NULL, 10 );
826     }
827 }
828
829 /**
830  * xmlNanoHTTPConnectAttempt:
831  * @addr:  a socket address structure
832  *
833  * Attempt a connection to the given IP:port endpoint. It forces
834  * non-blocking semantic on the socket, and allow 60 seconds for
835  * the host to answer.
836  *
837  * Returns -1 in case of failure, the file descriptor number otherwise
838  */
839
840 static SOCKET
841 xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
842 {
843 #ifndef HAVE_POLL_H
844     fd_set wfd;
845 #ifdef _WINSOCKAPI_
846     fd_set xfd;
847 #endif
848     struct timeval tv;
849 #else /* !HAVE_POLL_H */
850     struct pollfd p;
851 #endif /* !HAVE_POLL_H */
852     int status;
853
854     int addrlen;
855
856     SOCKET s;
857
858 #ifdef SUPPORT_IP6
859     if (addr->sa_family == AF_INET6) {
860         s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
861         addrlen = sizeof(struct sockaddr_in6);
862     } else
863 #endif
864     {
865         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
866         addrlen = sizeof(struct sockaddr_in);
867     }
868     if (s == INVALID_SOCKET) {
869 #ifdef DEBUG_HTTP
870         perror("socket");
871 #endif
872         __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
873         return INVALID_SOCKET;
874     }
875 #ifdef _WINSOCKAPI_
876     {
877         u_long one = 1;
878
879         status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
880     }
881 #else /* _WINSOCKAPI_ */
882 #if defined(VMS)
883     {
884         int enable = 1;
885
886         status = ioctl(s, FIONBIO, &enable);
887     }
888 #else /* VMS */
889 #if defined(__BEOS__) && !defined(__HAIKU__)
890     {
891         bool noblock = true;
892
893         status =
894             setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
895                        sizeof(noblock));
896     }
897 #else /* __BEOS__ */
898     if ((status = fcntl(s, F_GETFL, 0)) != -1) {
899 #ifdef O_NONBLOCK
900         status |= O_NONBLOCK;
901 #else /* O_NONBLOCK */
902 #ifdef F_NDELAY
903         status |= F_NDELAY;
904 #endif /* F_NDELAY */
905 #endif /* !O_NONBLOCK */
906         status = fcntl(s, F_SETFL, status);
907     }
908     if (status < 0) {
909 #ifdef DEBUG_HTTP
910         perror("nonblocking");
911 #endif
912         __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
913         closesocket(s);
914         return INVALID_SOCKET;
915     }
916 #endif /* !__BEOS__ */
917 #endif /* !VMS */
918 #endif /* !_WINSOCKAPI_ */
919
920     if (connect(s, addr, addrlen) == -1) {
921         switch (socket_errno()) {
922             case EINPROGRESS:
923             case EWOULDBLOCK:
924                 break;
925             default:
926                 __xmlIOErr(XML_FROM_HTTP, 0,
927                            "error connecting to HTTP server");
928                 closesocket(s);
929                 return INVALID_SOCKET;
930         }
931     }
932 #ifndef HAVE_POLL_H
933     tv.tv_sec = timeout;
934     tv.tv_usec = 0;
935
936 #ifdef _MSC_VER
937 #pragma warning(push)
938 #pragma warning(disable: 4018)
939 #endif
940 #ifndef _WINSOCKAPI_
941     if (s > FD_SETSIZE)
942         return INVALID_SOCKET;
943 #endif
944     FD_ZERO(&wfd);
945     FD_SET(s, &wfd);
946
947 #ifdef _WINSOCKAPI_
948     FD_ZERO(&xfd);
949     FD_SET(s, &xfd);
950
951     switch (select(s + 1, NULL, &wfd, &xfd, &tv))
952 #else
953     switch (select(s + 1, NULL, &wfd, NULL, &tv))
954 #endif
955 #ifdef _MSC_VER
956 #pragma warning(pop)
957 #endif
958
959 #else /* !HAVE_POLL_H */
960     p.fd = s;
961     p.events = POLLOUT;
962     switch (poll(&p, 1, timeout * 1000))
963 #endif /* !HAVE_POLL_H */
964
965     {
966         case 0:
967             /* Time out */
968             __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
969             closesocket(s);
970             return INVALID_SOCKET;
971         case -1:
972             /* Ermm.. ?? */
973             __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
974             closesocket(s);
975             return INVALID_SOCKET;
976     }
977
978 #ifndef HAVE_POLL_H
979     if (FD_ISSET(s, &wfd)
980 #ifdef _WINSOCKAPI_
981         || FD_ISSET(s, &xfd)
982 #endif
983         )
984 #else /* !HAVE_POLL_H */
985     if (p.revents == POLLOUT)
986 #endif /* !HAVE_POLL_H */
987     {
988         XML_SOCKLEN_T len;
989
990         len = sizeof(status);
991 #ifdef SO_ERROR
992         if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
993             0) {
994             /* Solaris error code */
995             __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
996             return INVALID_SOCKET;
997         }
998 #endif
999         if (status) {
1000             __xmlIOErr(XML_FROM_HTTP, 0,
1001                        "Error connecting to remote host");
1002             closesocket(s);
1003             errno = status;
1004             return INVALID_SOCKET;
1005         }
1006     } else {
1007         /* pbm */
1008         __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
1009         closesocket(s);
1010         return INVALID_SOCKET;
1011     }
1012
1013     return (s);
1014 }
1015
1016 /**
1017  * xmlNanoHTTPConnectHost:
1018  * @host:  the host name
1019  * @port:  the port number
1020  *
1021  * Attempt a connection to the given host:port endpoint. It tries
1022  * the multiple IP provided by the DNS if available.
1023  *
1024  * Returns -1 in case of failure, the file descriptor number otherwise
1025  */
1026
1027 static SOCKET
1028 xmlNanoHTTPConnectHost(const char *host, int port)
1029 {
1030     struct hostent *h;
1031     struct sockaddr *addr = NULL;
1032     struct in_addr ia;
1033     struct sockaddr_in sockin;
1034
1035 #ifdef SUPPORT_IP6
1036     struct in6_addr ia6;
1037     struct sockaddr_in6 sockin6;
1038 #endif
1039     int i;
1040     SOCKET s;
1041
1042     memset (&sockin, 0, sizeof(sockin));
1043 #ifdef SUPPORT_IP6
1044     memset (&sockin6, 0, sizeof(sockin6));
1045 #endif
1046
1047 #if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
1048     if (have_ipv6 ())
1049     {
1050         if (!(_res.options & RES_INIT))
1051             res_init();
1052         _res.options |= RES_USE_INET6;
1053     }
1054 #endif
1055
1056 #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1057     if (have_ipv6 ())
1058 #endif
1059 #if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
1060     {
1061         int status;
1062         struct addrinfo hints, *res, *result;
1063
1064         result = NULL;
1065         memset (&hints, 0,sizeof(hints));
1066         hints.ai_socktype = SOCK_STREAM;
1067
1068         status = getaddrinfo (host, NULL, &hints, &result);
1069         if (status) {
1070             __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
1071             return INVALID_SOCKET;
1072         }
1073
1074         for (res = result; res; res = res->ai_next) {
1075             if (res->ai_family == AF_INET) {
1076                 if (res->ai_addrlen > sizeof(sockin)) {
1077                     __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1078                     freeaddrinfo (result);
1079                     return INVALID_SOCKET;
1080                 }
1081                 memcpy (&sockin, res->ai_addr, res->ai_addrlen);
1082                 sockin.sin_port = htons (port);
1083                 addr = (struct sockaddr *)&sockin;
1084 #ifdef SUPPORT_IP6
1085             } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
1086                 if (res->ai_addrlen > sizeof(sockin6)) {
1087                     __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1088                     freeaddrinfo (result);
1089                     return INVALID_SOCKET;
1090                 }
1091                 memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
1092                 sockin6.sin6_port = htons (port);
1093                 addr = (struct sockaddr *)&sockin6;
1094 #endif
1095             } else
1096                 continue;              /* for */
1097
1098             s = xmlNanoHTTPConnectAttempt (addr);
1099             if (s != INVALID_SOCKET) {
1100                 freeaddrinfo (result);
1101                 return (s);
1102             }
1103         }
1104
1105         if (result)
1106             freeaddrinfo (result);
1107     }
1108 #endif
1109 #if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
1110     else
1111 #endif
1112 #if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
1113     {
1114         h = gethostbyname (host);
1115         if (h == NULL) {
1116
1117 /*
1118  * Okay, I got fed up by the non-portability of this error message
1119  * extraction code. it work on Linux, if it work on your platform
1120  * and one want to enable it, send me the defined(foobar) needed
1121  */
1122 #if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
1123             const char *h_err_txt = "";
1124
1125             switch (h_errno) {
1126                 case HOST_NOT_FOUND:
1127                     h_err_txt = "Authoritive host not found";
1128                     break;
1129
1130                 case TRY_AGAIN:
1131                     h_err_txt =
1132                         "Non-authoritive host not found or server failure.";
1133                     break;
1134
1135                 case NO_RECOVERY:
1136                     h_err_txt =
1137                         "Non-recoverable errors:  FORMERR, REFUSED, or NOTIMP.";
1138                     break;
1139
1140 #ifdef NO_ADDRESS
1141                 case NO_ADDRESS:
1142                     h_err_txt =
1143                         "Valid name, no data record of requested type.";
1144                     break;
1145 #endif
1146
1147                 default:
1148                     h_err_txt = "No error text defined.";
1149                     break;
1150             }
1151             __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
1152 #else
1153             __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
1154 #endif
1155             return INVALID_SOCKET;
1156         }
1157
1158         for (i = 0; h->h_addr_list[i]; i++) {
1159             if (h->h_addrtype == AF_INET) {
1160                 /* A records (IPv4) */
1161                 if ((unsigned int) h->h_length > sizeof(ia)) {
1162                     __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1163                     return INVALID_SOCKET;
1164                 }
1165                 memcpy (&ia, h->h_addr_list[i], h->h_length);
1166                 sockin.sin_family = h->h_addrtype;
1167                 sockin.sin_addr = ia;
1168                 sockin.sin_port = (unsigned short)htons ((unsigned short)port);
1169                 addr = (struct sockaddr *) &sockin;
1170 #ifdef SUPPORT_IP6
1171             } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
1172                 /* AAAA records (IPv6) */
1173                 if ((unsigned int) h->h_length > sizeof(ia6)) {
1174                     __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
1175                     return INVALID_SOCKET;
1176                 }
1177                 memcpy (&ia6, h->h_addr_list[i], h->h_length);
1178                 sockin6.sin6_family = h->h_addrtype;
1179                 sockin6.sin6_addr = ia6;
1180                 sockin6.sin6_port = htons (port);
1181                 addr = (struct sockaddr *) &sockin6;
1182 #endif
1183             } else
1184                 break;              /* for */
1185
1186             s = xmlNanoHTTPConnectAttempt (addr);
1187             if (s != INVALID_SOCKET)
1188                 return (s);
1189         }
1190     }
1191 #endif
1192
1193 #ifdef DEBUG_HTTP
1194     xmlGenericError(xmlGenericErrorContext,
1195                     "xmlNanoHTTPConnectHost:  unable to connect to '%s'.\n",
1196                     host);
1197 #endif
1198     return INVALID_SOCKET;
1199 }
1200
1201
1202 /**
1203  * xmlNanoHTTPOpen:
1204  * @URL:  The URL to load
1205  * @contentType:  if available the Content-Type information will be
1206  *                returned at that location
1207  *
1208  * This function try to open a connection to the indicated resource
1209  * via HTTP GET.
1210  *
1211  * Returns NULL in case of failure, otherwise a request handler.
1212  *     The contentType, if provided must be freed by the caller
1213  */
1214
1215 void*
1216 xmlNanoHTTPOpen(const char *URL, char **contentType) {
1217     if (contentType != NULL) *contentType = NULL;
1218     return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
1219 }
1220
1221 /**
1222  * xmlNanoHTTPOpenRedir:
1223  * @URL:  The URL to load
1224  * @contentType:  if available the Content-Type information will be
1225  *                returned at that location
1226  * @redir: if available the redirected URL will be returned
1227  *
1228  * This function try to open a connection to the indicated resource
1229  * via HTTP GET.
1230  *
1231  * Returns NULL in case of failure, otherwise a request handler.
1232  *     The contentType, if provided must be freed by the caller
1233  */
1234
1235 void*
1236 xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
1237     if (contentType != NULL) *contentType = NULL;
1238     if (redir != NULL) *redir = NULL;
1239     return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
1240 }
1241
1242 /**
1243  * xmlNanoHTTPRead:
1244  * @ctx:  the HTTP context
1245  * @dest:  a buffer
1246  * @len:  the buffer length
1247  *
1248  * This function tries to read @len bytes from the existing HTTP connection
1249  * and saves them in @dest. This is a blocking call.
1250  *
1251  * Returns the number of byte read. 0 is an indication of an end of connection.
1252  *         -1 indicates a parameter error.
1253  */
1254 int
1255 xmlNanoHTTPRead(void *ctx, void *dest, int len) {
1256     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1257 #ifdef HAVE_ZLIB_H
1258     int bytes_read = 0;
1259     int orig_avail_in;
1260     int z_ret;
1261 #endif
1262
1263     if (ctx == NULL) return(-1);
1264     if (dest == NULL) return(-1);
1265     if (len <= 0) return(0);
1266
1267 #ifdef HAVE_ZLIB_H
1268     if (ctxt->usesGzip == 1) {
1269         if (ctxt->strm == NULL) return(0);
1270  
1271         ctxt->strm->next_out = dest;
1272         ctxt->strm->avail_out = len;
1273         ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
1274
1275         while (ctxt->strm->avail_out > 0 &&
1276                (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
1277             orig_avail_in = ctxt->strm->avail_in =
1278                             ctxt->inptr - ctxt->inrptr - bytes_read;
1279             ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
1280
1281             z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
1282             bytes_read += orig_avail_in - ctxt->strm->avail_in;
1283
1284             if (z_ret != Z_OK) break;
1285         }
1286
1287         ctxt->inrptr += bytes_read;
1288         return(len - ctxt->strm->avail_out);
1289     }
1290 #endif
1291
1292     while (ctxt->inptr - ctxt->inrptr < len) {
1293         if (xmlNanoHTTPRecv(ctxt) <= 0) break;
1294     }
1295     if (ctxt->inptr - ctxt->inrptr < len)
1296         len = ctxt->inptr - ctxt->inrptr;
1297     memcpy(dest, ctxt->inrptr, len);
1298     ctxt->inrptr += len;
1299     return(len);
1300 }
1301
1302 /**
1303  * xmlNanoHTTPClose:
1304  * @ctx:  the HTTP context
1305  *
1306  * This function closes an HTTP context, it ends up the connection and
1307  * free all data related to it.
1308  */
1309 void
1310 xmlNanoHTTPClose(void *ctx) {
1311     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1312
1313     if (ctx == NULL) return;
1314
1315     xmlNanoHTTPFreeCtxt(ctxt);
1316 }
1317
1318 /**
1319  * xmlNanoHTTPMethodRedir:
1320  * @URL:  The URL to load
1321  * @method:  the HTTP method to use
1322  * @input:  the input string if any
1323  * @contentType:  the Content-Type information IN and OUT
1324  * @redir:  the redirected URL OUT
1325  * @headers:  the extra headers
1326  * @ilen:  input length
1327  *
1328  * This function try to open a connection to the indicated resource
1329  * via HTTP using the given @method, adding the given extra headers
1330  * and the input buffer for the request content.
1331  *
1332  * Returns NULL in case of failure, otherwise a request handler.
1333  *     The contentType, or redir, if provided must be freed by the caller
1334  */
1335
1336 void*
1337 xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
1338                   char **contentType, char **redir,
1339                   const char *headers, int ilen ) {
1340     xmlNanoHTTPCtxtPtr ctxt;
1341     char *bp, *p;
1342     int blen;
1343     SOCKET ret;
1344     int nbRedirects = 0;
1345     char *redirURL = NULL;
1346 #ifdef DEBUG_HTTP
1347     int xmt_bytes;
1348 #endif
1349     
1350     if (URL == NULL) return(NULL);
1351     if (method == NULL) method = "GET";
1352     xmlNanoHTTPInit();
1353
1354 retry:
1355     if (redirURL == NULL)
1356         ctxt = xmlNanoHTTPNewCtxt(URL);
1357     else {
1358         ctxt = xmlNanoHTTPNewCtxt(redirURL);
1359         ctxt->location = xmlMemStrdup(redirURL);
1360     }
1361
1362     if ( ctxt == NULL ) {
1363         return ( NULL );
1364     }
1365
1366     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
1367         __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
1368         xmlNanoHTTPFreeCtxt(ctxt);
1369         if (redirURL != NULL) xmlFree(redirURL);
1370         return(NULL);
1371     }
1372     if (ctxt->hostname == NULL) {
1373         __xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
1374                    "Failed to identify host in URI");
1375         xmlNanoHTTPFreeCtxt(ctxt);
1376         if (redirURL != NULL) xmlFree(redirURL);
1377         return(NULL);
1378     }
1379     if (proxy) {
1380         blen = strlen(ctxt->hostname) * 2 + 16;
1381         ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
1382     }
1383     else {
1384         blen = strlen(ctxt->hostname);
1385         ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1386     }
1387     if (ret == INVALID_SOCKET) {
1388         xmlNanoHTTPFreeCtxt(ctxt);
1389         if (redirURL != NULL) xmlFree(redirURL);
1390         return(NULL);
1391     }
1392     ctxt->fd = ret;
1393
1394     if (input == NULL)
1395         ilen = 0;
1396     else
1397         blen += 36;
1398
1399     if (headers != NULL)
1400         blen += strlen(headers) + 2;
1401     if (contentType && *contentType)
1402         /* reserve for string plus 'Content-Type: \r\n" */
1403         blen += strlen(*contentType) + 16;
1404     if (ctxt->query != NULL)
1405         /* 1 for '?' */
1406         blen += strlen(ctxt->query) + 1;
1407     blen += strlen(method) + strlen(ctxt->path) + 24;
1408 #ifdef HAVE_ZLIB_H
1409     /* reserve for possible 'Accept-Encoding: gzip' string */
1410     blen += 23;
1411 #endif
1412     if (ctxt->port != 80) {
1413         /* reserve space for ':xxxxx', incl. potential proxy */
1414         if (proxy)
1415             blen += 12;
1416         else
1417             blen += 6;
1418     }
1419     bp = (char*)xmlMallocAtomic(blen);
1420     if ( bp == NULL ) {
1421         xmlNanoHTTPFreeCtxt( ctxt );
1422         xmlHTTPErrMemory("allocating header buffer");
1423         return ( NULL );
1424     }
1425
1426     p = bp;
1427
1428     if (proxy) {
1429         if (ctxt->port != 80) {
1430             p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 
1431                         method, ctxt->hostname,
1432                         ctxt->port, ctxt->path );
1433         }
1434         else 
1435             p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
1436                         ctxt->hostname, ctxt->path);
1437     }
1438     else
1439         p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
1440
1441     if (ctxt->query != NULL)
1442         p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
1443
1444     if (ctxt->port == 80) {
1445         p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n", 
1446                     ctxt->hostname);
1447     } else {
1448         p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
1449                     ctxt->hostname, ctxt->port);
1450     }
1451
1452 #ifdef HAVE_ZLIB_H
1453     p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
1454 #endif
1455
1456     if (contentType != NULL && *contentType) 
1457         p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
1458
1459     if (headers != NULL)
1460         p += snprintf( p, blen - (p - bp), "%s", headers );
1461
1462     if (input != NULL)
1463         snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
1464     else
1465         snprintf(p, blen - (p - bp), "\r\n");
1466
1467 #ifdef DEBUG_HTTP
1468     xmlGenericError(xmlGenericErrorContext,
1469             "-> %s%s", proxy? "(Proxy) " : "", bp);
1470     if ((blen -= strlen(bp)+1) < 0)
1471         xmlGenericError(xmlGenericErrorContext,
1472                 "ERROR: overflowed buffer by %d bytes\n", -blen);
1473 #endif
1474     ctxt->outptr = ctxt->out = bp;
1475     ctxt->state = XML_NANO_HTTP_WRITE;
1476     blen = strlen( ctxt->out );
1477 #ifdef DEBUG_HTTP
1478     xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
1479     if ( xmt_bytes != blen )
1480         xmlGenericError( xmlGenericErrorContext,
1481                         "xmlNanoHTTPMethodRedir:  Only %d of %d %s %s\n",
1482                         xmt_bytes, blen,
1483                         "bytes of HTTP headers sent to host",
1484                         ctxt->hostname );
1485 #else
1486     xmlNanoHTTPSend(ctxt, ctxt->out, blen );
1487 #endif
1488
1489     if ( input != NULL ) {
1490 #ifdef DEBUG_HTTP
1491         xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
1492
1493         if ( xmt_bytes != ilen )
1494             xmlGenericError( xmlGenericErrorContext,
1495                         "xmlNanoHTTPMethodRedir:  Only %d of %d %s %s\n",
1496                         xmt_bytes, ilen,
1497                         "bytes of HTTP content sent to host",
1498                         ctxt->hostname );
1499 #else
1500         xmlNanoHTTPSend( ctxt, input, ilen );
1501 #endif
1502     }
1503
1504     ctxt->state = XML_NANO_HTTP_READ;
1505
1506     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
1507         if (*p == 0) {
1508             ctxt->content = ctxt->inrptr;
1509             xmlFree(p);
1510             break;
1511         }
1512         xmlNanoHTTPScanAnswer(ctxt, p);
1513
1514 #ifdef DEBUG_HTTP
1515         xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
1516 #endif
1517         xmlFree(p);
1518     }
1519
1520     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1521         (ctxt->returnValue < 400)) {
1522 #ifdef DEBUG_HTTP
1523         xmlGenericError(xmlGenericErrorContext,
1524                 "\nRedirect to: %s\n", ctxt->location);
1525 #endif
1526         while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
1527         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1528             nbRedirects++;
1529             if (redirURL != NULL)
1530                 xmlFree(redirURL);
1531             redirURL = xmlMemStrdup(ctxt->location);
1532             xmlNanoHTTPFreeCtxt(ctxt);
1533             goto retry;
1534         }
1535         xmlNanoHTTPFreeCtxt(ctxt);
1536         if (redirURL != NULL) xmlFree(redirURL);
1537 #ifdef DEBUG_HTTP
1538         xmlGenericError(xmlGenericErrorContext,
1539                 "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
1540 #endif
1541         return(NULL);
1542     }
1543
1544     if (contentType != NULL) {
1545         if (ctxt->contentType != NULL)
1546             *contentType = xmlMemStrdup(ctxt->contentType);
1547         else
1548             *contentType = NULL;
1549     }
1550
1551     if ((redir != NULL) && (redirURL != NULL)) {
1552         *redir = redirURL;
1553     } else {
1554         if (redirURL != NULL)
1555             xmlFree(redirURL);
1556         if (redir != NULL)
1557             *redir = NULL;
1558     }
1559
1560 #ifdef DEBUG_HTTP
1561     if (ctxt->contentType != NULL)
1562         xmlGenericError(xmlGenericErrorContext,
1563                 "\nCode %d, content-type '%s'\n\n",
1564                ctxt->returnValue, ctxt->contentType);
1565     else
1566         xmlGenericError(xmlGenericErrorContext,
1567                 "\nCode %d, no content-type\n\n",
1568                ctxt->returnValue);
1569 #endif
1570
1571     return((void *) ctxt);
1572 }
1573
1574 /**
1575  * xmlNanoHTTPMethod:
1576  * @URL:  The URL to load
1577  * @method:  the HTTP method to use
1578  * @input:  the input string if any
1579  * @contentType:  the Content-Type information IN and OUT
1580  * @headers:  the extra headers
1581  * @ilen:  input length
1582  *
1583  * This function try to open a connection to the indicated resource
1584  * via HTTP using the given @method, adding the given extra headers
1585  * and the input buffer for the request content.
1586  *
1587  * Returns NULL in case of failure, otherwise a request handler.
1588  *     The contentType, if provided must be freed by the caller
1589  */
1590
1591 void*
1592 xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
1593                   char **contentType, const char *headers, int ilen) {
1594     return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
1595                                   NULL, headers, ilen));
1596 }
1597
1598 /**
1599  * xmlNanoHTTPFetch:
1600  * @URL:  The URL to load
1601  * @filename:  the filename where the content should be saved
1602  * @contentType:  if available the Content-Type information will be
1603  *                returned at that location
1604  *
1605  * This function try to fetch the indicated resource via HTTP GET
1606  * and save it's content in the file.
1607  *
1608  * Returns -1 in case of failure, 0 incase of success. The contentType,
1609  *     if provided must be freed by the caller
1610  */
1611 int
1612 xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
1613     void *ctxt = NULL;
1614     char *buf = NULL;
1615     int fd;
1616     int len;
1617     int ret = 0;
1618
1619     if (filename == NULL) return(-1);
1620     ctxt = xmlNanoHTTPOpen(URL, contentType);
1621     if (ctxt == NULL) return(-1);
1622
1623     if (!strcmp(filename, "-")) 
1624         fd = 0;
1625     else {
1626         fd = open(filename, O_CREAT | O_WRONLY, 00644);
1627         if (fd < 0) {
1628             xmlNanoHTTPClose(ctxt);
1629             if ((contentType != NULL) && (*contentType != NULL)) {
1630                 xmlFree(*contentType);
1631                 *contentType = NULL;
1632             }
1633             return(-1);
1634         }
1635     }
1636
1637     xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1638     if ( len > 0 ) {
1639         if (write(fd, buf, len) == -1) {
1640             ret = -1;
1641         }
1642     }
1643
1644     xmlNanoHTTPClose(ctxt);
1645     close(fd);
1646     return(ret);
1647 }
1648
1649 #ifdef LIBXML_OUTPUT_ENABLED
1650 /**
1651  * xmlNanoHTTPSave:
1652  * @ctxt:  the HTTP context
1653  * @filename:  the filename where the content should be saved
1654  *
1655  * This function saves the output of the HTTP transaction to a file
1656  * It closes and free the context at the end
1657  *
1658  * Returns -1 in case of failure, 0 incase of success.
1659  */
1660 int
1661 xmlNanoHTTPSave(void *ctxt, const char *filename) {
1662     char *buf = NULL;
1663     int fd;
1664     int len;
1665     int ret = 0;
1666
1667     if ((ctxt == NULL) || (filename == NULL)) return(-1);
1668
1669     if (!strcmp(filename, "-")) 
1670         fd = 0;
1671     else {
1672         fd = open(filename, O_CREAT | O_WRONLY, 0666);
1673         if (fd < 0) {
1674             xmlNanoHTTPClose(ctxt);
1675             return(-1);
1676         }
1677     }
1678
1679     xmlNanoHTTPFetchContent( ctxt, &buf, &len );
1680     if ( len > 0 ) {
1681         if (write(fd, buf, len) == -1) {
1682             ret = -1;
1683         }
1684     }
1685
1686     xmlNanoHTTPClose(ctxt);
1687     close(fd);
1688     return(ret);
1689 }
1690 #endif /* LIBXML_OUTPUT_ENABLED */
1691
1692 /**
1693  * xmlNanoHTTPReturnCode:
1694  * @ctx:  the HTTP context
1695  *
1696  * Get the latest HTTP return code received
1697  *
1698  * Returns the HTTP return code for the request.
1699  */
1700 int
1701 xmlNanoHTTPReturnCode(void *ctx) {
1702     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1703
1704     if (ctxt == NULL) return(-1);
1705
1706     return(ctxt->returnValue);
1707 }
1708
1709 /**
1710  * xmlNanoHTTPAuthHeader:
1711  * @ctx:  the HTTP context
1712  *
1713  * Get the authentication header of an HTTP context
1714  *
1715  * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
1716  * header.
1717  */
1718 const char *
1719 xmlNanoHTTPAuthHeader(void *ctx) {
1720     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
1721
1722     if (ctxt == NULL) return(NULL);
1723
1724     return(ctxt->authHeader);
1725 }
1726
1727 /**
1728  * xmlNanoHTTPContentLength:
1729  * @ctx:  the HTTP context
1730  *
1731  * Provides the specified content length from the HTTP header.
1732  *
1733  * Return the specified content length from the HTTP header.  Note that
1734  * a value of -1 indicates that the content length element was not included in
1735  * the response header.
1736  */
1737 int
1738 xmlNanoHTTPContentLength( void * ctx ) {
1739     xmlNanoHTTPCtxtPtr  ctxt = (xmlNanoHTTPCtxtPtr)ctx;
1740
1741     return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
1742 }
1743
1744 /**
1745  * xmlNanoHTTPRedir:
1746  * @ctx:  the HTTP context
1747  *
1748  * Provides the specified redirection URL if available from the HTTP header.
1749  *
1750  * Return the specified redirection URL or NULL if not redirected.
1751  */
1752 const char *
1753 xmlNanoHTTPRedir( void * ctx ) {
1754     xmlNanoHTTPCtxtPtr  ctxt = (xmlNanoHTTPCtxtPtr)ctx;
1755
1756     return ( ( ctxt == NULL ) ? NULL : ctxt->location );
1757 }
1758
1759 /**
1760  * xmlNanoHTTPEncoding:
1761  * @ctx:  the HTTP context
1762  *
1763  * Provides the specified encoding if specified in the HTTP headers.
1764  *
1765  * Return the specified encoding or NULL if not available
1766  */
1767 const char *
1768 xmlNanoHTTPEncoding( void * ctx ) {
1769     xmlNanoHTTPCtxtPtr  ctxt = (xmlNanoHTTPCtxtPtr)ctx;
1770
1771     return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
1772 }
1773
1774 /**
1775  * xmlNanoHTTPMimeType:
1776  * @ctx:  the HTTP context
1777  *
1778  * Provides the specified Mime-Type if specified in the HTTP headers.
1779  *
1780  * Return the specified Mime-Type or NULL if not available
1781  */
1782 const char *
1783 xmlNanoHTTPMimeType( void * ctx ) {
1784     xmlNanoHTTPCtxtPtr  ctxt = (xmlNanoHTTPCtxtPtr)ctx;
1785
1786     return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
1787 }
1788
1789 /**
1790  * xmlNanoHTTPFetchContent:
1791  * @ctx:  the HTTP context
1792  * @ptr:  pointer to set to the content buffer.
1793  * @len:  integer pointer to hold the length of the content
1794  *
1795  * Check if all the content was read
1796  *
1797  * Returns 0 if all the content was read and available, returns
1798  * -1 if received content length was less than specified or an error 
1799  * occurred.
1800  */
1801 static int
1802 xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
1803     xmlNanoHTTPCtxtPtr  ctxt = (xmlNanoHTTPCtxtPtr)ctx;
1804
1805     int                 rc = 0;
1806     int                 cur_lgth;
1807     int                 rcvd_lgth;
1808     int                 dummy_int;
1809     char *              dummy_ptr = NULL;
1810
1811     /*  Dummy up return input parameters if not provided  */
1812
1813     if ( len == NULL )
1814         len = &dummy_int;
1815
1816     if ( ptr == NULL )
1817         ptr = &dummy_ptr;
1818
1819     /*  But can't work without the context pointer  */
1820
1821     if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
1822         *len = 0;
1823         *ptr = NULL;
1824         return ( -1 );
1825     }
1826
1827     rcvd_lgth = ctxt->inptr - ctxt->content;
1828
1829     while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
1830
1831         rcvd_lgth += cur_lgth;
1832         if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
1833             break;
1834     }
1835
1836     *ptr = ctxt->content;
1837     *len = rcvd_lgth;
1838
1839     if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
1840         rc = -1;
1841     else if ( rcvd_lgth == 0 )
1842         rc = -1;
1843
1844     return ( rc );
1845 }
1846
1847 #ifdef STANDALONE
1848 int main(int argc, char **argv) {
1849     char *contentType = NULL;
1850
1851     if (argv[1] != NULL) {
1852         if (argv[2] != NULL) 
1853             xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
1854         else
1855             xmlNanoHTTPFetch(argv[1], "-", &contentType);
1856         if (contentType != NULL) xmlFree(contentType);
1857     } else {
1858         xmlGenericError(xmlGenericErrorContext,
1859                 "%s: minimal HTTP GET implementation\n", argv[0]);
1860         xmlGenericError(xmlGenericErrorContext,
1861                 "\tusage %s [ URL [ filename ] ]\n", argv[0]);
1862     }
1863     xmlNanoHTTPCleanup();
1864     xmlMemoryDump();
1865     return(0);
1866 }
1867 #endif /* STANDALONE */
1868 #else /* !LIBXML_HTTP_ENABLED */
1869 #ifdef STANDALONE
1870 #include <stdio.h>
1871 int main(int argc, char **argv) {
1872     xmlGenericError(xmlGenericErrorContext,
1873             "%s : HTTP support not compiled in\n", argv[0]);
1874     return(0);
1875 }
1876 #endif /* STANDALONE */
1877 #endif /* LIBXML_HTTP_ENABLED */
1878 #define bottom_nanohttp
1879 #include "elfgcchack.h"