The R Project SVN R

Rev

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

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