Hans Leidekker : winhttp: Handle redirects.
Alexandre Julliard
julliard at winehq.org
Wed Sep 3 07:44:04 CDT 2008
Module: wine
Branch: master
Commit: 41a763629f3150e5bcdf878e7d08554c50ef0f89
URL: http://source.winehq.org/git/wine.git/?a=commit;h=41a763629f3150e5bcdf878e7d08554c50ef0f89
Author: Hans Leidekker <hans at codeweavers.com>
Date: Wed Sep 3 12:31:09 2008 +0200
winhttp: Handle redirects.
---
dlls/winhttp/request.c | 151 ++++++++++++++++++++++++++++++++++--------
dlls/winhttp/tests/winhttp.c | 17 +++++-
2 files changed, 140 insertions(+), 28 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 66d2abd..9a273fa 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -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_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;
+ 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;
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index 3e963ac..5b3bd38 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -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);
More information about the wine-cvs
mailing list