From a1c16d28fadc3a57e126b8d59cca86b75dd1f2a7 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 22 Jul 2003 03:17:52 +0000 Subject: [PATCH] Implement support for proxies with usernames and passwords. --- dlls/wininet/.cvsignore | 1 + dlls/wininet/Makefile.in | 7 +- dlls/wininet/dialogs.c | 363 +++++++++++++++++++++++++++++++++++++ dlls/wininet/http.c | 313 +++++++++++++++++++++----------- dlls/wininet/internet.c | 149 ++++++++++----- dlls/wininet/internet.h | 4 + dlls/wininet/resource.h | 27 +++ dlls/wininet/rsrc.rc | 42 +++++ dlls/wininet/wininet.spec | 2 +- dlls/wininet/wininet_En.rc | 39 ++++ 10 files changed, 792 insertions(+), 155 deletions(-) create mode 100644 dlls/wininet/dialogs.c create mode 100644 dlls/wininet/resource.h create mode 100644 dlls/wininet/rsrc.rc create mode 100644 dlls/wininet/wininet_En.rc diff --git a/dlls/wininet/.cvsignore b/dlls/wininet/.cvsignore index 2286be2cd18..330cb68ea5a 100644 --- a/dlls/wininet/.cvsignore +++ b/dlls/wininet/.cvsignore @@ -1,4 +1,5 @@ Makefile +rsrc.res version.res wininet.dll.dbg.c wininet.spec.c diff --git a/dlls/wininet/Makefile.in b/dlls/wininet/Makefile.in index ec64f11c4fd..98d2c37b043 100644 --- a/dlls/wininet/Makefile.in +++ b/dlls/wininet/Makefile.in @@ -4,7 +4,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = wininet.dll -IMPORTS = shlwapi user32 advapi32 kernel32 +IMPORTS = mpr shlwapi user32 advapi32 kernel32 EXTRALIBS = $(LIBUNICODE) LDDLLFLAGS = @LDDLLFLAGS@ @@ -12,6 +12,7 @@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = \ cookie.c \ + dialogs.c \ ftp.c \ http.c \ internet.c \ @@ -20,7 +21,9 @@ C_SRCS = \ utility.c \ wininet_main.c -RC_SRCS = version.rc +RC_SRCS = \ + rsrc.rc \ + version.rc SUBDIRS = tests diff --git a/dlls/wininet/dialogs.c b/dlls/wininet/dialogs.c new file mode 100644 index 00000000000..d6a1707a846 --- /dev/null +++ b/dlls/wininet/dialogs.c @@ -0,0 +1,363 @@ +/* + * Wininet + * + * Copyright 2003 Mike McCormack for CodeWeavers Inc. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "wininet.h" +#include "winnetwk.h" +#include "winnls.h" +#include "wine/debug.h" +#include "winerror.h" +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" + +#include "internet.h" + +#include "wine/unicode.h" + +#include "resource.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wininet); + +struct WININET_ErrorDlgParams +{ + HWND hWnd; + HINTERNET hRequest; + DWORD dwError; + DWORD dwFlags; + LPVOID* lppvData; +}; + +/*********************************************************************** + * WININET_GetProxyServer + * + * Determine the name of the proxy server the request is using + */ +static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPSTR szBuf, DWORD sz ) +{ + LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hRequest; + LPWININETHTTPSESSIONA lpwhs = NULL; + LPWININETAPPINFOA hIC = NULL; + LPSTR p; + + if (NULL == lpwhr) + return FALSE; + + lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent; + if (NULL == lpwhs) + return FALSE; + + hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent; + if (NULL == hIC) + return FALSE; + + strncpy(szBuf, hIC->lpszProxy, sz); + + /* FIXME: perhaps it would be better to use InternetCrackUrl here */ + p = strchr(szBuf, ':'); + if(*p) + *p = 0; + + return TRUE; +} + +/*********************************************************************** + * WININET_GetAuthRealm + * + * Determine the name of the (basic) Authentication realm + */ +static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPSTR szBuf, DWORD sz ) +{ + LPSTR p, q; + DWORD index; + + /* extract the Realm from the proxy response and show it */ + index = 0; + if( !HttpQueryInfoA( hRequest, HTTP_QUERY_PROXY_AUTHENTICATE, + szBuf, &sz, &index) ) + return FALSE; + + /* + * FIXME: maybe we should check that we're + * dealing with 'Basic' Authentication + */ + p = strchr( szBuf, ' ' ); + if( p && !strncmp( p+1, "realm=", 6 ) ) + { + /* remove quotes */ + p += 7; + if( *p == '"' ) + { + p++; + q = strrchr( p, '"' ); + if( q ) + *q = 0; + } + } + + strcpy( szBuf, p ); + + return TRUE; +} + +/*********************************************************************** + * WININET_GetSetPassword + */ +static BOOL WININET_GetSetPassword( HWND hdlg, LPCSTR szServer, + LPCSTR szRealm, BOOL bSet ) +{ + CHAR szResource[0x80], szUserPass[0x40]; + LPSTR p; + HWND hUserItem, hPassItem; + DWORD r, dwMagic = 19; + UINT len; + WORD sz; + + hUserItem = GetDlgItem( hdlg, IDC_USERNAME ); + hPassItem = GetDlgItem( hdlg, IDC_PASSWORD ); + + /* now try fetch the username and password */ + strcpy( szResource, szServer); + strcat( szResource, "/"); + strcat( szResource, szRealm); + + if( bSet ) + { + szUserPass[0] = 0; + GetWindowTextA( hUserItem, szUserPass, sizeof szUserPass-1 ); + strcat(szUserPass, ":"); + len = strlen( szUserPass ); + GetWindowTextA( hPassItem, szUserPass+len, sizeof szUserPass-len ); + + r = WNetCachePassword( szResource, strlen( szResource ) + 1, + szUserPass, strlen( szUserPass ) + 1, dwMagic, 0 ); + + return ( r == WN_SUCCESS ); + } + + sz = sizeof szUserPass; + r = WNetGetCachedPassword( szResource, strlen( szResource ) + 1, + szUserPass, &sz, dwMagic ); + if( r != WN_SUCCESS ) + return FALSE; + + p = strchr( szUserPass, ':' ); + if( p ) + { + *p = 0; + SetWindowTextA( hUserItem, szUserPass ); + SetWindowTextA( hPassItem, p+1 ); + } + + return TRUE; +} + +/*********************************************************************** + * WININET_SetProxyAuthorization + */ +static BOOL WININET_SetProxyAuthorization( HINTERNET hRequest, + LPSTR username, LPSTR password ) +{ + LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hRequest; + LPWININETHTTPSESSIONA lpwhs; + LPWININETAPPINFOA hIC; + LPSTR p; + + lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent; + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } + + hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent; + + p = HeapAlloc( GetProcessHeap(), 0, strlen( username ) + 1 ); + if( !p ) + return FALSE; + + strcpy( p, username ); + hIC->lpszProxyUsername = p; + + p = HeapAlloc( GetProcessHeap(), 0, strlen( password ) + 1 ); + if( !p ) + return FALSE; + + strcpy( p, password ); + hIC->lpszProxyPassword = p; + + return TRUE; +} + +/*********************************************************************** + * WININET_ProxyPasswordDialog + */ +static INT_PTR WINAPI WININET_ProxyPasswordDialog( + HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + HWND hitem; + struct WININET_ErrorDlgParams *params; + CHAR szRealm[0x80], szServer[0x80]; + + if( uMsg == WM_INITDIALOG ) + { + TRACE("WM_INITDIALOG (%08lx)\n", lParam); + + /* save the parameter list */ + params = (struct WININET_ErrorDlgParams*) lParam; + SetWindowLongW( hdlg, GWL_USERDATA, lParam ); + + /* extract the Realm from the proxy response and show it */ + if( WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm) ) + { + hitem = GetDlgItem( hdlg, IDC_REALM ); + SetWindowTextA( hitem, szRealm ); + } + + /* extract the name of the proxy server */ + if( WININET_GetProxyServer( params->hRequest, + szServer, sizeof szServer) ) + { + hitem = GetDlgItem( hdlg, IDC_PROXY ); + SetWindowTextA( hitem, szServer ); + } + + WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); + + return TRUE; + } + + params = (struct WININET_ErrorDlgParams*) + GetWindowLongW( hdlg, GWL_USERDATA ); + + switch( uMsg ) + { + case WM_COMMAND: + if( wParam == IDOK ) + { + LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) params->hRequest; + CHAR username[0x20], password[0x20]; + + username[0] = 0; + hitem = GetDlgItem( hdlg, IDC_USERNAME ); + if( hitem ) + GetWindowTextA( hitem, username, sizeof username ); + + password[0] = 0; + hitem = GetDlgItem( hdlg, IDC_PASSWORD ); + if( hitem ) + GetWindowTextA( hitem, password, sizeof password ); + + hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); + if( hitem && + SendMessageA( hitem, BM_GETSTATE, 0, 0 ) && + WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm) && + WININET_GetProxyServer( params->hRequest, + szServer, sizeof szServer) ) + { + WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); + } + WININET_SetProxyAuthorization( lpwhr, username, password ); + + EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); + return TRUE; + } + if( wParam == IDCANCEL ) + { + EndDialog( hdlg, 0 ); + return TRUE; + } + break; + } + return FALSE; +} + +/*********************************************************************** + * WININET_GetConnectionStatus + */ +static INT WININET_GetConnectionStatus( HINTERNET hRequest ) +{ + CHAR szStatus[0x20]; + DWORD sz, index, dwStatus; + + TRACE("%p\n", hRequest ); + + sz = sizeof szStatus; + index = 0; + if( !HttpQueryInfoA( hRequest, HTTP_QUERY_STATUS_CODE, + szStatus, &sz, &index)) + return -1; + dwStatus = atoi( szStatus ); + + TRACE("request %p status = %ld\n", hRequest, dwStatus ); + + return dwStatus; +} + + +/*********************************************************************** + * InternetErrorDlg + */ +DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, + DWORD dwError, DWORD dwFlags, LPVOID* lppvData) +{ + struct WININET_ErrorDlgParams params; + HMODULE hwininet = GetModuleHandleA( "wininet.dll" ); + INT dwStatus; + + TRACE("%p %p %ld %08lx %p\n", hWnd, hRequest, dwError, dwFlags, lppvData); + + params.hWnd = hWnd; + params.hRequest = hRequest; + params.dwError = dwError; + params.dwFlags = dwFlags; + params.lppvData = lppvData; + + switch( dwError ) + { + case ERROR_SUCCESS: + if( !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) + return 0; + dwStatus = WININET_GetConnectionStatus( hRequest ); + if( HTTP_STATUS_PROXY_AUTH_REQ != dwStatus ) + return ERROR_SUCCESS; + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), + hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + + case ERROR_INTERNET_INCORRECT_PASSWORD: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), + hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + + case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: + case ERROR_INTERNET_INVALID_CA: + case ERROR_INTERNET_POST_IS_NON_SECURE: + case ERROR_INTERNET_SEC_CERT_CN_INVALID: + case ERROR_INTERNET_SEC_CERT_DATE_INVALID: + FIXME("Need to display dialog for error %ld\n", dwError); + return ERROR_SUCCESS; + } + return ERROR_INVALID_PARAMETER; +} diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 4462ec87536..cc86cb6b3db 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -83,8 +83,9 @@ BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWO void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr); BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen); INT HTTP_GetStdHeaderIndex(LPCSTR lpszField); -INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr); +BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr); INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField); +BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index); inline static LPSTR HTTP_strdup( LPCSTR str ) { @@ -373,6 +374,160 @@ end: return rc; } +/*********************************************************************** + * HTTP_Base64 + */ +static UINT HTTP_Base64( LPCSTR bin, LPSTR base64 ) +{ + UINT n = 0, x; + static LPSTR HTTP_Base64Enc = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + while( bin[0] ) + { + /* first 6 bits, all from bin[0] */ + base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2]; + x = (bin[0] & 3) << 4; + + /* next 6 bits, 2 from bin[0] and 4 from bin[1] */ + if( !bin[1] ) + { + base64[n++] = HTTP_Base64Enc[x]; + base64[n++] = '='; + base64[n++] = '='; + break; + } + base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ]; + x = ( bin[1] & 0x0f ) << 2; + + /* next 6 bits 4 from bin[1] and 2 from bin[2] */ + if( !bin[2] ) + { + base64[n++] = HTTP_Base64Enc[x]; + base64[n++] = '='; + break; + } + base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ]; + + /* last 6 bits, all from bin [2] */ + base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ]; + bin += 3; + } + base64[n] = 0; + return n; +} + +/*********************************************************************** + * HTTP_EncodeBasicAuth + * + * Encode the basic authentication string for HTTP 1.1 + */ +static LPSTR HTTP_EncodeBasicAuth( LPCSTR username, LPCSTR password) +{ + UINT len; + LPSTR in, out, szBasic = "Basic "; + + len = strlen( username ) + 1 + strlen ( password ) + 1; + in = HeapAlloc( GetProcessHeap(), 0, len ); + if( !in ) + return NULL; + + len = strlen(szBasic) + + (strlen( username ) + 1 + strlen ( password ))*2 + 1 + 1; + out = HeapAlloc( GetProcessHeap(), 0, len ); + if( out ) + { + strcpy( in, username ); + strcat( in, ":" ); + strcat( in, password ); + strcpy( out, szBasic ); + HTTP_Base64( in, &out[strlen(out)] ); + } + HeapFree( GetProcessHeap(), 0, in ); + + return out; +} + +/*********************************************************************** + * HTTP_InsertProxyAuthorization + * + * Insert the basic authorization field in the request header + */ +BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQA lpwhr, + LPCSTR username, LPCSTR password ) +{ + HTTPHEADERA hdr; + INT index; + + hdr.lpszField = "Proxy-Authorization"; + hdr.lpszValue = HTTP_EncodeBasicAuth( username, password ); + hdr.wFlags = HDR_ISREQUEST; + hdr.wCount = 0; + if( !hdr.lpszValue ) + return FALSE; + + TRACE("Inserting %s = %s\n", + debugstr_a( hdr.lpszField ), debugstr_a( hdr.lpszValue ) ); + + /* remove the old proxy authorization header */ + index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField ); + if( index >=0 ) + HTTP_DeleteCustomHeader( lpwhr, index ); + + HTTP_InsertCustomHeader(lpwhr, &hdr); + HeapFree( GetProcessHeap(), 0, hdr.lpszValue ); + + return TRUE; +} + +/*********************************************************************** + * HTTP_DealWithProxy + */ +static BOOL HTTP_DealWithProxy( LPWININETAPPINFOA hIC, + LPWININETHTTPSESSIONA lpwhs, LPWININETHTTPREQA lpwhr) +{ + char buf[MAXHOSTNAME]; + char proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ + char* url, *szNul = ""; + URL_COMPONENTSA UrlComponents; + + memset( &UrlComponents, 0, sizeof UrlComponents ); + UrlComponents.dwStructSize = sizeof UrlComponents; + UrlComponents.lpszHostName = buf; + UrlComponents.dwHostNameLength = MAXHOSTNAME; + + sprintf(proxy, "http://%s/", hIC->lpszProxy); + if( !InternetCrackUrlA(proxy, 0, 0, &UrlComponents) ) + return FALSE; + if( UrlComponents.dwHostNameLength == 0 ) + return FALSE; + + if( !lpwhr->lpszPath ) + lpwhr->lpszPath = szNul; + TRACE("server='%s' path='%s'\n", + lpwhs->lpszServerName, lpwhr->lpszPath); + /* for constant 15 see above */ + url = HeapAlloc(GetProcessHeap(), 0, + strlen(lpwhs->lpszServerName) + strlen(lpwhr->lpszPath) + 15); + + if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) + UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; + + sprintf(url, "http://%s:%d", lpwhs->lpszServerName, + lpwhs->nServerPort); + if( lpwhr->lpszPath[0] != '/' ) + strcat( url, "/" ); + strcat(url, lpwhr->lpszPath); + if(lpwhr->lpszPath != szNul) + HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); + lpwhr->lpszPath = url; + /* FIXME: Do I have to free lpwhs->lpszServerName here ? */ + lpwhs->lpszServerName = HTTP_strdup(UrlComponents.lpszHostName); + lpwhs->nServerPort = UrlComponents.nPort; + + return TRUE; +} + /*********************************************************************** * HTTP_HttpOpenRequestA (internal) * @@ -454,54 +609,19 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, char buf[MAXHOSTNAME]; URL_COMPONENTSA UrlComponents; - UrlComponents.lpszExtraInfo = NULL; - UrlComponents.lpszPassword = NULL; - UrlComponents.lpszScheme = NULL; - UrlComponents.lpszUrlPath = NULL; - UrlComponents.lpszUserName = NULL; + memset( &UrlComponents, 0, sizeof UrlComponents ); + UrlComponents.dwStructSize = sizeof UrlComponents; UrlComponents.lpszHostName = buf; UrlComponents.dwHostNameLength = MAXHOSTNAME; InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents); if (strlen(UrlComponents.lpszHostName)) lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName); - } else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) { - char buf[MAXHOSTNAME]; - char proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ - URL_COMPONENTSA UrlComponents; - - UrlComponents.lpszExtraInfo = NULL; - UrlComponents.lpszPassword = NULL; - UrlComponents.lpszScheme = NULL; - UrlComponents.lpszUrlPath = NULL; - UrlComponents.lpszUserName = NULL; - UrlComponents.lpszHostName = buf; - UrlComponents.dwHostNameLength = MAXHOSTNAME; - - sprintf(proxy, "http://%s/", hIC->lpszProxy); - InternetCrackUrlA(proxy, 0, 0, &UrlComponents); - if (strlen(UrlComponents.lpszHostName)) { - /* for constant 15 see above */ - char* url = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhs->lpszServerName) + strlen(lpwhr->lpszPath) + 15); - - if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) - UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; - - if(lpwhr->lpszHostName != 0) { - HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName); - lpwhr->lpszHostName = 0; - } - sprintf(url, "http://%s:%d/%s", lpwhs->lpszServerName, lpwhs->nServerPort, lpwhr->lpszPath); - if(lpwhr->lpszPath) - HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); - lpwhr->lpszPath = url; - /* FIXME: Do I have to free lpwhs->lpszServerName here ? */ - lpwhs->lpszServerName = HTTP_strdup(UrlComponents.lpszHostName); - lpwhs->nServerPort = UrlComponents.nPort; - } } else { lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName); } + if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) + HTTP_DealWithProxy( hIC, lpwhs, lpwhr ); if (hIC->lpszAgent) { @@ -913,6 +1033,11 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR /* if it's an absolute path, keep the same session info */ strcpy(path,lpszUrl); } + else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) + { + TRACE("Redirect through proxy\n"); + strcpy(path,lpszUrl); + } else { URL_COMPONENTSA urlComponents; @@ -937,9 +1062,22 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; - /* consider the current host as the referef */ +#if 0 + /* + * This upsets redirects to binary files on sourceforge.net + * and gives an html page instead of the target file + * Examination of the HTTP request sent by native wininet.dll + * reveals that it doesn't send a referrer in that case. + * Maybe there's a flag that enables this, or maybe a referrer + * shouldn't be added in case of a redirect. + */ + + /* consider the current host as the referrer */ if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName)) - HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW); + HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName, + HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE| + HTTP_ADDHDR_FLAG_ADD_IF_NEW); +#endif if (NULL != lpwhs->lpszServerName) HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); @@ -1087,6 +1225,13 @@ BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, requestStringLen += headerLength + 2; /* \r\n */ } + + /* if there isa proxy username and password, add it to the headers */ + if( hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword ) ) + { + HTTP_InsertProxyAuthorization( lpwhr, hIC->lpszProxyUsername, hIC->lpszProxyPassword ); + } + /* Calculate length of custom request headers */ for (i = 0; i < lpwhr->nCustHeaders; i++) { @@ -1264,60 +1409,6 @@ BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, nPosStart = nPosEnd; } } - - /* FIXME: is this right? I'm not sure if this should be here or elsewhere (the loop, too) - * FIXME: don't do this if they specify INTERNET_FLAG_NO_AUTO_REDIRECT */ - if (lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue) - { - URL_COMPONENTSA urlComponents; - char protocol[32], hostName[MAXHOSTNAME], userName[1024]; - char password[1024], path[2048], extra[1024]; - - TRACE("Got a Location header: Going around to a new location: %s", - debugstr_a(lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue)); - - urlComponents.dwStructSize = sizeof(URL_COMPONENTSA); - urlComponents.lpszScheme = protocol; - urlComponents.dwSchemeLength = 32; - urlComponents.lpszHostName = hostName; - urlComponents.dwHostNameLength = MAXHOSTNAME; - urlComponents.lpszUserName = userName; - urlComponents.dwUserNameLength = 1024; - urlComponents.lpszPassword = password; - urlComponents.dwPasswordLength = 1024; - urlComponents.lpszUrlPath = path; - urlComponents.dwUrlPathLength = 2048; - urlComponents.lpszExtraInfo = extra; - urlComponents.dwExtraInfoLength = 1024; - if (!InternetCrackUrlA(lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue, - strlen(lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue), - 0, &urlComponents)) - goto lend; - - if (urlComponents.nScheme != INTERNET_SCHEME_HTTP) - { - FIXME("cannot redirect to non HTTP page\n"); - goto lend; - } - - HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); - HeapAlloc(GetProcessHeap(), 0, strlen(path) + 1); - strcpy(lpwhr->lpszPath, path); - - if (urlComponents.dwHostNameLength) - { - HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName); - HeapAlloc(GetProcessHeap(), 0, strlen(hostName) + 1); - strcpy(lpwhr->lpszHostName, hostName); - } - - SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, NULL, 0); - - HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue); - lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue = NULL; - loop_next = TRUE; - } } while (loop_next); @@ -1699,6 +1790,8 @@ INT HTTP_GetStdHeaderIndex(LPCSTR lpszField) index = HTTP_QUERY_CONTENT_LENGTH; else if (!strcasecmp(lpszField,"User-Agent")) index = HTTP_QUERY_USER_AGENT; + else if (!strcasecmp(lpszField,"Proxy-Authenticate")) + index = HTTP_QUERY_PROXY_AUTHENTICATE; else { TRACE("Couldn't find %s in standard header table\n", lpszField); @@ -1757,8 +1850,7 @@ BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWO if (dwModifier & HTTP_ADDHDR_FLAG_REQ) hdr.wFlags |= HDR_ISREQUEST; - index = HTTP_InsertCustomHeader(lpwhr, &hdr); - return index >= 0; + return HTTP_InsertCustomHeader(lpwhr, &hdr); } } @@ -2011,10 +2103,11 @@ INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField) * Insert header into array * */ -INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr) +BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr) { INT count; LPHTTPHEADERA lph = NULL; + BOOL r = FALSE; TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue); count = lpwhr->nCustHeaders + 1; @@ -2031,15 +2124,14 @@ INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr) lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; lpwhr->nCustHeaders++; + r = TRUE; } else { INTERNET_SetLastError(ERROR_OUTOFMEMORY); - count = 0; } - TRACE("%d <--\n", count-1); - return count - 1; + return r; } @@ -2047,12 +2139,21 @@ INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr) * HTTP_DeleteCustomHeader (internal) * * Delete header from array - * + * If this function is called, the indexs may change. */ -BOOL HTTP_DeleteCustomHeader(INT index) +BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index) { - FIXME("STUB\n"); - return FALSE; + if( lpwhr->nCustHeaders <= 0 ) + return FALSE; + if( lpwhr->nCustHeaders >= index ) + return FALSE; + lpwhr->nCustHeaders--; + + memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1], + (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERA) ); + memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERA) ); + + return TRUE; } /*********************************************************************** diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 1d9232ef6b7..8f2a51b113e 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -208,6 +208,68 @@ BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl, } +/*********************************************************************** + * INTERNET_ConfigureProxyFromReg + * + * FIXME: + * The proxy may be specified in the form 'http=proxy.my.org' + * Presumably that means there can be ftp=ftpproxy.my.org too. + */ +static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOA lpwai ) +{ + HKEY key; + DWORD r, keytype, len, enabled; + LPSTR lpszInternetSettings = + "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; + + r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key); + if ( r != ERROR_SUCCESS ) + return FALSE; + + len = sizeof enabled; + r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype, + (BYTE*)&enabled, &len); + if( (r == ERROR_SUCCESS) && enabled ) + { + TRACE("Proxy is enabled.\n"); + + /* figure out how much memory the proxy setting takes */ + r = RegQueryValueExA( key, "ProxyServer", NULL, &keytype, + NULL, &len); + if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) ) + { + LPSTR szProxy, p, szHttp = "http="; + + szProxy=HeapAlloc( GetProcessHeap(), 0, len+1 ); + RegQueryValueExA( key, "ProxyServer", NULL, &keytype, + (BYTE*)szProxy, &len); + + /* find the http proxy, and strip away everything else */ + p = strstr( szProxy, szHttp ); + if( p ) + { + p += strlen(szHttp); + strcpy( szProxy, p ); + } + p = strchr( szProxy, ' ' ); + if( p ) + *p = 0; + + lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; + lpwai->lpszProxy = szProxy; + + TRACE("http proxy = %s\n", lpwai->lpszProxy); + } + else + ERR("Couldn't read proxy server settings.\n"); + } + else + TRACE("Proxy is not enabled.\n"); + RegCloseKey(key); + + return enabled; +} + /*********************************************************************** * InternetOpenA (WININET.@) * @@ -231,53 +293,42 @@ HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA)); if (NULL == lpwai) - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - else { - memset(lpwai, 0, sizeof(WININETAPPINFOA)); - lpwai->hdr.htype = WH_HINIT; - lpwai->hdr.lpwhparent = NULL; - lpwai->hdr.dwFlags = dwFlags; - if (NULL != lpszAgent) - { - if ((lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,strlen(lpszAgent)+1))) - strcpy( lpwai->lpszAgent, lpszAgent ); - } - if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) - { - HKEY key; - if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &key)) - { - DWORD keytype, len, enabled; - RegQueryValueExA(key, "ProxyEnable", NULL, NULL, (BYTE*)&enabled, NULL); - if(enabled) - { - if(!RegQueryValueExA(key, "ProxyServer", NULL, &keytype, NULL, &len) && len && keytype == REG_SZ) - { - lpwai->lpszProxy=HeapAlloc( GetProcessHeap(), 0, len+1 ); - RegQueryValueExA(key, "ProxyServer", NULL, &keytype, (BYTE*)lpwai->lpszProxy, &len); - TRACE("Proxy = %s\n", lpwai->lpszProxy); - dwAccessType = INTERNET_OPEN_TYPE_PROXY; - } - } - else - { - TRACE("Proxy is not enabled.\n"); - } - RegCloseKey(key); - } - } - else if (NULL != lpszProxy) - { - if ((lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0, strlen(lpszProxy)+1 ))) - strcpy( lpwai->lpszProxy, lpszProxy ); - } - if (NULL != lpszProxyBypass) - { - if ((lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0, strlen(lpszProxyBypass)+1))) - strcpy( lpwai->lpszProxyBypass, lpszProxyBypass ); - } - lpwai->dwAccessType = dwAccessType; + INTERNET_SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + memset(lpwai, 0, sizeof(WININETAPPINFOA)); + lpwai->hdr.htype = WH_HINIT; + lpwai->hdr.lpwhparent = NULL; + lpwai->hdr.dwFlags = dwFlags; + lpwai->dwAccessType = dwAccessType; + lpwai->lpszProxyUsername = NULL; + lpwai->lpszProxyPassword = NULL; + + if (NULL != lpszAgent) + { + lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0, + strlen(lpszAgent)+1); + if (lpwai->lpszAgent) + strcpy( lpwai->lpszAgent, lpszAgent ); + } + if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) + INTERNET_ConfigureProxyFromReg( lpwai ); + else if (NULL != lpszProxy) + { + lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0, + strlen(lpszProxy)+1); + if (lpwai->lpszProxy) + strcpy( lpwai->lpszProxy, lpszProxy ); + } + + if (NULL != lpszProxyBypass) + { + lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0, + strlen(lpszProxyBypass)+1); + if (lpwai->lpszProxyBypass) + strcpy( lpwai->lpszProxyBypass, lpszProxyBypass ); } TRACE("returning %p\n", (HINTERNET)lpwai); @@ -648,6 +699,12 @@ VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai) if (lpwai->lpszProxyBypass) HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass); + if (lpwai->lpszProxyUsername) + HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername); + + if (lpwai->lpszProxyPassword) + HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword); + HeapFree(GetProcessHeap(), 0, lpwai); } diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index e6cc1b76107..63396335eb0 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -73,6 +73,8 @@ typedef struct LPSTR lpszAgent; LPSTR lpszProxy; LPSTR lpszProxyBypass; + LPSTR lpszProxyUsername; + LPSTR lpszProxyPassword; DWORD dwAccessType; INTERNET_STATUS_CALLBACK lpfnStatusCB; } WININETAPPINFOA, *LPWININETAPPINFOA; @@ -281,6 +283,8 @@ VOID SendAsyncCallbackInt(LPWININETAPPINFOA hIC, HINTERNET hHttpSession, DWORD dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo , DWORD dwStatusInfoLength); +BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQA lpwhr, + LPCSTR username, LPCSTR password ); BOOL NETCON_connected(WININET_NETCONNECTION *connection); void NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); diff --git a/dlls/wininet/resource.h b/dlls/wininet/resource.h new file mode 100644 index 00000000000..93336de7f85 --- /dev/null +++ b/dlls/wininet/resource.h @@ -0,0 +1,27 @@ +/* + * Wininet resource definitions + * + * Copyright 2003 Mike McCormack 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define IDD_PROXYDLG 0x400 + +#define IDC_PROXY 0x401 +#define IDC_REALM 0x402 +#define IDC_USERNAME 0x403 +#define IDC_PASSWORD 0x404 +#define IDC_SAVEPASSWORD 0x405 diff --git a/dlls/wininet/rsrc.rc b/dlls/wininet/rsrc.rc new file mode 100644 index 00000000000..ddda1bb2c11 --- /dev/null +++ b/dlls/wininet/rsrc.rc @@ -0,0 +1,42 @@ +/* + * Top level resource file for Wininet + * + * Copyright 2003 Mike McCormack 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "windef.h" +#include "winuser.h" +#include "winnls.h" + +#include "resource.h" + +/* + * Everything that does not depend on language, + * like textless bitmaps etc, go into the + * neutral language. This will prevent them from + * being duplicated for each language. + */ +/* #include "wininet_xx.rc" */ + +/* + * Everything specific to any language goes + * in one of the specific files. + * Note that you can and may override resources + * which also have a neutral version. This is to + * get localized bitmaps for example. + */ +#include "wininet_En.rc" diff --git a/dlls/wininet/wininet.spec b/dlls/wininet/wininet.spec index 055202edfec..a29676ecc32 100644 --- a/dlls/wininet/wininet.spec +++ b/dlls/wininet/wininet.spec @@ -101,7 +101,7 @@ @ stdcall InternetCreateUrlW(ptr long ptr ptr) @ stub InternetDebugGetLocalTime @ stub InternetDial -@ stub InternetErrorDlg +@ stdcall InternetErrorDlg(long long long long ptr) @ stdcall InternetFindNextFileA(ptr ptr) @ stub InternetFindNextFileW @ stub InternetGetCertByURL diff --git a/dlls/wininet/wininet_En.rc b/dlls/wininet/wininet_En.rc new file mode 100644 index 00000000000..d40b842fc50 --- /dev/null +++ b/dlls/wininet/wininet_En.rc @@ -0,0 +1,39 @@ +/* + * Copyright 2003 Mike McCormack 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter Network Password" +FONT 8, "Helv" +{ + LTEXT "Please enter your username and password:", -1, 40, 6, 150, 15 + LTEXT "Proxy", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "User", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Save this password (insecure)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +}