winhttp: Handle redirects.
This commit is contained in:
parent
8063f5cbd4
commit
41a763629f
|
@ -932,6 +932,108 @@ end:
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL handle_redirect( request_t *request )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
DWORD size, len;
|
||||
URL_COMPONENTS uc;
|
||||
connect_t *connect = request->connect;
|
||||
INTERNET_PORT port;
|
||||
WCHAR *hostname = NULL, *location = NULL;
|
||||
|
||||
size = 0;
|
||||
query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL );
|
||||
if (!(location = heap_alloc( size ))) return FALSE;
|
||||
if (!query_headers( request, WINHTTP_QUERY_LOCATION, NULL, location, &size, NULL )) goto end;
|
||||
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, size / sizeof(WCHAR) + 1 );
|
||||
|
||||
memset( &uc, 0, sizeof(uc) );
|
||||
uc.dwStructSize = sizeof(uc);
|
||||
uc.dwSchemeLength = uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = ~0UL;
|
||||
|
||||
if (!(ret = WinHttpCrackUrl( location, size / sizeof(WCHAR), 0, &uc ))) goto end;
|
||||
|
||||
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->servername );
|
||||
connect->servername = hostname;
|
||||
connect->serverport = port;
|
||||
|
||||
netconn_close( &request->netconn );
|
||||
if (!(ret = netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE ))) goto end;
|
||||
}
|
||||
if (!(ret = process_header( request, attr_host, hostname, WINHTTP_ADDREQ_FLAG_REPLACE, TRUE ))) 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 );
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
end:
|
||||
if (!ret) heap_free( hostname );
|
||||
heap_free( location );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
|
||||
{
|
||||
DWORD to_read;
|
||||
int bytes_read;
|
||||
|
||||
to_read = min( size, request->content_length - request->content_read );
|
||||
if (!netconn_recv( &request->netconn, buffer, to_read, async ? 0 : MSG_WAITALL, &bytes_read ))
|
||||
{
|
||||
if (bytes_read != to_read)
|
||||
{
|
||||
ERR("not all data received %d/%d\n", bytes_read, to_read);
|
||||
}
|
||||
/* always return success, even if the network layer returns an error */
|
||||
*read = 0;
|
||||
return TRUE;
|
||||
}
|
||||
request->content_read += bytes_read;
|
||||
*read = bytes_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.@)
|
||||
*/
|
||||
|
@ -939,7 +1041,7 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
|
|||
{
|
||||
BOOL ret = TRUE;
|
||||
request_t *request;
|
||||
DWORD size, query;
|
||||
DWORD size, query, status;
|
||||
|
||||
TRACE("%p, %p\n", hrequest, reserved);
|
||||
|
||||
|
@ -955,12 +1057,28 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ret = receive_response( request, TRUE );
|
||||
for (;;)
|
||||
{
|
||||
if (!(ret = receive_response( request, TRUE ))) 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;
|
||||
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.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;
|
||||
|
@ -994,27 +1112,6 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
|
||||
{
|
||||
DWORD to_read;
|
||||
int bytes_read;
|
||||
|
||||
to_read = min( size, request->content_length - request->content_read );
|
||||
if (!netconn_recv( &request->netconn, buffer, to_read, async ? 0 : MSG_WAITALL, &bytes_read ))
|
||||
{
|
||||
if (bytes_read != to_read)
|
||||
{
|
||||
ERR("not all data received %d/%d\n", bytes_read, to_read);
|
||||
}
|
||||
/* always return success, even if the network layer returns an error */
|
||||
*read = 0;
|
||||
return TRUE;
|
||||
}
|
||||
request->content_read += bytes_read;
|
||||
*read = bytes_read;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD get_chunk_size( const char *buffer )
|
||||
{
|
||||
const char *p;
|
||||
|
|
|
@ -532,7 +532,7 @@ static void test_secure_connection(void)
|
|||
static const WCHAR google[] = {'w','w','w','.','g','o','o','g','l','e','.','c','o','m',0};
|
||||
|
||||
HANDLE ses, con, req;
|
||||
DWORD size;
|
||||
DWORD size, status;
|
||||
BOOL ret;
|
||||
|
||||
ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
|
||||
|
@ -566,6 +566,10 @@ static void test_secure_connection(void)
|
|||
ret = WinHttpReceiveResponse(req, NULL);
|
||||
ok(ret, "failed to receive response %u\n", GetLastError());
|
||||
|
||||
size = sizeof(status);
|
||||
ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
|
||||
ok(ret, "failed unexpectedly %u\n", GetLastError());
|
||||
|
||||
size = 0;
|
||||
ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL);
|
||||
ok(!ret, "succeeded unexpectedly\n");
|
||||
|
@ -581,6 +585,7 @@ static void test_request_parameter_defaults(void)
|
|||
static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
|
||||
|
||||
HANDLE ses, con, req;
|
||||
DWORD size, status;
|
||||
BOOL ret;
|
||||
|
||||
ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
|
||||
|
@ -598,6 +603,11 @@ static void test_request_parameter_defaults(void)
|
|||
ret = WinHttpReceiveResponse(req, NULL);
|
||||
ok(ret, "failed to receive response %u\n", GetLastError());
|
||||
|
||||
size = sizeof(status);
|
||||
ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
|
||||
ok(ret, "failed unexpectedly %u\n", GetLastError());
|
||||
ok(status == 200, "request failed unexpectedly %u\n", status);
|
||||
|
||||
WinHttpCloseHandle(req);
|
||||
|
||||
req = WinHttpOpenRequest(con, empty, empty, empty, NULL, NULL, 0);
|
||||
|
@ -609,6 +619,11 @@ static void test_request_parameter_defaults(void)
|
|||
ret = WinHttpReceiveResponse(req, NULL);
|
||||
ok(ret, "failed to receive response %u\n", GetLastError());
|
||||
|
||||
size = sizeof(status);
|
||||
ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
|
||||
ok(ret, "failed unexpectedly %u\n", GetLastError());
|
||||
ok(status == 200, "request failed unexpectedly %u\n", status);
|
||||
|
||||
WinHttpCloseHandle(req);
|
||||
WinHttpCloseHandle(con);
|
||||
WinHttpCloseHandle(ses);
|
||||
|
|
Loading…
Reference in New Issue