2 * Copyright 2005-2006 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
38 static struct list name_space_list
= LIST_INIT(name_space_list
);
39 static struct list mime_filter_list
= LIST_INIT(mime_filter_list
);
41 static CRITICAL_SECTION session_cs
;
42 static CRITICAL_SECTION_DEBUG session_cs_dbg
=
45 { &session_cs_dbg
.ProcessLocksList
, &session_cs_dbg
.ProcessLocksList
},
46 0, 0, { (DWORD_PTR
)(__FILE__
": session") }
48 static CRITICAL_SECTION session_cs
= { &session_cs_dbg
, -1, 0, 0, 0, 0 };
50 static const WCHAR internet_settings_keyW
[] =
51 {'S','O','F','T','W','A','R','E',
52 '\\','M','i','c','r','o','s','o','f','t',
53 '\\','W','i','n','d','o','w','s',
54 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
55 '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
57 static name_space
*find_name_space(LPCWSTR protocol
)
61 LIST_FOR_EACH_ENTRY(iter
, &name_space_list
, name_space
, entry
) {
62 if(!strcmpiW(iter
->protocol
, protocol
))
69 static HRESULT
get_protocol_cf(LPCWSTR schema
, DWORD schema_len
, CLSID
*pclsid
, IClassFactory
**ret
)
73 DWORD res
, type
, size
;
78 static const WCHAR wszProtocolsKey
[] =
79 {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'};
80 static const WCHAR wszCLSID
[] = {'C','L','S','I','D',0};
82 wszKey
= heap_alloc(sizeof(wszProtocolsKey
)+(schema_len
+1)*sizeof(WCHAR
));
83 memcpy(wszKey
, wszProtocolsKey
, sizeof(wszProtocolsKey
));
84 memcpy(wszKey
+ sizeof(wszProtocolsKey
)/sizeof(WCHAR
), schema
, (schema_len
+1)*sizeof(WCHAR
));
86 res
= RegOpenKeyW(HKEY_CLASSES_ROOT
, wszKey
, &hkey
);
88 if(res
!= ERROR_SUCCESS
) {
89 TRACE("Could not open protocol handler key\n");
93 size
= sizeof(str_clsid
);
94 res
= RegQueryValueExW(hkey
, wszCLSID
, NULL
, &type
, (LPBYTE
)str_clsid
, &size
);
96 if(res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
97 WARN("Could not get protocol CLSID res=%d\n", res
);
101 hres
= CLSIDFromString(str_clsid
, &clsid
);
103 WARN("CLSIDFromString failed: %08x\n", hres
);
113 hres
= CoGetClassObject(&clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IClassFactory
, (void**)ret
);
114 return SUCCEEDED(hres
) ? S_OK
: MK_E_SYNTAX
;
117 HRESULT
register_namespace(IClassFactory
*cf
, REFIID clsid
, LPCWSTR protocol
, BOOL urlmon_protocol
)
119 name_space
*new_name_space
;
121 new_name_space
= heap_alloc(sizeof(name_space
));
124 IClassFactory_AddRef(cf
);
125 new_name_space
->cf
= cf
;
126 new_name_space
->clsid
= *clsid
;
127 new_name_space
->urlmon
= urlmon_protocol
;
128 new_name_space
->protocol
= heap_strdupW(protocol
);
130 EnterCriticalSection(&session_cs
);
132 list_add_head(&name_space_list
, &new_name_space
->entry
);
134 LeaveCriticalSection(&session_cs
);
139 static HRESULT
unregister_namespace(IClassFactory
*cf
, LPCWSTR protocol
)
143 EnterCriticalSection(&session_cs
);
145 LIST_FOR_EACH_ENTRY(iter
, &name_space_list
, name_space
, entry
) {
146 if(iter
->cf
== cf
&& !strcmpiW(iter
->protocol
, protocol
)) {
147 list_remove(&iter
->entry
);
149 LeaveCriticalSection(&session_cs
);
152 IClassFactory_Release(iter
->cf
);
153 heap_free(iter
->protocol
);
159 LeaveCriticalSection(&session_cs
);
163 BOOL
is_registered_protocol(LPCWSTR url
)
169 hres
= CoInternetParseUrl(url
, PARSE_SCHEMA
, 0, schema
, sizeof(schema
)/sizeof(schema
[0]),
174 return get_protocol_cf(schema
, schema_len
, NULL
, NULL
) == S_OK
;
177 IInternetProtocolInfo
*get_protocol_info(LPCWSTR url
)
179 IInternetProtocolInfo
*ret
= NULL
;
186 hres
= CoInternetParseUrl(url
, PARSE_SCHEMA
, 0, schema
, sizeof(schema
)/sizeof(schema
[0]),
188 if(FAILED(hres
) || !schema_len
)
191 EnterCriticalSection(&session_cs
);
193 ns
= find_name_space(schema
);
194 if(ns
&& !ns
->urlmon
) {
195 hres
= IClassFactory_QueryInterface(ns
->cf
, &IID_IInternetProtocolInfo
, (void**)&ret
);
197 hres
= IClassFactory_CreateInstance(ns
->cf
, NULL
, &IID_IInternetProtocolInfo
, (void**)&ret
);
200 LeaveCriticalSection(&session_cs
);
202 if(ns
&& SUCCEEDED(hres
))
205 hres
= get_protocol_cf(schema
, schema_len
, NULL
, &cf
);
209 hres
= IClassFactory_QueryInterface(cf
, &IID_IInternetProtocolInfo
, (void**)&ret
);
211 IClassFactory_CreateInstance(cf
, NULL
, &IID_IInternetProtocolInfo
, (void**)&ret
);
212 IClassFactory_Release(cf
);
217 HRESULT
get_protocol_handler(IUri
*uri
, CLSID
*clsid
, BOOL
*urlmon_protocol
, IClassFactory
**ret
)
225 /* FIXME: Avoid GetSchemeName call for known schemes */
226 hres
= IUri_GetSchemeName(uri
, &scheme
);
230 EnterCriticalSection(&session_cs
);
232 ns
= find_name_space(scheme
);
235 IClassFactory_AddRef(*ret
);
239 *urlmon_protocol
= ns
->urlmon
;
242 LeaveCriticalSection(&session_cs
);
248 *urlmon_protocol
= FALSE
;
249 hres
= get_protocol_cf(scheme
, SysStringLen(scheme
), clsid
, ret
);
252 SysFreeString(scheme
);
256 IInternetProtocol
*get_mime_filter(LPCWSTR mime
)
258 static const WCHAR filtersW
[] = {'P','r','o','t','o','c','o','l','s',
259 '\\','F','i','l','t','e','r',0 };
260 static const WCHAR CLSIDW
[] = {'C','L','S','I','D',0};
262 IClassFactory
*cf
= NULL
;
263 IInternetProtocol
*ret
;
268 DWORD res
, type
, size
;
271 EnterCriticalSection(&session_cs
);
273 LIST_FOR_EACH_ENTRY(iter
, &mime_filter_list
, mime_filter
, entry
) {
274 if(!strcmpW(iter
->mime
, mime
)) {
280 LeaveCriticalSection(&session_cs
);
283 hres
= IClassFactory_CreateInstance(cf
, NULL
, &IID_IInternetProtocol
, (void**)&ret
);
285 WARN("CreateInstance failed: %08x\n", hres
);
292 res
= RegOpenKeyW(HKEY_CLASSES_ROOT
, filtersW
, &hlist
);
293 if(res
!= ERROR_SUCCESS
) {
294 TRACE("Could not open MIME filters key\n");
298 res
= RegOpenKeyW(hlist
, mime
, &hfilter
);
300 if(res
!= ERROR_SUCCESS
)
303 size
= sizeof(clsidw
);
304 res
= RegQueryValueExW(hfilter
, CLSIDW
, NULL
, &type
, (LPBYTE
)clsidw
, &size
);
305 CloseHandle(hfilter
);
306 if(res
!=ERROR_SUCCESS
|| type
!=REG_SZ
) {
307 WARN("Could not get filter CLSID for %s\n", debugstr_w(mime
));
311 hres
= CLSIDFromString(clsidw
, &clsid
);
313 WARN("CLSIDFromString failed for %s (%x)\n", debugstr_w(mime
), hres
);
317 hres
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IInternetProtocol
, (void**)&ret
);
319 WARN("CoCreateInstance failed: %08x\n", hres
);
326 static HRESULT WINAPI
InternetSession_QueryInterface(IInternetSession
*iface
,
327 REFIID riid
, void **ppv
)
329 TRACE("(%s %p)\n", debugstr_guid(riid
), ppv
);
331 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetSession
, riid
)) {
333 IInternetSession_AddRef(iface
);
338 return E_NOINTERFACE
;
341 static ULONG WINAPI
InternetSession_AddRef(IInternetSession
*iface
)
348 static ULONG WINAPI
InternetSession_Release(IInternetSession
*iface
)
351 URLMON_UnlockModule();
355 static HRESULT WINAPI
InternetSession_RegisterNameSpace(IInternetSession
*iface
,
356 IClassFactory
*pCF
, REFCLSID rclsid
, LPCWSTR pwzProtocol
, ULONG cPatterns
,
357 const LPCWSTR
*ppwzPatterns
, DWORD dwReserved
)
359 TRACE("(%p %s %s %d %p %d)\n", pCF
, debugstr_guid(rclsid
), debugstr_w(pwzProtocol
),
360 cPatterns
, ppwzPatterns
, dwReserved
);
362 if(cPatterns
|| ppwzPatterns
)
363 FIXME("patterns not supported\n");
365 WARN("dwReserved = %d\n", dwReserved
);
367 if(!pCF
|| !pwzProtocol
)
370 return register_namespace(pCF
, rclsid
, pwzProtocol
, FALSE
);
373 static HRESULT WINAPI
InternetSession_UnregisterNameSpace(IInternetSession
*iface
,
374 IClassFactory
*pCF
, LPCWSTR pszProtocol
)
376 TRACE("(%p %s)\n", pCF
, debugstr_w(pszProtocol
));
378 if(!pCF
|| !pszProtocol
)
381 return unregister_namespace(pCF
, pszProtocol
);
384 static HRESULT WINAPI
InternetSession_RegisterMimeFilter(IInternetSession
*iface
,
385 IClassFactory
*pCF
, REFCLSID rclsid
, LPCWSTR pwzType
)
389 TRACE("(%p %s %s)\n", pCF
, debugstr_guid(rclsid
), debugstr_w(pwzType
));
391 filter
= heap_alloc(sizeof(mime_filter
));
393 IClassFactory_AddRef(pCF
);
395 filter
->clsid
= *rclsid
;
396 filter
->mime
= heap_strdupW(pwzType
);
398 EnterCriticalSection(&session_cs
);
400 list_add_head(&mime_filter_list
, &filter
->entry
);
402 LeaveCriticalSection(&session_cs
);
407 static HRESULT WINAPI
InternetSession_UnregisterMimeFilter(IInternetSession
*iface
,
408 IClassFactory
*pCF
, LPCWSTR pwzType
)
412 TRACE("(%p %s)\n", pCF
, debugstr_w(pwzType
));
414 EnterCriticalSection(&session_cs
);
416 LIST_FOR_EACH_ENTRY(iter
, &mime_filter_list
, mime_filter
, entry
) {
417 if(iter
->cf
== pCF
&& !strcmpW(iter
->mime
, pwzType
)) {
418 list_remove(&iter
->entry
);
420 LeaveCriticalSection(&session_cs
);
422 IClassFactory_Release(iter
->cf
);
423 heap_free(iter
->mime
);
429 LeaveCriticalSection(&session_cs
);
433 static HRESULT WINAPI
InternetSession_CreateBinding(IInternetSession
*iface
,
434 LPBC pBC
, LPCWSTR szUrl
, IUnknown
*pUnkOuter
, IUnknown
**ppUnk
,
435 IInternetProtocol
**ppOInetProt
, DWORD dwOption
)
437 BindProtocol
*protocol
;
440 TRACE("(%p %s %p %p %p %08x)\n", pBC
, debugstr_w(szUrl
), pUnkOuter
, ppUnk
,
441 ppOInetProt
, dwOption
);
443 if(pBC
|| pUnkOuter
|| ppUnk
|| dwOption
)
444 FIXME("Unsupported arguments\n");
446 hres
= create_binding_protocol(FALSE
, &protocol
);
450 *ppOInetProt
= (IInternetProtocol
*)&protocol
->IInternetProtocolEx_iface
;
454 static HRESULT WINAPI
InternetSession_SetSessionOption(IInternetSession
*iface
,
455 DWORD dwOption
, LPVOID pBuffer
, DWORD dwBufferLength
, DWORD dwReserved
)
457 FIXME("(%08x %p %d %d)\n", dwOption
, pBuffer
, dwBufferLength
, dwReserved
);
461 static const IInternetSessionVtbl InternetSessionVtbl
= {
462 InternetSession_QueryInterface
,
463 InternetSession_AddRef
,
464 InternetSession_Release
,
465 InternetSession_RegisterNameSpace
,
466 InternetSession_UnregisterNameSpace
,
467 InternetSession_RegisterMimeFilter
,
468 InternetSession_UnregisterMimeFilter
,
469 InternetSession_CreateBinding
,
470 InternetSession_SetSessionOption
473 static IInternetSession InternetSession
= { &InternetSessionVtbl
};
475 /***********************************************************************
476 * CoInternetGetSession (URLMON.@)
478 * Create a new internet session and return an IInternetSession interface
482 * dwSessionMode [I] Mode for the internet session
483 * ppIInternetSession [O] Destination for creates IInternetSession object
484 * dwReserved [I] Reserved, must be 0.
487 * Success: S_OK. ppIInternetSession contains the IInternetSession interface.
488 * Failure: E_INVALIDARG, if any argument is invalid, or
489 * E_OUTOFMEMORY if memory allocation fails.
491 HRESULT WINAPI
CoInternetGetSession(DWORD dwSessionMode
, IInternetSession
**ppIInternetSession
,
494 TRACE("(%d %p %d)\n", dwSessionMode
, ppIInternetSession
, dwReserved
);
497 ERR("dwSessionMode=%d\n", dwSessionMode
);
499 ERR("dwReserved=%d\n", dwReserved
);
501 IInternetSession_AddRef(&InternetSession
);
502 *ppIInternetSession
= &InternetSession
;
506 /**************************************************************************
507 * UrlMkGetSessionOption (URLMON.@)
509 static BOOL
get_url_encoding(HKEY root
, DWORD
*encoding
)
511 DWORD size
= sizeof(DWORD
), res
, type
;
514 static const WCHAR wszUrlEncoding
[] = {'U','r','l','E','n','c','o','d','i','n','g',0};
516 res
= RegOpenKeyW(root
, internet_settings_keyW
, &hkey
);
517 if(res
!= ERROR_SUCCESS
)
520 res
= RegQueryValueExW(hkey
, wszUrlEncoding
, NULL
, &type
, (LPBYTE
)encoding
, &size
);
523 return res
== ERROR_SUCCESS
;
526 static LPWSTR user_agent
;
528 static void ensure_useragent(void)
530 OSVERSIONINFOW info
= {sizeof(info
)};
531 const WCHAR
*os_type
, *is_nt
;
532 WCHAR buf
[512], *ret
, *tmp
;
538 static const WCHAR formatW
[] =
539 {'M','o','z','i','l','l','a','/','4','.','0',
540 ' ','(','c','o','m','p','a','t','i','b','l','e',';',
541 ' ','M','S','I','E',' ','8','.','0',';',
542 ' ','W','i','n','d','o','w','s',' ','%','s','%','d','.','%','d',';',
543 ' ','%','s','T','r','i','d','e','n','t','/','5','.','0',0};
544 static const WCHAR post_platform_keyW
[] =
545 {'S','O','F','T','W','A','R','E',
546 '\\','M','i','c','r','o','s','o','f','t',
547 '\\','W','i','n','d','o','w','s',
548 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
549 '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',
550 '\\','5','.','0','\\','U','s','e','r',' ','A','g','e','n','t',
551 '\\','P','o','s','t',' ','P','l','a','t','f','o','r','m',0};
552 static const WCHAR ntW
[] = {'N','T',' ',0};
553 static const WCHAR win64W
[] = {'W','i','n','6','4',';',' ','x','6','4',';',' ',0};
554 static const WCHAR wow64W
[] = {'W','O','W','6','4',';',' ',0};
555 static const WCHAR emptyW
[] = {0};
560 GetVersionExW(&info
);
561 is_nt
= info
.dwPlatformId
== VER_PLATFORM_WIN32_NT
? ntW
: emptyW
;
563 if(sizeof(void*) == 8)
565 else if(IsWow64Process(GetCurrentProcess(), &is_wow
) && is_wow
)
570 sprintfW(buf
, formatW
, is_nt
, info
.dwMajorVersion
, info
.dwMinorVersion
, os_type
);
574 ret
= heap_alloc(size
* sizeof(WCHAR
));
578 memcpy(ret
, buf
, len
*sizeof(WCHAR
));
580 res
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, post_platform_keyW
, &key
);
581 if(res
== ERROR_SUCCESS
) {
585 value_len
= sizeof(buf
)/sizeof(WCHAR
);
586 res
= RegEnumValueW(key
, idx
, buf
, &value_len
, NULL
, NULL
, NULL
, NULL
);
587 if(res
!= ERROR_SUCCESS
)
591 if(len
+ value_len
+ 2 /* strlen("; ") */ + 1 /* trailing ')' */ >= size
) {
592 tmp
= heap_realloc(ret
, (size
*2+value_len
)*sizeof(WCHAR
));
596 size
= size
*2+value_len
;
601 memcpy(ret
+len
, buf
, value_len
*sizeof(WCHAR
));
612 TRACE("Using user agent %s\n", debugstr_w(user_agent
));
615 LPWSTR
get_useragent(void)
621 EnterCriticalSection(&session_cs
);
622 ret
= heap_strdupW(user_agent
);
623 LeaveCriticalSection(&session_cs
);
628 HRESULT WINAPI
UrlMkGetSessionOption(DWORD dwOption
, LPVOID pBuffer
, DWORD dwBufferLength
,
629 DWORD
* pdwBufferLength
, DWORD dwReserved
)
631 TRACE("(%x, %p, %d, %p)\n", dwOption
, pBuffer
, dwBufferLength
, pdwBufferLength
);
634 WARN("dwReserved = %d\n", dwReserved
);
637 case URLMON_OPTION_USERAGENT
: {
638 HRESULT hres
= E_OUTOFMEMORY
;
644 EnterCriticalSection(&session_cs
);
648 size
= WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, NULL
, 0, NULL
, NULL
);
649 *pdwBufferLength
= size
;
650 if(size
<= dwBufferLength
) {
652 WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, pBuffer
, size
, NULL
, NULL
);
658 LeaveCriticalSection(&session_cs
);
660 /* Tests prove that we have to return E_OUTOFMEMORY on success. */
663 case URLMON_OPTION_URL_ENCODING
: {
666 if(!pBuffer
|| dwBufferLength
< sizeof(DWORD
) || !pdwBufferLength
)
669 if(!get_url_encoding(HKEY_CURRENT_USER
, &encoding
))
670 get_url_encoding(HKEY_LOCAL_MACHINE
, &encoding
);
672 *pdwBufferLength
= sizeof(DWORD
);
673 *(DWORD
*)pBuffer
= encoding
? URL_ENCODING_DISABLE_UTF8
: URL_ENCODING_ENABLE_UTF8
;
677 FIXME("unsupported option %x\n", dwOption
);
683 /**************************************************************************
684 * UrlMkSetSessionOption (URLMON.@)
686 HRESULT WINAPI
UrlMkSetSessionOption(DWORD dwOption
, LPVOID pBuffer
, DWORD dwBufferLength
,
689 TRACE("(%x %p %x)\n", dwOption
, pBuffer
, dwBufferLength
);
692 case URLMON_OPTION_USERAGENT
: {
693 LPWSTR new_user_agent
;
697 if(!pBuffer
|| !dwBufferLength
)
700 for(len
=0; len
<dwBufferLength
&& buf
[len
]; len
++);
702 TRACE("Setting user agent %s\n", debugstr_an(buf
, len
));
704 size
= MultiByteToWideChar(CP_ACP
, 0, buf
, len
, NULL
, 0);
705 new_user_agent
= heap_alloc((size
+1)*sizeof(WCHAR
));
707 return E_OUTOFMEMORY
;
708 MultiByteToWideChar(CP_ACP
, 0, buf
, len
, new_user_agent
, size
);
709 new_user_agent
[size
] = 0;
711 EnterCriticalSection(&session_cs
);
713 heap_free(user_agent
);
714 user_agent
= new_user_agent
;
715 update_user_agent(user_agent
);
717 LeaveCriticalSection(&session_cs
);
721 FIXME("Unknown option %x\n", dwOption
);
728 /**************************************************************************
729 * ObtainUserAgentString (URLMON.@)
731 HRESULT WINAPI
ObtainUserAgentString(DWORD dwOption
, LPSTR pcszUAOut
, DWORD
*cbSize
)
734 HRESULT hres
= E_FAIL
;
736 TRACE("(%d %p %p)\n", dwOption
, pcszUAOut
, cbSize
);
738 if(!pcszUAOut
|| !cbSize
)
741 EnterCriticalSection(&session_cs
);
745 size
= WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, NULL
, 0, NULL
, NULL
);
747 if(size
<= *cbSize
) {
748 WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, pcszUAOut
, *cbSize
, NULL
, NULL
);
751 hres
= E_OUTOFMEMORY
;
757 LeaveCriticalSection(&session_cs
);
761 void free_session(void)
763 name_space
*ns_iter
, *ns_last
;
764 mime_filter
*mf_iter
, *mf_last
;
766 LIST_FOR_EACH_ENTRY_SAFE(ns_iter
, ns_last
, &name_space_list
, name_space
, entry
) {
768 IClassFactory_Release(ns_iter
->cf
);
769 heap_free(ns_iter
->protocol
);
773 LIST_FOR_EACH_ENTRY_SAFE(mf_iter
, mf_last
, &mime_filter_list
, mime_filter
, entry
) {
774 IClassFactory_Release(mf_iter
->cf
);
775 heap_free(mf_iter
->mime
);
779 heap_free(user_agent
);