From f07f2304b0b30e2efac70f0a4defc0999a7b583e Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 26 Aug 2008 11:03:40 +0200 Subject: [PATCH] winhttp: Implement WinHttpSendRequest. --- dlls/winhttp/handle.c | 2 + dlls/winhttp/main.c | 13 ---- dlls/winhttp/request.c | 142 +++++++++++++++++++++++++++++++++++++++++ dlls/winhttp/session.c | 7 +- dlls/winhttp/tests/winhttp.c | 4 +- dlls/winhttp/winhttp_private.h | 13 ++++ 6 files changed, 165 insertions(+), 16 deletions(-) diff --git a/dlls/winhttp/handle.c b/dlls/winhttp/handle.c index 607bfcd331d..6f542a3b731 100644 --- a/dlls/winhttp/handle.c +++ b/dlls/winhttp/handle.c @@ -77,6 +77,8 @@ void release_object( object_header_t *hdr ) TRACE("object %p refcount = %d\n", hdr, refs); if (!refs) { + if (hdr->type == WINHTTP_HANDLE_TYPE_REQUEST) close_connection( (request_t *)hdr ); + send_callback( hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, &hdr->handle, sizeof(HINTERNET) ); TRACE("destroying object %p\n", hdr); diff --git a/dlls/winhttp/main.c b/dlls/winhttp/main.c index b660dba56e2..3fb302662e4 100644 --- a/dlls/winhttp/main.c +++ b/dlls/winhttp/main.c @@ -84,19 +84,6 @@ HRESULT WINAPI DllUnregisterServer(void) } /*********************************************************************** - * WinHttpSendRequest (winhttp.@) - */ -BOOL WINAPI WinHttpSendRequest (HINTERNET hRequest, LPCWSTR pwszHeaders, DWORD dwHeadersLength, - LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, - DWORD_PTR dwContext) -{ - FIXME("(%s, %d, %d, %d): stub\n", debugstr_w(pwszHeaders), dwHeadersLength, dwOptionalLength, dwTotalLength); - - SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; -} - -/*********************************************************************** * WinHttpQueryOption (winhttp.@) */ BOOL WINAPI WinHttpQueryOption (HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 7953538c25f..8a323204259 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -21,6 +21,9 @@ #include "wine/debug.h" #include +#ifdef HAVE_ARPA_INET_H +# include +#endif #include "windef.h" #include "winbase.h" @@ -654,3 +657,142 @@ BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, LPCWSTR name, release_object( &request->hdr ); return ret; } + +static BOOL open_connection( request_t *request ) +{ + connect_t *connect; + char address[32]; + WCHAR *addressW; + + if (netconn_connected( &request->netconn )) return TRUE; + + connect = request->connect; + if (!netconn_resolve( connect->servername, connect->serverport, &connect->sockaddr )) return FALSE; + + inet_ntop( connect->sockaddr.sin_family, &connect->sockaddr.sin_addr, address, sizeof(address) ); + TRACE("connecting to %s:%u\n", address, ntohs(connect->sockaddr.sin_port)); + addressW = strdupAW( address ); + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, 0 ); + + if (!netconn_create( &request->netconn, connect->sockaddr.sin_family, SOCK_STREAM, 0 )) + { + heap_free( addressW ); + return FALSE; + } + if (!netconn_connect( &request->netconn, (struct sockaddr *)&connect->sockaddr, sizeof(struct sockaddr_in) )) + { + netconn_close( &request->netconn ); + heap_free( addressW ); + return FALSE; + } + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, 0 ); + + heap_free( addressW ); + return TRUE; +} + +void close_connection( request_t *request ) +{ + if (!netconn_connected( &request->netconn )) return; + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); + netconn_close( &request->netconn ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); +} + +static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional, + DWORD optional_len, DWORD total_len, DWORD_PTR context ) +{ + static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0}; + static const WCHAR no_cache[] = {'n','o','-','c','a','c','h','e',0}; + static const WCHAR length_fmt[] = {'%','l','d',0}; + + BOOL ret = FALSE; + connect_t *connect = request->connect; + session_t *session = connect->session; + WCHAR *req = NULL; + char *req_ascii; + int bytes_sent; + DWORD len; + + if (session->agent) + process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + + if (connect->hostname) + process_header( request, attr_host, connect->hostname, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + + if (optional_len) + { + WCHAR length[21]; /* decimal long int + null */ + sprintfW( length, length_fmt, optional_len ); + process_header( request, attr_content_length, length, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + } + if (!(request->hdr.flags & WINHTTP_DISABLE_KEEP_ALIVE)) + { + process_header( request, attr_connection, keep_alive, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + } + if (request->hdr.flags & WINHTTP_FLAG_REFRESH) + { + process_header( request, attr_pragma, no_cache, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + process_header( request, attr_cache_control, no_cache, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + } + if (headers && !add_request_headers( request, headers, headers_len, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) + { + TRACE("failed to add request headers\n"); + return FALSE; + } + + if (!(ret = open_connection( request ))) goto end; + if (!(req = build_request_string( request, request->verb, request->path, request->version ))) goto end; + + if (!(req_ascii = strdupWA( req ))) goto end; + TRACE("full request: %s\n", debugstr_a(req_ascii)); + len = strlen(req_ascii); + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 ); + + ret = netconn_send( &request->netconn, req_ascii, len, 0, &bytes_sent ); + heap_free( req_ascii ); + if (!ret) goto end; + + if (optional_len && !netconn_send( &request->netconn, optional, optional_len, 0, &bytes_sent )) goto end; + len += optional_len; + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(DWORD) ); + +end: + heap_free( req ); + return ret; +} + +/*********************************************************************** + * WinHttpSendRequest (winhttp.@) + */ +BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD headers_len, + LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context ) +{ + BOOL ret; + request_t *request; + + TRACE("%p, %s, 0x%x, %u, %u, %lx\n", + hrequest, debugstr_w(headers), headers_len, optional_len, total_len, context); + + if (!(request = (request_t *)grab_object( hrequest ))) + { + set_last_error( ERROR_INVALID_HANDLE ); + return FALSE; + } + if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) + { + release_object( &request->hdr ); + set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); + return FALSE; + } + + ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context ); + + release_object( &request->hdr ); + return ret; +} diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index d2bb3407e0f..6548c7fd92c 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -177,7 +177,10 @@ HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PO list_add_head( &session->hdr.children, &connect->hdr.entry ); if (server && !(connect->hostname = strdupW( server ))) goto end; - connect->hostport = port; + connect->hostport = port ? port : (connect->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); + + if (server && !(connect->servername = strdupW( server ))) goto end; + connect->serverport = port ? port : (connect->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); if (!(hconnect = alloc_handle( &connect->hdr ))) goto end; connect->hdr.handle = hconnect; @@ -268,6 +271,8 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o request->connect = connect; list_add_head( &connect->hdr.children, &request->hdr.entry ); + if (!netconn_init( &request->netconn )) goto end; + if (!verb) verb = get; if (!object) object = slash; if (!version) version = http1_1; diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index d77dcc0f926..985c7def9a1 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -59,7 +59,7 @@ static void test_OpenRequest (void) ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError()); ret = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0); - todo_wine ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); + ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); ret = WinHttpCloseHandle(request); ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); @@ -111,7 +111,7 @@ static void test_SendRequest (void) ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError()); ret = WinHttpSendRequest(request, content_type, header_len, post_data, optional_len, total_len, 0); - todo_wine ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); + ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); for (i = 3; post_data[i]; i++) { diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 2d4c31357d5..86868aff168 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -123,6 +123,7 @@ BOOL free_handle( HINTERNET ); void set_last_error( DWORD ); void send_callback( object_header_t *, DWORD, LPVOID, DWORD ); +void close_connection( request_t * ); BOOL netconn_close( netconn_t * ); BOOL netconn_connect( netconn_t *, const struct sockaddr *, unsigned int ); @@ -170,6 +171,18 @@ static inline WCHAR *strdupW( const WCHAR *src ) return dst; } +static inline WCHAR *strdupAW( const char *src ) +{ + WCHAR *dst = NULL; + if (src) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); + if ((dst = heap_alloc( len * sizeof(WCHAR) ))) + MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); + } + return dst; +} + static inline char *strdupWA( const WCHAR *src ) { char *dst = NULL; -- 2.11.4.GIT