q++; /* skip past colon */
while (*q == ' ') q++;
- if (!*q)
- {
- WARN("no value in line %s\n", debugstr_w(string));
- return header;
- }
len = strlenW( q );
+
if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) )))
{
free_header( header );
static BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DWORD flags, BOOL request_only )
{
int index;
- header_t *header;
+ header_t hdr;
TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags);
- /* replace wins out over add */
- if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) flags &= ~WINHTTP_ADDREQ_FLAG_ADD;
-
- if (flags & WINHTTP_ADDREQ_FLAG_ADD) index = -1;
- else
- index = get_header_index( request, field, 0, request_only );
-
- if (index >= 0)
+ if ((index = get_header_index( request, field, 0, request_only )) >= 0)
{
if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return FALSE;
- header = &request->headers[index];
}
- else if (value)
+
+ if (flags & WINHTTP_ADDREQ_FLAG_REPLACE)
{
- header_t hdr;
+ if (index >= 0)
+ {
+ delete_header( request, index );
+ if (!value || !value[0]) return TRUE;
+ }
+ else if (!(flags & WINHTTP_ADDREQ_FLAG_ADD))
+ {
+ set_last_error( ERROR_WINHTTP_HEADER_NOT_FOUND );
+ return FALSE;
+ }
hdr.field = (LPWSTR)field;
hdr.value = (LPWSTR)value;
hdr.is_request = request_only;
-
return insert_header( request, &hdr );
}
- /* no value to delete */
- else return TRUE;
-
- if (flags & WINHTTP_ADDREQ_FLAG_REPLACE)
- {
- delete_header( request, index );
- if (value)
- {
- header_t hdr;
-
- hdr.field = (LPWSTR)field;
- hdr.value = (LPWSTR)value;
- hdr.is_request = request_only;
-
- return insert_header( request, &hdr );
- }
- return TRUE;
- }
- else if (flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON))
+ else if (value)
{
- WCHAR sep, *tmp;
- int len, orig_len, value_len;
- orig_len = strlenW( header->value );
- value_len = strlenW( value );
+ if ((flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON)) &&
+ index >= 0)
+ {
+ WCHAR *tmp;
+ int len, len_orig, len_value;
+ header_t *header = &request->headers[index];
- if (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) sep = ',';
- else sep = ';';
+ len_orig = strlenW( header->value );
+ len_value = strlenW( value );
- len = orig_len + value_len + 2;
- if ((tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) )))
- {
+ len = len_orig + len_value + 2;
+ if (!(tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) return FALSE;
header->value = tmp;
+ header->value[len_orig++] = (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) ? ',' : ';';
+ header->value[len_orig++] = ' ';
- header->value[orig_len] = sep;
- orig_len++;
- header->value[orig_len] = ' ';
- orig_len++;
-
- memcpy( &header->value[orig_len], value, value_len * sizeof(WCHAR) );
+ memcpy( &header->value[len_orig], value, len_value * sizeof(WCHAR) );
header->value[len] = 0;
return TRUE;
}
+ else
+ {
+ hdr.field = (LPWSTR)field;
+ hdr.value = (LPWSTR)value;
+ hdr.is_request = request_only;
+ return insert_header( request, &hdr );
+ }
}
+
return TRUE;
}
if (len == ~0u) len = strlenW( headers );
if (!len) return TRUE;
if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
- strcpyW( buffer, headers );
+ memcpy( buffer, headers, len * sizeof(WCHAR) );
+ buffer[len] = 0;
p = buffer;
do
TRACE("%p, %s, 0x%x, 0x%08x\n", hrequest, debugstr_w(headers), len, flags);
- if (!headers)
+ if (!headers || !len)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
#define INET6_ADDRSTRLEN 46
#endif
-static WCHAR *addr_to_str( const struct sockaddr *addr )
+static WCHAR *addr_to_str( struct sockaddr *addr )
{
char buf[INET6_ADDRSTRLEN];
- const void *src;
+ void *src;
switch (addr->sa_family)
{
return FALSE;
}
+ if (headers && !headers_len) headers_len = strlenW( headers );
+
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
{
send_request_t *s;
return FALSE;
auth_ptr = &request->authinfo;
auth_target = attr_authorization;
- username = request->connect->username;
- password = request->connect->password;
+ if (request->creds[TARGET_SERVER][scheme].username)
+ {
+ username = request->creds[TARGET_SERVER][scheme].username;
+ password = request->creds[TARGET_SERVER][scheme].password;
+ }
+ else
+ {
+ username = request->connect->username;
+ password = request->connect->password;
+ }
break;
case WINHTTP_AUTH_TARGET_PROXY:
return FALSE;
auth_ptr = &request->proxy_authinfo;
auth_target = attr_proxy_authorization;
- username = request->connect->session->proxy_username;
- password = request->connect->session->proxy_password;
+ if (request->creds[TARGET_PROXY][scheme].username)
+ {
+ username = request->creds[TARGET_PROXY][scheme].username;
+ password = request->creds[TARGET_PROXY][scheme].password;
+ }
+ else
+ {
+ username = request->connect->session->proxy_username;
+ password = request->connect->session->proxy_password;
+ }
break;
default:
return ret;
}
-static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme, const WCHAR *username,
+static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme_flag, const WCHAR *username,
const WCHAR *password )
{
- if ((scheme == WINHTTP_AUTH_SCHEME_BASIC || scheme == WINHTTP_AUTH_SCHEME_DIGEST) &&
- (!username || !password))
+ enum auth_scheme scheme = scheme_from_flag( scheme_flag );
+
+ if (scheme == SCHEME_INVALID || ((scheme == SCHEME_BASIC || scheme == SCHEME_DIGEST) && (!username || !password)))
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
{
case WINHTTP_AUTH_TARGET_SERVER:
{
- heap_free( request->connect->username );
- if (!username) request->connect->username = NULL;
- else if (!(request->connect->username = strdupW( username ))) return FALSE;
+ heap_free( request->creds[TARGET_SERVER][scheme].username );
+ if (!username) request->creds[TARGET_SERVER][scheme].username = NULL;
+ else if (!(request->creds[TARGET_SERVER][scheme].username = strdupW( username ))) return FALSE;
- heap_free( request->connect->password );
- if (!password) request->connect->password = NULL;
- else if (!(request->connect->password = strdupW( password ))) return FALSE;
+ heap_free( request->creds[TARGET_SERVER][scheme].password );
+ if (!password) request->creds[TARGET_SERVER][scheme].password = NULL;
+ else if (!(request->creds[TARGET_SERVER][scheme].password = strdupW( password ))) return FALSE;
break;
}
case WINHTTP_AUTH_TARGET_PROXY:
{
- heap_free( request->connect->session->proxy_username );
- if (!username) request->connect->session->proxy_username = NULL;
- else if (!(request->connect->session->proxy_username = strdupW( username ))) return FALSE;
+ heap_free( request->creds[TARGET_PROXY][scheme].username );
+ if (!username) request->creds[TARGET_PROXY][scheme].username = NULL;
+ else if (!(request->creds[TARGET_PROXY][scheme].username = strdupW( username ))) return FALSE;
- heap_free( request->connect->session->proxy_password );
- if (!password) request->connect->session->proxy_password = NULL;
- else if (!(request->connect->session->proxy_password = strdupW( password ))) return FALSE;
+ heap_free( request->creds[TARGET_PROXY][scheme].password );
+ if (!password) request->creds[TARGET_PROXY][scheme].password = NULL;
+ else if (!(request->creds[TARGET_PROXY][scheme].password = strdupW( password ))) return FALSE;
break;
}
default:
{
if (!start_next_chunk( request, notify )) return FALSE;
}
+ len = min( len, request->read_chunked_size );
}
- if (!request->read_chunked && request->content_length != ~0u)
+ else if (request->content_length != ~0u)
+ {
len = min( len, request->content_length - request->content_read );
+ }
+
if (len <= request->read_size) return TRUE;
if (!read_more_data( request, len, notify )) return FALSE;
if (!request->read_size) request->content_length = request->content_read = 0;
/* we rely on the fact that the protocol is ascii */
MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len );
status_codeW[len] = 0;
- if (!(process_header( request, attr_status, status_codeW, WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) return FALSE;
+ if (!(process_header( request, attr_status, status_codeW,
+ WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, FALSE )))
+ return FALSE;
len = status_code - buffer;
if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
{
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 );
-
+ if (location[0] == '/')
+ {
+ len = strlenW( location );
+ if (!(path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
+ strcpyW( path, location );
+ }
+ else
+ {
+ if ((p = strrchrW( request->path, '/' ))) *p = 0;
+ len = strlenW( request->path ) + 1 + strlenW( location );
+ if (!(path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end;
+ strcpyW( path, request->path );
+ strcatW( path, slashW );
+ strcatW( path, location );
+ }
heap_free( request->path );
request->path = path;
}
else heap_free( hostname );
- if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end;
+ if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end;
if (!(ret = open_connection( request ))) goto end;
heap_free( request->path );
LONG send_timeout;
LONG receive_timeout;
WINHTTP_PROXY_INFO proxy;
+ BOOL async;
};
static inline struct winhttp_request *impl_from_IWinHttpRequest( IWinHttpRequest *iface )
static void cancel_request( struct winhttp_request *request )
{
if (request->state <= REQUEST_STATE_CANCELLED) return;
- if (request->thread) SetEvent( request->cancel );
+
+ SetEvent( request->cancel );
+ LeaveCriticalSection( &request->cs );
+ WaitForSingleObject( request->thread, INFINITE );
+ EnterCriticalSection( &request->cs );
+
request->state = REQUEST_STATE_CANCELLED;
+
+ CloseHandle( request->thread );
+ request->thread = NULL;
+ CloseHandle( request->wait );
+ request->wait = NULL;
+ CloseHandle( request->cancel );
+ request->cancel = NULL;
}
/* critical section must be held */
request->bytes_available = 0;
request->bytes_read = 0;
request->error = ERROR_SUCCESS;
+ request->async = FALSE;
request->logon_policy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM;
request->disable_feature = 0;
request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
request->state = REQUEST_STATE_INITIALIZED;
}
+static void reset_request( struct winhttp_request *request )
+{
+ cancel_request( request );
+ WinHttpCloseHandle( request->hrequest );
+ request->hrequest = NULL;
+ WinHttpCloseHandle( request->hconnect );
+ request->hconnect = NULL;
+ heap_free( request->buffer );
+ request->buffer = NULL;
+ heap_free( request->verb );
+ request->verb = NULL;
+ request->offset = 0;
+ request->bytes_available = 0;
+ request->bytes_read = 0;
+ request->error = ERROR_SUCCESS;
+ request->async = FALSE;
+ VariantClear( &request->data );
+ request->state = REQUEST_STATE_INITIALIZED;
+}
+
static HRESULT WINAPI winhttp_request_Open(
IWinHttpRequest *iface,
BSTR method,
'W','i','n','3','2',';',' ','W','i','n','H','t','t','p','.','W','i','n','H','t','t','p',
'R','e','q','u','e','s','t','.','5',')',0};
struct winhttp_request *request = impl_from_IWinHttpRequest( iface );
- HINTERNET hsession = NULL, hconnect = NULL, hrequest;
URL_COMPONENTS uc;
WCHAR *hostname, *path = NULL, *verb = NULL;
- DWORD err = ERROR_OUTOFMEMORY, len, flags = 0, request_flags = 0;
+ DWORD err = ERROR_OUTOFMEMORY, len, flags = 0;
TRACE("%p, %s, %s, %s\n", request, debugstr_w(method), debugstr_w(url),
debugstr_variant(&async));
if (!WinHttpCrackUrl( url, 0, 0, &uc )) return HRESULT_FROM_WIN32( get_last_error() );
EnterCriticalSection( &request->cs );
- if (request->state != REQUEST_STATE_INITIALIZED)
- {
- cancel_request( request );
- free_request( request );
- initialize_request( request );
- }
+ if (request->state < REQUEST_STATE_INITIALIZED) initialize_request( request );
+ else reset_request( request );
+
if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) goto error;
memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
hostname[uc.dwHostNameLength] = 0;
path[uc.dwUrlPathLength + uc.dwExtraInfoLength] = 0;
if (!(verb = strdupW( method ))) goto error;
- if (SUCCEEDED( VariantChangeType( &async, &async, 0, VT_BOOL )) && V_BOOL( &async )) flags |= WINHTTP_FLAG_ASYNC;
- if (!(hsession = WinHttpOpen( user_agentW, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, flags )))
+ if (SUCCEEDED( VariantChangeType( &async, &async, 0, VT_BOOL )) && V_BOOL( &async )) request->async = TRUE;
+ else request->async = FALSE;
+
+ if (!request->hsession)
{
- err = get_last_error();
- goto error;
+ if (!(request->hsession = WinHttpOpen( user_agentW, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL,
+ WINHTTP_FLAG_ASYNC )))
+ {
+ err = get_last_error();
+ goto error;
+ }
+ if (!(request->hconnect = WinHttpConnect( request->hsession, hostname, uc.nPort, 0 )))
+ {
+ WinHttpCloseHandle( request->hsession );
+ request->hsession = NULL;
+ err = get_last_error();
+ goto error;
+ }
}
- if (!(hconnect = WinHttpConnect( hsession, hostname, uc.nPort, 0 )))
+ else if (!(request->hconnect = WinHttpConnect( request->hsession, hostname, uc.nPort, 0 )))
{
err = get_last_error();
goto error;
}
+
len = sizeof(httpsW) / sizeof(WCHAR);
if (uc.dwSchemeLength == len && !memcmp( uc.lpszScheme, httpsW, len * sizeof(WCHAR) ))
{
- request_flags |= WINHTTP_FLAG_SECURE;
+ flags |= WINHTTP_FLAG_SECURE;
}
- if (!(hrequest = WinHttpOpenRequest( hconnect, method, path, NULL, NULL, acceptW, request_flags )))
+ if (!(request->hrequest = WinHttpOpenRequest( request->hconnect, method, path, NULL, NULL, acceptW, flags )))
{
err = get_last_error();
goto error;
}
- if (flags & WINHTTP_FLAG_ASYNC)
- {
- request->wait = CreateEventW( NULL, FALSE, FALSE, NULL );
- request->cancel = CreateEventW( NULL, FALSE, FALSE, NULL );
- WinHttpSetOption( hrequest, WINHTTP_OPTION_CONTEXT_VALUE, &request, sizeof(request) );
- }
+ WinHttpSetOption( request->hrequest, WINHTTP_OPTION_CONTEXT_VALUE, &request, sizeof(request) );
+
request->state = REQUEST_STATE_OPEN;
- request->hsession = hsession;
- request->hconnect = hconnect;
- request->hrequest = hrequest;
request->verb = verb;
heap_free( hostname );
heap_free( path );
return S_OK;
error:
- WinHttpCloseHandle( hconnect );
- WinHttpCloseHandle( hsession );
+ WinHttpCloseHandle( request->hconnect );
+ request->hconnect = NULL;
heap_free( hostname );
heap_free( path );
heap_free( verb );
goto done;
}
sprintfW( str, fmtW, header, value ? value : emptyW );
- if (!WinHttpAddRequestHeaders( request->hrequest, str, len, WINHTTP_ADDREQ_FLAG_REPLACE ))
+ if (!WinHttpAddRequestHeaders( request->hrequest, str, len,
+ WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))
{
err = get_last_error();
}
static void wait_set_status_callback( struct winhttp_request *request, DWORD status )
{
- if (!request->wait) return;
status |= WINHTTP_CALLBACK_STATUS_REQUEST_ERROR;
WinHttpSetStatusCallback( request->hrequest, wait_status_callback, status, 0 );
}
static DWORD wait_for_completion( struct winhttp_request *request )
{
- HANDLE handles[2];
+ HANDLE handles[2] = { request->wait, request->cancel };
- if (!request->wait)
- {
- request->error = ERROR_SUCCESS;
- return ERROR_SUCCESS;
- }
- handles[0] = request->wait;
- handles[1] = request->cancel;
switch (WaitForMultipleObjects( 2, handles, FALSE, INFINITE ))
{
case WAIT_OBJECT_0:
return request_send_and_receive( request );
}
+/* critical section must be held */
+static DWORD request_wait( struct winhttp_request *request, DWORD timeout )
+{
+ HANDLE thread = request->thread;
+ DWORD err, ret;
+
+ LeaveCriticalSection( &request->cs );
+ while ((err = MsgWaitForMultipleObjects( 1, &thread, FALSE, timeout, QS_ALLINPUT )) == WAIT_OBJECT_0 + 1)
+ {
+ MSG msg;
+ while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage( &msg );
+ DispatchMessageW( &msg );
+ }
+ }
+ switch (err)
+ {
+ case WAIT_OBJECT_0:
+ ret = ERROR_SUCCESS;
+ break;
+ case WAIT_TIMEOUT:
+ ret = ERROR_TIMEOUT;
+ break;
+ case WAIT_FAILED:
+ default:
+ ret = get_last_error();
+ break;
+ }
+ EnterCriticalSection( &request->cs );
+ return ret;
+}
+
static HRESULT WINAPI winhttp_request_Send(
IWinHttpRequest *iface,
VARIANT body )
return S_OK;
}
VariantClear( &request->data );
- if ((hr = VariantCopyInd( &request->data, &body )) != S_OK) {
+ if ((hr = VariantCopyInd( &request->data, &body )) != S_OK)
+ {
LeaveCriticalSection( &request->cs );
return hr;
}
-
- if (request->wait) /* async request */
+ if (!(request->thread = CreateThread( NULL, 0, send_and_receive_proc, request, 0, NULL )))
{
- if (!(request->thread = CreateThread( NULL, 0, send_and_receive_proc, request, 0, NULL )))
- {
- LeaveCriticalSection( &request->cs );
- return HRESULT_FROM_WIN32( get_last_error() );
- }
+ LeaveCriticalSection( &request->cs );
+ return HRESULT_FROM_WIN32( get_last_error() );
+ }
+ request->wait = CreateEventW( NULL, FALSE, FALSE, NULL );
+ request->cancel = CreateEventW( NULL, FALSE, FALSE, NULL );
+ if (!request->async)
+ {
+ hr = HRESULT_FROM_WIN32( request_wait( request, INFINITE ) );
}
- else hr = request_send_and_receive( request );
LeaveCriticalSection( &request->cs );
return hr;
}
return hr;
}
-/* critical section must be held */
-static DWORD wait_for_response( struct winhttp_request *request, DWORD timeout )
-{
- HANDLE thread = request->thread;
- DWORD err, ret;
-
- LeaveCriticalSection( &request->cs );
- while ((err = MsgWaitForMultipleObjects( 1, &thread, FALSE, timeout, QS_ALLINPUT )) == WAIT_OBJECT_0 + 1)
- {
- MSG msg;
- while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ))
- {
- TranslateMessage( &msg );
- DispatchMessageW( &msg );
- }
- }
- switch (err)
- {
- case WAIT_OBJECT_0:
- ret = ERROR_SUCCESS;
- break;
- case WAIT_TIMEOUT:
- ret = ERROR_TIMEOUT;
- break;
- case WAIT_FAILED:
- default:
- ret = get_last_error();
- break;
- }
- EnterCriticalSection( &request->cs );
- return ret;
-}
-
static HRESULT WINAPI winhttp_request_WaitForResponse(
IWinHttpRequest *iface,
VARIANT timeout,
TRACE("%p, %s, %p\n", request, debugstr_variant(&timeout), succeeded);
EnterCriticalSection( &request->cs );
- if (!request->thread)
- {
- LeaveCriticalSection( &request->cs );
- return S_OK;
- }
if (request->state >= REQUEST_STATE_RESPONSE_RECEIVED)
{
LeaveCriticalSection( &request->cs );
return S_OK;
}
- switch ((err = wait_for_response( request, msecs )))
+ switch ((err = request_wait( request, msecs )))
{
case ERROR_TIMEOUT:
if (succeeded) *succeeded = VARIANT_FALSE;