mirror of
https://github.com/reactos/reactos.git
synced 2024-12-31 19:42:51 +00:00
sync urlmon and winhttp with wine 1.1.23
svn path=/trunk/; revision=41333
This commit is contained in:
parent
8d470e46d8
commit
12c11159c8
12 changed files with 1604 additions and 280 deletions
|
@ -608,10 +608,14 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
|
|||
static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
|
||||
{
|
||||
BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("(%p)->(%p)\n", This, pProtocolData);
|
||||
|
||||
return IInternetProtocol_Continue(This->protocol, pProtocolData);
|
||||
hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
|
||||
|
||||
heap_free(pProtocolData);
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
|
||||
|
@ -874,14 +878,14 @@ static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
|
|||
|
||||
typedef struct {
|
||||
task_header_t header;
|
||||
PROTOCOLDATA data;
|
||||
PROTOCOLDATA *data;
|
||||
} switch_task_t;
|
||||
|
||||
static void switch_proc(BindProtocol *bind, task_header_t *t)
|
||||
{
|
||||
switch_task_t *task = (switch_task_t*)t;
|
||||
|
||||
IInternetProtocol_Continue(bind->protocol_handler, &task->data);
|
||||
IInternetProtocol_Continue(bind->protocol_handler, task->data);
|
||||
|
||||
heap_free(task);
|
||||
}
|
||||
|
@ -890,12 +894,18 @@ static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface
|
|||
PROTOCOLDATA *pProtocolData)
|
||||
{
|
||||
BindProtocol *This = PROTSINK_THIS(iface);
|
||||
PROTOCOLDATA *data;
|
||||
|
||||
TRACE("(%p)->(%p)\n", This, pProtocolData);
|
||||
|
||||
TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
|
||||
pProtocolData->pData, pProtocolData->cbData);
|
||||
|
||||
data = heap_alloc(sizeof(PROTOCOLDATA));
|
||||
if(!data)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
|
||||
|
||||
if(!do_direct_notif(This)) {
|
||||
switch_task_t *task;
|
||||
|
||||
|
@ -903,18 +913,18 @@ static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface
|
|||
if(!task)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
task->data = *pProtocolData;
|
||||
task->data = data;
|
||||
|
||||
push_task(This, &task->header, switch_proc);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if(!This->protocol_sink) {
|
||||
IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
|
||||
IInternetProtocol_Continue(This->protocol_handler, data);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
|
||||
return IInternetProtocolSink_Switch(This->protocol_sink, data);
|
||||
}
|
||||
|
||||
static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
|
||||
|
|
|
@ -85,7 +85,7 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD requ
|
|||
BYTE security_id[512];
|
||||
DWORD len = 0;
|
||||
ULONG num = 0;
|
||||
BOOL res;
|
||||
BOOL res, b;
|
||||
HRESULT hres;
|
||||
|
||||
static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] =
|
||||
|
@ -209,6 +209,11 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD requ
|
|||
optional = (LPWSTR)This->base.bind_info.stgmedData.u.hGlobal;
|
||||
}
|
||||
|
||||
b = TRUE;
|
||||
res = InternetSetOptionW(This->base.request, INTERNET_OPTION_HTTP_DECODING, &b, sizeof(b));
|
||||
if(!res)
|
||||
WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %08x\n", GetLastError());
|
||||
|
||||
res = HttpSendRequestW(This->base.request, This->full_header, lstrlenW(This->full_header),
|
||||
optional, optional ? This->base.bind_info.cbstgmedData : 0);
|
||||
if(!res && GetLastError() != ERROR_IO_PENDING) {
|
||||
|
|
|
@ -36,7 +36,7 @@ LONG URLMON_refCount = 0;
|
|||
|
||||
HINSTANCE URLMON_hInstance = 0;
|
||||
static HMODULE hCabinet = NULL;
|
||||
static DWORD urlmon_tls;
|
||||
static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
|
||||
|
||||
static void init_session(BOOL);
|
||||
|
||||
|
@ -56,9 +56,12 @@ tls_data_t *get_tls_data(void)
|
|||
{
|
||||
tls_data_t *data;
|
||||
|
||||
if(!urlmon_tls) {
|
||||
if(urlmon_tls == TLS_OUT_OF_INDEXES) {
|
||||
DWORD tls = TlsAlloc();
|
||||
tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, 0);
|
||||
if(tls == TLS_OUT_OF_INDEXES)
|
||||
return NULL;
|
||||
|
||||
tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
|
||||
if(tls != urlmon_tls)
|
||||
TlsFree(tls);
|
||||
}
|
||||
|
@ -83,7 +86,7 @@ static void free_tls_list(void)
|
|||
{
|
||||
tls_data_t *data;
|
||||
|
||||
if(!urlmon_tls)
|
||||
if(urlmon_tls == TLS_OUT_OF_INDEXES)
|
||||
return;
|
||||
|
||||
while(!list_empty(&tls_list)) {
|
||||
|
@ -99,7 +102,7 @@ static void detach_thread(void)
|
|||
{
|
||||
tls_data_t *data;
|
||||
|
||||
if(!urlmon_tls)
|
||||
if(urlmon_tls == TLS_OUT_OF_INDEXES)
|
||||
return;
|
||||
|
||||
data = TlsGetValue(urlmon_tls);
|
||||
|
|
281
reactos/dll/win32/winhttp/cookie.c
Normal file
281
reactos/dll/win32/winhttp/cookie.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright 2008 Hans Leidekker for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/list.h"
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winhttp.h"
|
||||
|
||||
#include "winhttp_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
|
||||
|
||||
static domain_t *add_domain( session_t *session, WCHAR *name )
|
||||
{
|
||||
domain_t *domain;
|
||||
|
||||
if (!(domain = heap_alloc_zero( sizeof(domain_t) ))) return NULL;
|
||||
|
||||
list_init( &domain->entry );
|
||||
list_init( &domain->cookies );
|
||||
|
||||
domain->name = name;
|
||||
list_add_tail( &session->cookie_cache, &domain->entry );
|
||||
|
||||
TRACE("%s\n", debugstr_w(domain->name));
|
||||
return domain;
|
||||
}
|
||||
|
||||
static cookie_t *find_cookie( domain_t *domain, const WCHAR *path, const WCHAR *name )
|
||||
{
|
||||
struct list *item;
|
||||
cookie_t *cookie;
|
||||
|
||||
LIST_FOR_EACH( item, &domain->cookies )
|
||||
{
|
||||
cookie = LIST_ENTRY( item, cookie_t, entry );
|
||||
if (!strcmpW( cookie->path, path ) && !strcmpiW( cookie->name, name ))
|
||||
{
|
||||
TRACE("found %s=%s\n", debugstr_w(cookie->name), debugstr_w(cookie->value));
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL domain_match( const WCHAR *name, domain_t *domain, BOOL partial )
|
||||
{
|
||||
TRACE("comparing %s with %s\n", debugstr_w(name), debugstr_w(domain->name));
|
||||
|
||||
if (partial && !strstrW( name, domain->name )) return FALSE;
|
||||
else if (!partial && strcmpW( name, domain->name )) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void free_cookie( cookie_t *cookie )
|
||||
{
|
||||
heap_free( cookie->name );
|
||||
heap_free( cookie->value );
|
||||
heap_free( cookie->path );
|
||||
heap_free( cookie );
|
||||
}
|
||||
|
||||
static void delete_cookie( cookie_t *cookie )
|
||||
{
|
||||
list_remove( &cookie->entry );
|
||||
free_cookie( cookie );
|
||||
}
|
||||
|
||||
void delete_domain( domain_t *domain )
|
||||
{
|
||||
cookie_t *cookie;
|
||||
struct list *item, *next;
|
||||
|
||||
LIST_FOR_EACH_SAFE( item, next, &domain->cookies )
|
||||
{
|
||||
cookie = LIST_ENTRY( item, cookie_t, entry );
|
||||
delete_cookie( cookie );
|
||||
}
|
||||
|
||||
list_remove( &domain->entry );
|
||||
heap_free( domain->name );
|
||||
heap_free( domain );
|
||||
}
|
||||
|
||||
static BOOL add_cookie( session_t *session, cookie_t *cookie, WCHAR *domain_name, WCHAR *path )
|
||||
{
|
||||
domain_t *domain = NULL;
|
||||
cookie_t *old_cookie;
|
||||
struct list *item;
|
||||
|
||||
LIST_FOR_EACH( item, &session->cookie_cache )
|
||||
{
|
||||
domain = LIST_ENTRY( item, domain_t, entry );
|
||||
if (domain_match( domain_name, domain, FALSE )) break;
|
||||
domain = NULL;
|
||||
}
|
||||
if (!domain)
|
||||
{
|
||||
if (!(domain = add_domain( session, domain_name ))) return FALSE;
|
||||
}
|
||||
else if ((old_cookie = find_cookie( domain, path, cookie->name ))) delete_cookie( old_cookie );
|
||||
|
||||
cookie->path = path;
|
||||
list_add_tail( &domain->cookies, &cookie->entry );
|
||||
|
||||
TRACE("domain %s path %s <- %s=%s\n", debugstr_w(domain_name), debugstr_w(cookie->path),
|
||||
debugstr_w(cookie->name), debugstr_w(cookie->value));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static cookie_t *parse_cookie( const WCHAR *string )
|
||||
{
|
||||
cookie_t *cookie;
|
||||
const WCHAR *p;
|
||||
int len;
|
||||
|
||||
if (!(cookie = heap_alloc_zero( sizeof(cookie_t) ))) return NULL;
|
||||
|
||||
list_init( &cookie->entry );
|
||||
|
||||
if (!(p = strchrW( string, '=' )))
|
||||
{
|
||||
WARN("no '=' in %s\n", debugstr_w(string));
|
||||
return NULL;
|
||||
}
|
||||
if (p == string)
|
||||
{
|
||||
WARN("empty cookie name in %s\n", debugstr_w(string));
|
||||
return NULL;
|
||||
}
|
||||
len = p - string;
|
||||
if (!(cookie->name = heap_alloc( (len + 1) * sizeof(WCHAR) )))
|
||||
{
|
||||
heap_free( cookie );
|
||||
return NULL;
|
||||
}
|
||||
memcpy( cookie->name, string, len * sizeof(WCHAR) );
|
||||
cookie->name[len] = 0;
|
||||
|
||||
p++; /* skip '=' */
|
||||
while (*p == ' ') p++;
|
||||
|
||||
len = strlenW( p );
|
||||
if (!(cookie->value = heap_alloc( (len + 1) * sizeof(WCHAR) )))
|
||||
{
|
||||
free_cookie( cookie );
|
||||
return NULL;
|
||||
}
|
||||
memcpy( cookie->value, p, len * sizeof(WCHAR) );
|
||||
cookie->value[len] = 0;
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
BOOL set_cookies( request_t *request, const WCHAR *cookies )
|
||||
{
|
||||
static const WCHAR pathW[] = {'p','a','t','h',0};
|
||||
static const WCHAR domainW[] = {'d','o','m','a','i','n',0};
|
||||
|
||||
BOOL ret = FALSE;
|
||||
WCHAR *buffer, *p, *q, *r;
|
||||
WCHAR *cookie_domain = NULL, *cookie_path = NULL;
|
||||
session_t *session = request->connect->session;
|
||||
cookie_t *cookie;
|
||||
int len;
|
||||
|
||||
len = strlenW( cookies );
|
||||
if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
|
||||
strcpyW( buffer, cookies );
|
||||
|
||||
p = buffer;
|
||||
while (*p && *p != ';') p++;
|
||||
if (*p == ';') *p++ = 0;
|
||||
if (!(cookie = parse_cookie( buffer )))
|
||||
{
|
||||
heap_free( buffer );
|
||||
return FALSE;
|
||||
}
|
||||
if ((q = strstrW( p, domainW ))) /* FIXME: do real attribute parsing */
|
||||
{
|
||||
while (*q && *q != '=') q++;
|
||||
if (!*q) goto end;
|
||||
|
||||
r = ++q;
|
||||
while (*r && *r != ';') r++;
|
||||
len = r - q;
|
||||
|
||||
if (!(cookie_domain = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
|
||||
memcpy( cookie_domain, q, len * sizeof(WCHAR) );
|
||||
cookie_domain[len] = 0;
|
||||
|
||||
}
|
||||
if ((q = strstrW( p, pathW )))
|
||||
{
|
||||
while (*q && *q != '=') q++;
|
||||
if (!*q) goto end;
|
||||
|
||||
r = ++q;
|
||||
while (*r && *r != ';') r++;
|
||||
len = r - q;
|
||||
|
||||
if (!(cookie_path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
|
||||
memcpy( cookie_path, q, len * sizeof(WCHAR) );
|
||||
cookie_path[len] = 0;
|
||||
}
|
||||
if (!cookie_domain && !(cookie_domain = strdupW( request->connect->servername ))) goto end;
|
||||
if (!cookie_path && !(cookie_path = strdupW( request->path ))) goto end;
|
||||
|
||||
if ((p = strrchrW( cookie_path, '/' )) && p != cookie_path) *p = 0;
|
||||
ret = add_cookie( session, cookie, cookie_domain, cookie_path );
|
||||
|
||||
end:
|
||||
if (!ret)
|
||||
{
|
||||
free_cookie( cookie );
|
||||
heap_free( cookie_domain );
|
||||
heap_free( cookie_path );
|
||||
}
|
||||
heap_free( buffer );
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL add_cookie_headers( request_t *request )
|
||||
{
|
||||
struct list *domain_cursor;
|
||||
session_t *session = request->connect->session;
|
||||
|
||||
LIST_FOR_EACH( domain_cursor, &session->cookie_cache )
|
||||
{
|
||||
domain_t *domain = LIST_ENTRY( domain_cursor, domain_t, entry );
|
||||
if (domain_match( request->connect->servername, domain, TRUE ))
|
||||
{
|
||||
struct list *cookie_cursor;
|
||||
TRACE("found domain %s\n", debugstr_w(domain->name));
|
||||
|
||||
LIST_FOR_EACH( cookie_cursor, &domain->cookies )
|
||||
{
|
||||
cookie_t *cookie = LIST_ENTRY( cookie_cursor, cookie_t, entry );
|
||||
|
||||
TRACE("comparing path %s with %s\n", debugstr_w(request->path), debugstr_w(cookie->path));
|
||||
|
||||
if (strstrW( request->path, cookie->path ) == request->path)
|
||||
{
|
||||
const WCHAR format[] = {'C','o','o','k','i','e',':',' ','%','s','=','%','s',0};
|
||||
int len;
|
||||
WCHAR *header;
|
||||
|
||||
len = strlenW( cookie->name ) + strlenW( format ) + strlenW( cookie->value );
|
||||
if (!(header = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
|
||||
|
||||
sprintfW( header, format, cookie->name, cookie->value );
|
||||
|
||||
TRACE("%s\n", debugstr_w(header));
|
||||
add_request_headers( request, header, len, WINHTTP_ADDREQ_FLAG_ADD );
|
||||
heap_free( header );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
|
@ -38,8 +38,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
|
|||
{
|
||||
switch(fdwReason)
|
||||
{
|
||||
case DLL_WINE_PREATTACH:
|
||||
return FALSE; /* prefer native version */
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstDLL);
|
||||
break;
|
||||
|
@ -84,41 +82,3 @@ HRESULT WINAPI DllUnregisterServer(void)
|
|||
FIXME("()\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#define SCHEME_HTTP 3
|
||||
#define SCHEME_HTTPS 4
|
||||
|
||||
BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW );
|
||||
BOOL WINAPI InternetCreateUrlW( LPURL_COMPONENTS, DWORD, LPWSTR, LPDWORD );
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpCrackUrl (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW components )
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, components);
|
||||
|
||||
if ((ret = InternetCrackUrlW( url, len, flags, components )))
|
||||
{
|
||||
/* fix up an incompatibility between wininet and winhttp */
|
||||
if (components->nScheme == SCHEME_HTTP) components->nScheme = INTERNET_SCHEME_HTTP;
|
||||
else if (components->nScheme == SCHEME_HTTPS) components->nScheme = INTERNET_SCHEME_HTTPS;
|
||||
else
|
||||
{
|
||||
set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpCreateUrl (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS comps, DWORD flags, LPWSTR url, LPDWORD len )
|
||||
{
|
||||
TRACE("%p, 0x%08x, %p, %p\n", comps, flags, url, len);
|
||||
return InternetCreateUrlW( comps, flags, url, len );
|
||||
}
|
||||
|
|
|
@ -48,13 +48,14 @@
|
|||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winhttp.h"
|
||||
#include "wincrypt.h"
|
||||
|
||||
#include "winhttp_private.h"
|
||||
|
||||
/* to avoid conflicts with the Unix socket headers */
|
||||
#define USE_WS_PREFIX
|
||||
#include "winsock2.h"
|
||||
|
||||
#include "winhttp_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
|
||||
|
||||
#define DEFAULT_SEND_TIMEOUT 30
|
||||
|
@ -83,6 +84,7 @@ static void *libssl_handle;
|
|||
static void *libcrypto_handle;
|
||||
|
||||
static SSL_METHOD *method;
|
||||
static SSL_CTX *ctx;
|
||||
|
||||
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
|
||||
|
||||
|
@ -90,7 +92,6 @@ MAKE_FUNCPTR( SSL_library_init );
|
|||
MAKE_FUNCPTR( SSL_load_error_strings );
|
||||
MAKE_FUNCPTR( SSLv23_method );
|
||||
MAKE_FUNCPTR( SSL_CTX_new );
|
||||
MAKE_FUNCPTR( SSL_CTX_free );
|
||||
MAKE_FUNCPTR( SSL_new );
|
||||
MAKE_FUNCPTR( SSL_free );
|
||||
MAKE_FUNCPTR( SSL_set_fd );
|
||||
|
@ -107,14 +108,15 @@ MAKE_FUNCPTR( SSL_CTX_set_default_verify_paths );
|
|||
MAKE_FUNCPTR( BIO_new_fp );
|
||||
MAKE_FUNCPTR( ERR_get_error );
|
||||
MAKE_FUNCPTR( ERR_error_string );
|
||||
MAKE_FUNCPTR( i2d_X509 );
|
||||
#undef MAKE_FUNCPTR
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* translate a unix error code into a winsock error code */
|
||||
static int sock_get_error( int err )
|
||||
{
|
||||
#if !defined(__MINGW32__) && !defined (_MSC_VER)
|
||||
switch (err)
|
||||
{
|
||||
case EINTR: return WSAEINTR;
|
||||
|
@ -174,11 +176,9 @@ static int sock_get_error( int err )
|
|||
#endif
|
||||
default: errno = err; perror( "sock_set_error" ); return WSAEFAULT;
|
||||
}
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
#define sock_get_error(x) WSAGetLastError()
|
||||
#endif
|
||||
|
||||
BOOL netconn_init( netconn_t *conn, BOOL secure )
|
||||
{
|
||||
|
@ -210,7 +210,6 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
|
|||
LOAD_FUNCPTR( SSL_load_error_strings );
|
||||
LOAD_FUNCPTR( SSLv23_method );
|
||||
LOAD_FUNCPTR( SSL_CTX_new );
|
||||
LOAD_FUNCPTR( SSL_CTX_free );
|
||||
LOAD_FUNCPTR( SSL_new );
|
||||
LOAD_FUNCPTR( SSL_free );
|
||||
LOAD_FUNCPTR( SSL_set_fd );
|
||||
|
@ -235,6 +234,7 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
|
|||
LOAD_FUNCPTR( BIO_new_fp );
|
||||
LOAD_FUNCPTR( ERR_get_error );
|
||||
LOAD_FUNCPTR( ERR_error_string );
|
||||
LOAD_FUNCPTR( i2d_X509 );
|
||||
#undef LOAD_FUNCPTR
|
||||
|
||||
pSSL_library_init();
|
||||
|
@ -242,8 +242,6 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
|
|||
pBIO_new_fp( stderr, BIO_NOCLOSE );
|
||||
|
||||
method = pSSLv23_method();
|
||||
conn->ssl_ctx = pSSL_CTX_new( method );
|
||||
|
||||
#else
|
||||
WARN("SSL support not compiled in.\n");
|
||||
set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
|
||||
|
@ -314,13 +312,14 @@ BOOL netconn_secure_connect( netconn_t *conn )
|
|||
X509 *cert;
|
||||
long res;
|
||||
|
||||
if (!pSSL_CTX_set_default_verify_paths( conn->ssl_ctx ))
|
||||
ctx = pSSL_CTX_new( method );
|
||||
if (!pSSL_CTX_set_default_verify_paths( ctx ))
|
||||
{
|
||||
ERR("SSL_CTX_set_default_verify_paths failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
|
||||
set_last_error( ERROR_OUTOFMEMORY );
|
||||
return FALSE;
|
||||
}
|
||||
if (!(conn->ssl_conn = pSSL_new( conn->ssl_ctx )))
|
||||
if (!(conn->ssl_conn = pSSL_new( ctx )))
|
||||
{
|
||||
ERR("SSL_new failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
|
||||
set_last_error( ERROR_OUTOFMEMORY );
|
||||
|
@ -468,11 +467,7 @@ BOOL netconn_query_data_available( netconn_t *conn, DWORD *available )
|
|||
return TRUE;
|
||||
}
|
||||
#ifdef FIONREAD
|
||||
if (!(ret = ioctlsocket( conn->socket, FIONREAD, &unread )))
|
||||
{
|
||||
TRACE("%d bytes of queued, but unread data\n", unread);
|
||||
*available += unread;
|
||||
}
|
||||
if (!(ret = ioctlsocket( conn->socket, FIONREAD, &unread ))) *available = unread;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -491,8 +486,8 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
|
|||
#ifdef SONAME_LIBSSL
|
||||
long timeout;
|
||||
|
||||
timeout = pSSL_CTX_get_timeout( conn->ssl_ctx );
|
||||
pSSL_CTX_set_timeout( conn->ssl_ctx, DEFAULT_RECEIVE_TIMEOUT );
|
||||
timeout = pSSL_CTX_get_timeout( ctx );
|
||||
pSSL_CTX_set_timeout( ctx, DEFAULT_RECEIVE_TIMEOUT );
|
||||
|
||||
while (recvd < *buflen)
|
||||
{
|
||||
|
@ -509,7 +504,7 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
|
|||
}
|
||||
if (buffer[recvd] != '\r') recvd++;
|
||||
}
|
||||
pSSL_CTX_set_timeout( conn->ssl_ctx, timeout );
|
||||
pSSL_CTX_set_timeout( ctx, timeout );
|
||||
if (ret)
|
||||
{
|
||||
buffer[recvd++] = 0;
|
||||
|
@ -567,7 +562,7 @@ DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
|
|||
tv.tv_sec = value / 1000;
|
||||
tv.tv_usec = (value % 1000) * 1000;
|
||||
|
||||
if ((res = setsockopt( netconn->socket, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, &tv, sizeof(tv) ) == -1))
|
||||
if ((res = setsockopt( netconn->socket, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv) ) == -1))
|
||||
{
|
||||
WARN("setsockopt failed (%s)\n", strerror( errno ));
|
||||
return sock_get_error( errno );
|
||||
|
@ -595,7 +590,7 @@ BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *
|
|||
heap_free( hostname );
|
||||
if (ret != 0)
|
||||
{
|
||||
TRACE("failed to get address of %s (%s)\n", debugstr_a(hostname), gai_strerror(ret));
|
||||
TRACE("failed to get address of %s (%s)\n", debugstr_w(hostnameW), gai_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
memset( sa, 0, sizeof(struct sockaddr_in) );
|
||||
|
@ -611,12 +606,12 @@ BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *
|
|||
heap_free( hostname );
|
||||
if (!he)
|
||||
{
|
||||
TRACE("failed to get address of %s (%d)\n", debugstr_a(hostname), h_errno);
|
||||
TRACE("failed to get address of %s (%d)\n", debugstr_w(hostnameW), h_errno);
|
||||
LeaveCriticalSection( &cs_gethostbyname );
|
||||
return FALSE;
|
||||
}
|
||||
memset( sa, 0, sizeof(struct sockaddr_in) );
|
||||
memcpy( (char *)&sa->sin_addr, he->h_addr, he->h_length );
|
||||
memcpy( &sa->sin_addr, he->h_addr, he->h_length );
|
||||
sa->sin_family = he->h_addrtype;
|
||||
sa->sin_port = htons( port );
|
||||
|
||||
|
@ -624,3 +619,46 @@ BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *
|
|||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const void *netconn_get_certificate( netconn_t *conn )
|
||||
{
|
||||
#ifdef SONAME_LIBSSL
|
||||
X509 *cert;
|
||||
unsigned char *buffer, *p;
|
||||
int len;
|
||||
BOOL malloc = FALSE;
|
||||
const CERT_CONTEXT *ret;
|
||||
|
||||
if (!conn->secure) return NULL;
|
||||
|
||||
if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn ))) return NULL;
|
||||
p = NULL;
|
||||
if ((len = pi2d_X509( cert, &p )) < 0) return NULL;
|
||||
/*
|
||||
* SSL 0.9.7 and above malloc the buffer if it is null.
|
||||
* however earlier version do not and so we would need to alloc the buffer.
|
||||
*
|
||||
* see the i2d_X509 man page for more details.
|
||||
*/
|
||||
if (!p)
|
||||
{
|
||||
if (!(buffer = heap_alloc( len ))) return NULL;
|
||||
p = buffer;
|
||||
len = pi2d_X509( cert, &p );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = p;
|
||||
malloc = TRUE;
|
||||
}
|
||||
|
||||
ret = CertCreateCertificateContext( X509_ASN_ENCODING, buffer, len );
|
||||
|
||||
if (malloc) free( buffer );
|
||||
else heap_free( buffer );
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -175,6 +175,22 @@ static const WCHAR *attribute_table[] =
|
|||
NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */
|
||||
};
|
||||
|
||||
static DWORD CALLBACK task_thread( LPVOID param )
|
||||
{
|
||||
task_header_t *task = param;
|
||||
|
||||
task->proc( task );
|
||||
|
||||
release_object( &task->request->hdr );
|
||||
heap_free( task );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static BOOL queue_task( task_header_t *task )
|
||||
{
|
||||
return QueueUserWorkItem( task_thread, task, WT_EXECUTELONGFUNCTION );
|
||||
}
|
||||
|
||||
static void free_header( header_t *header )
|
||||
{
|
||||
heap_free( header->field );
|
||||
|
@ -391,13 +407,13 @@ static BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DW
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL add_request_headers( request_t *request, LPCWSTR headers, DWORD len, DWORD flags )
|
||||
BOOL add_request_headers( request_t *request, LPCWSTR headers, DWORD len, DWORD flags )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
WCHAR *buffer, *p, *q;
|
||||
header_t *header;
|
||||
|
||||
if (len == ~0UL) len = strlenW( headers );
|
||||
if (len == ~0u) len = strlenW( headers );
|
||||
if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
|
||||
strcpyW( buffer, headers );
|
||||
|
||||
|
@ -467,28 +483,20 @@ static WCHAR *build_request_string( request_t *request )
|
|||
static const WCHAR crlf[] = {'\r','\n',0};
|
||||
static const WCHAR colon[] = {':',' ',0};
|
||||
static const WCHAR twocrlf[] = {'\r','\n','\r','\n',0};
|
||||
static const WCHAR get[] = {'G','E','T',0};
|
||||
static const WCHAR slash[] = {'/',0};
|
||||
static const WCHAR http1_1[] = {'H','T','T','P','/','1','.','1',0};
|
||||
|
||||
WCHAR *ret;
|
||||
const WCHAR **headers, **p;
|
||||
const WCHAR *verb = get, *path = slash, *version = http1_1;
|
||||
unsigned int len, i = 0, j;
|
||||
|
||||
if (request->verb && request->verb[0]) verb = request->verb;
|
||||
if (request->path && request->path[0]) path = request->path;
|
||||
if (request->version && request->version[0]) version = request->version;
|
||||
|
||||
/* allocate space for an array of all the string pointers to be added */
|
||||
len = request->num_headers * 4 + 7;
|
||||
if (!(headers = heap_alloc( len * sizeof(LPCWSTR) ))) return NULL;
|
||||
|
||||
headers[i++] = verb;
|
||||
headers[i++] = request->verb;
|
||||
headers[i++] = space;
|
||||
headers[i++] = path;
|
||||
headers[i++] = request->path;
|
||||
headers[i++] = space;
|
||||
headers[i++] = version;
|
||||
headers[i++] = request->version;
|
||||
|
||||
for (j = 0; j < request->num_headers; j++)
|
||||
{
|
||||
|
@ -561,7 +569,7 @@ static BOOL query_headers( request_t *request, DWORD level, LPCWSTR name, LPVOID
|
|||
}
|
||||
else if (buffer)
|
||||
{
|
||||
for (p = headers, q = (WCHAR *)buffer; *p; p++, q++)
|
||||
for (p = headers, q = buffer; *p; p++, q++)
|
||||
{
|
||||
if (*p != '\r') *q = *p;
|
||||
else
|
||||
|
@ -571,7 +579,7 @@ static BOOL query_headers( request_t *request, DWORD level, LPCWSTR name, LPVOID
|
|||
}
|
||||
}
|
||||
*q = 0;
|
||||
TRACE("returning data: %s\n", debugstr_wn((WCHAR *)buffer, len));
|
||||
TRACE("returning data: %s\n", debugstr_wn(buffer, len));
|
||||
ret = TRUE;
|
||||
}
|
||||
*buflen = len * sizeof(WCHAR);
|
||||
|
@ -606,7 +614,7 @@ static BOOL query_headers( request_t *request, DWORD level, LPCWSTR name, LPVOID
|
|||
}
|
||||
default:
|
||||
{
|
||||
if (attr > sizeof(attribute_table)/sizeof(attribute_table[0]) || !attribute_table[attr])
|
||||
if (attr >= sizeof(attribute_table)/sizeof(attribute_table[0]) || !attribute_table[attr])
|
||||
{
|
||||
FIXME("attribute %u not implemented\n", attr);
|
||||
return FALSE;
|
||||
|
@ -710,13 +718,16 @@ static BOOL open_connection( request_t *request )
|
|||
connect_t *connect;
|
||||
char address[32];
|
||||
WCHAR *addressW;
|
||||
INTERNET_PORT port;
|
||||
|
||||
if (netconn_connected( &request->netconn )) return TRUE;
|
||||
|
||||
connect = request->connect;
|
||||
port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
|
||||
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, connect->servername, strlenW(connect->servername) + 1 );
|
||||
|
||||
if (!netconn_resolve( connect->servername, connect->serverport, &connect->sockaddr )) return FALSE;
|
||||
if (!netconn_resolve( connect->servername, port, &connect->sockaddr )) return FALSE;
|
||||
inet_ntop( connect->sockaddr.sin_family, &connect->sockaddr.sin_addr, address, sizeof(address) );
|
||||
addressW = strdupAW( address );
|
||||
|
||||
|
@ -759,32 +770,35 @@ void close_connection( request_t *request )
|
|||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 );
|
||||
}
|
||||
|
||||
static BOOL add_host_header( request_t *request, WCHAR *hostname, INTERNET_PORT port, DWORD modifier )
|
||||
static BOOL add_host_header( request_t *request, DWORD modifier )
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
WCHAR *host;
|
||||
static const WCHAR fmt[] = {'%','s',':','%','u',0};
|
||||
connect_t *connect = request->connect;
|
||||
INTERNET_PORT port;
|
||||
|
||||
port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
|
||||
|
||||
if (port == INTERNET_DEFAULT_HTTP_PORT || port == INTERNET_DEFAULT_HTTPS_PORT)
|
||||
{
|
||||
return process_header( request, attr_host, hostname, modifier, TRUE );
|
||||
return process_header( request, attr_host, connect->hostname, modifier, TRUE );
|
||||
}
|
||||
len = strlenW( hostname ) + 7; /* sizeof(":65335") */
|
||||
len = strlenW( connect->hostname ) + 7; /* sizeof(":65335") */
|
||||
if (!(host = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
|
||||
sprintfW( host, fmt, hostname, port );
|
||||
sprintfW( host, fmt, connect->hostname, port );
|
||||
ret = process_header( request, attr_host, host, modifier, TRUE );
|
||||
heap_free( host );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional,
|
||||
DWORD optional_len, DWORD total_len, DWORD_PTR context )
|
||||
DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
|
||||
{
|
||||
static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0};
|
||||
static const WCHAR no_cache[] = {'n','o','-','c','a','c','h','e',0};
|
||||
static const WCHAR length_fmt[] = {'%','l','d',0};
|
||||
static const WCHAR post[] = {'P','O','S','T',0};
|
||||
|
||||
BOOL ret = FALSE;
|
||||
connect_t *connect = request->connect;
|
||||
|
@ -798,9 +812,9 @@ static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len
|
|||
process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
||||
|
||||
if (connect->hostname)
|
||||
add_host_header( request, connect->hostname, connect->hostport, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW );
|
||||
add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW );
|
||||
|
||||
if (total_len || (request->verb && !strcmpW( request->verb, post )))
|
||||
if (total_len || (request->verb && !strcmpW( request->verb, postW )))
|
||||
{
|
||||
WCHAR length[21]; /* decimal long int + null */
|
||||
sprintfW( length, length_fmt, total_len );
|
||||
|
@ -820,6 +834,11 @@ static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len
|
|||
TRACE("failed to add request headers\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request ))
|
||||
{
|
||||
WARN("failed to add cookie headers\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(ret = open_connection( request ))) goto end;
|
||||
if (!(req = build_request_string( request ))) goto end;
|
||||
|
@ -840,10 +859,28 @@ static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len
|
|||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(DWORD) );
|
||||
|
||||
end:
|
||||
if (async)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT result;
|
||||
result.dwResult = API_SEND_REQUEST;
|
||||
result.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
|
||||
}
|
||||
}
|
||||
heap_free( req );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void task_send_request( task_header_t *task )
|
||||
{
|
||||
send_request_t *s = (send_request_t *)task;
|
||||
send_request( s->hdr.request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE );
|
||||
heap_free( s->headers );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpSendRequest (winhttp.@)
|
||||
*/
|
||||
|
@ -868,7 +905,25 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD heade
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context );
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
send_request_t *s;
|
||||
|
||||
if (!(s = heap_alloc( sizeof(send_request_t) ))) return FALSE;
|
||||
s->hdr.request = request;
|
||||
s->hdr.proc = task_send_request;
|
||||
s->headers = strdupW( headers );
|
||||
s->headers_len = headers_len;
|
||||
s->optional = optional;
|
||||
s->optional_len = optional_len;
|
||||
s->total_len = total_len;
|
||||
s->context = context;
|
||||
|
||||
addref_object( &request->hdr );
|
||||
ret = queue_task( (task_header_t *)s );
|
||||
}
|
||||
else
|
||||
ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE );
|
||||
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
|
@ -889,9 +944,9 @@ static void clear_response_headers( request_t *request )
|
|||
}
|
||||
|
||||
#define MAX_REPLY_LEN 1460
|
||||
#define INITIAL_HEADER_BUFFER_SIZE 512
|
||||
#define INITIAL_HEADER_BUFFER_LEN 512
|
||||
|
||||
static BOOL receive_response( request_t *request, BOOL clear )
|
||||
static BOOL read_reply( request_t *request )
|
||||
{
|
||||
static const WCHAR crlf[] = {'\r','\n',0};
|
||||
|
||||
|
@ -903,9 +958,6 @@ static BOOL receive_response( request_t *request, BOOL clear )
|
|||
|
||||
if (!netconn_connected( &request->netconn )) return FALSE;
|
||||
|
||||
/* clear old response headers (eg. from a redirect response) */
|
||||
if (clear) clear_response_headers( request );
|
||||
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 );
|
||||
|
||||
received_len = 0;
|
||||
|
@ -949,7 +1001,7 @@ static BOOL receive_response( request_t *request, BOOL clear )
|
|||
heap_free( request->status_text );
|
||||
request->status_text = status_textW;
|
||||
|
||||
len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_SIZE );
|
||||
len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_LEN );
|
||||
if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
|
||||
MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen );
|
||||
memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) );
|
||||
|
@ -1002,6 +1054,7 @@ static BOOL handle_redirect( request_t *request )
|
|||
connect_t *connect = request->connect;
|
||||
INTERNET_PORT port;
|
||||
WCHAR *hostname = NULL, *location = NULL;
|
||||
int index;
|
||||
|
||||
size = 0;
|
||||
query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL );
|
||||
|
@ -1012,48 +1065,73 @@ static BOOL handle_redirect( request_t *request )
|
|||
|
||||
memset( &uc, 0, sizeof(uc) );
|
||||
uc.dwStructSize = sizeof(uc);
|
||||
uc.dwSchemeLength = uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = ~0UL;
|
||||
uc.dwSchemeLength = uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = ~0u;
|
||||
|
||||
if (!(ret = WinHttpCrackUrl( location, size / sizeof(WCHAR), 0, &uc ))) goto end;
|
||||
|
||||
if (uc.nScheme == INTERNET_SCHEME_HTTP && request->hdr.flags & WINHTTP_FLAG_SECURE)
|
||||
if (!WinHttpCrackUrl( location, size / sizeof(WCHAR), 0, &uc )) /* assume relative redirect */
|
||||
{
|
||||
TRACE("redirect from secure page to non-secure page\n");
|
||||
request->hdr.flags &= ~WINHTTP_FLAG_SECURE;
|
||||
WCHAR *path, *p;
|
||||
|
||||
len = strlenW( location ) + 1;
|
||||
if (location[0] != '/') len++;
|
||||
if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
|
||||
|
||||
if (location[0] != '/') *p++ = '/';
|
||||
strcpyW( p, location );
|
||||
|
||||
heap_free( request->path );
|
||||
request->path = path;
|
||||
}
|
||||
else if (uc.nScheme == INTERNET_SCHEME_HTTPS && !(request->hdr.flags & WINHTTP_FLAG_SECURE))
|
||||
else
|
||||
{
|
||||
TRACE("redirect from non-secure page to secure page\n");
|
||||
request->hdr.flags |= WINHTTP_FLAG_SECURE;
|
||||
if (uc.nScheme == INTERNET_SCHEME_HTTP && request->hdr.flags & WINHTTP_FLAG_SECURE)
|
||||
{
|
||||
TRACE("redirect from secure page to non-secure page\n");
|
||||
request->hdr.flags &= ~WINHTTP_FLAG_SECURE;
|
||||
}
|
||||
else if (uc.nScheme == INTERNET_SCHEME_HTTPS && !(request->hdr.flags & WINHTTP_FLAG_SECURE))
|
||||
{
|
||||
TRACE("redirect from non-secure page to secure page\n");
|
||||
request->hdr.flags |= WINHTTP_FLAG_SECURE;
|
||||
}
|
||||
|
||||
len = uc.dwHostNameLength;
|
||||
if (!(hostname = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
|
||||
memcpy( hostname, uc.lpszHostName, len * sizeof(WCHAR) );
|
||||
hostname[len] = 0;
|
||||
|
||||
port = uc.nPort ? uc.nPort : (uc.nScheme == INTERNET_SCHEME_HTTPS ? 443 : 80);
|
||||
if (strcmpiW( connect->servername, hostname ) || connect->serverport != port)
|
||||
{
|
||||
heap_free( connect->hostname );
|
||||
connect->hostname = hostname;
|
||||
heap_free( connect->servername );
|
||||
connect->servername = strdupW( connect->hostname );
|
||||
connect->serverport = connect->hostport = port;
|
||||
|
||||
netconn_close( &request->netconn );
|
||||
if (!(ret = netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE ))) goto end;
|
||||
}
|
||||
if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end;
|
||||
if (!(ret = open_connection( request ))) goto end;
|
||||
|
||||
heap_free( request->path );
|
||||
request->path = NULL;
|
||||
if (uc.dwUrlPathLength)
|
||||
{
|
||||
len = uc.dwUrlPathLength + uc.dwExtraInfoLength;
|
||||
if (!(request->path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
|
||||
strcpyW( request->path, uc.lpszUrlPath );
|
||||
}
|
||||
else request->path = strdupW( slashW );
|
||||
}
|
||||
|
||||
len = uc.dwHostNameLength;
|
||||
if (!(hostname = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
|
||||
memcpy( hostname, uc.lpszHostName, len * sizeof(WCHAR) );
|
||||
hostname[len] = 0;
|
||||
|
||||
port = uc.nPort ? uc.nPort : (uc.nScheme == INTERNET_SCHEME_HTTPS ? 443 : 80);
|
||||
if (strcmpiW( connect->servername, hostname ) || connect->serverport != port)
|
||||
{
|
||||
heap_free( connect->servername );
|
||||
connect->servername = hostname;
|
||||
connect->serverport = connect->hostport = port;
|
||||
|
||||
netconn_close( &request->netconn );
|
||||
if (!(ret = netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE ))) goto end;
|
||||
}
|
||||
if (!(ret = add_host_header( request, hostname, port, WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end;
|
||||
if (!(ret = open_connection( request ))) goto end;
|
||||
|
||||
heap_free( request->path );
|
||||
request->path = NULL;
|
||||
if (uc.lpszUrlPath)
|
||||
{
|
||||
len = uc.dwUrlPathLength + uc.dwExtraInfoLength;
|
||||
if (!(request->path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
|
||||
strcpyW( request->path, uc.lpszUrlPath );
|
||||
}
|
||||
/* remove content-type/length headers */
|
||||
if ((index = get_header_index( request, attr_content_type, 0, TRUE )) >= 0) delete_header( request, index );
|
||||
if ((index = get_header_index( request, attr_content_length, 0, TRUE )) >= 0 ) delete_header( request, index );
|
||||
|
||||
/* redirects are always GET requests */
|
||||
heap_free( request->verb );
|
||||
request->verb = strdupW( getW );
|
||||
ret = TRUE;
|
||||
|
||||
end:
|
||||
|
@ -1062,7 +1140,7 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
|
||||
static BOOL receive_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
|
||||
{
|
||||
DWORD to_read;
|
||||
int bytes_read;
|
||||
|
@ -1083,99 +1161,6 @@ static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* read any content returned by the server so that the connection can be reused */
|
||||
static void drain_content( request_t *request )
|
||||
{
|
||||
DWORD bytes_read;
|
||||
char buffer[2048];
|
||||
|
||||
if (request->content_length == ~0UL) return;
|
||||
for (;;)
|
||||
{
|
||||
if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpReceiveResponse (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
request_t *request;
|
||||
DWORD size, query, status;
|
||||
|
||||
TRACE("%p, %p\n", hrequest, reserved);
|
||||
|
||||
if (!(request = (request_t *)grab_object( hrequest )))
|
||||
{
|
||||
set_last_error( ERROR_INVALID_HANDLE );
|
||||
return FALSE;
|
||||
}
|
||||
if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
|
||||
{
|
||||
release_object( &request->hdr );
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!(ret = receive_response( request, TRUE ))) break;
|
||||
|
||||
size = sizeof(DWORD);
|
||||
query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER;
|
||||
if (!(ret = query_headers( request, query, NULL, &status, &size, NULL ))) break;
|
||||
|
||||
size = sizeof(DWORD);
|
||||
query = WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER;
|
||||
if (!query_headers( request, query, NULL, &request->content_length, &size, NULL ))
|
||||
request->content_length = ~0UL;
|
||||
|
||||
if (status == 200) break;
|
||||
if (status == 301 || status == 302)
|
||||
{
|
||||
if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS) break;
|
||||
drain_content( request );
|
||||
if (!(ret = handle_redirect( request ))) break;
|
||||
}
|
||||
ret = send_request( request, NULL, 0, NULL, 0, 0, 0 );
|
||||
}
|
||||
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpQueryDataAvailable (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD num_bytes;
|
||||
request_t *request;
|
||||
|
||||
TRACE("%p, %p\n", hrequest, available);
|
||||
|
||||
if (!(request = (request_t *)grab_object( hrequest )))
|
||||
{
|
||||
set_last_error( ERROR_INVALID_HANDLE );
|
||||
return FALSE;
|
||||
}
|
||||
if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
|
||||
{
|
||||
release_object( &request->hdr );
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = netconn_query_data_available( &request->netconn, &num_bytes );
|
||||
|
||||
if (ret && available) *available = num_bytes;
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD get_chunk_size( const char *buffer )
|
||||
{
|
||||
const char *p;
|
||||
|
@ -1191,7 +1176,7 @@ static DWORD get_chunk_size( const char *buffer )
|
|||
return size;
|
||||
}
|
||||
|
||||
static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
|
||||
static BOOL receive_data_chunked( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
|
||||
{
|
||||
char reply[MAX_REPLY_LEN], *p = buffer;
|
||||
DWORD buflen, to_read, to_write = size;
|
||||
|
@ -1202,7 +1187,7 @@ static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWO
|
|||
{
|
||||
if (*read == size) break;
|
||||
|
||||
if (request->content_length == ~0UL) /* new chunk */
|
||||
if (request->content_length == ~0u) /* new chunk */
|
||||
{
|
||||
buflen = sizeof(reply);
|
||||
if (!netconn_get_next_line( &request->netconn, reply, &buflen )) break;
|
||||
|
@ -1210,7 +1195,7 @@ static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWO
|
|||
if (!(request->content_length = get_chunk_size( reply )))
|
||||
{
|
||||
/* zero sized chunk marks end of transfer; read any trailing headers and return */
|
||||
receive_response( request, FALSE );
|
||||
read_reply( request );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1236,7 +1221,7 @@ static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWO
|
|||
if (request->content_read == request->content_length) /* chunk complete */
|
||||
{
|
||||
request->content_read = 0;
|
||||
request->content_length = ~0UL;
|
||||
request->content_length = ~0u;
|
||||
|
||||
buflen = sizeof(reply);
|
||||
if (!netconn_get_next_line( &request->netconn, reply, &buflen ))
|
||||
|
@ -1250,17 +1235,285 @@ static BOOL read_data_chunked( request_t *request, void *buffer, DWORD size, DWO
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void finished_reading( request_t *request )
|
||||
{
|
||||
static const WCHAR closeW[] = {'c','l','o','s','e',0};
|
||||
|
||||
BOOL close = FALSE;
|
||||
WCHAR connection[20];
|
||||
DWORD size = sizeof(connection);
|
||||
|
||||
if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE;
|
||||
else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) ||
|
||||
query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION, NULL, connection, &size, NULL ))
|
||||
{
|
||||
if (!strcmpiW( connection, closeW )) close = TRUE;
|
||||
}
|
||||
else if (!strcmpW( request->version, http1_0 )) close = TRUE;
|
||||
|
||||
if (close) close_connection( request );
|
||||
request->content_length = ~0u;
|
||||
request->content_read = 0;
|
||||
}
|
||||
|
||||
static BOOL read_data( request_t *request, void *buffer, DWORD to_read, DWORD *read, BOOL async )
|
||||
{
|
||||
static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0};
|
||||
|
||||
BOOL ret;
|
||||
WCHAR encoding[20];
|
||||
DWORD num_bytes, buflen = sizeof(encoding);
|
||||
|
||||
if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) &&
|
||||
!strcmpiW( encoding, chunked ))
|
||||
{
|
||||
ret = receive_data_chunked( request, buffer, to_read, &num_bytes, async );
|
||||
}
|
||||
else
|
||||
ret = receive_data( request, buffer, to_read, &num_bytes, async );
|
||||
|
||||
if (async)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, num_bytes );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT result;
|
||||
result.dwResult = API_READ_DATA;
|
||||
result.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
if (read) *read = num_bytes;
|
||||
if (!num_bytes) finished_reading( request );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read any content returned by the server so that the connection can be reused */
|
||||
static void drain_content( request_t *request )
|
||||
{
|
||||
DWORD bytes_read;
|
||||
char buffer[2048];
|
||||
|
||||
if (!request->content_length) return;
|
||||
for (;;)
|
||||
{
|
||||
if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return;
|
||||
}
|
||||
}
|
||||
|
||||
static void record_cookies( request_t *request )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < request->num_headers; i++)
|
||||
{
|
||||
header_t *set_cookie = &request->headers[i];
|
||||
if (!strcmpiW( set_cookie->field, attr_set_cookie ) && !set_cookie->is_request)
|
||||
{
|
||||
set_cookies( request, set_cookie->value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL receive_response( request_t *request, BOOL async )
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD size, query, status;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!(ret = read_reply( request ))) break;
|
||||
|
||||
size = sizeof(DWORD);
|
||||
query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER;
|
||||
if (!(ret = query_headers( request, query, NULL, &status, &size, NULL ))) break;
|
||||
|
||||
size = sizeof(DWORD);
|
||||
query = WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER;
|
||||
if (!query_headers( request, query, NULL, &request->content_length, &size, NULL ))
|
||||
request->content_length = ~0u;
|
||||
|
||||
if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request );
|
||||
|
||||
if (status == 301 || status == 302)
|
||||
{
|
||||
if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS) break;
|
||||
|
||||
drain_content( request );
|
||||
if (!(ret = handle_redirect( request ))) break;
|
||||
|
||||
clear_response_headers( request );
|
||||
ret = send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE ); /* recurse synchronously */
|
||||
continue;
|
||||
}
|
||||
if (status == 401) FIXME("authentication not supported\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (async)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT result;
|
||||
result.dwResult = API_RECEIVE_RESPONSE;
|
||||
result.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void task_receive_response( task_header_t *task )
|
||||
{
|
||||
receive_response_t *r = (receive_response_t *)task;
|
||||
receive_response( r->hdr.request, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpReceiveResponse (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
|
||||
{
|
||||
BOOL ret;
|
||||
request_t *request;
|
||||
|
||||
TRACE("%p, %p\n", hrequest, reserved);
|
||||
|
||||
if (!(request = (request_t *)grab_object( hrequest )))
|
||||
{
|
||||
set_last_error( ERROR_INVALID_HANDLE );
|
||||
return FALSE;
|
||||
}
|
||||
if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
|
||||
{
|
||||
release_object( &request->hdr );
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
receive_response_t *r;
|
||||
|
||||
if (!(r = heap_alloc( sizeof(receive_response_t) ))) return FALSE;
|
||||
r->hdr.request = request;
|
||||
r->hdr.proc = task_receive_response;
|
||||
|
||||
addref_object( &request->hdr );
|
||||
ret = queue_task( (task_header_t *)r );
|
||||
}
|
||||
else
|
||||
ret = receive_response( request, FALSE );
|
||||
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL query_data( request_t *request, LPDWORD available, BOOL async )
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD num_bytes;
|
||||
|
||||
if ((ret = netconn_query_data_available( &request->netconn, &num_bytes )))
|
||||
{
|
||||
if (request->content_read < request->content_length)
|
||||
{
|
||||
if (!num_bytes)
|
||||
{
|
||||
char buffer[4096];
|
||||
size_t to_read = min( sizeof(buffer), request->content_length - request->content_read );
|
||||
|
||||
ret = netconn_recv( &request->netconn, buffer, to_read, MSG_PEEK, (int *)&num_bytes );
|
||||
if (ret && !num_bytes) WARN("expected more data to be available\n");
|
||||
}
|
||||
}
|
||||
else if (num_bytes)
|
||||
{
|
||||
WARN("extra data available %u\n", num_bytes);
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
TRACE("%u bytes available\n", num_bytes);
|
||||
|
||||
if (async)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, &num_bytes, sizeof(DWORD) );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT result;
|
||||
result.dwResult = API_QUERY_DATA_AVAILABLE;
|
||||
result.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
|
||||
}
|
||||
}
|
||||
if (ret && available) *available = num_bytes;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void task_query_data( task_header_t *task )
|
||||
{
|
||||
query_data_t *q = (query_data_t *)task;
|
||||
query_data( q->hdr.request, q->available, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpQueryDataAvailable (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
|
||||
{
|
||||
BOOL ret;
|
||||
request_t *request;
|
||||
|
||||
TRACE("%p, %p\n", hrequest, available);
|
||||
|
||||
if (!(request = (request_t *)grab_object( hrequest )))
|
||||
{
|
||||
set_last_error( ERROR_INVALID_HANDLE );
|
||||
return FALSE;
|
||||
}
|
||||
if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
|
||||
{
|
||||
release_object( &request->hdr );
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
query_data_t *q;
|
||||
|
||||
if (!(q = heap_alloc( sizeof(query_data_t) ))) return FALSE;
|
||||
q->hdr.request = request;
|
||||
q->hdr.proc = task_query_data;
|
||||
q->available = available;
|
||||
|
||||
addref_object( &request->hdr );
|
||||
ret = queue_task( (task_header_t *)q );
|
||||
}
|
||||
else
|
||||
ret = query_data( request, available, FALSE );
|
||||
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void task_read_data( task_header_t *task )
|
||||
{
|
||||
read_data_t *r = (read_data_t *)task;
|
||||
read_data( r->hdr.request, r->buffer, r->to_read, r->read, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpReadData (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, LPDWORD read )
|
||||
{
|
||||
static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0};
|
||||
|
||||
BOOL ret;
|
||||
request_t *request;
|
||||
WCHAR encoding[20];
|
||||
DWORD num_bytes, buflen = sizeof(encoding);
|
||||
|
||||
TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read);
|
||||
|
||||
|
@ -1276,19 +1529,55 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) &&
|
||||
!strcmpiW( encoding, chunked ))
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
ret = read_data_chunked( request, buffer, to_read, &num_bytes, request->hdr.flags & WINHTTP_FLAG_ASYNC );
|
||||
read_data_t *r;
|
||||
|
||||
if (!(r = heap_alloc( sizeof(read_data_t) ))) return FALSE;
|
||||
r->hdr.request = request;
|
||||
r->hdr.proc = task_read_data;
|
||||
r->buffer = buffer;
|
||||
r->to_read = to_read;
|
||||
r->read = read;
|
||||
|
||||
addref_object( &request->hdr );
|
||||
ret = queue_task( (task_header_t *)r );
|
||||
}
|
||||
else
|
||||
ret = read_data( request, buffer, to_read, &num_bytes, request->hdr.flags & WINHTTP_FLAG_ASYNC );
|
||||
ret = read_data( request, buffer, to_read, read, FALSE );
|
||||
|
||||
if (ret && read) *read = num_bytes;
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL write_data( request_t *request, LPCVOID buffer, DWORD to_write, LPDWORD written, BOOL async )
|
||||
{
|
||||
BOOL ret;
|
||||
int num_bytes;
|
||||
|
||||
ret = netconn_send( &request->netconn, buffer, to_write, 0, &num_bytes );
|
||||
|
||||
if (async)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &num_bytes, sizeof(DWORD) );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT result;
|
||||
result.dwResult = API_WRITE_DATA;
|
||||
result.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
|
||||
}
|
||||
}
|
||||
if (ret && written) *written = num_bytes;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void task_write_data( task_header_t *task )
|
||||
{
|
||||
write_data_t *w = (write_data_t *)task;
|
||||
write_data( w->hdr.request, w->buffer, w->to_write, w->written, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpWriteData (winhttp.@)
|
||||
*/
|
||||
|
@ -1311,7 +1600,22 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ret = netconn_send( &request->netconn, buffer, to_write, 0, (int *)written );
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
write_data_t *w;
|
||||
|
||||
if (!(w = heap_alloc( sizeof(write_data_t) ))) return FALSE;
|
||||
w->hdr.request = request;
|
||||
w->hdr.proc = task_write_data;
|
||||
w->buffer = buffer;
|
||||
w->to_write = to_write;
|
||||
w->written = written;
|
||||
|
||||
addref_object( &request->hdr );
|
||||
ret = queue_task( (task_header_t *)w );
|
||||
}
|
||||
else
|
||||
ret = write_data( request, buffer, to_write, written, FALSE );
|
||||
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winhttp.h"
|
||||
#include "wincrypt.h"
|
||||
|
||||
#include "winhttp_private.h"
|
||||
|
||||
|
@ -36,11 +37,17 @@ void set_last_error( DWORD error )
|
|||
SetLastError( error );
|
||||
}
|
||||
|
||||
DWORD get_last_error( void )
|
||||
{
|
||||
/* FIXME */
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
|
||||
{
|
||||
TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
|
||||
|
||||
if (hdr->notify_mask & status) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
|
||||
if (hdr->callback && (hdr->notify_mask & status)) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -58,9 +65,16 @@ BOOL WINAPI WinHttpCheckPlatform( void )
|
|||
static void session_destroy( object_header_t *hdr )
|
||||
{
|
||||
session_t *session = (session_t *)hdr;
|
||||
struct list *item, *next;
|
||||
domain_t *domain;
|
||||
|
||||
TRACE("%p\n", session);
|
||||
|
||||
LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
|
||||
{
|
||||
domain = LIST_ENTRY( item, domain_t, entry );
|
||||
delete_domain( domain );
|
||||
}
|
||||
heap_free( session->agent );
|
||||
heap_free( session->proxy_server );
|
||||
heap_free( session->proxy_bypass );
|
||||
|
@ -69,6 +83,30 @@ static void session_destroy( object_header_t *hdr )
|
|||
heap_free( session );
|
||||
}
|
||||
|
||||
static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case WINHTTP_OPTION_REDIRECT_POLICY:
|
||||
{
|
||||
if (!buffer || *buflen < sizeof(DWORD))
|
||||
{
|
||||
*buflen = sizeof(DWORD);
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*(DWORD *)buffer = hdr->redirect_policy;
|
||||
*buflen = sizeof(DWORD);
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
FIXME("unimplemented option %u\n", option);
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
|
||||
{
|
||||
switch (option)
|
||||
|
@ -82,22 +120,33 @@ static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffe
|
|||
}
|
||||
case WINHTTP_OPTION_REDIRECT_POLICY:
|
||||
{
|
||||
DWORD policy = *(DWORD *)buffer;
|
||||
DWORD policy;
|
||||
|
||||
if (buflen != sizeof(policy))
|
||||
{
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
policy = *(DWORD *)buffer;
|
||||
TRACE("0x%x\n", policy);
|
||||
hdr->redirect_policy = policy;
|
||||
return TRUE;
|
||||
}
|
||||
case WINHTTP_OPTION_DISABLE_FEATURE:
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
default:
|
||||
FIXME("unimplemented option %u\n", option);
|
||||
return TRUE;
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static const object_vtbl_t session_vtbl =
|
||||
{
|
||||
session_destroy,
|
||||
NULL,
|
||||
session_query_option,
|
||||
session_set_option
|
||||
};
|
||||
|
||||
|
@ -118,6 +167,8 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWST
|
|||
session->hdr.flags = flags;
|
||||
session->hdr.refs = 1;
|
||||
session->access = access;
|
||||
session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
|
||||
list_init( &session->cookie_cache );
|
||||
|
||||
if (agent && !(session->agent = strdupW( agent ))) goto end;
|
||||
if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
|
||||
|
@ -202,10 +253,10 @@ HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PO
|
|||
list_add_head( &session->hdr.children, &connect->hdr.entry );
|
||||
|
||||
if (server && !(connect->hostname = strdupW( server ))) goto end;
|
||||
connect->hostport = port ? port : (connect->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
|
||||
connect->hostport = port;
|
||||
|
||||
if (server && !(connect->servername = strdupW( server ))) goto end;
|
||||
connect->serverport = port ? port : (connect->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
|
||||
connect->serverport = port;
|
||||
|
||||
if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
|
||||
connect->hdr.handle = hconnect;
|
||||
|
@ -225,7 +276,7 @@ end:
|
|||
static void request_destroy( object_header_t *hdr )
|
||||
{
|
||||
request_t *request = (request_t *)hdr;
|
||||
int i;
|
||||
DWORD i;
|
||||
|
||||
TRACE("%p\n", request);
|
||||
|
||||
|
@ -251,15 +302,54 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
|
|||
{
|
||||
case WINHTTP_OPTION_SECURITY_FLAGS:
|
||||
{
|
||||
DWORD flags = 0;
|
||||
DWORD flags;
|
||||
|
||||
if (!buffer || *buflen < sizeof(flags))
|
||||
{
|
||||
*buflen = sizeof(flags);
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
|
||||
*(DWORD *)buffer = flags;
|
||||
*buflen = sizeof(flags);
|
||||
return TRUE;
|
||||
}
|
||||
case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
|
||||
{
|
||||
const CERT_CONTEXT *cert;
|
||||
request_t *request = (request_t *)hdr;
|
||||
|
||||
if (!buffer || *buflen < sizeof(cert))
|
||||
{
|
||||
*buflen = sizeof(cert);
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
|
||||
*(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
|
||||
*buflen = sizeof(cert);
|
||||
return TRUE;
|
||||
}
|
||||
case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
|
||||
{
|
||||
if (!buffer || *buflen < sizeof(DWORD))
|
||||
{
|
||||
*buflen = sizeof(DWORD);
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*(DWORD *)buffer = 128; /* FIXME */
|
||||
*buflen = sizeof(DWORD);
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
FIXME("unimplemented option %u\n", option);
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -277,30 +367,52 @@ static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffe
|
|||
}
|
||||
case WINHTTP_OPTION_DISABLE_FEATURE:
|
||||
{
|
||||
DWORD disable = *(DWORD *)buffer;
|
||||
DWORD disable;
|
||||
|
||||
if (buflen != sizeof(DWORD))
|
||||
{
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
disable = *(DWORD *)buffer;
|
||||
TRACE("0x%x\n", disable);
|
||||
hdr->disable_flags &= disable;
|
||||
hdr->disable_flags |= disable;
|
||||
return TRUE;
|
||||
}
|
||||
case WINHTTP_OPTION_AUTOLOGON_POLICY:
|
||||
{
|
||||
DWORD policy = *(DWORD *)buffer;
|
||||
DWORD policy;
|
||||
|
||||
if (buflen != sizeof(DWORD))
|
||||
{
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
policy = *(DWORD *)buffer;
|
||||
TRACE("0x%x\n", policy);
|
||||
hdr->logon_policy = policy;
|
||||
return TRUE;
|
||||
}
|
||||
case WINHTTP_OPTION_REDIRECT_POLICY:
|
||||
{
|
||||
DWORD policy = *(DWORD *)buffer;
|
||||
DWORD policy;
|
||||
|
||||
if (buflen != sizeof(DWORD))
|
||||
{
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
policy = *(DWORD *)buffer;
|
||||
TRACE("0x%x\n", policy);
|
||||
hdr->redirect_policy = policy;
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
FIXME("unimplemented option %u\n", option);
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -355,9 +467,26 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o
|
|||
|
||||
if (!netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE )) goto end;
|
||||
|
||||
if (verb && !(request->verb = strdupW( verb ))) goto end;
|
||||
if (object && !(request->path = strdupW( object ))) goto end;
|
||||
if (version && !(request->version = strdupW( version ))) goto end;
|
||||
if (!verb || !verb[0]) verb = getW;
|
||||
if (!(request->verb = strdupW( verb ))) goto end;
|
||||
|
||||
if (object)
|
||||
{
|
||||
WCHAR *path, *p;
|
||||
unsigned int len;
|
||||
|
||||
len = strlenW( object ) + 1;
|
||||
if (object[0] != '/') len++;
|
||||
if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
|
||||
|
||||
if (object[0] != '/') *p++ = '/';
|
||||
strcpyW( p, object );
|
||||
request->path = path;
|
||||
}
|
||||
else if (!(request->path = strdupW( slashW ))) goto end;
|
||||
|
||||
if (!version || !version[0]) version = http1_1;
|
||||
if (!(request->version = strdupW( version ))) goto end;
|
||||
|
||||
if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
|
||||
request->hdr.handle = hrequest;
|
||||
|
@ -394,19 +523,36 @@ static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPD
|
|||
{
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!buflen)
|
||||
{
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case WINHTTP_OPTION_CONTEXT_VALUE:
|
||||
{
|
||||
if (!buffer || *buflen < sizeof(DWORD_PTR))
|
||||
{
|
||||
*buflen = sizeof(DWORD_PTR);
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*(DWORD_PTR *)buffer = hdr->context;
|
||||
*buflen = sizeof(DWORD_PTR);
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
|
||||
else FIXME("unimplemented option %u\n", option);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("unimplemented option %u\n", option);
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -437,18 +583,34 @@ static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD
|
|||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case WINHTTP_OPTION_CONTEXT_VALUE:
|
||||
{
|
||||
if (buflen != sizeof(DWORD_PTR))
|
||||
{
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hdr->context = *(DWORD_PTR *)buffer;
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
|
||||
else FIXME("unimplemented option %u\n", option);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("unimplemented option %u\n", option);
|
||||
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
484
reactos/dll/win32/winhttp/url.c
Normal file
484
reactos/dll/win32/winhttp/url.c
Normal file
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* Copyright 2008 Hans Leidekker for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "winhttp.h"
|
||||
#include "shlwapi.h"
|
||||
|
||||
#include "winhttp_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
|
||||
|
||||
static const WCHAR scheme_http[] = {'h','t','t','p',0};
|
||||
static const WCHAR scheme_https[] = {'h','t','t','p','s',0};
|
||||
|
||||
static BOOL set_component( WCHAR **str, DWORD *str_len, WCHAR *value, DWORD len, DWORD flags )
|
||||
{
|
||||
if (!*str)
|
||||
{
|
||||
if (len && (flags & ICU_DECODE))
|
||||
{
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
*str = value;
|
||||
*str_len = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len > (*str_len) - 1)
|
||||
{
|
||||
*str_len = len + 1;
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
memcpy( *str, value, len * sizeof(WCHAR) );
|
||||
(*str)[len] = 0;
|
||||
*str_len = len;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL decode_url( LPCWSTR url, LPWSTR buffer, LPDWORD buflen )
|
||||
{
|
||||
HRESULT hr = UrlCanonicalizeW( url, buffer, buflen, URL_WININET_COMPATIBILITY | URL_UNESCAPE );
|
||||
if (hr == E_POINTER) set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
if (hr == E_INVALIDARG) set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return (SUCCEEDED(hr)) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpCrackUrl (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
WCHAR *p, *q, *r;
|
||||
WCHAR *url_decoded = NULL;
|
||||
|
||||
TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, uc);
|
||||
|
||||
if (flags & ICU_ESCAPE) FIXME("flag ICU_ESCAPE not supported\n");
|
||||
|
||||
if (!url || !uc || uc->dwStructSize != sizeof(URL_COMPONENTS))
|
||||
{
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
if (!len) len = strlenW( url );
|
||||
|
||||
if (flags & ICU_DECODE)
|
||||
{
|
||||
WCHAR *url_tmp;
|
||||
DWORD url_len = len + 1;
|
||||
|
||||
if (!(url_tmp = HeapAlloc( GetProcessHeap(), 0, url_len * sizeof(WCHAR) )))
|
||||
{
|
||||
set_last_error( ERROR_OUTOFMEMORY );
|
||||
return FALSE;
|
||||
}
|
||||
memcpy( url_tmp, url, len * sizeof(WCHAR) );
|
||||
url_tmp[len] = 0;
|
||||
if (!(url_decoded = HeapAlloc( GetProcessHeap(), 0, url_len * sizeof(WCHAR) )))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, url_tmp );
|
||||
set_last_error( ERROR_OUTOFMEMORY );
|
||||
return FALSE;
|
||||
}
|
||||
if (decode_url( url_tmp, url_decoded, &url_len ))
|
||||
{
|
||||
len = url_len;
|
||||
url = url_decoded;
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, url_tmp );
|
||||
}
|
||||
if (!(p = strchrW( url, ':' )))
|
||||
{
|
||||
set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
|
||||
return FALSE;
|
||||
}
|
||||
if (p - url == 4 && !strncmpiW( url, scheme_http, 4 )) uc->nScheme = INTERNET_SCHEME_HTTP;
|
||||
else if (p - url == 5 && !strncmpiW( url, scheme_https, 5 )) uc->nScheme = INTERNET_SCHEME_HTTPS;
|
||||
else
|
||||
{
|
||||
set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
|
||||
goto exit;
|
||||
}
|
||||
if (!(set_component( &uc->lpszScheme, &uc->dwSchemeLength, (WCHAR *)url, p - url, flags ))) goto exit;
|
||||
|
||||
p++; /* skip ':' */
|
||||
if (!p[0] || p[0] != '/' || p[1] != '/') goto exit;
|
||||
p += 2;
|
||||
|
||||
if (!p[0]) goto exit;
|
||||
if ((q = memchrW( p, '@', len - (p - url) )))
|
||||
{
|
||||
if ((r = memchrW( p, ':', q - p )))
|
||||
{
|
||||
if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, r - p, flags ))) goto exit;
|
||||
r++;
|
||||
if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, r, q - r, flags ))) goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, q - p, flags ))) goto exit;
|
||||
if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags ))) goto exit;
|
||||
}
|
||||
p = q + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, NULL, 0, flags ))) goto exit;
|
||||
if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags ))) goto exit;
|
||||
}
|
||||
if ((q = memchrW( p, '/', len - (p - url) )))
|
||||
{
|
||||
if ((r = memchrW( p, ':', q - p )))
|
||||
{
|
||||
if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags ))) goto exit;
|
||||
r++;
|
||||
uc->nPort = atoiW( r );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, q - p, flags ))) goto exit;
|
||||
if (uc->nScheme == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT;
|
||||
if (uc->nScheme == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT;
|
||||
}
|
||||
|
||||
if ((r = memchrW( q, '?', len - (q - url) )))
|
||||
{
|
||||
if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, r - q, flags ))) goto exit;
|
||||
if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, r, len - (r - url), flags ))) goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, len - (q - url), flags ))) goto exit;
|
||||
if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags ))) goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r = memchrW( p, ':', len - (p - url) )))
|
||||
{
|
||||
if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags ))) goto exit;
|
||||
r++;
|
||||
uc->nPort = atoiW( r );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, len - (p - url), flags ))) goto exit;
|
||||
if (uc->nScheme == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT;
|
||||
if (uc->nScheme == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT;
|
||||
}
|
||||
if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, (WCHAR *)url + len, 0, flags ))) goto exit;
|
||||
if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags ))) goto exit;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
TRACE("scheme(%s) host(%s) port(%d) path(%s) extra(%s)\n",
|
||||
debugstr_wn( uc->lpszScheme, uc->dwSchemeLength ),
|
||||
debugstr_wn( uc->lpszHostName, uc->dwHostNameLength ),
|
||||
uc->nPort,
|
||||
debugstr_wn( uc->lpszUrlPath, uc->dwUrlPathLength ),
|
||||
debugstr_wn( uc->lpszExtraInfo, uc->dwExtraInfoLength ));
|
||||
|
||||
exit:
|
||||
HeapFree( GetProcessHeap(), 0, url_decoded );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static INTERNET_SCHEME get_scheme( const WCHAR *scheme, DWORD len )
|
||||
{
|
||||
if (!strncmpW( scheme, scheme_http, len )) return INTERNET_SCHEME_HTTP;
|
||||
if (!strncmpW( scheme, scheme_https, len )) return INTERNET_SCHEME_HTTPS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const WCHAR *get_scheme_string( INTERNET_SCHEME scheme )
|
||||
{
|
||||
if (scheme == INTERNET_SCHEME_HTTP) return scheme_http;
|
||||
if (scheme == INTERNET_SCHEME_HTTPS) return scheme_https;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL uses_default_port( INTERNET_SCHEME scheme, INTERNET_PORT port )
|
||||
{
|
||||
if ((scheme == INTERNET_SCHEME_HTTP) && (port == INTERNET_DEFAULT_HTTP_PORT)) return TRUE;
|
||||
if ((scheme == INTERNET_SCHEME_HTTPS) && (port == INTERNET_DEFAULT_HTTPS_PORT)) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL need_escape( WCHAR c )
|
||||
{
|
||||
if (isalnumW( c )) return FALSE;
|
||||
|
||||
if (c <= 31 || c >= 127) return TRUE;
|
||||
else
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ':
|
||||
case '"':
|
||||
case '#':
|
||||
case '%':
|
||||
case '<':
|
||||
case '>':
|
||||
case ']':
|
||||
case '\\':
|
||||
case '[':
|
||||
case '^':
|
||||
case '`':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
case '~':
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD copy_escape( WCHAR *dst, const WCHAR *src, DWORD len )
|
||||
{
|
||||
static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
DWORD ret = len;
|
||||
unsigned int i;
|
||||
WCHAR *p = dst;
|
||||
|
||||
for (i = 0; i < len; i++, p++)
|
||||
{
|
||||
if (need_escape( src[i] ))
|
||||
{
|
||||
p[0] = '%';
|
||||
p[1] = hex[(src[i] >> 4) & 0xf];
|
||||
p[2] = hex[src[i] & 0xf];
|
||||
ret += 2;
|
||||
p += 2;
|
||||
}
|
||||
else *p = src[i];
|
||||
}
|
||||
dst[ret] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD comp_length( DWORD len, DWORD flags, WCHAR *comp )
|
||||
{
|
||||
DWORD ret;
|
||||
unsigned int i;
|
||||
|
||||
ret = len ? len : strlenW( comp );
|
||||
if (!(flags & ICU_ESCAPE)) return ret;
|
||||
for (i = 0; i < len; i++) if (need_escape( comp[i] )) ret += 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL calc_length( URL_COMPONENTS *uc, DWORD flags, LPDWORD len )
|
||||
{
|
||||
static const WCHAR formatW[] = {'%','d',0};
|
||||
INTERNET_SCHEME scheme;
|
||||
|
||||
*len = 0;
|
||||
if (uc->lpszScheme)
|
||||
{
|
||||
DWORD scheme_len = comp_length( uc->dwSchemeLength, 0, uc->lpszScheme );
|
||||
*len += scheme_len;
|
||||
scheme = get_scheme( uc->lpszScheme, scheme_len );
|
||||
}
|
||||
else
|
||||
{
|
||||
scheme = uc->nScheme;
|
||||
if (!scheme) scheme = INTERNET_SCHEME_HTTP;
|
||||
*len += strlenW( get_scheme_string( scheme ) );
|
||||
}
|
||||
*len += 1; /* ':' */
|
||||
if (uc->lpszHostName) *len += 2; /* "//" */
|
||||
|
||||
if (uc->lpszUserName)
|
||||
{
|
||||
*len += comp_length( uc->dwUserNameLength, 0, uc->lpszUserName );
|
||||
*len += 1; /* "@" */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uc->lpszPassword)
|
||||
{
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (uc->lpszPassword)
|
||||
{
|
||||
*len += 1; /* ":" */
|
||||
*len += comp_length( uc->dwPasswordLength, 0, uc->lpszPassword );
|
||||
}
|
||||
if (uc->lpszHostName)
|
||||
{
|
||||
*len += comp_length( uc->dwHostNameLength, 0, uc->lpszHostName );
|
||||
|
||||
if (!uses_default_port( scheme, uc->nPort ))
|
||||
{
|
||||
WCHAR port[sizeof("65535")];
|
||||
|
||||
sprintfW( port, formatW, uc->nPort );
|
||||
*len += strlenW( port );
|
||||
*len += 1; /* ":" */
|
||||
}
|
||||
if (uc->lpszUrlPath && *uc->lpszUrlPath != '/') *len += 1; /* '/' */
|
||||
}
|
||||
if (uc->lpszUrlPath) *len += comp_length( uc->dwUrlPathLength, flags, uc->lpszUrlPath );
|
||||
if (uc->lpszExtraInfo) *len += comp_length( uc->dwExtraInfoLength, flags, uc->lpszExtraInfo );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WinHttpCreateUrl (winhttp.@)
|
||||
*/
|
||||
BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDWORD required )
|
||||
{
|
||||
static const WCHAR formatW[] = {'%','d',0};
|
||||
static const WCHAR twoslashW[] = {'/','/'};
|
||||
|
||||
DWORD len;
|
||||
INTERNET_SCHEME scheme;
|
||||
|
||||
TRACE("%p, 0x%08x, %p, %p\n", uc, flags, url, required);
|
||||
|
||||
if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required)
|
||||
{
|
||||
set_last_error( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!calc_length( uc, flags, &len )) return FALSE;
|
||||
|
||||
if (!url || *required < len)
|
||||
{
|
||||
*required = len + 1;
|
||||
set_last_error( ERROR_INSUFFICIENT_BUFFER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
url[0] = 0;
|
||||
*required = len;
|
||||
if (uc->lpszScheme)
|
||||
{
|
||||
len = comp_length( uc->dwSchemeLength, 0, uc->lpszScheme );
|
||||
memcpy( url, uc->lpszScheme, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
|
||||
scheme = get_scheme( uc->lpszScheme, len );
|
||||
}
|
||||
else
|
||||
{
|
||||
const WCHAR *schemeW;
|
||||
scheme = uc->nScheme;
|
||||
|
||||
if (!scheme) scheme = INTERNET_SCHEME_HTTP;
|
||||
|
||||
schemeW = get_scheme_string( scheme );
|
||||
len = strlenW( schemeW );
|
||||
memcpy( url, schemeW, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
}
|
||||
|
||||
/* all schemes are followed by at least a colon */
|
||||
*url = ':';
|
||||
url++;
|
||||
|
||||
if (uc->lpszHostName)
|
||||
{
|
||||
memcpy( url, twoslashW, sizeof(twoslashW) );
|
||||
url += sizeof(twoslashW) / sizeof(twoslashW[0]);
|
||||
}
|
||||
if (uc->lpszUserName)
|
||||
{
|
||||
len = comp_length( uc->dwUserNameLength, 0, uc->lpszUserName );
|
||||
memcpy( url, uc->lpszUserName, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
|
||||
if (uc->lpszPassword)
|
||||
{
|
||||
*url = ':';
|
||||
url++;
|
||||
|
||||
len = comp_length( uc->dwPasswordLength, 0, uc->lpszPassword );
|
||||
memcpy( url, uc->lpszPassword, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
}
|
||||
*url = '@';
|
||||
url++;
|
||||
}
|
||||
if (uc->lpszHostName)
|
||||
{
|
||||
len = comp_length( uc->dwHostNameLength, 0, uc->lpszHostName );
|
||||
memcpy( url, uc->lpszHostName, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
|
||||
if (!uses_default_port( scheme, uc->nPort ))
|
||||
{
|
||||
WCHAR port[sizeof("65535")];
|
||||
|
||||
sprintfW( port, formatW, uc->nPort );
|
||||
*url = ':';
|
||||
url++;
|
||||
|
||||
len = strlenW( port );
|
||||
memcpy( url, port, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
}
|
||||
|
||||
/* add slash between hostname and path if necessary */
|
||||
if (uc->lpszUrlPath && *uc->lpszUrlPath != '/')
|
||||
{
|
||||
*url = '/';
|
||||
url++;
|
||||
}
|
||||
}
|
||||
if (uc->lpszUrlPath)
|
||||
{
|
||||
len = comp_length( uc->dwUrlPathLength, 0, uc->lpszUrlPath );
|
||||
if (flags & ICU_ESCAPE) url += copy_escape( url, uc->lpszUrlPath, len );
|
||||
else
|
||||
{
|
||||
memcpy( url, uc->lpszUrlPath, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
}
|
||||
}
|
||||
if (uc->lpszExtraInfo)
|
||||
{
|
||||
len = comp_length( uc->dwExtraInfoLength, 0, uc->lpszExtraInfo );
|
||||
if (flags & ICU_ESCAPE) url += copy_escape( url, uc->lpszExtraInfo, len );
|
||||
else
|
||||
{
|
||||
memcpy( url, uc->lpszExtraInfo, len * sizeof(WCHAR) );
|
||||
url += len;
|
||||
}
|
||||
}
|
||||
*url = 0;
|
||||
return TRUE;
|
||||
}
|
|
@ -7,12 +7,15 @@
|
|||
<include base="winhttp">.</include>
|
||||
<include base="ReactOS">include/reactos/wine</include>
|
||||
<define name="__WINESRC__" />
|
||||
<file>cookie.c</file>
|
||||
<file>handle.c</file>
|
||||
<file>main.c</file>
|
||||
<file>net.c</file>
|
||||
<file>request.c</file>
|
||||
<file>session.c</file>
|
||||
<file>url.c</file>
|
||||
<library>wine</library>
|
||||
<library>shlwapi</library>
|
||||
<library>wininet</library>
|
||||
<library>ws2_32</library>
|
||||
<library>kernel32</library>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "wine/list.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
@ -33,14 +34,17 @@
|
|||
# include <netdb.h>
|
||||
#endif
|
||||
#if defined(__MINGW32__) || defined (_MSC_VER)
|
||||
# include "ws2tcpip.h"
|
||||
# ifndef MSG_WAITALL
|
||||
# define MSG_WAITALL 0
|
||||
# endif
|
||||
# include <ws2tcpip.h>
|
||||
#else
|
||||
# define closesocket close
|
||||
# define ioctlsocket ioctl
|
||||
#endif /* __MINGW32__ */
|
||||
# define closesocket close
|
||||
# define ioctlsocket ioctl
|
||||
#endif
|
||||
|
||||
static const WCHAR getW[] = {'G','E','T',0};
|
||||
static const WCHAR postW[] = {'P','O','S','T',0};
|
||||
static const WCHAR slashW[] = {'/',0};
|
||||
static const WCHAR http1_0[] = {'H','T','T','P','/','1','.','0',0};
|
||||
static const WCHAR http1_1[] = {'H','T','T','P','/','1','.','1',0};
|
||||
|
||||
typedef struct _object_header_t object_header_t;
|
||||
|
||||
|
@ -69,6 +73,21 @@ struct _object_header_t
|
|||
struct list children;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list entry;
|
||||
WCHAR *name;
|
||||
struct list cookies;
|
||||
} domain_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list entry;
|
||||
WCHAR *name;
|
||||
WCHAR *value;
|
||||
WCHAR *path;
|
||||
} cookie_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
object_header_t hdr;
|
||||
|
@ -78,6 +97,7 @@ typedef struct
|
|||
LPWSTR proxy_bypass;
|
||||
LPWSTR proxy_username;
|
||||
LPWSTR proxy_password;
|
||||
struct list cookie_cache;
|
||||
} session_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -97,7 +117,6 @@ typedef struct
|
|||
{
|
||||
int socket;
|
||||
BOOL secure; /* SSL active on connection? */
|
||||
void *ssl_ctx;
|
||||
void *ssl_conn;
|
||||
char *peek_msg;
|
||||
char *peek_msg_mem;
|
||||
|
@ -127,6 +146,52 @@ typedef struct
|
|||
DWORD num_headers;
|
||||
} request_t;
|
||||
|
||||
typedef struct _task_header_t task_header_t;
|
||||
|
||||
struct _task_header_t
|
||||
{
|
||||
request_t *request;
|
||||
void (*proc)( task_header_t * );
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
task_header_t hdr;
|
||||
LPWSTR headers;
|
||||
DWORD headers_len;
|
||||
LPVOID optional;
|
||||
DWORD optional_len;
|
||||
DWORD total_len;
|
||||
DWORD_PTR context;
|
||||
} send_request_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
task_header_t hdr;
|
||||
} receive_response_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
task_header_t hdr;
|
||||
LPDWORD available;
|
||||
} query_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
task_header_t hdr;
|
||||
LPVOID buffer;
|
||||
DWORD to_read;
|
||||
LPDWORD read;
|
||||
} read_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
task_header_t hdr;
|
||||
LPCVOID buffer;
|
||||
DWORD to_write;
|
||||
LPDWORD written;
|
||||
} write_data_t;
|
||||
|
||||
object_header_t *addref_object( object_header_t * );
|
||||
object_header_t *grab_object( HINTERNET );
|
||||
void release_object( object_header_t * );
|
||||
|
@ -134,6 +199,7 @@ HINTERNET alloc_handle( object_header_t * );
|
|||
BOOL free_handle( HINTERNET );
|
||||
|
||||
void set_last_error( DWORD );
|
||||
DWORD get_last_error( void );
|
||||
void send_callback( object_header_t *, DWORD, LPVOID, DWORD );
|
||||
void close_connection( request_t * );
|
||||
|
||||
|
@ -148,6 +214,12 @@ BOOL netconn_recv( netconn_t *, void *, size_t, int, int * );
|
|||
BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_in * );
|
||||
BOOL netconn_secure_connect( netconn_t * );
|
||||
BOOL netconn_send( netconn_t *, const void *, size_t, int, int * );
|
||||
const void *netconn_get_certificate( netconn_t * );
|
||||
|
||||
BOOL set_cookies( request_t *, const WCHAR * );
|
||||
BOOL add_cookie_headers( request_t * );
|
||||
BOOL add_request_headers( request_t *, LPCWSTR, DWORD, DWORD );
|
||||
void delete_domain( domain_t * );
|
||||
|
||||
static inline void *heap_alloc( SIZE_T size )
|
||||
{
|
||||
|
|
|
@ -36,6 +36,8 @@ typedef INTERNET_PORT *LPINTERNET_PORT;
|
|||
#define INTERNET_SCHEME_HTTPS 2
|
||||
typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
|
||||
|
||||
#define ICU_ESCAPE 0x80000000
|
||||
|
||||
/* flags for WinHttpOpen */
|
||||
#define WINHTTP_FLAG_ASYNC 0x10000000
|
||||
|
||||
|
|
Loading…
Reference in a new issue