version 1.1.1.1, 2012/02/21 23:16:22
|
version 1.1.1.2, 2013/07/22 00:36:10
|
Line 1
|
Line 1
|
/* $Id$ */ |
/* $Id$ */ |
/* Project : miniupnp |
/* Project : miniupnp |
|
* Website : http://miniupnp.free.fr/ |
* Author : Thomas Bernard |
* Author : Thomas Bernard |
* Copyright (c) 2005-2011 Thomas Bernard | * Copyright (c) 2005-2012 Thomas Bernard |
* This software is subject to the conditions detailed in the |
* This software is subject to the conditions detailed in the |
* LICENCE file provided in this distribution. */ |
* LICENCE file provided in this distribution. */ |
| |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <ctype.h> |
#include <ctype.h> |
#ifdef WIN32 | #ifdef _WIN32 |
#include <winsock2.h> |
#include <winsock2.h> |
#include <ws2tcpip.h> |
#include <ws2tcpip.h> |
#include <io.h> |
#include <io.h> |
Line 24
|
Line 25
|
#define strncasecmp memicmp |
#define strncasecmp memicmp |
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ |
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ |
#endif /* #ifndef strncasecmp */ |
#endif /* #ifndef strncasecmp */ |
#else /* #ifdef WIN32 */ | #else /* #ifdef _WIN32 */ |
#include <unistd.h> |
#include <unistd.h> |
#include <sys/param.h> |
#include <sys/param.h> |
#if defined(__amigaos__) && !defined(__amigaos4__) |
#if defined(__amigaos__) && !defined(__amigaos4__) |
Line 33
|
Line 34
|
#include <sys/select.h> |
#include <sys/select.h> |
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ |
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ |
#include <sys/socket.h> |
#include <sys/socket.h> |
|
#include <netinet/in.h> |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
|
#include <net/if.h> |
#include <netdb.h> |
#include <netdb.h> |
#define closesocket close |
#define closesocket close |
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions |
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions |
* during the connect() call */ |
* during the connect() call */ |
#define MINIUPNPC_IGNORE_EINTR |
#define MINIUPNPC_IGNORE_EINTR |
#endif /* #else WIN32 */ | #endif /* #else _WIN32 */ |
#if defined(__sun) || defined(sun) |
#if defined(__sun) || defined(sun) |
#define MIN(x,y) (((x)<(y))?(x):(y)) |
#define MIN(x,y) (((x)<(y))?(x):(y)) |
#endif |
#endif |
Line 67 getHTTPResponse(int s, int * size)
|
Line 70 getHTTPResponse(int s, int * size)
|
unsigned int bytestocopy = 0; |
unsigned int bytestocopy = 0; |
/* buffers : */ |
/* buffers : */ |
char * header_buf; |
char * header_buf; |
int header_buf_len = 2048; | unsigned int header_buf_len = 2048; |
int header_buf_used = 0; | unsigned int header_buf_used = 0; |
char * content_buf; |
char * content_buf; |
int content_buf_len = 2048; | unsigned int content_buf_len = 2048; |
int content_buf_used = 0; | unsigned int content_buf_used = 0; |
char chunksize_buf[32]; |
char chunksize_buf[32]; |
int chunksize_buf_index; | unsigned int chunksize_buf_index; |
|
|
header_buf = malloc(header_buf_len); |
header_buf = malloc(header_buf_len); |
content_buf = malloc(content_buf_len); |
content_buf = malloc(content_buf_len); |
chunksize_buf[0] = '\0'; |
chunksize_buf[0] = '\0'; |
chunksize_buf_index = 0; |
chunksize_buf_index = 0; |
|
|
while((n = receivedata(s, buf, 2048, 5000)) > 0) | while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) |
{ |
{ |
if(endofheaders == 0) |
if(endofheaders == 0) |
{ |
{ |
Line 97 getHTTPResponse(int s, int * size)
|
Line 100 getHTTPResponse(int s, int * size)
|
/* search for CR LF CR LF (end of headers) |
/* search for CR LF CR LF (end of headers) |
* recognize also LF LF */ |
* recognize also LF LF */ |
i = 0; |
i = 0; |
while(i < (header_buf_used-1) && (endofheaders == 0)) { | while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { |
if(header_buf[i] == '\r') { |
if(header_buf[i] == '\r') { |
i++; |
i++; |
if(header_buf[i] == '\n') { |
if(header_buf[i] == '\n') { |
i++; |
i++; |
if(i < header_buf_used && header_buf[i] == '\r') { | if(i < (int)header_buf_used && header_buf[i] == '\r') { |
i++; |
i++; |
if(i < header_buf_used && header_buf[i] == '\n') { | if(i < (int)header_buf_used && header_buf[i] == '\n') { |
endofheaders = i+1; |
endofheaders = i+1; |
} |
} |
} |
} |
Line 160 getHTTPResponse(int s, int * size)
|
Line 163 getHTTPResponse(int s, int * size)
|
linestart = i; |
linestart = i; |
colon = linestart; |
colon = linestart; |
valuestart = 0; |
valuestart = 0; |
} | } |
} |
} |
/* copy the remaining of the received data back to buf */ |
/* copy the remaining of the received data back to buf */ |
n = header_buf_used - endofheaders; |
n = header_buf_used - endofheaders; |
Line 194 getHTTPResponse(int s, int * size)
|
Line 197 getHTTPResponse(int s, int * size)
|
i++; /* discarding chunk-extension */ |
i++; /* discarding chunk-extension */ |
if(i<n && buf[i] == '\r') i++; |
if(i<n && buf[i] == '\r') i++; |
if(i<n && buf[i] == '\n') { |
if(i<n && buf[i] == '\n') { |
int j; | unsigned int j; |
for(j = 0; j < chunksize_buf_index; j++) { |
for(j = 0; j < chunksize_buf_index; j++) { |
if(chunksize_buf[j] >= '0' |
if(chunksize_buf[j] >= '0' |
&& chunksize_buf[j] <= '9') |
&& chunksize_buf[j] <= '9') |
Line 221 getHTTPResponse(int s, int * size)
|
Line 224 getHTTPResponse(int s, int * size)
|
goto end_of_stream; |
goto end_of_stream; |
} |
} |
} |
} |
bytestocopy = ((int)chunksize < n - i)?chunksize:(n - i); | bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); |
if((int)(content_buf_used + bytestocopy) > content_buf_len) | if((content_buf_used + bytestocopy) > content_buf_len) |
{ |
{ |
if(content_length >= content_buf_used + (int)bytestocopy) { | if(content_length >= (int)(content_buf_used + bytestocopy)) { |
content_buf_len = content_length; |
content_buf_len = content_length; |
} else { |
} else { |
content_buf_len = content_buf_used + (int)bytestocopy; | content_buf_len = content_buf_used + bytestocopy; |
} |
} |
content_buf = (char *)realloc((void *)content_buf, | content_buf = (char *)realloc((void *)content_buf, |
content_buf_len); |
content_buf_len); |
} |
} |
memcpy(content_buf + content_buf_used, buf + i, bytestocopy); |
memcpy(content_buf + content_buf_used, buf + i, bytestocopy); |
Line 242 getHTTPResponse(int s, int * size)
|
Line 245 getHTTPResponse(int s, int * size)
|
{ |
{ |
/* not chunked */ |
/* not chunked */ |
if(content_length > 0 |
if(content_length > 0 |
&& (content_buf_used + n) > content_length) { | && (int)(content_buf_used + n) > content_length) { |
/* skipping additional bytes */ |
/* skipping additional bytes */ |
n = content_length - content_buf_used; |
n = content_length - content_buf_used; |
} |
} |
if(content_buf_used + n > content_buf_len) |
if(content_buf_used + n > content_buf_len) |
{ |
{ |
if(content_length >= content_buf_used + n) { | if(content_length >= (int)(content_buf_used + n)) { |
content_buf_len = content_length; |
content_buf_len = content_length; |
} else { |
} else { |
content_buf_len = content_buf_used + n; |
content_buf_len = content_buf_used + n; |
} |
} |
content_buf = (char *)realloc((void *)content_buf, | content_buf = (char *)realloc((void *)content_buf, |
content_buf_len); |
content_buf_len); |
} |
} |
memcpy(content_buf + content_buf_used, buf, n); |
memcpy(content_buf + content_buf_used, buf, n); |
Line 261 getHTTPResponse(int s, int * size)
|
Line 264 getHTTPResponse(int s, int * size)
|
} |
} |
} |
} |
/* use the Content-Length header value if available */ |
/* use the Content-Length header value if available */ |
if(content_length > 0 && content_buf_used >= content_length) | if(content_length > 0 && (int)content_buf_used >= content_length) |
{ |
{ |
#ifdef DEBUG |
#ifdef DEBUG |
printf("End of HTTP content\n"); |
printf("End of HTTP content\n"); |
Line 284 end_of_stream:
|
Line 287 end_of_stream:
|
* do all the work. |
* do all the work. |
* Return NULL if something failed. */ |
* Return NULL if something failed. */ |
static void * |
static void * |
miniwget3(const char * url, const char * host, | miniwget3(const char * host, |
unsigned short port, const char * path, |
unsigned short port, const char * path, |
int * size, char * addr_str, int addr_str_len, |
int * size, char * addr_str, int addr_str_len, |
const char * httpversion) | const char * httpversion, unsigned int scope_id) |
{ |
{ |
char buf[2048]; |
char buf[2048]; |
int s; |
int s; |
Line 297 miniwget3(const char * url, const char * host,
|
Line 300 miniwget3(const char * url, const char * host,
|
void * content; |
void * content; |
|
|
*size = 0; |
*size = 0; |
s = connecthostport(host, port); | s = connecthostport(host, port, scope_id); |
if(s < 0) |
if(s < 0) |
return NULL; |
return NULL; |
|
|
Line 343 miniwget3(const char * url, const char * host,
|
Line 346 miniwget3(const char * url, const char * host,
|
NULL, 0, |
NULL, 0, |
NI_NUMERICHOST | NI_NUMERICSERV); |
NI_NUMERICHOST | NI_NUMERICSERV); |
if(n != 0) { |
if(n != 0) { |
#ifdef WIN32 | #ifdef _WIN32 |
fprintf(stderr, "getnameinfo() failed : %d\n", n); |
fprintf(stderr, "getnameinfo() failed : %d\n", n); |
#else |
#else |
fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); |
fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); |
Line 388 miniwget3(const char * url, const char * host,
|
Line 391 miniwget3(const char * url, const char * host,
|
/* miniwget2() : |
/* miniwget2() : |
* Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ |
* Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ |
static void * |
static void * |
miniwget2(const char * url, const char * host, | miniwget2(const char * host, |
unsigned short port, const char * path, |
unsigned short port, const char * path, |
int * size, char * addr_str, int addr_str_len) | int * size, char * addr_str, int addr_str_len, |
| unsigned int scope_id) |
{ |
{ |
char * respbuffer; |
char * respbuffer; |
|
|
respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); | #if 1 |
/* | respbuffer = miniwget3(host, port, path, size, |
respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.0"); | addr_str, addr_str_len, "1.1", scope_id); |
| #else |
| respbuffer = miniwget3(host, port, path, size, |
| addr_str, addr_str_len, "1.0", scope_id); |
if (*size == 0) |
if (*size == 0) |
{ |
{ |
#ifdef DEBUG |
#ifdef DEBUG |
printf("Retrying with HTTP/1.1\n"); |
printf("Retrying with HTTP/1.1\n"); |
#endif |
#endif |
free(respbuffer); |
free(respbuffer); |
respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); | respbuffer = miniwget3(host, port, path, size, |
| addr_str, addr_str_len, "1.1", scope_id); |
} |
} |
*/ | #endif |
return respbuffer; |
return respbuffer; |
} |
} |
|
|
Line 417 miniwget2(const char * url, const char * host,
|
Line 425 miniwget2(const char * url, const char * host,
|
* url : source string not modified |
* url : source string not modified |
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1) |
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1) |
* port : port (destination) |
* port : port (destination) |
* path : pointer to the path part of the URL | * path : pointer to the path part of the URL |
* |
* |
* Return values : |
* Return values : |
* 0 - Failure |
* 0 - Failure |
* 1 - Success */ |
* 1 - Success */ |
int parseURL(const char * url, char * hostname, unsigned short * port, char * * path) | int |
| parseURL(const char * url, |
| char * hostname, unsigned short * port, |
| char * * path, unsigned int * scope_id) |
{ |
{ |
char * p1, *p2, *p3; |
char * p1, *p2, *p3; |
if(!url) |
if(!url) |
Line 438 int parseURL(const char * url, char * hostname, unsign
|
Line 449 int parseURL(const char * url, char * hostname, unsign
|
if(*p1 == '[') |
if(*p1 == '[') |
{ |
{ |
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ |
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ |
|
char * scope; |
|
scope = strchr(p1, '%'); |
p2 = strchr(p1, ']'); |
p2 = strchr(p1, ']'); |
|
if(p2 && scope && scope < p2 && scope_id) { |
|
/* parse scope */ |
|
#ifdef IF_NAMESIZE |
|
char tmp[IF_NAMESIZE]; |
|
int l; |
|
scope++; |
|
/* "%25" is just '%' in URL encoding */ |
|
if(scope[0] == '2' && scope[1] == '5') |
|
scope += 2; /* skip "25" */ |
|
l = p2 - scope; |
|
if(l >= IF_NAMESIZE) |
|
l = IF_NAMESIZE - 1; |
|
memcpy(tmp, scope, l); |
|
tmp[l] = '\0'; |
|
*scope_id = if_nametoindex(tmp); |
|
if(*scope_id == 0) { |
|
*scope_id = (unsigned int)strtoul(tmp, NULL, 10); |
|
} |
|
#else |
|
/* under windows, scope is numerical */ |
|
char tmp[8]; |
|
int l; |
|
scope++; |
|
/* "%25" is just '%' in URL encoding */ |
|
if(scope[0] == '2' && scope[1] == '5') |
|
scope += 2; /* skip "25" */ |
|
l = p2 - scope; |
|
if(l >= sizeof(tmp)) |
|
l = sizeof(tmp) - 1; |
|
memcpy(tmp, scope, l); |
|
tmp[l] = '\0'; |
|
*scope_id = (unsigned int)strtoul(tmp, NULL, 10); |
|
#endif |
|
} |
p3 = strchr(p1, '/'); |
p3 = strchr(p1, '/'); |
if(p2 && p3) |
if(p2 && p3) |
{ |
{ |
Line 488 int parseURL(const char * url, char * hostname, unsign
|
Line 535 int parseURL(const char * url, char * hostname, unsign
|
return 1; |
return 1; |
} |
} |
|
|
void * miniwget(const char * url, int * size) | void * |
| miniwget(const char * url, int * size, unsigned int scope_id) |
{ |
{ |
unsigned short port; |
unsigned short port; |
char * path; |
char * path; |
/* protocol://host:port/chemin */ |
/* protocol://host:port/chemin */ |
char hostname[MAXHOSTNAMELEN+1]; |
char hostname[MAXHOSTNAMELEN+1]; |
*size = 0; |
*size = 0; |
if(!parseURL(url, hostname, &port, &path)) | if(!parseURL(url, hostname, &port, &path, &scope_id)) |
return NULL; |
return NULL; |
#ifdef DEBUG |
#ifdef DEBUG |
printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); | printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", |
| hostname, port, path, scope_id); |
#endif |
#endif |
return miniwget2(url, hostname, port, path, size, 0, 0); | return miniwget2(hostname, port, path, size, 0, 0, scope_id); |
} |
} |
|
|
void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen) | void * |
| miniwget_getaddr(const char * url, int * size, |
| char * addr, int addrlen, unsigned int scope_id) |
{ |
{ |
unsigned short port; |
unsigned short port; |
char * path; |
char * path; |
/* protocol://host:port/chemin */ | /* protocol://host:port/path */ |
char hostname[MAXHOSTNAMELEN+1]; |
char hostname[MAXHOSTNAMELEN+1]; |
*size = 0; |
*size = 0; |
if(addr) |
if(addr) |
addr[0] = '\0'; |
addr[0] = '\0'; |
if(!parseURL(url, hostname, &port, &path)) | if(!parseURL(url, hostname, &port, &path, &scope_id)) |
return NULL; |
return NULL; |
#ifdef DEBUG |
#ifdef DEBUG |
printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); | printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", |
| hostname, port, path, scope_id); |
#endif |
#endif |
return miniwget2(url, hostname, port, path, size, addr, addrlen); | return miniwget2(hostname, port, path, size, addr, addrlen, scope_id); |
} |
} |
|
|