Hans Leidekker : winhttp: Handle Passport redirects.
Alexandre Julliard
julliard at winehq.org
Fri Aug 2 14:26:31 CDT 2019
Module: wine
Branch: master
Commit: d6a80a4833123fc8e051907ed059f47bb386d4a7
URL: https://source.winehq.org/git/wine.git/?a=commit;h=d6a80a4833123fc8e051907ed059f47bb386d4a7
Author: Hans Leidekker <hans at codeweavers.com>
Date: Fri Aug 2 11:01:37 2019 +0200
winhttp: Handle Passport redirects.
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/winhttp/request.c | 46 +++++++++++++++++++++++--
dlls/winhttp/session.c | 2 +-
dlls/winhttp/tests/winhttp.c | 77 ++++++++++++++++++++++++++++++++++++++++++
dlls/winhttp/winhttp_private.h | 1 +
4 files changed, 122 insertions(+), 4 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 0e54168..175837d 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -873,7 +873,7 @@ static enum auth_scheme scheme_from_flag( DWORD flag )
return SCHEME_INVALID;
}
-static DWORD auth_scheme_from_header( WCHAR *header )
+static DWORD auth_scheme_from_header( const WCHAR *header )
{
unsigned int i;
@@ -2628,7 +2628,7 @@ static WCHAR *get_redirect_url( struct request *request, DWORD *len )
WCHAR *ret;
query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL );
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
if (!(ret = heap_alloc( size ))) return NULL;
*len = size / sizeof(WCHAR) - 1;
if (query_headers( request, WINHTTP_QUERY_LOCATION, NULL, ret, &size, NULL )) return ret;
@@ -2747,6 +2747,42 @@ end:
return ret;
}
+static BOOL is_passport_request( struct request *request )
+{
+ static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t','1','.','4'};
+ WCHAR buf[1024];
+ DWORD len = ARRAY_SIZE(buf);
+
+ if (!(request->connect->session->passport_flags & WINHTTP_ENABLE_PASSPORT_AUTH) ||
+ !query_headers( request, WINHTTP_QUERY_WWW_AUTHENTICATE, NULL, buf, &len, NULL )) return FALSE;
+
+ if (!strncmpiW( buf, passportW, ARRAY_SIZE(passportW) ) &&
+ (buf[ARRAY_SIZE(passportW)] == ' ' || !buf[ARRAY_SIZE(passportW)])) return TRUE;
+
+ return FALSE;
+}
+
+static BOOL handle_passport_redirect( struct request *request )
+{
+ static const WCHAR status401W[] = {'4','0','1',0};
+ DWORD flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE;
+ int i, len = strlenW( request->raw_headers );
+ WCHAR *p = request->raw_headers;
+
+ if (!process_header( request, attr_status, status401W, flags, FALSE )) return FALSE;
+
+ for (i = 0; i < len; i++)
+ {
+ if (i <= len - 3 && p[i] == '3' && p[i + 1] == '0' && p[i + 2] == '2')
+ {
+ p[i] = '4';
+ p[i + 2] = '1';
+ break;
+ }
+ }
+ return TRUE;
+}
+
static BOOL receive_response( struct request *request, BOOL async )
{
BOOL ret;
@@ -2774,7 +2810,11 @@ static BOOL receive_response( struct request *request, BOOL async )
if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request );
- if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB)
+ if (status == HTTP_STATUS_REDIRECT && is_passport_request( request ))
+ {
+ ret = handle_passport_redirect( request );
+ }
+ else if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB)
{
if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS ||
request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) break;
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index 239b86b..ef4bb17 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -210,7 +210,7 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b
return TRUE;
case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
- FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
+ session->passport_flags = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index 5849257..b075638 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -2236,6 +2236,13 @@ static const char largeauth[] =
"Content-Type: text/plain\r\n"
"\r\n";
+static const char passportauth[] =
+"HTTP/1.1 302 Found\r\n"
+"Content-Length: 0\r\n"
+"Location: /\r\n"
+"WWW-Authenticate: Passport1.4\r\n"
+"\r\n";
+
static const char unauthorized[] = "Unauthorized";
static const char hello_world[] = "Hello World";
static const char auth_unseen[] = "Auth Unseen";
@@ -2415,6 +2422,10 @@ static DWORD CALLBACK server_thread(LPVOID param)
}
else send(c, notokmsg, sizeof(notokmsg) - 1, 0);
}
+ else if (strstr(buffer, "GET /passport"))
+ {
+ send(c, passportauth, sizeof(passportauth) - 1, 0);
+ }
if (strstr(buffer, "GET /quit"))
{
send(c, okmsg, sizeof okmsg - 1, 0);
@@ -3518,6 +3529,71 @@ static void test_connection_info( int port )
WinHttpCloseHandle( ses );
}
+static void test_passport_auth( int port )
+{
+ static const WCHAR passportW[] =
+ {'/','p','a','s','s','p','o','r','t',0};
+ static const WCHAR foundW[] =
+ {'F','o','u','n','d',0};
+ static const WCHAR unauthorizedW[] =
+ {'U','n','a','u','t','h','o','r','i','z','e','d',0};
+ static const WCHAR headersW[] =
+ {'H','T','T','P','/','1','.','1',' ','4','0','1',' ','F','o','u','n','d','\r','\n',
+ 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','0','\r','\n',
+ 'L','o','c','a','t','i','o','n',':',' ','/','\r','\n',
+ 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',':',' ',
+ 'P','a','s','s','p','o','r','t','1','.','4','\r','\n','\r','\n',0};
+ HINTERNET ses, con, req;
+ DWORD status, size, option;
+ WCHAR buf[128];
+ BOOL ret;
+
+ ses = WinHttpOpen( test_useragent, 0, NULL, NULL, 0 );
+ ok( ses != NULL, "got %u\n", GetLastError() );
+
+ option = WINHTTP_ENABLE_PASSPORT_AUTH;
+ ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH, &option, sizeof(option) );
+ ok( ret, "got %u\n", GetLastError() );
+
+ con = WinHttpConnect( ses, localhostW, port, 0 );
+ ok( con != NULL, "got %u\n", GetLastError() );
+
+ req = WinHttpOpenRequest( con, NULL, passportW, NULL, NULL, NULL, 0 );
+ ok( req != NULL, "got %u\n", GetLastError() );
+
+ ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
+ ok( ret, "got %u\n", GetLastError() );
+
+ ret = WinHttpReceiveResponse( req, NULL );
+ ok( ret, "got %u\n", GetLastError() );
+
+ status = 0xdeadbeef;
+ size = sizeof(status);
+ ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
+ ok( ret, "got %u\n", GetLastError() );
+ ok( status == HTTP_STATUS_DENIED, "got %u\n", status );
+
+ buf[0] = 0;
+ size = sizeof(buf);
+ ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_TEXT, NULL, buf, &size, NULL );
+ ok( ret, "got %u\n", GetLastError() );
+ ok( !lstrcmpW(foundW, buf) || broken(!lstrcmpW(unauthorizedW, buf)) /* < win7 */, "got %s\n", wine_dbgstr_w(buf) );
+
+ buf[0] = 0;
+ size = sizeof(buf);
+ ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, buf, &size, NULL );
+ ok( ret || broken(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) /* < win7 */, "got %u\n", GetLastError() );
+ if (ret)
+ {
+ ok( size == lstrlenW(headersW) * sizeof(WCHAR), "got %u\n", size );
+ ok( !lstrcmpW(headersW, buf), "got %s\n", wine_dbgstr_w(buf) );
+ }
+
+ WinHttpCloseHandle( req );
+ WinHttpCloseHandle( con );
+ WinHttpCloseHandle( ses );
+}
+
static void test_credentials(void)
{
static WCHAR userW[] = {'u','s','e','r',0};
@@ -4783,6 +4859,7 @@ START_TEST (winhttp)
test_multiple_reads(si.port);
test_cookies(si.port);
test_request_path_escapes(si.port);
+ test_passport_auth(si.port);
/* send the basic request again to shutdown the server thread */
test_basic_request(si.port, NULL, quitW);
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 38e39cb..93cf0f7 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -93,6 +93,7 @@ struct session
struct list cookie_cache;
HANDLE unload_event;
DWORD secure_protocols;
+ DWORD passport_flags;
};
struct connect
More information about the wine-cvs
mailing list