[WININET] Sync with Wine Staging 1.9.11. CORE-11368

svn path=/trunk/; revision=71751
This commit is contained in:
Amine Khaldi 2016-07-02 15:23:01 +00:00
parent 91e48f534f
commit 7702f2f814
8 changed files with 892 additions and 1043 deletions

View file

@ -22,6 +22,8 @@
#include "internet.h"
#include <lmcons.h>
#define RESPONSE_TIMEOUT 30 /* FROM internet.c */
/* FIXME
@ -46,7 +48,8 @@ typedef struct _cookie_t {
typedef struct _cookie_container_t {
struct list entry;
WCHAR *path;
WCHAR *cookie_url;
substr_t path;
struct _cookie_domain_t *domain;
struct list cookie_list;
@ -75,19 +78,20 @@ static CRITICAL_SECTION_DEBUG cookie_cs_debug =
static CRITICAL_SECTION cookie_cs = { &cookie_cs_debug, -1, 0, 0, 0, 0 };
static struct list domain_list = LIST_INIT(domain_list);
static cookie_domain_t *get_cookie_domain(const WCHAR *domain, BOOL create)
static cookie_domain_t *get_cookie_domain(substr_t domain, BOOL create)
{
const WCHAR *ptr = domain + strlenW(domain), *ptr_end, *subdomain_ptr;
const WCHAR *ptr = domain.str + domain.len, *ptr_end, *subdomain_ptr;
cookie_domain_t *iter, *current_domain, *prev_domain = NULL;
struct list *current_list = &domain_list;
while(1) {
for(ptr_end = ptr--; ptr > domain && *ptr != '.'; ptr--);
for(ptr_end = ptr--; ptr > domain.str && *ptr != '.'; ptr--);
subdomain_ptr = *ptr == '.' ? ptr+1 : ptr;
current_domain = NULL;
LIST_FOR_EACH_ENTRY(iter, current_list, cookie_domain_t, entry) {
if(ptr_end-subdomain_ptr == iter->subdomain_len && !memcmp(subdomain_ptr, iter->domain, iter->subdomain_len)) {
if(ptr_end-subdomain_ptr == iter->subdomain_len
&& !memcmp(subdomain_ptr, iter->domain, iter->subdomain_len*sizeof(WCHAR))) {
current_domain = iter;
break;
}
@ -101,7 +105,7 @@ static cookie_domain_t *get_cookie_domain(const WCHAR *domain, BOOL create)
if(!current_domain)
return NULL;
current_domain->domain = heap_strdupW(subdomain_ptr);
current_domain->domain = heap_strndupW(subdomain_ptr, domain.str + domain.len - subdomain_ptr);
if(!current_domain->domain) {
heap_free(current_domain);
return NULL;
@ -116,7 +120,7 @@ static cookie_domain_t *get_cookie_domain(const WCHAR *domain, BOOL create)
list_add_tail(current_list, &current_domain->entry);
}
if(ptr == domain)
if(ptr == domain.str)
return current_domain;
prev_domain = current_domain;
@ -124,24 +128,57 @@ static cookie_domain_t *get_cookie_domain(const WCHAR *domain, BOOL create)
}
}
static cookie_container_t *get_cookie_container(const WCHAR *domain, const WCHAR *path, BOOL create)
static WCHAR *create_cookie_url(substr_t domain, substr_t path, substr_t *ret_path)
{
WCHAR user[UNLEN], *p, *url;
DWORD len, user_len, i;
static const WCHAR cookie_prefix[] = {'C','o','o','k','i','e',':'};
user_len = sizeof(user)/sizeof(WCHAR);
if(!GetUserNameW(user, &user_len))
return FALSE;
user_len--;
len = sizeof(cookie_prefix)/sizeof(WCHAR) + user_len + 1 /* @ */ + domain.len + path.len;
url = heap_alloc((len+1) * sizeof(WCHAR));
if(!url)
return NULL;
memcpy(url, cookie_prefix, sizeof(cookie_prefix));
p = url + sizeof(cookie_prefix)/sizeof(WCHAR);
memcpy(p, user, user_len*sizeof(WCHAR));
p += user_len;
*p++ = '@';
memcpy(p, domain.str, domain.len*sizeof(WCHAR));
p += domain.len;
for(i=0; i < path.len; i++)
p[i] = tolowerW(path.str[i]);
p[path.len] = 0;
ret_path->str = p;
ret_path->len = path.len;
return url;
}
static cookie_container_t *get_cookie_container(substr_t domain, substr_t path, BOOL create)
{
cookie_domain_t *cookie_domain;
cookie_container_t *cookie_container, *iter;
size_t path_len, len;
cookie_domain = get_cookie_domain(domain, create);
if(!cookie_domain)
return NULL;
path_len = strlenW(path);
LIST_FOR_EACH_ENTRY(cookie_container, &cookie_domain->path_list, cookie_container_t, entry) {
len = strlenW(cookie_container->path);
if(len < path_len)
if(cookie_container->path.len < path.len)
break;
if(!strcmpiW(cookie_container->path, path))
if(path.len == cookie_container->path.len && !strncmpiW(cookie_container->path.str, path.str, path.len))
return cookie_container;
}
@ -152,8 +189,8 @@ static cookie_container_t *get_cookie_container(const WCHAR *domain, const WCHAR
if(!cookie_container)
return NULL;
cookie_container->path = heap_strdupW(path);
if(!cookie_container->path) {
cookie_container->cookie_url = create_cookie_url(substrz(cookie_domain->domain), path, &cookie_container->path);
if(!cookie_container->cookie_url) {
heap_free(cookie_container);
return NULL;
}
@ -161,9 +198,8 @@ static cookie_container_t *get_cookie_container(const WCHAR *domain, const WCHAR
cookie_container->domain = cookie_domain;
list_init(&cookie_container->cookie_list);
LIST_FOR_EACH_ENTRY(iter, &cookie_domain->path_list, cookie_container_t, entry) {
if(strlenW(iter->path) <= path_len) {
if(iter->path.len <= path.len) {
list_add_before(&iter->entry, &cookie_container->entry);
return cookie_container;
}
@ -182,7 +218,7 @@ static void delete_cookie(cookie_t *cookie)
heap_free(cookie);
}
static cookie_t *alloc_cookie(const WCHAR *name, const WCHAR *data, FILETIME expiry, FILETIME create_time, DWORD flags)
static cookie_t *alloc_cookie(substr_t name, substr_t data, FILETIME expiry, FILETIME create_time, DWORD flags)
{
cookie_t *new_cookie;
@ -195,9 +231,9 @@ static cookie_t *alloc_cookie(const WCHAR *name, const WCHAR *data, FILETIME exp
new_cookie->flags = flags;
list_init(&new_cookie->entry);
new_cookie->name = heap_strdupW(name);
new_cookie->data = heap_strdupW(data);
if((name && !new_cookie->name) || (data && !new_cookie->data)) {
new_cookie->name = heap_strndupW(name.str, name.len);
new_cookie->data = heap_strndupW(data.str, data.len);
if(!new_cookie->name || !new_cookie->data) {
delete_cookie(new_cookie);
return NULL;
}
@ -205,12 +241,12 @@ static cookie_t *alloc_cookie(const WCHAR *name, const WCHAR *data, FILETIME exp
return new_cookie;
}
static cookie_t *find_cookie(cookie_container_t *container, const WCHAR *name)
static cookie_t *find_cookie(cookie_container_t *container, substr_t name)
{
cookie_t *iter;
LIST_FOR_EACH_ENTRY(iter, &container->cookie_list, cookie_t, entry) {
if(!strcmpiW(iter->name, name))
if(strlenW(iter->name) == name.len && !strncmpiW(iter->name, name.str, name.len))
return iter;
}
@ -219,8 +255,8 @@ static cookie_t *find_cookie(cookie_container_t *container, const WCHAR *name)
static void add_cookie(cookie_container_t *container, cookie_t *new_cookie)
{
TRACE("Adding %s=%s to %s %s\n", debugstr_w(new_cookie->name), debugstr_w(new_cookie->data),
debugstr_w(container->domain->domain), debugstr_w(container->path));
TRACE("Adding %s=%s to %s\n", debugstr_w(new_cookie->name), debugstr_w(new_cookie->data),
debugstr_w(container->cookie_url));
list_add_tail(&container->cookie_list, &new_cookie->entry);
new_cookie->container = container;
@ -230,86 +266,41 @@ static void replace_cookie(cookie_container_t *container, cookie_t *new_cookie)
{
cookie_t *old_cookie;
old_cookie = find_cookie(container, new_cookie->name);
old_cookie = find_cookie(container, substrz(new_cookie->name));
if(old_cookie)
delete_cookie(old_cookie);
add_cookie(container, new_cookie);
}
static BOOL cookie_match_path(cookie_container_t *container, const WCHAR *path)
static BOOL cookie_match_path(cookie_container_t *container, substr_t path)
{
return !strncmpiW(container->path, path, strlenW(container->path));
return path.len >= container->path.len && !strncmpiW(container->path.str, path.str, container->path.len);
}
static BOOL create_cookie_url(LPCWSTR domain, LPCWSTR path, WCHAR *buf, DWORD buf_len)
{
static const WCHAR cookie_prefix[] = {'C','o','o','k','i','e',':'};
WCHAR *p;
DWORD len;
if(buf_len < sizeof(cookie_prefix)/sizeof(WCHAR))
return FALSE;
memcpy(buf, cookie_prefix, sizeof(cookie_prefix));
buf += sizeof(cookie_prefix)/sizeof(WCHAR);
buf_len -= sizeof(cookie_prefix)/sizeof(WCHAR);
p = buf;
len = buf_len;
if(!GetUserNameW(buf, &len))
return FALSE;
buf += len-1;
buf_len -= len-1;
if(!buf_len)
return FALSE;
*(buf++) = '@';
buf_len--;
len = strlenW(domain);
if(len >= buf_len)
return FALSE;
memcpy(buf, domain, len*sizeof(WCHAR));
buf += len;
buf_len -= len;
len = strlenW(path);
if(len >= buf_len)
return FALSE;
memcpy(buf, path, len*sizeof(WCHAR));
buf += len;
*buf = 0;
for(; *p; p++)
*p = tolowerW(*p);
return TRUE;
}
static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
static BOOL load_persistent_cookie(substr_t domain, substr_t path)
{
INTERNET_CACHE_ENTRY_INFOW *info;
cookie_container_t *cookie_container;
cookie_t *new_cookie;
WCHAR cookie_url[MAX_PATH];
HANDLE cookie;
char *str = NULL, *pbeg, *pend;
DWORD size, flags;
WCHAR *name, *data;
FILETIME expiry, create, time;
if (!create_cookie_url(domain, path, cookie_url, sizeof(cookie_url)/sizeof(cookie_url[0])))
cookie_container = get_cookie_container(domain, path, TRUE);
if(!cookie_container)
return FALSE;
size = 0;
RetrieveUrlCacheEntryStreamW(cookie_url, NULL, &size, FALSE, 0);
RetrieveUrlCacheEntryStreamW(cookie_container->cookie_url, NULL, &size, FALSE, 0);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return TRUE;
info = heap_alloc(size);
if(!info)
return FALSE;
cookie = RetrieveUrlCacheEntryStreamW(cookie_url, info, &size, FALSE, 0);
cookie = RetrieveUrlCacheEntryStreamW(cookie_container->cookie_url, info, &size, FALSE, 0);
size = info->dwSizeLow;
heap_free(info);
if(!cookie)
@ -323,12 +314,6 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
str[size] = 0;
UnlockUrlCacheEntryStream(cookie, 0);
cookie_container = get_cookie_container(domain, path, TRUE);
if(!cookie_container) {
heap_free(str);
return FALSE;
}
GetSystemTimeAsFileTime(&time);
for(pbeg=str; pbeg && *pbeg; name=data=NULL) {
pend = strchr(pbeg, '\n');
@ -362,7 +347,7 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path)
break;
if(CompareFileTime(&time, &expiry) <= 0) {
new_cookie = alloc_cookie(NULL, NULL, expiry, create, flags);
new_cookie = alloc_cookie(substr(NULL, 0), substr(NULL, 0), expiry, create, flags);
if(!new_cookie)
break;
@ -386,16 +371,14 @@ static BOOL save_persistent_cookie(cookie_container_t *container)
{
static const WCHAR txtW[] = {'t','x','t',0};
WCHAR cookie_url[MAX_PATH], cookie_file[MAX_PATH];
WCHAR cookie_file[MAX_PATH];
HANDLE cookie_handle;
cookie_t *cookie_container = NULL, *cookie_iter;
BOOL do_save = FALSE;
char buf[64], *dyn_buf;
FILETIME time;
DWORD bytes_written;
if (!create_cookie_url(container->domain->domain, container->path, cookie_url, sizeof(cookie_url)/sizeof(cookie_url[0])))
return FALSE;
size_t len;
/* check if there's anything to save */
GetSystemTimeAsFileTime(&time);
@ -412,13 +395,15 @@ static BOOL save_persistent_cookie(cookie_container_t *container)
break;
}
}
if(!do_save) {
DeleteUrlCacheEntryW(cookie_url);
DeleteUrlCacheEntryW(container->cookie_url);
return TRUE;
}
if(!CreateUrlCacheEntryW(cookie_url, 0, txtW, cookie_file, 0))
if(!CreateUrlCacheEntryW(container->cookie_url, 0, txtW, cookie_file, 0))
return FALSE;
cookie_handle = CreateFileW(cookie_file, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(cookie_handle == INVALID_HANDLE_VALUE) {
DeleteFileW(cookie_file);
@ -462,7 +447,12 @@ static BOOL save_persistent_cookie(cookie_container_t *container)
}
heap_free(dyn_buf);
dyn_buf = heap_strdupWtoA(container->path);
len = WideCharToMultiByte(CP_ACP, 0, container->path.str, container->path.len, NULL, 0, NULL, NULL);
dyn_buf = heap_alloc(len+1);
if(dyn_buf) {
WideCharToMultiByte(CP_ACP, 0, container->path.str, container->path.len, dyn_buf, len, NULL, NULL);
dyn_buf[len] = 0;
}
if(!dyn_buf || !WriteFile(cookie_handle, dyn_buf, strlen(dyn_buf), &bytes_written, NULL)) {
heap_free(dyn_buf);
do_save = FALSE;
@ -487,47 +477,26 @@ static BOOL save_persistent_cookie(cookie_container_t *container)
}
memset(&time, 0, sizeof(time));
return CommitUrlCacheEntryW(cookie_url, cookie_file, time, time, 0, NULL, 0, txtW, 0);
return CommitUrlCacheEntryW(container->cookie_url, cookie_file, time, time, 0, NULL, 0, txtW, 0);
}
static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostNameLen, LPWSTR path, int pathLen)
static BOOL cookie_parse_url(const WCHAR *url, substr_t *host, substr_t *path)
{
URL_COMPONENTSW UrlComponents;
URL_COMPONENTSW comp = { sizeof(comp) };
static const WCHAR rootW[] = {'/',0};
UrlComponents.lpszExtraInfo = NULL;
UrlComponents.lpszPassword = NULL;
UrlComponents.lpszScheme = NULL;
UrlComponents.lpszUrlPath = path;
UrlComponents.lpszUserName = NULL;
UrlComponents.lpszHostName = hostName;
UrlComponents.dwExtraInfoLength = 0;
UrlComponents.dwPasswordLength = 0;
UrlComponents.dwSchemeLength = 0;
UrlComponents.dwUserNameLength = 0;
UrlComponents.dwHostNameLength = hostNameLen;
UrlComponents.dwUrlPathLength = pathLen;
comp.dwHostNameLength = 1;
comp.dwUrlPathLength = 1;
if (!InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents)) return FALSE;
if(!InternetCrackUrlW(url, 0, 0, &comp) || !comp.dwHostNameLength)
return FALSE;
/* discard the webpage off the end of the path */
if (UrlComponents.dwUrlPathLength)
{
if (path[UrlComponents.dwUrlPathLength - 1] != '/')
{
WCHAR *ptr;
if ((ptr = strrchrW(path, '/'))) *(++ptr) = 0;
else
{
path[0] = '/';
path[1] = 0;
}
}
}
else if (pathLen >= 2)
{
path[0] = '/';
path[1] = 0;
}
while(comp.dwUrlPathLength && comp.lpszUrlPath[comp.dwUrlPathLength-1] != '/')
comp.dwUrlPathLength--;
*host = substr(comp.lpszHostName, comp.dwHostNameLength);
*path = comp.dwUrlPathLength ? substr(comp.lpszUrlPath, comp.dwUrlPathLength) : substr(rootW, 1);
return TRUE;
}
@ -539,45 +508,38 @@ typedef struct {
unsigned string_len;
} cookie_set_t;
static DWORD get_cookie(const WCHAR *host, const WCHAR *path, DWORD flags, cookie_set_t *res)
static DWORD get_cookie(substr_t host, substr_t path, DWORD flags, cookie_set_t *res)
{
static const WCHAR empty_path[] = { '/',0 };
WCHAR *ptr, subpath[INTERNET_MAX_PATH_LENGTH];
const WCHAR *p;
cookie_domain_t *domain;
cookie_container_t *container;
unsigned len;
FILETIME tm;
GetSystemTimeAsFileTime(&tm);
len = strlenW(host);
p = host+len;
while(p>host && p[-1]!='.') p--;
while(p != host) {
p = host.str + host.len;
while(p > host.str && p[-1] != '.') p--;
while(p != host.str) {
p--;
while(p>host && p[-1]!='.') p--;
if(p == host) break;
while(p > host.str && p[-1] != '.') p--;
if(p == host.str) break;
load_persistent_cookie(p, empty_path);
load_persistent_cookie(substr(p, host.str+host.len-p), substr(empty_path, 1));
}
len = strlenW(path);
assert(len+1 < INTERNET_MAX_PATH_LENGTH);
memcpy(subpath, path, (len+1)*sizeof(WCHAR));
ptr = subpath+len;
p = path.str + path.len;
do {
*ptr = 0;
load_persistent_cookie(host, subpath);
load_persistent_cookie(host, substr(path.str, p-path.str));
ptr--;
while(ptr>subpath && ptr[-1]!='/') ptr--;
}while(ptr != subpath);
p--;
while(p > path.str && p[-1] != '/') p--;
}while(p != path.str);
domain = get_cookie_domain(host, FALSE);
if(!domain) {
TRACE("Unknown host %s\n", debugstr_w(host));
TRACE("Unknown host %s\n", debugstr_wn(host.str, host.len));
return ERROR_NO_MORE_ITEMS;
}
@ -587,7 +549,7 @@ static DWORD get_cookie(const WCHAR *host, const WCHAR *path, DWORD flags, cooki
LIST_FOR_EACH_ENTRY(container, &domain->path_list, cookie_container_t, entry) {
struct list *cursor, *cursor2;
TRACE("path %s\n", debugstr_w(container->path));
TRACE("path %s\n", debugstr_wn(container->path.str, container->path.len));
if(!cookie_match_path(container, path))
continue;
@ -672,7 +634,7 @@ DWORD get_cookie_header(const WCHAR *host, const WCHAR *path, WCHAR **ret)
EnterCriticalSection(&cookie_cs);
res = get_cookie(host, path, INTERNET_COOKIE_HTTPONLY, &cookie_set);
res = get_cookie(substrz(host), substrz(path), INTERNET_COOKIE_HTTPONLY, &cookie_set);
if(res != ERROR_SUCCESS) {
LeaveCriticalSection(&cookie_cs);
return res;
@ -722,8 +684,8 @@ DWORD get_cookie_header(const WCHAR *host, const WCHAR *path, WCHAR **ret)
BOOL WINAPI InternetGetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
LPWSTR lpCookieData, LPDWORD lpdwSize, DWORD flags, void *reserved)
{
WCHAR host[INTERNET_MAX_HOST_NAME_LENGTH], path[INTERNET_MAX_PATH_LENGTH];
cookie_set_t cookie_set = {0};
substr_t host, path;
DWORD res;
BOOL ret;
@ -738,9 +700,8 @@ BOOL WINAPI InternetGetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
return FALSE;
}
host[0] = 0;
ret = COOKIE_crackUrlSimple(lpszUrl, host, sizeof(host)/sizeof(host[0]), path, sizeof(path)/sizeof(path[0]));
if (!ret || !host[0]) {
ret = cookie_parse_url(lpszUrl, &host, &path);
if (!ret) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
@ -768,7 +729,7 @@ BOOL WINAPI InternetGetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
lpCookieData[cookie_set.string_len] = 0;
}
}else {
TRACE("no cookies found for %s\n", debugstr_w(host));
TRACE("no cookies found for %s\n", debugstr_wn(host.str, host.len));
SetLastError(ERROR_NO_MORE_ITEMS);
ret = FALSE;
}
@ -855,40 +816,25 @@ BOOL WINAPI InternetGetCookieExA(LPCSTR lpszUrl, LPCSTR lpszCookieName,
*/
BOOL WINAPI InternetGetCookieA(const char *url, const char *name, char *data, DWORD *size)
{
TRACE("(%s, %s, %s, %p)\n", debugstr_a(url), debugstr_a(name), debugstr_a(data), size);
TRACE("(%s, %s, %p, %p)\n", debugstr_a(url), debugstr_a(name), data, size);
return InternetGetCookieExA(url, name, data, size, 0, NULL);
}
/***********************************************************************
* IsDomainLegalCookieDomainW (WININET.@)
*/
BOOL WINAPI IsDomainLegalCookieDomainW( LPCWSTR s1, LPCWSTR s2 )
static BOOL is_domain_legal_for_cookie(substr_t domain, substr_t full_domain)
{
DWORD s1_len, s2_len;
const WCHAR *ptr;
FIXME("(%s, %s) semi-stub\n", debugstr_w(s1), debugstr_w(s2));
if (!s1 || !s2)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (s1[0] == '.' || !s1[0] || s2[0] == '.' || !s2[0])
{
if(!domain.len || *domain.str == '.' || !full_domain.len || *full_domain.str == '.') {
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
if(!strchrW(s1, '.') || !strchrW(s2, '.'))
if(domain.len > full_domain.len || !memchrW(domain.str, '.', domain.len) || !memchrW(full_domain.str, '.', full_domain.len))
return FALSE;
s1_len = strlenW(s1);
s2_len = strlenW(s2);
if (s1_len > s2_len)
return FALSE;
if (strncmpiW(s1, s2+s2_len-s1_len, s1_len) || (s2_len>s1_len && s2[s2_len-s1_len-1]!='.'))
{
ptr = full_domain.str + full_domain.len - domain.len;
if (strncmpiW(domain.str, ptr, domain.len) || (full_domain.len > domain.len && ptr[-1] != '.')) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
@ -896,129 +842,130 @@ BOOL WINAPI IsDomainLegalCookieDomainW( LPCWSTR s1, LPCWSTR s2 )
return TRUE;
}
DWORD set_cookie(const WCHAR *domain, const WCHAR *path, const WCHAR *cookie_name, const WCHAR *cookie_data, DWORD flags)
/***********************************************************************
* IsDomainLegalCookieDomainW (WININET.@)
*/
BOOL WINAPI IsDomainLegalCookieDomainW(const WCHAR *domain, const WCHAR *full_domain)
{
FIXME("(%s, %s) semi-stub\n", debugstr_w(domain), debugstr_w(full_domain));
if (!domain || !full_domain) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return is_domain_legal_for_cookie(substrz(domain), substrz(full_domain));
}
static void substr_skip(substr_t *str, size_t len)
{
assert(str->len >= len);
str->str += len;
str->len -= len;
}
DWORD set_cookie(substr_t domain, substr_t path, substr_t name, substr_t data, DWORD flags)
{
cookie_container_t *container;
cookie_t *thisCookie;
LPWSTR data, value;
WCHAR *ptr;
substr_t value;
const WCHAR *end_ptr;
FILETIME expiry, create;
BOOL expired = FALSE, update_persistent = FALSE;
DWORD cookie_flags = 0;
DWORD cookie_flags = 0, len;
TRACE("%s %s %s=%s %x\n", debugstr_w(domain), debugstr_w(path), debugstr_w(cookie_name), debugstr_w(cookie_data), flags);
value = data = heap_strdupW(cookie_data);
if (!data)
{
ERR("could not allocate the cookie data buffer\n");
return COOKIE_STATE_UNKNOWN;
}
TRACE("%s %s %s=%s %x\n", debugstr_wn(domain.str, domain.len), debugstr_wn(path.str, path.len),
debugstr_wn(name.str, name.len), debugstr_wn(data.str, data.len), flags);
memset(&expiry,0,sizeof(expiry));
GetSystemTimeAsFileTime(&create);
/* lots of information can be parsed out of the cookie value */
ptr = data;
for (;;)
{
static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0};
static const WCHAR szPath[] = {'p','a','t','h','=',0};
static const WCHAR szExpires[] = {'e','x','p','i','r','e','s','=',0};
static const WCHAR szSecure[] = {'s','e','c','u','r','e',0};
static const WCHAR szHttpOnly[] = {'h','t','t','p','o','n','l','y',0};
static const WCHAR szVersion[] = {'v','e','r','s','i','o','n','=',0};
if(!(end_ptr = memchrW(data.str, ';', data.len)))
end_ptr = data.str + data.len;
value = substr(data.str, end_ptr-data.str);
data.str += value.len;
data.len -= value.len;
if (!(ptr = strchrW(ptr,';'))) break;
*ptr++ = 0;
for(;;) {
static const WCHAR szDomain[] = {'d','o','m','a','i','n','='};
static const WCHAR szPath[] = {'p','a','t','h','='};
static const WCHAR szExpires[] = {'e','x','p','i','r','e','s','='};
static const WCHAR szSecure[] = {'s','e','c','u','r','e'};
static const WCHAR szHttpOnly[] = {'h','t','t','p','o','n','l','y'};
static const WCHAR szVersion[] = {'v','e','r','s','i','o','n','='};
if (value != data) heap_free(value);
value = heap_alloc((ptr - data) * sizeof(WCHAR));
if (value == NULL)
{
heap_free(data);
ERR("could not allocate the cookie value buffer\n");
return COOKIE_STATE_UNKNOWN;
}
strcpyW(value, data);
/* Skip ';' */
if(data.len)
substr_skip(&data, 1);
while (*ptr == ' ') ptr++; /* whitespace */
while(data.len && *data.str == ' ')
substr_skip(&data, 1);
if (strncmpiW(ptr, szDomain, 7) == 0)
{
WCHAR *end_ptr;
if(!data.len)
break;
ptr += sizeof(szDomain)/sizeof(szDomain[0])-1;
if(*ptr == '.')
ptr++;
end_ptr = strchrW(ptr, ';');
if(end_ptr)
*end_ptr = 0;
if(!(end_ptr = memchrW(data.str, ';', data.len)))
end_ptr = data.str + data.len;
if(!IsDomainLegalCookieDomainW(ptr, domain))
{
if(value != data)
heap_free(value);
heap_free(data);
if(data.len >= (len = sizeof(szDomain)/sizeof(WCHAR)) && !strncmpiW(data.str, szDomain, len)) {
substr_skip(&data, len);
if(data.len && *data.str == '.')
substr_skip(&data, 1);
if(!is_domain_legal_for_cookie(substr(data.str, end_ptr-data.str), domain))
return COOKIE_STATE_UNKNOWN;
}
if(end_ptr)
*end_ptr = ';';
domain = ptr;
TRACE("Parsing new domain %s\n",debugstr_w(domain));
}
else if (strncmpiW(ptr, szPath, 5) == 0)
{
ptr+=strlenW(szPath);
path = ptr;
TRACE("Parsing new path %s\n",debugstr_w(path));
}
else if (strncmpiW(ptr, szExpires, 8) == 0)
{
domain = substr(data.str, end_ptr-data.str);
TRACE("Parsing new domain %s\n", debugstr_wn(domain.str, domain.len));
}else if(data.len >= (len = sizeof(szPath)/sizeof(WCHAR)) && !strncmpiW(data.str, szPath, len)) {
substr_skip(&data, len);
path = substr(data.str, end_ptr - data.str);
TRACE("Parsing new path %s\n", debugstr_wn(path.str, path.len));
}else if(data.len >= (len = sizeof(szExpires)/sizeof(WCHAR)) && !strncmpiW(data.str, szExpires, len)) {
SYSTEMTIME st;
ptr+=strlenW(szExpires);
if (InternetTimeToSystemTimeW(ptr, &st, 0))
{
SystemTimeToFileTime(&st, &expiry);
WCHAR buf[128];
if (CompareFileTime(&create,&expiry) > 0)
{
TRACE("Cookie already expired.\n");
expired = TRUE;
substr_skip(&data, len);
if(end_ptr - data.str < sizeof(buf)/sizeof(WCHAR)-1) {
memcpy(buf, data.str, data.len*sizeof(WCHAR));
buf[data.len] = 0;
if (InternetTimeToSystemTimeW(data.str, &st, 0)) {
SystemTimeToFileTime(&st, &expiry);
if (CompareFileTime(&create,&expiry) > 0) {
TRACE("Cookie already expired.\n");
expired = TRUE;
}
}
}
}
else if (strncmpiW(ptr, szSecure, 6) == 0)
{
FIXME("secure not handled (%s)\n",debugstr_w(ptr));
ptr += strlenW(szSecure);
}
else if (strncmpiW(ptr, szHttpOnly, 8) == 0)
{
}else if(data.len >= (len = sizeof(szSecure)/sizeof(WCHAR)) && !strncmpiW(data.str, szSecure, len)) {
substr_skip(&data, len);
FIXME("secure not handled\n");
}else if(data.len >= (len = sizeof(szHttpOnly)/sizeof(WCHAR)) && !strncmpiW(data.str, szHttpOnly, len)) {
substr_skip(&data, len);
if(!(flags & INTERNET_COOKIE_HTTPONLY)) {
WARN("HTTP only cookie added without INTERNET_COOKIE_HTTPONLY flag\n");
heap_free(data);
if (value != data) heap_free(value);
SetLastError(ERROR_INVALID_OPERATION);
return COOKIE_STATE_REJECT;
}
cookie_flags |= INTERNET_COOKIE_HTTPONLY;
ptr += strlenW(szHttpOnly);
}
else if (strncmpiW(ptr, szVersion, 8) == 0)
{
FIXME("version not handled (%s)\n",debugstr_w(ptr));
ptr += strlenW(szVersion);
}
else if (*ptr)
{
FIXME("Unknown additional option %s\n",debugstr_w(ptr));
}else if(data.len >= (len = sizeof(szVersion)/sizeof(WCHAR)) && !strncmpiW(data.str, szVersion, len)) {
substr_skip(&data, len);
FIXME("version not handled (%s)\n",debugstr_wn(data.str, data.len));
}else if(data.len) {
FIXME("Unknown additional option %s\n", debugstr_wn(data.str, data.len));
break;
}
substr_skip(&data, end_ptr - data.str);
}
EnterCriticalSection(&cookie_cs);
@ -1027,8 +974,6 @@ DWORD set_cookie(const WCHAR *domain, const WCHAR *path, const WCHAR *cookie_nam
container = get_cookie_container(domain, path, !expired);
if(!container) {
heap_free(data);
if (value != data) heap_free(value);
LeaveCriticalSection(&cookie_cs);
return COOKIE_STATE_ACCEPT;
}
@ -1038,13 +983,10 @@ DWORD set_cookie(const WCHAR *domain, const WCHAR *path, const WCHAR *cookie_nam
else
update_persistent = TRUE;
if ((thisCookie = find_cookie(container, cookie_name)))
{
if ((thisCookie = find_cookie(container, name))) {
if ((thisCookie->flags & INTERNET_COOKIE_HTTPONLY) && !(flags & INTERNET_COOKIE_HTTPONLY)) {
WARN("An attempt to override httponly cookie\n");
SetLastError(ERROR_INVALID_OPERATION);
heap_free(data);
if (value != data) heap_free(value);
return COOKIE_STATE_REJECT;
}
@ -1053,24 +995,21 @@ DWORD set_cookie(const WCHAR *domain, const WCHAR *path, const WCHAR *cookie_nam
delete_cookie(thisCookie);
}
TRACE("setting cookie %s=%s for domain %s path %s\n", debugstr_w(cookie_name),
debugstr_w(value), debugstr_w(container->domain->domain),debugstr_w(container->path));
TRACE("setting cookie %s=%s for domain %s path %s\n", debugstr_wn(name.str, name.len),
debugstr_wn(value.str, value.len), debugstr_w(container->domain->domain),
debugstr_wn(container->path.str, container->path.len));
if (!expired) {
cookie_t *new_cookie;
new_cookie = alloc_cookie(cookie_name, value, expiry, create, cookie_flags);
new_cookie = alloc_cookie(name, value, expiry, create, cookie_flags);
if(!new_cookie) {
heap_free(data);
if (value != data) heap_free(value);
LeaveCriticalSection(&cookie_cs);
return COOKIE_STATE_UNKNOWN;
}
add_cookie(container, new_cookie);
}
heap_free(data);
if (value != data) heap_free(value);
if (!update_persistent || save_persistent_cookie(container))
{
@ -1089,8 +1028,8 @@ DWORD set_cookie(const WCHAR *domain, const WCHAR *path, const WCHAR *cookie_nam
DWORD WINAPI InternetSetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
LPCWSTR lpCookieData, DWORD flags, DWORD_PTR reserved)
{
substr_t host, path, name, data;
BOOL ret;
WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH], path[INTERNET_MAX_PATH_LENGTH];
TRACE("(%s, %s, %s, %x, %lx)\n", debugstr_w(lpszUrl), debugstr_w(lpszCookieName),
debugstr_w(lpCookieData), flags, reserved);
@ -1104,34 +1043,26 @@ DWORD WINAPI InternetSetCookieExW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName,
return COOKIE_STATE_UNKNOWN;
}
hostName[0] = 0;
ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0]));
if (!ret || !hostName[0]) return COOKIE_STATE_UNKNOWN;
ret = cookie_parse_url(lpszUrl, &host, &path);
if (!ret || !host.len) return COOKIE_STATE_UNKNOWN;
if (!lpszCookieName)
{
WCHAR *cookie, *data;
DWORD res;
cookie = heap_strdupW(lpCookieData);
if (!cookie)
{
SetLastError(ERROR_OUTOFMEMORY);
return COOKIE_STATE_UNKNOWN;
}
if (!lpszCookieName) {
const WCHAR *ptr;
/* some apps (or is it us??) try to add a cookie with no cookie name, but
* the cookie data in the form of name[=data].
*/
if (!(data = strchrW(cookie, '='))) data = cookie + strlenW(cookie);
else *data++ = 0;
if (!(ptr = strchrW(lpCookieData, '=')))
ptr = lpCookieData + strlenW(lpCookieData);
res = set_cookie(hostName, path, cookie, data, flags);
heap_free(cookie);
return res;
name = substr(lpCookieData, ptr - lpCookieData);
data = substrz(*ptr == '=' ? ptr+1 : ptr);
}else {
name = substrz(lpszCookieName);
data = substrz(lpCookieData);
}
return set_cookie(hostName, path, lpszCookieName, lpCookieData, flags);
return set_cookie(host, path, name, data, flags);
}
/***********************************************************************

View file

@ -179,7 +179,6 @@ static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT
static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
static BOOL drain_content(http_request_t*,BOOL);
@ -247,7 +246,7 @@ static BOOL process_host_port(server_t *server)
return TRUE;
}
server_t *get_server(const WCHAR *name, INTERNET_PORT port, BOOL is_https, BOOL do_create)
server_t *get_server(substr_t name, INTERNET_PORT port, BOOL is_https, BOOL do_create)
{
server_t *iter, *server = NULL;
@ -257,7 +256,8 @@ server_t *get_server(const WCHAR *name, INTERNET_PORT port, BOOL is_https, BOOL
EnterCriticalSection(&connection_pool_cs);
LIST_FOR_EACH_ENTRY(iter, &connection_pool, server_t, entry) {
if(iter->port == port && !strcmpW(iter->name, name) && iter->is_https == is_https) {
if(iter->port == port && name.len == strlenW(iter->name) && !strncmpW(iter->name, name.str, name.len)
&& iter->is_https == is_https) {
server = iter;
server_addref(server);
break;
@ -271,7 +271,7 @@ server_t *get_server(const WCHAR *name, INTERNET_PORT port, BOOL is_https, BOOL
server->port = port;
server->is_https = is_https;
list_init(&server->conn_pool);
server->name = heap_strdupW(name);
server->name = heap_strndupW(name.str, name.len);
if(server->name && process_host_port(server)) {
list_add_head(&connection_pool, &server->entry);
}else {
@ -767,7 +767,7 @@ static void HTTP_ProcessCookies( http_request_t *request )
while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, szSet_Cookie, numCookies++, FALSE)) != -1)
{
const WCHAR *data;
WCHAR *name;
substr_t name;
setCookieHeader = &request->custHeaders[HeaderIndex];
@ -778,13 +778,9 @@ static void HTTP_ProcessCookies( http_request_t *request )
if(!data)
continue;
name = heap_strndupW(setCookieHeader->lpszValue, data-setCookieHeader->lpszValue);
if(!name)
continue;
name = substr(setCookieHeader->lpszValue, data - setCookieHeader->lpszValue);
data++;
set_cookie(request->server->name, path, name, data, INTERNET_COOKIE_HTTPONLY);
heap_free(name);
set_cookie(substrz(request->server->name), substrz(path), name, substrz(data), INTERNET_COOKIE_HTTPONLY);
}
LeaveCriticalSection( &request->headers_section );
@ -1371,21 +1367,17 @@ BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
{
DWORD len;
LPWSTR hdr;
WCHAR *headers = NULL;
BOOL r;
TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
hdr = heap_alloc(len*sizeof(WCHAR));
MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
if( dwHeaderLength != ~0U )
dwHeaderLength = len;
if(lpszHeader)
headers = heap_strndupAtoW(lpszHeader, dwHeaderLength, &dwHeaderLength);
r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
r = HttpAddRequestHeadersW(hHttpRequest, headers, dwHeaderLength, dwModifier);
heap_free( hdr );
heap_free(headers);
return r;
}
@ -1717,55 +1709,47 @@ static WCHAR *build_proxy_path_url(http_request_t *req)
return url;
}
static BOOL HTTP_DomainMatches(LPCWSTR server, LPCWSTR domain)
static BOOL HTTP_DomainMatches(LPCWSTR server, substr_t domain)
{
static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
BOOL ret = FALSE;
const WCHAR *dot, *ptr;
int len;
if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
ret = TRUE;
else if (*domain == '*')
{
if (domain[1] == '.')
{
LPCWSTR dot;
if(domain.len == sizeof(localW)/sizeof(WCHAR)-1 && !strncmpiW(domain.str, localW, domain.len) && !strchrW(server, '.' ))
return TRUE;
/* 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(domain.len && *domain.str != '*')
return domain.len == strlenW(server) && !strncmpiW(server, domain.str, domain.len);
if (len > strlenW( domain + 2 ))
{
LPCWSTR ptr;
if(domain.len < 2 || domain.str[1] != '.')
return FALSE;
/* 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;
/* 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)
return FALSE;
len = strlenW(dot + 1);
if(len <= domain.len - 2)
return FALSE;
/* 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 + 1 + len - domain.len + 2;
if(!strncmpiW(ptr, domain.str+2, domain.len-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.
*/
return *(ptr - 1) == '.';
return len == domain.len-2 && !strncmpiW(dot + 1, domain.str + 2, len);
}
static BOOL HTTP_ShouldBypassProxy(appinfo_t *lpwai, LPCWSTR server)
@ -1775,27 +1759,19 @@ static BOOL HTTP_ShouldBypassProxy(appinfo_t *lpwai, LPCWSTR server)
if (!lpwai->proxyBypass) return FALSE;
ptr = lpwai->proxyBypass;
do {
while(1) {
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);
if (!ptr)
ptr = tmp + strlenW(ptr);
ret = HTTP_DomainMatches( server, substr(tmp, ptr-tmp) );
if (ret || !*ptr)
break;
ptr++;
}
return ret;
}
@ -1806,41 +1782,34 @@ static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *session, http_req
{
static const WCHAR protoHttp[] = { 'h','t','t','p',0 };
static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
WCHAR buf[INTERNET_MAX_HOST_NAME_LENGTH];
WCHAR protoProxy[INTERNET_MAX_URL_LENGTH];
DWORD protoProxyLen = INTERNET_MAX_URL_LENGTH;
WCHAR proxy[INTERNET_MAX_URL_LENGTH];
static WCHAR szNul[] = { 0 };
URL_COMPONENTSW UrlComponents;
server_t *new_server;
BOOL is_https;
URL_COMPONENTSW UrlComponents = { sizeof(UrlComponents) };
server_t *new_server = NULL;
WCHAR *proxy;
memset( &UrlComponents, 0, sizeof UrlComponents );
UrlComponents.dwStructSize = sizeof UrlComponents;
UrlComponents.lpszHostName = buf;
UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
if (!INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp, protoProxy, &protoProxyLen))
return FALSE;
if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
sprintfW(proxy, szFormat, protoProxy);
else
strcpyW(proxy, protoProxy);
if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
return FALSE;
if( UrlComponents.dwHostNameLength == 0 )
proxy = INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp);
if(!proxy)
return FALSE;
if(CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
proxy, strlenW(szHttp), szHttp, strlenW(szHttp))) {
WCHAR *proxy_url = heap_alloc(strlenW(proxy)*sizeof(WCHAR) + sizeof(szHttp));
if(!proxy_url)
return FALSE;
strcpyW(proxy_url, szHttp);
strcatW(proxy_url, proxy);
heap_free(proxy);
proxy = proxy_url;
}
if( !request->path )
request->path = szNul;
UrlComponents.dwHostNameLength = 1;
if(InternetCrackUrlW(proxy, 0, 0, &UrlComponents) && UrlComponents.dwHostNameLength) {
if( !request->path )
request->path = szNul;
is_https = (UrlComponents.nScheme == INTERNET_SCHEME_HTTPS);
if (is_https && UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
UrlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
new_server = get_server(UrlComponents.lpszHostName, UrlComponents.nPort, is_https, TRUE);
new_server = get_server(substr(UrlComponents.lpszHostName, UrlComponents.dwHostNameLength),
UrlComponents.nPort, UrlComponents.nScheme == INTERNET_SCHEME_HTTPS, TRUE);
}
heap_free(proxy);
if(!new_server)
return FALSE;
@ -1876,33 +1845,39 @@ static DWORD HTTP_ResolveName(http_request_t *request)
return ERROR_SUCCESS;
}
static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
static WCHAR *compose_request_url(http_request_t *req)
{
static const WCHAR http[] = { 'h','t','t','p',':','/','/',0 };
static const WCHAR https[] = { 'h','t','t','p','s',':','/','/',0 };
static const WCHAR slash[] = { '/',0 };
LPHTTPHEADERW host_header;
const WCHAR *host;
LPCWSTR scheme;
const WCHAR *host, *scheme;
WCHAR *buf, *ptr;
size_t len;
EnterCriticalSection( &req->headers_section );
host = req->server->canon_host_port;
host_header = HTTP_GetHeader(req, hostW);
if (host_header) host = host_header->lpszValue;
else host = req->server->canon_host_port;
if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
if (req->server->is_https)
scheme = https;
else
scheme = http;
strcpyW(buf, scheme);
strcatW(buf, host);
if (req->path[0] != '/')
strcatW(buf, slash);
strcatW(buf, req->path);
LeaveCriticalSection( &req->headers_section );
return TRUE;
len = strlenW(scheme) + strlenW(host) + (req->path[0] != '/' ? 1 : 0) + strlenW(req->path);
ptr = buf = heap_alloc((len+1) * sizeof(WCHAR));
if(buf) {
strcpyW(ptr, scheme);
ptr += strlenW(ptr);
strcpyW(ptr, host);
ptr += strlenW(ptr);
if(req->path[0] != '/')
*ptr++ = '/';
strcpyW(ptr, req->path);
ptr += strlenW(ptr);
*ptr = 0;
}
return buf;
}
@ -2140,17 +2115,18 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
return ERROR_SUCCESS;
case INTERNET_OPTION_URL: {
static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
WCHAR url[INTERNET_MAX_URL_LENGTH];
WCHAR *url;
DWORD res;
TRACE("INTERNET_OPTION_URL\n");
strcpyW(url, httpW);
strcatW(url, req->server->canon_host_port);
strcatW(url, req->path);
url = compose_request_url(req);
if(!url)
return ERROR_OUTOFMEMORY;
TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
return str_to_buffer(url, buffer, size, unicode);
res = str_to_buffer(url, buffer, size, unicode);
heap_free(url);
return res;
}
case INTERNET_OPTION_USER_AGENT:
return str_to_buffer(req->session->appInfo->agent, buffer, size, unicode);
@ -2166,27 +2142,29 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
case INTERNET_OPTION_CACHE_TIMESTAMPS: {
INTERNET_CACHE_ENTRY_INFOW *info;
INTERNET_CACHE_TIMESTAMPS *ts = buffer;
WCHAR url[INTERNET_MAX_URL_LENGTH];
DWORD nbytes, error;
BOOL ret;
TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
if(!req->req_file)
return ERROR_FILE_NOT_FOUND;
if (*size < sizeof(*ts))
{
*size = sizeof(*ts);
return ERROR_INSUFFICIENT_BUFFER;
}
nbytes = 0;
HTTP_GetRequestURL(req, url);
ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
ret = GetUrlCacheEntryInfoW(req->req_file->url, NULL, &nbytes);
error = GetLastError();
if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
{
if (!(info = heap_alloc(nbytes)))
return ERROR_OUTOFMEMORY;
GetUrlCacheEntryInfoW(url, info, &nbytes);
GetUrlCacheEntryInfoW(req->req_file->url, info, &nbytes);
ts->ftExpires = info->ExpireTime;
ts->ftLastModified = info->LastModifiedTime;
@ -2375,29 +2353,25 @@ static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer,
static void commit_cache_entry(http_request_t *req)
{
WCHAR url[INTERNET_MAX_URL_LENGTH];
WCHAR *header;
DWORD header_len;
BOOL res;
TRACE("%p\n", req);
CloseHandle(req->hCacheFile);
req->hCacheFile = NULL;
if(HTTP_GetRequestURL(req, url)) {
WCHAR *header;
DWORD header_len;
BOOL res;
header = build_response_header(req, TRUE);
header_len = (header ? strlenW(header) : 0);
res = CommitUrlCacheEntryW(url, req->req_file->file_name, req->expires,
req->last_modified, NORMAL_CACHE_ENTRY,
header, header_len, NULL, 0);
if(res)
req->req_file->is_committed = TRUE;
else
WARN("CommitUrlCacheEntry failed: %u\n", GetLastError());
heap_free(header);
}
header = build_response_header(req, TRUE);
header_len = (header ? strlenW(header) : 0);
res = CommitUrlCacheEntryW(req->req_file->url, req->req_file->file_name, req->expires,
req->last_modified, NORMAL_CACHE_ENTRY,
header, header_len, NULL, 0);
if(res)
req->req_file->is_committed = TRUE;
else
WARN("CommitUrlCacheEntry failed: %u\n", GetLastError());
heap_free(header);
}
static void create_cache_entry(http_request_t *req)
@ -2405,8 +2379,8 @@ static void create_cache_entry(http_request_t *req)
static const WCHAR no_cacheW[] = {'n','o','-','c','a','c','h','e',0};
static const WCHAR no_storeW[] = {'n','o','-','s','t','o','r','e',0};
WCHAR url[INTERNET_MAX_URL_LENGTH];
WCHAR file_name[MAX_PATH+1];
WCHAR *url;
BOOL b = TRUE;
/* FIXME: We should free previous cache file earlier */
@ -2463,8 +2437,8 @@ static void create_cache_entry(http_request_t *req)
FIXME("INTERNET_FLAG_NEED_FILE is not supported correctly\n");
}
b = HTTP_GetRequestURL(req, url);
if(!b) {
url = compose_request_url(req);
if(!url) {
WARN("Could not get URL\n");
return;
}
@ -2476,6 +2450,7 @@ static void create_cache_entry(http_request_t *req)
}
create_req_file(file_name, &req->req_file);
req->req_file->url = url;
req->hCacheFile = CreateFileW(file_name, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
@ -3036,7 +3011,7 @@ static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif, DWORD
}
/* read data from the http connection (the read section must be held) */
static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read)
{
DWORD current_read = 0, ret_read = 0;
blocking_mode_t blocking_mode;
@ -3090,7 +3065,7 @@ static BOOL drain_content(http_request_t *req, BOOL blocking)
DWORD bytes_read, res;
BYTE buf[4096];
res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read, TRUE);
res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read);
if(res != ERROR_SUCCESS) {
ret = FALSE;
break;
@ -3105,23 +3080,6 @@ static BOOL drain_content(http_request_t *req, BOOL blocking)
return ret;
}
static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
{
http_request_t *req = (http_request_t*)hdr;
DWORD res;
EnterCriticalSection( &req->read_section );
if(hdr->dwError == INTERNET_HANDLE_IN_USE)
hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
res = HTTPREQ_Read(req, buffer, size, read, TRUE);
if(res == ERROR_SUCCESS)
res = hdr->dwError;
LeaveCriticalSection( &req->read_section );
return res;
}
typedef struct {
task_header_t hdr;
void *buf;
@ -3133,11 +3091,23 @@ static void AsyncReadFileExProc(task_header_t *hdr)
{
read_file_ex_task_t *task = (read_file_ex_task_t*)hdr;
http_request_t *req = (http_request_t*)task->hdr.hdr;
DWORD res;
DWORD res = ERROR_SUCCESS, read = 0, buffered = 0;
TRACE("INTERNETREADFILEEXW %p\n", task->hdr.hdr);
TRACE("%p\n", req);
if(task->ret_read)
res = HTTPREQ_Read(req, task->buf, task->size, &read);
if(res == ERROR_SUCCESS)
res = refill_read_buffer(req, task->ret_read ? BLOCKING_DISALLOW : BLOCKING_ALLOW, &buffered);
if (res == ERROR_SUCCESS)
{
if(task->ret_read)
*task->ret_read = read;
read += buffered;
INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
&read, sizeof(read));
}
res = HTTPREQ_Read(req, task->buf, task->size, task->ret_read, TRUE);
send_request_complete(req, res == ERROR_SUCCESS, res);
}
@ -3148,20 +3118,22 @@ static DWORD HTTPREQ_ReadFileEx(object_header_t *hdr, void *buf, DWORD size, DWO
http_request_t *req = (http_request_t*)hdr;
DWORD res, read, cread, error = ERROR_SUCCESS;
TRACE("(%p %p %u %x)\n", req, buf, size, flags);
if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
read_file_ex_task_t *task;
if (TryEnterCriticalSection( &req->read_section ))
{
if (get_avail_data(req))
if (get_avail_data(req) || end_of_read_data(req))
{
res = HTTPREQ_Read(req, buf, size, &read, FALSE);
res = HTTPREQ_Read(req, buf, size, &read);
LeaveCriticalSection( &req->read_section );
goto done;
}
@ -3171,7 +3143,7 @@ static DWORD HTTPREQ_ReadFileEx(object_header_t *hdr, void *buf, DWORD size, DWO
task = alloc_async_task(&req->hdr, AsyncReadFileExProc, sizeof(*task));
task->buf = buf;
task->size = size;
task->ret_read = ret_read;
task->ret_read = (flags & IRF_NO_WAIT) ? NULL : ret_read;
INTERNET_AsyncCall(&task->hdr);
@ -3187,7 +3159,7 @@ static DWORD HTTPREQ_ReadFileEx(object_header_t *hdr, void *buf, DWORD size, DWO
hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
while(1) {
res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread, !(flags & IRF_NO_WAIT));
res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread);
if(res != ERROR_SUCCESS)
break;
@ -3238,6 +3210,49 @@ static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD s
return res;
}
static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
{
http_request_t *req = (http_request_t*)hdr;
DWORD res;
if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
read_file_ex_task_t *task;
if (TryEnterCriticalSection( &req->read_section ))
{
if (get_avail_data(req) || end_of_read_data(req))
{
res = HTTPREQ_Read(req, buffer, size, read);
LeaveCriticalSection( &req->read_section );
return res;
}
LeaveCriticalSection( &req->read_section );
}
task = alloc_async_task(&req->hdr, AsyncReadFileExProc, sizeof(*task));
task->buf = buffer;
task->size = size;
task->ret_read = read;
*read = 0;
INTERNET_AsyncCall(&task->hdr);
return ERROR_IO_PENDING;
}
EnterCriticalSection( &req->read_section );
if(hdr->dwError == INTERNET_HANDLE_IN_USE)
hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
res = HTTPREQ_Read(req, buffer, size, read);
if(res == ERROR_SUCCESS)
res = hdr->dwError;
LeaveCriticalSection( &req->read_section );
return res;
}
typedef struct {
task_header_t hdr;
DWORD *ret_size;
@ -3335,7 +3350,7 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
{
appinfo_t *hIC = session->appInfo;
http_request_t *request;
DWORD len;
DWORD port, len;
TRACE("-->\n");
@ -3364,7 +3379,14 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
request->session = session;
list_add_head( &session->hdr.children, &request->hdr.entry );
request->server = get_server(session->hostName, session->hostPort, (dwFlags & INTERNET_FLAG_SECURE) != 0, TRUE);
port = session->hostPort;
if (port == INTERNET_INVALID_PORT_NUMBER)
{
port = (session->hdr.dwFlags & INTERNET_FLAG_SECURE) ?
INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
}
request->server = get_server(substrz(session->hostName), port, (dwFlags & INTERNET_FLAG_SECURE) != 0, TRUE);
if(!request->server) {
WININET_Release(&request->hdr);
return ERROR_OUTOFMEMORY;
@ -4032,64 +4054,57 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
return result;
}
/***********************************************************************
* HTTP_GetRedirectURL (internal)
*/
static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl)
static WCHAR *get_redirect_url(http_request_t *request)
{
static WCHAR szHttp[] = {'h','t','t','p',0};
static WCHAR szHttps[] = {'h','t','t','p','s',0};
http_session_t *session = request->session;
URL_COMPONENTSW urlComponents;
DWORD url_length = 0;
LPWSTR orig_url;
LPWSTR combined_url;
urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
urlComponents.dwSchemeLength = 0;
urlComponents.lpszHostName = request->server->name;
urlComponents.dwHostNameLength = 0;
urlComponents.nPort = request->server->port;
urlComponents.lpszUserName = session->userName;
urlComponents.dwUserNameLength = 0;
urlComponents.lpszPassword = NULL;
urlComponents.dwPasswordLength = 0;
urlComponents.lpszUrlPath = request->path;
urlComponents.dwUrlPathLength = 0;
urlComponents.lpszExtraInfo = NULL;
urlComponents.dwExtraInfoLength = 0;
if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
(GetLastError() != ERROR_INSUFFICIENT_BUFFER))
return NULL;
orig_url = heap_alloc(url_length);
/* convert from bytes to characters */
url_length = url_length / sizeof(WCHAR) - 1;
if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
{
heap_free(orig_url);
return NULL;
}
URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
WCHAR *orig_url = NULL, *redirect_url = NULL, *combined_url = NULL;
DWORD url_length = 0, res;
BOOL b;
url_length = 0;
if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
(GetLastError() != ERROR_INSUFFICIENT_BUFFER))
{
heap_free(orig_url);
res = HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, redirect_url, &url_length, NULL);
if(res == ERROR_INSUFFICIENT_BUFFER) {
redirect_url = heap_alloc(url_length);
res = HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, redirect_url, &url_length, NULL);
}
if(res != ERROR_SUCCESS) {
heap_free(redirect_url);
return NULL;
}
combined_url = heap_alloc(url_length * sizeof(WCHAR));
if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
{
heap_free(orig_url);
heap_free(combined_url);
return NULL;
urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
urlComponents.lpszHostName = request->server->name;
urlComponents.nPort = request->server->port;
urlComponents.lpszUserName = session->userName;
urlComponents.lpszUrlPath = request->path;
b = InternetCreateUrlW(&urlComponents, 0, NULL, &url_length);
if(!b && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
orig_url = heap_alloc(url_length);
/* convert from bytes to characters */
url_length = url_length / sizeof(WCHAR) - 1;
b = InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length);
}
if(b) {
url_length = 0;
b = InternetCombineUrlW(orig_url, redirect_url, NULL, &url_length, ICU_ENCODE_SPACES_ONLY);
if(!b && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
combined_url = heap_alloc(url_length * sizeof(WCHAR));
b = InternetCombineUrlW(orig_url, redirect_url, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY);
if(!b) {
heap_free(combined_url);
combined_url = NULL;
}
}
}
heap_free(orig_url);
heap_free(redirect_url);
return combined_url;
}
@ -4100,84 +4115,62 @@ static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl)
static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
{
http_session_t *session = request->session;
WCHAR path[INTERNET_MAX_PATH_LENGTH];
WCHAR *path;
if(lpszUrl[0]=='/')
{
/* if it's an absolute path, keep the same session info */
lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
path = heap_strdupW(lpszUrl);
}
else
{
URL_COMPONENTSW urlComponents;
WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH];
WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH];
WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH];
URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
BOOL custom_port = FALSE;
substr_t host;
static const WCHAR httpW[] = {'h','t','t','p',0};
static const WCHAR httpsW[] = {'h','t','t','p','s',0};
userName[0] = 0;
hostName[0] = 0;
protocol[0] = 0;
urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
urlComponents.lpszScheme = protocol;
urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
urlComponents.lpszUserName = userName;
urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
urlComponents.lpszPassword = NULL;
urlComponents.dwPasswordLength = 0;
urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
urlComponents.lpszExtraInfo = NULL;
urlComponents.dwExtraInfoLength = 0;
urlComponents.dwHostNameLength = 1;
urlComponents.dwUserNameLength = 1;
urlComponents.dwUrlPathLength = 1;
if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
return INTERNET_GetLastError();
if(!strcmpiW(protocol, httpW)) {
if(urlComponents.nScheme == INTERNET_SCHEME_HTTP) {
if(request->hdr.dwFlags & INTERNET_FLAG_SECURE) {
TRACE("redirect from secure page to non-secure page\n");
/* FIXME: warn about from secure redirect to non-secure page */
request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
}
if(urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
else if(urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT)
custom_port = TRUE;
}else if(!strcmpiW(protocol, httpsW)) {
custom_port = urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT;
}else if(urlComponents.nScheme == INTERNET_SCHEME_HTTPS) {
if(!(request->hdr.dwFlags & INTERNET_FLAG_SECURE)) {
TRACE("redirect from non-secure page to secure page\n");
/* FIXME: notify about redirect to secure page */
request->hdr.dwFlags |= INTERNET_FLAG_SECURE;
}
if(urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
else if(urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
custom_port = TRUE;
custom_port = urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT;
}
heap_free(session->hostName);
session->hostName = heap_strdupW(hostName);
session->hostName = heap_strndupW(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
session->hostPort = urlComponents.nPort;
heap_free(session->userName);
session->userName = NULL;
if (userName[0])
session->userName = heap_strdupW(userName);
if (urlComponents.dwUserNameLength)
session->userName = heap_strndupW(urlComponents.lpszUserName, urlComponents.dwUserNameLength);
reset_data_stream(request);
if(strcmpiW(request->server->name, hostName) || request->server->port != urlComponents.nPort) {
host = substr(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
if(host.len != strlenW(request->server->name) || strncmpiW(request->server->name, host.str, host.len)
|| request->server->port != urlComponents.nPort) {
server_t *new_server;
new_server = get_server(hostName, urlComponents.nPort, urlComponents.nScheme == INTERNET_SCHEME_HTTPS, TRUE);
new_server = get_server(host, urlComponents.nPort, urlComponents.nScheme == INTERNET_SCHEME_HTTPS, TRUE);
server_release(request->server);
request->server = new_server;
}
@ -4186,16 +4179,18 @@ static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
HTTP_ProcessHeader(request, hostW, request->server->host_port, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
else
HTTP_ProcessHeader(request, hostW, request->server->name, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
path = heap_strndupW(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
}
heap_free(request->path);
request->path=NULL;
request->path = NULL;
if (*path)
{
DWORD needed = 0;
HRESULT rc;
rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
if (rc != E_POINTER)
if (rc == E_POINTER)
needed = strlenW(path)+1;
request->path = heap_alloc(needed*sizeof(WCHAR));
rc = UrlEscapeW(path, request->path, &needed,
@ -4203,10 +4198,12 @@ static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
if (rc != S_OK)
{
ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
strcpyW(request->path,path);
strcpyW(request->path, path);
}
}
heap_free(path);
/* Remove custom content-type/length headers on redirects. */
remove_header(request, szContent_Type, TRUE);
remove_header(request, szContent_Length, TRUE);
@ -5097,14 +5094,15 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen)
{
WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
dwBufferSize=sizeof(szNewLocation);
WCHAR *new_url;
switch(request->status_code) {
case HTTP_STATUS_REDIRECT:
case HTTP_STATUS_MOVED:
case HTTP_STATUS_REDIRECT_KEEP_VERB:
case HTTP_STATUS_REDIRECT_METHOD:
if(HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) != ERROR_SUCCESS)
new_url = get_redirect_url(request);
if(!new_url)
break;
if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
@ -5114,17 +5112,13 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
request->verb = heap_strdupW(szGET);
}
http_release_netconn(request, drain_content(request, FALSE));
if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
{
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
res = HTTP_HandleRedirect(request, new_url);
if (res == ERROR_SUCCESS)
{
heap_free(requestString);
loop_next = TRUE;
}
heap_free( new_url );
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
res = HTTP_HandleRedirect(request, new_url);
heap_free(new_url);
if (res == ERROR_SUCCESS) {
heap_free(requestString);
loop_next = TRUE;
}
redirected = TRUE;
}
@ -5267,7 +5261,6 @@ static void AsyncHttpSendRequestProc(task_header_t *hdr)
static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_PTR dwContext)
{
DWORD dwBufferSize;
INT responseLen;
DWORD res = ERROR_SUCCESS;
@ -5304,9 +5297,10 @@ static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_
case HTTP_STATUS_MOVED:
case HTTP_STATUS_REDIRECT_METHOD:
case HTTP_STATUS_REDIRECT_KEEP_VERB: {
WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
dwBufferSize=sizeof(szNewLocation);
if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) != ERROR_SUCCESS)
WCHAR *new_url;
new_url = get_redirect_url(request);
if(!new_url)
break;
if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) &&
@ -5316,15 +5310,12 @@ static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_
request->verb = heap_strdupW(szGET);
}
http_release_netconn(request, drain_content(request, FALSE));
if ((new_url = HTTP_GetRedirectURL( request, szNewLocation )))
{
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
res = HTTP_HandleRedirect(request, new_url);
if (res == ERROR_SUCCESS)
res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE);
heap_free( new_url );
}
INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT,
new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
res = HTTP_HandleRedirect(request, new_url);
heap_free(new_url);
if (res == ERROR_SUCCESS)
res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -89,10 +89,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet);
extern HMODULE WININET_hModule DECLSPEC_HIDDEN;
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
typedef struct {
WCHAR *name;
INTERNET_PORT port;
@ -227,6 +223,25 @@ static inline LPWSTR heap_strndupW(LPCWSTR str, UINT max_len)
return ret;
}
static inline WCHAR *heap_strndupAtoW(const char *str, int len_a, DWORD *len_w)
{
WCHAR *ret = NULL;
if(str) {
size_t len;
if(len_a < 0) len_a = strlen(str);
len = MultiByteToWideChar(CP_ACP, 0, str, len_a, NULL, 0);
ret = heap_alloc((len+1)*sizeof(WCHAR));
if(ret) {
MultiByteToWideChar(CP_ACP, 0, str, len_a, ret, len);
ret[len] = 0;
*len_w = len;
}
}
return ret;
}
static inline WCHAR *heap_strdupAtoW(const char *str)
{
LPWSTR ret = NULL;
@ -257,6 +272,22 @@ static inline char *heap_strdupWtoA(LPCWSTR str)
return ret;
}
typedef struct {
const WCHAR *str;
size_t len;
} substr_t;
static inline substr_t substr(const WCHAR *str, size_t len)
{
substr_t r = {str, len};
return r;
}
static inline substr_t substrz(const WCHAR *str)
{
return substr(str, strlenW(str));
}
static inline void WININET_find_data_WtoA(LPWIN32_FIND_DATAW dataW, LPWIN32_FIND_DATAA dataA)
{
dataA->dwFileAttributes = dataW->dwFileAttributes;
@ -294,6 +325,7 @@ typedef struct
LONG ref;
HANDLE file_handle;
WCHAR *file_name;
WCHAR *url;
BOOL is_committed;
} req_file_t;
@ -461,7 +493,7 @@ DWORD HTTP_Connect(appinfo_t*,LPCWSTR,
BOOL GetAddress(const WCHAR*,INTERNET_PORT,SOCKADDR*,int*,char*) DECLSPEC_HIDDEN;
DWORD get_cookie_header(const WCHAR*,const WCHAR*,WCHAR**) DECLSPEC_HIDDEN;
DWORD set_cookie(const WCHAR*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD) DECLSPEC_HIDDEN;
DWORD set_cookie(substr_t,substr_t,substr_t,substr_t,DWORD) DECLSPEC_HIDDEN;
void INTERNET_SetLastError(DWORD dwError) DECLSPEC_HIDDEN;
DWORD INTERNET_GetLastError(void) DECLSPEC_HIDDEN;
@ -475,7 +507,7 @@ VOID SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext,
VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext,
DWORD dwInternetStatus, LPVOID lpvStatusInfo,
DWORD dwStatusInfoLength) DECLSPEC_HIDDEN;
BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen) DECLSPEC_HIDDEN;
WCHAR *INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto) DECLSPEC_HIDDEN;
DWORD create_netconn(BOOL,server_t*,DWORD,BOOL,DWORD,netconn_t**) DECLSPEC_HIDDEN;
void free_netconn(netconn_t*) DECLSPEC_HIDDEN;
@ -492,7 +524,7 @@ DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, DWORD value) DECLSPEC
int sock_send(int fd, const void *msg, size_t len, int flags) DECLSPEC_HIDDEN;
int sock_recv(int fd, void *msg, size_t len, int flags) DECLSPEC_HIDDEN;
server_t *get_server(const WCHAR*,INTERNET_PORT,BOOL,BOOL) DECLSPEC_HIDDEN;
server_t *get_server(substr_t,INTERNET_PORT,BOOL,BOOL) DECLSPEC_HIDDEN;
DWORD create_req_file(const WCHAR*,req_file_t**) DECLSPEC_HIDDEN;
void req_file_release(req_file_t*) DECLSPEC_HIDDEN;

View file

@ -389,6 +389,7 @@ void free_netconn(netconn_t *netconn)
DeleteSecurityContext(&netconn->ssl_ctx);
}
close_netconn(netconn);
heap_free(netconn);
}

View file

@ -2109,7 +2109,7 @@ static BOOL urlcache_entry_get_file(const char *url, void *entry_info, DWORD *si
if (!urlcache_find_hash_entry(header, url, &hash_entry)) {
cache_container_unlock_index(container, header);
TRACE("entry %s not found!\n", url);
TRACE("entry %s not found!\n", debugstr_a(url));
SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}

View file

@ -1,7 +1,7 @@
diff -pudN e:\wine\dlls\wininet/http.c e:\reactos\dll\win32\wininet/http.c
--- e:\wine\dlls\wininet/http.c 2015-07-14 15:44:36.040192300 +0100
+++ e:\reactos\dll\win32\wininet/http.c 2015-07-20 14:37:24.319646400 +0100
@@ -143,6 +118,7 @@ static const WCHAR emptyW[] = {0};
--- e:\wine\dlls\wininet/http.c 2016-05-31 18:02:43 +0100
+++ e:\reactos\dll\win32\wininet/http.c 2016-07-02 16:18:16 +0100
@@ -118,6 +118,7 @@ static const WCHAR emptyW[] = {0};
#define COLLECT_TIME 60000
@ -9,7 +9,7 @@ diff -pudN e:\wine\dlls\wininet/http.c e:\reactos\dll\win32\wininet/http.c
#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
struct HttpAuthInfo
@@ -229,7 +205,13 @@ void server_release(server_t *server)
@@ -203,7 +204,13 @@ void server_release(server_t *server)
if(InterlockedDecrement(&server->ref))
return;
@ -23,7 +23,7 @@ diff -pudN e:\wine\dlls\wininet/http.c e:\reactos\dll\win32\wininet/http.c
if(server->cert_chain)
CertFreeCertificateChain(server->cert_chain);
@@ -311,7 +293,11 @@ BOOL collect_connections(collect_type_t
@@ -286,7 +293,11 @@ BOOL collect_connections(collect_type_t
BOOL remaining = FALSE;
DWORD64 now;
@ -35,7 +35,7 @@ diff -pudN e:\wine\dlls\wininet/http.c e:\reactos\dll\win32\wininet/http.c
LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) {
LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) {
@@ -1973,13 +1959,14 @@ static void http_release_netconn(http_re
@@ -1923,13 +1934,14 @@ static void http_release_netconn(http_re
if(!is_valid_netconn(req->netconn))
return;
@ -51,7 +51,7 @@ diff -pudN e:\wine\dlls\wininet/http.c e:\reactos\dll\win32\wininet/http.c
req->netconn = NULL;
run_collector = !collector_running;
@@ -2007,6 +1994,10 @@ static void http_release_netconn(http_re
@@ -1957,6 +1969,10 @@ static void http_release_netconn(http_re
}
return;
}
@ -63,9 +63,9 @@ diff -pudN e:\wine\dlls\wininet/http.c e:\reactos\dll\win32\wininet/http.c
INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
diff -pudN e:\wine\dlls\wininet/internet.c e:\reactos\dll\win32\wininet/internet.c
--- e:\wine\dlls\wininet/internet.c 2015-04-12 18:21:54.309796800 +0100
+++ e:\reactos\dll\win32\wininet/internet.c 2015-07-20 14:38:19.188784800 +0100
@@ -1033,6 +996,9 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR l
--- e:\wine\dlls\wininet/internet.c 2016-05-31 18:05:36 +0100
+++ e:\reactos\dll\win32\wininet/internet.c 2016-07-02 16:18:16 +0100
@@ -963,6 +963,9 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR l
{
appinfo_t *lpwai = NULL;
@ -77,9 +77,9 @@ diff -pudN e:\wine\dlls\wininet/internet.c e:\reactos\dll\win32\wininet/internet
static const wininet_flag_info access_type[] = {
diff -pudN e:\wine\dlls\wininet/urlcache.c e:\reactos\dll\win32\wininet/urlcache.c
--- e:\wine\dlls\wininet/urlcache.c 2015-07-14 15:44:36.059193400 +0100
+++ e:\reactos\dll\win32\wininet/urlcache.c 2015-07-20 14:40:55.736738800 +0100
@@ -202,6 +179,8 @@ typedef struct
--- e:\wine\dlls\wininet/urlcache.c 2016-05-31 18:02:43 +0100
+++ e:\reactos\dll\win32\wininet/urlcache.c 2016-07-02 16:18:16 +0100
@@ -179,6 +179,8 @@ typedef struct
/* List of all containers available */
static struct list UrlContainers = LIST_INIT(UrlContainers);
@ -88,7 +88,7 @@ diff -pudN e:\wine\dlls\wininet/urlcache.c e:\reactos\dll\win32\wininet/urlcache
static inline char *heap_strdupWtoUTF8(LPCWSTR str)
{
@@ -752,6 +731,8 @@ static void cache_containers_init(void)
@@ -729,6 +731,8 @@ static void cache_containers_init(void)
static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
static const WCHAR CookieSuffix[] = {0};
@ -97,21 +97,21 @@ diff -pudN e:\wine\dlls\wininet/urlcache.c e:\reactos\dll\win32\wininet/urlcache
static const struct
{
int nFolder; /* CSIDL_* constant */
@@ -766,6 +747,13 @@ static void cache_containers_init(void)
@@ -743,6 +747,13 @@ static void cache_containers_init(void)
};
DWORD i;
+ /* ReactOS r50916 */
+ if (GetEnvironmentVariableW(UserProfile, NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+ {
+ TRACE("Environment variable 'USERPROFILE' does not exist!\n");
+ ERR("Environment variable 'USERPROFILE' does not exist!\n");
+ return;
+ }
+
for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
{
WCHAR wszCachePath[MAX_PATH];
@@ -816,6 +804,10 @@ static void cache_containers_init(void)
@@ -793,6 +804,10 @@ static void cache_containers_init(void)
cache_containers_add(DefaultContainerData[i].cache_prefix, wszCachePath,
DefaultContainerData[i].default_entry_type, wszMutexName);
}
@ -122,7 +122,7 @@ diff -pudN e:\wine\dlls\wininet/urlcache.c e:\reactos\dll\win32\wininet/urlcache
}
static void cache_containers_free(void)
@@ -835,6 +827,12 @@ static DWORD cache_containers_find(const
@@ -812,6 +827,12 @@ static DWORD cache_containers_find(const
if(!url)
return ERROR_INVALID_PARAMETER;
@ -135,7 +135,7 @@ diff -pudN e:\wine\dlls\wininet/urlcache.c e:\reactos\dll\win32\wininet/urlcache
LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
{
int prefix_len = strlen(container->cache_prefix);
@@ -861,6 +859,12 @@ static BOOL cache_containers_enum(char *
@@ -838,6 +859,12 @@ static BOOL cache_containers_enum(char *
if (search_pattern && index > 0)
return FALSE;
@ -148,7 +148,7 @@ diff -pudN e:\wine\dlls\wininet/urlcache.c e:\reactos\dll\win32\wininet/urlcache
LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
{
if (search_pattern)
@@ -4018,7 +4022,9 @@ BOOL init_urlcache(void)
@@ -3995,7 +4022,9 @@ BOOL init_urlcache(void)
return FALSE;
}

View file

@ -205,7 +205,7 @@ reactos/dll/win32/windowscodecsext # Synced to WineStaging-1.9.4
reactos/dll/win32/winemp3.acm # Synced to WineStaging-1.9.4
reactos/dll/win32/wing32 # Synced to WineStaging-1.9.4
reactos/dll/win32/winhttp # Synced to WineStaging-1.9.4
reactos/dll/win32/wininet # Synced to WineStaging-1.9.4
reactos/dll/win32/wininet # Synced to WineStaging-1.9.11
reactos/dll/win32/winmm # Forked at Wine-20050628
reactos/dll/win32/winmm/midimap # Forked at Wine-20050628
reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628