[WINHTTP]
authorAmine Khaldi <amine.khaldi@reactos.org>
Tue, 21 May 2013 20:06:46 +0000 (20:06 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Tue, 21 May 2013 20:06:46 +0000 (20:06 +0000)
* Sync with Wine 1.5.26.
* Update winhttp_ros.diff.
[PSDK]
* Update winhttp.h.

svn path=/trunk/; revision=59064

reactos/dll/win32/winhttp/CMakeLists.txt
reactos/dll/win32/winhttp/net.c
reactos/dll/win32/winhttp/pac.js
reactos/dll/win32/winhttp/request.c
reactos/dll/win32/winhttp/session.c
reactos/dll/win32/winhttp/winhttp_private.h
reactos/dll/win32/winhttp/winhttp_ros.diff
reactos/include/psdk/winhttp.h
reactos/media/doc/README.WINE

index 82e1976..e181796 100644 (file)
@@ -25,7 +25,7 @@ add_library(winhttp SHARED ${SOURCE})
 
 set_module_type(winhttp win32dll)
 target_link_libraries(winhttp uuid wine)
-add_delay_importlibs(winhttp oleaut32 ole32 crypt32)
+add_delay_importlibs(winhttp oleaut32 ole32 crypt32 secur32)
 add_importlibs(winhttp user32 advapi32 ws2_32 msvcrt kernel32 ntdll)
 
 # wininet_tlb.tlb needs stdole2.tlb
index 458312c..54d5c49 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2008 Hans Leidekker for CodeWeavers
+ * Copyright 2013 Jacek Caban for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #define COM_NO_WINDOWS_H
 
 #include <config.h>
-//#include "wine/port.h"
+//#include <wine/port.h>
 
 //#include <stdarg.h>
 //#include <stdio.h>
 //#include <errno.h>
+#include <assert.h>
 
 //#include <sys/types.h>
 #ifdef HAVE_SYS_SOCKET_H
 #ifdef HAVE_POLL_H
 # include <poll.h>
 #endif
-#ifdef HAVE_OPENSSL_SSL_H
-# include <openssl/ssl.h>
-# include <openssl/opensslv.h>
-#undef FAR
-#undef DSA
-#endif
 
 #define NONAMELESSUNION
 
@@ -56,6 +52,7 @@
 //#include "winbase.h"
 #include <winhttp.h>
 //#include "wincrypt.h"
+#include <schannel.h>
 
 #include "winhttp_private.h"
 
@@ -79,90 +76,6 @@ static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 #endif
 
-#ifdef SONAME_LIBSSL
-
-#include <openssl/err.h>
-
-static CRITICAL_SECTION init_ssl_cs;
-static CRITICAL_SECTION_DEBUG init_ssl_cs_debug =
-{
-    0, 0, &init_ssl_cs,
-    { &init_ssl_cs_debug.ProcessLocksList,
-      &init_ssl_cs_debug.ProcessLocksList },
-    0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") }
-};
-static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 };
-
-static void *libssl_handle;
-static void *libcrypto_handle;
-
-#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER > 0x10000000)
-static const SSL_METHOD *method;
-#else
-static SSL_METHOD *method;
-#endif
-static SSL_CTX *ctx;
-static int hostname_idx;
-static int error_idx;
-static int conn_idx;
-
-#define MAKE_FUNCPTR(f) static typeof(f) * p##f
-
-MAKE_FUNCPTR( SSL_library_init );
-MAKE_FUNCPTR( SSL_load_error_strings );
-MAKE_FUNCPTR( SSLv23_method );
-MAKE_FUNCPTR( SSL_CTX_free );
-MAKE_FUNCPTR( SSL_CTX_new );
-MAKE_FUNCPTR( SSL_new );
-MAKE_FUNCPTR( SSL_free );
-MAKE_FUNCPTR( SSL_set_fd );
-MAKE_FUNCPTR( SSL_connect );
-MAKE_FUNCPTR( SSL_shutdown );
-MAKE_FUNCPTR( SSL_write );
-MAKE_FUNCPTR( SSL_read );
-MAKE_FUNCPTR( SSL_pending );
-MAKE_FUNCPTR( SSL_get_error );
-MAKE_FUNCPTR( SSL_get_ex_new_index );
-MAKE_FUNCPTR( SSL_get_ex_data );
-MAKE_FUNCPTR( SSL_set_ex_data );
-MAKE_FUNCPTR( SSL_get_ex_data_X509_STORE_CTX_idx );
-MAKE_FUNCPTR( SSL_get_peer_certificate );
-MAKE_FUNCPTR( SSL_CTX_set_default_verify_paths );
-MAKE_FUNCPTR( SSL_CTX_set_verify );
-MAKE_FUNCPTR( SSL_get_current_cipher );
-MAKE_FUNCPTR( SSL_CIPHER_get_bits );
-
-MAKE_FUNCPTR( CRYPTO_num_locks );
-MAKE_FUNCPTR( CRYPTO_set_id_callback );
-MAKE_FUNCPTR( CRYPTO_set_locking_callback );
-MAKE_FUNCPTR( ERR_free_strings );
-MAKE_FUNCPTR( ERR_get_error );
-MAKE_FUNCPTR( ERR_error_string );
-MAKE_FUNCPTR( X509_STORE_CTX_get_ex_data );
-MAKE_FUNCPTR( X509_STORE_CTX_get_chain );
-MAKE_FUNCPTR( i2d_X509 );
-MAKE_FUNCPTR( sk_value );
-MAKE_FUNCPTR( sk_num );
-#undef MAKE_FUNCPTR
-
-static CRITICAL_SECTION *ssl_locks;
-static unsigned int num_ssl_locks;
-
-static unsigned long ssl_thread_id(void)
-{
-    return GetCurrentThreadId();
-}
-
-static void ssl_lock_callback(int mode, int type, const char *file, int line)
-{
-    if (mode & CRYPTO_LOCK)
-        EnterCriticalSection( &ssl_locks[type] );
-    else
-        LeaveCriticalSection( &ssl_locks[type] );
-}
-
-#endif
-
 /* translate a unix error code into a winsock error code */
 #ifndef __REACTOS__
 static int sock_get_error( int err )
@@ -240,45 +153,9 @@ static inline int unix_ioctl(int filedes, long request, void *arg)
 #define ioctlsocket unix_ioctl
 #endif
 
-#ifdef SONAME_LIBSSL
-static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
-{
-    unsigned char *buffer, *p;
-    int len;
-    BOOL malloc = FALSE;
-    PCCERT_CONTEXT ret;
-
-    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;
-}
-
-static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store,
-                                  WCHAR *server, DWORD security_flags )
+static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD security_flags )
 {
+    HCERTSTORE store = cert->hCertStore;
     BOOL ret;
     CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
     PCCERT_CHAIN_CONTEXT chain;
@@ -369,234 +246,53 @@ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store,
     return err;
 }
 
-static int netconn_secure_verify( int preverify_ok, X509_STORE_CTX *ctx )
+static SecHandle cred_handle;
+static BOOL cred_handle_initialized;
+
+static CRITICAL_SECTION init_sechandle_cs;
+static CRITICAL_SECTION_DEBUG init_sechandle_cs_debug = {
+    0, 0, &init_sechandle_cs,
+    { &init_sechandle_cs_debug.ProcessLocksList,
+      &init_sechandle_cs_debug.ProcessLocksList },
+    0, 0, { (DWORD_PTR)(__FILE__ ": init_sechandle_cs") }
+};
+static CRITICAL_SECTION init_sechandle_cs = { &init_sechandle_cs_debug, -1, 0, 0, 0, 0 };
+
+static BOOL ensure_cred_handle(void)
 {
-    SSL *ssl;
-    WCHAR *server;
-    BOOL ret = FALSE;
-    netconn_t *conn;
-    HCERTSTORE store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0,
-     CERT_STORE_CREATE_NEW_FLAG, NULL );
-
-    ssl = pX509_STORE_CTX_get_ex_data( ctx, pSSL_get_ex_data_X509_STORE_CTX_idx() );
-    server = pSSL_get_ex_data( ssl, hostname_idx );
-    conn = pSSL_get_ex_data( ssl, conn_idx );
-    if (store)
-    {
-        X509 *cert;
-        int i;
-        PCCERT_CONTEXT endCert = NULL;
-        struct stack_st *chain = (struct stack_st *)pX509_STORE_CTX_get_chain( ctx );
+    BOOL ret = TRUE;
 
-        ret = TRUE;
-        for (i = 0; ret && i < psk_num(chain); i++)
-        {
-            PCCERT_CONTEXT context;
+    EnterCriticalSection(&init_sechandle_cs);
 
-            cert = (X509 *)psk_value(chain, i);
-            if ((context = X509_to_cert_context( cert )))
-            {
-                if (i == 0)
-                    ret = CertAddCertificateContextToStore( store, context,
-                        CERT_STORE_ADD_ALWAYS, &endCert );
-                else
-                    ret = CertAddCertificateContextToStore( store, context,
-                        CERT_STORE_ADD_ALWAYS, NULL );
-                CertFreeCertificateContext( context );
-            }
-        }
-        if (!endCert) ret = FALSE;
-        if (ret)
-        {
-            DWORD_PTR err = netconn_verify_cert( endCert, store, server,
-                                                 conn->security_flags );
+    if(!cred_handle_initialized) {
+        SECURITY_STATUS res;
 
-            if (err)
-            {
-                pSSL_set_ex_data( ssl, error_idx, (void *)err );
-                ret = FALSE;
-            }
+        res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, NULL,
+                NULL, NULL, &cred_handle, NULL);
+        if(res == SEC_E_OK) {
+            cred_handle_initialized = TRUE;
+        }else {
+            WARN("AcquireCredentialsHandleW failed: %u\n", res);
+            ret = FALSE;
         }
-        CertFreeCertificateContext( endCert );
-        CertCloseStore( store, 0 );
     }
+
+    LeaveCriticalSection(&init_sechandle_cs);
     return ret;
 }
-#endif
 
-BOOL netconn_init( netconn_t *conn, BOOL secure )
+BOOL netconn_init( netconn_t *conn )
 {
-#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
-    int i;
-#endif
-
+    memset(conn, 0, sizeof(*conn));
     conn->socket = -1;
-    if (!secure) return TRUE;
-
-#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
-    EnterCriticalSection( &init_ssl_cs );
-    if (libssl_handle)
-    {
-        LeaveCriticalSection( &init_ssl_cs );
-        return TRUE;
-    }
-    if (!(libssl_handle = wine_dlopen( SONAME_LIBSSL, RTLD_NOW, NULL, 0 )))
-    {
-        ERR("Trying to use SSL but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL);
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-    if (!(libcrypto_handle = wine_dlopen( SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0 )))
-    {
-        ERR("Trying to use SSL but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO);
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-#define LOAD_FUNCPTR(x) \
-    if (!(p##x = wine_dlsym( libssl_handle, #x, NULL, 0 ))) \
-    { \
-        ERR("Failed to load symbol %s\n", #x); \
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \
-        LeaveCriticalSection( &init_ssl_cs ); \
-        return FALSE; \
-    }
-    LOAD_FUNCPTR( SSL_library_init );
-    LOAD_FUNCPTR( SSL_load_error_strings );
-    LOAD_FUNCPTR( SSLv23_method );
-    LOAD_FUNCPTR( SSL_CTX_free );
-    LOAD_FUNCPTR( SSL_CTX_new );
-    LOAD_FUNCPTR( SSL_new );
-    LOAD_FUNCPTR( SSL_free );
-    LOAD_FUNCPTR( SSL_set_fd );
-    LOAD_FUNCPTR( SSL_connect );
-    LOAD_FUNCPTR( SSL_shutdown );
-    LOAD_FUNCPTR( SSL_write );
-    LOAD_FUNCPTR( SSL_read );
-    LOAD_FUNCPTR( SSL_pending );
-    LOAD_FUNCPTR( SSL_get_error );
-    LOAD_FUNCPTR( SSL_get_ex_new_index );
-    LOAD_FUNCPTR( SSL_get_ex_data );
-    LOAD_FUNCPTR( SSL_set_ex_data );
-    LOAD_FUNCPTR( SSL_get_ex_data_X509_STORE_CTX_idx );
-    LOAD_FUNCPTR( SSL_get_peer_certificate );
-    LOAD_FUNCPTR( SSL_CTX_set_default_verify_paths );
-    LOAD_FUNCPTR( SSL_CTX_set_verify );
-    LOAD_FUNCPTR( SSL_get_current_cipher );
-    LOAD_FUNCPTR( SSL_CIPHER_get_bits );
-#undef LOAD_FUNCPTR
-
-#define LOAD_FUNCPTR(x) \
-    if (!(p##x = wine_dlsym( libcrypto_handle, #x, NULL, 0 ))) \
-    { \
-        ERR("Failed to load symbol %s\n", #x); \
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \
-        LeaveCriticalSection( &init_ssl_cs ); \
-        return FALSE; \
-    }
-    LOAD_FUNCPTR( CRYPTO_num_locks );
-    LOAD_FUNCPTR( CRYPTO_set_id_callback );
-    LOAD_FUNCPTR( CRYPTO_set_locking_callback );
-    LOAD_FUNCPTR( ERR_free_strings );
-    LOAD_FUNCPTR( ERR_get_error );
-    LOAD_FUNCPTR( ERR_error_string );
-    LOAD_FUNCPTR( X509_STORE_CTX_get_ex_data );
-    LOAD_FUNCPTR( X509_STORE_CTX_get_chain );
-    LOAD_FUNCPTR( i2d_X509 );
-    LOAD_FUNCPTR( sk_value );
-    LOAD_FUNCPTR( sk_num );
-#undef LOAD_FUNCPTR
-
-    pSSL_library_init();
-    pSSL_load_error_strings();
-
-    method = pSSLv23_method();
-    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 );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-    hostname_idx = pSSL_get_ex_new_index( 0, (void *)"hostname index", NULL, NULL, NULL );
-    if (hostname_idx == -1)
-    {
-        ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
-        set_last_error( ERROR_OUTOFMEMORY );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-    error_idx = pSSL_get_ex_new_index( 0, (void *)"error index", NULL, NULL, NULL );
-    if (error_idx == -1)
-    {
-        ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
-        set_last_error( ERROR_OUTOFMEMORY );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-    conn_idx = pSSL_get_ex_new_index( 0, (void *)"netconn index", NULL, NULL, NULL );
-    if (conn_idx == -1)
-    {
-        ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
-        set_last_error( ERROR_OUTOFMEMORY );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-    pSSL_CTX_set_verify( ctx, SSL_VERIFY_PEER, netconn_secure_verify );
-
-    pCRYPTO_set_id_callback(ssl_thread_id);
-    num_ssl_locks = pCRYPTO_num_locks();
-    ssl_locks = heap_alloc(num_ssl_locks * sizeof(CRITICAL_SECTION));
-    if (!ssl_locks)
-    {
-        set_last_error( ERROR_OUTOFMEMORY );
-        LeaveCriticalSection( &init_ssl_cs );
-        return FALSE;
-    }
-    for (i = 0; i < num_ssl_locks; i++)
-    {
-        InitializeCriticalSection( &ssl_locks[i] );
-        ssl_locks[i].DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ssl_locks");
-    }
-    pCRYPTO_set_locking_callback(ssl_lock_callback);
-
-    LeaveCriticalSection( &init_ssl_cs );
-#else
-    WARN("SSL support not compiled in.\n");
-    set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
-    return FALSE;
-#endif
     return TRUE;
 }
 
 void netconn_unload( void )
 {
-#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
-    if (libcrypto_handle)
-    {
-        pERR_free_strings();
-        wine_dlclose( libcrypto_handle, NULL, 0 );
-    }
-    if (libssl_handle)
-    {
-        if (ctx)
-            pSSL_CTX_free( ctx );
-        wine_dlclose( libssl_handle, NULL, 0 );
-    }
-    if (ssl_locks)
-    {
-        int i;
-        for (i = 0; i < num_ssl_locks; i++)
-        {
-            ssl_locks[i].DebugInfo->Spare[0] = 0;
-            DeleteCriticalSection( &ssl_locks[i] );
-        }
-        heap_free( ssl_locks );
-    }
-    DeleteCriticalSection(&init_ssl_cs);
-#endif
+    if(cred_handle_initialized)
+        FreeCredentialsHandle(&cred_handle);
+    DeleteCriticalSection(&init_sechandle_cs);
 #ifndef HAVE_GETADDRINFO
     DeleteCriticalSection(&cs_gethostbyname);
 #endif
@@ -622,21 +318,20 @@ BOOL netconn_close( netconn_t *conn )
 {
     int res;
 
-#ifdef SONAME_LIBSSL
     if (conn->secure)
     {
         heap_free( conn->peek_msg_mem );
         conn->peek_msg_mem = NULL;
         conn->peek_msg = NULL;
         conn->peek_len = 0;
-
-        pSSL_shutdown( conn->ssl_conn );
-        pSSL_free( conn->ssl_conn );
-
-        conn->ssl_conn = NULL;
+        heap_free(conn->ssl_buf);
+        conn->ssl_buf = NULL;
+        heap_free(conn->extra_buf);
+        conn->extra_buf = NULL;
+        conn->extra_len = 0;
+        DeleteSecurityContext(&conn->ssl_ctx);
         conn->secure = FALSE;
     }
-#endif
     res = closesocket( conn->socket );
     conn->socket = -1;
     if (res == -1)
@@ -650,7 +345,8 @@ BOOL netconn_close( netconn_t *conn )
 BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len, int timeout )
 {
     BOOL ret = FALSE;
-    int res = 0, state;
+    int res = 0;
+    ULONG state;
 
     if (timeout > 0)
     {
@@ -695,54 +391,164 @@ BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned
 
 BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname )
 {
-#ifdef SONAME_LIBSSL
-    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 );
-        goto fail;
-    }
-    if (!pSSL_set_ex_data( conn->ssl_conn, hostname_idx, hostname ))
-    {
-        ERR("SSL_set_ex_data failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
-        goto fail;
-    }
-    if (!pSSL_set_ex_data( conn->ssl_conn, conn_idx, conn ))
-    {
-        ERR("SSL_set_ex_data failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
+    SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}};
+    SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs};
+    BYTE *read_buf;
+    SIZE_T read_buf_size = 2048;
+    ULONG attrs = 0;
+    CtxtHandle ctx;
+    SSIZE_T size;
+    const CERT_CONTEXT *cert;
+    SECURITY_STATUS status;
+    DWORD res = ERROR_SUCCESS;
+
+    const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY
+        |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION;
+
+    if(!ensure_cred_handle())
         return FALSE;
+
+    read_buf = heap_alloc(read_buf_size);
+    if(!read_buf)
+        return FALSE;
+
+    status = InitializeSecurityContextW(&cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0,
+            &ctx, &out_desc, &attrs, NULL);
+
+    assert(status != SEC_E_OK);
+
+    while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) {
+        if(out_buf.cbBuffer) {
+            assert(status == SEC_I_CONTINUE_NEEDED);
+
+            TRACE("sending %u bytes\n", out_buf.cbBuffer);
+
+            size = send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
+            if(size != out_buf.cbBuffer) {
+                ERR("send failed\n");
+                status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
+                break;
+            }
+
+            FreeContextBuffer(out_buf.pvBuffer);
+            out_buf.pvBuffer = NULL;
+            out_buf.cbBuffer = 0;
+        }
+
+        if(status == SEC_I_CONTINUE_NEEDED) {
+            assert(in_bufs[1].cbBuffer < read_buf_size);
+
+            memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer);
+            in_bufs[0].cbBuffer = in_bufs[1].cbBuffer;
+
+            in_bufs[1].BufferType = SECBUFFER_EMPTY;
+            in_bufs[1].cbBuffer = 0;
+            in_bufs[1].pvBuffer = NULL;
+        }
+
+        assert(in_bufs[0].BufferType == SECBUFFER_TOKEN);
+        assert(in_bufs[1].BufferType == SECBUFFER_EMPTY);
+
+        if(in_bufs[0].cbBuffer + 1024 > read_buf_size) {
+            BYTE *new_read_buf;
+
+            new_read_buf = heap_realloc(read_buf, read_buf_size + 1024);
+            if(!new_read_buf) {
+                status = E_OUTOFMEMORY;
+                break;
+            }
+
+            in_bufs[0].pvBuffer = read_buf = new_read_buf;
+            read_buf_size += 1024;
+        }
+
+        size = recv(conn->socket, (char *)(read_buf+in_bufs[0].cbBuffer), read_buf_size-in_bufs[0].cbBuffer, 0);
+        if(size < 1) {
+            WARN("recv error\n");
+            status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
+            break;
+        }
+
+        TRACE("recv %lu bytes\n", size);
+
+        in_bufs[0].cbBuffer += size;
+        in_bufs[0].pvBuffer = read_buf;
+        status = InitializeSecurityContextW(&cred_handle, &ctx, hostname,  isc_req_flags, 0, 0, &in_desc,
+                0, NULL, &out_desc, &attrs, NULL);
+        TRACE("InitializeSecurityContext ret %08x\n", status);
+
+        if(status == SEC_E_OK) {
+            if(in_bufs[1].BufferType == SECBUFFER_EXTRA)
+                FIXME("SECBUFFER_EXTRA not supported\n");
+
+            status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes);
+            if(status != SEC_E_OK) {
+                WARN("Could not get sizes\n");
+                break;
+            }
+
+            status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
+            if(status == SEC_E_OK) {
+                res = netconn_verify_cert(cert, hostname, conn->security_flags);
+                CertFreeCertificateContext(cert);
+                if(res != ERROR_SUCCESS) {
+                    WARN("cert verify failed: %u\n", res);
+                    break;
+                }
+            }else {
+                WARN("Could not get cert\n");
+                break;
+            }
+
+            conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
+            if(!conn->ssl_buf) {
+                res = GetLastError();
+                break;
+            }
+        }
     }
-    if (!pSSL_set_fd( conn->ssl_conn, conn->socket ))
-    {
-        ERR("SSL_set_fd failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
-        set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
-        goto fail;
-    }
-    if (pSSL_connect( conn->ssl_conn ) <= 0)
-    {
-        DWORD err;
 
-        err = (DWORD_PTR)pSSL_get_ex_data( conn->ssl_conn, error_idx );
-        if (!err) err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
-        ERR("couldn't verify server certificate (%d)\n", err);
-        set_last_error( err );
-        goto fail;
+
+    if(status != SEC_E_OK || res != ERROR_SUCCESS) {
+        WARN("Failed to initialize security context failed: %08x\n", status);
+        heap_free(conn->ssl_buf);
+        conn->ssl_buf = NULL;
+        DeleteSecurityContext(&ctx);
+        set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR);
+        return FALSE;
     }
+
+
     TRACE("established SSL connection\n");
     conn->secure = TRUE;
+    conn->ssl_ctx = ctx;
     return TRUE;
+}
 
-fail:
-    if (conn->ssl_conn)
-    {
-        pSSL_shutdown( conn->ssl_conn );
-        pSSL_free( conn->ssl_conn );
-        conn->ssl_conn = NULL;
+static BOOL send_ssl_chunk(netconn_t *conn, const void *msg, size_t size)
+{
+    SecBuffer bufs[4] = {
+        {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf},
+        {size,  SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader},
+        {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size},
+        {0, SECBUFFER_EMPTY, NULL}
+    };
+    SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
+    SECURITY_STATUS res;
+
+    memcpy(bufs[1].pvBuffer, msg, size);
+    res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0);
+    if(res != SEC_E_OK) {
+        WARN("EncryptMessage failed\n");
+        return FALSE;
     }
-#endif
-    return FALSE;
+
+    if(send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) {
+        WARN("send failed\n");
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int *sent )
@@ -750,14 +556,24 @@ BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int
     if (!netconn_connected( conn )) return FALSE;
     if (conn->secure)
     {
-#ifdef SONAME_LIBSSL
-        if (flags) FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
-        *sent = pSSL_write( conn->ssl_conn, msg, len );
-        if (*sent < 1 && len) return FALSE;
+        const BYTE *ptr = msg;
+        size_t chunk_size;
+
+        if (flags) FIXME("flags %08x not supported in SSL\n", flags);
+
+        *sent = 0;
+
+        while(len) {
+            chunk_size = min(len, conn->ssl_sizes.cbMaximumMessage);
+            if(!send_ssl_chunk(conn, ptr, chunk_size))
+                return FALSE;
+
+            *sent += chunk_size;
+            ptr += chunk_size;
+            len -= chunk_size;
+        }
+
         return TRUE;
-#else
-        return FALSE;
-#endif
     }
     if ((*sent = send( conn->socket, msg, len, flags )) == -1)
     {
@@ -767,6 +583,99 @@ BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int
     return TRUE;
 }
 
+static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof)
+{
+    const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer;
+    SecBuffer bufs[4];
+    SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
+    SSIZE_T size, buf_len;
+    unsigned int i;
+    SECURITY_STATUS res;
+
+    assert(conn->extra_len < ssl_buf_size);
+
+    if(conn->extra_len) {
+        memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len);
+        buf_len = conn->extra_len;
+        conn->extra_len = 0;
+        heap_free(conn->extra_buf);
+        conn->extra_buf = NULL;
+    }else {
+        buf_len = recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0);
+        if(buf_len < 0) {
+            WARN("recv failed\n");
+            return FALSE;
+        }
+
+        if(!buf_len) {
+            *eof = TRUE;
+            return TRUE;
+        }
+    }
+
+    *ret_size = 0;
+    *eof = FALSE;
+
+    do {
+        memset(bufs, 0, sizeof(bufs));
+        bufs[0].BufferType = SECBUFFER_DATA;
+        bufs[0].cbBuffer = buf_len;
+        bufs[0].pvBuffer = conn->ssl_buf;
+
+        res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL);
+        switch(res) {
+        case SEC_E_OK:
+            break;
+        case SEC_I_CONTEXT_EXPIRED:
+            TRACE("context expired\n");
+            *eof = TRUE;
+            return TRUE;
+        case SEC_E_INCOMPLETE_MESSAGE:
+            assert(buf_len < ssl_buf_size);
+
+            size = recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0);
+            if(size < 1)
+                return FALSE;
+
+            buf_len += size;
+            continue;
+        default:
+            WARN("failed: %08x\n", res);
+            return FALSE;
+        }
+    } while(res != SEC_E_OK);
+
+    for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
+        if(bufs[i].BufferType == SECBUFFER_DATA) {
+            size = min(buf_size, bufs[i].cbBuffer);
+            memcpy(buf, bufs[i].pvBuffer, size);
+            if(size < bufs[i].cbBuffer) {
+                assert(!conn->peek_len);
+                conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size);
+                if(!conn->peek_msg)
+                    return FALSE;
+                conn->peek_len = bufs[i].cbBuffer-size;
+                memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len);
+            }
+
+            *ret_size = size;
+        }
+    }
+
+    for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
+        if(bufs[i].BufferType == SECBUFFER_EXTRA) {
+            conn->extra_buf = heap_alloc(bufs[i].cbBuffer);
+            if(!conn->extra_buf)
+                return FALSE;
+
+            conn->extra_len = bufs[i].cbBuffer;
+            memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len);
+        }
+    }
+
+    return TRUE;
+}
+
 BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
 {
     *recvd = 0;
@@ -775,18 +684,13 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd
 
     if (conn->secure)
     {
-#ifdef SONAME_LIBSSL
-        int ret;
+        SIZE_T size, cread;
+        BOOL res, eof;
 
         if (flags & ~(MSG_PEEK | MSG_WAITALL))
             FIXME("SSL_read does not support the following flags: %08x\n", flags);
 
-        /* this ugly hack is all for MSG_PEEK */
-        if (flags & MSG_PEEK && !conn->peek_msg)
-        {
-            if (!(conn->peek_msg = conn->peek_msg_mem = heap_alloc( len + 1 ))) return FALSE;
-        }
-        else if (flags & MSG_PEEK && conn->peek_msg)
+        if (flags & MSG_PEEK && conn->peek_msg)
         {
             if (len < conn->peek_len) FIXME("buffer isn't big enough, should we wrap?\n");
             *recvd = min( len, conn->peek_len );
@@ -809,33 +713,36 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd
             /* check if we have enough data from the peek buffer */
             if (!(flags & MSG_WAITALL) || (*recvd == len)) return TRUE;
         }
-        ret = pSSL_read( conn->ssl_conn, (char *)buf + *recvd, len - *recvd );
-        if (ret < 0)
-            return FALSE;
+        size = *recvd;
+
+        do {
+            res = read_ssl_chunk(conn, (BYTE*)buf+size, len-size, &cread, &eof);
+            if(!res) {
+                WARN("read_ssl_chunk failed\n");
+                if(!size)
+                    return FALSE;
+                break;
+            }
 
-        /* check if EOF was received */
-        if (!ret && (pSSL_get_error( conn->ssl_conn, ret ) == SSL_ERROR_ZERO_RETURN ||
-                     pSSL_get_error( conn->ssl_conn, ret ) == SSL_ERROR_SYSCALL ))
-        {
-            netconn_close( conn );
-            return TRUE;
-        }
-        if (flags & MSG_PEEK) /* must copy into buffer */
-        {
-            conn->peek_len = ret;
-            if (!ret)
-            {
-                heap_free( conn->peek_msg_mem );
-                conn->peek_msg_mem = NULL;
-                conn->peek_msg = NULL;
+            if(eof) {
+                TRACE("EOF\n");
+                break;
             }
-            else memcpy( conn->peek_msg, buf, ret );
+
+            size += cread;
+        }while(!size || ((flags & MSG_WAITALL) && size < len));
+
+        if(size && (flags & MSG_PEEK)) {
+            conn->peek_msg_mem = conn->peek_msg = heap_alloc(size);
+            if(!conn->peek_msg)
+                return FALSE;
+
+            memcpy(conn->peek_msg, buf, size);
         }
-        *recvd += ret;
+
+        TRACE("received %ld bytes\n", size);
+        *recvd = size;
         return TRUE;
-#else
-        return FALSE;
-#endif
     }
     if ((*recvd = recv( conn->socket, buf, len, flags )) == -1)
     {
@@ -848,16 +755,15 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd
 BOOL netconn_query_data_available( netconn_t *conn, DWORD *available )
 {
 #ifdef FIONREAD
-    int ret, unread;
+    int ret;
+    ULONG unread;
 #endif
     *available = 0;
     if (!netconn_connected( conn )) return FALSE;
 
     if (conn->secure)
     {
-#ifdef SONAME_LIBSSL
-        *available = pSSL_pending( conn->ssl_conn ) + conn->peek_len;
-#endif
+        *available = conn->peek_len;
         return TRUE;
     }
 #ifdef FIONREAD
@@ -877,7 +783,6 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
 
     if (conn->secure)
     {
-#ifdef SONAME_LIBSSL
         while (recvd < *buflen)
         {
             int dummy;
@@ -900,9 +805,6 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
             TRACE("received line %s\n", debugstr_a(buffer));
         }
         return ret;
-#else
-        return FALSE;
-#endif
     }
 
     FD_ZERO(&infd);
@@ -950,14 +852,13 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
 
 DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
 {
-    int res;
     struct timeval tv;
 
     /* value is in milliseconds, convert to struct timeval */
     tv.tv_sec = value / 1000;
     tv.tv_usec = (value % 1000) * 1000;
 
-    if ((res = setsockopt( netconn->socket, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv) ) == -1))
+    if (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 );
@@ -965,7 +866,7 @@ DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
     return ERROR_SUCCESS;
 }
 
-static DWORD resolve_hostname( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len )
+static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len )
 {
     char *hostname;
 #ifdef HAVE_GETADDRINFO
@@ -1050,7 +951,7 @@ static DWORD resolve_hostname( WCHAR *hostnameW, INTERNET_PORT port, struct sock
 
 struct resolve_args
 {
-    WCHAR           *hostname;
+    const WCHAR     *hostname;
     INTERNET_PORT    port;
     struct sockaddr *sa;
     socklen_t       *sa_len;
@@ -1097,35 +998,22 @@ BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa,
 
 const void *netconn_get_certificate( netconn_t *conn )
 {
-#ifdef SONAME_LIBSSL
-    X509 *cert;
     const CERT_CONTEXT *ret;
+    SECURITY_STATUS res;
 
     if (!conn->secure) return NULL;
-
-    if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn ))) return NULL;
-    ret = X509_to_cert_context( cert );
-    return ret;
-#else
-    return NULL;
-#endif
+    res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret);
+    return res == SEC_E_OK ? ret : NULL;
 }
 
 int netconn_get_cipher_strength( netconn_t *conn )
 {
-#ifdef SONAME_LIBSSL
-#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090707f)
-    const SSL_CIPHER *cipher;
-#else
-    SSL_CIPHER *cipher;
-#endif
-    int bits = 0;
+    SecPkgContext_ConnectionInfo conn_info;
+    SECURITY_STATUS res;
 
     if (!conn->secure) return 0;
-    if (!(cipher = pSSL_get_current_cipher( conn->ssl_conn ))) return 0;
-    pSSL_CIPHER_get_bits( cipher, &bits );
-    return bits;
-#else
-    return 0;
-#endif
+    res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info);
+    if(res != SEC_E_OK)
+        WARN("QueryContextAttributesW failed: %08x\n", res);
+    return res == SEC_E_OK ? conn_info.dwCipherStrength : 0;
 }
index da644bf..4cfac53 100644 (file)
@@ -134,7 +134,7 @@ function dateRange() {
     if (isGMT) {
         argc--;
     }
-    // function will work even without explict handling of this case
+    // function will work even without explicit handling of this case
     if (argc == 1) {
         var tmp = parseInt(arguments[0]);
         if (isNaN(tmp)) {
index 1febb5e..55925ba 100644 (file)
@@ -1044,6 +1044,20 @@ static BOOL add_host_header( request_t *request, DWORD modifier )
     return ret;
 }
 
+static void clear_response_headers( request_t *request )
+{
+    unsigned int i;
+
+    for (i = 0; i < request->num_headers; i++)
+    {
+        if (!request->headers[i].field) continue;
+        if (!request->headers[i].value) continue;
+        if (request->headers[i].is_request) continue;
+        delete_header( request, i );
+        i--;
+    }
+}
+
 static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional,
                           DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
 {
@@ -1059,6 +1073,8 @@ static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len
     int bytes_sent;
     DWORD len, i, flags;
 
+    clear_response_headers( request );
+
     flags = WINHTTP_ADDREQ_FLAG_ADD|WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA;
     for (i = 0; i < request->num_accept_types; i++)
     {
@@ -1428,12 +1444,12 @@ static BOOL handle_authorization( request_t *request, DWORD status )
 
     switch (status)
     {
-    case 401:
+    case HTTP_STATUS_DENIED:
         target = WINHTTP_AUTH_TARGET_SERVER;
         level  = WINHTTP_QUERY_WWW_AUTHENTICATE;
         break;
 
-    case 407:
+    case HTTP_STATUS_PROXY_AUTH_REQ:
         target = WINHTTP_AUTH_TARGET_PROXY;
         level  = WINHTTP_QUERY_PROXY_AUTHENTICATE;
         break;
@@ -1463,20 +1479,6 @@ static BOOL handle_authorization( request_t *request, DWORD status )
     return FALSE;
 }
 
-static void clear_response_headers( request_t *request )
-{
-    unsigned int i;
-
-    for (i = 0; i < request->num_headers; i++)
-    {
-        if (!request->headers[i].field) continue;
-        if (!request->headers[i].value) continue;
-        if (request->headers[i].is_request) continue;
-        delete_header( request, i );
-        i--;
-    }
-}
-
 #define MAX_REPLY_LEN   1460
 #define INITIAL_HEADER_BUFFER_LEN  512
 
@@ -1580,101 +1582,6 @@ end:
     return TRUE;
 }
 
-static BOOL handle_redirect( request_t *request, DWORD status )
-{
-    BOOL ret = FALSE;
-    DWORD size, len;
-    URL_COMPONENTS uc;
-    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 );
-    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 = ~0u;
-
-    if (!WinHttpCrackUrl( location, size / sizeof(WCHAR), 0, &uc )) /* assume relative redirect */
-    {
-        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_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->hostname, hostname ) || connect->serverport != port)
-        {
-            heap_free( connect->hostname );
-            connect->hostname = hostname;
-            connect->hostport = port;
-            if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end;
-
-            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 );
-    }
-
-    /* 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 );
-
-    if (status != HTTP_STATUS_REDIRECT_KEEP_VERB && !strcmpW( request->verb, postW ))
-    {
-        heap_free( request->verb );
-        request->verb = strdupW( getW );
-    }
-    ret = TRUE;
-
-end:
-    if (!ret) heap_free( hostname );
-    heap_free( location );
-    return ret;
-}
-
 static BOOL receive_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async )
 {
     DWORD to_read;
@@ -1857,6 +1764,117 @@ static void record_cookies( request_t *request )
     }
 }
 
+static WCHAR *get_redirect_url( request_t *request, DWORD *len )
+{
+    DWORD size;
+    WCHAR *ret;
+
+    query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL );
+    if (get_last_error() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
+    if (!(ret = heap_alloc( size ))) return NULL;
+    *len = size / sizeof(WCHAR);
+    if (query_headers( request, WINHTTP_QUERY_LOCATION, NULL, ret, &size, NULL )) return ret;
+    heap_free( ret );
+    return NULL;
+}
+
+static BOOL handle_redirect( request_t *request, DWORD status )
+{
+    BOOL ret = FALSE;
+    DWORD len, len_url;
+    URL_COMPONENTS uc;
+    connect_t *connect = request->connect;
+    INTERNET_PORT port;
+    WCHAR *hostname = NULL, *location;
+    int index;
+
+    if (!(location = get_redirect_url( request, &len_url ))) return FALSE;
+
+    memset( &uc, 0, sizeof(uc) );
+    uc.dwStructSize = sizeof(uc);
+    uc.dwSchemeLength = uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = ~0u;
+
+    if (!WinHttpCrackUrl( location, len_url, 0, &uc )) /* assume relative redirect */
+    {
+        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;
+
+        drain_content( request );
+        send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, len_url + 1 );
+    }
+    else
+    {
+        if (uc.nScheme == INTERNET_SCHEME_HTTP && request->hdr.flags & WINHTTP_FLAG_SECURE)
+        {
+            if (request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP) goto end;
+            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;
+        }
+
+        drain_content( request );
+        send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, len_url + 1 );
+
+        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->hostname, hostname ) || connect->serverport != port)
+        {
+            heap_free( connect->hostname );
+            connect->hostname = hostname;
+            connect->hostport = port;
+            if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end;
+
+            netconn_close( &request->netconn );
+            if (!(ret = netconn_init( &request->netconn ))) 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 );
+    }
+
+    /* 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 );
+
+    if (status != HTTP_STATUS_REDIRECT_KEEP_VERB && !strcmpW( request->verb, postW ))
+    {
+        heap_free( request->verb );
+        request->verb = strdupW( getW );
+    }
+    ret = TRUE;
+
+end:
+    if (!ret) heap_free( hostname );
+    heap_free( location );
+    return ret;
+}
+
 static BOOL receive_response( request_t *request, BOOL async )
 {
     BOOL ret;
@@ -1882,16 +1900,15 @@ static BOOL receive_response( request_t *request, BOOL async )
 
         if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB)
         {
-            if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS) break;
+            if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS ||
+                request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) break;
 
-            drain_content( request );
             if (!(ret = handle_redirect( request, status ))) break;
 
-            clear_response_headers( request );
             send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE ); /* recurse synchronously */
             continue;
         }
-        else if (status == 401 || status == 407)
+        else if (status == HTTP_STATUS_DENIED || status == HTTP_STATUS_PROXY_AUTH_REQ)
         {
             if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break;
 
@@ -1901,7 +1918,6 @@ static BOOL receive_response( request_t *request, BOOL async )
                 ret = TRUE;
                 break;
             }
-            clear_response_headers( request );
             send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE );
             continue;
         }
@@ -2819,7 +2835,7 @@ static DWORD wait_for_completion( struct winhttp_request *request )
 
 static HRESULT request_receive( struct winhttp_request *request )
 {
-    DWORD err, size, total_bytes_read, buflen = 4096;
+    DWORD err, size, buflen = 4096;
 
     wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE );
     if (!WinHttpReceiveResponse( request->hrequest, NULL ))
@@ -2834,7 +2850,7 @@ static HRESULT request_receive( struct winhttp_request *request )
     }
     if (!(request->buffer = heap_alloc( buflen ))) return E_OUTOFMEMORY;
     request->buffer[0] = 0;
-    size = total_bytes_read = 0;
+    size = 0;
     do
     {
         wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE );
@@ -2865,7 +2881,6 @@ static HRESULT request_receive( struct winhttp_request *request )
             goto error;
         }
         if ((err = wait_for_completion( request ))) goto error;
-        total_bytes_read += request->bytes_read;
         request->offset += request->bytes_read;
     } while (request->bytes_read);
 
@@ -2918,7 +2933,6 @@ static HRESULT request_send( struct winhttp_request *request )
     char *ptr = NULL;
     LONG size = 0;
     HRESULT hr;
-    BOOL ret;
     DWORD err;
 
     if ((err = request_set_parameters( request ))) return HRESULT_FROM_WIN32( err );
@@ -2927,9 +2941,9 @@ static HRESULT request_send( struct winhttp_request *request )
         VariantInit( &data );
         if (V_VT( &request->data ) == VT_BSTR)
         {
-            UINT i, cp = CP_ACP;
+            UINT cp = CP_ACP;
             const WCHAR *str = V_BSTR( &request->data );
-            int len = strlenW( str );
+            int i, len = strlenW( str );
 
             for (i = 0; i < len; i++)
             {
@@ -2957,7 +2971,7 @@ static HRESULT request_send( struct winhttp_request *request )
         }
     }
     wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT );
-    if (!(ret = WinHttpSendRequest( request->hrequest, NULL, 0, ptr, size, size, 0 )))
+    if (!WinHttpSendRequest( request->hrequest, NULL, 0, ptr, size, size, 0 ))
     {
         err = get_last_error();
         goto error;
@@ -3047,6 +3061,7 @@ static HRESULT WINAPI winhttp_request_get_Status(
     if (!WinHttpQueryHeaders( request->hrequest, flags, NULL, &status_code, &len, &index ))
     {
         err = get_last_error();
+        goto done;
     }
     *status = status_code;
 
index 171dd14..1d8749b 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <windef.h>
 #include <winbase.h>
+#include <winsock2.h>
 #include <winhttp.h>
 #include <wincrypt.h>
 #include <winreg.h>
@@ -189,6 +190,9 @@ static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffe
     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
         session->recv_timeout = *(DWORD *)buffer;
         return TRUE;
+    case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
+        FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
+        return TRUE;
     default:
         FIXME("unimplemented option %u\n", option);
         set_last_error( ERROR_INVALID_PARAMETER );
@@ -521,6 +525,7 @@ HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PO
     connect->hdr.callback = session->hdr.callback;
     connect->hdr.notify_mask = session->hdr.notify_mask;
     connect->hdr.context = session->hdr.context;
+    connect->hdr.redirect_policy = session->hdr.redirect_policy;
     list_init( &connect->hdr.children );
 
     addref_object( &session->hdr );
@@ -595,6 +600,71 @@ static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
     return ret;
 }
 
+static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
+{
+#if !defined(__MINGW32__) && !defined(_MSC_VER)
+    switch (addr->sa_family)
+    {
+    case AF_INET:
+    {
+        const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
+        struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
+        char *p;
+
+        addr_win->sin_family = WS_AF_INET;
+        addr_win->sin_port   = addr_unix->sin_port;
+        memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
+        p = (char *)&addr_win->sin_addr + 4;
+        memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
+        return TRUE;
+    }
+    case AF_INET6:
+    {
+        const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
+        struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
+
+        addr_win->sin6_family   = WS_AF_INET6;
+        addr_win->sin6_port     = addr_unix->sin6_port;
+        addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
+        memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+        addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
+#else
+        addr_win->sin6_scope_id = 0;
+#endif
+        memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
+        return TRUE;
+    }
+    default:
+        ERR("unhandled family %u\n", addr->sa_family);
+        return FALSE;
+    }
+#else
+    switch (addr->sa_family)
+    {
+    case AF_INET:
+    {
+        struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
+
+        memcpy( addr_in, addr, sizeof(*addr_in) );
+        memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
+        return TRUE;
+    }
+    case AF_INET6:
+    {
+        struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
+
+        memcpy( addr_in6, addr, sizeof(*addr_in6) );
+        memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
+        return TRUE;
+    }
+    default:
+        ERR("unhandled family %u\n", addr->sa_family);
+        return FALSE;
+    }
+#endif
+}
+
 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
 {
     request_t *request = (request_t *)hdr;
@@ -691,6 +761,30 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
         *buflen = sizeof(DWORD);
         return TRUE;
     }
+    case WINHTTP_OPTION_CONNECTION_INFO:
+    {
+        WINHTTP_CONNECTION_INFO *info = buffer;
+        struct sockaddr local;
+        socklen_t len = sizeof(local);
+        const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
+
+        if (!buffer || *buflen < sizeof(*info))
+        {
+            *buflen = sizeof(*info);
+            set_last_error( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
+        if (!netconn_connected( &request->netconn ))
+        {
+            set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
+            return FALSE;
+        }
+        if (getsockname( request->netconn.socket, &local, &len )) return FALSE;
+        if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
+        if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
+        info->cbSize = sizeof(*info);
+        return TRUE;
+    }
     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
         *(DWORD *)buffer = request->resolve_timeout;
         *buflen = sizeof(DWORD);
@@ -886,7 +980,7 @@ static const object_vtbl_t request_vtbl =
 static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
 {
     const WCHAR **types = accept_types;
-    int i;
+    DWORD i;
 
     if (!types) return TRUE;
     while (*types)
@@ -905,7 +999,7 @@ static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
     {
         if (!(request->accept_types[i] = strdupW( *types )))
         {
-            for (; i >= 0; i--) heap_free( request->accept_types[i] );
+            for ( ; i > 0; --i) heap_free( request->accept_types[i - 1] );
             heap_free( request->accept_types );
             request->accept_types = NULL;
             request->num_accept_types = 0;
@@ -960,13 +1054,14 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o
     request->hdr.callback = connect->hdr.callback;
     request->hdr.notify_mask = connect->hdr.notify_mask;
     request->hdr.context = connect->hdr.context;
+    request->hdr.redirect_policy = connect->hdr.redirect_policy;
     list_init( &request->hdr.children );
 
     addref_object( &connect->hdr );
     request->connect = connect;
     list_add_head( &connect->hdr.children, &request->hdr.entry );
 
-    if (!netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE )) goto end;
+    if (!netconn_init( &request->netconn )) goto end;
     request->resolve_timeout = connect->session->resolve_timeout;
     request->connect_timeout = connect->session->connect_timeout;
     request->send_timeout = connect->session->send_timeout;
@@ -1177,18 +1272,34 @@ static void printf_addr( const WCHAR *fmt, WCHAR *buf, struct sockaddr_in *addr
               (unsigned int)(ntohl( addr->sin_addr.s_addr ) & 0xff) );
 }
 
-static WCHAR *build_wpad_url( const struct addrinfo *ai )
+static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
 {
-    static const WCHAR fmtW[] =
-        {'h','t','t','p',':','/','/','%','u','.','%','u','.','%','u','.','%','u',
-         '/','w','p','a','d','.','d','a','t',0};
-    WCHAR *ret;
+    int ret = -1;
+#ifdef HAVE_GETNAMEINFO
+    ret = getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
+#endif
+    return ret;
+}
 
-    while (ai && ai->ai_family != AF_INET) ai = ai->ai_next;
+static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
+{
+    static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
+    static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
+    char name[NI_MAXHOST];
+    WCHAR *ret, *p;
+    int len;
+
+    while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
     if (!ai) return NULL;
 
-    if (!(ret = GlobalAlloc( 0, sizeof(fmtW) + 12 * sizeof(WCHAR) ))) return NULL;
-    printf_addr( fmtW, ret, (struct sockaddr_in *)ai->ai_addr );
+    if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
+
+    len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW );
+    if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
+    strcpyW( p, httpW );
+    p += strlenW( httpW );
+    while (*hostname) { *p++ = *hostname++; }
+    strcpyW( p, wpadW );
     return ret;
 }
 
@@ -1206,7 +1317,11 @@ BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
         set_last_error( ERROR_INVALID_PARAMETER );
         return FALSE;
     }
-    if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP) FIXME("discovery via DHCP not supported\n");
+    if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
+    {
+        static int fixme_shown;
+        if (!fixme_shown++) FIXME("discovery via DHCP not supported\n");
+    }
     if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
     {
 #ifdef HAVE_GETADDRINFO
@@ -1234,18 +1349,19 @@ BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
             strcpy( name, "wpad" );
             strcat( name, p );
             res = getaddrinfo( name, NULL, NULL, &ai );
-            heap_free( name );
             if (!res)
             {
-                *url = build_wpad_url( ai );
+                *url = build_wpad_url( name, ai );
                 freeaddrinfo( ai );
                 if (*url)
                 {
                     TRACE("returning %s\n", debugstr_w(*url));
+                    heap_free( name );
                     ret = TRUE;
                     break;
                 }
             }
+            heap_free( name );
             p++;
         }
         heap_free( domain );
@@ -1836,6 +1952,16 @@ static BSTR include_pac_utils( BSTR script )
     return ret;
 }
 
+#ifdef _WIN64
+#define IActiveScriptParse_Release IActiveScriptParse64_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
+#else
+#define IActiveScriptParse_Release IActiveScriptParse32_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
+#endif
+
 static BOOL run_script( const BSTR script, const WCHAR *url, WINHTTP_PROXY_INFO *info )
 {
     static const WCHAR jscriptW[] = {'J','S','c','r','i','p','t',0};
@@ -1870,7 +1996,7 @@ static BOOL run_script( const BSTR script, const WCHAR *url, WINHTTP_PROXY_INFO
     hr = IActiveScript_QueryInterface( engine, &IID_IActiveScriptParse, (void **)&parser );
     if (hr != S_OK) goto done;
 
-    hr = IActiveScriptParse64_InitNew( parser );
+    hr = IActiveScriptParse_InitNew( parser );
     if (hr != S_OK) goto done;
 
     hr = IActiveScript_SetScriptSite( engine, &script_site );
@@ -1881,7 +2007,7 @@ static BOOL run_script( const BSTR script, const WCHAR *url, WINHTTP_PROXY_INFO
 
     if (!(full_script = include_pac_utils( script ))) goto done;
 
-    hr = IActiveScriptParse64_ParseScriptText( parser, full_script, NULL, NULL, NULL, 0, 0, 0, NULL, NULL );
+    hr = IActiveScriptParse_ParseScriptText( parser, full_script, NULL, NULL, NULL, 0, 0, 0, NULL, NULL );
     if (hr != S_OK) goto done;
 
     hr = IActiveScript_SetScriptState( engine, SCRIPTSTATE_STARTED );
@@ -1918,7 +2044,7 @@ done:
     SysFreeString( hostname );
     SysFreeString( func );
     if (dispatch) IDispatch_Release( dispatch );
-    if (parser) IUnknown_Release( parser );
+    if (parser) IActiveScriptParse_Release( parser );
     if (engine) IActiveScript_Release( engine );
     if (SUCCEEDED( init )) CoUninitialize();
     if (!ret) set_last_error( ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT );
@@ -1932,7 +2058,7 @@ static BSTR download_script( const WCHAR *url )
     HINTERNET ses, con = NULL, req = NULL;
     WCHAR *hostname;
     URL_COMPONENTSW uc;
-    DWORD size = 4096, offset, to_read, bytes_read, flags = 0;
+    DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
     char *tmp, *buffer = NULL;
     BSTR script = NULL;
     int len;
@@ -1949,8 +2075,12 @@ static BSTR download_script( const WCHAR *url )
     if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
     if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
     if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
+
     if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
+    if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
+        &size, NULL ) || status != HTTP_STATUS_OK) goto done;
 
+    size = 4096;
     if (!(buffer = heap_alloc( size ))) goto done;
     to_read = size;
     offset = 0;
@@ -2020,10 +2150,8 @@ BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTO
     }
     if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
         !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
-    {
-        set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
         goto done;
-    }
+
     if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
     else pac_url = detected_pac_url;
 
index 1b83dc9..91c3a70 100644 (file)
@@ -43,6 +43,7 @@
 # define ioctlsocket ioctl
 #endif
 #include <ole2.h>
+#include <sspi.h>
 
 static const WCHAR getW[]    = {'G','E','T',0};
 static const WCHAR postW[]   = {'P','O','S','T',0};
@@ -127,7 +128,11 @@ typedef struct
 {
     int socket;
     BOOL secure; /* SSL active on connection? */
-    void *ssl_conn;
+    CtxtHandle ssl_ctx;
+    SecPkgContext_StreamSizes ssl_sizes;
+    char *ssl_buf;
+    char *extra_buf;
+    size_t extra_len;
     char *peek_msg;
     char *peek_msg_mem;
     size_t peek_len;
@@ -225,7 +230,7 @@ BOOL netconn_connect( netconn_t *, const struct sockaddr *, unsigned int, int )
 BOOL netconn_connected( netconn_t * ) DECLSPEC_HIDDEN;
 BOOL netconn_create( netconn_t *, int, int, int ) DECLSPEC_HIDDEN;
 BOOL netconn_get_next_line( netconn_t *, char *, DWORD * ) DECLSPEC_HIDDEN;
-BOOL netconn_init( netconn_t *, BOOL ) DECLSPEC_HIDDEN;
+BOOL netconn_init( netconn_t * ) DECLSPEC_HIDDEN;
 void netconn_unload( void ) DECLSPEC_HIDDEN;
 BOOL netconn_query_data_available( netconn_t *, DWORD * ) DECLSPEC_HIDDEN;
 BOOL netconn_recv( netconn_t *, void *, size_t, int, int * ) DECLSPEC_HIDDEN;
index 9d867da..fb13da2 100644 (file)
@@ -1,6 +1,7 @@
---- wine-1.5.4/dlls/winhttp/net.c      2012-06-20 14:30:41 +0200
-+++ dll/win32/winhttp/net.c    2012-06-21 18:00:53 +0200
-@@ -160,6 +160,7 @@ static void ssl_lock_callback(int mode,
+diff -prudN e:\Wine\dlls\winhttp/net.c e:\reactos-clean\dll\win32\winhttp/net.c
+--- e:\Wine\dlls\winhttp/net.c 2013-03-16 11:54:52.602606100 +0100
++++ e:\reactos-clean\dll\win32\winhttp/net.c   2013-05-21 20:25:32.595598100 +0100
+@@ -73,6 +77,7 @@ static CRITICAL_SECTION cs_gethostbyname
  #endif
  
  /* translate a unix error code into a winsock error code */
@@ -8,7 +9,7 @@
  static int sock_get_error( int err )
  {
  #if !defined(__MINGW32__) && !defined (_MSC_VER)
-@@ -225,6 +226,15 @@ static int sock_get_error( int err )
+@@ -138,6 +143,15 @@ static int sock_get_error( int err )
  #endif
      return err;
  }
@@ -22,9 +23,9 @@
 +#define ioctlsocket unix_ioctl
 +#endif
  
- #ifdef SONAME_LIBSSL
- static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
-@@ -648,11 +658,17 @@ BOOL netconn_connect( netconn_t *conn, c
+ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD security_flags )
+ {
+@@ -344,11 +358,17 @@ BOOL netconn_connect( netconn_t *conn, c
          res = sock_get_error( errno );
          if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS)
          {
                  ret = TRUE;
              else
                  res = sock_get_error( errno );
-@@ -848,7 +864,8 @@ BOOL netconn_query_data_available( netco
+@@ -442,7 +462,7 @@ BOOL netconn_secure_connect( netconn_t *
+             read_buf_size += 1024;
+         }
+-        size = recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0);
++        size = recv(conn->socket, (char *)(read_buf+in_bufs[0].cbBuffer), read_buf_size-in_bufs[0].cbBuffer, 0);
+         if(size < 1) {
+             WARN("recv error\n");
+             status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
+@@ -754,7 +774,8 @@ BOOL netconn_query_data_available( netco
  
  BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
  {
@@ -56,8 +66,8 @@
      BOOL ret = FALSE;
      DWORD recvd = 0;
  
-@@ -884,19 +901,21 @@ BOOL netconn_get_next_line( netconn_t *c
- #endif
+@@ -786,19 +807,21 @@ BOOL netconn_get_next_line( netconn_t *c
+         return ret;
      }
  
 -    pfd.fd = conn->socket;
          {
              if ((res = recv( conn->socket, &buffer[recvd], 1, 0 )) <= 0)
              {
---- wine-1.5.4/dlls/winhttp/request.c  2012-06-20 14:30:41 +0200
-+++ dll/win32/winhttp/request.c        2012-06-21 17:32:47 +0200
-@@ -38,6 +38,8 @@
- #include "winhttp_private.h"
-+#include "inet_ntop.c"
-+
- WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
+diff -prudN e:\Wine\dlls\winhttp/request.c e:\reactos-clean\dll\win32\winhttp/request.c
+--- e:\Wine\dlls\winhttp/request.c     2013-03-16 11:54:52.603606700 +0100
++++ e:\reactos-clean\dll\win32\winhttp/request.c       2013-05-21 20:05:12.642413600 +0100
+@@ -2254,8 +2260,8 @@ static void free_request( struct winhttp
+     CloseHandle( request->thread );
+     CloseHandle( request->wait );
+     CloseHandle( request->cancel );
+-    heap_free( request->proxy.lpszProxy );
+-    heap_free( request->proxy.lpszProxyBypass );
++    heap_free( (WCHAR *)request->proxy.lpszProxy );
++    heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
+     heap_free( request->buffer );
+     heap_free( request->verb );
+     VariantClear( &request->data );
+@@ -2446,16 +2452,16 @@ static HRESULT WINAPI winhttp_request_Se
+     {
+     case HTTPREQUEST_PROXYSETTING_DEFAULT:
+         request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
+-        heap_free( request->proxy.lpszProxy );
+-        heap_free( request->proxy.lpszProxyBypass );
++        heap_free( (WCHAR *)request->proxy.lpszProxy );
++        heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
+         request->proxy.lpszProxy = NULL;
+         request->proxy.lpszProxyBypass = NULL;
+         break;
  
- static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0};
---- wine-1.5.4/dlls/winhttp/rsrc.rc    2012-06-20 14:30:41 +0200
-+++ dll/win32/winhttp/rsrc.rc  2012-07-14 15:25:28 +0200
+     case HTTPREQUEST_PROXYSETTING_DIRECT:
+         request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
+-        heap_free( request->proxy.lpszProxy );
+-        heap_free( request->proxy.lpszProxyBypass );
++        heap_free( (WCHAR *)request->proxy.lpszProxy );
++        heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
+         request->proxy.lpszProxy = NULL;
+         request->proxy.lpszProxyBypass = NULL;
+         break;
+@@ -2464,12 +2470,12 @@ static HRESULT WINAPI winhttp_request_Se
+         request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+         if (V_VT( &proxy_server ) == VT_BSTR)
+         {
+-            heap_free( request->proxy.lpszProxy );
++            heap_free( (WCHAR *)request->proxy.lpszProxy );
+             request->proxy.lpszProxy = strdupW( V_BSTR( &proxy_server ) );
+         }
+         if (V_VT( &bypass_list ) == VT_BSTR)
+         {
+-            heap_free( request->proxy.lpszProxyBypass );
++            heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
+             request->proxy.lpszProxyBypass = strdupW( V_BSTR( &bypass_list ) );
+         }
+         break;
+diff -prudN e:\Wine\dlls\winhttp/rsrc.rc e:\reactos-clean\dll\win32\winhttp/rsrc.rc
+--- e:\Wine\dlls\winhttp/rsrc.rc       2011-11-24 17:55:02.335439900 +0100
++++ e:\reactos-clean\dll\win32\winhttp/rsrc.rc 2012-07-20 21:40:58.173741700 +0100
 @@ -16,6 +16,12 @@
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   */
  /* @makedep: pac.js */
  pac.js 40 "pac.js"
  
---- wine-1.5.4/dlls/winhttp/session.c  2012-07-13 15:34:57 +0200
-+++ dll/win32/winhttp/session.c        2012-06-23 17:51:47 +0200
-@@ -95,6 +95,9 @@ static void session_destroy( object_head
+diff -prudN e:\Wine\dlls\winhttp/session.c e:\reactos-clean\dll\win32\winhttp/session.c
+--- e:\Wine\dlls\winhttp/session.c     2013-03-16 11:54:52.604607400 +0100
++++ e:\reactos-clean\dll\win32\winhttp/session.c       2013-05-21 20:19:52.231665900 +0100
+@@ -100,6 +100,9 @@ static void session_destroy( object_head
      heap_free( session->proxy_username );
      heap_free( session->proxy_password );
      heap_free( session );
  }
  
  static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
-@@ -203,6 +206,11 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR ag
+@@ -211,6 +214,11 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR ag
  {
      session_t *session;
      HINTERNET handle = NULL;
  
      TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
  
+@@ -237,14 +245,14 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR ag
+         session->access = info.dwAccessType;
+         if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
+         {
+-            GlobalFree( info.lpszProxy );
+-            GlobalFree( info.lpszProxyBypass );
++            GlobalFree( (LPWSTR)info.lpszProxy );
++            GlobalFree( (LPWSTR)info.lpszProxyBypass );
+             goto end;
+         }
+         if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
+         {
+-            GlobalFree( info.lpszProxy );
+-            GlobalFree( info.lpszProxyBypass );
++            GlobalFree( (LPWSTR)info.lpszProxy );
++            GlobalFree( (LPWSTR)info.lpszProxyBypass );
+             goto end;
+         }
+     }
+@@ -594,7 +602,7 @@ static WCHAR *blob_to_str( DWORD encodin
+ static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
+ {
+-#ifndef __MINGW32__
++#if !defined(__MINGW32__) && !defined(_MSC_VER)
+     switch (addr->sa_family)
+     {
+     case AF_INET:
index b54bd92..9247abf 100644 (file)
 #ifndef __WINE_WINHTTP_H
 #define __WINE_WINHTTP_H
 
+#ifdef _WIN64
+#include <pshpack8.h>
+#else
+#include <pshpack4.h>
+#endif
+
 #define WINHTTPAPI
 #define BOOLAPI WINHTTPAPI BOOL WINAPI
 
@@ -487,8 +493,8 @@ typedef struct
 typedef struct
 {
     DWORD dwAccessType;
-    LPCWSTR lpszProxy;
-    LPCWSTR lpszProxyBypass;
+    LPWSTR lpszProxy;
+    LPWSTR lpszProxyBypass;
 } WINHTTP_PROXY_INFO, *LPWINHTTP_PROXY_INFO;
 typedef WINHTTP_PROXY_INFO WINHTTP_PROXY_INFOW;
 typedef LPWINHTTP_PROXY_INFO LPWINHTTP_PROXY_INFOW;
@@ -527,6 +533,14 @@ typedef struct
     DWORD dwMinorVersion;
 } HTTP_VERSION_INFO, *LPHTTP_VERSION_INFO;
 
+#ifdef _WS2DEF_
+typedef struct
+{
+    DWORD cbSize;
+    SOCKADDR_STORAGE LocalAddress;
+    SOCKADDR_STORAGE RemoteAddress;
+} WINHTTP_CONNECTION_INFO;
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -565,4 +579,6 @@ BOOL        WINAPI WinHttpWriteData(HINTERNET,LPCVOID,DWORD,LPDWORD);
 }
 #endif
 
+#include <poppack.h>
+
 #endif  /* __WINE_WINHTTP_H */
index d8a9992..be17467 100644 (file)
@@ -190,7 +190,7 @@ reactos/dll/win32/wer             # Autosync
 reactos/dll/win32/windowscodecs   # Synced to Wine-1.5.19
 reactos/dll/win32/winemp3.acm     # Synced to Wine-1.5.19
 reactos/dll/win32/wing32          # Out of sync
-reactos/dll/win32/winhttp         # Synced to Wine-1.5.4
+reactos/dll/win32/winhttp         # Synced to Wine-1.5.26
 reactos/dll/win32/wininet         # Synced to Wine-1.5.26
 reactos/dll/win32/winmm           # Forked at Wine-20050628
 reactos/dll/win32/winmm/midimap   # Forked at Wine-20050628