- Sync to WINE 1.3.4
[WININET]
- Add a forgotten change to the diff
[WINHTTP]
- Sync to WINE 1.3.4
- Sync the inet_ntop.c change from wininet
- Update the diff

svn path=/trunk/; revision=49083
This commit is contained in:
Cameron Gutman 2010-10-09 21:52:25 +00:00
parent efe34232b4
commit 411c11b801
22 changed files with 5992 additions and 1015 deletions

View file

@ -1077,8 +1077,11 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres
}
if(This->to_object) {
if(!(This->state & BINDING_OBJAVAIL))
if(!(This->state & BINDING_OBJAVAIL)) {
IBinding_AddRef(BINDING(This));
create_object(This);
IBinding_Release(BINDING(This));
}
}else {
STGMEDIUM stgmed;
HRESULT hres;
@ -1519,7 +1522,7 @@ static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, I
}
if(binding_ctx) {
set_binding_sink(binding->protocol, PROTSINK(binding));
set_binding_sink(binding->protocol, PROTSINK(binding), BINDINF(binding));
if(binding_ctx->redirect_url)
IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_REDIRECTING, binding_ctx->redirect_url);
report_data(binding, 0, 0, 0);

View file

@ -382,7 +382,7 @@ static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
if(This->filter_proxy)
IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
set_binding_sink(PROTOCOL(This), NULL);
set_binding_sink(PROTOCOL(This), NULL, NULL);
if(This->notif_hwnd)
release_notif_hwnd(This->notif_hwnd);
@ -488,7 +488,7 @@ static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
return IInternetProtocol_UnlockRequest(This->protocol_handler);
}
void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
{
BindProtocol *This = PROTOCOL_THIS(bind_protocol);
IInternetProtocolSink *prev_sink;
@ -505,6 +505,12 @@ void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *s
service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
if(service_provider)
IServiceProvider_Release(service_provider);
if(bind_info)
IInternetBindInfo_AddRef(bind_info);
bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
if(bind_info)
IInternetBindInfo_Release(bind_info);
}
IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
@ -619,10 +625,7 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
if(urlmon_protocol)
IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
IInternetBindInfo_AddRef(pOIBindInfo);
This->bind_info = pOIBindInfo;
set_binding_sink(PROTOCOL(This), pOIProtSink);
set_binding_sink(PROTOCOL(This), pOIProtSink, pOIBindInfo);
hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
if(SUCCEEDED(hres)) {
@ -670,7 +673,7 @@ static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD
This->filter_proxy = NULL;
}
set_binding_sink(PROTOCOL(This), NULL);
set_binding_sink(PROTOCOL(This), NULL, NULL);
if(This->bind_info) {
IInternetBindInfo_Release(This->bind_info);

View file

@ -119,22 +119,22 @@ static HRESULT WINAPI DownloadBSC_OnLowResource(IBindStatusCallback *iface, DWOR
return E_NOTIMPL;
}
static void on_progress(DownloadBSC *This, ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text)
static HRESULT on_progress(DownloadBSC *This, ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text)
{
HRESULT hres;
if(!This->callback)
return;
return S_OK;
hres = IBindStatusCallback_OnProgress(This->callback, progress, progress_max, status_code, status_text);
if(FAILED(hres))
FIXME("OnProgress failed: %08x\n", hres);
return hres;
}
static HRESULT WINAPI DownloadBSC_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
{
DownloadBSC *This = STATUSCLB_THIS(iface);
HRESULT hres = S_OK;
TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
debugstr_w(szStatusText));
@ -146,11 +146,11 @@ static HRESULT WINAPI DownloadBSC_OnProgress(IBindStatusCallback *iface, ULONG u
case BINDSTATUS_ENDDOWNLOADDATA:
case BINDSTATUS_SENDINGREQUEST:
case BINDSTATUS_MIMETYPEAVAILABLE:
on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText);
hres = on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText);
break;
case BINDSTATUS_CACHEFILENAMEAVAILABLE:
on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText);
hres = on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText);
This->cache_file = heap_strdupW(szStatusText);
break;
@ -161,7 +161,7 @@ static HRESULT WINAPI DownloadBSC_OnProgress(IBindStatusCallback *iface, ULONG u
FIXME("Unsupported status %u\n", ulStatusCode);
}
return S_OK;
return hres;
}
static HRESULT WINAPI DownloadBSC_OnStopBinding(IBindStatusCallback *iface,

View file

@ -17,38 +17,46 @@
*/
#include "urlmon_main.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
typedef struct {
const IInternetProtocolVtbl *lpIInternetProtocolVtbl;
const IInternetPriorityVtbl *lpInternetPriorityVtbl;
const IInternetProtocolExVtbl *lpIInternetProtocolExVtbl;
const IInternetPriorityVtbl *lpInternetPriorityVtbl;
HANDLE file;
ULONG size;
LONG priority;
LONG ref;
} FileProtocol;
#define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
#define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
#define PROTOCOLEX(x) ((IInternetProtocolEx*) &(x)->lpIInternetProtocolExVtbl)
#define PROTOCOL_THIS(iface) DEFINE_THIS(FileProtocol, IInternetProtocol, iface)
#define PROTOCOL_THIS(iface) DEFINE_THIS(FileProtocol, IInternetProtocolEx, iface)
static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
{
FileProtocol *This = PROTOCOL_THIS(iface);
*ppv = NULL;
if(IsEqualGUID(&IID_IUnknown, riid)) {
TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
*ppv = PROTOCOL(This);
*ppv = PROTOCOLEX(This);
}else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
*ppv = PROTOCOL(This);
*ppv = PROTOCOLEX(This);
}else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
*ppv = PROTOCOL(This);
*ppv = PROTOCOLEX(This);
}else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
*ppv = PROTOCOLEX(This);
}else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
*ppv = PRIORITY(This);
@ -63,7 +71,7 @@ static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocol *iface, REFI
return E_NOINTERFACE;
}
static ULONG WINAPI FileProtocol_AddRef(IInternetProtocol *iface)
static ULONG WINAPI FileProtocol_AddRef(IInternetProtocolEx *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
LONG ref = InterlockedIncrement(&This->ref);
@ -71,7 +79,7 @@ static ULONG WINAPI FileProtocol_AddRef(IInternetProtocol *iface)
return ref;
}
static ULONG WINAPI FileProtocol_Release(IInternetProtocol *iface)
static ULONG WINAPI FileProtocol_Release(IInternetProtocolEx *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
LONG ref = InterlockedDecrement(&This->ref);
@ -79,7 +87,7 @@ static ULONG WINAPI FileProtocol_Release(IInternetProtocol *iface)
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
if(This->file)
if(This->file != INVALID_HANDLE_VALUE)
CloseHandle(This->file);
heap_free(This);
@ -89,27 +97,168 @@ static ULONG WINAPI FileProtocol_Release(IInternetProtocol *iface)
return ref;
}
static HRESULT WINAPI FileProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
static HRESULT WINAPI FileProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
DWORD grfPI, HANDLE_PTR dwReserved)
{
FileProtocol *This = PROTOCOL_THIS(iface);
BINDINFO bindinfo;
DWORD grfBINDF = 0;
LARGE_INTEGER size;
DWORD len;
LPWSTR url, mime = NULL, file_name;
WCHAR null_char = 0;
BOOL first_call = FALSE;
IUri *uri;
HRESULT hres;
static const WCHAR wszFile[] = {'f','i','l','e',':'};
TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
pOIBindInfo, grfPI, dwReserved);
if(!szUrl || strlenW(szUrl) < sizeof(wszFile)/sizeof(WCHAR)
|| memcmp(szUrl, wszFile, sizeof(wszFile)))
hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
if(FAILED(hres))
return hres;
hres = IInternetProtocolEx_StartEx(PROTOCOLEX(This), uri, pOIProtSink, pOIBindInfo,
grfPI, (HANDLE*)dwReserved);
IUri_Release(uri);
return hres;
}
static HRESULT WINAPI FileProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)->(%p)\n", This, pProtocolData);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
DWORD dwOptions)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
{
FileProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)->(%08x)\n", This, dwOptions);
return S_OK;
}
static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocolEx *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Resume(IInternetProtocolEx *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Read(IInternetProtocolEx *iface, void *pv,
ULONG cb, ULONG *pcbRead)
{
FileProtocol *This = PROTOCOL_THIS(iface);
DWORD read = 0;
TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
if (pcbRead)
*pcbRead = 0;
if(This->file == INVALID_HANDLE_VALUE)
return INET_E_DATA_NOT_AVAILABLE;
if (!ReadFile(This->file, pv, cb, &read, NULL))
return INET_E_DOWNLOAD_FAILURE;
if(pcbRead)
*pcbRead = read;
return cb == read ? S_OK : S_FALSE;
}
static HRESULT WINAPI FileProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
{
FileProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)->(%08x)\n", This, dwOptions);
return S_OK;
}
static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocolEx *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)\n", This);
return S_OK;
}
static inline HRESULT report_result(IInternetProtocolSink *protocol_sink, HRESULT hres, DWORD res)
{
IInternetProtocolSink_ReportResult(protocol_sink, hres, res, NULL);
return hres;
}
static HRESULT open_file(FileProtocol *This, const WCHAR *path, IInternetProtocolSink *protocol_sink)
{
LARGE_INTEGER size;
HANDLE file;
file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(file == INVALID_HANDLE_VALUE)
return report_result(protocol_sink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
if(!GetFileSizeEx(file, &size)) {
CloseHandle(file);
return report_result(protocol_sink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
}
This->file = file;
This->size = size.u.LowPart;
IInternetProtocolSink_ReportProgress(protocol_sink,
BINDSTATUS_CACHEFILENAMEAVAILABLE, path);
return S_OK;
}
static HRESULT WINAPI FileProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
DWORD grfPI, HANDLE *dwReserved)
{
FileProtocol *This = PROTOCOL_THIS(iface);
BINDINFO bindinfo;
DWORD grfBINDF = 0;
DWORD scheme;
LPWSTR mime = NULL;
WCHAR null_char = 0;
BSTR path, url;
HRESULT hres;
TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink,
pOIBindInfo, grfPI, dwReserved);
if(!pUri)
return E_INVALIDARG;
scheme = 0;
hres = IUri_GetScheme(pUri, &scheme);
if(FAILED(hres))
return hres;
if(scheme != URL_SCHEME_FILE)
return E_INVALIDARG;
memset(&bindinfo, 0, sizeof(bindinfo));
@ -122,170 +271,52 @@ static HRESULT WINAPI FileProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl
ReleaseBindInfo(&bindinfo);
len = lstrlenW(szUrl)+16;
url = heap_alloc(len*sizeof(WCHAR));
hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
if(FAILED(hres)) {
heap_free(url);
return hres;
}
if(!(grfBINDF & BINDF_FROMURLMON))
IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL);
if(!This->file) {
WCHAR *ptr;
if(This->file != INVALID_HANDLE_VALUE) {
IInternetProtocolSink_ReportData(pOIProtSink,
BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
This->size, This->size);
return S_OK;
}
first_call = TRUE;
IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, &null_char);
IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, &null_char);
hres = IUri_GetPath(pUri, &path);
if(FAILED(hres)) {
ERR("GetPath failed: %08x\n", hres);
return report_result(pOIProtSink, hres, 0);
}
file_name = url+sizeof(wszFile)/sizeof(WCHAR);
/* Strip both forward and back slashes */
if( (file_name[0] == '/' && file_name[1] == '/') ||
(file_name[0] == '\\' && file_name[1] == '\\'))
file_name += 2;
if(*file_name == '/')
file_name++;
for(ptr = file_name; *ptr; ptr++) {
if(*ptr == '?' || *ptr == '#') {
*ptr = 0;
break;
}
}
if(file_name[1] == '|')
file_name[1] = ':';
This->file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(This->file == INVALID_HANDLE_VALUE) {
This->file = NULL;
IInternetProtocolSink_ReportResult(pOIProtSink, INET_E_RESOURCE_NOT_FOUND,
GetLastError(), NULL);
heap_free(url);
return INET_E_RESOURCE_NOT_FOUND;
}
IInternetProtocolSink_ReportProgress(pOIProtSink,
BINDSTATUS_CACHEFILENAMEAVAILABLE, file_name);
hres = open_file(This, path, pOIProtSink);
SysFreeString(path);
if(FAILED(hres))
return hres;
hres = IUri_GetDisplayUri(pUri, &url);
if(hres == S_OK) {
hres = FindMimeFromData(NULL, url, NULL, 0, NULL, 0, &mime, 0);
SysFreeString(url);
if(SUCCEEDED(hres)) {
IInternetProtocolSink_ReportProgress(pOIProtSink,
(grfBINDF & BINDF_FROMURLMON) ?
BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
mime);
CoTaskMemFree(mime);
}
}
heap_free(url);
IInternetProtocolSink_ReportData(pOIProtSink,
BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
This->size, This->size);
if(GetFileSizeEx(This->file, &size))
IInternetProtocolSink_ReportData(pOIProtSink,
BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
size.u.LowPart, size.u.LowPart);
if(first_call)
IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
return S_OK;
}
static HRESULT WINAPI FileProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)->(%p)\n", This, pProtocolData);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
DWORD dwOptions)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
{
FileProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)->(%08x)\n", This, dwOptions);
return S_OK;
}
static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocol *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Resume(IInternetProtocol *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_Read(IInternetProtocol *iface, void *pv,
ULONG cb, ULONG *pcbRead)
{
FileProtocol *This = PROTOCOL_THIS(iface);
DWORD read = 0;
TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
if (pcbRead)
*pcbRead = 0;
if(!This->file)
return INET_E_DATA_NOT_AVAILABLE;
if (!ReadFile(This->file, pv, cb, &read, NULL))
return INET_E_DOWNLOAD_FAILURE;
if(pcbRead)
*pcbRead = read;
return cb == read ? S_OK : S_FALSE;
}
static HRESULT WINAPI FileProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
FileProtocol *This = PROTOCOL_THIS(iface);
FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
return E_NOTIMPL;
}
static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
{
FileProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)->(%08x)\n", This, dwOptions);
return S_OK;
}
static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocol *iface)
{
FileProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)\n", This);
return S_OK;
return report_result(pOIProtSink, S_OK, 0);
}
#undef PROTOCOL_THIS
static const IInternetProtocolVtbl FileProtocolVtbl = {
static const IInternetProtocolExVtbl FileProtocolExVtbl = {
FileProtocol_QueryInterface,
FileProtocol_AddRef,
FileProtocol_Release,
@ -298,7 +329,8 @@ static const IInternetProtocolVtbl FileProtocolVtbl = {
FileProtocol_Read,
FileProtocol_Seek,
FileProtocol_LockRequest,
FileProtocol_UnlockRequest
FileProtocol_UnlockRequest,
FileProtocol_StartEx
};
#define PRIORITY_THIS(iface) DEFINE_THIS(FileProtocol, InternetPriority, iface)
@ -307,19 +339,19 @@ static HRESULT WINAPI FilePriority_QueryInterface(IInternetPriority *iface,
REFIID riid, void **ppv)
{
FileProtocol *This = PRIORITY_THIS(iface);
return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
return IInternetProtocolEx_QueryInterface(PROTOCOLEX(This), riid, ppv);
}
static ULONG WINAPI FilePriority_AddRef(IInternetPriority *iface)
{
FileProtocol *This = PRIORITY_THIS(iface);
return IInternetProtocol_AddRef(PROTOCOL(This));
return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
}
static ULONG WINAPI FilePriority_Release(IInternetPriority *iface)
{
FileProtocol *This = PRIORITY_THIS(iface);
return IInternetProtocol_Release(PROTOCOL(This));
return IInternetProtocolEx_Release(PROTOCOLEX(This));
}
static HRESULT WINAPI FilePriority_SetPriority(IInternetPriority *iface, LONG nPriority)
@ -362,13 +394,12 @@ HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
ret = heap_alloc(sizeof(FileProtocol));
ret->lpIInternetProtocolVtbl = &FileProtocolVtbl;
ret->lpIInternetProtocolExVtbl = &FileProtocolExVtbl;
ret->lpInternetPriorityVtbl = &FilePriorityVtbl;
ret->file = NULL;
ret->file = INVALID_HANDLE_VALUE;
ret->priority = 0;
ret->ref = 1;
*ppobj = PROTOCOL(ret);
*ppobj = PROTOCOLEX(ret);
return S_OK;
}

View file

@ -36,14 +36,21 @@ typedef struct {
#define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(FtpProtocol, base, iface)
static HRESULT FtpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD request_flags,
static HRESULT FtpProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags,
HINTERNET internet_session, IInternetBindInfo *bind_info)
{
FtpProtocol *This = ASYNCPROTOCOL_THIS(prot);
BSTR url;
HRESULT hres;
hres = IUri_GetAbsoluteUri(uri, &url);
if(FAILED(hres))
return hres;
This->base.request = InternetOpenUrlW(internet_session, url, NULL, 0,
request_flags|INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_PASSIVE,
(DWORD_PTR)&This->base);
SysFreeString(url);
if (!This->base.request && GetLastError() != ERROR_IO_PENDING) {
WARN("InternetOpenUrl failed: %d\n", GetLastError());
return INET_E_RESOURCE_NOT_FOUND;
@ -145,6 +152,8 @@ static HRESULT WINAPI FtpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
DWORD grfPI, HANDLE_PTR dwReserved)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
IUri *uri;
HRESULT hres;
static const WCHAR ftpW[] = {'f','t','p',':'};
@ -154,7 +163,14 @@ static HRESULT WINAPI FtpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
if(strncmpW(szUrl, ftpW, sizeof(ftpW)/sizeof(WCHAR)))
return MK_E_SYNTAX;
return protocol_start(&This->base, PROTOCOL(This), szUrl, pOIProtSink, pOIBindInfo);
hres = CreateUri(szUrl, 0, 0, &uri);
if(FAILED(hres))
return hres;
hres = protocol_start(&This->base, PROTOCOL(This), uri, pOIProtSink, pOIBindInfo);
IUri_Release(uri);
return hres;
}
static HRESULT WINAPI FtpProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)

View file

@ -34,13 +34,20 @@ typedef struct {
#define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(GopherProtocol, base, iface)
static HRESULT GopherProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD request_flags,
static HRESULT GopherProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags,
HINTERNET internet_session, IInternetBindInfo *bind_info)
{
GopherProtocol *This = ASYNCPROTOCOL_THIS(prot);
BSTR url;
HRESULT hres;
hres = IUri_GetAbsoluteUri(uri, &url);
if(FAILED(hres))
return hres;
This->base.request = InternetOpenUrlW(internet_session, url, NULL, 0,
request_flags, (DWORD_PTR)&This->base);
SysFreeString(url);
if (!This->base.request && GetLastError() != ERROR_IO_PENDING) {
WARN("InternetOpenUrl failed: %d\n", GetLastError());
return INET_E_RESOURCE_NOT_FOUND;
@ -125,11 +132,20 @@ static HRESULT WINAPI GopherProtocol_Start(IInternetProtocol *iface, LPCWSTR szU
DWORD grfPI, HANDLE_PTR dwReserved)
{
GopherProtocol *This = PROTOCOL_THIS(iface);
IUri *uri;
HRESULT hres;
TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
pOIBindInfo, grfPI, dwReserved);
return protocol_start(&This->base, PROTOCOL(This), szUrl, pOIProtSink, pOIBindInfo);
hres = CreateUri(szUrl, 0, 0, &uri);
if(FAILED(hres))
return hres;
hres = protocol_start(&This->base, PROTOCOL(This), uri, pOIProtSink, pOIBindInfo);
IUri_Release(uri);
return hres;
}
static HRESULT WINAPI GopherProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)

View file

@ -67,18 +67,18 @@ static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
#define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(HttpProtocol, base, iface)
static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD request_flags,
static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags,
HINTERNET internet_session, IInternetBindInfo *bind_info)
{
HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
LPWSTR addl_header = NULL, post_cookie = NULL, optional = NULL;
IServiceProvider *service_provider = NULL;
IHttpNegotiate2 *http_negotiate2 = NULL;
LPWSTR host, user, pass, path;
BSTR url, host, user, pass, path;
LPOLESTR accept_mimes[257];
URL_COMPONENTSW url_comp;
const WCHAR **accept_types;
BYTE security_id[512];
DWORD len = 0;
DWORD len = 0, port;
ULONG num;
BOOL res, b;
HRESULT hres;
@ -88,24 +88,28 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD requ
{'P','O','S','T',0},
{'P','U','T',0}};
memset(&url_comp, 0, sizeof(url_comp));
url_comp.dwStructSize = sizeof(url_comp);
url_comp.dwSchemeLength = url_comp.dwHostNameLength = url_comp.dwUrlPathLength = url_comp.dwExtraInfoLength =
url_comp.dwUserNameLength = url_comp.dwPasswordLength = 1;
if (!InternetCrackUrlW(url, 0, 0, &url_comp))
return MK_E_SYNTAX;
hres = IUri_GetPort(uri, &port);
if(FAILED(hres))
return hres;
if(!url_comp.nPort)
url_comp.nPort = This->https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
hres = IUri_GetHost(uri, &host);
if(FAILED(hres))
return hres;
host = heap_strndupW(url_comp.lpszHostName, url_comp.dwHostNameLength);
user = heap_strndupW(url_comp.lpszUserName, url_comp.dwUserNameLength);
pass = heap_strndupW(url_comp.lpszPassword, url_comp.dwPasswordLength);
This->base.connection = InternetConnectW(internet_session, host, url_comp.nPort, user, pass,
INTERNET_SERVICE_HTTP, This->https ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)&This->base);
heap_free(pass);
heap_free(user);
heap_free(host);
hres = IUri_GetUserName(uri, &user);
if(SUCCEEDED(hres)) {
hres = IUri_GetPassword(uri, &pass);
if(SUCCEEDED(hres)) {
This->base.connection = InternetConnectW(internet_session, host, port, user, pass,
INTERNET_SERVICE_HTTP, This->https ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)&This->base);
SysFreeString(pass);
}
SysFreeString(user);
}
SysFreeString(host);
if(FAILED(hres))
return hres;
if(!This->base.connection) {
WARN("InternetConnect failed: %d\n", GetLastError());
return INET_E_CANNOT_CONNECT;
@ -113,27 +117,35 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD requ
num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1;
hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ACCEPT_MIMES, accept_mimes, num, &num);
if(hres != S_OK) {
if(hres == INET_E_USE_DEFAULT_SETTING) {
static const WCHAR default_accept_mimeW[] = {'*','/','*',0};
static const WCHAR *default_accept_mimes[] = {default_accept_mimeW, NULL};
accept_types = default_accept_mimes;
num = 0;
}else if(hres == S_OK) {
accept_types = (const WCHAR**)accept_mimes;
}else {
WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres);
return INET_E_NO_VALID_MEDIA;
}
accept_mimes[num] = 0;
path = heap_alloc((url_comp.dwUrlPathLength+url_comp.dwExtraInfoLength+1)*sizeof(WCHAR));
if(url_comp.dwUrlPathLength)
memcpy(path, url_comp.lpszUrlPath, url_comp.dwUrlPathLength*sizeof(WCHAR));
if(url_comp.dwExtraInfoLength)
memcpy(path+url_comp.dwUrlPathLength, url_comp.lpszExtraInfo, url_comp.dwExtraInfoLength*sizeof(WCHAR));
path[url_comp.dwUrlPathLength+url_comp.dwExtraInfoLength] = 0;
if(This->https)
request_flags |= INTERNET_FLAG_SECURE;
This->base.request = HttpOpenRequestW(This->base.connection,
This->base.bind_info.dwBindVerb < BINDVERB_CUSTOM
? wszBindVerb[This->base.bind_info.dwBindVerb] : This->base.bind_info.szCustomVerb,
path, NULL, NULL, (LPCWSTR *)accept_mimes, request_flags, (DWORD_PTR)&This->base);
heap_free(path);
hres = IUri_GetPathAndQuery(uri, &path);
if(SUCCEEDED(hres)) {
This->base.request = HttpOpenRequestW(This->base.connection,
This->base.bind_info.dwBindVerb < BINDVERB_CUSTOM
? wszBindVerb[This->base.bind_info.dwBindVerb] : This->base.bind_info.szCustomVerb,
path, NULL, NULL, accept_types, request_flags, (DWORD_PTR)&This->base);
SysFreeString(path);
}
while(num--)
CoTaskMemFree(accept_mimes[num]);
if(FAILED(hres))
return hres;
if (!This->base.request) {
WARN("HttpOpenRequest failed: %d\n", GetLastError());
return INET_E_RESOURCE_NOT_FOUND;
@ -153,8 +165,15 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD requ
return hres;
}
hres = IUri_GetAbsoluteUri(uri, &url);
if(FAILED(hres)) {
IServiceProvider_Release(service_provider);
return hres;
}
hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, url, wszHeaders,
0, &addl_header);
SysFreeString(url);
if(hres != S_OK) {
WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres);
IServiceProvider_Release(service_provider);
@ -382,6 +401,8 @@ static HRESULT WINAPI HttpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl
DWORD grfPI, HANDLE_PTR dwReserved)
{
HttpProtocol *This = PROTOCOL_THIS(iface);
IUri *uri;
HRESULT hres;
static const WCHAR httpW[] = {'h','t','t','p',':'};
static const WCHAR httpsW[] = {'h','t','t','p','s',':'};
@ -394,7 +415,14 @@ static HRESULT WINAPI HttpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl
: strncmpW(szUrl, httpW, sizeof(httpW)/sizeof(WCHAR)))
return MK_E_SYNTAX;
return protocol_start(&This->base, PROTOCOL(This), szUrl, pOIProtSink, pOIBindInfo);
hres = CreateUri(szUrl, 0, 0, &uri);
if(FAILED(hres))
return hres;
hres = protocol_start(&This->base, PROTOCOL(This), uri, pOIProtSink, pOIBindInfo);
IUri_Release(uri);
return hres;
}
static HRESULT WINAPI HttpProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)

View file

@ -234,7 +234,7 @@ HINTERNET get_internet_session(IInternetBindInfo *bind_info)
return internet_session;
}
HRESULT protocol_start(Protocol *protocol, IInternetProtocol *prot, LPCWSTR url,
HRESULT protocol_start(Protocol *protocol, IInternetProtocol *prot, IUri *uri,
IInternetProtocolSink *protocol_sink, IInternetBindInfo *bind_info)
{
DWORD request_flags;
@ -265,7 +265,7 @@ HRESULT protocol_start(Protocol *protocol, IInternetProtocol *prot, LPCWSTR url,
if(protocol->bindf & BINDF_NEEDFILE)
request_flags |= INTERNET_FLAG_NEED_FILE;
hres = protocol->vtbl->open_request(protocol, url, request_flags, internet_session, bind_info);
hres = protocol->vtbl->open_request(protocol, uri, request_flags, internet_session, bind_info);
if(FAILED(hres)) {
protocol_close_connection(protocol);
return report_result(protocol, hres);

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
@ stdcall CreateFormatEnumerator(long ptr ptr)
@ stdcall CreateIUriBuilder(ptr long long ptr)
@ stdcall CreateUri(wstr long long ptr)
@ stdcall CreateUriWithFragment(wstr wstr long long ptr)
@ stdcall CreateURLMoniker(ptr wstr ptr)
@ stdcall CreateURLMonikerEx(ptr wstr ptr long)
@ stdcall -private DllCanUnloadNow()

View file

@ -78,7 +78,7 @@ HRESULT bind_to_storage(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv);
HRESULT bind_to_object(IMoniker *mon, LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv);
HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol);
void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink);
void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink, IInternetBindInfo *bind_info);
IWinInetInfo *get_wininet_info(IInternetProtocol*);
typedef struct ProtocolVtbl ProtocolVtbl;
@ -105,12 +105,12 @@ typedef struct {
} Protocol;
struct ProtocolVtbl {
HRESULT (*open_request)(Protocol*,LPCWSTR,DWORD,HINTERNET,IInternetBindInfo*);
HRESULT (*open_request)(Protocol*,IUri*,DWORD,HINTERNET,IInternetBindInfo*);
HRESULT (*start_downloading)(Protocol*);
void (*close_connection)(Protocol*);
};
HRESULT protocol_start(Protocol*,IInternetProtocol*,LPCWSTR,IInternetProtocolSink*,IInternetBindInfo*);
HRESULT protocol_start(Protocol*,IInternetProtocol*,IUri*,IInternetProtocolSink*,IInternetBindInfo*);
HRESULT protocol_continue(Protocol*,PROTOCOLDATA*);
HRESULT protocol_read(Protocol*,void*,ULONG,ULONG*);
HRESULT protocol_lock_request(Protocol*);

View file

@ -39,7 +39,7 @@ static domain_t *add_domain( session_t *session, WCHAR *name )
list_init( &domain->entry );
list_init( &domain->cookies );
domain->name = name;
domain->name = strdupW( name );
list_add_tail( &session->cookie_cache, &domain->entry );
TRACE("%s\n", debugstr_w(domain->name));
@ -120,7 +120,7 @@ static BOOL add_cookie( session_t *session, cookie_t *cookie, WCHAR *domain_name
}
else if ((old_cookie = find_cookie( domain, path, cookie->name ))) delete_cookie( old_cookie );
cookie->path = path;
cookie->path = strdupW( path );
list_add_tail( &domain->cookies, &cookie->entry );
TRACE("domain %s path %s <- %s=%s\n", debugstr_w(domain_name), debugstr_w(cookie->path),
@ -230,12 +230,9 @@ BOOL set_cookies( request_t *request, const WCHAR *cookies )
ret = add_cookie( session, cookie, cookie_domain, cookie_path );
end:
if (!ret)
{
free_cookie( cookie );
heap_free( cookie_domain );
heap_free( cookie_path );
}
if (!ret) free_cookie( cookie );
heap_free( cookie_domain );
heap_free( cookie_path );
heap_free( buffer );
return ret;
}

View file

@ -16,8 +16,7 @@
* SOFTWARE.
*/
#define ENOSPC 28
#define EAFNOSUPPORT 52
#include <stdio.h>
#ifndef IN6ADDRSZ
#define IN6ADDRSZ 16
@ -64,7 +63,7 @@ inet_ntop(int af, const void *src, char *dst, size_t size)
return (inet_ntop6(src, dst, size));
#endif
default:
errno = EAFNOSUPPORT;
WSASetLastError(WSAEAFNOSUPPORT);
return (NULL);
}
/* NOTREACHED */
@ -88,7 +87,7 @@ inet_ntop4(const u_char *src, char *dst, size_t size)
char tmp[sizeof "255.255.255.255"];
if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) {
errno = ENOSPC;
WSASetLastError(WSAEINVAL);
return (NULL);
}
strcpy(dst, tmp);
@ -182,7 +181,7 @@ inet_ntop6(const u_char *src, char *dst, size_t size)
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = ENOSPC;
WSASetLastError(WSAEINVAL);
return (NULL);
}
strcpy(dst, tmp);

View file

@ -42,6 +42,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
DisableThreadLibraryCalls(hInstDLL);
break;
case DLL_PROCESS_DETACH:
netconn_unload();
break;
}
return TRUE;
@ -61,7 +62,6 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
*/
HRESULT WINAPI DllCanUnloadNow(void)
{
FIXME("()\n");
return S_FALSE;
}

View file

@ -38,10 +38,13 @@
#endif
#ifdef HAVE_OPENSSL_SSL_H
# include <openssl/ssl.h>
# include <openssl/opensslv.h>
#undef FAR
#undef DSA
#endif
#define NONAMELESSUNION
#include "wine/debug.h"
#include "wine/library.h"
@ -58,10 +61,6 @@
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() */
@ -80,17 +79,35 @@ static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
#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> 0x1000000)
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 );
@ -99,21 +116,49 @@ 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_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_get_timeout );
MAKE_FUNCPTR( SSL_CTX_set_timeout );
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( BIO_new_fp );
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( 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 */
#if 0
static int sock_get_error( int err )
{
#if !defined(__MINGW32__) && !defined (_MSC_VER)
@ -179,24 +224,222 @@ static int sock_get_error( int err )
#endif
return err;
}
#else
#define sock_get_error(x) WSAGetLastError()
#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 )
{
BOOL ret;
CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
PCCERT_CHAIN_CONTEXT chain;
char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
char *server_auth[] = { oid_server_auth };
DWORD err = ERROR_SUCCESS;
TRACE("verifying %s\n", debugstr_w( server ));
chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
if ((ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara, 0,
NULL, &chain )))
{
if (chain->TrustStatus.dwErrorStatus)
{
static const DWORD supportedErrors =
CERT_TRUST_IS_NOT_TIME_VALID |
CERT_TRUST_IS_UNTRUSTED_ROOT |
CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
{
if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
}
else if (chain->TrustStatus.dwErrorStatus &
CERT_TRUST_IS_UNTRUSTED_ROOT)
{
if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
err = ERROR_WINHTTP_SECURE_INVALID_CA;
}
else if ((chain->TrustStatus.dwErrorStatus &
CERT_TRUST_IS_OFFLINE_REVOCATION) ||
(chain->TrustStatus.dwErrorStatus &
CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
err = ERROR_WINHTTP_SECURE_CERT_REVOKED;
else if (chain->TrustStatus.dwErrorStatus &
CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
{
if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE))
err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
}
else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors)
err = ERROR_WINHTTP_SECURE_INVALID_CERT;
}
if (!err)
{
CERT_CHAIN_POLICY_PARA policyPara;
SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
CERT_CHAIN_POLICY_STATUS policyStatus;
CERT_CHAIN_CONTEXT chainCopy;
/* Clear chain->TrustStatus.dwErrorStatus so
* CertVerifyCertificateChainPolicy will verify additional checks
* rather than stopping with an existing, ignored error.
*/
memcpy(&chainCopy, chain, sizeof(chainCopy));
chainCopy.TrustStatus.dwErrorStatus = 0;
sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
sslExtraPolicyPara.pwszServerName = server;
policyPara.cbSize = sizeof(policyPara);
policyPara.dwFlags = 0;
policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
&chainCopy, &policyPara,
&policyStatus );
/* Any error in the policy status indicates that the
* policy couldn't be verified.
*/
if (ret && policyStatus.dwError)
{
if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
{
if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_CN_INVALID))
err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
}
else
err = ERROR_WINHTTP_SECURE_INVALID_CERT;
}
}
CertFreeCertificateChain( chain );
}
else
err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
TRACE("returning %08x\n", err);
return err;
}
static int netconn_secure_verify( int preverify_ok, X509_STORE_CTX *ctx )
{
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;
ret = TRUE;
for (i = 0; ret && i < psk_num((struct stack_st *)ctx->chain); i++)
{
PCCERT_CONTEXT context;
cert = (X509 *)psk_value((struct stack_st *)ctx->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 (err)
{
pSSL_set_ex_data( ssl, error_idx, (void *)err );
ret = FALSE;
}
}
CertFreeCertificateContext( endCert );
CertCloseStore( store, 0 );
}
return ret;
}
#endif
BOOL netconn_init( netconn_t *conn, BOOL secure )
{
#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
int i;
#endif
conn->socket = -1;
if (!secure) return TRUE;
#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
if (libssl_handle) return TRUE;
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) \
@ -204,11 +447,13 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
{ \
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 );
@ -217,11 +462,16 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
LOAD_FUNCPTR( SSL_shutdown );
LOAD_FUNCPTR( SSL_write );
LOAD_FUNCPTR( SSL_read );
LOAD_FUNCPTR( SSL_get_verify_result );
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_get_timeout );
LOAD_FUNCPTR( SSL_CTX_set_timeout );
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) \
@ -229,19 +479,72 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
{ \
ERR("Failed to load symbol %s\n", #x); \
set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \
LeaveCriticalSection( &init_ssl_cs ); \
return FALSE; \
}
LOAD_FUNCPTR( BIO_new_fp );
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( i2d_X509 );
LOAD_FUNCPTR( sk_value );
LOAD_FUNCPTR( sk_num );
#undef LOAD_FUNCPTR
pSSL_library_init();
pSSL_load_error_strings();
pBIO_new_fp( stderr, BIO_NOCLOSE );
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 = HeapAlloc(GetProcessHeap(), 0, 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] );
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 );
@ -250,6 +553,29 @@ BOOL netconn_init( netconn_t *conn, BOOL secure )
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++) DeleteCriticalSection( &ssl_locks[i] );
HeapFree( GetProcessHeap(), 0, ssl_locks );
}
#endif
}
BOOL netconn_connected( netconn_t *conn )
{
return (conn->socket != -1);
@ -295,36 +621,72 @@ BOOL netconn_close( netconn_t *conn )
return TRUE;
}
BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len )
BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len, int timeout )
{
if (connect( conn->socket, sockaddr, addr_len ) == -1)
BOOL ret = FALSE;
int res = 0, state;
if (timeout > 0)
{
WARN("unable to connect to host (%s)\n", strerror(errno));
set_last_error( sock_get_error( errno ) );
return FALSE;
state = 1;
ioctlsocket( conn->socket, FIONBIO, &state );
}
return TRUE;
if (connect( conn->socket, sockaddr, addr_len ) < 0)
{
res = sock_get_error( errno );
if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS)
{
fd_set outfd;
struct timeval tv;
FD_ZERO(&outfd);
FD_SET(conn->socket, &outfd);
tv.tv_sec = 0;
tv.tv_usec = timeout * 1000;
if (select( 0, NULL, &outfd, NULL, &tv ) > 0)
ret = TRUE;
else
res = sock_get_error( errno );
}
}
else
ret = TRUE;
if (timeout > 0)
{
state = 0;
ioctlsocket( conn->socket, FIONBIO, &state );
}
if (!ret)
{
WARN("unable to connect to host (%d)\n", res);
set_last_error( res );
}
return ret;
}
BOOL netconn_secure_connect( netconn_t *conn )
BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname )
{
#ifdef SONAME_LIBSSL
X509 *cert;
long res;
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 );
return FALSE;
}
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 );
return FALSE;
}
if (!pSSL_set_fd( conn->ssl_conn, conn->socket ))
{
ERR("SSL_set_fd failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
@ -333,21 +695,14 @@ BOOL netconn_secure_connect( netconn_t *conn )
}
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 );
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 (!(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;
@ -387,6 +742,8 @@ BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int
BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
{
int ret;
*recvd = 0;
if (!netconn_connected( conn )) return FALSE;
if (!len) return TRUE;
@ -425,19 +782,29 @@ 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;
}
*recvd += pSSL_read( conn->ssl_conn, (char *)buf + *recvd, len - *recvd );
ret = pSSL_read( conn->ssl_conn, (char *)buf + *recvd, len - *recvd );
if (ret < 0)
return FALSE;
/* 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 = *recvd;
if (!*recvd)
conn->peek_len = ret;
if (!ret)
{
heap_free( conn->peek_msg_mem );
conn->peek_msg_mem = NULL;
conn->peek_msg = NULL;
}
else memcpy( conn->peek_msg, buf, *recvd );
else memcpy( conn->peek_msg, buf, ret );
}
if (*recvd < 1 && len) return FALSE;
*recvd = ret;
return TRUE;
#else
return FALSE;
@ -474,7 +841,6 @@ BOOL netconn_query_data_available( netconn_t *conn, DWORD *available )
BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
{
struct timeval tv;
fd_set infd;
BOOL ret = FALSE;
DWORD recvd = 0;
@ -484,11 +850,6 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
if (conn->secure)
{
#ifdef SONAME_LIBSSL
long timeout;
timeout = pSSL_CTX_get_timeout( ctx );
pSSL_CTX_set_timeout( ctx, DEFAULT_RECEIVE_TIMEOUT );
while (recvd < *buflen)
{
int dummy;
@ -504,7 +865,6 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
}
if (buffer[recvd] != '\r') recvd++;
}
pSSL_CTX_set_timeout( ctx, timeout );
if (ret)
{
buffer[recvd++] = 0;
@ -516,16 +876,23 @@ BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
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;
struct timeval tv, *ptv;
socklen_t len = sizeof(tv);
if ((res = getsockopt( conn->socket, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, &len ) != -1))
ptv = &tv;
else
ptv = NULL;
if (select( 0, &infd, NULL, NULL, ptv ) > 0)
{
int res;
if ((res = recv( conn->socket, &buffer[recvd], 1, 0 )) <= 0)
{
if (res == -1) set_last_error( sock_get_error( errno ) );
@ -570,7 +937,7 @@ DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
return ERROR_SUCCESS;
}
BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *sa )
static DWORD resolve_hostname( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len )
{
char *hostname;
#ifdef HAVE_GETADDRINFO
@ -578,27 +945,53 @@ BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *
int ret;
#else
struct hostent *he;
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
#endif
if (!(hostname = strdupWA( hostnameW ))) return FALSE;
if (!(hostname = strdupWA( hostnameW ))) return ERROR_OUTOFMEMORY;
#ifdef HAVE_GETADDRINFO
memset( &hints, 0, sizeof(struct addrinfo) );
/* Prefer IPv4 to IPv6 addresses, since some web servers do not listen on
* their IPv6 addresses even though they have IPv6 addresses in the DNS.
*/
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_w(hostnameW), gai_strerror(ret));
return FALSE;
TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(hostnameW), gai_strerror(ret));
hints.ai_family = AF_INET6;
ret = getaddrinfo( hostname, NULL, &hints, &res );
if (ret != 0)
{
TRACE("failed to get address of %s (%s)\n", debugstr_w(hostnameW), gai_strerror(ret));
heap_free( hostname );
return ERROR_WINHTTP_NAME_NOT_RESOLVED;
}
}
heap_free( hostname );
if (*sa_len < res->ai_addrlen)
{
WARN("address too small\n");
freeaddrinfo( res );
return ERROR_WINHTTP_NAME_NOT_RESOLVED;
}
*sa_len = res->ai_addrlen;
memcpy( sa, res->ai_addr, res->ai_addrlen );
/* Copy port */
switch (res->ai_family)
{
case AF_INET:
((struct sockaddr_in *)sa)->sin_port = htons( port );
break;
case AF_INET6:
((struct sockaddr_in6 *)sa)->sin6_port = htons( port );
break;
}
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 );
return ERROR_SUCCESS;
#else
EnterCriticalSection( &cs_gethostbyname );
@ -608,15 +1001,69 @@ BOOL netconn_resolve( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_in *
{
TRACE("failed to get address of %s (%d)\n", debugstr_w(hostnameW), h_errno);
LeaveCriticalSection( &cs_gethostbyname );
return FALSE;
return ERROR_WINHTTP_NAME_NOT_RESOLVED;
}
if (*sa_len < sizeof(struct sockaddr_in))
{
WARN("address too small\n");
LeaveCriticalSection( &cs_gethostbyname );
return ERROR_WINHTTP_NAME_NOT_RESOLVED;
}
*sa_len = sizeof(struct sockaddr_in);
memset( sa, 0, sizeof(struct sockaddr_in) );
memcpy( &sa->sin_addr, he->h_addr, he->h_length );
sa->sin_family = he->h_addrtype;
sa->sin_port = htons( port );
memcpy( &sin->sin_addr, he->h_addr, he->h_length );
sin->sin_family = he->h_addrtype;
sin->sin_port = htons( port );
LeaveCriticalSection( &cs_gethostbyname );
return ERROR_SUCCESS;
#endif
}
struct resolve_args
{
WCHAR *hostname;
INTERNET_PORT port;
struct sockaddr *sa;
socklen_t *sa_len;
};
static DWORD CALLBACK resolve_proc( LPVOID arg )
{
struct resolve_args *ra = arg;
return resolve_hostname( ra->hostname, ra->port, ra->sa, ra->sa_len );
}
BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len, int timeout )
{
DWORD ret;
if (timeout)
{
DWORD status;
HANDLE thread;
struct resolve_args ra;
ra.hostname = hostname;
ra.port = port;
ra.sa = sa;
ra.sa_len = sa_len;
thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL );
if (!thread) return FALSE;
status = WaitForSingleObject( thread, timeout );
if (status == WAIT_OBJECT_0) GetExitCodeThread( thread, &ret );
else ret = ERROR_WINHTTP_TIMEOUT;
CloseHandle( thread );
}
else ret = resolve_hostname( hostname, port, sa, sa_len );
if (ret)
{
set_last_error( ret );
return FALSE;
}
return TRUE;
}
@ -624,41 +1071,29 @@ const void *netconn_get_certificate( netconn_t *conn )
{
#ifdef SONAME_LIBSSL
X509 *cert;
unsigned char *buffer, *p;
int len;
BOOL malloc = FALSE;
const CERT_CONTEXT *ret;
if (!conn->secure) return NULL;
if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn ))) return NULL;
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 );
ret = X509_to_cert_context( cert );
return ret;
#else
return NULL;
#endif
}
int netconn_get_cipher_strength( netconn_t *conn )
{
#ifdef SONAME_LIBSSL
SSL_CIPHER *cipher;
int bits = 0;
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
}

File diff suppressed because it is too large Load diff

View file

@ -21,16 +21,26 @@
#include "wine/debug.h"
#include <stdarg.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "winhttp.h"
#include "wincrypt.h"
#include "winreg.h"
#include "winhttp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
#define DEFAULT_RESOLVE_TIMEOUT 0
#define DEFAULT_CONNECT_TIMEOUT 20000
#define DEFAULT_SEND_TIMEOUT 30000
#define DEFAULT_RECEIVE_TIMEOUT 30000
/* FIXME */
#define CP_UNIXCP CP_ACP
void set_last_error( DWORD error )
{
/* FIXME */
@ -85,6 +95,8 @@ static void session_destroy( object_header_t *hdr )
static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
{
session_t *session = (session_t *)hdr;
switch (option)
{
case WINHTTP_OPTION_REDIRECT_POLICY:
@ -100,6 +112,22 @@ static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buf
*buflen = sizeof(DWORD);
return TRUE;
}
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
*(DWORD *)buffer = session->resolve_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
*(DWORD *)buffer = session->connect_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_SEND_TIMEOUT:
*(DWORD *)buffer = session->send_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
*(DWORD *)buffer = session->recv_timeout;
*buflen = sizeof(DWORD);
return TRUE;
default:
FIXME("unimplemented option %u\n", option);
set_last_error( ERROR_INVALID_PARAMETER );
@ -109,6 +137,8 @@ static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buf
static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
{
session_t *session = (session_t *)hdr;
switch (option)
{
case WINHTTP_OPTION_PROXY:
@ -136,6 +166,18 @@ static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffe
case WINHTTP_OPTION_DISABLE_FEATURE:
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
return FALSE;
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
session->resolve_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
session->connect_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_SEND_TIMEOUT:
session->send_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
session->recv_timeout = *(DWORD *)buffer;
return TRUE;
default:
FIXME("unimplemented option %u\n", option);
set_last_error( ERROR_INVALID_PARAMETER );
@ -166,13 +208,39 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWST
session->hdr.vtbl = &session_vtbl;
session->hdr.flags = flags;
session->hdr.refs = 1;
session->access = access;
session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
session->send_timeout = DEFAULT_SEND_TIMEOUT;
session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
list_init( &session->cookie_cache );
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 (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
{
WINHTTP_PROXY_INFO info;
WinHttpGetDefaultProxyConfiguration( &info );
session->access = info.dwAccessType;
if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
{
GlobalFree( (LPWSTR)info.lpszProxy );
GlobalFree( (LPWSTR)info.lpszProxyBypass );
goto end;
}
if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
{
GlobalFree( (LPWSTR)info.lpszProxy );
GlobalFree( (LPWSTR)info.lpszProxyBypass );
goto end;
}
}
else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
{
session->access = access;
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;
@ -201,13 +269,199 @@ static void connect_destroy( object_header_t *hdr )
heap_free( connect );
}
static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
{
connect_t *connect = (connect_t *)hdr;
switch (option)
{
case WINHTTP_OPTION_PARENT_HANDLE:
{
if (!buffer || *buflen < sizeof(HINTERNET))
{
*buflen = sizeof(HINTERNET);
set_last_error( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
*(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
*buflen = sizeof(HINTERNET);
return TRUE;
}
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
*(DWORD *)buffer = connect->session->resolve_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
*(DWORD *)buffer = connect->session->connect_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_SEND_TIMEOUT:
*(DWORD *)buffer = connect->session->send_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
*(DWORD *)buffer = connect->session->recv_timeout;
*buflen = sizeof(DWORD);
return TRUE;
default:
FIXME("unimplemented option %u\n", option);
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
static const object_vtbl_t connect_vtbl =
{
connect_destroy,
NULL,
connect_query_option,
NULL
};
static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
{
static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
BOOL ret = FALSE;
if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
ret = TRUE;
else if (*domain == '*')
{
if (domain[1] == '.')
{
LPCWSTR dot;
/* For a hostname to match a wildcard, the last domain must match
* the wildcard exactly. E.g. if the wildcard is *.a.b, and the
* hostname is www.foo.a.b, it matches, but a.b does not.
*/
dot = strchrW( server, '.' );
if (dot)
{
int len = strlenW( dot + 1 );
if (len > strlenW( domain + 2 ))
{
LPCWSTR ptr;
/* The server's domain is longer than the wildcard, so it
* could be a subdomain. Compare the last portion of the
* server's domain.
*/
ptr = dot + len + 1 - strlenW( domain + 2 );
if (!strcmpiW( ptr, domain + 2 ))
{
/* This is only a match if the preceding character is
* a '.', i.e. that it is a matching domain. E.g.
* if domain is '*.b.c' and server is 'www.ab.c' they
* do not match.
*/
ret = *(ptr - 1) == '.';
}
}
else
ret = !strcmpiW( dot + 1, domain + 2 );
}
}
}
else
ret = !strcmpiW( server, domain );
return ret;
}
/* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
#define MAX_HOST_NAME_LENGTH 256
static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
{
LPCWSTR ptr;
BOOL ret = FALSE;
if (!session->proxy_bypass) return FALSE;
ptr = session->proxy_bypass;
do {
LPCWSTR tmp = ptr;
ptr = strchrW( ptr, ';' );
if (!ptr)
ptr = strchrW( tmp, ' ' );
if (ptr)
{
if (ptr - tmp < MAX_HOST_NAME_LENGTH)
{
WCHAR domain[MAX_HOST_NAME_LENGTH];
memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
domain[ptr - tmp] = 0;
ret = domain_matches( server, domain );
}
ptr += 1;
}
else if (*tmp)
ret = domain_matches( server, tmp );
} while (ptr && !ret);
return ret;
}
BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
{
session_t *session = connect->session;
BOOL ret = TRUE;
if (session->proxy_server && !should_bypass_proxy(session, server))
{
LPCWSTR colon;
if ((colon = strchrW( session->proxy_server, ':' )))
{
if (!connect->servername || strncmpiW( connect->servername,
session->proxy_server, colon - session->proxy_server - 1 ))
{
heap_free( connect->servername );
if (!(connect->servername = heap_alloc(
(colon - session->proxy_server + 1) * sizeof(WCHAR) )))
{
ret = FALSE;
goto end;
}
memcpy( connect->servername, session->proxy_server,
(colon - session->proxy_server) * sizeof(WCHAR) );
connect->servername[colon - session->proxy_server] = 0;
if (*(colon + 1))
connect->serverport = atoiW( colon + 1 );
else
connect->serverport = INTERNET_DEFAULT_PORT;
}
}
else
{
if (!connect->servername || strcmpiW( connect->servername,
session->proxy_server ))
{
heap_free( connect->servername );
if (!(connect->servername = strdupW( session->proxy_server )))
{
ret = FALSE;
goto end;
}
connect->serverport = INTERNET_DEFAULT_PORT;
}
}
}
else if (server)
{
heap_free( connect->servername );
if (!(connect->servername = strdupW( server )))
{
ret = FALSE;
goto end;
}
connect->serverport = port;
}
end:
return ret;
}
/***********************************************************************
* WinHttpConnect (winhttp.@)
*/
@ -252,11 +506,11 @@ HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PO
connect->session = session;
list_add_head( &session->hdr.children, &connect->hdr.entry );
if (server && !(connect->hostname = strdupW( server ))) goto end;
if (!(connect->hostname = strdupW( server ))) goto end;
connect->hostport = port;
if (server && !(connect->servername = strdupW( server ))) goto end;
connect->serverport = port;
if (!set_server_for_hostname( connect, server, port ))
goto end;
if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
connect->hdr.handle = hconnect;
@ -296,13 +550,40 @@ static void request_destroy( object_header_t *hdr )
heap_free( request );
}
static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
{
int len = 0;
if (str) len = strlenW( str );
if (buffer && *buflen > len)
{
memcpy( buffer, str, len * sizeof(WCHAR) );
buffer[len] = 0;
}
*buflen = len * sizeof(WCHAR);
}
static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
{
WCHAR *ret;
DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
size = CertNameToStrW( encoding, blob, format, NULL, 0 );
if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
CertNameToStrW( encoding, blob, format, ret, size );
return ret;
}
static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
{
request_t *request = (request_t *)hdr;
switch (option)
{
case WINHTTP_OPTION_SECURITY_FLAGS:
{
DWORD flags;
int bits;
if (!buffer || *buflen < sizeof(flags))
{
@ -313,6 +594,14 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
flags = 0;
if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
flags |= request->netconn.security_flags;
bits = netconn_get_cipher_strength( &request->netconn );
if (bits >= 128)
flags |= SECURITY_FLAG_STRENGTH_STRONG;
else if (bits >= 56)
flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
else
flags |= SECURITY_FLAG_STRENGTH_WEAK;
*(DWORD *)buffer = flags;
*buflen = sizeof(flags);
return TRUE;
@ -320,7 +609,6 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
{
const CERT_CONTEXT *cert;
request_t *request = (request_t *)hdr;
if (!buffer || *buflen < sizeof(cert))
{
@ -334,6 +622,41 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
*buflen = sizeof(cert);
return TRUE;
}
case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
{
const CERT_CONTEXT *cert;
const CRYPT_OID_INFO *oidInfo;
WINHTTP_CERTIFICATE_INFO *ci = buffer;
FIXME("partial stub\n");
if (!buffer || *buflen < sizeof(*ci))
{
*buflen = sizeof(*ci);
set_last_error( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
ci->ftExpiry = cert->pCertInfo->NotAfter;
ci->ftStart = cert->pCertInfo->NotBefore;
ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
ci->lpszProtocolName = NULL;
oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
cert->pCertInfo->SignatureAlgorithm.pszObjId,
0 );
if (oidInfo)
ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
else
ci->lpszSignatureAlgName = NULL;
ci->lpszEncryptionAlgName = NULL;
ci->dwKeySize = netconn_get_cipher_strength( &request->netconn );
CertFreeCertificateContext( cert );
*buflen = sizeof(*ci);
return TRUE;
}
case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
{
if (!buffer || *buflen < sizeof(DWORD))
@ -343,10 +666,43 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
return FALSE;
}
*(DWORD *)buffer = 128; /* FIXME */
*(DWORD *)buffer = netconn_get_cipher_strength( &request->netconn );
*buflen = sizeof(DWORD);
return TRUE;
}
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
*(DWORD *)buffer = request->resolve_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
*(DWORD *)buffer = request->connect_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_SEND_TIMEOUT:
*(DWORD *)buffer = request->send_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
*(DWORD *)buffer = request->recv_timeout;
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_USERNAME:
str_to_buffer( buffer, request->connect->username, buflen );
return TRUE;
case WINHTTP_OPTION_PASSWORD:
str_to_buffer( buffer, request->connect->password, buflen );
return TRUE;
case WINHTTP_OPTION_PROXY_USERNAME:
str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
return TRUE;
case WINHTTP_OPTION_PROXY_PASSWORD:
str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
return TRUE;
default:
FIXME("unimplemented option %u\n", option);
set_last_error( ERROR_INVALID_PARAMETER );
@ -354,8 +710,23 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
}
}
static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
{
WCHAR *ret;
if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
{
memcpy( ret, buffer, buflen * sizeof(WCHAR) );
ret[buflen] = 0;
return ret;
}
set_last_error( ERROR_OUTOFMEMORY );
return NULL;
}
static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
{
request_t *request = (request_t *)hdr;
switch (option)
{
case WINHTTP_OPTION_PROXY:
@ -410,6 +781,73 @@ static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffe
hdr->redirect_policy = policy;
return TRUE;
}
case WINHTTP_OPTION_SECURITY_FLAGS:
{
DWORD flags;
if (buflen < sizeof(DWORD))
{
set_last_error( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
flags = *(DWORD *)buffer;
TRACE("0x%x\n", flags);
if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
request->netconn.security_flags = flags;
return TRUE;
}
case WINHTTP_OPTION_RESOLVE_TIMEOUT:
request->resolve_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_CONNECT_TIMEOUT:
request->connect_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_SEND_TIMEOUT:
request->send_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_RECEIVE_TIMEOUT:
request->recv_timeout = *(DWORD *)buffer;
return TRUE;
case WINHTTP_OPTION_USERNAME:
{
connect_t *connect = request->connect;
heap_free( connect->username );
if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
return TRUE;
}
case WINHTTP_OPTION_PASSWORD:
{
connect_t *connect = request->connect;
heap_free( connect->password );
if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
return TRUE;
}
case WINHTTP_OPTION_PROXY_USERNAME:
{
session_t *session = request->connect->session;
heap_free( session->proxy_username );
if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
return TRUE;
}
case WINHTTP_OPTION_PROXY_PASSWORD:
{
session_t *session = request->connect->session;
heap_free( session->proxy_password );
if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
return TRUE;
}
default:
FIXME("unimplemented option %u\n", option);
set_last_error( ERROR_INVALID_PARAMETER );
@ -466,6 +904,10 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o
list_add_head( &connect->hdr.children, &request->hdr.entry );
if (!netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE )) goto end;
request->resolve_timeout = connect->session->resolve_timeout;
request->connect_timeout = connect->session->connect_timeout;
request->send_timeout = connect->session->send_timeout;
request->recv_timeout = connect->session->recv_timeout;
if (!verb || !verb[0]) verb = getW;
if (!(request->verb = strdupW( verb ))) goto end;
@ -648,17 +1090,167 @@ BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
return FALSE;
}
static const WCHAR Connections[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','\\',
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
'C','o','n','n','e','c','t','i','o','n','s',0 };
static const WCHAR WinHttpSettings[] = {
'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
static const DWORD WINHTTPSETTINGS_MAGIC = 0x18;
static const DWORD WINHTTP_PROXY_TYPE_DIRECT = 1;
static const DWORD WINHTTP_PROXY_TYPE_PROXY = 2;
struct winhttp_settings_header
{
DWORD magic;
DWORD unknown; /* always zero? */
DWORD flags; /* one of WINHTTP_PROXY_TYPE_* */
};
static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
{
const BYTE *begin;
for (begin = src; src - begin < len; src++, dst++)
*dst = *src;
*dst = 0;
}
/***********************************************************************
* WinHttpGetDefaultProxyConfiguration (winhttp.@)
*/
BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
{
FIXME("%p\n", info);
LONG l;
HKEY key;
BOOL got_from_reg = FALSE, direct = TRUE;
char *envproxy;
info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
info->lpszProxy = NULL;
info->lpszProxyBypass = NULL;
TRACE("%p\n", info);
l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
if (!l)
{
DWORD type, size = 0;
l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
if (!l && type == REG_BINARY &&
size >= sizeof(struct winhttp_settings_header) + 2 * sizeof(DWORD))
{
BYTE *buf = heap_alloc( size );
if (buf)
{
struct winhttp_settings_header *hdr =
(struct winhttp_settings_header *)buf;
DWORD *len = (DWORD *)(hdr + 1);
l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
&size );
if (!l && hdr->magic == WINHTTPSETTINGS_MAGIC &&
hdr->unknown == 0)
{
if (hdr->flags & WINHTTP_PROXY_TYPE_PROXY)
{
BOOL sane = FALSE;
LPWSTR proxy = NULL;
LPWSTR proxy_bypass = NULL;
/* Sanity-check length of proxy string */
if ((BYTE *)len - buf + *len <= size)
{
sane = TRUE;
proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
if (proxy)
copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
len = (DWORD *)((BYTE *)(len + 1) + *len);
}
if (sane)
{
/* Sanity-check length of proxy bypass string */
if ((BYTE *)len - buf + *len <= size)
{
proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
if (proxy_bypass)
copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
}
else
{
sane = FALSE;
GlobalFree( proxy );
proxy = NULL;
}
}
info->lpszProxy = proxy;
info->lpszProxyBypass = proxy_bypass;
if (sane)
{
got_from_reg = TRUE;
direct = FALSE;
info->dwAccessType =
WINHTTP_ACCESS_TYPE_NAMED_PROXY;
TRACE("http proxy (from registry) = %s, bypass = %s\n",
debugstr_w(info->lpszProxy),
debugstr_w(info->lpszProxyBypass));
}
}
}
heap_free( buf );
}
}
RegCloseKey( key );
}
if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
{
char *colon, *http_proxy;
if ((colon = strchr( envproxy, ':' )))
{
if (*(colon + 1) == '/' && *(colon + 2) == '/')
{
static const char http[] = "http://";
/* It's a scheme, check that it's http */
if (!strncmp( envproxy, http, strlen( http ) ))
http_proxy = envproxy + strlen( http );
else
{
WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
http_proxy = NULL;
}
}
else
http_proxy = envproxy;
}
else
http_proxy = envproxy;
if (http_proxy)
{
WCHAR *http_proxyW;
int len;
len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
{
MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
direct = FALSE;
info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
info->lpszProxy = http_proxyW;
info->lpszProxyBypass = NULL;
TRACE("http proxy (from environment) = %s\n",
debugstr_w(info->lpszProxy));
}
}
}
if (direct)
{
info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
info->lpszProxy = NULL;
info->lpszProxyBypass = NULL;
}
return TRUE;
}
@ -703,9 +1295,106 @@ BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTO
*/
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;
LONG l;
HKEY key;
BOOL ret = FALSE;
const WCHAR *src;
TRACE("%p\n", info);
if (!info)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
switch (info->dwAccessType)
{
case WINHTTP_ACCESS_TYPE_NO_PROXY:
break;
case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
if (!info->lpszProxy)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* Only ASCII characters are allowed */
for (src = info->lpszProxy; *src; src++)
if (*src > 0x7f)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (info->lpszProxyBypass)
{
for (src = info->lpszProxyBypass; *src; src++)
if (*src > 0x7f)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
break;
default:
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
KEY_WRITE, NULL, &key, NULL );
if (!l)
{
DWORD size = sizeof(struct winhttp_settings_header) + 2 * sizeof(DWORD);
BYTE *buf;
if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
{
size += strlenW( info->lpszProxy );
if (info->lpszProxyBypass)
size += strlenW( info->lpszProxyBypass );
}
buf = heap_alloc( size );
if (buf)
{
struct winhttp_settings_header *hdr =
(struct winhttp_settings_header *)buf;
DWORD *len = (DWORD *)(hdr + 1);
hdr->magic = WINHTTPSETTINGS_MAGIC;
hdr->unknown = 0;
if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
{
BYTE *dst;
hdr->flags = WINHTTP_PROXY_TYPE_PROXY;
*len++ = strlenW( info->lpszProxy );
for (dst = (BYTE *)len, src = info->lpszProxy; *src;
src++, dst++)
*dst = *src;
len = (DWORD *)dst;
if (info->lpszProxyBypass)
{
*len++ = strlenW( info->lpszProxyBypass );
for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
src++, dst++)
*dst = *src;
}
else
*len++ = 0;
}
else
{
hdr->flags = WINHTTP_PROXY_TYPE_DIRECT;
*len++ = 0;
*len++ = 0;
}
l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
if (!l)
ret = TRUE;
heap_free( buf );
}
RegCloseKey( key );
}
return ret;
}
/***********************************************************************
@ -737,8 +1426,69 @@ WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHT
*/
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;
BOOL ret = TRUE;
object_header_t *hdr;
request_t *request;
session_t *session;
TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (!(hdr = grab_object( handle )))
{
set_last_error( ERROR_INVALID_HANDLE );
return FALSE;
}
switch(hdr->type)
{
case WINHTTP_HANDLE_TYPE_REQUEST:
request = (request_t *)hdr;
request->connect_timeout = connect;
if (resolve < 0) resolve = 0;
request->resolve_timeout = resolve;
if (send < 0) send = 0;
request->send_timeout = send;
if (receive < 0) receive = 0;
request->recv_timeout = receive;
if (netconn_connected( &request->netconn ))
{
if (netconn_set_timeout( &request->netconn, TRUE, send )) ret = FALSE;
if (netconn_set_timeout( &request->netconn, FALSE, receive )) ret = FALSE;
}
release_object( &request->hdr );
break;
case WINHTTP_HANDLE_TYPE_SESSION:
session = (session_t *)hdr;
session->connect_timeout = connect;
if (resolve < 0) resolve = 0;
session->resolve_timeout = resolve;
if (send < 0) send = 0;
session->send_timeout = send;
if (receive < 0) receive = 0;
session->recv_timeout = receive;
break;
default:
release_object( hdr );
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
return FALSE;
}
return ret;
}
static const WCHAR wkday[7][4] =

View file

@ -133,7 +133,7 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN
p += 2;
if (!p[0]) goto exit;
if ((q = memchrW( p, '@', len - (p - url) )))
if ((q = memchrW( p, '@', len - (p - url) )) && !(memchrW( p, '/', q - p )))
{
if ((r = memchrW( p, ':', q - p )))
{
@ -368,7 +368,7 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW
TRACE("%p, 0x%08x, %p, %p\n", uc, flags, url, required);
if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required)
if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required || !url)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
@ -376,7 +376,7 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW
if (!calc_length( uc, flags, &len )) return FALSE;
if (!url || *required < len)
if (*required < len)
{
*required = len + 1;
set_last_error( ERROR_INSUFFICIENT_BUFFER );

View file

@ -15,6 +15,8 @@
<file>session.c</file>
<file>url.c</file>
<library>wine</library>
<library>advapi32</library>
<library>crypt32</library>
<library>shlwapi</library>
<library>wininet</library>
<library>ws2_32</library>

View file

@ -27,6 +27,9 @@
#include "wine/unicode.h"
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@ -93,6 +96,10 @@ typedef struct
object_header_t hdr;
LPWSTR agent;
DWORD access;
int resolve_timeout;
int connect_timeout;
int send_timeout;
int recv_timeout;
LPWSTR proxy_server;
LPWSTR proxy_bypass;
LPWSTR proxy_username;
@ -110,7 +117,7 @@ typedef struct
LPWSTR password;
INTERNET_PORT hostport;
INTERNET_PORT serverport;
struct sockaddr_in sockaddr;
struct sockaddr_storage sockaddr;
} connect_t;
typedef struct
@ -121,6 +128,7 @@ typedef struct
char *peek_msg;
char *peek_msg_mem;
size_t peek_len;
DWORD security_flags;
} netconn_t;
typedef struct
@ -139,6 +147,10 @@ typedef struct
LPWSTR version;
LPWSTR raw_headers;
netconn_t netconn;
int resolve_timeout;
int connect_timeout;
int send_timeout;
int recv_timeout;
LPWSTR status_text;
DWORD content_length; /* total number of bytes to be read (per chunk) */
DWORD content_read; /* bytes read so far */
@ -204,22 +216,26 @@ 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_connect( netconn_t *, const struct sockaddr *, unsigned int, 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 );
void netconn_unload( void );
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_resolve( WCHAR *, INTERNET_PORT, struct sockaddr *, socklen_t *, int );
BOOL netconn_secure_connect( netconn_t *, WCHAR * );
BOOL netconn_send( netconn_t *, const void *, size_t, int, int * );
DWORD netconn_set_timeout( netconn_t *, BOOL, int );
const void *netconn_get_certificate( netconn_t * );
int netconn_get_cipher_strength( netconn_t * );
BOOL set_cookies( request_t *, const WCHAR * );
BOOL add_cookie_headers( request_t * );
BOOL add_request_headers( request_t *, LPCWSTR, DWORD, DWORD );
void delete_domain( domain_t * );
BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port );
static inline void *heap_alloc( SIZE_T size )
{

View file

@ -1,111 +1,104 @@
--- 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 @@
--- wine-1.3.4/dlls/winhttp/net.c 2010-10-01 14:46:44.000000000 -0400
+++ dll/win32/winhttp/net.c 2010-10-09 17:04:11.000000000 -0400
@@ -158,6 +158,7 @@
#endif
+#if 0
/* translate a unix error code into a winsock error code */
+#if 0
static int sock_get_error( int err )
{
@@ -174,6 +176,9 @@
}
#if !defined(__MINGW32__) && !defined (_MSC_VER)
@@ -223,6 +224,9 @@
#endif
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 @@
#ifdef SONAME_LIBSSL
static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
@@ -632,11 +636,16 @@
res = sock_get_error( errno );
if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS)
{
- struct pollfd pfd;
+ fd_set outfd;
+ struct timeval tv;
+
+ FD_ZERO(&outfd);
+ FD_SET(conn->socket, &outfd);
- pfd.fd = conn->socket;
- pfd.events = POLLOUT;
- if (poll( &pfd, 1, timeout ) > 0)
+ tv.tv_sec = 0;
+ tv.tv_usec = timeout * 1000;
+
+ if (select( 0, NULL, &outfd, NULL, &tv ) > 0)
ret = TRUE;
else
res = sock_get_error( errno );
@@ -832,7 +841,7 @@
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 @@
@@ -867,20 +876,22 @@
return FALSE;
#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 11:29:55 2008
@@ -20,6 +20,7 @@
#include "wine/port.h"
#include "wine/debug.h"
- int timeout, res;
- struct timeval tv;
+ int res;
+ struct timeval tv, *ptv;
socklen_t len = sizeof(tv);
+#include <stdio.h>
#include <stdarg.h>
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
@@ -33,6 +34,8 @@
#include "winhttp.h"
if ((res = getsockopt( conn->socket, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, &len ) != -1))
- timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ ptv = &tv;
else
- timeout = -1;
- if (poll( &pfd, 1, timeout ) > 0)
+ ptv = NULL;
+
+ if (select( 0, &infd, NULL, NULL, ptv ) > 0)
{
if ((res = recv( conn->socket, &buffer[recvd], 1, 0 )) <= 0)
{
--- wine-1.3.4/dlls/winhttp/session.c 2010-10-01 14:46:44.000000000 -0400
+++ dll/win32/winhttp/session.c 2010-10-09 17:04:11.000000000 -0400
@@ -38,6 +38,9 @@
#define DEFAULT_SEND_TIMEOUT 30000
#define DEFAULT_RECEIVE_TIMEOUT 30000
+/* FIXME */
+#define CP_UNIXCP CP_ACP
+
void set_last_error( DWORD error )
{
/* FIXME */
--- wine-1.3.4/dlls/winhttp/request.c 2010-10-01 14:46:44.000000000 -0400
+++ dll/win32/winhttp/request.c 2010-10-09 17:04:11.000000000 -0400
@@ -34,6 +34,8 @@
#include "winhttp_private.h"
+
+#include "inet_ntop.c"
+#include "inet_ntop.c"
+
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
--- 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;
static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0};

View file

@ -37,4 +37,33 @@
+#endif
/******************************************************************************
* NETCON_create
* NETCON_create
--- wine-1.3.4/dlls/wininet/internet.c 2010-10-01 14:46:44.000000000 -0400
+++ dll/win32/wininet/internet.c 2010-10-09 15:33:04.000000000 -0400
@@ -3569,19 +3569,22 @@
LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
{
- struct pollfd pfd;
+ fd_set infd;
+ struct timeval tv;
BOOL bSuccess = FALSE;
INT nRecv = 0;
LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
TRACE("\n");
- pfd.fd = nSocket;
- pfd.events = POLLIN;
+ FD_ZERO(&infd);
+ FD_SET(nSocket,&infd);
+ tv.tv_sec = RESPONSE_TIMEOUT;
+ tv.tv_usec = 0;
while (nRecv < MAX_REPLY_LEN)
{
- if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
+ if (select(0, &infd, NULL, NULL, &tv) > 0)
{
if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
{