* Sync up to trunk head (r64377).
[reactos.git] / dll / win32 / wininet / http.c
index 714c4a6..e472d3e 100644 (file)
@@ -299,7 +299,11 @@ BOOL collect_connections(collect_type_t collect_type)
     BOOL remaining = FALSE;
     DWORD64 now;
 
+#ifdef __REACTOS__
     now = GetTickCount();
+#else
+    now = GetTickCount64();
+#endif
 
     LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) {
         LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) {
@@ -740,7 +744,7 @@ static void HTTP_ProcessCookies( http_request_t *request )
             continue;
 
         data++;
-        set_cookie(host->lpszValue, request->path, name, data);
+        set_cookie(host->lpszValue, request->path, name, data, INTERNET_COOKIE_HTTPONLY);
         heap_free(name);
     }
 }
@@ -1300,7 +1304,7 @@ BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
 
     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
 
-    if (!lpszHeader)
+    if (!lpszHeader) 
       return TRUE;
 
     request = (http_request_t*) get_handle_object( hHttpRequest );
@@ -1951,7 +1955,7 @@ static void http_release_netconn(http_request_t *req, BOOL reuse)
         return;
     }
 #else
-    // silence unused function warning
+    /* Silence unused function warning */
     (void)collect_connections_proc;
 #endif
 
@@ -2859,10 +2863,11 @@ static const data_stream_vtbl_t chunked_stream_vtbl = {
 static DWORD set_content_length(http_request_t *request)
 {
     static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
+    static const WCHAR headW[] = {'H','E','A','D',0};
     WCHAR encoding[20];
     DWORD size;
 
-    if(request->status_code == HTTP_STATUS_NO_CONTENT) {
+    if(request->status_code == HTTP_STATUS_NO_CONTENT || !strcmpW(request->verb, headW)) {
         request->contentLength = request->netconn_stream.content_length = 0;
         return ERROR_SUCCESS;
     }
@@ -3346,9 +3351,6 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session,
 
     HTTP_ProcessHeader(request, hostW, request->server->canon_host_port, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
 
-    if (session->hostPort == INTERNET_INVALID_PORT_NUMBER)
-        session->hostPort = INTERNET_DEFAULT_HTTP_PORT;
-
     if (hIC->proxy && hIC->proxy[0] && !HTTP_ShouldBypassProxy(hIC, session->hostName))
         HTTP_DealWithProxy( hIC, session, request );
 
@@ -3673,8 +3675,6 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
         return ERROR_HTTP_HEADER_NOT_FOUND;
     }
 
-    if (lpdwIndex) (*lpdwIndex)++;
-
     /* coalesce value to requested type */
     if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
     {
@@ -3720,6 +3720,7 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
         }
         *lpdwBufferLength = len - sizeof(WCHAR);
     }
+    if (lpdwIndex) (*lpdwIndex)++;
     return ERROR_SUCCESS;
 }
 
@@ -3842,13 +3843,13 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
                info_mod &= ~ modifier_flags[i].val;
            }
        }
-
+       
        if (info_mod) {
            TRACE(" Unknown (%08x)", info_mod);
        }
        TRACE("\n");
     }
-
+    
     request = (http_request_t*) get_handle_object( hHttpRequest );
     if (NULL == request ||  request->hdr.htype != WH_HHTTPREQ)
     {
@@ -3955,9 +3956,9 @@ static LPWSTR HTTP_GetRedirectURL(http_request_t *request, LPCWSTR lpszUrl)
     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
     urlComponents.lpszScheme = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
     urlComponents.dwSchemeLength = 0;
-    urlComponents.lpszHostName = session->hostName;
+    urlComponents.lpszHostName = request->server->name;
     urlComponents.dwHostNameLength = 0;
-    urlComponents.nPort = session->hostPort;
+    urlComponents.nPort = request->server->port;
     urlComponents.lpszUserName = session->userName;
     urlComponents.dwUserNameLength = 0;
     urlComponents.lpszPassword = NULL;
@@ -4082,6 +4083,7 @@ static DWORD HTTP_HandleRedirect(http_request_t *request, LPCWSTR lpszUrl)
         }
         else
             session->hostName = heap_strdupW(hostName);
+        session->hostPort = urlComponents.nPort;
 
         HTTP_ProcessHeader(request, hostW, session->hostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
 
@@ -4154,68 +4156,17 @@ static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
     return str;
 }
 
-static DWORD HTTP_SecureProxyConnect(http_request_t *request)
-{
-    server_t *server = request->server;
-    LPWSTR requestString;
-    INT len;
-    INT cnt;
-    INT responseLen;
-    char *ascii_req;
-    DWORD res;
-
-    static const WCHAR connectW[] = {'C','O','N','N','E','C','T',0};
-
-    TRACE("\n");
-
-    requestString = build_request_header( request, connectW, server->host_port, g_szHttp1_1, TRUE );
-
-    len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
-                                NULL, 0, NULL, NULL );
-    len--; /* the nul terminator isn't needed */
-    ascii_req = heap_alloc(len);
-    WideCharToMultiByte( CP_ACP, 0, requestString, -1, ascii_req, len, NULL, NULL );
-    heap_free( requestString );
-
-    TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
-
-    NETCON_set_timeout( request->netconn, TRUE, request->send_timeout );
-    res = NETCON_send( request->netconn, ascii_req, len, 0, &cnt );
-    heap_free( ascii_req );
-    if (res != ERROR_SUCCESS)
-        return res;
-
-    if (HTTP_GetResponseHeaders( request, &responseLen ) || !responseLen)
-        return ERROR_HTTP_INVALID_HEADER;
-
-    return ERROR_SUCCESS;
-}
-
 static void HTTP_InsertCookies(http_request_t *request)
 {
-    DWORD cookie_size, size, cnt = 0;
-    HTTPHEADERW *host;
     WCHAR *cookies;
+    DWORD res;
 
-    static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' ',0};
-
-    host = HTTP_GetHeader(request, hostW);
-    if(!host)
-        return;
-
-    if(get_cookie(host->lpszValue, request->path, NULL, &cookie_size) != ERROR_SUCCESS)
-        return;
-
-    size = sizeof(cookieW) + cookie_size * sizeof(WCHAR) + sizeof(szCrLf);
-    if(!(cookies = heap_alloc(size)))
+    res = get_cookie_header(request->server->name, request->path, &cookies);
+    if(res != ERROR_SUCCESS || !cookies)
         return;
 
-    cnt += sprintfW(cookies, cookieW);
-    get_cookie(host->lpszValue, request->path, cookies+cnt, &cookie_size);
-    strcatW(cookies, szCrLf);
-
+    get_cookie_header(request->server->name, request->path, &cookies);
     HTTP_HttpAddRequestHeadersW(request, cookies, strlenW(cookies), HTTP_ADDREQ_FLAG_REPLACE);
-
     heap_free(cookies);
 }
 
@@ -4815,29 +4766,24 @@ static DWORD open_http_connection(http_request_t *request, BOOL *reusing)
             INTERNET_STATUS_CONNECTED_TO_SERVER,
             request->server->addr_str, strlen(request->server->addr_str)+1);
 
-    if(is_https) {
-        /* Note: we differ from Microsoft's WinINet here. they seem to have
-         * a bug that causes no status callbacks to be sent when starting
-         * a tunnel to a proxy server using the CONNECT verb. i believe our
-         * behaviour to be more correct and to not cause any incompatibilities
-         * because using a secure connection through a proxy server is a rare
-         * case that would be hard for anyone to depend on */
-        if(request->proxy)
-            res = HTTP_SecureProxyConnect(request);
-        if(res == ERROR_SUCCESS)
-            res = NETCON_secure_connect(request->netconn, request->server);
-    }
-
-    if(res != ERROR_SUCCESS) {
-        http_release_netconn(request, FALSE);
-        return res;
-    }
-
     *reusing = FALSE;
     TRACE("Created connection to %s: %p\n", debugstr_w(request->server->name), netconn);
     return ERROR_SUCCESS;
 }
 
+static char *build_ascii_request( const WCHAR *str, void *data, DWORD data_len, DWORD *out_len )
+{
+    int len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
+    char *ret;
+
+    if (!(ret = heap_alloc( len + data_len ))) return NULL;
+    WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
+    if (data_len) memcpy( ret + len - 1, data, data_len );
+    *out_len = len + data_len - 1;
+    ret[*out_len] = 0;
+    return ret;
+}
+
 /***********************************************************************
  *           HTTP_HttpSendRequestW (internal)
  *
@@ -4852,13 +4798,11 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
        DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
        DWORD dwContentLength, BOOL bEndRequest)
 {
-    INT cnt;
-    BOOL redirected = FALSE;
-    LPWSTR requestString = NULL;
-    INT responseLen;
-    BOOL loop_next;
     static const WCHAR szContentLength[] =
         { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
+    BOOL redirected = FALSE, secure_proxy_connect = FALSE, loop_next;
+    LPWSTR requestString = NULL;
+    INT responseLen, cnt;
     WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
     DWORD res;
 
@@ -4873,7 +4817,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
     if (dwContentLength || strcmpW(request->verb, szGET))
     {
         sprintfW(contentLengthStr, szContentLength, dwContentLength);
-        HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
+        HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
         request->bytesToWrite = dwContentLength;
     }
     if (request->session->appInfo->agent)
@@ -4907,7 +4851,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
 
     do
     {
-        DWORD len;
+        DWORD len, data_len = dwOptionalLength;
         BOOL reusing_connection;
         char *ascii_req;
 
@@ -4935,7 +4879,31 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
         if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES))
             HTTP_InsertCookies(request);
 
-        if (request->proxy)
+        res = open_http_connection(request, &reusing_connection);
+        if (res != ERROR_SUCCESS)
+            break;
+
+        if (!reusing_connection && (request->hdr.dwFlags & INTERNET_FLAG_SECURE))
+        {
+            if (request->proxy) secure_proxy_connect = TRUE;
+            else
+            {
+                res = NETCON_secure_connect(request->netconn, request->server);
+                if (res != ERROR_SUCCESS)
+                {
+                    WARN("failed to upgrade to secure connection\n");
+                    http_release_netconn(request, FALSE);
+                    break;
+                }
+            }
+        }
+        if (secure_proxy_connect)
+        {
+            static const WCHAR connectW[] = {'C','O','N','N','E','C','T',0};
+            const WCHAR *target = request->server->host_port;
+            requestString = build_request_header(request, connectW, target, g_szHttp1_1, TRUE);
+        }
+        else if (request->proxy && !(request->hdr.dwFlags & INTERNET_FLAG_SECURE))
         {
             WCHAR *url = build_proxy_path_url(request);
             requestString = build_request_header(request, request->verb, url, request->version, TRUE);
@@ -4944,25 +4912,13 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
         else
             requestString = build_request_header(request, request->verb, request->path, request->version, TRUE);
 
-
         TRACE("Request header -> %s\n", debugstr_w(requestString) );
 
-        res = open_http_connection(request, &reusing_connection);
-        if (res != ERROR_SUCCESS)
-            break;
-
         /* send the request as ASCII, tack on the optional data */
-        if (!lpOptional || redirected)
-            dwOptionalLength = 0;
-        len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
-                                   NULL, 0, NULL, NULL );
-        ascii_req = heap_alloc(len + dwOptionalLength);
-        WideCharToMultiByte( CP_ACP, 0, requestString, -1,
-                             ascii_req, len, NULL, NULL );
-        if( lpOptional )
-            memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
-        len = (len + dwOptionalLength - 1);
-        ascii_req[len] = 0;
+        if (!lpOptional || redirected || secure_proxy_connect)
+            data_len = 0;
+
+        ascii_req = build_ascii_request( requestString, lpOptional, data_len, &len );
         TRACE("full request -> %s\n", debugstr_a(ascii_req) );
 
         INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
@@ -4980,7 +4936,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
             continue;
         }
 
-        request->bytesWritten = dwOptionalLength;
+        request->bytesWritten = data_len;
 
         INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
                               INTERNET_STATUS_REQUEST_SENT,
@@ -4992,7 +4948,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
 
             INTERNET_SendCallback(&request->hdr, request->hdr.dwContext,
                                 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
+    
             if (HTTP_GetResponseHeaders(request, &responseLen))
             {
                 http_release_netconn(request, FALSE);
@@ -5117,6 +5073,25 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
                     }
                 }
             }
+            if (secure_proxy_connect && request->status_code == HTTP_STATUS_OK)
+            {
+                int index;
+
+                res = NETCON_secure_connect(request->netconn, request->server);
+                if (res != ERROR_SUCCESS)
+                {
+                    WARN("failed to upgrade to secure proxy connection\n");
+                    http_release_netconn( request, FALSE );
+                    break;
+                }
+                index = HTTP_GetCustomHeaderIndex(request, szProxy_Authorization, 0, TRUE);
+                if (index != -1) HTTP_DeleteCustomHeader(request, index);
+                destroy_authinfo(request->proxyAuthInfo);
+                request->proxyAuthInfo = NULL;
+
+                secure_proxy_connect = FALSE;
+                loop_next = TRUE;
+            }
         }
         else
             res = ERROR_SUCCESS;
@@ -6039,7 +6014,7 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR
     /* REPLACE wins out over ADD */
     if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
         dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
-
+    
     if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
         index = -1;
     else