Synced winhttp.dll with Wine HEAD using stuff and methods from wininet.dll.

It helps Chrome setup starting (but not working yet).

svn path=/trunk/; revision=36016
This commit is contained in:
Pierre Schweitzer 2008-09-07 08:21:35 +00:00
parent d158ab5aa3
commit 51ee2d9ff9
10 changed files with 3575 additions and 164 deletions

View file

@ -0,0 +1,159 @@
/*
* Copyright 2008 Hans Leidekker for CodeWeavers
*
* Based on the handle implementation from wininet.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include "wine/debug.h"
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winhttp.h"
#include "winhttp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
#define HANDLE_CHUNK_SIZE 0x10
static CRITICAL_SECTION handle_cs;
static CRITICAL_SECTION_DEBUG handle_cs_debug =
{
0, 0, &handle_cs,
{ &handle_cs_debug.ProcessLocksList, &handle_cs_debug.ProcessLocksList },
0, 0, { (ULONG_PTR)(__FILE__ ": handle_cs") }
};
static CRITICAL_SECTION handle_cs = { &handle_cs_debug, -1, 0, 0, 0, 0 };
static object_header_t **handles;
static ULONG_PTR next_handle;
static ULONG_PTR max_handles;
object_header_t *addref_object( object_header_t *hdr )
{
ULONG refs = InterlockedIncrement( &hdr->refs );
TRACE("%p -> refcount = %d\n", hdr, refs);
return hdr;
}
object_header_t *grab_object( HINTERNET hinternet )
{
object_header_t *hdr = NULL;
ULONG_PTR handle = (ULONG_PTR)hinternet;
EnterCriticalSection( &handle_cs );
if ((handle > 0) && (handle <= max_handles) && handles[handle - 1])
hdr = addref_object( handles[handle - 1] );
LeaveCriticalSection( &handle_cs );
TRACE("handle 0x%lx -> %p\n", handle, hdr);
return hdr;
}
void release_object( object_header_t *hdr )
{
ULONG refs = InterlockedDecrement( &hdr->refs );
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);
if (hdr->type != WINHTTP_HANDLE_TYPE_SESSION) list_remove( &hdr->entry );
hdr->vtbl->destroy( hdr );
}
}
HINTERNET alloc_handle( object_header_t *hdr )
{
object_header_t **p;
ULONG_PTR handle = 0, num;
list_init( &hdr->children );
EnterCriticalSection( &handle_cs );
if (!max_handles)
{
num = HANDLE_CHUNK_SIZE;
if (!(p = heap_alloc_zero( sizeof(ULONG_PTR) * num ))) goto end;
handles = p;
max_handles = num;
}
if (max_handles == next_handle)
{
num = max_handles + HANDLE_CHUNK_SIZE;
if (!(p = heap_realloc_zero( handles, sizeof(ULONG_PTR) * num ))) goto end;
handles = p;
max_handles = num;
}
handle = next_handle;
if (handles[handle]) ERR("handle isn't free but should be\n");
handles[handle] = addref_object( hdr );
while (handles[next_handle] && (next_handle < max_handles)) next_handle++;
end:
LeaveCriticalSection( &handle_cs );
return hdr->handle = (HINTERNET)(handle + 1);
}
BOOL free_handle( HINTERNET hinternet )
{
BOOL ret = FALSE;
ULONG_PTR handle = (ULONG_PTR)hinternet;
object_header_t *hdr = NULL, *child, *next;
EnterCriticalSection( &handle_cs );
if ((handle > 0) && (handle <= max_handles))
{
handle--;
if (handles[handle])
{
hdr = handles[handle];
TRACE("destroying handle 0x%lx for object %p\n", handle + 1, hdr);
handles[handle] = NULL;
ret = TRUE;
}
}
LeaveCriticalSection( &handle_cs );
if (hdr)
{
LIST_FOR_EACH_ENTRY_SAFE( child, next, &hdr->children, object_header_t, entry )
{
TRACE("freeing child handle %p for parent handle 0x%lx\n", child->handle, handle + 1);
free_handle( child->handle );
}
release_object( hdr );
}
EnterCriticalSection( &handle_cs );
if (next_handle > handle && !handles[handle]) next_handle = handle;
LeaveCriticalSection( &handle_cs );
return ret;
}

View file

@ -0,0 +1,192 @@
/* from NetBSD: inet_ntop.c,v 1.9 2000/01/22 22:19:16 mycroft Exp */
/* Copyright (c) 1996 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#define ENOSPC 28
#define EAFNOSUPPORT 52
#ifndef IN6ADDRSZ
#define IN6ADDRSZ 16
#endif
#ifndef INT16SZ
#define INT16SZ 2
#endif
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static const char *inet_ntop4(const u_char *src, char *dst, size_t size);
#ifdef INET6
static const char *inet_ntop6(const u_char *src, char *dst, size_t size);
#endif
/* char *
* inet_ntop(af, src, dst, size)
* convert a network format address to presentation format.
* return:
* pointer to presentation format address (`dst'), or NULL (see errno).
* author:
* Paul Vixie, 1996.
*/
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
#ifdef INET6
case AF_INET6:
return (inet_ntop6(src, dst, size));
#endif
default:
errno = EAFNOSUPPORT;
return (NULL);
}
/* NOTREACHED */
}
/* const char *
* inet_ntop4(src, dst, size)
* format an IPv4 address, more or less like inet_ntoa()
* return:
* `dst' (as a const)
* notes:
* (1) uses no statics
* (2) takes a u_char* not an in_addr as input
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop4(const u_char *src, char *dst, size_t size)
{
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
#ifdef INET6
/* const char *
* inet_ntop6(src, dst, size)
* convert IPv6 binary address into presentation (printable) format
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop6(const u_char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
u_int words[IN6ADDRSZ / INT16SZ];
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
cur.base = -1;
for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
return (NULL);
tp += strlen(tp);
break;
}
tp += SPRINTF((tp, "%x", words[i]));
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
*tp++ = ':';
*tp++ = '\0';
/*
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
#endif

View file

@ -27,6 +27,8 @@
#include "wine/debug.h"
#include "winhttp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
/******************************************************************
@ -83,167 +85,40 @@ HRESULT WINAPI DllUnregisterServer(void)
return S_OK;
}
/***********************************************************************
* WinHttpCheckPlatform (winhttp.@)
*/
BOOL WINAPI WinHttpCheckPlatform(void)
{
FIXME("stub\n");
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
#define SCHEME_HTTP 3
#define SCHEME_HTTPS 4
BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW );
BOOL WINAPI InternetCreateUrlW( LPURL_COMPONENTS, DWORD, LPWSTR, LPDWORD );
/***********************************************************************
* WinHttpDetectAutoProxyConfigUrl (winhttp.@)
* WinHttpCrackUrl (winhttp.@)
*/
BOOL WINAPI WinHttpDetectAutoProxyConfigUrl(DWORD flags, LPWSTR *url)
BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW components )
{
FIXME("(%x %p)\n", flags, url);
BOOL ret;
SetLastError(ERROR_WINHTTP_AUTODETECTION_FAILED);
return FALSE;
}
TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, components);
/***********************************************************************
* WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
*/
BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* config)
{
if(!config)
if ((ret = InternetCrackUrlW( url, len, flags, components )))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
/* fix up an incompatibility between wininet and winhttp */
if (components->nScheme == SCHEME_HTTP) components->nScheme = INTERNET_SCHEME_HTTP;
else if (components->nScheme == SCHEME_HTTPS) components->nScheme = INTERNET_SCHEME_HTTPS;
else
{
set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
return FALSE;
}
}
/* TODO: read from HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings */
FIXME("returning no proxy used\n");
config->fAutoDetect = FALSE;
config->lpszAutoConfigUrl = NULL;
config->lpszProxy = NULL;
config->lpszProxyBypass = NULL;
SetLastError(ERROR_SUCCESS);
return TRUE;
return ret;
}
/***********************************************************************
* WinHttpOpen (winhttp.@)
* WinHttpCreateUrl (winhttp.@)
*/
HINTERNET WINAPI WinHttpOpen(LPCWSTR pwszUserAgent, DWORD dwAccessType,
LPCWSTR pwszProxyName, LPCWSTR pwszProxyByPass,
DWORD dwFlags)
BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS comps, DWORD flags, LPWSTR url, LPDWORD len )
{
FIXME("(%s, %d, %s, %s, 0x%x): stub\n", debugstr_w(pwszUserAgent),
dwAccessType, debugstr_w(pwszProxyName), debugstr_w(pwszProxyByPass),
dwFlags);
SetLastError(ERROR_NOT_SUPPORTED);
return NULL;
}
/***********************************************************************
* WinHttpConnect (winhttp.@)
*/
HINTERNET WINAPI WinHttpConnect (HINTERNET hSession, LPCWSTR pwszServerName,
INTERNET_PORT nServerPort, DWORD dwReserved)
{
FIXME("(%s, %d, 0x%x): stub\n", debugstr_w(pwszServerName), nServerPort, dwReserved);
SetLastError(ERROR_NOT_SUPPORTED);
return NULL;
}
/***********************************************************************
* WinHttpOpenRequest (winhttp.@)
*/
HINTERNET WINAPI WinHttpOpenRequest (HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName,
LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR* ppwszAcceptTypes,
DWORD dwFlags)
{
FIXME("(%s, %s, %s, %s, 0x%x): stub\n", debugstr_w(pwszVerb), debugstr_w(pwszObjectName),
debugstr_w(pwszVersion), debugstr_w(pwszReferrer), dwFlags);
SetLastError(ERROR_NOT_SUPPORTED);
return NULL;
}
/***********************************************************************
* 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)
{
FIXME("(%d): stub\n", dwOption);
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
/***********************************************************************
* WinHttpQueryDataAvailable (winhttp.@)
*/
BOOL WINAPI WinHttpQueryDataAvailable (HINTERNET hInternet, LPDWORD lpdwNumberOfBytesAvailable)
{
FIXME("stub\n");
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
/***********************************************************************
* WinHttpReceiveResponse (winhttp.@)
*/
BOOL WINAPI WinHttpReceiveResponse (HINTERNET hRequest, LPVOID lpReserved)
{
FIXME("stub\n");
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
/***********************************************************************
* WinHttpSetOption (winhttp.@)
*/
BOOL WINAPI WinHttpSetOption (HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength)
{
FIXME("stub\n");
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
/***********************************************************************
* WinHttpReadData (winhttp.@)
*/
BOOL WINAPI WinHttpReadData (HINTERNET hInternet, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead,
LPDWORD lpdwNumberOfBytesRead)
{
FIXME("(%d): stub\n", dwNumberOfBytesToRead);
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
/***********************************************************************
* WinHttpReadData (winhttp.@)
*/
BOOL WINAPI WinHttpCloseHandle (HINTERNET hInternet)
{
FIXME("stub\n");
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
TRACE("%p, 0x%08x, %p, %p\n", comps, flags, url, len);
return InternetCreateUrlW( comps, flags, url, len );
}

View file

@ -0,0 +1,626 @@
/*
* Copyright 2008 Hans Leidekker for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#ifdef HAVE_POLL_H
# include <poll.h>
#endif
#ifdef HAVE_OPENSSL_SSL_H
# include <openssl/ssl.h>
#undef FAR
#undef DSA
#endif
#include "wine/debug.h"
#include "wine/library.h"
#include "windef.h"
#include "winbase.h"
#include "winhttp.h"
/* to avoid conflicts with the Unix socket headers */
#define USE_WS_PREFIX
#include "winsock2.h"
#include "winhttp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
#define DEFAULT_SEND_TIMEOUT 30
#define DEFAULT_RECEIVE_TIMEOUT 30
#define RESPONSE_TIMEOUT 30
#ifndef HAVE_GETADDRINFO
/* critical section to protect non-reentrant gethostbyname() */
static CRITICAL_SECTION cs_gethostbyname;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &cs_gethostbyname,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": cs_gethostbyname") }
};
static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
#endif
#ifdef SONAME_LIBSSL
#include <openssl/err.h>
static void *libssl_handle;
static void *libcrypto_handle;
static SSL_METHOD *method;
#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_new );
MAKE_FUNCPTR( SSL_CTX_free );
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_get_verify_result );
MAKE_FUNCPTR( SSL_get_peer_certificate );
MAKE_FUNCPTR( SSL_CTX_get_timeout );
MAKE_FUNCPTR( SSL_CTX_set_timeout );
MAKE_FUNCPTR( SSL_CTX_set_default_verify_paths );
MAKE_FUNCPTR( BIO_new_fp );
MAKE_FUNCPTR( ERR_get_error );
MAKE_FUNCPTR( ERR_error_string );
#undef MAKE_FUNCPTR
#endif
#if 0
/* translate a unix error code into a winsock error code */
static int sock_get_error( int err )
{
switch (err)
{
case EINTR: return WSAEINTR;
case EBADF: return WSAEBADF;
case EPERM:
case EACCES: return WSAEACCES;
case EFAULT: return WSAEFAULT;
case EINVAL: return WSAEINVAL;
case EMFILE: return WSAEMFILE;
case EWOULDBLOCK: return WSAEWOULDBLOCK;
case EINPROGRESS: return WSAEINPROGRESS;
case EALREADY: return WSAEALREADY;
case ENOTSOCK: return WSAENOTSOCK;
case EDESTADDRREQ: return WSAEDESTADDRREQ;
case EMSGSIZE: return WSAEMSGSIZE;
case EPROTOTYPE: return WSAEPROTOTYPE;
case ENOPROTOOPT: return WSAENOPROTOOPT;
case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
case EOPNOTSUPP: return WSAEOPNOTSUPP;
case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
case EADDRINUSE: return WSAEADDRINUSE;
case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
case ENETDOWN: return WSAENETDOWN;
case ENETUNREACH: return WSAENETUNREACH;
case ENETRESET: return WSAENETRESET;
case ECONNABORTED: return WSAECONNABORTED;
case EPIPE:
case ECONNRESET: return WSAECONNRESET;
case ENOBUFS: return WSAENOBUFS;
case EISCONN: return WSAEISCONN;
case ENOTCONN: return WSAENOTCONN;
case ESHUTDOWN: return WSAESHUTDOWN;
case ETOOMANYREFS: return WSAETOOMANYREFS;
case ETIMEDOUT: return WSAETIMEDOUT;
case ECONNREFUSED: return WSAECONNREFUSED;
case ELOOP: return WSAELOOP;
case ENAMETOOLONG: return WSAENAMETOOLONG;
case EHOSTDOWN: return WSAEHOSTDOWN;
case EHOSTUNREACH: return WSAEHOSTUNREACH;
case ENOTEMPTY: return WSAENOTEMPTY;
#ifdef EPROCLIM
case EPROCLIM: return WSAEPROCLIM;
#endif
#ifdef EUSERS
case EUSERS: return WSAEUSERS;
#endif
#ifdef EDQUOT
case EDQUOT: return WSAEDQUOT;
#endif
#ifdef ESTALE
case ESTALE: return WSAESTALE;
#endif
#ifdef EREMOTE
case EREMOTE: return WSAEREMOTE;
#endif
default: errno = err; perror( "sock_set_error" ); return WSAEFAULT;
}
return err;
}
#else
#define sock_get_error(x) WSAGetLastError()
#endif
BOOL netconn_init( netconn_t *conn, BOOL secure )
{
conn->socket = -1;
if (!secure) return TRUE;
#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
if (libssl_handle) 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 );
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 );
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 ); \
return FALSE; \
}
LOAD_FUNCPTR( SSL_library_init );
LOAD_FUNCPTR( SSL_load_error_strings );
LOAD_FUNCPTR( SSLv23_method );
LOAD_FUNCPTR( SSL_CTX_new );
LOAD_FUNCPTR( SSL_CTX_free );
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_get_verify_result );
LOAD_FUNCPTR( SSL_get_peer_certificate );
LOAD_FUNCPTR( SSL_CTX_get_timeout );
LOAD_FUNCPTR( SSL_CTX_set_timeout );
LOAD_FUNCPTR( SSL_CTX_set_default_verify_paths );
#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 ); \
return FALSE; \
}
LOAD_FUNCPTR( BIO_new_fp );
LOAD_FUNCPTR( ERR_get_error );
LOAD_FUNCPTR( ERR_error_string );
#undef LOAD_FUNCPTR
pSSL_library_init();
pSSL_load_error_strings();
pBIO_new_fp( stderr, BIO_NOCLOSE );
method = pSSLv23_method();
conn->ssl_ctx = pSSL_CTX_new( method );
#else
WARN("SSL support not compiled in.\n");
set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
return FALSE;
#endif
return TRUE;
}
BOOL netconn_connected( netconn_t *conn )
{
return (conn->socket != -1);
}
BOOL netconn_create( netconn_t *conn, int domain, int type, int protocol )
{
if ((conn->socket = socket( domain, type, protocol )) == -1)
{
WARN("unable to create socket (%s)\n", strerror(errno));
set_last_error( sock_get_error( errno ) );
return FALSE;
}
return TRUE;
}
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;
conn->secure = FALSE;
}
#endif
res = closesocket( conn->socket );
conn->socket = -1;
if (res == -1)
{
set_last_error( sock_get_error( errno ) );
return FALSE;
}
return TRUE;
}
BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len )
{
if (connect( conn->socket, sockaddr, addr_len ) == -1)
{
WARN("unable to connect to host (%s)\n", strerror(errno));
set_last_error( sock_get_error( errno ) );
return FALSE;
}
return TRUE;
}
BOOL netconn_secure_connect( netconn_t *conn )
{
#ifdef SONAME_LIBSSL
X509 *cert;
long res;
if (!pSSL_CTX_set_default_verify_paths( conn->ssl_ctx ))
{
ERR("SSL_CTX_set_default_verify_paths failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
set_last_error( ERROR_OUTOFMEMORY );
return FALSE;
}
if (!(conn->ssl_conn = pSSL_new( conn->ssl_ctx )))
{
ERR("SSL_new failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
set_last_error( ERROR_OUTOFMEMORY );
goto fail;
}
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)
{
ERR("SSL_connect failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
goto fail;
}
if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn )))
{
ERR("No certificate for server: %s\n", pERR_error_string( pERR_get_error(), 0 ));
set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
goto fail;
}
if ((res = pSSL_get_verify_result( conn->ssl_conn )) != X509_V_OK)
{
/* FIXME: we should set an error and return, but we only print an error at the moment */
ERR("couldn't verify server certificate (%ld)\n", res);
}
TRACE("established SSL connection\n");
conn->secure = TRUE;
return TRUE;
fail:
if (conn->ssl_conn)
{
pSSL_shutdown( conn->ssl_conn );
pSSL_free( conn->ssl_conn );
conn->ssl_conn = NULL;
}
#endif
return FALSE;
}
BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int *sent )
{
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;
return TRUE;
#else
return FALSE;
#endif
}
if ((*sent = send( conn->socket, msg, len, flags )) == -1)
{
set_last_error( sock_get_error( errno ) );
return FALSE;
}
return TRUE;
}
BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
{
*recvd = 0;
if (!netconn_connected( conn )) return FALSE;
if (!len) return TRUE;
if (conn->secure)
{
#ifdef SONAME_LIBSSL
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 (len < conn->peek_len) FIXME("buffer isn't big enough, should we wrap?\n");
*recvd = min( len, conn->peek_len );
memcpy( buf, conn->peek_msg, *recvd );
return TRUE;
}
else if (conn->peek_msg)
{
*recvd = min( len, conn->peek_len );
memcpy( buf, conn->peek_msg, *recvd );
conn->peek_len -= *recvd;
conn->peek_msg += *recvd;
if (conn->peek_len == 0)
{
heap_free( conn->peek_msg_mem );
conn->peek_msg_mem = NULL;
conn->peek_msg = NULL;
}
/* check if we have enough data from the peek buffer */
if (!(flags & MSG_WAITALL) || (*recvd == len)) return TRUE;
}
*recvd += pSSL_read( conn->ssl_conn, (char *)buf + *recvd, len - *recvd );
if (flags & MSG_PEEK) /* must copy into buffer */
{
conn->peek_len = *recvd;
if (!*recvd)
{
heap_free( conn->peek_msg_mem );
conn->peek_msg_mem = NULL;
conn->peek_msg = NULL;
}
else memcpy( conn->peek_msg, buf, *recvd );
}
if (*recvd < 1 && len) return FALSE;
return TRUE;
#else
return FALSE;
#endif
}
if ((*recvd = recv( conn->socket, buf, len, flags )) == -1)
{
set_last_error( sock_get_error( errno ) );
return FALSE;
}
return TRUE;
}
BOOL netconn_query_data_available( netconn_t *conn, DWORD *available )
{
#ifdef FIONREAD
int ret, unread;
#endif
*available = 0;
if (!netconn_connected( conn )) return FALSE;
if (conn->secure)
{
#ifdef SONAME_LIBSSL
if (conn->peek_msg) *available = conn->peek_len;
#endif
return TRUE;
}
#ifdef FIONREAD
if (!(ret = ioctlsocket( conn->socket, FIONREAD, &unread )))
{
TRACE("%d bytes of queued, but unread data\n", unread);
*available += unread;
}
#endif
return TRUE;
}
BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
{
struct timeval tv;
fd_set infd;
BOOL ret = FALSE;
DWORD recvd = 0;
if (!netconn_connected( conn )) return FALSE;
if (conn->secure)
{
#ifdef SONAME_LIBSSL
long timeout;
timeout = pSSL_CTX_get_timeout( conn->ssl_ctx );
pSSL_CTX_set_timeout( conn->ssl_ctx, DEFAULT_RECEIVE_TIMEOUT );
while (recvd < *buflen)
{
int dummy;
if (!netconn_recv( conn, &buffer[recvd], 1, 0, &dummy ))
{
set_last_error( ERROR_CONNECTION_ABORTED );
break;
}
if (buffer[recvd] == '\n')
{
ret = TRUE;
break;
}
if (buffer[recvd] != '\r') recvd++;
}
pSSL_CTX_set_timeout( conn->ssl_ctx, timeout );
if (ret)
{
buffer[recvd++] = 0;
*buflen = recvd;
TRACE("received line %s\n", debugstr_a(buffer));
}
return ret;
#else
return FALSE;
#endif
}
FD_ZERO(&infd);
FD_SET(conn->socket, &infd);
tv.tv_sec=RESPONSE_TIMEOUT;
tv.tv_usec=0;
while (recvd < *buflen)
{
if (select(conn->socket+1,&infd,NULL,NULL,&tv) > 0)
{
int res;
if ((res = recv( conn->socket, &buffer[recvd], 1, 0 )) <= 0)
{
if (res == -1) set_last_error( sock_get_error( errno ) );
break;
}
if (buffer[recvd] == '\n')
{
ret = TRUE;
break;
}
if (buffer[recvd] != '\r') recvd++;
}
else
{
set_last_error( ERROR_WINHTTP_TIMEOUT );
break;
}
}
if (ret)
{
buffer[recvd++] = 0;
*buflen = recvd;
TRACE("received line %s\n", debugstr_a(buffer));
}
return ret;
}
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, &tv, sizeof(tv) ) == -1))
{
WARN("setsockopt failed (%s)\n", strerror( errno ));
return sock_get_error( errno );
}
return ERROR_SUCCESS;
}
BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *sa )
{
char *hostname;
#ifdef HAVE_GETADDRINFO
struct addrinfo *res, hints;
int ret;
#else
struct hostent *he;
#endif
if (!(hostname = strdupWA( hostnameW ))) return FALSE;
#ifdef HAVE_GETADDRINFO
memset( &hints, 0, sizeof(struct addrinfo) );
hints.ai_family = AF_INET;
ret = getaddrinfo( hostname, NULL, &hints, &res );
heap_free( hostname );
if (ret != 0)
{
TRACE("failed to get address of %s (%s)\n", debugstr_a(hostname), gai_strerror(ret));
return FALSE;
}
memset( sa, 0, sizeof(struct sockaddr_in) );
memcpy( &sa->sin_addr, &((struct sockaddr_in *)res->ai_addr)->sin_addr, sizeof(struct in_addr) );
sa->sin_family = res->ai_family;
sa->sin_port = htons( port );
freeaddrinfo( res );
#else
EnterCriticalSection( &cs_gethostbyname );
he = gethostbyname( hostname );
heap_free( hostname );
if (!he)
{
TRACE("failed to get address of %s (%d)\n", debugstr_a(hostname), h_errno);
LeaveCriticalSection( &cs_gethostbyname );
return FALSE;
}
memset( sa, 0, sizeof(struct sockaddr_in) );
memcpy( (char *)&sa->sin_addr, he->h_addr, he->h_length );
sa->sin_family = he->h_addrtype;
sa->sin_port = htons( port );
LeaveCriticalSection( &cs_gethostbyname );
#endif
return TRUE;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,693 @@
/*
* Copyright 2008 Hans Leidekker for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include "wine/debug.h"
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winhttp.h"
#include "winhttp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
void set_last_error( DWORD error )
{
/* FIXME */
SetLastError( error );
}
void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
{
TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
if (hdr->notify_mask & status) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
}
/***********************************************************************
* WinHttpCheckPlatform (winhttp.@)
*/
BOOL WINAPI WinHttpCheckPlatform( void )
{
TRACE("\n");
return TRUE;
}
/***********************************************************************
* session_destroy (internal)
*/
static void session_destroy( object_header_t *hdr )
{
session_t *session = (session_t *)hdr;
TRACE("%p\n", session);
heap_free( session->agent );
heap_free( session->proxy_server );
heap_free( session->proxy_bypass );
heap_free( session->proxy_username );
heap_free( session->proxy_password );
heap_free( session );
}
static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
{
switch (option)
{
case WINHTTP_OPTION_PROXY:
{
WINHTTP_PROXY_INFO *pi = buffer;
FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
return TRUE;
}
case WINHTTP_OPTION_REDIRECT_POLICY:
{
DWORD policy = *(DWORD *)buffer;
TRACE("0x%x\n", policy);
hdr->redirect_policy = policy;
return TRUE;
}
default:
FIXME("unimplemented option %u\n", option);
return TRUE;
}
}
static const object_vtbl_t session_vtbl =
{
session_destroy,
NULL,
session_set_option
};
/***********************************************************************
* WinHttpOpen (winhttp.@)
*/
HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
{
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);
if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
session->hdr.vtbl = &session_vtbl;
session->hdr.flags = flags;
session->hdr.refs = 1;
session->access = access;
if (agent && !(session->agent = strdupW( agent ))) goto end;
if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
if (!(handle = alloc_handle( &session->hdr ))) goto end;
session->hdr.handle = handle;
end:
release_object( &session->hdr );
TRACE("returning %p\n", handle);
return handle;
}
/***********************************************************************
* connect_destroy (internal)
*/
static void connect_destroy( object_header_t *hdr )
{
connect_t *connect = (connect_t *)hdr;
TRACE("%p\n", connect);
release_object( &connect->session->hdr );
heap_free( connect->hostname );
heap_free( connect->servername );
heap_free( connect->username );
heap_free( connect->password );
heap_free( connect );
}
static const object_vtbl_t connect_vtbl =
{
connect_destroy,
NULL,
NULL
};
/***********************************************************************
* WinHttpConnect (winhttp.@)
*/
HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
{
connect_t *connect;
session_t *session;
HINTERNET hconnect = NULL;
TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
if (!server)
{
set_last_error( ERROR_INVALID_PARAMETER );
return NULL;
}
if (!(session = (session_t *)grab_object( hsession )))
{
set_last_error( ERROR_INVALID_HANDLE );
return NULL;
}
if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
{
release_object( &session->hdr );
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
return NULL;
}
if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
{
release_object( &session->hdr );
return NULL;
}
connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
connect->hdr.vtbl = &connect_vtbl;
connect->hdr.refs = 1;
connect->hdr.flags = session->hdr.flags;
connect->hdr.callback = session->hdr.callback;
connect->hdr.notify_mask = session->hdr.notify_mask;
connect->hdr.context = session->hdr.context;
addref_object( &session->hdr );
connect->session = session;
list_add_head( &session->hdr.children, &connect->hdr.entry );
if (server && !(connect->hostname = strdupW( server ))) goto end;
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;
send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
end:
release_object( &connect->hdr );
TRACE("returning %p\n", hconnect);
return hconnect;
}
/***********************************************************************
* request_destroy (internal)
*/
static void request_destroy( object_header_t *hdr )
{
request_t *request = (request_t *)hdr;
int i;
TRACE("%p\n", request);
release_object( &request->connect->hdr );
heap_free( request->verb );
heap_free( request->path );
heap_free( request->version );
heap_free( request->raw_headers );
heap_free( request->status_text );
for (i = 0; i < request->num_headers; i++)
{
heap_free( request->headers[i].field );
heap_free( request->headers[i].value );
}
heap_free( request->headers );
heap_free( request );
}
static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
{
switch (option)
{
case WINHTTP_OPTION_SECURITY_FLAGS:
{
DWORD flags = 0;
if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
*(DWORD *)buffer = flags;
*buflen = sizeof(DWORD);
return TRUE;
}
default:
FIXME("unimplemented option %u\n", option);
return FALSE;
}
}
static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
{
switch (option)
{
case WINHTTP_OPTION_PROXY:
{
WINHTTP_PROXY_INFO *pi = buffer;
FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
return TRUE;
}
case WINHTTP_OPTION_DISABLE_FEATURE:
{
DWORD disable = *(DWORD *)buffer;
TRACE("0x%x\n", disable);
hdr->disable_flags &= disable;
return TRUE;
}
case WINHTTP_OPTION_AUTOLOGON_POLICY:
{
DWORD policy = *(DWORD *)buffer;
TRACE("0x%x\n", policy);
hdr->logon_policy = policy;
return TRUE;
}
case WINHTTP_OPTION_REDIRECT_POLICY:
{
DWORD policy = *(DWORD *)buffer;
TRACE("0x%x\n", policy);
hdr->redirect_policy = policy;
return TRUE;
}
default:
FIXME("unimplemented option %u\n", option);
return TRUE;
}
}
static const object_vtbl_t request_vtbl =
{
request_destroy,
request_query_option,
request_set_option
};
/***********************************************************************
* WinHttpOpenRequest (winhttp.@)
*/
HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
LPCWSTR referrer, LPCWSTR *types, DWORD flags )
{
request_t *request;
connect_t *connect;
HINTERNET hrequest = NULL;
TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
debugstr_w(version), debugstr_w(referrer), types, flags);
if (!(connect = (connect_t *)grab_object( hconnect )))
{
set_last_error( ERROR_INVALID_HANDLE );
return NULL;
}
if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
{
release_object( &connect->hdr );
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
return NULL;
}
if (!(request = heap_alloc_zero( sizeof(request_t) )))
{
release_object( &connect->hdr );
return NULL;
}
request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
request->hdr.vtbl = &request_vtbl;
request->hdr.refs = 1;
request->hdr.flags = flags;
request->hdr.callback = connect->hdr.callback;
request->hdr.notify_mask = connect->hdr.notify_mask;
request->hdr.context = connect->hdr.context;
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 (verb && !(request->verb = strdupW( verb ))) goto end;
if (object && !(request->path = strdupW( object ))) goto end;
if (version && !(request->version = strdupW( version ))) goto end;
if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
request->hdr.handle = hrequest;
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
end:
release_object( &request->hdr );
TRACE("returning %p\n", hrequest);
return hrequest;
}
/***********************************************************************
* WinHttpCloseHandle (winhttp.@)
*/
BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
{
object_header_t *hdr;
TRACE("%p\n", handle);
if (!(hdr = grab_object( handle )))
{
set_last_error( ERROR_INVALID_HANDLE );
return FALSE;
}
release_object( hdr );
free_handle( handle );
return TRUE;
}
static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
{
BOOL ret = FALSE;
switch (option)
{
case WINHTTP_OPTION_CONTEXT_VALUE:
{
*(DWORD_PTR *)buffer = hdr->context;
*buflen = sizeof(DWORD_PTR);
return TRUE;
}
default:
{
if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
else FIXME("unimplemented option %u\n", option);
}
}
return ret;
}
/***********************************************************************
* WinHttpQueryOption (winhttp.@)
*/
BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
{
BOOL ret = FALSE;
object_header_t *hdr;
TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
if (!(hdr = grab_object( handle )))
{
set_last_error( ERROR_INVALID_HANDLE );
return FALSE;
}
ret = query_option( hdr, option, buffer, buflen );
release_object( hdr );
return ret;
}
static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
{
BOOL ret = TRUE;
switch (option)
{
case WINHTTP_OPTION_CONTEXT_VALUE:
{
hdr->context = *(DWORD_PTR *)buffer;
return TRUE;
}
default:
{
if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
else FIXME("unimplemented option %u\n", option);
}
}
return ret;
}
/***********************************************************************
* WinHttpSetOption (winhttp.@)
*/
BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
{
BOOL ret = FALSE;
object_header_t *hdr;
TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
if (!(hdr = grab_object( handle )))
{
set_last_error( ERROR_INVALID_HANDLE );
return FALSE;
}
ret = set_option( hdr, option, buffer, buflen );
release_object( hdr );
return ret;
}
/***********************************************************************
* WinHttpDetectAutoProxyConfigUrl (winhttp.@)
*/
BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
{
FIXME("0x%08x, %p\n", flags, url);
set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
return FALSE;
}
/***********************************************************************
* WinHttpGetDefaultProxyConfiguration (winhttp.@)
*/
BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
{
FIXME("%p\n", info);
info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
info->lpszProxy = NULL;
info->lpszProxyBypass = NULL;
return TRUE;
}
/***********************************************************************
* WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
*/
BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
{
TRACE("%p\n", config);
if (!config)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* FIXME: read from HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings */
FIXME("returning no proxy used\n");
config->fAutoDetect = FALSE;
config->lpszAutoConfigUrl = NULL;
config->lpszProxy = NULL;
config->lpszProxyBypass = NULL;
return TRUE;
}
/***********************************************************************
* WinHttpGetProxyForUrl (winhttp.@)
*/
BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
WINHTTP_PROXY_INFO *info )
{
FIXME("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
return FALSE;
}
/***********************************************************************
* WinHttpSetDefaultProxyConfiguration (winhttp.@)
*/
BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
{
FIXME("%p [%u, %s, %s]\n", info, info->dwAccessType, debugstr_w(info->lpszProxy),
debugstr_w(info->lpszProxyBypass));
return TRUE;
}
/***********************************************************************
* WinHttpSetStatusCallback (winhttp.@)
*/
WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
DWORD flags, DWORD_PTR reserved )
{
object_header_t *hdr;
WINHTTP_STATUS_CALLBACK ret;
TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
if (!(hdr = grab_object( handle )))
{
set_last_error( ERROR_INVALID_HANDLE );
return WINHTTP_INVALID_STATUS_CALLBACK;
}
ret = hdr->callback;
hdr->callback = callback;
hdr->notify_mask = flags;
release_object( hdr );
return ret;
}
/***********************************************************************
* WinHttpSetTimeouts (winhttp.@)
*/
BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
{
FIXME("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
return TRUE;
}
static const WCHAR wkday[7][4] =
{{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
{'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
static const WCHAR month[12][4] =
{{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
{'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
{'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
/***********************************************************************
* WinHttpTimeFromSystemTime (WININET.@)
*/
BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
{
static const WCHAR format[] =
{'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
'2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
TRACE("%p, %p\n", time, string);
if (!time || !string) return FALSE;
sprintfW( string, format,
wkday[time->wDayOfWeek],
time->wDay,
month[time->wMonth - 1],
time->wYear,
time->wHour,
time->wMinute,
time->wSecond );
return TRUE;
}
/***********************************************************************
* WinHttpTimeToSystemTime (WININET.@)
*/
BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
{
unsigned int i;
const WCHAR *s = string;
WCHAR *end;
TRACE("%s, %p\n", debugstr_w(string), time);
if (!string || !time) return FALSE;
/* Windows does this too */
GetSystemTime( time );
/* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
* a SYSTEMTIME structure.
*/
while (*s && !isalphaW( *s )) s++;
if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
time->wDayOfWeek = 7;
for (i = 0; i < 7; i++)
{
if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
toupperW( wkday[i][2] ) == toupperW( s[2] ) )
{
time->wDayOfWeek = i;
break;
}
}
if (time->wDayOfWeek > 6) return TRUE;
while (*s && !isdigitW( *s )) s++;
time->wDay = strtolW( s, &end, 10 );
s = end;
while (*s && !isalphaW( *s )) s++;
if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
time->wMonth = 0;
for (i = 0; i < 12; i++)
{
if (toupperW( month[i][0]) == toupperW( s[0] ) &&
toupperW( month[i][1]) == toupperW( s[1] ) &&
toupperW( month[i][2]) == toupperW( s[2] ) )
{
time->wMonth = i + 1;
break;
}
}
if (time->wMonth == 0) return TRUE;
while (*s && !isdigitW( *s )) s++;
if (*s == '\0') return TRUE;
time->wYear = strtolW( s, &end, 10 );
s = end;
while (*s && !isdigitW( *s )) s++;
if (*s == '\0') return TRUE;
time->wHour = strtolW( s, &end, 10 );
s = end;
while (*s && !isdigitW( *s )) s++;
if (*s == '\0') return TRUE;
time->wMinute = strtolW( s, &end, 10 );
s = end;
while (*s && !isdigitW( *s )) s++;
if (*s == '\0') return TRUE;
time->wSecond = strtolW( s, &end, 10 );
s = end;
time->wMilliseconds = 0;
return TRUE;
}

View file

@ -9,9 +9,15 @@
<define name="__WINESRC__" />
<define name="WINVER">0x600</define>
<define name="_WIN32_WINNT">0x600</define>
<file>handle.c</file>
<file>main.c</file>
<file>net.c</file>
<file>request.c</file>
<file>session.c</file>
<file>winhttp.spec</file>
<library>wine</library>
<library>wininet</library>
<library>ws2_32</library>
<library>kernel32</library>
<library>ntdll</library>
</module>

View file

@ -2,30 +2,30 @@
@ stdcall -private DllGetClassObject(ptr ptr ptr)
@ stdcall -private DllRegisterServer()
@ stdcall -private DllUnregisterServer()
@ stub WinHttpAddRequestHeaders
@ stdcall WinHttpAddRequestHeaders(ptr wstr long long)
@ stdcall WinHttpCheckPlatform()
@ stdcall WinHttpCloseHandle(ptr)
@ stdcall WinHttpConnect(ptr wstr long long)
@ stub WinHttpCrackUrl
@ stub WinHttpCreateUrl
@ stdcall WinHttpCrackUrl(wstr long long ptr)
@ stdcall WinHttpCreateUrl(ptr long ptr ptr)
@ stdcall WinHttpDetectAutoProxyConfigUrl(long ptr)
@ stub WinHttpGetDefaultProxyConfiguration
@ stdcall WinHttpGetDefaultProxyConfiguration(ptr)
@ stdcall WinHttpGetIEProxyConfigForCurrentUser(ptr)
@ stub WinHttpGetProxyForUrl
@ stdcall WinHttpGetProxyForUrl(ptr wstr ptr ptr)
@ stdcall WinHttpOpen(wstr long wstr wstr long)
@ stdcall WinHttpOpenRequest(ptr wstr wstr wstr wstr ptr long)
@ stub WinHttpQueryAuthSchemes
@ stdcall WinHttpQueryAuthSchemes(ptr ptr ptr ptr)
@ stdcall WinHttpQueryDataAvailable(ptr ptr)
@ stub WinHttpQueryHeaders
@ stdcall WinHttpQueryHeaders(ptr long wstr ptr ptr ptr)
@ stdcall WinHttpQueryOption(ptr long ptr ptr)
@ stdcall WinHttpReadData(ptr ptr long ptr)
@ stdcall WinHttpReceiveResponse(ptr ptr)
@ stdcall WinHttpSendRequest(ptr wstr long ptr long long ptr)
@ stub WinHttpSetCredentials
@ stub WinHttpSetDefaultProxyConfiguration
@ stdcall WinHttpSetCredentials(ptr long long wstr ptr ptr)
@ stdcall WinHttpSetDefaultProxyConfiguration(ptr)
@ stdcall WinHttpSetOption(ptr long ptr long)
@ stub WinHttpSetStatusCallback
@ stub WinHttpSetTimeouts
@ stub WinHttpTimeFromSystemTime
@ stub WinHttpTimeToSystemTime
@ stub WinHttpWriteData
@ stdcall WinHttpSetStatusCallback(ptr ptr long ptr)
@ stdcall WinHttpSetTimeouts(ptr long long long long)
@ stdcall WinHttpTimeFromSystemTime(ptr ptr)
@ stdcall WinHttpTimeToSystemTime(wstr ptr)
@ stdcall WinHttpWriteData(ptr ptr long ptr)

View file

@ -0,0 +1,211 @@
/*
* Copyright 2008 Hans Leidekker for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _WINE_WINHTTP_PRIVATE_H_
#define _WINE_WINHTTP_PRIVATE_H_
#ifndef __WINE_CONFIG_H
# error You must include config.h to use this header
#endif
#include "wine/list.h"
#include "wine/unicode.h"
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#if defined(__MINGW32__) || defined (_MSC_VER)
# include "ws2tcpip.h"
# ifndef MSG_WAITALL
# define MSG_WAITALL 0
# endif
#else
# define closesocket close
# define ioctlsocket ioctl
#endif /* __MINGW32__ */
typedef struct _object_header_t object_header_t;
typedef struct
{
void (*destroy)( object_header_t * );
BOOL (*query_option)( object_header_t *, DWORD, void *, DWORD * );
BOOL (*set_option)( object_header_t *, DWORD, void *, DWORD );
} object_vtbl_t;
struct _object_header_t
{
DWORD type;
HINTERNET handle;
const object_vtbl_t *vtbl;
DWORD flags;
DWORD disable_flags;
DWORD logon_policy;
DWORD redirect_policy;
DWORD error;
DWORD_PTR context;
LONG refs;
WINHTTP_STATUS_CALLBACK callback;
DWORD notify_mask;
struct list entry;
struct list children;
};
typedef struct
{
object_header_t hdr;
LPWSTR agent;
DWORD access;
LPWSTR proxy_server;
LPWSTR proxy_bypass;
LPWSTR proxy_username;
LPWSTR proxy_password;
} session_t;
typedef struct
{
object_header_t hdr;
session_t *session;
LPWSTR hostname; /* final destination of the request */
LPWSTR servername; /* name of the server we directly connect to */
LPWSTR username;
LPWSTR password;
INTERNET_PORT hostport;
INTERNET_PORT serverport;
struct sockaddr_in sockaddr;
} connect_t;
typedef struct
{
int socket;
BOOL secure; /* SSL active on connection? */
void *ssl_ctx;
void *ssl_conn;
char *peek_msg;
char *peek_msg_mem;
size_t peek_len;
} netconn_t;
typedef struct
{
LPWSTR field;
LPWSTR value;
BOOL is_request; /* part of request headers? */
} header_t;
typedef struct
{
object_header_t hdr;
connect_t *connect;
LPWSTR verb;
LPWSTR path;
LPWSTR version;
LPWSTR raw_headers;
netconn_t netconn;
LPWSTR status_text;
DWORD content_length; /* total number of bytes to be read (per chunk) */
DWORD content_read; /* bytes read so far */
header_t *headers;
DWORD num_headers;
} request_t;
object_header_t *addref_object( object_header_t * );
object_header_t *grab_object( HINTERNET );
void release_object( object_header_t * );
HINTERNET alloc_handle( object_header_t * );
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 );
BOOL netconn_connected( netconn_t * );
BOOL netconn_create( netconn_t *, int, int, int );
BOOL netconn_get_next_line( netconn_t *, char *, DWORD * );
BOOL netconn_init( netconn_t *, BOOL );
BOOL netconn_query_data_available( netconn_t *, DWORD * );
BOOL netconn_recv( netconn_t *, void *, size_t, int, int * );
BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_in * );
BOOL netconn_secure_connect( netconn_t * );
BOOL netconn_send( netconn_t *, const void *, size_t, int, int * );
static inline void *heap_alloc( SIZE_T size )
{
return HeapAlloc( GetProcessHeap(), 0, size );
}
static inline void *heap_alloc_zero( SIZE_T size )
{
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
}
static inline void *heap_realloc( LPVOID mem, SIZE_T size )
{
return HeapReAlloc( GetProcessHeap(), 0, mem, size );
}
static inline void *heap_realloc_zero( LPVOID mem, SIZE_T size )
{
return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size );
}
static inline BOOL heap_free( LPVOID mem )
{
return HeapFree( GetProcessHeap(), 0, mem );
}
static inline WCHAR *strdupW( const WCHAR *src )
{
WCHAR *dst;
if (!src) return NULL;
dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) );
if (dst) strcpyW( dst, 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;
if (src)
{
int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL );
if ((dst = heap_alloc( len )))
WideCharToMultiByte( CP_ACP, 0, src, -1, dst, len, NULL, NULL );
}
return dst;
}
#endif /* _WINE_WINHTTP_PRIVATE_H_ */

View file

@ -0,0 +1,103 @@
--- net.c Wed Sep 03 14:46:10 2008
+++ net.c Sun Sep 07 10:54:26 2008
@@ -59,6 +59,7 @@
#define DEFAULT_SEND_TIMEOUT 30
#define DEFAULT_RECEIVE_TIMEOUT 30
+#define RESPONSE_TIMEOUT 30
#ifndef HAVE_GETADDRINFO
@@ -110,6 +111,7 @@
#endif
+#if 0
/* translate a unix error code into a winsock error code */
static int sock_get_error( int err )
{
@@ -174,6 +176,9 @@
}
return err;
}
+#else
+#define sock_get_error(x) WSAGetLastError()
+#endif
BOOL netconn_init( netconn_t *conn, BOOL secure )
{
@@ -282,7 +287,7 @@
conn->secure = FALSE;
}
#endif
- res = close( conn->socket );
+ res = closesocket( conn->socket );
conn->socket = -1;
if (res == -1)
{
@@ -463,7 +468,7 @@
return TRUE;
}
#ifdef FIONREAD
- if (!(ret = ioctl( conn->socket, FIONREAD, &unread )))
+ if (!(ret = ioctlsocket( conn->socket, FIONREAD, &unread )))
{
TRACE("%d bytes of queued, but unread data\n", unread);
*available += unread;
@@ -474,7 +479,8 @@
BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
{
- struct pollfd pfd;
+ struct timeval tv;
+ fd_set infd;
BOOL ret = FALSE;
DWORD recvd = 0;
@@ -516,11 +522,13 @@
#endif
}
- pfd.fd = conn->socket;
- pfd.events = POLLIN;
+ FD_ZERO(&infd);
+ FD_SET(conn->socket, &infd);
+ tv.tv_sec=RESPONSE_TIMEOUT;
+ tv.tv_usec=0;
while (recvd < *buflen)
{
- if (poll( &pfd, 1, DEFAULT_RECEIVE_TIMEOUT * 1000 ) > 0)
+ if (select(conn->socket+1,&infd,NULL,NULL,&tv) > 0)
{
int res;
if ((res = recv( conn->socket, &buffer[recvd], 1, 0 )) <= 0)
--- request.c Fri Sep 05 17:34:17 2008
+++ request.c Sun Sep 07 10:55:25 2008
@@ -34,6 +34,8 @@
#include "winhttp_private.h"
+#include "inet_ntop.c"
+
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0};
--- winhttp_private.h Thu Sep 04 15:27:29 2008
+++ winhttp_private.h Sun Sep 07 10:46:54 2008
@@ -33,8 +33,14 @@
# include <netdb.h>
#endif
#if defined(__MINGW32__) || defined (_MSC_VER)
-# include <ws2tcpip.h>
-#endif
+# include "ws2tcpip.h"
+# ifndef MSG_WAITALL
+# define MSG_WAITALL 0
+# endif
+#else
+# define closesocket close
+# define ioctlsocket ioctl
+#endif /* __MINGW32__ */
typedef struct _object_header_t object_header_t;