Coverage Report

Created: 2025-08-04 07:15

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