[WININET]

* Sync with Wine 1.7.1.
CORE-7469

svn path=/trunk/; revision=60428
This commit is contained in:
Amine Khaldi 2013-09-28 15:25:41 +00:00
parent 7ac948cd02
commit 3c2b97abe0
10 changed files with 2290 additions and 2663 deletions

View file

@ -20,13 +20,10 @@ list(APPEND SOURCE
urlcache.c urlcache.c
utility.c utility.c
wininet_main.c wininet_main.c
rsrc.rc
version.rc
${CMAKE_CURRENT_BINARY_DIR}/wininet_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/wininet_stubs.c
${CMAKE_CURRENT_BINARY_DIR}/wininet.def) ${CMAKE_CURRENT_BINARY_DIR}/wininet.def)
add_library(wininet SHARED ${SOURCE}) add_library(wininet SHARED ${SOURCE} rsrc.rc)
set_module_type(wininet win32dll) set_module_type(wininet win32dll)
target_link_libraries(wininet wine ${PSEH_LIB} zlib) target_link_libraries(wininet wine ${PSEH_LIB} zlib)
add_delay_importlibs(wininet secur32 crypt32 cryptui) add_delay_importlibs(wininet secur32 crypt32 cryptui)

View file

@ -238,6 +238,7 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
heap_free(name); heap_free(name);
heap_free(data); heap_free(data);
} }
heap_free(str);
heap_free(name); heap_free(name);
heap_free(data); heap_free(data);
@ -537,8 +538,11 @@ static void COOKIE_deleteDomain(cookie_domain *deadDomain)
DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size) DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size)
{ {
static const WCHAR empty_path[] = { '/',0 };
unsigned cnt = 0, len, name_len, domain_count = 0, cookie_count = 0; unsigned cnt = 0, len, name_len, domain_count = 0, cookie_count = 0;
WCHAR *ptr = cookie_data; WCHAR *ptr, subpath[INTERNET_MAX_PATH_LENGTH];
const WCHAR *p;
cookie_domain *domain; cookie_domain *domain;
FILETIME tm; FILETIME tm;
@ -546,8 +550,30 @@ DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD
EnterCriticalSection(&cookie_cs); EnterCriticalSection(&cookie_cs);
load_persistent_cookie(host, path); len = strlenW(host);
p = host+len;
while(p>host && p[-1]!='.') p--;
while(p != host) {
p--;
while(p>host && p[-1]!='.') p--;
if(p == host) break;
load_persistent_cookie(p, empty_path);
}
len = strlenW(path);
assert(len+1 < INTERNET_MAX_PATH_LENGTH);
memcpy(subpath, path, (len+1)*sizeof(WCHAR));
ptr = subpath+len;
do {
*ptr = 0;
load_persistent_cookie(host, subpath);
ptr--;
while(ptr>subpath && ptr[-1]!='/') ptr--;
}while(ptr != subpath);
ptr = cookie_data;
LIST_FOR_EACH_ENTRY(domain, &domain_list, cookie_domain, entry) { LIST_FOR_EACH_ENTRY(domain, &domain_list, cookie_domain, entry) {
struct list *cursor, *cursor2; struct list *cursor, *cursor2;

View file

@ -148,6 +148,8 @@ static const WCHAR szVia[] = { 'V','i','a',0 };
static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
static const WCHAR emptyW[] = {0};
#define HTTP_REFERER szReferer #define HTTP_REFERER szReferer
#define HTTP_ACCEPT szAccept #define HTTP_ACCEPT szAccept
#define HTTP_USERAGENT szUser_Agent #define HTTP_USERAGENT szUser_Agent
@ -214,7 +216,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
}; };
static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear); static DWORD HTTP_GetResponseHeaders(http_request_t *req, INT *len);
static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier); static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr); static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
@ -597,62 +599,10 @@ static DWORD init_gzip_stream(http_request_t *req)
#endif #endif
/***********************************************************************
* HTTP_Tokenize (internal)
*
* Tokenize a string, allocating memory for the tokens.
*/
static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
{
LPWSTR * token_array;
int tokens = 0;
int i;
LPCWSTR next_token;
if (string)
{
/* empty string has no tokens */
if (*string)
tokens++;
/* count tokens */
for (i = 0; string[i]; i++)
{
if (!strncmpW(string+i, token_string, strlenW(token_string)))
{
DWORD j;
tokens++;
/* we want to skip over separators, but not the null terminator */
for (j = 0; j < strlenW(token_string) - 1; j++)
if (!string[i+j])
break;
i += j;
}
}
}
/* add 1 for terminating NULL */
token_array = heap_alloc((tokens+1) * sizeof(*token_array));
token_array[tokens] = NULL;
if (!tokens)
return token_array;
for (i = 0; i < tokens; i++)
{
int len;
next_token = strstrW(string, token_string);
if (!next_token) next_token = string+strlenW(string);
len = next_token - string;
token_array[i] = heap_alloc((len+1)*sizeof(WCHAR));
memcpy(token_array[i], string, len*sizeof(WCHAR));
token_array[i][len] = '\0';
string = next_token+strlenW(token_string);
}
return token_array;
}
/*********************************************************************** /***********************************************************************
* HTTP_FreeTokens (internal) * HTTP_FreeTokens (internal)
* *
* Frees memory returned from HTTP_Tokenize. * Frees table of pointers.
*/ */
static void HTTP_FreeTokens(LPWSTR * token_array) static void HTTP_FreeTokens(LPWSTR * token_array)
{ {
@ -696,20 +646,21 @@ static void HTTP_FixURL(http_request_t *request)
} }
} }
static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) static WCHAR* build_request_header(http_request_t *request, const WCHAR *verb,
const WCHAR *path, const WCHAR *version, BOOL use_cr)
{ {
LPWSTR requestString; LPWSTR requestString;
DWORD len, n; DWORD len, n;
LPCWSTR *req; LPCWSTR *req;
UINT i; UINT i;
LPWSTR p;
static const WCHAR szSpace[] = { ' ',0 }; static const WCHAR szSpace[] = { ' ',0 };
static const WCHAR szColon[] = { ':',' ',0 }; static const WCHAR szColon[] = { ':',' ',0 };
static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; static const WCHAR szCr[] = { '\r',0 };
static const WCHAR szLf[] = { '\n',0 };
/* allocate space for an array of all the string pointers to be added */ /* allocate space for an array of all the string pointers to be added */
len = (request->nCustHeaders)*4 + 10; len = (request->nCustHeaders)*5 + 10;
req = heap_alloc(len*sizeof(LPCWSTR)); req = heap_alloc(len*sizeof(LPCWSTR));
/* add the verb, path and HTTP version string */ /* add the verb, path and HTTP version string */
@ -719,42 +670,90 @@ static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR ve
req[n++] = path; req[n++] = path;
req[n++] = szSpace; req[n++] = szSpace;
req[n++] = version; req[n++] = version;
if (use_cr)
req[n++] = szCr;
req[n++] = szLf;
/* Append custom request headers */ /* Append custom request headers */
for (i = 0; i < request->nCustHeaders; i++) for (i = 0; i < request->nCustHeaders; i++)
{ {
if (request->custHeaders[i].wFlags & HDR_ISREQUEST) if (request->custHeaders[i].wFlags & HDR_ISREQUEST)
{ {
req[n++] = szCrLf;
req[n++] = request->custHeaders[i].lpszField; req[n++] = request->custHeaders[i].lpszField;
req[n++] = szColon; req[n++] = szColon;
req[n++] = request->custHeaders[i].lpszValue; req[n++] = request->custHeaders[i].lpszValue;
if (use_cr)
req[n++] = szCr;
req[n++] = szLf;
TRACE("Adding custom header %s (%s)\n", TRACE("Adding custom header %s (%s)\n",
debugstr_w(request->custHeaders[i].lpszField), debugstr_w(request->custHeaders[i].lpszField),
debugstr_w(request->custHeaders[i].lpszValue)); debugstr_w(request->custHeaders[i].lpszValue));
} }
} }
if (use_cr)
if( n >= len ) req[n++] = szCr;
ERR("oops. buffer overrun\n"); req[n++] = szLf;
req[n] = NULL; req[n] = NULL;
requestString = HTTP_build_req( req, 4 ); requestString = HTTP_build_req( req, 4 );
heap_free( req ); heap_free( req );
/*
* Set (header) termination string for request
* Make sure there's exactly two new lines at the end of the request
*/
p = &requestString[strlenW(requestString)-1];
while ( (*p == '\n') || (*p == '\r') )
p--;
strcpyW( p+1, sztwocrlf );
return requestString; return requestString;
} }
static WCHAR* build_response_header(http_request_t *request, BOOL use_cr)
{
static const WCHAR colonW[] = { ':',' ',0 };
static const WCHAR crW[] = { '\r',0 };
static const WCHAR lfW[] = { '\n',0 };
static const WCHAR status_fmt[] = { ' ','%','u',' ',0 };
const WCHAR **req;
WCHAR *ret, buf[14];
DWORD i, n = 0;
req = heap_alloc((request->nCustHeaders*5+8)*sizeof(WCHAR*));
if(!req)
return NULL;
if (request->status_code)
{
req[n++] = request->version;
sprintfW(buf, status_fmt, request->status_code);
req[n++] = buf;
req[n++] = request->statusText;
if (use_cr)
req[n++] = crW;
req[n++] = lfW;
}
for(i = 0; i < request->nCustHeaders; i++)
{
if(!(request->custHeaders[i].wFlags & HDR_ISREQUEST)
&& strcmpW(request->custHeaders[i].lpszField, szStatus))
{
req[n++] = request->custHeaders[i].lpszField;
req[n++] = colonW;
req[n++] = request->custHeaders[i].lpszValue;
if(use_cr)
req[n++] = crW;
req[n++] = lfW;
TRACE("Adding custom header %s (%s)\n",
debugstr_w(request->custHeaders[i].lpszField),
debugstr_w(request->custHeaders[i].lpszValue));
}
}
if(use_cr)
req[n++] = crW;
req[n++] = lfW;
req[n] = NULL;
ret = HTTP_build_req(req, 0);
heap_free(req);
return ret;
}
static void HTTP_ProcessCookies( http_request_t *request ) static void HTTP_ProcessCookies( http_request_t *request )
{ {
int HeaderIndex; int HeaderIndex;
@ -1714,6 +1713,88 @@ static WCHAR *build_proxy_path_url(http_request_t *req)
return url; return url;
} }
static BOOL HTTP_DomainMatches(LPCWSTR server, LPCWSTR domain)
{
static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
BOOL ret = FALSE;
if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
ret = TRUE;
else if (*domain == '*')
{
if (domain[1] == '.')
{
LPCWSTR dot;
/* For a hostname to match a wildcard, the last domain must match
* the wildcard exactly. E.g. if the wildcard is *.a.b, and the
* hostname is www.foo.a.b, it matches, but a.b does not.
*/
dot = strchrW( server, '.' );
if (dot)
{
int len = strlenW( dot + 1 );
if (len > strlenW( domain + 2 ))
{
LPCWSTR ptr;
/* The server's domain is longer than the wildcard, so it
* could be a subdomain. Compare the last portion of the
* server's domain.
*/
ptr = dot + len + 1 - strlenW( domain + 2 );
if (!strcmpiW( ptr, domain + 2 ))
{
/* This is only a match if the preceding character is
* a '.', i.e. that it is a matching domain. E.g.
* if domain is '*.b.c' and server is 'www.ab.c' they
* do not match.
*/
ret = *(ptr - 1) == '.';
}
}
else
ret = !strcmpiW( dot + 1, domain + 2 );
}
}
}
else
ret = !strcmpiW( server, domain );
return ret;
}
static BOOL HTTP_ShouldBypassProxy(appinfo_t *lpwai, LPCWSTR server)
{
LPCWSTR ptr;
BOOL ret = FALSE;
if (!lpwai->proxyBypass) return FALSE;
ptr = lpwai->proxyBypass;
do {
LPCWSTR tmp = ptr;
ptr = strchrW( ptr, ';' );
if (!ptr)
ptr = strchrW( tmp, ' ' );
if (ptr)
{
if (ptr - tmp < INTERNET_MAX_HOST_NAME_LENGTH)
{
WCHAR domain[INTERNET_MAX_HOST_NAME_LENGTH];
memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
domain[ptr - tmp] = 0;
ret = HTTP_DomainMatches( server, domain );
}
ptr += 1;
}
else if (*tmp)
ret = HTTP_DomainMatches( server, tmp );
} while (ptr && !ret);
return ret;
}
/*********************************************************************** /***********************************************************************
* HTTP_DealWithProxy * HTTP_DealWithProxy
*/ */
@ -1863,7 +1944,6 @@ static void HTTPREQ_Destroy(object_header_t *hdr)
heap_free(request->path); heap_free(request->path);
heap_free(request->verb); heap_free(request->verb);
heap_free(request->rawHeaders);
heap_free(request->version); heap_free(request->version);
heap_free(request->statusText); heap_free(request->statusText);
@ -1965,6 +2045,45 @@ static void HTTPREQ_CloseConnection(object_header_t *hdr)
http_release_netconn(req, drain_content(req, FALSE)); http_release_netconn(req, drain_content(req, FALSE));
} }
static DWORD str_to_buffer(const WCHAR *str, void *buffer, DWORD *size, BOOL unicode)
{
int len;
if (unicode)
{
WCHAR *buf = buffer;
if (str) len = strlenW(str);
else len = 0;
if (*size < (len + 1) * sizeof(WCHAR))
{
*size = (len + 1) * sizeof(WCHAR);
return ERROR_INSUFFICIENT_BUFFER;
}
if (str) strcpyW(buf, str);
else buf[0] = 0;
*size = len;
return ERROR_SUCCESS;
}
else
{
char *buf = buffer;
if (str) len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
else len = 1;
if (*size < len)
{
*size = len;
return ERROR_INSUFFICIENT_BUFFER;
}
if (str) WideCharToMultiByte(CP_ACP, 0, str, -1, buf, *size, NULL, NULL);
else buf[0] = 0;
*size = len - 1;
return ERROR_SUCCESS;
}
}
static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
{ {
http_request_t *req = (http_request_t*)hdr; http_request_t *req = (http_request_t*)hdr;
@ -1991,7 +2110,7 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
info->Flags |= IDSI_FLAG_KEEP_ALIVE; info->Flags |= IDSI_FLAG_KEEP_ALIVE;
if (req->proxy) if (req->proxy)
info->Flags |= IDSI_FLAG_PROXY; info->Flags |= IDSI_FLAG_PROXY;
if (req->netconn->secure) if (req->netconn && req->netconn->secure)
info->Flags |= IDSI_FLAG_SECURE; info->Flags |= IDSI_FLAG_SECURE;
return ERROR_SUCCESS; return ERROR_SUCCESS;
@ -2028,8 +2147,6 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
case INTERNET_OPTION_URL: { case INTERNET_OPTION_URL: {
WCHAR url[INTERNET_MAX_URL_LENGTH]; WCHAR url[INTERNET_MAX_URL_LENGTH];
HTTPHEADERW *host; HTTPHEADERW *host;
DWORD len;
WCHAR *pch;
static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
@ -2038,29 +2155,21 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
host = HTTP_GetHeader(req, hostW); host = HTTP_GetHeader(req, hostW);
strcpyW(url, httpW); strcpyW(url, httpW);
strcatW(url, host->lpszValue); strcatW(url, host->lpszValue);
if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
*pch = 0;
strcatW(url, req->path); strcatW(url, req->path);
TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url)); TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
return str_to_buffer(url, buffer, size, unicode);
if(unicode) {
len = (strlenW(url)+1) * sizeof(WCHAR);
if(*size < len)
return ERROR_INSUFFICIENT_BUFFER;
*size = len;
strcpyW(buffer, url);
return ERROR_SUCCESS;
}else {
len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
if(len > *size)
return ERROR_INSUFFICIENT_BUFFER;
*size = len;
return ERROR_SUCCESS;
}
} }
case INTERNET_OPTION_USER_AGENT:
return str_to_buffer(req->session->appInfo->agent, buffer, size, unicode);
case INTERNET_OPTION_USERNAME:
return str_to_buffer(req->session->userName, buffer, size, unicode);
case INTERNET_OPTION_PASSWORD:
return str_to_buffer(req->session->password, buffer, size, unicode);
case INTERNET_OPTION_PROXY_USERNAME:
return str_to_buffer(req->session->appInfo->proxyUsername, buffer, size, unicode);
case INTERNET_OPTION_PROXY_PASSWORD:
return str_to_buffer(req->session->appInfo->proxyPassword, buffer, size, unicode);
case INTERNET_OPTION_CACHE_TIMESTAMPS: { case INTERNET_OPTION_CACHE_TIMESTAMPS: {
INTERNET_CACHE_ENTRY_INFOW *info; INTERNET_CACHE_ENTRY_INFOW *info;
@ -2129,6 +2238,9 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: { case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
PCCERT_CONTEXT context; PCCERT_CONTEXT context;
if(!req->netconn)
return ERROR_INTERNET_INVALID_OPERATION;
if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) { if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) {
*size = sizeof(INTERNET_CERTIFICATE_INFOA); *size = sizeof(INTERNET_CERTIFICATE_INFOA);
return ERROR_INSUFFICIENT_BUFFER; return ERROR_INSUFFICIENT_BUFFER;
@ -2182,7 +2294,7 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
if(req->proxy) if(req->proxy)
flags |= INTERNET_REQFLAG_VIA_PROXY; flags |= INTERNET_REQFLAG_VIA_PROXY;
if(!req->rawHeaders) if(!req->status_code)
flags |= INTERNET_REQFLAG_NO_HEADERS; flags |= INTERNET_REQFLAG_NO_HEADERS;
TRACE("INTERNET_OPTION_REQUEST_FLAGS returning %x\n", flags); TRACE("INTERNET_OPTION_REQUEST_FLAGS returning %x\n", flags);
@ -2248,6 +2360,17 @@ static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer,
heap_free(req->session->password); heap_free(req->session->password);
if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS; return ERROR_SUCCESS;
case INTERNET_OPTION_PROXY_USERNAME:
heap_free(req->session->appInfo->proxyUsername);
if (!(req->session->appInfo->proxyUsername = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
case INTERNET_OPTION_PROXY_PASSWORD:
heap_free(req->session->appInfo->proxyPassword);
if (!(req->session->appInfo->proxyPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
case INTERNET_OPTION_HTTP_DECODING: case INTERNET_OPTION_HTTP_DECODING:
if(size != sizeof(BOOL)) if(size != sizeof(BOOL))
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
@ -2268,12 +2391,15 @@ static void commit_cache_entry(http_request_t *req)
req->hCacheFile = NULL; req->hCacheFile = NULL;
if(HTTP_GetRequestURL(req, url)) { if(HTTP_GetRequestURL(req, url)) {
DWORD headersLen; WCHAR *header;
DWORD header_len;
headersLen = req->rawHeaders ? strlenW(req->rawHeaders) : 0; header = build_response_header(req, TRUE);
header_len = (header ? strlenW(header) : 0);
CommitUrlCacheEntryW(url, req->cacheFile, req->expires, CommitUrlCacheEntryW(url, req->cacheFile, req->expires,
req->last_modified, NORMAL_CACHE_ENTRY, req->last_modified, NORMAL_CACHE_ENTRY,
req->rawHeaders, headersLen, NULL, 0); header, header_len, NULL, 0);
heap_free(header);
} }
} }
@ -2296,9 +2422,30 @@ static void create_cache_entry(http_request_t *req)
if(b) { if(b) {
int header_idx = HTTP_GetCustomHeaderIndex(req, szCache_Control, 0, FALSE); int header_idx = HTTP_GetCustomHeaderIndex(req, szCache_Control, 0, FALSE);
if(header_idx!=-1 && (!strcmpiW(req->custHeaders[header_idx].lpszValue, no_cacheW) if(header_idx != -1) {
|| !strcmpiW(req->custHeaders[header_idx].lpszValue, no_storeW))) WCHAR *ptr;
for(ptr=req->custHeaders[header_idx].lpszValue; *ptr; ) {
WCHAR *end;
while(*ptr==' ' || *ptr=='\t')
ptr++;
end = strchrW(ptr, ',');
if(!end)
end = ptr + strlenW(ptr);
if(!strncmpiW(ptr, no_cacheW, sizeof(no_cacheW)/sizeof(*no_cacheW)-1)
|| !strncmpiW(ptr, no_storeW, sizeof(no_storeW)/sizeof(*no_storeW)-1)) {
b = FALSE; b = FALSE;
break;
}
ptr = end;
if(*ptr == ',')
ptr++;
}
}
} }
if(!b) { if(!b) {
@ -2372,7 +2519,7 @@ static void remove_data( http_request_t *req, int count )
else req->read_pos += count; else req->read_pos += count;
} }
static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) static DWORD read_line( http_request_t *req, LPSTR buffer, DWORD *len )
{ {
int count, bytes_read, pos = 0; int count, bytes_read, pos = 0;
DWORD res; DWORD res;
@ -2395,13 +2542,18 @@ static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
remove_data( req, bytes_read ); remove_data( req, bytes_read );
if (eol) break; if (eol) break;
if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size) if ((res = read_more_data( req, -1 )))
{
WARN( "read failed %u\n", res );
LeaveCriticalSection( &req->read_section );
return res;
}
if (!req->read_size)
{ {
*len = 0; *len = 0;
TRACE( "returning empty string %u\n", res); TRACE( "returning empty string\n" );
LeaveCriticalSection( &req->read_section ); LeaveCriticalSection( &req->read_section );
INTERNET_SetLastError(res); return ERROR_SUCCESS;
return FALSE;
} }
} }
LeaveCriticalSection( &req->read_section ); LeaveCriticalSection( &req->read_section );
@ -2413,7 +2565,7 @@ static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
} }
buffer[*len - 1] = 0; buffer[*len - 1] = 0;
TRACE( "returning %s\n", debugstr_a(buffer)); TRACE( "returning %s\n", debugstr_a(buffer));
return TRUE; return ERROR_SUCCESS;
} }
/* check if we have reached the end of the data to read (the read section must be held) */ /* check if we have reached the end of the data to read (the read section must be held) */
@ -2498,6 +2650,7 @@ static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf,
DWORD *read, read_mode_t read_mode) DWORD *read, read_mode_t read_mode)
{ {
netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
DWORD res = ERROR_SUCCESS;
int len = 0; int len = 0;
size = min(size, netconn_stream->content_length-netconn_stream->content_read); size = min(size, netconn_stream->content_length-netconn_stream->content_read);
@ -2509,7 +2662,7 @@ static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf,
} }
if(size && req->netconn) { if(size && req->netconn) {
if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS) if((res = NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len)))
len = 0; len = 0;
if(!len) if(!len)
netconn_stream->content_length = netconn_stream->content_read; netconn_stream->content_length = netconn_stream->content_read;
@ -2517,7 +2670,7 @@ static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf,
netconn_stream->content_read += *read = len; netconn_stream->content_read += *read = len;
TRACE("read %u bytes\n", len); TRACE("read %u bytes\n", len);
return ERROR_SUCCESS; return res;
} }
static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req) static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req)
@ -2787,9 +2940,11 @@ static DWORD set_content_length(http_request_t *request)
static const WCHAR gzipW[] = {'g','z','i','p',0}; static const WCHAR gzipW[] = {'g','z','i','p',0};
encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE); encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE);
if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW)) if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW)) {
HTTP_DeleteCustomHeader(request, encoding_idx);
return init_gzip_stream(request); return init_gzip_stream(request);
} }
}
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
@ -3205,7 +3360,7 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
if (session->hostPort == INTERNET_INVALID_PORT_NUMBER) if (session->hostPort == INTERNET_INVALID_PORT_NUMBER)
session->hostPort = INTERNET_DEFAULT_HTTP_PORT; session->hostPort = INTERNET_DEFAULT_HTTP_PORT;
if (hIC->proxy && hIC->proxy[0]) if (hIC->proxy && hIC->proxy[0] && !HTTP_ShouldBypassProxy(hIC, session->hostName))
HTTP_DealWithProxy( hIC, session, request ); HTTP_DealWithProxy( hIC, session, request );
INTERNET_SendCallback(&session->hdr, dwContext, INTERNET_SendCallback(&session->hdr, dwContext,
@ -3382,13 +3537,13 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
DWORD res = ERROR_INVALID_PARAMETER; DWORD res = ERROR_INVALID_PARAMETER;
if (request_only) if (request_only)
headers = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); headers = build_request_header(request, request->verb, request->path, request->version, TRUE);
else else
headers = request->rawHeaders; headers = build_response_header(request, TRUE);
if (!headers)
return ERROR_OUTOFMEMORY;
if (headers)
len = strlenW(headers) * sizeof(WCHAR); len = strlenW(headers) * sizeof(WCHAR);
if (len + sizeof(WCHAR) > *lpdwBufferLength) if (len + sizeof(WCHAR) > *lpdwBufferLength)
{ {
len += sizeof(WCHAR); len += sizeof(WCHAR);
@ -3396,50 +3551,51 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
} }
else if (lpBuffer) else if (lpBuffer)
{ {
if (headers)
memcpy(lpBuffer, headers, len + sizeof(WCHAR)); memcpy(lpBuffer, headers, len + sizeof(WCHAR));
else
{
len = strlenW(szCrLf) * sizeof(WCHAR);
memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
}
TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR))); TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
res = ERROR_SUCCESS; res = ERROR_SUCCESS;
} }
*lpdwBufferLength = len; *lpdwBufferLength = len;
if (request_only) heap_free(headers); heap_free(headers);
return res; return res;
} }
case HTTP_QUERY_RAW_HEADERS: case HTTP_QUERY_RAW_HEADERS:
{ {
LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(request->rawHeaders, szCrLf); LPWSTR headers;
DWORD i, size = 0; DWORD len;
LPWSTR pszString = lpBuffer;
for (i = 0; ppszRawHeaderLines[i]; i++) if (request_only)
size += strlenW(ppszRawHeaderLines[i]) + 1; headers = build_request_header(request, request->verb, request->path, request->version, FALSE);
else
headers = build_response_header(request, FALSE);
if (!headers)
return ERROR_OUTOFMEMORY;
if (size + 1 > *lpdwBufferLength/sizeof(WCHAR)) len = strlenW(headers) * sizeof(WCHAR);
if (len > *lpdwBufferLength)
{ {
HTTP_FreeTokens(ppszRawHeaderLines); *lpdwBufferLength = len;
*lpdwBufferLength = (size + 1) * sizeof(WCHAR); heap_free(headers);
return ERROR_INSUFFICIENT_BUFFER; return ERROR_INSUFFICIENT_BUFFER;
} }
if (pszString)
{
for (i = 0; ppszRawHeaderLines[i]; i++)
{
DWORD len = strlenW(ppszRawHeaderLines[i]);
memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
pszString += len+1;
}
*pszString = '\0';
TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
}
*lpdwBufferLength = size * sizeof(WCHAR);
HTTP_FreeTokens(ppszRawHeaderLines);
if (lpBuffer)
{
DWORD i;
TRACE("returning data: %s\n", debugstr_wn(headers, len / sizeof(WCHAR)));
for (i=0; i<len; i++)
{
if (headers[i] == '\n')
headers[i] = 0;
}
memcpy(lpBuffer, headers, len + sizeof(WCHAR));
}
*lpdwBufferLength = len - sizeof(WCHAR);
heap_free(headers);
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
case HTTP_QUERY_STATUS_TEXT: case HTTP_QUERY_STATUS_TEXT:
@ -3559,7 +3715,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
STHook->wDayOfWeek = tmpTM.tm_wday; STHook->wDayOfWeek = tmpTM.tm_wday;
STHook->wMonth = tmpTM.tm_mon + 1; STHook->wMonth = tmpTM.tm_mon + 1;
STHook->wSecond = tmpTM.tm_sec; STHook->wSecond = tmpTM.tm_sec;
STHook->wYear = tmpTM.tm_year; STHook->wYear = 1900+tmpTM.tm_year;
TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
@ -3749,6 +3905,8 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
DWORD len; DWORD len;
WCHAR* bufferW; WCHAR* bufferW;
TRACE("%p %x\n", hHttpRequest, dwInfoLevel);
if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) || if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
(dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)) (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
{ {
@ -4027,7 +4185,7 @@ static DWORD HTTP_SecureProxyConnect(http_request_t *request)
TRACE("\n"); TRACE("\n");
requestString = HTTP_BuildHeaderRequestString( request, connectW, server->host_port, g_szHttp1_1 ); requestString = build_request_header( request, connectW, server->host_port, g_szHttp1_1, TRUE );
len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
NULL, 0, NULL, NULL ); NULL, 0, NULL, NULL );
@ -4044,8 +4202,7 @@ static DWORD HTTP_SecureProxyConnect(http_request_t *request)
if (res != ERROR_SUCCESS) if (res != ERROR_SUCCESS)
return res; return res;
responseLen = HTTP_GetResponseHeaders( request, TRUE ); if (HTTP_GetResponseHeaders( request, &responseLen ) || !responseLen)
if (!responseLen)
return ERROR_HTTP_INVALID_HEADER; return ERROR_HTTP_INVALID_HEADER;
return ERROR_SUCCESS; return ERROR_SUCCESS;
@ -4596,8 +4753,9 @@ static void http_process_keep_alive(http_request_t *req)
{ {
int index; int index;
index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE); if ((index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE)) != -1)
if(index != -1) req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive);
else if ((index = HTTP_GetCustomHeaderIndex(req, szProxy_Connection, 0, FALSE)) != -1)
req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive); req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive);
else else
req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1); req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1);
@ -4703,7 +4861,6 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
LPWSTR requestString = NULL; LPWSTR requestString = NULL;
INT responseLen; INT responseLen;
BOOL loop_next; BOOL loop_next;
static const WCHAR szPost[] = { 'P','O','S','T',0 };
static const WCHAR szContentLength[] = static const WCHAR szContentLength[] =
{ 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ]; WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
@ -4741,7 +4898,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0}; static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0};
HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW); HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
} }
if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(request->verb, szPost)) if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && strcmpW(request->verb, szGET))
{ {
static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':', static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
' ','n','o','-','c','a','c','h','e','\r','\n',0}; ' ','n','o','-','c','a','c','h','e','\r','\n',0};
@ -4786,11 +4943,11 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
if (request->proxy) if (request->proxy)
{ {
WCHAR *url = build_proxy_path_url(request); WCHAR *url = build_proxy_path_url(request);
requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version); requestString = build_request_header(request, request->verb, url, request->version, TRUE);
heap_free(url); heap_free(url);
} }
else else
requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); requestString = build_request_header(request, request->verb, request->path, request->version, TRUE);
TRACE("Request header -> %s\n", debugstr_w(requestString) ); TRACE("Request header -> %s\n", debugstr_w(requestString) );
@ -4840,7 +4997,12 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
responseLen = HTTP_GetResponseHeaders(request, TRUE); if (HTTP_GetResponseHeaders(request, &responseLen))
{
http_release_netconn(request, FALSE);
res = ERROR_INTERNET_CONNECTION_ABORTED;
goto lend;
}
/* FIXME: We should know that connection is closed before sending /* FIXME: We should know that connection is closed before sending
* headers. Otherwise wrong callbacks are executed */ * headers. Otherwise wrong callbacks are executed */
if(!responseLen && reusing_connection) { if(!responseLen && reusing_connection) {
@ -4942,6 +5104,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
request->session->appInfo->proxyPassword, request->session->appInfo->proxyPassword,
NULL)) NULL))
{ {
heap_free(requestString);
if(!drain_content(request, TRUE)) { if(!drain_content(request, TRUE)) {
FIXME("Could not drain content\n"); FIXME("Could not drain content\n");
http_release_netconn(request, FALSE); http_release_netconn(request, FALSE);
@ -5033,8 +5196,7 @@ static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
responseLen = HTTP_GetResponseHeaders(request, TRUE); if (HTTP_GetResponseHeaders(request, &responseLen) || !responseLen)
if (!responseLen)
res = ERROR_HTTP_HEADER_NOT_FOUND; res = ERROR_HTTP_HEADER_NOT_FOUND;
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
@ -5533,6 +5695,18 @@ static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buf
if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
case INTERNET_OPTION_PROXY_USERNAME:
{
heap_free(ses->appInfo->proxyUsername);
if (!(ses->appInfo->proxyUsername = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
}
case INTERNET_OPTION_PROXY_PASSWORD:
{
heap_free(ses->appInfo->proxyPassword);
if (!(ses->appInfo->proxyPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
}
case INTERNET_OPTION_CONNECT_TIMEOUT: case INTERNET_OPTION_CONNECT_TIMEOUT:
{ {
if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
@ -5611,10 +5785,6 @@ DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
session->appInfo = hIC; session->appInfo = hIC;
list_add_head( &hIC->hdr.children, &session->hdr.entry ); list_add_head( &hIC->hdr.children, &session->hdr.entry );
if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) {
if(hIC->proxyBypass)
FIXME("Proxy bypass is ignored.\n");
}
session->hostName = heap_strdupW(lpszServerName); session->hostName = heap_strdupW(lpszServerName);
if (lpszUserName && lpszUserName[0]) if (lpszUserName && lpszUserName[0])
session->userName = heap_strdupW(lpszUserName); session->userName = heap_strdupW(lpszUserName);
@ -5676,19 +5846,15 @@ static void HTTP_clear_response_headers( http_request_t *request )
* TRUE on success * TRUE on success
* FALSE on error * FALSE on error
*/ */
static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) static DWORD HTTP_GetResponseHeaders(http_request_t *request, INT *len)
{ {
INT cbreaks = 0; INT cbreaks = 0;
WCHAR buffer[MAX_REPLY_LEN]; WCHAR buffer[MAX_REPLY_LEN];
DWORD buflen = MAX_REPLY_LEN; DWORD buflen = MAX_REPLY_LEN;
BOOL bSuccess = FALSE;
INT rc = 0; INT rc = 0;
char bufferA[MAX_REPLY_LEN]; char bufferA[MAX_REPLY_LEN];
LPWSTR status_code = NULL, status_text = NULL; LPWSTR status_code = NULL, status_text = NULL;
DWORD cchMaxRawHeaders = 1024; DWORD res = ERROR_HTTP_INVALID_SERVER_RESPONSE;
LPWSTR lpszRawHeaders = NULL;
LPWSTR temp;
DWORD cchRawHeaders = 0;
BOOL codeHundred = FALSE; BOOL codeHundred = FALSE;
TRACE("-->\n"); TRACE("-->\n");
@ -5696,20 +5862,19 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
if(!request->netconn) if(!request->netconn)
goto lend; goto lend;
/* clear old response headers (eg. from a redirect response) */
HTTP_clear_response_headers( request );
NETCON_set_timeout( request->netconn, FALSE, request->receive_timeout ); NETCON_set_timeout( request->netconn, FALSE, request->receive_timeout );
do { do {
/* /*
* We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
*/ */
buflen = MAX_REPLY_LEN; buflen = MAX_REPLY_LEN;
if (!read_line(request, bufferA, &buflen)) if ((res = read_line(request, bufferA, &buflen)))
goto lend; goto lend;
/* clear old response headers (eg. from a redirect response) */ if (!buflen) goto lend;
if (clear) {
HTTP_clear_response_headers( request );
clear = FALSE;
}
rc += buflen; rc += buflen;
MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
@ -5724,8 +5889,7 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
/* split the status code from the status text */ /* split the status code from the status text */
status_text = strchrW( status_code, ' ' ); status_text = strchrW( status_code, ' ' );
if( !status_text ) if( status_text )
goto lend;
*status_text++=0; *status_text++=0;
request->status_code = atoiW(status_code); request->status_code = atoiW(status_code);
@ -5746,10 +5910,6 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
request->version = heap_strdupW(g_szHttp1_0); request->version = heap_strdupW(g_szHttp1_0);
request->statusText = heap_strdupW(szOK); request->statusText = heap_strdupW(szOK);
heap_free(request->rawHeaders);
request->rawHeaders = heap_strdupW(szDefaultHeader);
bSuccess = TRUE;
goto lend; goto lend;
} }
} while (codeHundred); } while (codeHundred);
@ -5762,32 +5922,18 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
heap_free(request->statusText); heap_free(request->statusText);
request->version = heap_strdupW(buffer); request->version = heap_strdupW(buffer);
request->statusText = heap_strdupW(status_text); request->statusText = heap_strdupW(status_text ? status_text : emptyW);
/* Restore the spaces */ /* Restore the spaces */
*(status_code-1) = ' '; *(status_code-1) = ' ';
if (status_text)
*(status_text-1) = ' '; *(status_text-1) = ' ';
/* regenerate raw headers */
lpszRawHeaders = heap_alloc((cchMaxRawHeaders + 1) * sizeof(WCHAR));
if (!lpszRawHeaders) goto lend;
while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
cchMaxRawHeaders *= 2;
temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
if (temp == NULL) goto lend;
lpszRawHeaders = temp;
memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
cchRawHeaders += (buflen-1);
memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
lpszRawHeaders[cchRawHeaders] = '\0';
/* Parse each response line */ /* Parse each response line */
do do
{ {
buflen = MAX_REPLY_LEN; buflen = MAX_REPLY_LEN;
if (read_line(request, bufferA, &buflen)) if (!read_line(request, bufferA, &buflen) && buflen)
{ {
LPWSTR * pFieldAndValue; LPWSTR * pFieldAndValue;
@ -5799,20 +5945,8 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
pFieldAndValue = HTTP_InterpretHttpHeader(buffer); pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
if (pFieldAndValue) if (pFieldAndValue)
{ {
while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
cchMaxRawHeaders *= 2;
temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
if (temp == NULL) goto lend;
lpszRawHeaders = temp;
memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
cchRawHeaders += (buflen-1);
memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
lpszRawHeaders[cchRawHeaders] = '\0';
HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1], HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1],
HTTP_ADDREQ_FLAG_ADD ); HTTP_ADDREQ_FLAG_ADD );
HTTP_FreeTokens(pFieldAndValue); HTTP_FreeTokens(pFieldAndValue);
} }
} }
@ -5824,34 +5958,13 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear)
} }
}while(1); }while(1);
/* make sure the response header is terminated with an empty line. Some apps really res = ERROR_SUCCESS;
truly care about that empty line being there for some reason. Just add it to the
header. */
if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
{
cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
if (temp == NULL) goto lend;
lpszRawHeaders = temp;
}
memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
heap_free(request->rawHeaders);
request->rawHeaders = lpszRawHeaders;
TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
bSuccess = TRUE;
lend: lend:
*len = rc;
TRACE("<--\n"); TRACE("<--\n");
if (bSuccess) return res;
return rc;
else
{
heap_free(lpszRawHeaders);
return 0;
}
} }
/*********************************************************************** /***********************************************************************
@ -5967,7 +6080,7 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR
{ {
HTTP_DeleteCustomHeader( request, index ); HTTP_DeleteCustomHeader( request, index );
if (value) if (value && value[0])
{ {
HTTPHEADERW hdr; HTTPHEADERW hdr;

View file

@ -121,6 +121,7 @@ static const WCHAR szInternetSettings[] =
'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
static const WCHAR szProxyOverride[] = { 'P','r','o','x','y','O','v','e','r','r','i','d','e', 0 };
void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size) void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
{ {
@ -315,6 +316,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
if (lpvReserved) break;
collect_connections(COLLECT_CLEANUP); collect_connections(COLLECT_CLEANUP);
NETCON_unload(); NETCON_unload();
free_urlcache(); free_urlcache();
@ -613,9 +615,49 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy)); TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
} }
RegCloseKey( key );
lpwpi->proxyBypass = NULL; lpwpi->proxyBypass = NULL;
if (lpwpi->proxyEnabled)
{
if (!(envproxy = getenv( "no_proxy" )))
{
/* figure out how much memory the proxy setting takes */
if (!RegQueryValueExW( key, szProxyOverride, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
{
LPWSTR szProxy;
if (!(szProxy = heap_alloc(len)))
{
RegCloseKey( key );
return ERROR_OUTOFMEMORY;
}
RegQueryValueExW( key, szProxyOverride, NULL, &type, (BYTE*)szProxy, &len );
lpwpi->proxyBypass = szProxy;
TRACE("http proxy bypass = %s\n", debugstr_w(lpwpi->proxyBypass));
}
else
{
TRACE("No proxy bypass server settings in registry.\n");
}
}
else if (envproxy)
{
WCHAR *envproxyW;
len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
return ERROR_OUTOFMEMORY;
MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
lpwpi->proxyBypass = envproxyW;
TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass));
}
}
RegCloseKey( key );
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
@ -625,7 +667,7 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
*/ */
static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
{ {
proxyinfo_t wpi; proxyinfo_t wpi = {0};
if (INTERNET_LoadProxySettings( &wpi )) if (INTERNET_LoadProxySettings( &wpi ))
return FALSE; return FALSE;
@ -659,13 +701,15 @@ static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
lpwai->accessType = INTERNET_OPEN_TYPE_PROXY; lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
lpwai->proxy = heap_strdupW(proxyurl); lpwai->proxy = heap_strdupW(proxyurl);
lpwai->proxyBypass = heap_strdupW(wpi.proxyBypass);
if (UrlComponents.dwUserNameLength) if (UrlComponents.dwUserNameLength)
{ {
lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName); lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName);
lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword); lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword);
} }
TRACE("http proxy = %s\n", debugstr_w(lpwai->proxy)); TRACE("http proxy = %s bypass = %s\n", debugstr_w(lpwai->proxy), debugstr_w(lpwai->proxyBypass));
FreeProxyInfo(&wpi);
return TRUE; return TRUE;
} }
else else
@ -676,6 +720,7 @@ static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
} }
lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT; lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
FreeProxyInfo(&wpi);
return FALSE; return FALSE;
} }
@ -794,7 +839,7 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
/* If the buffer is copied, the returned length doesn't include /* If the buffer is copied, the returned length doesn't include
* the NULL terminator. * the NULL terminator.
*/ */
*size = len * sizeof(WCHAR); *size = len;
}else { }else {
if (ai->agent) if (ai->agent)
*size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL); *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
@ -985,6 +1030,11 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
/* Clear any error information */ /* Clear any error information */
INTERNET_SetLastError(0); INTERNET_SetLastError(0);
if((dwAccessType == INTERNET_OPEN_TYPE_PROXY) && !lpszProxy) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t)); lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
if (!lpwai) { if (!lpwai) {
SetLastError(ERROR_OUTOFMEMORY); SetLastError(ERROR_OUTOFMEMORY);
@ -1001,9 +1051,10 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
lpwai->agent = heap_strdupW(lpszAgent); lpwai->agent = heap_strdupW(lpszAgent);
if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
INTERNET_ConfigureProxy( lpwai ); INTERNET_ConfigureProxy( lpwai );
else else if(dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
lpwai->proxy = heap_strdupW(lpszProxy); lpwai->proxy = heap_strdupW(lpszProxy);
lpwai->proxyBypass = heap_strdupW(lpszProxyBypass); lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);
}
TRACE("returning %p\n", lpwai); TRACE("returning %p\n", lpwai);
@ -1591,7 +1642,7 @@ static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
return INTERNET_SCHEME_UNKNOWN; return INTERNET_SCHEME_UNKNOWN;
for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++) for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp)) if (!strncmpiW(lpszScheme, url_schemes[i], nMaxCmp))
return INTERNET_SCHEME_FIRST + i; return INTERNET_SCHEME_FIRST + i;
return INTERNET_SCHEME_UNKNOWN; return INTERNET_SCHEME_UNKNOWN;
@ -2954,11 +3005,11 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
case INTERNET_OPTION_USER_AGENT: case INTERNET_OPTION_USER_AGENT:
case INTERNET_OPTION_USERNAME: case INTERNET_OPTION_USERNAME:
case INTERNET_OPTION_PASSWORD: case INTERNET_OPTION_PASSWORD:
wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, case INTERNET_OPTION_PROXY_USERNAME:
NULL, 0 ); case INTERNET_OPTION_PROXY_PASSWORD:
wbuffer = heap_alloc(wlen*sizeof(WCHAR) ); wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, if (!(wbuffer = heap_alloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
wbuffer, wlen ); MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
break; break;
case INTERNET_OPTION_PER_CONNECTION_OPTION: { case INTERNET_OPTION_PER_CONNECTION_OPTION: {
unsigned int i; unsigned int i;

View file

@ -91,8 +91,15 @@ typedef struct
{ {
int socket; int socket;
BOOL secure; BOOL secure;
void *ssl_s; CtxtHandle ssl_ctx;
SecPkgContext_StreamSizes ssl_sizes;
server_t *server; server_t *server;
char *ssl_buf;
char *extra_buf;
size_t extra_len;
char *peek_msg;
char *peek_msg_mem;
size_t peek_len;
DWORD security_flags; DWORD security_flags;
BOOL mask_errors; BOOL mask_errors;
@ -142,6 +149,21 @@ static inline LPWSTR heap_strdupW(LPCWSTR str)
return ret; return ret;
} }
static inline char *heap_strdupA(const char *str)
{
char *ret = NULL;
if(str) {
DWORD size = strlen(str)+1;
ret = heap_alloc(size);
if(ret)
memcpy(ret, str, size);
}
return ret;
}
static inline LPWSTR heap_strndupW(LPCWSTR str, UINT max_len) static inline LPWSTR heap_strndupW(LPCWSTR str, UINT max_len)
{ {
LPWSTR ret; LPWSTR ret;
@ -321,7 +343,6 @@ typedef struct
server_t *proxy; server_t *proxy;
LPWSTR path; LPWSTR path;
LPWSTR verb; LPWSTR verb;
LPWSTR rawHeaders;
netconn_t *netconn; netconn_t *netconn;
DWORD security_flags; DWORD security_flags;
DWORD connect_timeout; DWORD connect_timeout;

File diff suppressed because it is too large Load diff

View file

@ -123,3 +123,5 @@
#ifdef LANGUAGE_ZH_CN #ifdef LANGUAGE_ZH_CN
#include "lang/wininet_Zh.rc" #include "lang/wininet_Zh.rc"
#endif #endif
#include "version.rc"

File diff suppressed because it is too large Load diff

View file

@ -25,4 +25,4 @@
#define WINE_PRODUCTVERSION 6,0,2800,1106 #define WINE_PRODUCTVERSION 6,0,2800,1106
#define WINE_PRODUCTVERSION_STR "6.0.2800.1106" #define WINE_PRODUCTVERSION_STR "6.0.2800.1106"
#include "wine/wine_common_ver.rc" #include <wine/wine_common_ver.rc>

View file

@ -203,7 +203,7 @@ reactos/dll/win32/windowscodecs # Synced to Wine-1.7.1
reactos/dll/win32/winemp3.acm # Synced to Wine-1.7.1 reactos/dll/win32/winemp3.acm # Synced to Wine-1.7.1
reactos/dll/win32/wing32 # Out of sync reactos/dll/win32/wing32 # Out of sync
reactos/dll/win32/winhttp # Synced to Wine-1.7.1 reactos/dll/win32/winhttp # Synced to Wine-1.7.1
reactos/dll/win32/wininet # Synced to Wine-1.5.26 reactos/dll/win32/wininet # Synced to Wine-1.7.1
reactos/dll/win32/winmm # Forked at Wine-20050628 reactos/dll/win32/winmm # Forked at Wine-20050628
reactos/dll/win32/winmm/midimap # Forked at Wine-20050628 reactos/dll/win32/winmm/midimap # Forked at Wine-20050628
reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628 reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628