The R Project SVN R

Rev

Rev 61850 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 61850 Rev 62559
1
/*
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 2001-12   The R Core Team.
3
 *  Copyright (C) 2001-12   The R Core Team.
4
 *
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
8
 *  (at your option) any later version.
9
 *
9
 *
10
 *  This program is distributed in the hope that it will be useful,
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
13
 *  GNU General Public License for more details.
14
 *
14
 *
15
 *  You should have received a copy of the GNU General Public License
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, a copy is available at
16
 *  along with this program; if not, a copy is available at
17
 *  http://www.r-project.org/Licenses/
17
 *  http://www.r-project.org/Licenses/
18
 */
18
 */
19
 
19
 
20
/* <UTF8> the only interpretation of char is ASCII 
20
/* <UTF8> the only interpretation of char is ASCII 
21
   <MBCS> all the char quantities should be ASCII
21
   <MBCS> all the char quantities should be ASCII
22
 */
22
 */
23
 
23
 
24
 
24
 
25
/* based on libxml2-2.3.6:
25
/* based on libxml2-2.3.6:
26
 * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets.
26
 * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets.
27
 *             focuses on size, streamability, reentrancy and portability
27
 *             focuses on size, streamability, reentrancy and portability
28
 *
28
 *
29
 * This is clearly not a general purpose HTTP implementation
29
 * This is clearly not a general purpose HTTP implementation
30
 * If you look for one, check:
30
 * If you look for one, check:
31
 *         http://www.w3.org/Library/
31
 *         http://www.w3.org/Library/
32
 *
32
 *
33
 * See Copyright for the status of this software.
33
 * See Copyright for the status of this software.
34
 *
34
 *
35
 * daniel@veillard.com
35
 * daniel@veillard.com
36
 */
36
 */
37
 
37
 
38
 
38
 
39
#ifdef HAVE_CONFIG_H
39
#ifdef HAVE_CONFIG_H
40
#include <config.h>
40
#include <config.h>
41
#endif
41
#endif
42
 
42
 
43
#undef HAVE_ZLIB_H
43
#undef HAVE_ZLIB_H
44
 
44
 
45
#ifdef ENABLE_NLS
45
#ifdef ENABLE_NLS
46
#include <libintl.h>
46
#include <libintl.h>
47
#ifdef Win32
47
#ifdef Win32
48
#define _(String) libintl_gettext (String)
48
#define _(String) libintl_gettext (String)
49
#undef gettext /* needed for graphapp */
49
#undef gettext /* needed for graphapp */
50
#else
50
#else
51
#define _(String) gettext (String)
51
#define _(String) gettext (String)
52
#endif
52
#endif
53
#else /* not NLS */
53
#else /* not NLS */
54
#define _(String) (String)
54
#define _(String) (String)
55
#endif
55
#endif
56
 
56
 
57
extern void R_ProcessEvents(void);
57
extern void R_ProcessEvents(void);
58
#if !defined(Unix) || defined(HAVE_BSD_NETWORKING)
58
#if !defined(Unix) || defined(HAVE_BSD_NETWORKING)
59
 
59
 
60
#ifdef Win32
60
#ifdef Win32
61
#include <io.h>
61
#include <io.h>
62
#include <winsock2.h>
62
#include <winsock2.h>
63
#ifndef EWOULDBLOCK
63
#ifndef EWOULDBLOCK
64
# define EWOULDBLOCK             WSAEWOULDBLOCK
64
# define EWOULDBLOCK             WSAEWOULDBLOCK
65
#endif
65
#endif
66
#ifndef EINPROGRESS
66
#ifndef EINPROGRESS
67
# define EINPROGRESS             WSAEINPROGRESS
67
# define EINPROGRESS             WSAEINPROGRESS
68
#endif
68
#endif
69
#ifndef EALREADY
69
#ifndef EALREADY
70
# define EALREADY                WSAEALREADY
70
# define EALREADY                WSAEALREADY
71
#endif
71
#endif
72
#define _WINSOCKAPI_
72
#define _WINSOCKAPI_
73
extern void R_FlushConsole(void);
73
extern void R_FlushConsole(void);
74
#define R_SelectEx(n,rfd,wrd,efd,tv,ih) select(n,rfd,wrd,efd,tv)
74
#define R_SelectEx(n,rfd,wrd,efd,tv,ih) select(n,rfd,wrd,efd,tv)
75
#endif
75
#endif
76
 
76
 
77
#include <R_ext/R-ftp-http.h>
77
#include <R_ext/R-ftp-http.h>
78
#ifdef Win32
78
#ifdef Win32
79
# include <R_ext/Print.h>
79
# include <R_ext/Print.h>
80
#endif
80
#endif
81
 
81
 
82
#ifdef HAVE_STRINGS_H
82
#ifdef HAVE_STRINGS_H
83
   /* may be needed to define bzero in FD_ZERO (eg AIX) */
83
   /* may be needed to define bzero in FD_ZERO (eg AIX) */
84
  #include <strings.h>
84
  #include <strings.h>
85
#endif
85
#endif
86
 
86
 
87
#include <stdio.h>
87
#include <stdio.h>
88
#include <string.h>
88
#include <string.h>
89
#include <stdlib.h>
89
#include <stdlib.h>
90
 
90
 
91
#ifdef HAVE_UNISTD_H
91
#ifdef HAVE_UNISTD_H
92
#include <unistd.h>
92
#include <unistd.h>
93
#endif
93
#endif
94
 
94
 
95
#ifdef HAVE_BSD_NETWORKING
95
#ifdef HAVE_BSD_NETWORKING
96
#  include <netdb.h>
96
#  include <netdb.h>
97
#  include <sys/socket.h>
97
#  include <sys/socket.h>
98
#  include <netinet/in.h>
98
#  include <netinet/in.h>
99
#endif
99
#endif
100
 
100
 
101
#ifdef HAVE_FCNTL_H
101
#ifdef HAVE_FCNTL_H
102
#include <fcntl.h>
102
#include <fcntl.h>
103
#endif
103
#endif
104
#ifdef HAVE_ERRNO_H
104
#ifdef HAVE_ERRNO_H
105
#include <errno.h>
105
#include <errno.h>
106
#endif
106
#endif
107
#ifdef HAVE_SYS_TIME_H
107
#ifdef HAVE_SYS_TIME_H
108
#include <sys/time.h>
108
#include <sys/time.h>
109
#endif
109
#endif
110
#ifdef HAVE_SYS_SELECT_H
110
#ifdef HAVE_SYS_SELECT_H
111
#include <sys/select.h>
111
#include <sys/select.h>
112
#endif
112
#endif
113
#ifdef SUPPORT_IP6
113
#ifdef SUPPORT_IP6
114
#include <resolv.h>
114
#include <resolv.h>
115
#endif
115
#endif
116
#ifdef HAVE_ZLIB_H
116
#ifdef HAVE_ZLIB_H
117
#include <zlib.h>
117
#include <zlib.h>
118
#endif
118
#endif
119
 
119
 
120
/* #define DEBUG_HTTP */
120
/* #define DEBUG_HTTP */
121
 
121
 
122
#define BAD_CAST (unsigned char *)
122
#define BAD_CAST (unsigned char *)
123
 
123
 
124
#if !defined(strdup) && defined(HAVE_DECL_STRDUP) && !HAVE_DECL_STRDUP
124
#if !defined(strdup) && defined(HAVE_DECL_STRDUP) && !HAVE_DECL_STRDUP
125
extern char *strdup(const char *s1);
125
extern char *strdup(const char *s1);
126
#endif
126
#endif
127
 
127
 
128
#define xmlFree free
128
#define xmlFree free
129
#define xmlMalloc malloc
129
#define xmlMalloc malloc
130
#define xmlRealloc realloc
130
#define xmlRealloc realloc
131
#define xmlMemStrdup strdup
131
#define xmlMemStrdup strdup
132
#define xmlStrndup(a, b) strdup(a)
132
#define xmlStrndup(a, b) strdup(a)
133
#define xmlStrstr(a, b) strstr((const char *)a, (const char *)b) 
133
#define xmlStrstr(a, b) strstr((const char *)a, (const char *)b) 
134
#define xmlStrdup(a) strdup((char *)a)
134
#define xmlStrdup(a) strdup((char *)a)
135
 
135
 
136
static void RxmlNanoHTTPScanProxy(const char *URL);
136
static void RxmlNanoHTTPScanProxy(const char *URL);
137
static void *RxmlNanoHTTPMethod(const char *URL, const char *method,
137
static void *RxmlNanoHTTPMethod(const char *URL, const char *method,
138
				const char *input, char **contentType,
138
				const char *input, char **contentType,
139
				const char *headers, const int cacheOK);
139
				const char *headers, const int cacheOK);
140
 
140
 
141
#ifdef Unix
141
#ifdef Unix
142
#include <R_ext/eventloop.h>
142
#include <R_ext/eventloop.h>
143
 
143
 
144
/* modified from src/unix/sys-std.c  */
144
/* modified from src/unix/sys-std.c  */
145
static int
145
static int
146
setSelectMask(InputHandler *handlers, fd_set *readMask)
146
setSelectMask(InputHandler *handlers, fd_set *readMask)
147
{
147
{
148
    int maxfd = -1;
148
    int maxfd = -1;
149
    InputHandler *tmp = handlers;
149
    InputHandler *tmp = handlers;
150
    FD_ZERO(readMask);
150
    FD_ZERO(readMask);
151
 
151
 
152
    while(tmp) {
152
    while(tmp) {
153
	if(tmp->fileDescriptor > 0) {
153
	if(tmp->fileDescriptor > 0) {
154
	    FD_SET(tmp->fileDescriptor, readMask);
154
	    FD_SET(tmp->fileDescriptor, readMask);
155
	    maxfd = maxfd < tmp->fileDescriptor ? tmp->fileDescriptor : maxfd;
155
	    maxfd = maxfd < tmp->fileDescriptor ? tmp->fileDescriptor : maxfd;
156
	}
156
	}
157
	tmp = tmp->next;
157
	tmp = tmp->next;
158
    }
158
    }
159
 
159
 
160
    return(maxfd);
160
    return(maxfd);
161
}
161
}
162
#endif
162
#endif
163
 
163
 
164
/**
164
/**
165
 * A couple of portability macros
165
 * A couple of portability macros
166
 */
166
 */
167
#ifndef _WINSOCKAPI_
167
#ifndef _WINSOCKAPI_
168
#define closesocket(s) close(s)
168
#define closesocket(s) close(s)
169
#define SOCKET int
169
#define SOCKET int
170
#endif
170
#endif
171
 
171
 
172
/* where strncasecmp is defined seems system-specific,
172
/* where strncasecmp is defined seems system-specific,
173
   and on Windows the cross-compiler doesn't find strings.h */
173
   and on Windows the cross-compiler doesn't find strings.h */
174
#if defined(HAVE_STRINGS_H) && !defined(Win32)
174
#if defined(HAVE_STRINGS_H) && !defined(Win32)
175
# include <strings.h>
175
# include <strings.h>
176
#endif
176
#endif
177
#if !defined(strncasecmp) && defined(HAVE_DECL_STRNCASECMP) && !HAVE_DECL_STRNCASECMP
177
#if !defined(strncasecmp) && defined(HAVE_DECL_STRNCASECMP) && !HAVE_DECL_STRNCASECMP
178
extern int strncasecmp(const char *s1, const char *s2, size_t n);
178
extern int strncasecmp(const char *s1, const char *s2, size_t n);
179
#endif
179
#endif
180
#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
180
#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
181
 
181
 
182
#define XML_NANO_HTTP_MAX_REDIR	10
182
#define XML_NANO_HTTP_MAX_REDIR	10
183
 
183
 
184
#define XML_NANO_HTTP_CHUNK	4096
184
#define XML_NANO_HTTP_CHUNK	4096
185
 
185
 
186
#define XML_NANO_HTTP_CLOSED	0
186
#define XML_NANO_HTTP_CLOSED	0
187
#define XML_NANO_HTTP_WRITE	1
187
#define XML_NANO_HTTP_WRITE	1
188
#define XML_NANO_HTTP_READ	2
188
#define XML_NANO_HTTP_READ	2
189
#define XML_NANO_HTTP_NONE	4
189
#define XML_NANO_HTTP_NONE	4
190
 
190
 
191
typedef struct RxmlNanoHTTPCtxt {
191
typedef struct RxmlNanoHTTPCtxt {
192
    char *protocol;	/* the protocol name */
192
    char *protocol;	/* the protocol name */
193
    char *hostname;	/* the host name */
193
    char *hostname;	/* the host name */
194
    int port;		/* the port */
194
    int port;		/* the port */
195
    char *path;		/* the path within the URL */
195
    char *path;		/* the path within the URL */
196
    char *query;	/* the query string */
196
    char *query;	/* the query string */
197
    SOCKET fd;		/* the file descriptor for the socket */
197
    SOCKET fd;		/* the file descriptor for the socket */
198
    int state;		/* WRITE / READ / CLOSED */
198
    int state;		/* WRITE / READ / CLOSED */
199
    char *out;		/* buffer sent (zero terminated) */
199
    char *out;		/* buffer sent (zero terminated) */
200
    char *outptr;	/* index within the buffer sent */
200
    char *outptr;	/* index within the buffer sent */
201
    char *in;		/* the receiving buffer */
201
    char *in;		/* the receiving buffer */
202
    char *content;	/* the start of the content */
202
    char *content;	/* the start of the content */
203
    char *inptr;	/* the next byte to read from network */
203
    char *inptr;	/* the next byte to read from network */
204
    char *inrptr;	/* the next byte to give back to the client */
204
    char *inrptr;	/* the next byte to give back to the client */
205
    int inlen;		/* len of the input buffer */
205
    int inlen;		/* len of the input buffer */
206
    int last;		/* return code for last operation */
206
    int last;		/* return code for last operation */
207
    int returnValue;	/* the protocol return value */
207
    int returnValue;	/* the protocol return value */
208
    char *statusMsg;    /* the protocol status message */
208
    char *statusMsg;    /* the protocol status message */
209
    char *contentType;	/* the MIME type for the input */
209
    char *contentType;	/* the MIME type for the input */
210
    int contentLength;	/* the reported length */
210
    int contentLength;	/* the reported length */
211
    char *location;	/* the new URL in case of redirect */
211
    char *location;	/* the new URL in case of redirect */
212
    char *authHeader;	/* contents of {WWW,Proxy}-Authenticate header */
212
    char *authHeader;	/* contents of {WWW,Proxy}-Authenticate header */
213
    char *encoding;	/* encoding extracted from the contentType */
213
    char *encoding;	/* encoding extracted from the contentType */
214
    char *mimeType;	/* Mime-Type extracted from the contentType */
214
    char *mimeType;	/* Mime-Type extracted from the contentType */
215
#ifdef HAVE_ZLIB_H
215
#ifdef HAVE_ZLIB_H
216
    z_stream *strm;	/* Zlib stream object */
216
    z_stream *strm;	/* Zlib stream object */
217
    int usesGzip;	/* "Content-Encoding: gzip" was detected */
217
    int usesGzip;	/* "Content-Encoding: gzip" was detected */
218
#endif
218
#endif
219
} RxmlNanoHTTPCtxt, *RxmlNanoHTTPCtxtPtr;
219
} RxmlNanoHTTPCtxt, *RxmlNanoHTTPCtxtPtr;
220
 
220
 
221
static int initialized = 0;
221
static int initialized = 0;
222
static char *proxy = NULL;	 /* the proxy name if any */
222
static char *proxy = NULL;	 /* the proxy name if any */
223
static int proxyPort;	/* the proxy port if any */
223
static int proxyPort;	/* the proxy port if any */
224
static char *proxyUser; /* the proxy user:pwd if any */
224
static char *proxyUser; /* the proxy user:pwd if any */
225
static unsigned int timeout = 60;/* the select() timeout in seconds */
225
static unsigned int timeout = 60;/* the select() timeout in seconds */
226
 
226
 
227
/**
227
/**
228
 * A portability function
228
 * A portability function
229
 */
229
 */
230
static int socket_errno(void)
230
static int socket_errno(void)
231
{
231
{
232
#ifdef _WINSOCKAPI_
232
#ifdef _WINSOCKAPI_
233
    return(WSAGetLastError());
233
    return(WSAGetLastError());
234
#else
234
#else
235
    return(errno);
235
    return(errno);
236
#endif
236
#endif
237
}
237
}
238
 
238
 
239
/**
239
/**
240
 * RxmlNanoHTTPInit:
240
 * RxmlNanoHTTPInit:
241
 *
241
 *
242
 * Initialize the HTTP protocol layer.
242
 * Initialize the HTTP protocol layer.
243
 * Currently it just checks for proxy informations
243
 * Currently it just checks for proxy informations
244
 */
244
 */
245
 
245
 
246
#ifdef Win32
246
#ifdef Win32
247
# include "graphapp.h"
247
# include "graphapp.h"
248
#endif
248
#endif
249
 
249
 
250
static void
250
static void
251
RxmlNanoHTTPInit(void)
251
RxmlNanoHTTPInit(void)
252
{
252
{
253
    const char *env;
253
    const char *env;
254
#ifdef _WINSOCKAPI_
254
#ifdef _WINSOCKAPI_
255
    WSADATA wsaData;
255
    WSADATA wsaData;
256
#endif
256
#endif
257
 
257
 
258
    if (initialized)
258
    if (initialized)
259
	return;
259
	return;
260
 
260
 
261
#ifdef _WINSOCKAPI_
261
#ifdef _WINSOCKAPI_
262
    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
262
    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
263
	return;
263
	return;
264
#endif
264
#endif
265
 
265
 
266
    if (proxy == NULL) {
266
    if (proxy == NULL) {
267
	proxyPort = 80;
267
	proxyPort = 80;
268
	env = getenv("no_proxy");
268
	env = getenv("no_proxy");
269
	if (env && ((env[0] == '*') && (env[1] == 0)))
269
	if (env && ((env[0] == '*') && (env[1] == 0)))
270
	    goto done;
270
	    goto done;
271
	env = getenv("http_proxy");
271
	env = getenv("http_proxy");
272
	if (env != NULL) {
272
	if (env != NULL) {
273
	    RxmlNanoHTTPScanProxy(env);
273
	    RxmlNanoHTTPScanProxy(env);
274
	    goto chkuser;
274
	    goto chkuser;
275
	}
275
	}
276
	env = getenv("HTTP_PROXY");
276
	env = getenv("HTTP_PROXY");
277
	if (env != NULL) {
277
	if (env != NULL) {
278
	    RxmlNanoHTTPScanProxy(env);
278
	    RxmlNanoHTTPScanProxy(env);
279
	    goto chkuser;
279
	    goto chkuser;
280
	}
280
	}
281
    chkuser:
281
    chkuser:
282
	if((env = getenv("http_proxy_user")) != NULL) {   
282
	if((env = getenv("http_proxy_user")) != NULL) {   
283
	    if (proxyUser != NULL) {xmlFree(proxyUser); proxyUser = NULL;}
283
	    if (proxyUser != NULL) {xmlFree(proxyUser); proxyUser = NULL;}
284
#ifdef Win32
284
#ifdef Win32
285
	    if (strcmp(env, "ask") == 0) 
285
	    if (strcmp(env, "ask") == 0) 
286
		env = askUserPass("Proxy Authentication");
286
		env = askUserPass("Proxy Authentication");
287
#endif
287
#endif
288
	    proxyUser = xmlMemStrdup(env);
288
	    proxyUser = xmlMemStrdup(env);
289
	}
289
	}
290
    }
290
    }
291
 done:
291
 done:
292
    initialized = 1;
292
    initialized = 1;
293
}
293
}
294
 
294
 
295
/**
295
/**
296
 * RxmlNanoHTTPClenup:
296
 * RxmlNanoHTTPClenup:
297
 *
297
 *
298
 * Cleanup the HTTP protocol layer.
298
 * Cleanup the HTTP protocol layer.
299
 */
299
 */
300
 
300
 
301
void
301
void
302
RxmlNanoHTTPCleanup(void)
302
RxmlNanoHTTPCleanup(void)
303
{
303
{
304
    if (proxy != NULL) xmlFree(proxy);
304
    if (proxy != NULL) xmlFree(proxy);
305
    if (proxyUser != NULL) xmlFree(proxyUser);
305
    if (proxyUser != NULL) xmlFree(proxyUser);
306
#ifdef _WINSOCKAPI_
306
#ifdef _WINSOCKAPI_
307
    if (initialized)
307
    if (initialized)
308
	WSACleanup();
308
	WSACleanup();
309
#endif
309
#endif
310
    initialized = 0;
310
    initialized = 0;
311
    return;
311
    return;
312
}
312
}
313
 
313
 
314
/**
314
/**
315
 * RxmlNanoHTTPTimeout:
315
 * RxmlNanoHTTPTimeout:
316
 * @delay:  the delay in seconds
316
 * @delay:  the delay in seconds
317
 *
317
 *
318
 * Set the HTTP timeout, (default is 60secs).  0 means immediate
318
 * Set the HTTP timeout, (default is 60secs).  0 means immediate
319
 * return, while -1 infinite.
319
 * return, while -1 infinite.
320
 */
320
 */
321
 
321
 
322
void
322
void
323
RxmlNanoHTTPTimeout(int delay)
323
RxmlNanoHTTPTimeout(int delay)
324
{
324
{
325
    timeout = (unsigned int) delay;
325
    timeout = (unsigned int) delay;
326
}
326
}
327
 
327
 
328
/**
328
/**
329
 * RxmlNanoHTTPScanURL:
329
 * RxmlNanoHTTPScanURL:
330
 * @ctxt:  an HTTP context
330
 * @ctxt:  an HTTP context
331
 * @URL:  The URL used to initialize the context
331
 * @URL:  The URL used to initialize the context
332
 *
332
 *
333
 * (Re)Initialize an HTTP context by parsing the URL and finding
333
 * (Re)Initialize an HTTP context by parsing the URL and finding
334
 * the protocol host port and path it indicates.
334
 * the protocol host port and path it indicates.
335
 */
335
 */
336
 
336
 
337
/* GET URLs can be very long, so use more generous limit here */
337
/* GET URLs can be very long, so use more generous limit here */
338
 
338
 
339
static void
339
static void
340
RxmlNanoHTTPScanURL(RxmlNanoHTTPCtxtPtr ctxt, const char *URL)
340
RxmlNanoHTTPScanURL(RxmlNanoHTTPCtxtPtr ctxt, const char *URL)
341
{
341
{
342
    const char *cur = URL;
342
    const char *cur = URL;
343
    char buf[40960];
343
    char buf[40960];
344
    int indx = 0;
344
    int indx = 0;
345
    int port = 0;
345
    int port = 0;
346
 
346
 
347
    if (ctxt->protocol != NULL) {
347
    if (ctxt->protocol != NULL) {
348
        xmlFree(ctxt->protocol);
348
        xmlFree(ctxt->protocol);
349
	ctxt->protocol = NULL;
349
	ctxt->protocol = NULL;
350
    }
350
    }
351
    if (ctxt->hostname != NULL) {
351
    if (ctxt->hostname != NULL) {
352
        xmlFree(ctxt->hostname);
352
        xmlFree(ctxt->hostname);
353
	ctxt->hostname = NULL;
353
	ctxt->hostname = NULL;
354
    }
354
    }
355
    if (ctxt->path != NULL) {
355
    if (ctxt->path != NULL) {
356
        xmlFree(ctxt->path);
356
        xmlFree(ctxt->path);
357
	ctxt->path = NULL;
357
	ctxt->path = NULL;
358
    }
358
    }
359
    if (URL == NULL) return;
359
    if (URL == NULL) return;
360
    buf[indx] = 0;
360
    buf[indx] = 0;
361
    while (*cur != 0) {
361
    while (*cur != 0) {
362
        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
362
        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
363
	    buf[indx] = 0;
363
	    buf[indx] = 0;
364
	    ctxt->protocol = xmlMemStrdup(buf);
364
	    ctxt->protocol = xmlMemStrdup(buf);
365
	    indx = 0;
365
	    indx = 0;
366
            cur += 3;
366
            cur += 3;
367
	    break;
367
	    break;
368
	}
368
	}
369
	if(indx >= 40959)
369
	if(indx >= 40959)
370
	    RxmlMessage(2, _("RxmlNanoHTTPScanURL: overlong (invalid?) URL"));	buf[indx++] = *cur++;
370
	    RxmlMessage(2, _("RxmlNanoHTTPScanURL: overlong (invalid?) URL"));	buf[indx++] = *cur++;
371
    }
371
    }
372
    if (*cur == 0) return;
372
    if (*cur == 0) return;
373
 
373
 
374
    buf[indx] = 0;
374
    buf[indx] = 0;
375
    while (1) {
375
    while (1) {
376
        if (cur[0] == ':') {
376
        if (cur[0] == ':') {
377
	    buf[indx] = 0;
377
	    buf[indx] = 0;
378
	    ctxt->hostname = xmlMemStrdup(buf);
378
	    ctxt->hostname = xmlMemStrdup(buf);
379
	    indx = 0;
379
	    indx = 0;
380
	    cur += 1;
380
	    cur += 1;
381
	    while ((*cur >= '0') && (*cur <= '9')) {
381
	    while ((*cur >= '0') && (*cur <= '9')) {
382
	        port *= 10;
382
	        port *= 10;
383
		port += *cur - '0';
383
		port += *cur - '0';
384
		cur++;
384
		cur++;
385
	    }
385
	    }
386
	    if (port != 0) ctxt->port = port;
386
	    if (port != 0) ctxt->port = port;
387
	    while ((cur[0] != '/') && (*cur != 0))
387
	    while ((cur[0] != '/') && (*cur != 0))
388
	        cur++;
388
	        cur++;
389
	    break;
389
	    break;
390
	}
390
	}
391
        if ((*cur == '/') || (*cur == 0)) {
391
        if ((*cur == '/') || (*cur == 0)) {
392
	    buf[indx] = 0;
392
	    buf[indx] = 0;
393
	    ctxt->hostname = xmlMemStrdup(buf);
393
	    ctxt->hostname = xmlMemStrdup(buf);
394
	    indx = 0;
394
	    indx = 0;
395
	    break;
395
	    break;
396
	}
396
	}
397
	if(indx >= 40959)
397
	if(indx >= 40959)
398
	    RxmlMessage(2, _("RxmlNanoHTTPScanURL: overlong (invalid?) URL"));	buf[indx++] = *cur++;
398
	    RxmlMessage(2, _("RxmlNanoHTTPScanURL: overlong (invalid?) URL"));	buf[indx++] = *cur++;
399
    }
399
    }
400
    if (*cur == 0)
400
    if (*cur == 0)
401
        ctxt->path = xmlMemStrdup("/");
401
        ctxt->path = xmlMemStrdup("/");
402
    else {
402
    else {
403
        indx = 0;
403
        indx = 0;
404
        buf[indx] = 0;
404
        buf[indx] = 0;
405
	while (*cur != 0) {   
405
	while (*cur != 0) {   
406
	    if(indx >= 40959)
406
	    if(indx >= 40959)
407
		RxmlMessage(2, _("RxmlNanoHTTPScanURL: overlong (invalid?) URL"));	   
407
		RxmlMessage(2, _("RxmlNanoHTTPScanURL: overlong (invalid?) URL"));	   
408
	    buf[indx++] = *cur++;
408
	    buf[indx++] = *cur++;
409
	}
409
	}
410
	buf[indx] = 0;
410
	buf[indx] = 0;
411
	ctxt->path = xmlMemStrdup(buf);
411
	ctxt->path = xmlMemStrdup(buf);
412
    }
412
    }
413
}
413
}
414
 
414
 
415
/**
415
/**
416
 * RxmlNanoHTTPScanProxy:
416
 * RxmlNanoHTTPScanProxy:
417
 * @URL:  The proxy URL used to initialize the proxy context
417
 * @URL:  The proxy URL used to initialize the proxy context
418
 *
418
 *
419
 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
419
 * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
420
 * the protocol host port it indicates.
420
 * the protocol host port it indicates.
421
 * Should be like http://myproxy/ or http://myproxy:3128/
421
 * Should be like http://myproxy/ or http://myproxy:3128/
422
 * A NULL URL cleans up proxy informations.
422
 * A NULL URL cleans up proxy informations.
423
 */
423
 */
424
 
424
 
425
void
425
void
426
RxmlNanoHTTPScanProxy(const char *URL)
426
RxmlNanoHTTPScanProxy(const char *URL)
427
{
427
{
428
    const char *cur = URL;
428
    const char *cur = URL;
429
    char buf[4096];
429
    char buf[4096];
430
    int indx = 0;
430
    int indx = 0;
431
    int port = 0;
431
    int port = 0;
432
 
432
 
433
    if (proxy != NULL) {
433
    if (proxy != NULL) {
434
        xmlFree(proxy);
434
        xmlFree(proxy);
435
	proxy = NULL;
435
	proxy = NULL;
436
    }
436
    }
437
    /*if (proxyPort != 0) {
437
    /*if (proxyPort != 0) {
438
	proxyPort = 0;
438
	proxyPort = 0;
439
	}*/
439
	}*/
440
    if (URL == NULL)
440
    if (URL == NULL)
441
	RxmlMessage(0, _("removing HTTP proxy info"));
441
	RxmlMessage(0, _("removing HTTP proxy info"));
442
    else
442
    else
443
	RxmlMessage(1, _("using HTTP proxy '%s'"), URL);
443
	RxmlMessage(1, _("using HTTP proxy '%s'"), URL);
444
    if (URL == NULL) return;
444
    if (URL == NULL) return;
445
    buf[indx] = 0;
445
    buf[indx] = 0;
446
    while (*cur != 0) {
446
    while (*cur != 0) {
447
        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
447
        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
448
	    buf[indx] = 0;
448
	    buf[indx] = 0;
449
	    indx = 0;
449
	    indx = 0;
450
            cur += 3;
450
            cur += 3;
451
	    break;
451
	    break;
452
	}
452
	}
453
	if(indx >= 4095)
453
	if(indx >= 4095)
454
	    RxmlMessage(2, _("RxmlNanoHTTPScanProxy: overlong (invalid?) URL"));
454
	    RxmlMessage(2, _("RxmlNanoHTTPScanProxy: overlong (invalid?) URL"));
455
	buf[indx++] = *cur++;
455
	buf[indx++] = *cur++;
456
    }
456
    }
457
    if (*cur == 0) return;
457
    if (*cur == 0) return;
458
 
458
 
459
    if(strchr(cur, '@')) {
459
    if(strchr(cur, '@')) {
460
	strcpy(buf, cur);
460
	strcpy(buf, cur);
461
	*(strchr(buf, '@')) = '\0';
461
	*(strchr(buf, '@')) = '\0';
462
	if(proxyUser) xmlFree(proxyUser);
462
	if(proxyUser) xmlFree(proxyUser);
463
	proxyUser = xmlMemStrdup(buf);
463
	proxyUser = xmlMemStrdup(buf);
464
	cur += (int)strlen(buf) + 1;
464
	cur += (int)strlen(buf) + 1;
465
    }
465
    }
466
    buf[indx] = 0;
466
    buf[indx] = 0;
467
    while (1) {
467
    while (1) {
468
        if (cur[0] == ':') {
468
        if (cur[0] == ':') {
469
	    buf[indx] = 0;
469
	    buf[indx] = 0;
470
	    proxy = xmlMemStrdup(buf);
470
	    proxy = xmlMemStrdup(buf);
471
	    indx = 0;
471
	    indx = 0;
472
	    cur += 1;
472
	    cur += 1;
473
	    while ((*cur >= '0') && (*cur <= '9')) {
473
	    while ((*cur >= '0') && (*cur <= '9')) {
474
	        port *= 10;
474
	        port *= 10;
475
		port += *cur - '0';
475
		port += *cur - '0';
476
		cur++;
476
		cur++;
477
	    }
477
	    }
478
	    if (port != 0) proxyPort = port;
478
	    if (port != 0) proxyPort = port;
479
	    while ((cur[0] != '/') && (*cur != 0))
479
	    while ((cur[0] != '/') && (*cur != 0))
480
	        cur++;
480
	        cur++;
481
	    break;
481
	    break;
482
	}
482
	}
483
        if ((*cur == '/') || (*cur == 0)) {
483
        if ((*cur == '/') || (*cur == 0)) {
484
	    buf[indx] = 0;
484
	    buf[indx] = 0;
485
	    proxy = xmlMemStrdup(buf);
485
	    proxy = xmlMemStrdup(buf);
486
	    indx = 0;
486
	    indx = 0;
487
	    break;
487
	    break;
488
	}
488
	}
489
	if(indx >= 4095)
489
	if(indx >= 4095)
490
	    RxmlMessage(2, _("RxmlNanoHTTPScanProxy: overlong (invalid?) URL"));	buf[indx++] = *cur++;
490
	    RxmlMessage(2, _("RxmlNanoHTTPScanProxy: overlong (invalid?) URL"));	buf[indx++] = *cur++;
491
    }
491
    }
492
}
492
}
493
 
493
 
494
/**
494
/**
495
 * RxmlNanoHTTPNewCtxt:
495
 * RxmlNanoHTTPNewCtxt:
496
 * @URL:  The URL used to initialize the context
496
 * @URL:  The URL used to initialize the context
497
 *
497
 *
498
 * Allocate and initialize a new HTTP context.
498
 * Allocate and initialize a new HTTP context.
499
 *
499
 *
500
 * Returns an HTTP context or NULL in case of error.
500
 * Returns an HTTP context or NULL in case of error.
501
 */
501
 */
502
 
502
 
503
static RxmlNanoHTTPCtxtPtr
503
static RxmlNanoHTTPCtxtPtr
504
RxmlNanoHTTPNewCtxt(const char *URL)
504
RxmlNanoHTTPNewCtxt(const char *URL)
505
{
505
{
506
    RxmlNanoHTTPCtxtPtr ret;
506
    RxmlNanoHTTPCtxtPtr ret;
507
 
507
 
508
    ret = (RxmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(RxmlNanoHTTPCtxt));
508
    ret = (RxmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(RxmlNanoHTTPCtxt));
509
    if (ret == NULL) {
509
    if (ret == NULL) {
510
        RxmlMessage(1, "error allocating context");
510
        RxmlMessage(1, "error allocating context");
511
	return(NULL);
511
	return(NULL);
512
    }
512
    }
513
 
513
 
514
    memset(ret, 0, sizeof(RxmlNanoHTTPCtxt));
514
    memset(ret, 0, sizeof(RxmlNanoHTTPCtxt));
515
    ret->port = 80;
515
    ret->port = 80;
516
    ret->returnValue = 0;
516
    ret->returnValue = 0;
517
    ret->statusMsg = NULL;
517
    ret->statusMsg = NULL;
518
    ret->contentLength = -1;
518
    ret->contentLength = -1;
519
    ret->fd = -1;
519
    ret->fd = -1;
520
 
520
 
521
    RxmlNanoHTTPScanURL(ret, URL);
521
    RxmlNanoHTTPScanURL(ret, URL);
522
 
522
 
523
    return(ret);
523
    return(ret);
524
}
524
}
525
 
525
 
526
/**
526
/**
527
 * RxmlNanoHTTPFreeCtxt:
527
 * RxmlNanoHTTPFreeCtxt:
528
 * @ctxt:  an HTTP context
528
 * @ctxt:  an HTTP context
529
 *
529
 *
530
 * Frees the context after closing the connection.
530
 * Frees the context after closing the connection.
531
 */
531
 */
532
 
532
 
533
static void
533
static void
534
RxmlNanoHTTPFreeCtxt(RxmlNanoHTTPCtxtPtr ctxt)
534
RxmlNanoHTTPFreeCtxt(RxmlNanoHTTPCtxtPtr ctxt)
535
{
535
{
536
    if (ctxt == NULL) return;
536
    if (ctxt == NULL) return;
537
    if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
537
    if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
538
    if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
538
    if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
539
    if (ctxt->path != NULL) xmlFree(ctxt->path);
539
    if (ctxt->path != NULL) xmlFree(ctxt->path);
540
    if (ctxt->query != NULL) xmlFree(ctxt->query);
540
    if (ctxt->query != NULL) xmlFree(ctxt->query);
541
    if (ctxt->out != NULL) xmlFree(ctxt->out);
541
    if (ctxt->out != NULL) xmlFree(ctxt->out);
542
    if (ctxt->in != NULL) xmlFree(ctxt->in);
542
    if (ctxt->in != NULL) xmlFree(ctxt->in);
543
    if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
543
    if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
544
    if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
544
    if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
545
    if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
545
    if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
546
    if (ctxt->location != NULL) xmlFree(ctxt->location);
546
    if (ctxt->location != NULL) xmlFree(ctxt->location);
547
    if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
547
    if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
548
#ifdef HAVE_ZLIB_H
548
#ifdef HAVE_ZLIB_H
549
    if (ctxt->strm != NULL) {
549
    if (ctxt->strm != NULL) {
550
	inflateEnd(ctxt->strm);
550
	inflateEnd(ctxt->strm);
551
	xmlFree(ctxt->strm);
551
	xmlFree(ctxt->strm);
552
    }
552
    }
553
#endif
553
#endif
554
 
554
 
555
    ctxt->state = XML_NANO_HTTP_NONE;
555
    ctxt->state = XML_NANO_HTTP_NONE;
556
    if (ctxt->fd >= 0) closesocket(ctxt->fd);
556
    if (ctxt->fd >= 0) closesocket(ctxt->fd);
557
    ctxt->fd = -1;
557
    ctxt->fd = -1;
558
    xmlFree(ctxt);
558
    xmlFree(ctxt);
559
}
559
}
560
 
560
 
561
/**
561
/**
562
 * RxmlNanoHTTPSend:
562
 * RxmlNanoHTTPSend:
563
 * @ctxt:  an HTTP context
563
 * @ctxt:  an HTTP context
564
 *
564
 *
565
 * Send the input needed to initiate the processing on the server side
565
 * Send the input needed to initiate the processing on the server side
566
 */
566
 */
567
 
567
 
568
static void
568
static void
569
RxmlNanoHTTPSend(RxmlNanoHTTPCtxtPtr ctxt)
569
RxmlNanoHTTPSend(RxmlNanoHTTPCtxtPtr ctxt)
570
{
570
{
571
    if (ctxt->state & XML_NANO_HTTP_WRITE) {
571
    if (ctxt->state & XML_NANO_HTTP_WRITE) {
572
        unsigned int total_sent = 0;
572
        unsigned int total_sent = 0;
573
        while (total_sent <strlen(ctxt->outptr)) {
573
        while (total_sent <strlen(ctxt->outptr)) {
574
            unsigned int nsent = send(ctxt->fd, ctxt->outptr+total_sent,
574
            unsigned int nsent = send(ctxt->fd, ctxt->outptr+total_sent,
575
                                      strlen(ctxt->outptr)-total_sent, 0);
575
                                      strlen(ctxt->outptr)-total_sent, 0);
576
            if (nsent>0)
576
            if (nsent>0)
577
                total_sent += nsent;
577
                total_sent += nsent;
578
	}
578
	}
579
        ctxt->last = total_sent;
579
        ctxt->last = total_sent;
580
    }
580
    }
581
}
581
}
582
 
582
 
583
/**
583
/**
584
 * RxmlNanoHTTPRecv:
584
 * RxmlNanoHTTPRecv:
585
 * @ctxt:  an HTTP context
585
 * @ctxt:  an HTTP context
586
 *
586
 *
587
 * Read information coming from the HTTP connection.
587
 * Read information coming from the HTTP connection.
588
 * This is a blocking call (but it blocks in select(), not read()).
588
 * This is a blocking call (but it blocks in select(), not read()).
589
 *
589
 *
590
 * Returns the number of byte read or -1 in case of error.
590
 * Returns the number of byte read or -1 in case of error.
591
 */
591
 */
592
 
592
 
593
static int
593
static int
594
RxmlNanoHTTPRecv(RxmlNanoHTTPCtxtPtr ctxt)
594
RxmlNanoHTTPRecv(RxmlNanoHTTPCtxtPtr ctxt)
595
{
595
{
596
    fd_set rfd;
596
    fd_set rfd;
597
    struct timeval tv;
597
    struct timeval tv;
598
    double used = 0.0;
598
    double used = 0.0;
599
 
599
 
600
 
600
 
601
    if (ctxt->state & XML_NANO_HTTP_READ) {
601
    if (ctxt->state & XML_NANO_HTTP_READ) {
602
	if (ctxt->in == NULL) {
602
	if (ctxt->in == NULL) {
603
	    ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
603
	    ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
604
	    if (ctxt->in == NULL) {
604
	    if (ctxt->in == NULL) {
605
		RxmlMessage(1, "error allocating input");
605
		RxmlMessage(1, "error allocating input");
606
	        ctxt->last = -1;
606
	        ctxt->last = -1;
607
		return(-1);
607
		return(-1);
608
	    }
608
	    }
609
	    ctxt->inlen = 65000;
609
	    ctxt->inlen = 65000;
610
	    ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
610
	    ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
611
	}
611
	}
612
	if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
612
	if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
613
	    int delta = ctxt->inrptr - ctxt->in;
613
	    int delta = ctxt->inrptr - ctxt->in;
614
	    int len = ctxt->inptr - ctxt->inrptr;
614
	    int len = ctxt->inptr - ctxt->inrptr;
615
 
615
 
616
	    memmove(ctxt->in, ctxt->inrptr, len);
616
	    memmove(ctxt->in, ctxt->inrptr, len);
617
	    ctxt->inrptr -= delta;
617
	    ctxt->inrptr -= delta;
618
	    ctxt->content -= delta;
618
	    ctxt->content -= delta;
619
	    ctxt->inptr -= delta;
619
	    ctxt->inptr -= delta;
620
	}
620
	}
621
        if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
621
        if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
622
	    int d_inptr = ctxt->inptr - ctxt->in;
622
	    int d_inptr = ctxt->inptr - ctxt->in;
623
	    int d_content = ctxt->content - ctxt->in;
623
	    int d_content = ctxt->content - ctxt->in;
624
	    int d_inrptr = ctxt->inrptr - ctxt->in;
624
	    int d_inrptr = ctxt->inrptr - ctxt->in;
625
	    char *	tmp_ptr = ctxt->in;
625
	    char *	tmp_ptr = ctxt->in;
626
 
626
 
627
	    ctxt->inlen *= 2;
627
	    ctxt->inlen *= 2;
628
            ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
628
            ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
629
	    if (ctxt->in == NULL) {
629
	    if (ctxt->in == NULL) {
630
		RxmlMessage(1, "error allocating input buffer");
630
		RxmlMessage(1, "error allocating input buffer");
631
		xmlFree( tmp_ptr );
631
		xmlFree( tmp_ptr );
632
	        ctxt->last = -1;
632
	        ctxt->last = -1;
633
		return(-1);
633
		return(-1);
634
	    }
634
	    }
635
            ctxt->inptr = ctxt->in + d_inptr;
635
            ctxt->inptr = ctxt->in + d_inptr;
636
            ctxt->content = ctxt->in + d_content;
636
            ctxt->content = ctxt->in + d_content;
637
            ctxt->inrptr = ctxt->in + d_inrptr;
637
            ctxt->inrptr = ctxt->in + d_inrptr;
638
	}
638
	}
639
 
639
 
640
	while(1) {
640
	while(1) {
641
	    int maxfd = 0, howmany;
641
	    int maxfd = 0, howmany;
642
	    struct timeval tv_save; /* select() is destructive on Linux, so save tv */
642
	    struct timeval tv_save; /* select() is destructive on Linux, so save tv */
643
	    R_ProcessEvents();
643
	    R_ProcessEvents();
644
#ifdef Unix
644
#ifdef Unix
645
	    if(R_wait_usec > 0) {
645
	    if(R_wait_usec > 0) {
646
		tv.tv_sec = 0;
646
		tv.tv_sec = 0;
647
		tv.tv_usec = R_wait_usec;
647
		tv.tv_usec = R_wait_usec;
648
	    } else {
648
	    } else {
649
		tv.tv_sec = timeout;
649
		tv.tv_sec = timeout;
650
		tv.tv_usec = 0;
650
		tv.tv_usec = 0;
651
	    }
651
	    }
652
#elif defined(Win32)
652
#elif defined(Win32)
653
	    tv.tv_sec = 0;
653
	    tv.tv_sec = 0;
654
	    tv.tv_usec = 2e5;
654
	    tv.tv_usec = 2e5;
655
#else
655
#else
656
	    tv.tv_sec = timeout;
656
	    tv.tv_sec = timeout;
657
	    tv.tv_usec = 0;
657
	    tv.tv_usec = 0;
658
#endif
658
#endif
659
 
659
 
660
	    tv_save = tv;
660
	    tv_save = tv;
661
 
661
 
662
#ifdef Unix
662
#ifdef Unix
663
	    maxfd = setSelectMask(R_InputHandlers, &rfd);
663
	    maxfd = setSelectMask(R_InputHandlers, &rfd);
664
#else
664
#else
665
	    FD_ZERO(&rfd);
665
	    FD_ZERO(&rfd);
666
#endif
666
#endif
667
	    FD_SET(ctxt->fd, &rfd);
667
	    FD_SET(ctxt->fd, &rfd);
668
	    if(maxfd < ctxt->fd) maxfd = ctxt->fd;
668
	    if(maxfd < ctxt->fd) maxfd = ctxt->fd;
669
 
669
 
670
	    howmany = R_SelectEx(maxfd+1, &rfd, NULL, NULL, &tv, NULL);
670
	    howmany = R_SelectEx(maxfd+1, &rfd, NULL, NULL, &tv, NULL);
671
 
671
 
672
	    if (howmany < 0) {
672
	    if (howmany < 0) {
673
#ifdef DEBUG_HTTP
673
#ifdef DEBUG_HTTP
674
		perror("select in RxmlNanoHTTPRecv");
674
		perror("select in RxmlNanoHTTPRecv");
675
#endif
675
#endif
676
		return(0);
676
		return(0);
677
	    }
677
	    }
678
	    if (howmany == 0) {
678
	    if (howmany == 0) {
679
		used += tv_save.tv_sec + 1e-6 * tv_save.tv_usec;
679
		used += tv_save.tv_sec + 1e-6 * tv_save.tv_usec;
680
		if(used >= timeout) return(0);
680
		if(used >= timeout) return(0);
681
		continue;
681
		continue;
682
	    }
682
	    }
683
 
683
 
684
#ifdef Unix
684
#ifdef Unix
685
	    if(!FD_ISSET(ctxt->fd, &rfd) || howmany > 1) {
685
	    if(!FD_ISSET(ctxt->fd, &rfd) || howmany > 1) {
686
		/* was one of the extras */
686
		/* was one of the extras */
687
		InputHandler *what;
687
		InputHandler *what;
688
		what = getSelectedHandler(R_InputHandlers, &rfd);
688
		what = getSelectedHandler(R_InputHandlers, &rfd);
689
		if(what != NULL) what->handler((void*) NULL);
689
		if(what != NULL) what->handler((void*) NULL);
690
		continue;
690
		continue;
691
	    }
691
	    }
692
#endif
692
#endif
693
 
693
 
694
	    /* was the socket */
694
	    /* was the socket */
695
	    ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
695
	    ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
696
	    if (ctxt->last > 0) {
696
	    if (ctxt->last > 0) {
697
		ctxt->inptr += ctxt->last;
697
		ctxt->inptr += ctxt->last;
698
		return(ctxt->last);
698
		return(ctxt->last);
699
	    }
699
	    }
700
	    if (ctxt->last == 0) {
700
	    if (ctxt->last == 0) {
701
		return(0);
701
		return(0);
702
	    }
702
	    }
703
	    if (ctxt->last == -1) {
703
	    if (ctxt->last == -1) {
704
		switch (socket_errno()) {
704
		switch (socket_errno()) {
705
		case EINPROGRESS:
705
		case EINPROGRESS:
706
		case EWOULDBLOCK:
706
		case EWOULDBLOCK:
707
#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
707
#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
708
		case EAGAIN:
708
		case EAGAIN:
709
#endif
709
#endif
710
		    break;
710
		    break;
711
 
711
 
712
		default:
712
		default:
713
		    return(0);
713
		    return(0);
714
		}
714
		}
715
	    }
715
	    }
716
	}
716
	}
717
    }
717
    }
718
 
718
 
719
    return(0);
719
    return(0);
720
}
720
}
721
 
721
 
722
/**
722
/**
723
 * RxmlNanoHTTPReadLine:
723
 * RxmlNanoHTTPReadLine:
724
 * @ctxt:  an HTTP context
724
 * @ctxt:  an HTTP context
725
 *
725
 *
726
 * Read one line in the HTTP server output, usually for extracting
726
 * Read one line in the HTTP server output, usually for extracting
727
 * the HTTP protocol informations from the answer header.
727
 * the HTTP protocol informations from the answer header.
728
 *
728
 *
729
 * Returns a newly allocated string with a copy of the line, or NULL
729
 * Returns a newly allocated string with a copy of the line, or NULL
730
 *         which indicate the end of the input.
730
 *         which indicate the end of the input.
731
 */
731
 */
732
 
732
 
733
static char *
733
static char *
734
RxmlNanoHTTPReadLine(RxmlNanoHTTPCtxtPtr ctxt)
734
RxmlNanoHTTPReadLine(RxmlNanoHTTPCtxtPtr ctxt)
735
{
735
{
736
    char buf[4096];
736
    char buf[4096];
737
    char *bp = buf;
737
    char *bp = buf;
738
    int	rc;
738
    int	rc;
739
 
739
 
740
    while (bp - buf < 4095) {
740
    while (bp - buf < 4095) {
741
	if (ctxt->inrptr == ctxt->inptr) {
741
	if (ctxt->inrptr == ctxt->inptr) {
742
	    if ( (rc = RxmlNanoHTTPRecv(ctxt)) == 0) {
742
	    if ( (rc = RxmlNanoHTTPRecv(ctxt)) == 0) {
743
		if (bp == buf)
743
		if (bp == buf)
744
		    return(NULL);
744
		    return(NULL);
745
		else
745
		else
746
		    *bp = 0;
746
		    *bp = 0;
747
		return(xmlMemStrdup(buf));
747
		return(xmlMemStrdup(buf));
748
	    }
748
	    }
749
	    else if ( rc == -1 ) {
749
	    else if ( rc == -1 ) {
750
	        return ( NULL );
750
	        return ( NULL );
751
	    }
751
	    }
752
	}
752
	}
753
	*bp = *ctxt->inrptr++;
753
	*bp = *ctxt->inrptr++;
754
	if (*bp == '\n') {
754
	if (*bp == '\n') {
755
	    *bp = 0;
755
	    *bp = 0;
756
	    return(xmlMemStrdup(buf));
756
	    return(xmlMemStrdup(buf));
757
	}
757
	}
758
	if (*bp != '\r')
758
	if (*bp != '\r')
759
	    bp++;
759
	    bp++;
760
    }
760
    }
761
    buf[4095] = 0;
761
    buf[4095] = 0;
762
    return(xmlMemStrdup(buf));
762
    return(xmlMemStrdup(buf));
763
}
763
}
764
 
764
 
765
 
765
 
766
/**
766
/**
767
 * RxmlNanoHTTPScanAnswer:
767
 * RxmlNanoHTTPScanAnswer:
768
 * @ctxt:  an HTTP context
768
 * @ctxt:  an HTTP context
769
 * @line:  an HTTP header line
769
 * @line:  an HTTP header line
770
 *
770
 *
771
 * Try to extract useful informations from the server answer.
771
 * Try to extract useful informations from the server answer.
772
 * We currently parse and process:
772
 * We currently parse and process:
773
 *  - The HTTP revision/ return code
773
 *  - The HTTP revision/ return code
774
 *  - The Content-Type, Mime-Type and charset used
774
 *  - The Content-Type, Mime-Type and charset used
775
 *  - The Location for redirect processing.
775
 *  - The Location for redirect processing.
776
 *
776
 *
777
 * Returns -1 in case of failure, the file descriptor number otherwise
777
 * Returns -1 in case of failure, the file descriptor number otherwise
778
 */
778
 */
779
 
779
 
780
static void
780
static void
781
RxmlNanoHTTPScanAnswer(RxmlNanoHTTPCtxtPtr ctxt, const char *line)
781
RxmlNanoHTTPScanAnswer(RxmlNanoHTTPCtxtPtr ctxt, const char *line)
782
{
782
{
783
    const char *cur = line;
783
    const char *cur = line;
784
 
784
 
785
    if (line == NULL) return;
785
    if (line == NULL) return;
786
 
786
 
787
    if (!strncmp(line, "HTTP/", 5)) {
787
    if (!strncmp(line, "HTTP/", 5)) {
788
        int version = 0;
788
        int version = 0;
789
	int ret = 0;
789
	int ret = 0;
790
 
790
 
791
	cur += 5;
791
	cur += 5;
792
	while ((*cur >= '0') && (*cur <= '9')) {
792
	while ((*cur >= '0') && (*cur <= '9')) {
793
	    version *= 10;
793
	    version *= 10;
794
	    version += *cur - '0';
794
	    version += *cur - '0';
795
	    cur++;
795
	    cur++;
796
	}
796
	}
797
	if (*cur == '.') {
797
	if (*cur == '.') {
798
	    cur++;
798
	    cur++;
799
	    if ((*cur >= '0') && (*cur <= '9')) {
799
	    if ((*cur >= '0') && (*cur <= '9')) {
800
		version *= 10;
800
		version *= 10;
801
		version += *cur - '0';
801
		version += *cur - '0';
802
		cur++;
802
		cur++;
803
	    }
803
	    }
804
	    while ((*cur >= '0') && (*cur <= '9'))
804
	    while ((*cur >= '0') && (*cur <= '9'))
805
		cur++;
805
		cur++;
806
	} else
806
	} else
807
	    version *= 10;
807
	    version *= 10;
808
	if ((*cur != ' ') && (*cur != '\t')) return;
808
	if ((*cur != ' ') && (*cur != '\t')) return;
809
	while ((*cur == ' ') || (*cur == '\t')) cur++;
809
	while ((*cur == ' ') || (*cur == '\t')) cur++;
810
	if ((*cur < '0') || (*cur > '9')) return;
810
	if ((*cur < '0') || (*cur > '9')) return;
811
	while ((*cur >= '0') && (*cur <= '9')) {
811
	while ((*cur >= '0') && (*cur <= '9')) {
812
	    ret *= 10;
812
	    ret *= 10;
813
	    ret += *cur - '0';
813
	    ret += *cur - '0';
814
	    cur++;
814
	    cur++;
815
	}
815
	}
816
	if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
816
	if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
817
	ctxt->returnValue = ret;
817
	ctxt->returnValue = ret;
818
	if ((*cur == ' ') || (*cur == '\t')) cur++;
818
	if ((*cur == ' ') || (*cur == '\t')) cur++;
819
	if(ctxt->statusMsg) xmlFree(ctxt->statusMsg);
819
	if(ctxt->statusMsg) xmlFree(ctxt->statusMsg);
820
	ctxt->statusMsg = xmlMemStrdup(cur);
820
	ctxt->statusMsg = xmlMemStrdup(cur);
821
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
821
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
822
        const char *charset, *last, *mime;
822
        const char *charset, *last, *mime;
823
        cur += 13;
823
        cur += 13;
824
	while ((*cur == ' ') || (*cur == '\t')) cur++;
824
	while ((*cur == ' ') || (*cur == '\t')) cur++;
825
	if (ctxt->contentType != NULL)
825
	if (ctxt->contentType != NULL)
826
	    xmlFree(ctxt->contentType);
826
	    xmlFree(ctxt->contentType);
827
	ctxt->contentType = xmlMemStrdup(cur);
827
	ctxt->contentType = xmlMemStrdup(cur);
828
	mime = (const char *) cur;
828
	mime = (const char *) cur;
829
	last = mime;
829
	last = mime;
830
	while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
830
	while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
831
	       (*last != ';') && (*last != ','))
831
	       (*last != ';') && (*last != ','))
832
	    last++;
832
	    last++;
833
	if (ctxt->mimeType != NULL)
833
	if (ctxt->mimeType != NULL)
834
	    xmlFree(ctxt->mimeType);
834
	    xmlFree(ctxt->mimeType);
835
	ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
835
	ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
836
	charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
836
	charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
837
	if (charset != NULL) {
837
	if (charset != NULL) {
838
	    charset += 8;
838
	    charset += 8;
839
	    last = charset;
839
	    last = charset;
840
	    while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
840
	    while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
841
	           (*last != ';') && (*last != ','))
841
	           (*last != ';') && (*last != ','))
842
		last++;
842
		last++;
843
	    if (ctxt->encoding != NULL)
843
	    if (ctxt->encoding != NULL)
844
	        xmlFree(ctxt->encoding);
844
	        xmlFree(ctxt->encoding);
845
	    ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
845
	    ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
846
	}
846
	}
847
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
847
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
848
        const char *charset, *last, *mime;
848
        const char *charset, *last, *mime;
849
        cur += 12;
849
        cur += 12;
850
	if (ctxt->contentType != NULL) return;
850
	if (ctxt->contentType != NULL) return;
851
	while ((*cur == ' ') || (*cur == '\t')) cur++;
851
	while ((*cur == ' ') || (*cur == '\t')) cur++;
852
	ctxt->contentType = xmlMemStrdup(cur);
852
	ctxt->contentType = xmlMemStrdup(cur);
853
	mime = (const char *) cur;
853
	mime = (const char *) cur;
854
	last = mime;
854
	last = mime;
855
	while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
855
	while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
856
	       (*last != ';') && (*last != ','))
856
	       (*last != ';') && (*last != ','))
857
	    last++;
857
	    last++;
858
	if (ctxt->mimeType != NULL)
858
	if (ctxt->mimeType != NULL)
859
	    xmlFree(ctxt->mimeType);
859
	    xmlFree(ctxt->mimeType);
860
	ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
860
	ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
861
	charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
861
	charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
862
	if (charset != NULL) {
862
	if (charset != NULL) {
863
	    charset += 8;
863
	    charset += 8;
864
	    last = charset;
864
	    last = charset;
865
	    while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
865
	    while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
866
	           (*last != ';') && (*last != ','))
866
	           (*last != ';') && (*last != ','))
867
		last++;
867
		last++;
868
	    if (ctxt->encoding != NULL)
868
	    if (ctxt->encoding != NULL)
869
	        xmlFree(ctxt->encoding);
869
	        xmlFree(ctxt->encoding);
870
	    ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
870
	    ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
871
	}
871
	}
872
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Length:", 15)) {
872
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Length:", 15)) {
873
        cur += 15;
873
        cur += 15;
874
	while ((*cur == ' ') || (*cur == '\t')) cur++;
874
	while ((*cur == ' ') || (*cur == '\t')) cur++;
875
	ctxt->contentLength = atoi(cur);
875
	ctxt->contentLength = atoi(cur);
876
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
876
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
877
        cur += 9;
877
        cur += 9;
878
	while ((*cur == ' ') || (*cur == '\t')) cur++;
878
	while ((*cur == ' ') || (*cur == '\t')) cur++;
879
	if (ctxt->location != NULL)
879
	if (ctxt->location != NULL)
880
	    xmlFree(ctxt->location);
880
	    xmlFree(ctxt->location);
881
	if (*cur == '/') {
881
	if (*cur == '/') {
882
	    char buf[1000];
882
	    char buf[1000];
883
	    snprintf(buf, 1000, "http://%s%s", ctxt->hostname, cur);
883
	    snprintf(buf, 1000, "http://%s%s", ctxt->hostname, cur);
884
	    ctxt->location = xmlMemStrdup(buf);
884
	    ctxt->location = xmlMemStrdup(buf);
885
	} else {
885
	} else {
886
	    ctxt->location = xmlMemStrdup(cur);
886
	    ctxt->location = xmlMemStrdup(cur);
887
	}
887
	}
888
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
888
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
889
        cur += 17;
889
        cur += 17;
890
	while ((*cur == ' ') || (*cur == '\t')) cur++;
890
	while ((*cur == ' ') || (*cur == '\t')) cur++;
891
	if (ctxt->authHeader != NULL)
891
	if (ctxt->authHeader != NULL)
892
	    xmlFree(ctxt->authHeader);
892
	    xmlFree(ctxt->authHeader);
893
	ctxt->authHeader = xmlMemStrdup(cur);
893
	ctxt->authHeader = xmlMemStrdup(cur);
894
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
894
    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
895
        cur += 19;
895
        cur += 19;
896
	while ((*cur == ' ') || (*cur == '\t')) cur++;
896
	while ((*cur == ' ') || (*cur == '\t')) cur++;
897
	if (ctxt->authHeader != NULL)
897
	if (ctxt->authHeader != NULL)
898
	    xmlFree(ctxt->authHeader);
898
	    xmlFree(ctxt->authHeader);
899
	ctxt->authHeader = xmlMemStrdup(cur);
899
	ctxt->authHeader = xmlMemStrdup(cur);
900
#ifdef HAVE_ZLIB_H
900
#ifdef HAVE_ZLIB_H
901
    } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
901
    } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
902
	cur += 17;
902
	cur += 17;
903
	while ((*cur == ' ') || (*cur == '\t')) cur++;
903
	while ((*cur == ' ') || (*cur == '\t')) cur++;
904
	if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
904
	if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
905
	    ctxt->usesGzip = 1;
905
	    ctxt->usesGzip = 1;
906
 
906
 
907
	    ctxt->strm = xmlMalloc(sizeof(z_stream));
907
	    ctxt->strm = xmlMalloc(sizeof(z_stream));
908
 
908
 
909
	    if (ctxt->strm != NULL) {
909
	    if (ctxt->strm != NULL) {
910
		ctxt->strm->zalloc = Z_NULL;
910
		ctxt->strm->zalloc = Z_NULL;
911
		ctxt->strm->zfree = Z_NULL;
911
		ctxt->strm->zfree = Z_NULL;
912
		ctxt->strm->opaque = Z_NULL;
912
		ctxt->strm->opaque = Z_NULL;
913
		ctxt->strm->avail_in = 0;
913
		ctxt->strm->avail_in = 0;
914
		ctxt->strm->next_in = Z_NULL;
914
		ctxt->strm->next_in = Z_NULL;
915
 
915
 
916
		inflateInit2( ctxt->strm, 31 );
916
		inflateInit2( ctxt->strm, 31 );
917
	    }
917
	    }
918
	}
918
	}
919
#endif
919
#endif
920
    }
920
    }
921
}
921
}
922
 
922
 
923
/**
923
/**
924
 * RxmlNanoHTTPConnectAttempt:
924
 * RxmlNanoHTTPConnectAttempt:
925
 * @addr:  a socket address structure
925
 * @addr:  a socket address structure
926
 *
926
 *
927
 * Attempt a connection to the given IP:port endpoint. It forces
927
 * Attempt a connection to the given IP:port endpoint. It forces
928
 * non-blocking semantic on the socket, and allow 60 seconds for
928
 * non-blocking semantic on the socket, and allow 60 seconds for
929
 * the host to answer.
929
 * the host to answer.
930
 *
930
 *
931
 * Returns -1 in case of failure, the file descriptor number otherwise
931
 * Returns -1 in case of failure, the file descriptor number otherwise
932
 */
932
 */
933
 
933
 
934
static int
934
static int
935
RxmlNanoHTTPConnectAttempt(struct sockaddr *addr)
935
RxmlNanoHTTPConnectAttempt(struct sockaddr *addr)
936
{
936
{
937
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
937
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
938
    fd_set wfd, rfd;
938
    fd_set wfd, rfd;
939
    struct timeval tv;
939
    struct timeval tv;
940
    int status = 0;
940
    int status = 0;
941
    double used = 0.0;
941
    double used = 0.0;
942
 
942
 
943
    if (s==-1) {
943
    if (s==-1) {
944
#ifdef DEBUG_HTTP
944
#ifdef DEBUG_HTTP
945
	perror("socket");
945
	perror("socket");
946
#endif
946
#endif
947
	RxmlMessage(0, "socket failed");
947
	RxmlMessage(0, "socket failed");
948
	return(-1);
948
	return(-1);
949
    }
949
    }
950
 
950
 
951
#ifdef _WINSOCKAPI_
951
#ifdef _WINSOCKAPI_
952
    {
952
    {
953
	u_long one = 1;
953
	u_long one = 1;
954
 
954
 
955
	status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
955
	status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
956
    }
956
    }
957
#else /* _WINSOCKAPI_ */
957
#else /* _WINSOCKAPI_ */
958
#if defined(VMS)
958
#if defined(VMS)
959
    {
959
    {
960
	int enable = 1;
960
	int enable = 1;
961
	status = ioctl(s, FIONBIO, &enable);
961
	status = ioctl(s, FIONBIO, &enable);
962
    }
962
    }
963
#else /* VMS */
963
#else /* VMS */
964
#ifdef HAVE_FCNTL
964
#ifdef HAVE_FCNTL
965
    if ((status = fcntl(s, F_GETFL, 0)) != -1) {
965
    if ((status = fcntl(s, F_GETFL, 0)) != -1) {
966
#ifdef O_NONBLOCK
966
#ifdef O_NONBLOCK
967
	status |= O_NONBLOCK;
967
	status |= O_NONBLOCK;
968
#else /* O_NONBLOCK */
968
#else /* O_NONBLOCK */
969
#ifdef F_NDELAY
969
#ifdef F_NDELAY
970
	status |= F_NDELAY;
970
	status |= F_NDELAY;
971
#endif /* F_NDELAY */
971
#endif /* F_NDELAY */
972
#endif /* !O_NONBLOCK */
972
#endif /* !O_NONBLOCK */
973
	status = fcntl(s, F_SETFL, status);
973
	status = fcntl(s, F_SETFL, status);
974
    }
974
    }
975
#endif
975
#endif
976
    if (status < 0) {
976
    if (status < 0) {
977
#ifdef DEBUG_HTTP
977
#ifdef DEBUG_HTTP
978
	perror("nonblocking");
978
	perror("nonblocking");
979
#endif
979
#endif
980
	RxmlMessage(0, "error setting non-blocking IO");
980
	RxmlMessage(0, "error setting non-blocking IO");
981
	closesocket(s);
981
	closesocket(s);
982
	return(-1);
982
	return(-1);
983
    }
983
    }
984
#endif /* !VMS */
984
#endif /* !VMS */
985
#endif /* !_WINSOCKAPI_ */
985
#endif /* !_WINSOCKAPI_ */
986
 
986
 
987
 
987
 
988
    if ((connect(s, addr, sizeof(*addr))==-1)) {
988
    if ((connect(s, addr, sizeof(*addr))==-1)) {
989
 
989
 
990
	switch (socket_errno()) {
990
	switch (socket_errno()) {
991
	case EINPROGRESS:
991
	case EINPROGRESS:
992
	case EWOULDBLOCK:
992
	case EWOULDBLOCK:
993
	    break;
993
	    break;
994
	default:
994
	default:
995
	    perror("connect");
995
	    perror("connect");
996
	    closesocket(s);
996
	    closesocket(s);
997
	    return(-1);
997
	    return(-1);
998
	}
998
	}
999
    }
999
    }
1000
 
1000
 
1001
    while(1) {
1001
    while(1) {
1002
	int maxfd = 0;
1002
	int maxfd = 0;
1003
	struct timeval tv_save; /* select() is destructive on Linux, so save tv */
1003
	struct timeval tv_save; /* select() is destructive on Linux, so save tv */
1004
	R_ProcessEvents();
1004
	R_ProcessEvents();
1005
#ifdef Unix
1005
#ifdef Unix
1006
	if(R_wait_usec > 0) {
1006
	if(R_wait_usec > 0) {
1007
	    tv.tv_sec = 0;
1007
	    tv.tv_sec = 0;
1008
	    tv.tv_usec = R_wait_usec;
1008
	    tv.tv_usec = R_wait_usec;
1009
	} else {
1009
	} else {
1010
	    tv.tv_sec = timeout;
1010
	    tv.tv_sec = timeout;
1011
	    tv.tv_usec = 0;
1011
	    tv.tv_usec = 0;
1012
	}
1012
	}
1013
#elif defined(Win32)
1013
#elif defined(Win32)
1014
	tv.tv_sec = 0;
1014
	tv.tv_sec = 0;
1015
	tv.tv_usec = 2e5;
1015
	tv.tv_usec = 2e5;
1016
#else
1016
#else
1017
	tv.tv_sec = timeout;
1017
	tv.tv_sec = timeout;
1018
	tv.tv_usec = 0;
1018
	tv.tv_usec = 0;
1019
#endif
1019
#endif
1020
 
1020
 
1021
	tv_save = tv;
1021
	tv_save = tv;
1022
 
1022
 
1023
#ifdef Unix
1023
#ifdef Unix
1024
	maxfd = setSelectMask(R_InputHandlers, &rfd);
1024
	maxfd = setSelectMask(R_InputHandlers, &rfd);
1025
#else
1025
#else
1026
	FD_ZERO(&rfd);
1026
	FD_ZERO(&rfd);
1027
#endif
1027
#endif
1028
	FD_ZERO(&wfd);
1028
	FD_ZERO(&wfd);
1029
	FD_SET(s, &wfd);
1029
	FD_SET(s, &wfd);
1030
	if(maxfd < s) maxfd = s;
1030
	if(maxfd < s) maxfd = s;
1031
 
1031
 
1032
	switch(R_SelectEx(maxfd+1, &rfd, &wfd, NULL, &tv, NULL))
1032
	switch(R_SelectEx(maxfd+1, &rfd, &wfd, NULL, &tv, NULL))
1033
	{
1033
	{
1034
	case 0:
1034
	case 0:
1035
	    /* Time out */
1035
	    /* Time out */
1036
	    RxmlMessage(0, "Connect attempt timed out");
1036
	    RxmlMessage(0, "Connect attempt timed out");
1037
	    used += tv_save.tv_sec + 1e-6 * tv_save.tv_usec;
1037
	    used += tv_save.tv_sec + 1e-6 * tv_save.tv_usec;
1038
	    if(used < timeout) continue;
1038
	    if(used < timeout) continue;
1039
	    closesocket(s);
1039
	    closesocket(s);
1040
	    return(-1);
1040
	    return(-1);
1041
	case -1:
1041
	case -1:
1042
	    /* Ermm.. ?? */
1042
	    /* Ermm.. ?? */
1043
	    RxmlMessage(0, "Connect failed");
1043
	    RxmlMessage(0, "Connect failed");
1044
	    closesocket(s);
1044
	    closesocket(s);
1045
	    return(-1);
1045
	    return(-1);
1046
	}
1046
	}
1047
 
1047
 
1048
	if ( FD_ISSET(s, &wfd) ) {
1048
	if ( FD_ISSET(s, &wfd) ) {
1049
	    R_SOCKLEN_T len;
1049
	    R_SOCKLEN_T len;
1050
	    len = sizeof(status);
1050
	    len = sizeof(status);
1051
	    if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0){
1051
	    if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0){
1052
		/* Solaris error code */
1052
		/* Solaris error code */
1053
		return (-1);
1053
		return (-1);
1054
	    }
1054
	    }
1055
	    if ( status ) {
1055
	    if ( status ) {
1056
		RxmlMessage(0, "Error connecting to remote host");
1056
		RxmlMessage(0, "Error connecting to remote host");
1057
		closesocket(s);
1057
		closesocket(s);
1058
		errno = status;
1058
		errno = status;
1059
		return (-1);
1059
		return (-1);
1060
	    } else return(s);
1060
	    } else return(s);
1061
#ifdef Unix
1061
#ifdef Unix
1062
	} else { /* some other handler needed */
1062
	} else { /* some other handler needed */
1063
	    InputHandler *what;
1063
	    InputHandler *what;
1064
	    what = getSelectedHandler(R_InputHandlers, &rfd);
1064
	    what = getSelectedHandler(R_InputHandlers, &rfd);
1065
	    if(what != NULL) what->handler((void*) NULL);
1065
	    if(what != NULL) what->handler((void*) NULL);
1066
	    continue;
1066
	    continue;
1067
#endif
1067
#endif
1068
	}
1068
	}
1069
    }
1069
    }
1070
    /* not reached
1070
    /* not reached
1071
    return(-1); */
1071
    return(-1); */
1072
}
1072
}
1073
 
1073
 
1074
/**
1074
/**
1075
 * RxmlNanoHTTPConnectHost:
1075
 * RxmlNanoHTTPConnectHost:
1076
 * @host:  the host name
1076
 * @host:  the host name
1077
 * @port:  the port number
1077
 * @port:  the port number
1078
 *
1078
 *
1079
 * Attempt a connection to the given host:port endpoint. It tries
1079
 * Attempt a connection to the given host:port endpoint. It tries
1080
 * the multiple IP provided by the DNS if available.
1080
 * the multiple IP provided by the DNS if available.
1081
 *
1081
 *
1082
 * Returns -1 in case of failure, the file descriptor number otherwise
1082
 * Returns -1 in case of failure, the file descriptor number otherwise
1083
 */
1083
 */
1084
 
1084
 
1085
static int
1085
static int
1086
RxmlNanoHTTPConnectHost(const char *host, int port)
1086
RxmlNanoHTTPConnectHost(const char *host, int port)
1087
{
1087
{
1088
    struct hostent *h;
1088
    struct hostent *h;
1089
    struct sockaddr *addr;
1089
    struct sockaddr *addr;
1090
    struct in_addr ia;
1090
    struct in_addr ia;
1091
    struct sockaddr_in sockin;
1091
    struct sockaddr_in sockin;
1092
#ifdef SUPPORT_IP6
1092
#ifdef SUPPORT_IP6
1093
    struct in6_addr ia6;
1093
    struct in6_addr ia6;
1094
    struct sockaddr_in6 sockin6;
1094
    struct sockaddr_in6 sockin6;
1095
#endif
1095
#endif
1096
    int i;
1096
    int i;
1097
    int s;
1097
    int s;
1098
 
1098
 
1099
#if defined(SUPPORT_IP6) && defined(RES_USE_INET6)
1099
#if defined(SUPPORT_IP6) && defined(RES_USE_INET6)
1100
    if (!(_res.options & RES_INIT))
1100
    if (!(_res.options & RES_INIT))
1101
	res_init();
1101
	res_init();
1102
    _res.options |= RES_USE_INET6;
1102
    _res.options |= RES_USE_INET6;
1103
#endif
1103
#endif
1104
    h=gethostbyname(host);
1104
    h=gethostbyname(host);
1105
    if (h==NULL)
1105
    if (h==NULL)
1106
    {
1106
    {
1107
	RxmlMessage(2, _("unable to resolve '%s'"), host);
1107
	RxmlMessage(2, _("unable to resolve '%s'"), host);
1108
	return(-1);
1108
	return(-1);
1109
    }
1109
    }
1110
 
1110
 
1111
    for(i=0; h->h_addr_list[i]; i++)
1111
    for(i=0; h->h_addr_list[i]; i++)
1112
    {
1112
    {
1113
	if (h->h_addrtype == AF_INET) {
1113
	if (h->h_addrtype == AF_INET) {
1114
	    /* A records (IPv4) */
1114
	    /* A records (IPv4) */
1115
	    memcpy(&ia, h->h_addr_list[i], h->h_length);
1115
	    memcpy(&ia, h->h_addr_list[i], h->h_length);
1116
	    sockin.sin_family = h->h_addrtype;
1116
	    sockin.sin_family = h->h_addrtype;
1117
	    sockin.sin_addr   = ia;
1117
	    sockin.sin_addr   = ia;
1118
	    sockin.sin_port   = htons(port);
1118
	    sockin.sin_port   = htons(port);
1119
	    addr = (struct sockaddr *)&sockin;
1119
	    addr = (struct sockaddr *)&sockin;
1120
#ifdef SUPPORT_IP6
1120
#ifdef SUPPORT_IP6
1121
	} else if (h->h_addrtype == AF_INET6) {
1121
	} else if (h->h_addrtype == AF_INET6) {
1122
	    /* AAAA records (IPv6) */
1122
	    /* AAAA records (IPv6) */
1123
	    memcpy(&ia6, h->h_addr_list[i], h->h_length);
1123
	    memcpy(&ia6, h->h_addr_list[i], h->h_length);
1124
	    sockin6.sin_family = h->h_addrtype;
1124
	    sockin6.sin_family = h->h_addrtype;
1125
	    sockin6.sin_addr   = ia6;
1125
	    sockin6.sin_addr   = ia6;
1126
	    sockin6.sin_port   = htons(port);
1126
	    sockin6.sin_port   = htons(port);
1127
	    addr = (struct sockaddr *)&sockin6;
1127
	    addr = (struct sockaddr *)&sockin6;
1128
#endif
1128
#endif
1129
	} else
1129
	} else
1130
	    break; /* for */
1130
	    break; /* for */
1131
 
1131
 
1132
	s = RxmlNanoHTTPConnectAttempt(addr);
1132
	s = RxmlNanoHTTPConnectAttempt(addr);
1133
	if (s != -1) {
1133
	if (s != -1) {
1134
	    RxmlMessage(1, _("connected to '%s' on port %d."), host, port);
1134
	    RxmlMessage(1, _("connected to '%s' on port %d."), host, port);
1135
	    return(s);
1135
	    return(s);
1136
	}
1136
	}
1137
    }
1137
    }
1138
 
1138
 
1139
    RxmlMessage(2, _("unable to connect to '%s' on port %d."), host, port);
1139
    RxmlMessage(2, _("unable to connect to '%s' on port %d."), host, port);
1140
    return(-1);
1140
    return(-1);
1141
}
1141
}
1142
 
1142
 
1143
 
1143
 
1144
/**
1144
/**
1145
 * RxmlNanoHTTPOpen:
1145
 * RxmlNanoHTTPOpen:
1146
 * @URL:  The URL to load
1146
 * @URL:  The URL to load
1147
 * @contentType:  if available the Content-Type information will be
1147
 * @contentType:  if available the Content-Type information will be
1148
 *                returned at that location
1148
 *                returned at that location
1149
 *
1149
 *
1150
 * @headers: headers to be used in the HTTP request.  These must be name/value
1150
 * @headers: headers to be used in the HTTP request.  These must be name/value
1151
 *           pairs separated by ':', each on their own line.
1151
 *           pairs separated by ':', each on their own line.
1152
 *
1152
 *
1153
 * This function try to open a connection to the indicated resource
1153
 * This function try to open a connection to the indicated resource
1154
 * via HTTP GET.
1154
 * via HTTP GET.
1155
 *
1155
 *
1156
 * Returns NULL in case of failure, otherwise a request handler.
1156
 * Returns NULL in case of failure, otherwise a request handler.
1157
 *     The contentType, if provided must be freed by the caller
1157
 *     The contentType, if provided must be freed by the caller
1158
 */
1158
 */
1159
 
1159
 
1160
void*
1160
void*
1161
RxmlNanoHTTPOpen(const char *URL, char **contentType, const char *headers,
1161
RxmlNanoHTTPOpen(const char *URL, char **contentType, const char *headers,
1162
                 int cacheOK)
1162
                 int cacheOK)
1163
{
1163
{
1164
    if (contentType != NULL) *contentType = NULL;
1164
    if (contentType != NULL) *contentType = NULL;
1165
    return RxmlNanoHTTPMethod(URL, NULL, NULL, contentType, headers, cacheOK);
1165
    return RxmlNanoHTTPMethod(URL, NULL, NULL, contentType, headers, cacheOK);
1166
}
1166
}
1167
 
1167
 
1168
/**
1168
/**
1169
 * RxmlNanoHTTPRead:
1169
 * RxmlNanoHTTPRead:
1170
 * @ctx:  the HTTP context
1170
 * @ctx:  the HTTP context
1171
 * @dest:  a buffer
1171
 * @dest:  a buffer
1172
 * @len:  the buffer length
1172
 * @len:  the buffer length
1173
 *
1173
 *
1174
 * This function tries to read @len bytes from the existing HTTP connection
1174
 * This function tries to read @len bytes from the existing HTTP connection
1175
 * and saves them in @dest. This is a blocking call.
1175
 * and saves them in @dest. This is a blocking call.
1176
 *
1176
 *
1177
 * Returns the number of byte read. 0 is an indication of an end of connection.
1177
 * Returns the number of byte read. 0 is an indication of an end of connection.
1178
 *         -1 indicates a parameter error.
1178
 *         -1 indicates a parameter error.
1179
 */
1179
 */
1180
int
1180
int
1181
RxmlNanoHTTPRead(void *ctx, void *dest, int len)
1181
RxmlNanoHTTPRead(void *ctx, void *dest, int len)
1182
{
1182
{
1183
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1183
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1184
 
1184
 
1185
#ifdef HAVE_ZLIB_H
1185
#ifdef HAVE_ZLIB_H
1186
    int bytes_read = 0;
1186
    int bytes_read = 0;
1187
    int orig_avail_in;
1187
    int orig_avail_in;
1188
    int z_ret;
1188
    int z_ret;
1189
#endif
1189
#endif
1190
 
1190
 
1191
    if (ctx == NULL) return(-1);
1191
    if (ctx == NULL) return(-1);
1192
    if (dest == NULL) return(-1);
1192
    if (dest == NULL) return(-1);
1193
    if (len <= 0) return(0);
1193
    if (len <= 0) return(0);
1194
 
1194
 
1195
#ifdef HAVE_ZLIB_H
1195
#ifdef HAVE_ZLIB_H
1196
    if (ctxt->usesGzip == 1) {
1196
    if (ctxt->usesGzip == 1) {
1197
        if (ctxt->strm == NULL) return(0);
1197
        if (ctxt->strm == NULL) return(0);
1198
 
1198
 
1199
        ctxt->strm->next_out = dest;
1199
        ctxt->strm->next_out = dest;
1200
        ctxt->strm->avail_out = len;
1200
        ctxt->strm->avail_out = len;
1201
 
1201
 
1202
        do {
1202
        do {
1203
            orig_avail_in = ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr - bytes_read;
1203
            orig_avail_in = ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr - bytes_read;
1204
            ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
1204
            ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
1205
 
1205
 
1206
            z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
1206
            z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
1207
            bytes_read += orig_avail_in - ctxt->strm->avail_in;
1207
            bytes_read += orig_avail_in - ctxt->strm->avail_in;
1208
 
1208
 
1209
            if (z_ret != Z_OK) break;
1209
            if (z_ret != Z_OK) break;
1210
        } while (ctxt->strm->avail_out > 0 && RxmlNanoHTTPRecv(ctxt) > 0);
1210
        } while (ctxt->strm->avail_out > 0 && RxmlNanoHTTPRecv(ctxt) > 0);
1211
 
1211
 
1212
        ctxt->inrptr += bytes_read;
1212
        ctxt->inrptr += bytes_read;
1213
        return(len - ctxt->strm->avail_out);
1213
        return(len - ctxt->strm->avail_out);
1214
    }
1214
    }
1215
#endif
1215
#endif
1216
 
1216
 
1217
    while (ctxt->inptr - ctxt->inrptr < len) {
1217
    while (ctxt->inptr - ctxt->inrptr < len) {
1218
        if (RxmlNanoHTTPRecv(ctxt) <= 0) break;
1218
        if (RxmlNanoHTTPRecv(ctxt) <= 0) break;
1219
    }
1219
    }
1220
    if (ctxt->inptr - ctxt->inrptr < len)
1220
    if (ctxt->inptr - ctxt->inrptr < len)
1221
        len = ctxt->inptr - ctxt->inrptr;
1221
        len = ctxt->inptr - ctxt->inrptr;
1222
    memcpy(dest, ctxt->inrptr, len);
1222
    memcpy(dest, ctxt->inrptr, len);
1223
    ctxt->inrptr += len;
1223
    ctxt->inrptr += len;
1224
    return(len);
1224
    return(len);
1225
}
1225
}
1226
 
1226
 
1227
static void base64_encode(char *proxyUser, char *out)
1227
static void base64_encode(char *proxyUser, char *out)
1228
{
1228
{
1229
    /* Conversion table.  */
1229
    /* Conversion table.  */
1230
    static char tbl[64] = {
1230
    static char tbl[64] = {
1231
	'A','B','C','D','E','F','G','H',
1231
	'A','B','C','D','E','F','G','H',
1232
	'I','J','K','L','M','N','O','P',
1232
	'I','J','K','L','M','N','O','P',
1233
	'Q','R','S','T','U','V','W','X',
1233
	'Q','R','S','T','U','V','W','X',
1234
	'Y','Z','a','b','c','d','e','f',
1234
	'Y','Z','a','b','c','d','e','f',
1235
	'g','h','i','j','k','l','m','n',
1235
	'g','h','i','j','k','l','m','n',
1236
	'o','p','q','r','s','t','u','v',
1236
	'o','p','q','r','s','t','u','v',
1237
	'w','x','y','z','0','1','2','3',
1237
	'w','x','y','z','0','1','2','3',
1238
	'4','5','6','7','8','9','+','/'
1238
	'4','5','6','7','8','9','+','/'
1239
    };
1239
    };
1240
    char *s = proxyUser;
1240
    char *s = proxyUser;
1241
    int i, length;
1241
    int i, length;
1242
    unsigned char *p = (unsigned char *)out;
1242
    unsigned char *p = (unsigned char *)out;
1243
 
1243
 
1244
    length = (int) strlen(s);
1244
    length = (int) strlen(s);
1245
    for (i = 0; i < length; i += 3) {
1245
    for (i = 0; i < length; i += 3) {
1246
	*p++ = tbl[s[i] >> 2];
1246
	*p++ = tbl[s[i] >> 2];
1247
	*p++ = tbl[((s[i] & 3) << 4) + (s[i+1] >> 4)];
1247
	*p++ = tbl[((s[i] & 3) << 4) + (s[i+1] >> 4)];
1248
	*p++ = tbl[((s[i+1] & 0xf) << 2) + (s[i+2] >> 6)];
1248
	*p++ = tbl[((s[i+1] & 0xf) << 2) + (s[i+2] >> 6)];
1249
	*p++ = tbl[s[i+2] & 0x3f];
1249
	*p++ = tbl[s[i+2] & 0x3f];
1250
    }
1250
    }
1251
    /* Pad the result if necessary...  */
1251
    /* Pad the result if necessary...  */
1252
    if (i == length + 1) *(p - 1) = '=';
1252
    if (i == length + 1) *(p - 1) = '=';
1253
    else if (i == length + 2) *(p - 1) = *(p - 2) = '=';
1253
    else if (i == length + 2) *(p - 1) = *(p - 2) = '=';
1254
    /* ...and zero-terminate it.  */
1254
    /* ...and zero-terminate it.  */
1255
    *p = '\0';
1255
    *p = '\0';
1256
}
1256
}
1257
 
1257
 
1258
/**
1258
/**
1259
 * RxmlNanoHTTPClose:
1259
 * RxmlNanoHTTPClose:
1260
 * @ctx:  the HTTP context
1260
 * @ctx:  the HTTP context
1261
 *
1261
 *
1262
 * This function closes an HTTP context, it ends up the connection and
1262
 * This function closes an HTTP context, it ends up the connection and
1263
 * free all data related to it.
1263
 * free all data related to it.
1264
 */
1264
 */
1265
void
1265
void
1266
RxmlNanoHTTPClose(void *ctx)
1266
RxmlNanoHTTPClose(void *ctx)
1267
{
1267
{
1268
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1268
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1269
 
1269
 
1270
    if (ctx == NULL) return;
1270
    if (ctx == NULL) return;
1271
 
1271
 
1272
    RxmlNanoHTTPFreeCtxt(ctxt);
1272
    RxmlNanoHTTPFreeCtxt(ctxt);
1273
}
1273
}
1274
 
1274
 
1275
/**
1275
/**
1276
 * RxmlNanoHTTPMethod:
1276
 * RxmlNanoHTTPMethod:
1277
 * @URL:  The URL to load
1277
 * @URL:  The URL to load
1278
 * @method:  the HTTP method to use
1278
 * @method:  the HTTP method to use
1279
 * @input:  the input string if any
1279
 * @input:  the input string if any
1280
 * @contentType:  the Content-Type information IN and OUT
1280
 * @contentType:  the Content-Type information IN and OUT
1281
 * @headers:  the extra headers
1281
 * @headers:  the extra headers
1282
 *
1282
 *
1283
 * This function try to open a connection to the indicated resource
1283
 * This function try to open a connection to the indicated resource
1284
 * via HTTP using the given @method, adding the given extra headers
1284
 * via HTTP using the given @method, adding the given extra headers
1285
 * and the input buffer for the request content.
1285
 * and the input buffer for the request content.
1286
 *
1286
 *
1287
 * Returns NULL in case of failure, otherwise a request handler.
1287
 * Returns NULL in case of failure, otherwise a request handler.
1288
 *     The contentType, if provided must be freed by the caller
1288
 *     The contentType, if provided must be freed by the caller
1289
 */
1289
 */
1290
 
1290
 
1291
void*
1291
void*
1292
RxmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
1292
RxmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
1293
                  char **contentType, const char *headers, const int cacheOK)
1293
                  char **contentType, const char *headers, const int cacheOK)
1294
{
1294
{
1295
    RxmlNanoHTTPCtxtPtr ctxt;
1295
    RxmlNanoHTTPCtxtPtr ctxt;
1296
    char *bp, *p;
1296
    char *bp, *p;
1297
    int blen, ilen, ret;
1297
    int blen, ilen, ret;
1298
    int head;
1298
    int head;
1299
    int nbRedirects = 0;
1299
    int nbRedirects = 0;
1300
#ifdef Win32
1300
#ifdef Win32
1301
    int nAuthenticate = 0;
1301
    int nAuthenticate = 0;
1302
#endif
1302
#endif
1303
    char *redirURL = NULL;
1303
    char *redirURL = NULL;
1304
    char buf[1000];
1304
    char buf[1000];
1305
 
1305
 
1306
    if (URL == NULL) return(NULL);
1306
    if (URL == NULL) return(NULL);
1307
    if (method == NULL) method = "GET";
1307
    if (method == NULL) method = "GET";
1308
    RxmlNanoHTTPInit();
1308
    RxmlNanoHTTPInit();
1309
 
1309
 
1310
 retry:
1310
 retry:
1311
    if (redirURL == NULL)
1311
    if (redirURL == NULL)
1312
	ctxt = RxmlNanoHTTPNewCtxt(URL);
1312
	ctxt = RxmlNanoHTTPNewCtxt(URL);
1313
    else {
1313
    else {
1314
	ctxt = RxmlNanoHTTPNewCtxt(redirURL);
1314
	ctxt = RxmlNanoHTTPNewCtxt(redirURL);
1315
	xmlFree(redirURL);
1315
	xmlFree(redirURL);
1316
	redirURL = NULL;
1316
	redirURL = NULL;
1317
    }
1317
    }
1318
 
1318
 
1319
    if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
1319
    if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
1320
	RxmlMessage(0, "Not a valid HTTP URI");
1320
	RxmlMessage(0, "Not a valid HTTP URI");
1321
        RxmlNanoHTTPFreeCtxt(ctxt);
1321
        RxmlNanoHTTPFreeCtxt(ctxt);
1322
	if (redirURL != NULL) xmlFree(redirURL);
1322
	if (redirURL != NULL) xmlFree(redirURL);
1323
        return(NULL);
1323
        return(NULL);
1324
    }
1324
    }
1325
    if (ctxt->hostname == NULL) {
1325
    if (ctxt->hostname == NULL) {
1326
	RxmlMessage(0, "Failed to identify host in URI");
1326
	RxmlMessage(0, "Failed to identify host in URI");
1327
        RxmlNanoHTTPFreeCtxt(ctxt);
1327
        RxmlNanoHTTPFreeCtxt(ctxt);
1328
        return(NULL);
1328
        return(NULL);
1329
    }
1329
    }
1330
    if (proxy) {
1330
    if (proxy) {
1331
	blen = (int) strlen(ctxt->hostname) * 2 + 16;
1331
	blen = (int) strlen(ctxt->hostname) * 2 + 16;
1332
	ret = RxmlNanoHTTPConnectHost(proxy, proxyPort);
1332
	ret = RxmlNanoHTTPConnectHost(proxy, proxyPort);
1333
    }
1333
    }
1334
    else {
1334
    else {
1335
	blen = (int) strlen(ctxt->hostname);
1335
	blen = (int) strlen(ctxt->hostname);
1336
	ret = RxmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1336
	ret = RxmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
1337
    }
1337
    }
1338
    if (ret < 0) {
1338
    if (ret < 0) {
1339
        RxmlNanoHTTPFreeCtxt(ctxt);
1339
        RxmlNanoHTTPFreeCtxt(ctxt);
1340
        return(NULL);
1340
        return(NULL);
1341
    }
1341
    }
1342
    ctxt->fd = ret;
1342
    ctxt->fd = ret;
1343
 
1343
 
1344
    if (input != NULL) {
1344
    if (input != NULL) {
1345
	ilen = (int) strlen(input);
1345
	ilen = (int) strlen(input);
1346
	blen += ilen + 32;
1346
	blen += ilen + 32;
1347
    }
1347
    }
1348
    else
1348
    else
1349
	ilen = 0;
1349
	ilen = 0;
1350
    if (!cacheOK)
1350
    if (!cacheOK)
1351
	blen += 20;
1351
	blen += 20;
1352
    if (headers != NULL)
1352
    if (headers != NULL)
1353
	blen += (int) strlen(headers) + 2;
1353
	blen += (int) strlen(headers) + 2;
1354
    if (contentType && *contentType)
1354
    if (contentType && *contentType)
1355
	blen += (int) strlen(*contentType) + 16;
1355
	blen += (int) strlen(*contentType) + 16;
1356
    if (proxy && proxyUser) {
1356
    if (proxy && proxyUser) {
1357
	base64_encode(proxyUser,  buf);
1357
	base64_encode(proxyUser,  buf);
1358
	blen += (int )strlen(buf) + 50;
1358
	blen += (int )strlen(buf) + 50;
1359
    }
1359
    }
1360
    blen += (int) strlen(method) + (int) strlen(ctxt->path) + 23;
1360
    blen += (int) strlen(method) + (int) strlen(ctxt->path) + 23;
1361
#ifdef HAVE_ZLIB_H
1361
#ifdef HAVE_ZLIB_H
1362
    blen += 23;
1362
    blen += 23;
1363
#endif
1363
#endif
1364
    p = bp = xmlMalloc(blen);
1364
    p = bp = xmlMalloc(blen + 8);
-
 
1365
    memset(p, 0, blen + 8);
1365
    if (proxy) {
1366
    if (proxy) {
1366
	if (ctxt->port != 80) {
1367
	if (ctxt->port != 80) {
1367
	    p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 
1368
	    p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 
1368
			method, ctxt->hostname,
1369
			method, ctxt->hostname,
1369
		 	ctxt->port, ctxt->path );
1370
		 	ctxt->port, ctxt->path );
1370
	}
1371
	}
1371
	else
1372
	else
1372
	    p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
1373
	    p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
1373
	    		ctxt->hostname, ctxt->path);
1374
	    		ctxt->hostname, ctxt->path);
1374
    }
1375
    }
1375
    else
1376
    else
1376
	p += snprintf(p, blen - (p - bp), "%s %s", method, ctxt->path);
1377
	p += snprintf(p, blen - (p - bp), "%s %s", method, ctxt->path);
1377
 
1378
 
1378
    p += snprintf(p,  blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
1379
    p += snprintf(p,  blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n",
1379
		  ctxt->hostname);
1380
		  ctxt->hostname);
1380
 
1381
 
1381
#ifdef HAVE_ZLIB_H
1382
#ifdef HAVE_ZLIB_H
1382
    p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
1383
    p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
1383
#endif
1384
#endif
1384
 
1385
 
1385
    if(!cacheOK)
1386
    if(!cacheOK)
1386
	p += snprintf(p, blen - (p - bp), "Pragma: no-cache\r\n");
1387
	p += snprintf(p, blen - (p - bp), "Pragma: no-cache\r\n");
1387
    if(proxy && proxyUser)
1388
    if(proxy && proxyUser)
1388
	p += snprintf(p, blen - (p - bp),"Proxy-Authorization: Basic %s\r\n", 
1389
	p += snprintf(p, blen - (p - bp),"Proxy-Authorization: Basic %s\r\n", 
1389
		      buf);
1390
		      buf);
1390
    if (contentType != NULL && *contentType)
1391
    if (contentType != NULL && *contentType)
1391
	p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
1392
	p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
1392
    if (headers != NULL)
1393
    if (headers != NULL)
1393
	p += snprintf(p, blen - (p - bp), "%s", headers);
1394
	p += snprintf(p, blen - (p - bp), "%s", headers);
1394
    if (input != NULL)
1395
    if (input != NULL)
1395
 
1396
 
1396
	snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n%s", 
1397
	snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n%s", 
1397
		 ilen, input);
1398
		 ilen, input);
1398
    else
1399
    else
1399
	snprintf(p, blen - (p - bp), "\r\n");
1400
	snprintf(p, blen - (p - bp), "\r\n");
1400
    RxmlMessage(0, "-> %s%s", proxy? "(Proxy) " : "", bp);
1401
    RxmlMessage(0, "-> %s%s", proxy? "(Proxy) " : "", bp);
1401
    if ((blen -= (int) strlen(bp)+1) < 0)
1402
    if ((blen -= (int) strlen(bp)+1) < 0)
1402
	RxmlMessage(0, "ERROR: overflowed buffer by %d bytes\n", -blen);
1403
	RxmlMessage(0, "ERROR: overflowed buffer by %d bytes\n", -blen);
1403
    ctxt->outptr = ctxt->out = bp;
1404
    ctxt->outptr = ctxt->out = bp;
1404
    ctxt->state = XML_NANO_HTTP_WRITE;
1405
    ctxt->state = XML_NANO_HTTP_WRITE;
1405
    RxmlNanoHTTPSend(ctxt);
1406
    RxmlNanoHTTPSend(ctxt);
1406
    ctxt->state = XML_NANO_HTTP_READ;
1407
    ctxt->state = XML_NANO_HTTP_READ;
1407
    head = 1;
1408
    head = 1;
1408
 
1409
 
1409
    while ((p = RxmlNanoHTTPReadLine(ctxt)) != NULL) {
1410
    while ((p = RxmlNanoHTTPReadLine(ctxt)) != NULL) {
1410
        if (head && (*p == 0)) {
1411
        if (head && (*p == 0)) {
1411
	    head = 0;
1412
	    head = 0;
1412
	    ctxt->content = ctxt->inrptr;
1413
	    ctxt->content = ctxt->inrptr;
1413
	    xmlFree(p);
1414
	    xmlFree(p);
1414
	    break;
1415
	    break;
1415
	}
1416
	}
1416
	RxmlNanoHTTPScanAnswer(ctxt, p);
1417
	RxmlNanoHTTPScanAnswer(ctxt, p);
1417
 
1418
 
1418
	RxmlMessage(0, "<- %s\n", p);
1419
	RxmlMessage(0, "<- %s\n", p);
1419
        xmlFree(p);
1420
        xmlFree(p);
1420
    }
1421
    }
1421
 
1422
 
1422
#ifdef Win32
1423
#ifdef Win32
1423
    /* Prompt for username/password again if status was proxy
1424
    /* Prompt for username/password again if status was proxy
1424
       authentication failure */
1425
       authentication failure */
1425
    if(proxy && !nAuthenticate && ctxt->returnValue == 407) {
1426
    if(proxy && !nAuthenticate && ctxt->returnValue == 407) {
1426
	char *env;
1427
	char *env;
1427
	REprintf("%s\n%s\n", "Proxy authentication failed:",
1428
	REprintf("%s\n%s\n", "Proxy authentication failed:",
1428
		"\tplease re-enter the credentials or hit Cancel");
1429
		"\tplease re-enter the credentials or hit Cancel");
1429
	R_FlushConsole(); R_ProcessEvents();
1430
	R_FlushConsole(); R_ProcessEvents();
1430
	env = askUserPass("Proxy Authentication");
1431
	env = askUserPass("Proxy Authentication");
1431
	if(strlen(env)) {
1432
	if(strlen(env)) {
1432
	    if (proxyUser != NULL) {xmlFree(proxyUser); proxyUser = NULL;}
1433
	    if (proxyUser != NULL) {xmlFree(proxyUser); proxyUser = NULL;}
1433
	    proxyUser = xmlMemStrdup(env);
1434
	    proxyUser = xmlMemStrdup(env);
1434
	    nAuthenticate++;
1435
	    nAuthenticate++;
1435
	    goto retry;
1436
	    goto retry;
1436
	}
1437
	}
1437
    }
1438
    }
1438
#endif
1439
#endif
1439
 
1440
 
1440
    if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1441
    if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
1441
        (ctxt->returnValue < 400)) {
1442
        (ctxt->returnValue < 400)) {
1442
	RxmlMessage(1, _("redirect to: '%s'"), ctxt->location);
1443
	RxmlMessage(1, _("redirect to: '%s'"), ctxt->location);
1443
	while (RxmlNanoHTTPRecv(ctxt)) 
1444
	while (RxmlNanoHTTPRecv(ctxt)) 
1444
	    ;  // clang likes this on a separate line
1445
	    ;  // clang likes this on a separate line
1445
        if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1446
        if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
1446
	    nbRedirects++;
1447
	    nbRedirects++;
1447
	    redirURL = xmlMemStrdup(ctxt->location);
1448
	    redirURL = xmlMemStrdup(ctxt->location);
1448
	    fflush(stdout);
1449
	    fflush(stdout);
1449
	    RxmlNanoHTTPFreeCtxt(ctxt);
1450
	    RxmlNanoHTTPFreeCtxt(ctxt);
1450
	    goto retry;
1451
	    goto retry;
1451
	}
1452
	}
1452
	RxmlNanoHTTPFreeCtxt(ctxt);
1453
	RxmlNanoHTTPFreeCtxt(ctxt);
1453
	RxmlMessage(2, _("too many redirects, aborting ..."));
1454
	RxmlMessage(2, _("too many redirects, aborting ..."));
1454
	return(NULL);
1455
	return(NULL);
1455
 
1456
 
1456
    }
1457
    }
1457
 
1458
 
1458
    if (contentType != NULL) {
1459
    if (contentType != NULL) {
1459
	if (ctxt->contentType != NULL)
1460
	if (ctxt->contentType != NULL)
1460
	    *contentType = xmlMemStrdup(ctxt->contentType);
1461
	    *contentType = xmlMemStrdup(ctxt->contentType);
1461
	else
1462
	else
1462
	    *contentType = NULL;
1463
	    *contentType = NULL;
1463
    }
1464
    }
1464
 
1465
 
1465
    if (ctxt->contentType != NULL)
1466
    if (ctxt->contentType != NULL)
1466
	RxmlMessage(1, "Code %d, content-type '%s'",
1467
	RxmlMessage(1, "Code %d, content-type '%s'",
1467
		    ctxt->returnValue, ctxt->contentType);
1468
		    ctxt->returnValue, ctxt->contentType);
1468
    else
1469
    else
1469
	RxmlMessage(1, "Code %d, no content-type",
1470
	RxmlMessage(1, "Code %d, no content-type",
1470
		    ctxt->returnValue);
1471
		    ctxt->returnValue);
1471
 
1472
 
1472
    return((void *) ctxt);
1473
    return((void *) ctxt);
1473
}
1474
}
1474
 
1475
 
1475
 
1476
 
1476
 
1477
 
1477
/**
1478
/**
1478
 * RxmlNanoHTTPReturnCode:
1479
 * RxmlNanoHTTPReturnCode:
1479
 * @ctx:  the HTTP context
1480
 * @ctx:  the HTTP context
1480
 *
1481
 *
1481
 * Returns the HTTP return code for the request.
1482
 * Returns the HTTP return code for the request.
1482
 */
1483
 */
1483
int
1484
int
1484
RxmlNanoHTTPReturnCode(void *ctx)
1485
RxmlNanoHTTPReturnCode(void *ctx)
1485
{
1486
{
1486
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1487
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1487
 
1488
 
1488
    if (ctxt == NULL) return(-1);
1489
    if (ctxt == NULL) return(-1);
1489
 
1490
 
1490
    return(ctxt->returnValue);
1491
    return(ctxt->returnValue);
1491
}
1492
}
1492
 
1493
 
1493
char *
1494
char *
1494
RxmlNanoHTTPStatusMsg(void *ctx)
1495
RxmlNanoHTTPStatusMsg(void *ctx)
1495
{
1496
{
1496
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1497
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1497
    return(ctxt->statusMsg);
1498
    return(ctxt->statusMsg);
1498
}
1499
}
1499
 
1500
 
1500
int
1501
int
1501
RxmlNanoHTTPContentLength(void *ctx)
1502
RxmlNanoHTTPContentLength(void *ctx)
1502
{
1503
{
1503
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1504
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1504
 
1505
 
1505
    if (ctxt == NULL) return(-1);
1506
    if (ctxt == NULL) return(-1);
1506
 
1507
 
1507
    return(ctxt->contentLength);
1508
    return(ctxt->contentLength);
1508
}
1509
}
1509
 
1510
 
1510
char *
1511
char *
1511
RxmlNanoHTTPContentType(void *ctx)
1512
RxmlNanoHTTPContentType(void *ctx)
1512
{
1513
{
1513
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1514
    RxmlNanoHTTPCtxtPtr ctxt = (RxmlNanoHTTPCtxtPtr) ctx;
1514
    return(ctxt->contentType);
1515
    return(ctxt->contentType);
1515
}
1516
}
1516
#endif /* !Unix or BSD_NETWORKING */
1517
#endif /* !Unix or BSD_NETWORKING */