xref: /reactos/dll/win32/winhttp/session.c (revision 9048bdf9)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright 2008 Hans Leidekker for CodeWeavers
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
5c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
6c2c66affSColin Finck  * License as published by the Free Software Foundation; either
7c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
8c2c66affSColin Finck  *
9c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
10c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12c2c66affSColin Finck  * Lesser General Public License for more details.
13c2c66affSColin Finck  *
14c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
15c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
16c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17c2c66affSColin Finck  */
18c2c66affSColin Finck 
19c2c66affSColin Finck #include "winhttp_private.h"
20c2c66affSColin Finck 
21c2c66affSColin Finck #include <wincrypt.h>
22c2c66affSColin Finck #include <winreg.h>
23c2c66affSColin Finck #include <dispex.h>
24c2c66affSColin Finck #include <activscp.h>
25c2c66affSColin Finck 
26c2c66affSColin Finck #define DEFAULT_RESOLVE_TIMEOUT     0
27c2c66affSColin Finck #define DEFAULT_CONNECT_TIMEOUT     20000
28c2c66affSColin Finck #define DEFAULT_SEND_TIMEOUT        30000
29c2c66affSColin Finck #define DEFAULT_RECEIVE_TIMEOUT     30000
30c2c66affSColin Finck 
31c2c66affSColin Finck void set_last_error( DWORD error )
32c2c66affSColin Finck {
33c2c66affSColin Finck     /* FIXME */
34c2c66affSColin Finck     SetLastError( error );
35c2c66affSColin Finck }
36c2c66affSColin Finck 
37c2c66affSColin Finck DWORD get_last_error( void )
38c2c66affSColin Finck {
39c2c66affSColin Finck     /* FIXME */
40c2c66affSColin Finck     return GetLastError();
41c2c66affSColin Finck }
42c2c66affSColin Finck 
43c2c66affSColin Finck void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
44c2c66affSColin Finck {
45c2c66affSColin Finck     if (hdr->callback && (hdr->notify_mask & status))
46c2c66affSColin Finck     {
47c2c66affSColin Finck         TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
48c2c66affSColin Finck         hdr->callback( hdr->handle, hdr->context, status, info, buflen );
49c2c66affSColin Finck         TRACE("returning from 0x%08x callback\n", status);
50c2c66affSColin Finck     }
51c2c66affSColin Finck }
52c2c66affSColin Finck 
53c2c66affSColin Finck /***********************************************************************
54c2c66affSColin Finck  *          WinHttpCheckPlatform (winhttp.@)
55c2c66affSColin Finck  */
56c2c66affSColin Finck BOOL WINAPI WinHttpCheckPlatform( void )
57c2c66affSColin Finck {
58c2c66affSColin Finck     TRACE("\n");
59c2c66affSColin Finck     return TRUE;
60c2c66affSColin Finck }
61c2c66affSColin Finck 
62c2c66affSColin Finck /***********************************************************************
63c2c66affSColin Finck  *          session_destroy (internal)
64c2c66affSColin Finck  */
65c2c66affSColin Finck static void session_destroy( object_header_t *hdr )
66c2c66affSColin Finck {
67c2c66affSColin Finck     session_t *session = (session_t *)hdr;
68c2c66affSColin Finck     struct list *item, *next;
69c2c66affSColin Finck     domain_t *domain;
70c2c66affSColin Finck 
71c2c66affSColin Finck     TRACE("%p\n", session);
72c2c66affSColin Finck 
73c2c66affSColin Finck     if (session->unload_event) SetEvent( session->unload_event );
74*9048bdf9SAmine Khaldi     if (session->cred_handle_initialized) FreeCredentialsHandle( &session->cred_handle );
75c2c66affSColin Finck 
76c2c66affSColin Finck     LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
77c2c66affSColin Finck     {
78c2c66affSColin Finck         domain = LIST_ENTRY( item, domain_t, entry );
79c2c66affSColin Finck         delete_domain( domain );
80c2c66affSColin Finck     }
81c2c66affSColin Finck     heap_free( session->agent );
82c2c66affSColin Finck     heap_free( session->proxy_server );
83c2c66affSColin Finck     heap_free( session->proxy_bypass );
84c2c66affSColin Finck     heap_free( session->proxy_username );
85c2c66affSColin Finck     heap_free( session->proxy_password );
86c2c66affSColin Finck     heap_free( session );
87c2c66affSColin Finck }
88c2c66affSColin Finck 
89c2c66affSColin Finck static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
90c2c66affSColin Finck {
91c2c66affSColin Finck     session_t *session = (session_t *)hdr;
92c2c66affSColin Finck 
93c2c66affSColin Finck     switch (option)
94c2c66affSColin Finck     {
95c2c66affSColin Finck     case WINHTTP_OPTION_REDIRECT_POLICY:
96c2c66affSColin Finck     {
97c2c66affSColin Finck         if (!buffer || *buflen < sizeof(DWORD))
98c2c66affSColin Finck         {
99c2c66affSColin Finck             *buflen = sizeof(DWORD);
100c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
101c2c66affSColin Finck             return FALSE;
102c2c66affSColin Finck         }
103c2c66affSColin Finck 
104c2c66affSColin Finck         *(DWORD *)buffer = hdr->redirect_policy;
105c2c66affSColin Finck         *buflen = sizeof(DWORD);
106c2c66affSColin Finck         return TRUE;
107c2c66affSColin Finck     }
108c2c66affSColin Finck     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
109c2c66affSColin Finck         *(DWORD *)buffer = session->resolve_timeout;
110c2c66affSColin Finck         *buflen = sizeof(DWORD);
111c2c66affSColin Finck         return TRUE;
112c2c66affSColin Finck     case WINHTTP_OPTION_CONNECT_TIMEOUT:
113c2c66affSColin Finck         *(DWORD *)buffer = session->connect_timeout;
114c2c66affSColin Finck         *buflen = sizeof(DWORD);
115c2c66affSColin Finck         return TRUE;
116c2c66affSColin Finck     case WINHTTP_OPTION_SEND_TIMEOUT:
117c2c66affSColin Finck         *(DWORD *)buffer = session->send_timeout;
118c2c66affSColin Finck         *buflen = sizeof(DWORD);
119c2c66affSColin Finck         return TRUE;
120c2c66affSColin Finck     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
121c2c66affSColin Finck         *(DWORD *)buffer = session->recv_timeout;
122c2c66affSColin Finck         *buflen = sizeof(DWORD);
123c2c66affSColin Finck         return TRUE;
124c2c66affSColin Finck     default:
125c2c66affSColin Finck         FIXME("unimplemented option %u\n", option);
126c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
127c2c66affSColin Finck         return FALSE;
128c2c66affSColin Finck     }
129c2c66affSColin Finck }
130c2c66affSColin Finck 
131c2c66affSColin Finck static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
132c2c66affSColin Finck {
133c2c66affSColin Finck     session_t *session = (session_t *)hdr;
134c2c66affSColin Finck 
135c2c66affSColin Finck     switch (option)
136c2c66affSColin Finck     {
137c2c66affSColin Finck     case WINHTTP_OPTION_PROXY:
138c2c66affSColin Finck     {
139c2c66affSColin Finck         WINHTTP_PROXY_INFO *pi = buffer;
140c2c66affSColin Finck 
141c2c66affSColin Finck         FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
142c2c66affSColin Finck         return TRUE;
143c2c66affSColin Finck     }
144c2c66affSColin Finck     case WINHTTP_OPTION_REDIRECT_POLICY:
145c2c66affSColin Finck     {
146c2c66affSColin Finck         DWORD policy;
147c2c66affSColin Finck 
148c2c66affSColin Finck         if (buflen != sizeof(policy))
149c2c66affSColin Finck         {
150c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
151c2c66affSColin Finck             return FALSE;
152c2c66affSColin Finck         }
153c2c66affSColin Finck 
154c2c66affSColin Finck         policy = *(DWORD *)buffer;
155c2c66affSColin Finck         TRACE("0x%x\n", policy);
156c2c66affSColin Finck         hdr->redirect_policy = policy;
157c2c66affSColin Finck         return TRUE;
158c2c66affSColin Finck     }
159*9048bdf9SAmine Khaldi     case WINHTTP_OPTION_SECURE_PROTOCOLS:
160*9048bdf9SAmine Khaldi     {
161*9048bdf9SAmine Khaldi         if (buflen != sizeof(session->secure_protocols))
162*9048bdf9SAmine Khaldi         {
163*9048bdf9SAmine Khaldi             set_last_error( ERROR_INSUFFICIENT_BUFFER );
164*9048bdf9SAmine Khaldi             return FALSE;
165*9048bdf9SAmine Khaldi         }
166*9048bdf9SAmine Khaldi         session->secure_protocols = *(DWORD *)buffer;
167*9048bdf9SAmine Khaldi         TRACE("0x%x\n", session->secure_protocols);
168*9048bdf9SAmine Khaldi         return TRUE;
169*9048bdf9SAmine Khaldi     }
170c2c66affSColin Finck     case WINHTTP_OPTION_DISABLE_FEATURE:
171c2c66affSColin Finck         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
172c2c66affSColin Finck         return FALSE;
173c2c66affSColin Finck     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
174c2c66affSColin Finck         session->resolve_timeout = *(DWORD *)buffer;
175c2c66affSColin Finck         return TRUE;
176c2c66affSColin Finck     case WINHTTP_OPTION_CONNECT_TIMEOUT:
177c2c66affSColin Finck         session->connect_timeout = *(DWORD *)buffer;
178c2c66affSColin Finck         return TRUE;
179c2c66affSColin Finck     case WINHTTP_OPTION_SEND_TIMEOUT:
180c2c66affSColin Finck         session->send_timeout = *(DWORD *)buffer;
181c2c66affSColin Finck         return TRUE;
182c2c66affSColin Finck     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
183c2c66affSColin Finck         session->recv_timeout = *(DWORD *)buffer;
184c2c66affSColin Finck         return TRUE;
185c2c66affSColin Finck     case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
186c2c66affSColin Finck         FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
187c2c66affSColin Finck         return TRUE;
188c2c66affSColin Finck     case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
189c2c66affSColin Finck         TRACE("WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: %p\n", *(HANDLE *)buffer);
190c2c66affSColin Finck         session->unload_event = *(HANDLE *)buffer;
191c2c66affSColin Finck         return TRUE;
192c2c66affSColin Finck     case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
193c2c66affSColin Finck         FIXME("WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %d\n", *(DWORD *)buffer);
194c2c66affSColin Finck         return TRUE;
195c2c66affSColin Finck     case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
196c2c66affSColin Finck         FIXME("WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %d\n", *(DWORD *)buffer);
197c2c66affSColin Finck         return TRUE;
198c2c66affSColin Finck     default:
199c2c66affSColin Finck         FIXME("unimplemented option %u\n", option);
200c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
201c2c66affSColin Finck         return FALSE;
202c2c66affSColin Finck     }
203c2c66affSColin Finck }
204c2c66affSColin Finck 
205c2c66affSColin Finck static const object_vtbl_t session_vtbl =
206c2c66affSColin Finck {
207c2c66affSColin Finck     session_destroy,
208c2c66affSColin Finck     session_query_option,
209c2c66affSColin Finck     session_set_option
210c2c66affSColin Finck };
211c2c66affSColin Finck 
212c2c66affSColin Finck #ifdef __REACTOS__
213c2c66affSColin Finck BOOL netconn_init_winsock();
214c2c66affSColin Finck #endif /* __REACTOS__ */
215c2c66affSColin Finck /***********************************************************************
216c2c66affSColin Finck  *          WinHttpOpen (winhttp.@)
217c2c66affSColin Finck  */
218c2c66affSColin Finck HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
219c2c66affSColin Finck {
220c2c66affSColin Finck     session_t *session;
221c2c66affSColin Finck     HINTERNET handle = NULL;
222c2c66affSColin Finck #ifdef __REACTOS__
223c2c66affSColin Finck     if (!netconn_init_winsock()) return NULL;
224c2c66affSColin Finck #endif
225c2c66affSColin Finck 
226c2c66affSColin Finck     TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
227c2c66affSColin Finck 
228c2c66affSColin Finck     if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
229c2c66affSColin Finck 
230c2c66affSColin Finck     session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
231c2c66affSColin Finck     session->hdr.vtbl = &session_vtbl;
232c2c66affSColin Finck     session->hdr.flags = flags;
233c2c66affSColin Finck     session->hdr.refs = 1;
234c2c66affSColin Finck     session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
235c2c66affSColin Finck     list_init( &session->hdr.children );
236c2c66affSColin Finck     session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
237c2c66affSColin Finck     session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
238c2c66affSColin Finck     session->send_timeout = DEFAULT_SEND_TIMEOUT;
239c2c66affSColin Finck     session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
240c2c66affSColin Finck     list_init( &session->cookie_cache );
241c2c66affSColin Finck 
242c2c66affSColin Finck     if (agent && !(session->agent = strdupW( agent ))) goto end;
243c2c66affSColin Finck     if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
244c2c66affSColin Finck     {
245c2c66affSColin Finck         WINHTTP_PROXY_INFO info;
246c2c66affSColin Finck 
247c2c66affSColin Finck         WinHttpGetDefaultProxyConfiguration( &info );
248c2c66affSColin Finck         session->access = info.dwAccessType;
249c2c66affSColin Finck         if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
250c2c66affSColin Finck         {
251c2c66affSColin Finck             GlobalFree( (LPWSTR)info.lpszProxy );
252c2c66affSColin Finck             GlobalFree( (LPWSTR)info.lpszProxyBypass );
253c2c66affSColin Finck             goto end;
254c2c66affSColin Finck         }
255c2c66affSColin Finck         if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
256c2c66affSColin Finck         {
257c2c66affSColin Finck             GlobalFree( (LPWSTR)info.lpszProxy );
258c2c66affSColin Finck             GlobalFree( (LPWSTR)info.lpszProxyBypass );
259c2c66affSColin Finck             goto end;
260c2c66affSColin Finck         }
261c2c66affSColin Finck     }
262c2c66affSColin Finck     else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
263c2c66affSColin Finck     {
264c2c66affSColin Finck         session->access = access;
265c2c66affSColin Finck         if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
266c2c66affSColin Finck         if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
267c2c66affSColin Finck     }
268c2c66affSColin Finck 
269c2c66affSColin Finck     if (!(handle = alloc_handle( &session->hdr ))) goto end;
270c2c66affSColin Finck     session->hdr.handle = handle;
271c2c66affSColin Finck 
272c2c66affSColin Finck end:
273c2c66affSColin Finck     release_object( &session->hdr );
274c2c66affSColin Finck     TRACE("returning %p\n", handle);
275c2c66affSColin Finck     if (handle) set_last_error( ERROR_SUCCESS );
276c2c66affSColin Finck     return handle;
277c2c66affSColin Finck }
278c2c66affSColin Finck 
279c2c66affSColin Finck /***********************************************************************
280c2c66affSColin Finck  *          connect_destroy (internal)
281c2c66affSColin Finck  */
282c2c66affSColin Finck static void connect_destroy( object_header_t *hdr )
283c2c66affSColin Finck {
284c2c66affSColin Finck     connect_t *connect = (connect_t *)hdr;
285c2c66affSColin Finck 
286c2c66affSColin Finck     TRACE("%p\n", connect);
287c2c66affSColin Finck 
288c2c66affSColin Finck     release_object( &connect->session->hdr );
289c2c66affSColin Finck 
290c2c66affSColin Finck     heap_free( connect->hostname );
291c2c66affSColin Finck     heap_free( connect->servername );
292c2c66affSColin Finck     heap_free( connect->username );
293c2c66affSColin Finck     heap_free( connect->password );
294c2c66affSColin Finck     heap_free( connect );
295c2c66affSColin Finck }
296c2c66affSColin Finck 
297c2c66affSColin Finck static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
298c2c66affSColin Finck {
299c2c66affSColin Finck     connect_t *connect = (connect_t *)hdr;
300c2c66affSColin Finck 
301c2c66affSColin Finck     switch (option)
302c2c66affSColin Finck     {
303c2c66affSColin Finck     case WINHTTP_OPTION_PARENT_HANDLE:
304c2c66affSColin Finck     {
305c2c66affSColin Finck         if (!buffer || *buflen < sizeof(HINTERNET))
306c2c66affSColin Finck         {
307c2c66affSColin Finck             *buflen = sizeof(HINTERNET);
308c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
309c2c66affSColin Finck             return FALSE;
310c2c66affSColin Finck         }
311c2c66affSColin Finck 
312c2c66affSColin Finck         *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
313c2c66affSColin Finck         *buflen = sizeof(HINTERNET);
314c2c66affSColin Finck         return TRUE;
315c2c66affSColin Finck     }
316c2c66affSColin Finck     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
317c2c66affSColin Finck         *(DWORD *)buffer = connect->session->resolve_timeout;
318c2c66affSColin Finck         *buflen = sizeof(DWORD);
319c2c66affSColin Finck         return TRUE;
320c2c66affSColin Finck     case WINHTTP_OPTION_CONNECT_TIMEOUT:
321c2c66affSColin Finck         *(DWORD *)buffer = connect->session->connect_timeout;
322c2c66affSColin Finck         *buflen = sizeof(DWORD);
323c2c66affSColin Finck         return TRUE;
324c2c66affSColin Finck     case WINHTTP_OPTION_SEND_TIMEOUT:
325c2c66affSColin Finck         *(DWORD *)buffer = connect->session->send_timeout;
326c2c66affSColin Finck         *buflen = sizeof(DWORD);
327c2c66affSColin Finck         return TRUE;
328c2c66affSColin Finck     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
329c2c66affSColin Finck         *(DWORD *)buffer = connect->session->recv_timeout;
330c2c66affSColin Finck         *buflen = sizeof(DWORD);
331c2c66affSColin Finck         return TRUE;
332c2c66affSColin Finck     default:
333c2c66affSColin Finck         FIXME("unimplemented option %u\n", option);
334c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
335c2c66affSColin Finck         return FALSE;
336c2c66affSColin Finck     }
337c2c66affSColin Finck }
338c2c66affSColin Finck 
339c2c66affSColin Finck static const object_vtbl_t connect_vtbl =
340c2c66affSColin Finck {
341c2c66affSColin Finck     connect_destroy,
342c2c66affSColin Finck     connect_query_option,
343c2c66affSColin Finck     NULL
344c2c66affSColin Finck };
345c2c66affSColin Finck 
346c2c66affSColin Finck static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
347c2c66affSColin Finck {
348c2c66affSColin Finck     static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
349c2c66affSColin Finck     BOOL ret = FALSE;
350c2c66affSColin Finck 
351c2c66affSColin Finck     if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
352c2c66affSColin Finck         ret = TRUE;
353c2c66affSColin Finck     else if (*domain == '*')
354c2c66affSColin Finck     {
355c2c66affSColin Finck         if (domain[1] == '.')
356c2c66affSColin Finck         {
357c2c66affSColin Finck             LPCWSTR dot;
358c2c66affSColin Finck 
359c2c66affSColin Finck             /* For a hostname to match a wildcard, the last domain must match
360c2c66affSColin Finck              * the wildcard exactly.  E.g. if the wildcard is *.a.b, and the
361c2c66affSColin Finck              * hostname is www.foo.a.b, it matches, but a.b does not.
362c2c66affSColin Finck              */
363c2c66affSColin Finck             dot = strchrW( server, '.' );
364c2c66affSColin Finck             if (dot)
365c2c66affSColin Finck             {
366c2c66affSColin Finck                 int len = strlenW( dot + 1 );
367c2c66affSColin Finck 
368c2c66affSColin Finck                 if (len > strlenW( domain + 2 ))
369c2c66affSColin Finck                 {
370c2c66affSColin Finck                     LPCWSTR ptr;
371c2c66affSColin Finck 
372c2c66affSColin Finck                     /* The server's domain is longer than the wildcard, so it
373c2c66affSColin Finck                      * could be a subdomain.  Compare the last portion of the
374c2c66affSColin Finck                      * server's domain.
375c2c66affSColin Finck                      */
376c2c66affSColin Finck                     ptr = dot + len + 1 - strlenW( domain + 2 );
377c2c66affSColin Finck                     if (!strcmpiW( ptr, domain + 2 ))
378c2c66affSColin Finck                     {
379c2c66affSColin Finck                         /* This is only a match if the preceding character is
380c2c66affSColin Finck                          * a '.', i.e. that it is a matching domain.  E.g.
381c2c66affSColin Finck                          * if domain is '*.b.c' and server is 'www.ab.c' they
382c2c66affSColin Finck                          * do not match.
383c2c66affSColin Finck                          */
384c2c66affSColin Finck                         ret = *(ptr - 1) == '.';
385c2c66affSColin Finck                     }
386c2c66affSColin Finck                 }
387c2c66affSColin Finck                 else
388c2c66affSColin Finck                     ret = !strcmpiW( dot + 1, domain + 2 );
389c2c66affSColin Finck             }
390c2c66affSColin Finck         }
391c2c66affSColin Finck     }
392c2c66affSColin Finck     else
393c2c66affSColin Finck         ret = !strcmpiW( server, domain );
394c2c66affSColin Finck     return ret;
395c2c66affSColin Finck }
396c2c66affSColin Finck 
397c2c66affSColin Finck /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
398c2c66affSColin Finck #define MAX_HOST_NAME_LENGTH 256
399c2c66affSColin Finck 
400c2c66affSColin Finck static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
401c2c66affSColin Finck {
402c2c66affSColin Finck     LPCWSTR ptr;
403c2c66affSColin Finck     BOOL ret = FALSE;
404c2c66affSColin Finck 
405c2c66affSColin Finck     if (!session->proxy_bypass) return FALSE;
406c2c66affSColin Finck     ptr = session->proxy_bypass;
407c2c66affSColin Finck     do {
408c2c66affSColin Finck         LPCWSTR tmp = ptr;
409c2c66affSColin Finck 
410c2c66affSColin Finck         ptr = strchrW( ptr, ';' );
411c2c66affSColin Finck         if (!ptr)
412c2c66affSColin Finck             ptr = strchrW( tmp, ' ' );
413c2c66affSColin Finck         if (ptr)
414c2c66affSColin Finck         {
415c2c66affSColin Finck             if (ptr - tmp < MAX_HOST_NAME_LENGTH)
416c2c66affSColin Finck             {
417c2c66affSColin Finck                 WCHAR domain[MAX_HOST_NAME_LENGTH];
418c2c66affSColin Finck 
419c2c66affSColin Finck                 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
420c2c66affSColin Finck                 domain[ptr - tmp] = 0;
421c2c66affSColin Finck                 ret = domain_matches( server, domain );
422c2c66affSColin Finck             }
423c2c66affSColin Finck             ptr += 1;
424c2c66affSColin Finck         }
425c2c66affSColin Finck         else if (*tmp)
426c2c66affSColin Finck             ret = domain_matches( server, tmp );
427c2c66affSColin Finck     } while (ptr && !ret);
428c2c66affSColin Finck     return ret;
429c2c66affSColin Finck }
430c2c66affSColin Finck 
431c2c66affSColin Finck BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
432c2c66affSColin Finck {
433c2c66affSColin Finck     session_t *session = connect->session;
434c2c66affSColin Finck     BOOL ret = TRUE;
435c2c66affSColin Finck 
436c2c66affSColin Finck     if (session->proxy_server && !should_bypass_proxy(session, server))
437c2c66affSColin Finck     {
438c2c66affSColin Finck         LPCWSTR colon;
439c2c66affSColin Finck 
440c2c66affSColin Finck         if ((colon = strchrW( session->proxy_server, ':' )))
441c2c66affSColin Finck         {
442c2c66affSColin Finck             if (!connect->servername || strncmpiW( connect->servername,
443c2c66affSColin Finck                 session->proxy_server, colon - session->proxy_server - 1 ))
444c2c66affSColin Finck             {
445c2c66affSColin Finck                 heap_free( connect->servername );
446c2c66affSColin Finck                 connect->resolved = FALSE;
447c2c66affSColin Finck                 if (!(connect->servername = heap_alloc(
448c2c66affSColin Finck                     (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
449c2c66affSColin Finck                 {
450c2c66affSColin Finck                     ret = FALSE;
451c2c66affSColin Finck                     goto end;
452c2c66affSColin Finck                 }
453c2c66affSColin Finck                 memcpy( connect->servername, session->proxy_server,
454c2c66affSColin Finck                     (colon - session->proxy_server) * sizeof(WCHAR) );
455c2c66affSColin Finck                 connect->servername[colon - session->proxy_server] = 0;
456c2c66affSColin Finck                 if (*(colon + 1))
457c2c66affSColin Finck                     connect->serverport = atoiW( colon + 1 );
458c2c66affSColin Finck                 else
459c2c66affSColin Finck                     connect->serverport = INTERNET_DEFAULT_PORT;
460c2c66affSColin Finck             }
461c2c66affSColin Finck         }
462c2c66affSColin Finck         else
463c2c66affSColin Finck         {
464c2c66affSColin Finck             if (!connect->servername || strcmpiW( connect->servername,
465c2c66affSColin Finck                 session->proxy_server ))
466c2c66affSColin Finck             {
467c2c66affSColin Finck                 heap_free( connect->servername );
468c2c66affSColin Finck                 connect->resolved = FALSE;
469c2c66affSColin Finck                 if (!(connect->servername = strdupW( session->proxy_server )))
470c2c66affSColin Finck                 {
471c2c66affSColin Finck                     ret = FALSE;
472c2c66affSColin Finck                     goto end;
473c2c66affSColin Finck                 }
474c2c66affSColin Finck                 connect->serverport = INTERNET_DEFAULT_PORT;
475c2c66affSColin Finck             }
476c2c66affSColin Finck         }
477c2c66affSColin Finck     }
478c2c66affSColin Finck     else if (server)
479c2c66affSColin Finck     {
480c2c66affSColin Finck         heap_free( connect->servername );
481c2c66affSColin Finck         connect->resolved = FALSE;
482c2c66affSColin Finck         if (!(connect->servername = strdupW( server )))
483c2c66affSColin Finck         {
484c2c66affSColin Finck             ret = FALSE;
485c2c66affSColin Finck             goto end;
486c2c66affSColin Finck         }
487c2c66affSColin Finck         connect->serverport = port;
488c2c66affSColin Finck     }
489c2c66affSColin Finck end:
490c2c66affSColin Finck     return ret;
491c2c66affSColin Finck }
492c2c66affSColin Finck 
493c2c66affSColin Finck /***********************************************************************
494c2c66affSColin Finck  *          WinHttpConnect (winhttp.@)
495c2c66affSColin Finck  */
496c2c66affSColin Finck HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
497c2c66affSColin Finck {
498c2c66affSColin Finck     connect_t *connect;
499c2c66affSColin Finck     session_t *session;
500c2c66affSColin Finck     HINTERNET hconnect = NULL;
501c2c66affSColin Finck 
502c2c66affSColin Finck     TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
503c2c66affSColin Finck 
504c2c66affSColin Finck     if (!server)
505c2c66affSColin Finck     {
506c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
507c2c66affSColin Finck         return NULL;
508c2c66affSColin Finck     }
509c2c66affSColin Finck     if (!(session = (session_t *)grab_object( hsession )))
510c2c66affSColin Finck     {
511c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
512c2c66affSColin Finck         return NULL;
513c2c66affSColin Finck     }
514c2c66affSColin Finck     if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
515c2c66affSColin Finck     {
516c2c66affSColin Finck         release_object( &session->hdr );
517c2c66affSColin Finck         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
518c2c66affSColin Finck         return NULL;
519c2c66affSColin Finck     }
520c2c66affSColin Finck     if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
521c2c66affSColin Finck     {
522c2c66affSColin Finck         release_object( &session->hdr );
523c2c66affSColin Finck         return NULL;
524c2c66affSColin Finck     }
525c2c66affSColin Finck     connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
526c2c66affSColin Finck     connect->hdr.vtbl = &connect_vtbl;
527c2c66affSColin Finck     connect->hdr.refs = 1;
528c2c66affSColin Finck     connect->hdr.flags = session->hdr.flags;
529c2c66affSColin Finck     connect->hdr.callback = session->hdr.callback;
530c2c66affSColin Finck     connect->hdr.notify_mask = session->hdr.notify_mask;
531c2c66affSColin Finck     connect->hdr.context = session->hdr.context;
532c2c66affSColin Finck     connect->hdr.redirect_policy = session->hdr.redirect_policy;
533c2c66affSColin Finck     list_init( &connect->hdr.children );
534c2c66affSColin Finck 
535c2c66affSColin Finck     addref_object( &session->hdr );
536c2c66affSColin Finck     connect->session = session;
537c2c66affSColin Finck     list_add_head( &session->hdr.children, &connect->hdr.entry );
538c2c66affSColin Finck 
539c2c66affSColin Finck     if (!(connect->hostname = strdupW( server ))) goto end;
540c2c66affSColin Finck     connect->hostport = port;
541c2c66affSColin Finck     if (!set_server_for_hostname( connect, server, port )) goto end;
542c2c66affSColin Finck 
543c2c66affSColin Finck     if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
544c2c66affSColin Finck     connect->hdr.handle = hconnect;
545c2c66affSColin Finck 
546c2c66affSColin Finck     send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
547c2c66affSColin Finck 
548c2c66affSColin Finck end:
549c2c66affSColin Finck     release_object( &connect->hdr );
550c2c66affSColin Finck     release_object( &session->hdr );
551c2c66affSColin Finck     TRACE("returning %p\n", hconnect);
552c2c66affSColin Finck     if (hconnect) set_last_error( ERROR_SUCCESS );
553c2c66affSColin Finck     return hconnect;
554c2c66affSColin Finck }
555c2c66affSColin Finck 
556c2c66affSColin Finck /***********************************************************************
557c2c66affSColin Finck  *          request_destroy (internal)
558c2c66affSColin Finck  */
559c2c66affSColin Finck static void request_destroy( object_header_t *hdr )
560c2c66affSColin Finck {
561c2c66affSColin Finck     request_t *request = (request_t *)hdr;
562c2c66affSColin Finck     unsigned int i, j;
563c2c66affSColin Finck 
564c2c66affSColin Finck     TRACE("%p\n", request);
565c2c66affSColin Finck 
566c2c66affSColin Finck     if (request->task_thread)
567c2c66affSColin Finck     {
568c2c66affSColin Finck         /* Signal to the task proc to quit.  It will call
569c2c66affSColin Finck            this again when it does. */
570c2c66affSColin Finck         HANDLE thread = request->task_thread;
571c2c66affSColin Finck         request->task_thread = 0;
572c2c66affSColin Finck         SetEvent( request->task_cancel );
573c2c66affSColin Finck         CloseHandle( thread );
574c2c66affSColin Finck         return;
575c2c66affSColin Finck     }
576c2c66affSColin Finck     release_object( &request->connect->hdr );
577c2c66affSColin Finck 
578c2c66affSColin Finck     destroy_authinfo( request->authinfo );
579c2c66affSColin Finck     destroy_authinfo( request->proxy_authinfo );
580c2c66affSColin Finck 
581c2c66affSColin Finck     heap_free( request->verb );
582c2c66affSColin Finck     heap_free( request->path );
583c2c66affSColin Finck     heap_free( request->version );
584c2c66affSColin Finck     heap_free( request->raw_headers );
585c2c66affSColin Finck     heap_free( request->status_text );
586c2c66affSColin Finck     for (i = 0; i < request->num_headers; i++)
587c2c66affSColin Finck     {
588c2c66affSColin Finck         heap_free( request->headers[i].field );
589c2c66affSColin Finck         heap_free( request->headers[i].value );
590c2c66affSColin Finck     }
591c2c66affSColin Finck     heap_free( request->headers );
592*9048bdf9SAmine Khaldi     for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] );
593*9048bdf9SAmine Khaldi     heap_free( request->accept_types );
594c2c66affSColin Finck     for (i = 0; i < TARGET_MAX; i++)
595c2c66affSColin Finck     {
596c2c66affSColin Finck         for (j = 0; j < SCHEME_MAX; j++)
597c2c66affSColin Finck         {
598c2c66affSColin Finck             heap_free( request->creds[i][j].username );
599c2c66affSColin Finck             heap_free( request->creds[i][j].password );
600c2c66affSColin Finck         }
601c2c66affSColin Finck     }
602c2c66affSColin Finck     heap_free( request );
603c2c66affSColin Finck }
604c2c66affSColin Finck 
605c2c66affSColin Finck static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
606c2c66affSColin Finck {
607c2c66affSColin Finck     int len = 0;
608c2c66affSColin Finck     if (str) len = strlenW( str );
609c2c66affSColin Finck     if (buffer && *buflen > len)
610c2c66affSColin Finck     {
611c2c66affSColin Finck         if (str) memcpy( buffer, str, len * sizeof(WCHAR) );
612c2c66affSColin Finck         buffer[len] = 0;
613c2c66affSColin Finck     }
614c2c66affSColin Finck     *buflen = len * sizeof(WCHAR);
615c2c66affSColin Finck }
616c2c66affSColin Finck 
617c2c66affSColin Finck static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
618c2c66affSColin Finck {
619c2c66affSColin Finck     WCHAR *ret;
620c2c66affSColin Finck     DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
621c2c66affSColin Finck 
622c2c66affSColin Finck     size = CertNameToStrW( encoding, blob, format, NULL, 0 );
623c2c66affSColin Finck     if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
624c2c66affSColin Finck         CertNameToStrW( encoding, blob, format, ret, size );
625c2c66affSColin Finck 
626c2c66affSColin Finck     return ret;
627c2c66affSColin Finck }
628c2c66affSColin Finck 
629c2c66affSColin Finck static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
630c2c66affSColin Finck {
631c2c66affSColin Finck #if !defined(__MINGW32__) && !defined(_MSC_VER)
632c2c66affSColin Finck     switch (addr->sa_family)
633c2c66affSColin Finck     {
634c2c66affSColin Finck     case AF_INET:
635c2c66affSColin Finck     {
636c2c66affSColin Finck         const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
637c2c66affSColin Finck         struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
638c2c66affSColin Finck         char *p;
639c2c66affSColin Finck 
640c2c66affSColin Finck         addr_win->sin_family = WS_AF_INET;
641c2c66affSColin Finck         addr_win->sin_port   = addr_unix->sin_port;
642c2c66affSColin Finck         memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
643c2c66affSColin Finck         p = (char *)&addr_win->sin_addr + 4;
644c2c66affSColin Finck         memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
645c2c66affSColin Finck         return TRUE;
646c2c66affSColin Finck     }
647c2c66affSColin Finck     case AF_INET6:
648c2c66affSColin Finck     {
649c2c66affSColin Finck         const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
650c2c66affSColin Finck         struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
651c2c66affSColin Finck 
652c2c66affSColin Finck         addr_win->sin6_family   = WS_AF_INET6;
653c2c66affSColin Finck         addr_win->sin6_port     = addr_unix->sin6_port;
654c2c66affSColin Finck         addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
655c2c66affSColin Finck         memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
656c2c66affSColin Finck #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
657c2c66affSColin Finck         addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
658c2c66affSColin Finck #else
659c2c66affSColin Finck         addr_win->sin6_scope_id = 0;
660c2c66affSColin Finck #endif
661c2c66affSColin Finck         memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
662c2c66affSColin Finck         return TRUE;
663c2c66affSColin Finck     }
664c2c66affSColin Finck     default:
665c2c66affSColin Finck         ERR("unhandled family %u\n", addr->sa_family);
666c2c66affSColin Finck         return FALSE;
667c2c66affSColin Finck     }
668c2c66affSColin Finck #else
669c2c66affSColin Finck     switch (addr->sa_family)
670c2c66affSColin Finck     {
671c2c66affSColin Finck     case AF_INET:
672c2c66affSColin Finck     {
673c2c66affSColin Finck         struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
674c2c66affSColin Finck 
675c2c66affSColin Finck         memcpy( addr_in, addr, sizeof(*addr_in) );
676c2c66affSColin Finck         memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
677c2c66affSColin Finck         return TRUE;
678c2c66affSColin Finck     }
679c2c66affSColin Finck     case AF_INET6:
680c2c66affSColin Finck     {
681c2c66affSColin Finck         struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
682c2c66affSColin Finck 
683c2c66affSColin Finck         memcpy( addr_in6, addr, sizeof(*addr_in6) );
684c2c66affSColin Finck         memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
685c2c66affSColin Finck         return TRUE;
686c2c66affSColin Finck     }
687c2c66affSColin Finck     default:
688c2c66affSColin Finck         ERR("unhandled family %u\n", addr->sa_family);
689c2c66affSColin Finck         return FALSE;
690c2c66affSColin Finck     }
691c2c66affSColin Finck #endif
692c2c66affSColin Finck }
693c2c66affSColin Finck 
694c2c66affSColin Finck static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
695c2c66affSColin Finck {
696c2c66affSColin Finck     request_t *request = (request_t *)hdr;
697c2c66affSColin Finck 
698c2c66affSColin Finck     switch (option)
699c2c66affSColin Finck     {
700c2c66affSColin Finck     case WINHTTP_OPTION_SECURITY_FLAGS:
701c2c66affSColin Finck     {
702c2c66affSColin Finck         DWORD flags = 0;
703c2c66affSColin Finck         int bits;
704c2c66affSColin Finck 
705c2c66affSColin Finck         if (!buffer || *buflen < sizeof(flags))
706c2c66affSColin Finck         {
707c2c66affSColin Finck             *buflen = sizeof(flags);
708c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
709c2c66affSColin Finck             return FALSE;
710c2c66affSColin Finck         }
711c2c66affSColin Finck 
712c2c66affSColin Finck         flags = 0;
713c2c66affSColin Finck         if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
714c2c66affSColin Finck         flags |= request->security_flags;
715c2c66affSColin Finck         if (request->netconn)
716c2c66affSColin Finck         {
717c2c66affSColin Finck             bits = netconn_get_cipher_strength( request->netconn );
718c2c66affSColin Finck             if (bits >= 128)
719c2c66affSColin Finck                 flags |= SECURITY_FLAG_STRENGTH_STRONG;
720c2c66affSColin Finck             else if (bits >= 56)
721c2c66affSColin Finck                 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
722c2c66affSColin Finck             else
723c2c66affSColin Finck                 flags |= SECURITY_FLAG_STRENGTH_WEAK;
724c2c66affSColin Finck         }
725c2c66affSColin Finck         *(DWORD *)buffer = flags;
726c2c66affSColin Finck         *buflen = sizeof(flags);
727c2c66affSColin Finck         return TRUE;
728c2c66affSColin Finck     }
729c2c66affSColin Finck     case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
730c2c66affSColin Finck     {
731c2c66affSColin Finck         const CERT_CONTEXT *cert;
732c2c66affSColin Finck 
733c2c66affSColin Finck         if (!buffer || *buflen < sizeof(cert))
734c2c66affSColin Finck         {
735c2c66affSColin Finck             *buflen = sizeof(cert);
736c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
737c2c66affSColin Finck             return FALSE;
738c2c66affSColin Finck         }
739c2c66affSColin Finck 
740c2c66affSColin Finck         if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE;
741c2c66affSColin Finck         *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
742c2c66affSColin Finck         *buflen = sizeof(cert);
743c2c66affSColin Finck         return TRUE;
744c2c66affSColin Finck     }
745c2c66affSColin Finck     case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
746c2c66affSColin Finck     {
747c2c66affSColin Finck         const CERT_CONTEXT *cert;
748c2c66affSColin Finck         const CRYPT_OID_INFO *oidInfo;
749c2c66affSColin Finck         WINHTTP_CERTIFICATE_INFO *ci = buffer;
750c2c66affSColin Finck 
751c2c66affSColin Finck         FIXME("partial stub\n");
752c2c66affSColin Finck 
753c2c66affSColin Finck         if (!buffer || *buflen < sizeof(*ci))
754c2c66affSColin Finck         {
755c2c66affSColin Finck             *buflen = sizeof(*ci);
756c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
757c2c66affSColin Finck             return FALSE;
758c2c66affSColin Finck         }
759c2c66affSColin Finck         if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE;
760c2c66affSColin Finck 
761c2c66affSColin Finck         ci->ftExpiry = cert->pCertInfo->NotAfter;
762c2c66affSColin Finck         ci->ftStart  = cert->pCertInfo->NotBefore;
763c2c66affSColin Finck         ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
764c2c66affSColin Finck         ci->lpszIssuerInfo  = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
765c2c66affSColin Finck         ci->lpszProtocolName      = NULL;
766c2c66affSColin Finck         oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
767c2c66affSColin Finck                                     cert->pCertInfo->SignatureAlgorithm.pszObjId,
768c2c66affSColin Finck                                     0 );
769c2c66affSColin Finck         if (oidInfo)
770c2c66affSColin Finck             ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
771c2c66affSColin Finck         else
772c2c66affSColin Finck             ci->lpszSignatureAlgName  = NULL;
773c2c66affSColin Finck         ci->lpszEncryptionAlgName = NULL;
774c2c66affSColin Finck         ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
775c2c66affSColin Finck 
776c2c66affSColin Finck         CertFreeCertificateContext( cert );
777c2c66affSColin Finck         *buflen = sizeof(*ci);
778c2c66affSColin Finck         return TRUE;
779c2c66affSColin Finck     }
780c2c66affSColin Finck     case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
781c2c66affSColin Finck     {
782c2c66affSColin Finck         if (!buffer || *buflen < sizeof(DWORD))
783c2c66affSColin Finck         {
784c2c66affSColin Finck             *buflen = sizeof(DWORD);
785c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
786c2c66affSColin Finck             return FALSE;
787c2c66affSColin Finck         }
788c2c66affSColin Finck 
789c2c66affSColin Finck         *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
790c2c66affSColin Finck         *buflen = sizeof(DWORD);
791c2c66affSColin Finck         return TRUE;
792c2c66affSColin Finck     }
793c2c66affSColin Finck     case WINHTTP_OPTION_CONNECTION_INFO:
794c2c66affSColin Finck     {
795c2c66affSColin Finck         WINHTTP_CONNECTION_INFO *info = buffer;
796c2c66affSColin Finck         struct sockaddr local;
797c2c66affSColin Finck         socklen_t len = sizeof(local);
798c2c66affSColin Finck         const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
799c2c66affSColin Finck 
800c2c66affSColin Finck         if (!buffer || *buflen < sizeof(*info))
801c2c66affSColin Finck         {
802c2c66affSColin Finck             *buflen = sizeof(*info);
803c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
804c2c66affSColin Finck             return FALSE;
805c2c66affSColin Finck         }
806c2c66affSColin Finck         if (!request->netconn)
807c2c66affSColin Finck         {
808c2c66affSColin Finck             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
809c2c66affSColin Finck             return FALSE;
810c2c66affSColin Finck         }
811c2c66affSColin Finck         if (getsockname( request->netconn->socket, &local, &len )) return FALSE;
812c2c66affSColin Finck         if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
813c2c66affSColin Finck         if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
814c2c66affSColin Finck         info->cbSize = sizeof(*info);
815c2c66affSColin Finck         return TRUE;
816c2c66affSColin Finck     }
817c2c66affSColin Finck     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
818c2c66affSColin Finck         *(DWORD *)buffer = request->resolve_timeout;
819c2c66affSColin Finck         *buflen = sizeof(DWORD);
820c2c66affSColin Finck         return TRUE;
821c2c66affSColin Finck     case WINHTTP_OPTION_CONNECT_TIMEOUT:
822c2c66affSColin Finck         *(DWORD *)buffer = request->connect_timeout;
823c2c66affSColin Finck         *buflen = sizeof(DWORD);
824c2c66affSColin Finck         return TRUE;
825c2c66affSColin Finck     case WINHTTP_OPTION_SEND_TIMEOUT:
826c2c66affSColin Finck         *(DWORD *)buffer = request->send_timeout;
827c2c66affSColin Finck         *buflen = sizeof(DWORD);
828c2c66affSColin Finck         return TRUE;
829c2c66affSColin Finck     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
830c2c66affSColin Finck         *(DWORD *)buffer = request->recv_timeout;
831c2c66affSColin Finck         *buflen = sizeof(DWORD);
832c2c66affSColin Finck         return TRUE;
833c2c66affSColin Finck 
834c2c66affSColin Finck     case WINHTTP_OPTION_USERNAME:
835c2c66affSColin Finck         str_to_buffer( buffer, request->connect->username, buflen );
836c2c66affSColin Finck         return TRUE;
837c2c66affSColin Finck 
838c2c66affSColin Finck     case WINHTTP_OPTION_PASSWORD:
839c2c66affSColin Finck         str_to_buffer( buffer, request->connect->password, buflen );
840c2c66affSColin Finck         return TRUE;
841c2c66affSColin Finck 
842c2c66affSColin Finck     case WINHTTP_OPTION_PROXY_USERNAME:
843c2c66affSColin Finck         str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
844c2c66affSColin Finck         return TRUE;
845c2c66affSColin Finck 
846c2c66affSColin Finck     case WINHTTP_OPTION_PROXY_PASSWORD:
847c2c66affSColin Finck         str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
848c2c66affSColin Finck         return TRUE;
849c2c66affSColin Finck 
850c2c66affSColin Finck     default:
851c2c66affSColin Finck         FIXME("unimplemented option %u\n", option);
852c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
853c2c66affSColin Finck         return FALSE;
854c2c66affSColin Finck     }
855c2c66affSColin Finck }
856c2c66affSColin Finck 
857c2c66affSColin Finck static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
858c2c66affSColin Finck {
859c2c66affSColin Finck     WCHAR *ret;
860c2c66affSColin Finck     if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
861c2c66affSColin Finck     {
862c2c66affSColin Finck         memcpy( ret, buffer, buflen * sizeof(WCHAR) );
863c2c66affSColin Finck         ret[buflen] = 0;
864c2c66affSColin Finck         return ret;
865c2c66affSColin Finck     }
866c2c66affSColin Finck     set_last_error( ERROR_OUTOFMEMORY );
867c2c66affSColin Finck     return NULL;
868c2c66affSColin Finck }
869c2c66affSColin Finck 
870c2c66affSColin Finck static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
871c2c66affSColin Finck {
872c2c66affSColin Finck     request_t *request = (request_t *)hdr;
873c2c66affSColin Finck 
874c2c66affSColin Finck     switch (option)
875c2c66affSColin Finck     {
876c2c66affSColin Finck     case WINHTTP_OPTION_PROXY:
877c2c66affSColin Finck     {
878c2c66affSColin Finck         WINHTTP_PROXY_INFO *pi = buffer;
879c2c66affSColin Finck 
880c2c66affSColin Finck         FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
881c2c66affSColin Finck         return TRUE;
882c2c66affSColin Finck     }
883c2c66affSColin Finck     case WINHTTP_OPTION_DISABLE_FEATURE:
884c2c66affSColin Finck     {
885c2c66affSColin Finck         DWORD disable;
886c2c66affSColin Finck 
887c2c66affSColin Finck         if (buflen != sizeof(DWORD))
888c2c66affSColin Finck         {
889c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
890c2c66affSColin Finck             return FALSE;
891c2c66affSColin Finck         }
892c2c66affSColin Finck 
893c2c66affSColin Finck         disable = *(DWORD *)buffer;
894c2c66affSColin Finck         TRACE("0x%x\n", disable);
895c2c66affSColin Finck         hdr->disable_flags |= disable;
896c2c66affSColin Finck         return TRUE;
897c2c66affSColin Finck     }
898c2c66affSColin Finck     case WINHTTP_OPTION_AUTOLOGON_POLICY:
899c2c66affSColin Finck     {
900c2c66affSColin Finck         DWORD policy;
901c2c66affSColin Finck 
902c2c66affSColin Finck         if (buflen != sizeof(DWORD))
903c2c66affSColin Finck         {
904c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
905c2c66affSColin Finck             return FALSE;
906c2c66affSColin Finck         }
907c2c66affSColin Finck 
908c2c66affSColin Finck         policy = *(DWORD *)buffer;
909c2c66affSColin Finck         TRACE("0x%x\n", policy);
910c2c66affSColin Finck         hdr->logon_policy = policy;
911c2c66affSColin Finck         return TRUE;
912c2c66affSColin Finck     }
913c2c66affSColin Finck     case WINHTTP_OPTION_REDIRECT_POLICY:
914c2c66affSColin Finck     {
915c2c66affSColin Finck         DWORD policy;
916c2c66affSColin Finck 
917c2c66affSColin Finck         if (buflen != sizeof(DWORD))
918c2c66affSColin Finck         {
919c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
920c2c66affSColin Finck             return FALSE;
921c2c66affSColin Finck         }
922c2c66affSColin Finck 
923c2c66affSColin Finck         policy = *(DWORD *)buffer;
924c2c66affSColin Finck         TRACE("0x%x\n", policy);
925c2c66affSColin Finck         hdr->redirect_policy = policy;
926c2c66affSColin Finck         return TRUE;
927c2c66affSColin Finck     }
928c2c66affSColin Finck     case WINHTTP_OPTION_SECURITY_FLAGS:
929c2c66affSColin Finck     {
930c2c66affSColin Finck         DWORD flags;
931c2c66affSColin Finck 
932c2c66affSColin Finck         if (buflen < sizeof(DWORD))
933c2c66affSColin Finck         {
934c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
935c2c66affSColin Finck             return FALSE;
936c2c66affSColin Finck         }
937c2c66affSColin Finck         flags = *(DWORD *)buffer;
938c2c66affSColin Finck         TRACE("0x%x\n", flags);
939c2c66affSColin Finck         if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID   |
940c2c66affSColin Finck                        SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
941c2c66affSColin Finck                        SECURITY_FLAG_IGNORE_UNKNOWN_CA        |
942c2c66affSColin Finck                        SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
943c2c66affSColin Finck         {
944c2c66affSColin Finck             set_last_error( ERROR_INVALID_PARAMETER );
945c2c66affSColin Finck             return FALSE;
946c2c66affSColin Finck         }
947c2c66affSColin Finck         request->security_flags = flags;
948c2c66affSColin Finck         return TRUE;
949c2c66affSColin Finck     }
950c2c66affSColin Finck     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
951c2c66affSColin Finck         request->resolve_timeout = *(DWORD *)buffer;
952c2c66affSColin Finck         return TRUE;
953c2c66affSColin Finck     case WINHTTP_OPTION_CONNECT_TIMEOUT:
954c2c66affSColin Finck         request->connect_timeout = *(DWORD *)buffer;
955c2c66affSColin Finck         return TRUE;
956c2c66affSColin Finck     case WINHTTP_OPTION_SEND_TIMEOUT:
957c2c66affSColin Finck         request->send_timeout = *(DWORD *)buffer;
958c2c66affSColin Finck         return TRUE;
959c2c66affSColin Finck     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
960c2c66affSColin Finck         request->recv_timeout = *(DWORD *)buffer;
961c2c66affSColin Finck         return TRUE;
962c2c66affSColin Finck 
963c2c66affSColin Finck     case WINHTTP_OPTION_USERNAME:
964c2c66affSColin Finck     {
965c2c66affSColin Finck         connect_t *connect = request->connect;
966c2c66affSColin Finck 
967c2c66affSColin Finck         heap_free( connect->username );
968c2c66affSColin Finck         if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
969c2c66affSColin Finck         return TRUE;
970c2c66affSColin Finck     }
971c2c66affSColin Finck     case WINHTTP_OPTION_PASSWORD:
972c2c66affSColin Finck     {
973c2c66affSColin Finck         connect_t *connect = request->connect;
974c2c66affSColin Finck 
975c2c66affSColin Finck         heap_free( connect->password );
976c2c66affSColin Finck         if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
977c2c66affSColin Finck         return TRUE;
978c2c66affSColin Finck     }
979c2c66affSColin Finck     case WINHTTP_OPTION_PROXY_USERNAME:
980c2c66affSColin Finck     {
981c2c66affSColin Finck         session_t *session = request->connect->session;
982c2c66affSColin Finck 
983c2c66affSColin Finck         heap_free( session->proxy_username );
984c2c66affSColin Finck         if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
985c2c66affSColin Finck         return TRUE;
986c2c66affSColin Finck     }
987c2c66affSColin Finck     case WINHTTP_OPTION_PROXY_PASSWORD:
988c2c66affSColin Finck     {
989c2c66affSColin Finck         session_t *session = request->connect->session;
990c2c66affSColin Finck 
991c2c66affSColin Finck         heap_free( session->proxy_password );
992c2c66affSColin Finck         if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
993c2c66affSColin Finck         return TRUE;
994c2c66affSColin Finck     }
995c2c66affSColin Finck     case WINHTTP_OPTION_CLIENT_CERT_CONTEXT:
996c2c66affSColin Finck         if (!(hdr->flags & WINHTTP_FLAG_SECURE))
997c2c66affSColin Finck         {
998c2c66affSColin Finck             SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
999c2c66affSColin Finck             return FALSE;
1000c2c66affSColin Finck         }
1001c2c66affSColin Finck         FIXME("WINHTTP_OPTION_CLIENT_CERT_CONTEXT\n");
1002c2c66affSColin Finck         return TRUE;
1003c2c66affSColin Finck     default:
1004c2c66affSColin Finck         FIXME("unimplemented option %u\n", option);
1005c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1006c2c66affSColin Finck         return TRUE;
1007c2c66affSColin Finck     }
1008c2c66affSColin Finck }
1009c2c66affSColin Finck 
1010c2c66affSColin Finck static const object_vtbl_t request_vtbl =
1011c2c66affSColin Finck {
1012c2c66affSColin Finck     request_destroy,
1013c2c66affSColin Finck     request_query_option,
1014c2c66affSColin Finck     request_set_option
1015c2c66affSColin Finck };
1016c2c66affSColin Finck 
1017c2c66affSColin Finck static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
1018c2c66affSColin Finck {
1019c2c66affSColin Finck     const WCHAR **types = accept_types;
1020*9048bdf9SAmine Khaldi     DWORD i;
1021c2c66affSColin Finck 
1022c2c66affSColin Finck     if (!types) return TRUE;
1023c2c66affSColin Finck     while (*types)
1024c2c66affSColin Finck     {
1025*9048bdf9SAmine Khaldi         request->num_accept_types++;
1026*9048bdf9SAmine Khaldi         types++;
1027*9048bdf9SAmine Khaldi     }
1028*9048bdf9SAmine Khaldi     if (!request->num_accept_types) return TRUE;
1029*9048bdf9SAmine Khaldi     if (!(request->accept_types = heap_alloc( request->num_accept_types * sizeof(WCHAR *))))
1030*9048bdf9SAmine Khaldi     {
1031*9048bdf9SAmine Khaldi         request->num_accept_types = 0;
1032*9048bdf9SAmine Khaldi         return FALSE;
1033*9048bdf9SAmine Khaldi     }
1034*9048bdf9SAmine Khaldi     types = accept_types;
1035*9048bdf9SAmine Khaldi     for (i = 0; i < request->num_accept_types; i++)
1036*9048bdf9SAmine Khaldi     {
1037*9048bdf9SAmine Khaldi         if (!(request->accept_types[i] = strdupW( *types )))
1038*9048bdf9SAmine Khaldi         {
1039*9048bdf9SAmine Khaldi             for ( ; i > 0; --i) heap_free( request->accept_types[i - 1] );
1040*9048bdf9SAmine Khaldi             heap_free( request->accept_types );
1041*9048bdf9SAmine Khaldi             request->accept_types = NULL;
1042*9048bdf9SAmine Khaldi             request->num_accept_types = 0;
1043*9048bdf9SAmine Khaldi             return FALSE;
1044*9048bdf9SAmine Khaldi         }
1045c2c66affSColin Finck         types++;
1046c2c66affSColin Finck     }
1047c2c66affSColin Finck     return TRUE;
1048c2c66affSColin Finck }
1049c2c66affSColin Finck 
1050c2c66affSColin Finck /***********************************************************************
1051c2c66affSColin Finck  *          WinHttpOpenRequest (winhttp.@)
1052c2c66affSColin Finck  */
1053c2c66affSColin Finck HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
1054c2c66affSColin Finck                                      LPCWSTR referrer, LPCWSTR *types, DWORD flags )
1055c2c66affSColin Finck {
1056c2c66affSColin Finck     request_t *request;
1057c2c66affSColin Finck     connect_t *connect;
1058c2c66affSColin Finck     HINTERNET hrequest = NULL;
1059c2c66affSColin Finck 
1060c2c66affSColin Finck     TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
1061c2c66affSColin Finck           debugstr_w(version), debugstr_w(referrer), types, flags);
1062c2c66affSColin Finck 
1063c2c66affSColin Finck     if(types && TRACE_ON(winhttp)) {
1064c2c66affSColin Finck         const WCHAR **iter;
1065c2c66affSColin Finck 
1066c2c66affSColin Finck         TRACE("accept types:\n");
1067c2c66affSColin Finck         for(iter = types; *iter; iter++)
1068c2c66affSColin Finck             TRACE("    %s\n", debugstr_w(*iter));
1069c2c66affSColin Finck     }
1070c2c66affSColin Finck 
1071c2c66affSColin Finck     if (!(connect = (connect_t *)grab_object( hconnect )))
1072c2c66affSColin Finck     {
1073c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
1074c2c66affSColin Finck         return NULL;
1075c2c66affSColin Finck     }
1076c2c66affSColin Finck     if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
1077c2c66affSColin Finck     {
1078c2c66affSColin Finck         release_object( &connect->hdr );
1079c2c66affSColin Finck         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1080c2c66affSColin Finck         return NULL;
1081c2c66affSColin Finck     }
1082c2c66affSColin Finck     if (!(request = heap_alloc_zero( sizeof(request_t) )))
1083c2c66affSColin Finck     {
1084c2c66affSColin Finck         release_object( &connect->hdr );
1085c2c66affSColin Finck         return NULL;
1086c2c66affSColin Finck     }
1087c2c66affSColin Finck     request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
1088c2c66affSColin Finck     request->hdr.vtbl = &request_vtbl;
1089c2c66affSColin Finck     request->hdr.refs = 1;
1090c2c66affSColin Finck     request->hdr.flags = flags;
1091c2c66affSColin Finck     request->hdr.callback = connect->hdr.callback;
1092c2c66affSColin Finck     request->hdr.notify_mask = connect->hdr.notify_mask;
1093c2c66affSColin Finck     request->hdr.context = connect->hdr.context;
1094c2c66affSColin Finck     request->hdr.redirect_policy = connect->hdr.redirect_policy;
1095c2c66affSColin Finck     list_init( &request->hdr.children );
1096c2c66affSColin Finck     list_init( &request->task_queue );
1097c2c66affSColin Finck 
1098c2c66affSColin Finck     addref_object( &connect->hdr );
1099c2c66affSColin Finck     request->connect = connect;
1100c2c66affSColin Finck     list_add_head( &connect->hdr.children, &request->hdr.entry );
1101c2c66affSColin Finck 
1102c2c66affSColin Finck     request->resolve_timeout = connect->session->resolve_timeout;
1103c2c66affSColin Finck     request->connect_timeout = connect->session->connect_timeout;
1104c2c66affSColin Finck     request->send_timeout = connect->session->send_timeout;
1105c2c66affSColin Finck     request->recv_timeout = connect->session->recv_timeout;
1106c2c66affSColin Finck 
1107c2c66affSColin Finck     if (!verb || !verb[0]) verb = getW;
1108c2c66affSColin Finck     if (!(request->verb = strdupW( verb ))) goto end;
1109c2c66affSColin Finck 
1110c2c66affSColin Finck     if (object)
1111c2c66affSColin Finck     {
1112c2c66affSColin Finck         WCHAR *path, *p;
1113c2c66affSColin Finck         unsigned int len;
1114c2c66affSColin Finck 
1115c2c66affSColin Finck         len = strlenW( object ) + 1;
1116c2c66affSColin Finck         if (object[0] != '/') len++;
1117c2c66affSColin Finck         if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
1118c2c66affSColin Finck 
1119c2c66affSColin Finck         if (object[0] != '/') *p++ = '/';
1120c2c66affSColin Finck         strcpyW( p, object );
1121c2c66affSColin Finck         request->path = path;
1122c2c66affSColin Finck     }
1123c2c66affSColin Finck     else if (!(request->path = strdupW( slashW ))) goto end;
1124c2c66affSColin Finck 
1125c2c66affSColin Finck     if (!version || !version[0]) version = http1_1;
1126c2c66affSColin Finck     if (!(request->version = strdupW( version ))) goto end;
1127c2c66affSColin Finck     if (!(store_accept_types( request, types ))) goto end;
1128c2c66affSColin Finck 
1129c2c66affSColin Finck     if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
1130c2c66affSColin Finck     request->hdr.handle = hrequest;
1131c2c66affSColin Finck 
1132c2c66affSColin Finck     send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1133c2c66affSColin Finck 
1134c2c66affSColin Finck end:
1135c2c66affSColin Finck     release_object( &request->hdr );
1136c2c66affSColin Finck     release_object( &connect->hdr );
1137c2c66affSColin Finck     TRACE("returning %p\n", hrequest);
1138c2c66affSColin Finck     if (hrequest) set_last_error( ERROR_SUCCESS );
1139c2c66affSColin Finck     return hrequest;
1140c2c66affSColin Finck }
1141c2c66affSColin Finck 
1142c2c66affSColin Finck /***********************************************************************
1143c2c66affSColin Finck  *          WinHttpCloseHandle (winhttp.@)
1144c2c66affSColin Finck  */
1145c2c66affSColin Finck BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1146c2c66affSColin Finck {
1147c2c66affSColin Finck     object_header_t *hdr;
1148c2c66affSColin Finck 
1149c2c66affSColin Finck     TRACE("%p\n", handle);
1150c2c66affSColin Finck 
1151c2c66affSColin Finck     if (!(hdr = grab_object( handle )))
1152c2c66affSColin Finck     {
1153c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
1154c2c66affSColin Finck         return FALSE;
1155c2c66affSColin Finck     }
1156c2c66affSColin Finck     release_object( hdr );
1157c2c66affSColin Finck     free_handle( handle );
1158c2c66affSColin Finck     set_last_error( ERROR_SUCCESS );
1159c2c66affSColin Finck     return TRUE;
1160c2c66affSColin Finck }
1161c2c66affSColin Finck 
1162c2c66affSColin Finck static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
1163c2c66affSColin Finck {
1164c2c66affSColin Finck     BOOL ret = FALSE;
1165c2c66affSColin Finck 
1166c2c66affSColin Finck     if (!buflen)
1167c2c66affSColin Finck     {
1168c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1169c2c66affSColin Finck         return FALSE;
1170c2c66affSColin Finck     }
1171c2c66affSColin Finck 
1172c2c66affSColin Finck     switch (option)
1173c2c66affSColin Finck     {
1174c2c66affSColin Finck     case WINHTTP_OPTION_CONTEXT_VALUE:
1175c2c66affSColin Finck     {
1176c2c66affSColin Finck         if (!buffer || *buflen < sizeof(DWORD_PTR))
1177c2c66affSColin Finck         {
1178c2c66affSColin Finck             *buflen = sizeof(DWORD_PTR);
1179c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
1180c2c66affSColin Finck             return FALSE;
1181c2c66affSColin Finck         }
1182c2c66affSColin Finck 
1183c2c66affSColin Finck         *(DWORD_PTR *)buffer = hdr->context;
1184c2c66affSColin Finck         *buflen = sizeof(DWORD_PTR);
1185c2c66affSColin Finck         return TRUE;
1186c2c66affSColin Finck     }
1187c2c66affSColin Finck     default:
1188c2c66affSColin Finck         if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1189c2c66affSColin Finck         else
1190c2c66affSColin Finck         {
1191c2c66affSColin Finck             FIXME("unimplemented option %u\n", option);
1192c2c66affSColin Finck             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1193c2c66affSColin Finck             return FALSE;
1194c2c66affSColin Finck         }
1195c2c66affSColin Finck         break;
1196c2c66affSColin Finck     }
1197c2c66affSColin Finck     return ret;
1198c2c66affSColin Finck }
1199c2c66affSColin Finck 
1200c2c66affSColin Finck /***********************************************************************
1201c2c66affSColin Finck  *          WinHttpQueryOption (winhttp.@)
1202c2c66affSColin Finck  */
1203c2c66affSColin Finck BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1204c2c66affSColin Finck {
1205c2c66affSColin Finck     BOOL ret = FALSE;
1206c2c66affSColin Finck     object_header_t *hdr;
1207c2c66affSColin Finck 
1208c2c66affSColin Finck     TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1209c2c66affSColin Finck 
1210c2c66affSColin Finck     if (!(hdr = grab_object( handle )))
1211c2c66affSColin Finck     {
1212c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
1213c2c66affSColin Finck         return FALSE;
1214c2c66affSColin Finck     }
1215c2c66affSColin Finck 
1216c2c66affSColin Finck     ret = query_option( hdr, option, buffer, buflen );
1217c2c66affSColin Finck 
1218c2c66affSColin Finck     release_object( hdr );
1219c2c66affSColin Finck     if (ret) set_last_error( ERROR_SUCCESS );
1220c2c66affSColin Finck     return ret;
1221c2c66affSColin Finck }
1222c2c66affSColin Finck 
1223c2c66affSColin Finck static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1224c2c66affSColin Finck {
1225c2c66affSColin Finck     BOOL ret = TRUE;
1226c2c66affSColin Finck 
1227c2c66affSColin Finck     if (!buffer && buflen)
1228c2c66affSColin Finck     {
1229c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1230c2c66affSColin Finck         return FALSE;
1231c2c66affSColin Finck     }
1232c2c66affSColin Finck 
1233c2c66affSColin Finck     switch (option)
1234c2c66affSColin Finck     {
1235c2c66affSColin Finck     case WINHTTP_OPTION_CONTEXT_VALUE:
1236c2c66affSColin Finck     {
1237c2c66affSColin Finck         if (buflen != sizeof(DWORD_PTR))
1238c2c66affSColin Finck         {
1239c2c66affSColin Finck             set_last_error( ERROR_INSUFFICIENT_BUFFER );
1240c2c66affSColin Finck             return FALSE;
1241c2c66affSColin Finck         }
1242c2c66affSColin Finck 
1243c2c66affSColin Finck         hdr->context = *(DWORD_PTR *)buffer;
1244c2c66affSColin Finck         return TRUE;
1245c2c66affSColin Finck     }
1246c2c66affSColin Finck     default:
1247c2c66affSColin Finck         if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1248c2c66affSColin Finck         else
1249c2c66affSColin Finck         {
1250c2c66affSColin Finck             FIXME("unimplemented option %u\n", option);
1251c2c66affSColin Finck             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1252c2c66affSColin Finck             return FALSE;
1253c2c66affSColin Finck         }
1254c2c66affSColin Finck         break;
1255c2c66affSColin Finck     }
1256c2c66affSColin Finck     return ret;
1257c2c66affSColin Finck }
1258c2c66affSColin Finck 
1259c2c66affSColin Finck /***********************************************************************
1260c2c66affSColin Finck  *          WinHttpSetOption (winhttp.@)
1261c2c66affSColin Finck  */
1262c2c66affSColin Finck BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1263c2c66affSColin Finck {
1264c2c66affSColin Finck     BOOL ret = FALSE;
1265c2c66affSColin Finck     object_header_t *hdr;
1266c2c66affSColin Finck 
1267c2c66affSColin Finck     TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1268c2c66affSColin Finck 
1269c2c66affSColin Finck     if (!(hdr = grab_object( handle )))
1270c2c66affSColin Finck     {
1271c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
1272c2c66affSColin Finck         return FALSE;
1273c2c66affSColin Finck     }
1274c2c66affSColin Finck 
1275c2c66affSColin Finck     ret = set_option( hdr, option, buffer, buflen );
1276c2c66affSColin Finck 
1277c2c66affSColin Finck     release_object( hdr );
1278c2c66affSColin Finck     if (ret) set_last_error( ERROR_SUCCESS );
1279c2c66affSColin Finck     return ret;
1280c2c66affSColin Finck }
1281c2c66affSColin Finck 
1282c2c66affSColin Finck static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1283c2c66affSColin Finck {
1284c2c66affSColin Finck     char *ret;
1285c2c66affSColin Finck     DWORD size = 0;
1286c2c66affSColin Finck 
1287c2c66affSColin Finck     GetComputerNameExA( format, NULL, &size );
1288c2c66affSColin Finck     if (GetLastError() != ERROR_MORE_DATA) return NULL;
1289c2c66affSColin Finck     if (!(ret = heap_alloc( size ))) return NULL;
1290c2c66affSColin Finck     if (!GetComputerNameExA( format, ret, &size ))
1291c2c66affSColin Finck     {
1292c2c66affSColin Finck         heap_free( ret );
1293c2c66affSColin Finck         return NULL;
1294c2c66affSColin Finck     }
1295c2c66affSColin Finck     return ret;
1296c2c66affSColin Finck }
1297c2c66affSColin Finck 
1298c2c66affSColin Finck static BOOL is_domain_suffix( const char *domain, const char *suffix )
1299c2c66affSColin Finck {
1300c2c66affSColin Finck     int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1301c2c66affSColin Finck 
1302c2c66affSColin Finck     if (len_suffix > len_domain) return FALSE;
1303c2c66affSColin Finck     if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1304c2c66affSColin Finck     return FALSE;
1305c2c66affSColin Finck }
1306c2c66affSColin Finck 
1307c2c66affSColin Finck static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1308c2c66affSColin Finck {
1309c2c66affSColin Finck     int ret = -1;
1310c2c66affSColin Finck #ifdef HAVE_GETNAMEINFO
1311c2c66affSColin Finck     ret = getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1312c2c66affSColin Finck #endif
1313c2c66affSColin Finck     return ret;
1314c2c66affSColin Finck }
1315c2c66affSColin Finck 
1316c2c66affSColin Finck static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1317c2c66affSColin Finck {
1318c2c66affSColin Finck     static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1319c2c66affSColin Finck     static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
1320c2c66affSColin Finck     char name[NI_MAXHOST];
1321c2c66affSColin Finck     WCHAR *ret, *p;
1322c2c66affSColin Finck     int len;
1323c2c66affSColin Finck 
1324c2c66affSColin Finck     while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1325c2c66affSColin Finck     if (!ai) return NULL;
1326c2c66affSColin Finck 
1327c2c66affSColin Finck     if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1328c2c66affSColin Finck 
1329c2c66affSColin Finck     len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW );
1330c2c66affSColin Finck     if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1331c2c66affSColin Finck     strcpyW( p, httpW );
1332c2c66affSColin Finck     p += strlenW( httpW );
1333c2c66affSColin Finck     while (*hostname) { *p++ = *hostname++; }
1334c2c66affSColin Finck     strcpyW( p, wpadW );
1335c2c66affSColin Finck     return ret;
1336c2c66affSColin Finck }
1337c2c66affSColin Finck 
1338c2c66affSColin Finck static BOOL get_system_proxy_autoconfig_url( char *buf, DWORD buflen )
1339c2c66affSColin Finck {
1340c2c66affSColin Finck #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1341c2c66affSColin Finck     CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
1342c2c66affSColin Finck     const void *ref;
1343c2c66affSColin Finck     BOOL ret = FALSE;
1344c2c66affSColin Finck 
1345c2c66affSColin Finck     if (!settings) return FALSE;
1346c2c66affSColin Finck 
1347c2c66affSColin Finck     if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
1348c2c66affSColin Finck     {
1349c2c66affSColin Finck         CFRelease( settings );
1350c2c66affSColin Finck         return FALSE;
1351c2c66affSColin Finck     }
1352c2c66affSColin Finck     if (CFStringGetCString( ref, buf, buflen, kCFStringEncodingASCII ))
1353c2c66affSColin Finck     {
1354c2c66affSColin Finck         TRACE( "returning %s\n", debugstr_a(buf) );
1355c2c66affSColin Finck         ret = TRUE;
1356c2c66affSColin Finck     }
1357c2c66affSColin Finck     CFRelease( settings );
1358c2c66affSColin Finck     return ret;
1359c2c66affSColin Finck #else
1360c2c66affSColin Finck     static BOOL first = TRUE;
1361c2c66affSColin Finck     if (first)
1362c2c66affSColin Finck     {
1363c2c66affSColin Finck         FIXME( "no support on this platform\n" );
1364c2c66affSColin Finck         first = FALSE;
1365c2c66affSColin Finck     }
1366c2c66affSColin Finck     else
1367c2c66affSColin Finck         TRACE( "no support on this platform\n" );
1368c2c66affSColin Finck     return FALSE;
1369c2c66affSColin Finck #endif
1370c2c66affSColin Finck }
1371c2c66affSColin Finck 
1372c2c66affSColin Finck #define INTERNET_MAX_URL_LENGTH 2084
1373c2c66affSColin Finck 
1374c2c66affSColin Finck /***********************************************************************
1375c2c66affSColin Finck  *          WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1376c2c66affSColin Finck  */
1377c2c66affSColin Finck BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1378c2c66affSColin Finck {
1379c2c66affSColin Finck     BOOL ret = FALSE;
1380c2c66affSColin Finck     char system_url[INTERNET_MAX_URL_LENGTH + 1];
1381c2c66affSColin Finck 
1382c2c66affSColin Finck     TRACE("0x%08x, %p\n", flags, url);
1383c2c66affSColin Finck 
1384c2c66affSColin Finck     if (!flags || !url)
1385c2c66affSColin Finck     {
1386c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1387c2c66affSColin Finck         return FALSE;
1388c2c66affSColin Finck     }
1389c2c66affSColin Finck     if (get_system_proxy_autoconfig_url( system_url, sizeof(system_url) ))
1390c2c66affSColin Finck     {
1391c2c66affSColin Finck         WCHAR *urlW;
1392c2c66affSColin Finck 
1393c2c66affSColin Finck         if (!(urlW = strdupAW( system_url ))) return FALSE;
1394c2c66affSColin Finck         *url = urlW;
1395c2c66affSColin Finck         set_last_error( ERROR_SUCCESS );
1396c2c66affSColin Finck         return TRUE;
1397c2c66affSColin Finck     }
1398c2c66affSColin Finck     if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1399c2c66affSColin Finck     {
1400c2c66affSColin Finck         static int fixme_shown;
1401c2c66affSColin Finck         if (!fixme_shown++) FIXME("discovery via DHCP not supported\n");
1402c2c66affSColin Finck     }
1403c2c66affSColin Finck     if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1404c2c66affSColin Finck     {
1405c2c66affSColin Finck #ifdef HAVE_GETADDRINFO
1406c2c66affSColin Finck         char *fqdn, *domain, *p;
1407c2c66affSColin Finck 
1408c2c66affSColin Finck         if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE;
1409c2c66affSColin Finck         if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1410c2c66affSColin Finck         {
1411c2c66affSColin Finck             heap_free( fqdn );
1412c2c66affSColin Finck             return FALSE;
1413c2c66affSColin Finck         }
1414c2c66affSColin Finck         p = fqdn;
1415c2c66affSColin Finck         while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1416c2c66affSColin Finck         {
1417c2c66affSColin Finck             struct addrinfo *ai;
1418c2c66affSColin Finck             char *name;
1419c2c66affSColin Finck             int res;
1420c2c66affSColin Finck 
1421c2c66affSColin Finck             if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
1422c2c66affSColin Finck             {
1423c2c66affSColin Finck                 heap_free( fqdn );
1424c2c66affSColin Finck                 heap_free( domain );
1425c2c66affSColin Finck                 return FALSE;
1426c2c66affSColin Finck             }
1427c2c66affSColin Finck             strcpy( name, "wpad" );
1428c2c66affSColin Finck             strcat( name, p );
1429c2c66affSColin Finck             res = getaddrinfo( name, NULL, NULL, &ai );
1430c2c66affSColin Finck             if (!res)
1431c2c66affSColin Finck             {
1432c2c66affSColin Finck                 *url = build_wpad_url( name, ai );
1433c2c66affSColin Finck                 freeaddrinfo( ai );
1434c2c66affSColin Finck                 if (*url)
1435c2c66affSColin Finck                 {
1436c2c66affSColin Finck                     TRACE("returning %s\n", debugstr_w(*url));
1437c2c66affSColin Finck                     heap_free( name );
1438c2c66affSColin Finck                     ret = TRUE;
1439c2c66affSColin Finck                     break;
1440c2c66affSColin Finck                 }
1441c2c66affSColin Finck             }
1442c2c66affSColin Finck             heap_free( name );
1443c2c66affSColin Finck             p++;
1444c2c66affSColin Finck         }
1445c2c66affSColin Finck         heap_free( domain );
1446c2c66affSColin Finck         heap_free( fqdn );
1447c2c66affSColin Finck #else
1448c2c66affSColin Finck     FIXME("getaddrinfo not found at build time\n");
1449c2c66affSColin Finck #endif
1450c2c66affSColin Finck     }
1451c2c66affSColin Finck     if (!ret)
1452c2c66affSColin Finck     {
1453c2c66affSColin Finck         set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1454c2c66affSColin Finck         *url = NULL;
1455c2c66affSColin Finck     }
1456c2c66affSColin Finck     else set_last_error( ERROR_SUCCESS );
1457c2c66affSColin Finck     return ret;
1458c2c66affSColin Finck }
1459c2c66affSColin Finck 
1460c2c66affSColin Finck static const WCHAR Connections[] = {
1461c2c66affSColin Finck     'S','o','f','t','w','a','r','e','\\',
1462c2c66affSColin Finck     'M','i','c','r','o','s','o','f','t','\\',
1463c2c66affSColin Finck     'W','i','n','d','o','w','s','\\',
1464c2c66affSColin Finck     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1465c2c66affSColin Finck     'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1466c2c66affSColin Finck     'C','o','n','n','e','c','t','i','o','n','s',0 };
1467c2c66affSColin Finck static const WCHAR WinHttpSettings[] = {
1468c2c66affSColin Finck     'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1469c2c66affSColin Finck static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1470c2c66affSColin Finck static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1471c2c66affSColin Finck static const DWORD PROXY_TYPE_DIRECT         = 1;
1472c2c66affSColin Finck static const DWORD PROXY_TYPE_PROXY          = 2;
1473c2c66affSColin Finck static const DWORD PROXY_USE_PAC_SCRIPT      = 4;
1474c2c66affSColin Finck static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1475c2c66affSColin Finck 
1476c2c66affSColin Finck struct connection_settings_header
1477c2c66affSColin Finck {
1478c2c66affSColin Finck     DWORD magic;
1479c2c66affSColin Finck     DWORD unknown; /* always zero? */
1480c2c66affSColin Finck     DWORD flags;   /* one or more of PROXY_* */
1481c2c66affSColin Finck };
1482c2c66affSColin Finck 
1483c2c66affSColin Finck static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1484c2c66affSColin Finck {
1485c2c66affSColin Finck     const BYTE *begin;
1486c2c66affSColin Finck 
1487c2c66affSColin Finck     for (begin = src; src - begin < len; src++, dst++)
1488c2c66affSColin Finck         *dst = *src;
1489c2c66affSColin Finck     *dst = 0;
1490c2c66affSColin Finck }
1491c2c66affSColin Finck 
1492c2c66affSColin Finck /***********************************************************************
1493c2c66affSColin Finck  *          WinHttpGetDefaultProxyConfiguration (winhttp.@)
1494c2c66affSColin Finck  */
1495c2c66affSColin Finck BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1496c2c66affSColin Finck {
1497c2c66affSColin Finck     LONG l;
1498c2c66affSColin Finck     HKEY key;
1499c2c66affSColin Finck     BOOL got_from_reg = FALSE, direct = TRUE;
1500c2c66affSColin Finck     char *envproxy;
1501c2c66affSColin Finck 
1502c2c66affSColin Finck     TRACE("%p\n", info);
1503c2c66affSColin Finck 
1504c2c66affSColin Finck     l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1505c2c66affSColin Finck     if (!l)
1506c2c66affSColin Finck     {
1507c2c66affSColin Finck         DWORD type, size = 0;
1508c2c66affSColin Finck 
1509c2c66affSColin Finck         l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1510c2c66affSColin Finck         if (!l && type == REG_BINARY &&
1511c2c66affSColin Finck             size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1512c2c66affSColin Finck         {
1513c2c66affSColin Finck             BYTE *buf = heap_alloc( size );
1514c2c66affSColin Finck 
1515c2c66affSColin Finck             if (buf)
1516c2c66affSColin Finck             {
1517c2c66affSColin Finck                 struct connection_settings_header *hdr =
1518c2c66affSColin Finck                     (struct connection_settings_header *)buf;
1519c2c66affSColin Finck                 DWORD *len = (DWORD *)(hdr + 1);
1520c2c66affSColin Finck 
1521c2c66affSColin Finck                 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1522c2c66affSColin Finck                     &size );
1523c2c66affSColin Finck                 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1524c2c66affSColin Finck                     hdr->unknown == 0)
1525c2c66affSColin Finck                 {
1526c2c66affSColin Finck                     if (hdr->flags & PROXY_TYPE_PROXY)
1527c2c66affSColin Finck                     {
1528c2c66affSColin Finck                        BOOL sane = FALSE;
1529c2c66affSColin Finck                        LPWSTR proxy = NULL;
1530c2c66affSColin Finck                        LPWSTR proxy_bypass = NULL;
1531c2c66affSColin Finck 
1532c2c66affSColin Finck                         /* Sanity-check length of proxy string */
1533c2c66affSColin Finck                         if ((BYTE *)len - buf + *len <= size)
1534c2c66affSColin Finck                         {
1535c2c66affSColin Finck                             sane = TRUE;
1536c2c66affSColin Finck                             proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1537c2c66affSColin Finck                             if (proxy)
1538c2c66affSColin Finck                                 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1539c2c66affSColin Finck                             len = (DWORD *)((BYTE *)(len + 1) + *len);
1540c2c66affSColin Finck                         }
1541c2c66affSColin Finck                         if (sane)
1542c2c66affSColin Finck                         {
1543c2c66affSColin Finck                             /* Sanity-check length of proxy bypass string */
1544c2c66affSColin Finck                             if ((BYTE *)len - buf + *len <= size)
1545c2c66affSColin Finck                             {
1546c2c66affSColin Finck                                 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1547c2c66affSColin Finck                                 if (proxy_bypass)
1548c2c66affSColin Finck                                     copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1549c2c66affSColin Finck                             }
1550c2c66affSColin Finck                             else
1551c2c66affSColin Finck                             {
1552c2c66affSColin Finck                                 sane = FALSE;
1553c2c66affSColin Finck                                 GlobalFree( proxy );
1554c2c66affSColin Finck                                 proxy = NULL;
1555c2c66affSColin Finck                             }
1556c2c66affSColin Finck                         }
1557c2c66affSColin Finck                         info->lpszProxy = proxy;
1558c2c66affSColin Finck                         info->lpszProxyBypass = proxy_bypass;
1559c2c66affSColin Finck                         if (sane)
1560c2c66affSColin Finck                         {
1561c2c66affSColin Finck                             got_from_reg = TRUE;
1562c2c66affSColin Finck                             direct = FALSE;
1563c2c66affSColin Finck                             info->dwAccessType =
1564c2c66affSColin Finck                                 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1565c2c66affSColin Finck                             TRACE("http proxy (from registry) = %s, bypass = %s\n",
1566c2c66affSColin Finck                                 debugstr_w(info->lpszProxy),
1567c2c66affSColin Finck                                 debugstr_w(info->lpszProxyBypass));
1568c2c66affSColin Finck                         }
1569c2c66affSColin Finck                     }
1570c2c66affSColin Finck                 }
1571c2c66affSColin Finck                 heap_free( buf );
1572c2c66affSColin Finck             }
1573c2c66affSColin Finck         }
1574c2c66affSColin Finck         RegCloseKey( key );
1575c2c66affSColin Finck     }
1576c2c66affSColin Finck     if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1577c2c66affSColin Finck     {
1578c2c66affSColin Finck         char *colon, *http_proxy;
1579c2c66affSColin Finck 
1580c2c66affSColin Finck         if ((colon = strchr( envproxy, ':' )))
1581c2c66affSColin Finck         {
1582c2c66affSColin Finck             if (*(colon + 1) == '/' && *(colon + 2) == '/')
1583c2c66affSColin Finck             {
1584c2c66affSColin Finck                 static const char http[] = "http://";
1585c2c66affSColin Finck 
1586c2c66affSColin Finck                 /* It's a scheme, check that it's http */
1587c2c66affSColin Finck                 if (!strncmp( envproxy, http, strlen( http ) ))
1588c2c66affSColin Finck                     http_proxy = envproxy + strlen( http );
1589c2c66affSColin Finck                 else
1590c2c66affSColin Finck                 {
1591c2c66affSColin Finck                     WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1592c2c66affSColin Finck                     http_proxy = NULL;
1593c2c66affSColin Finck                 }
1594c2c66affSColin Finck             }
1595c2c66affSColin Finck             else
1596c2c66affSColin Finck                 http_proxy = envproxy;
1597c2c66affSColin Finck         }
1598c2c66affSColin Finck         else
1599c2c66affSColin Finck             http_proxy = envproxy;
1600c2c66affSColin Finck         if (http_proxy)
1601c2c66affSColin Finck         {
1602c2c66affSColin Finck             WCHAR *http_proxyW;
1603c2c66affSColin Finck             int len;
1604c2c66affSColin Finck 
1605c2c66affSColin Finck             len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1606c2c66affSColin Finck             if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1607c2c66affSColin Finck             {
1608c2c66affSColin Finck                 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1609c2c66affSColin Finck                 direct = FALSE;
1610c2c66affSColin Finck                 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1611c2c66affSColin Finck                 info->lpszProxy = http_proxyW;
1612c2c66affSColin Finck                 info->lpszProxyBypass = NULL;
1613c2c66affSColin Finck                 TRACE("http proxy (from environment) = %s\n",
1614c2c66affSColin Finck                     debugstr_w(info->lpszProxy));
1615c2c66affSColin Finck             }
1616c2c66affSColin Finck         }
1617c2c66affSColin Finck     }
1618c2c66affSColin Finck     if (direct)
1619c2c66affSColin Finck     {
1620c2c66affSColin Finck         info->dwAccessType    = WINHTTP_ACCESS_TYPE_NO_PROXY;
1621c2c66affSColin Finck         info->lpszProxy       = NULL;
1622c2c66affSColin Finck         info->lpszProxyBypass = NULL;
1623c2c66affSColin Finck     }
1624c2c66affSColin Finck     set_last_error( ERROR_SUCCESS );
1625c2c66affSColin Finck     return TRUE;
1626c2c66affSColin Finck }
1627c2c66affSColin Finck 
1628c2c66affSColin Finck /***********************************************************************
1629c2c66affSColin Finck  *          WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1630c2c66affSColin Finck  */
1631c2c66affSColin Finck BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1632c2c66affSColin Finck {
1633c2c66affSColin Finck     static const WCHAR settingsW[] =
1634c2c66affSColin Finck         {'D','e','f','a','u','l','t','C','o','n','n','e','c','t','i','o','n','S','e','t','t','i','n','g','s',0};
1635c2c66affSColin Finck     HKEY hkey = NULL;
1636c2c66affSColin Finck     struct connection_settings_header *hdr = NULL;
1637c2c66affSColin Finck     DWORD type, offset, len, size = 0;
1638c2c66affSColin Finck     BOOL ret = FALSE;
1639c2c66affSColin Finck 
1640c2c66affSColin Finck     TRACE("%p\n", config);
1641c2c66affSColin Finck 
1642c2c66affSColin Finck     if (!config)
1643c2c66affSColin Finck     {
1644c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1645c2c66affSColin Finck         return FALSE;
1646c2c66affSColin Finck     }
1647c2c66affSColin Finck     memset( config, 0, sizeof(*config) );
1648c2c66affSColin Finck     config->fAutoDetect = TRUE;
1649c2c66affSColin Finck 
1650c2c66affSColin Finck     if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) ||
1651c2c66affSColin Finck         RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) ||
1652c2c66affSColin Finck         type != REG_BINARY || size < sizeof(struct connection_settings_header))
1653c2c66affSColin Finck     {
1654c2c66affSColin Finck         ret = TRUE;
1655c2c66affSColin Finck         goto done;
1656c2c66affSColin Finck     }
1657c2c66affSColin Finck     if (!(hdr = heap_alloc( size ))) goto done;
1658c2c66affSColin Finck     if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) ||
1659c2c66affSColin Finck         hdr->magic != WININET_SETTINGS_MAGIC)
1660c2c66affSColin Finck     {
1661c2c66affSColin Finck         ret = TRUE;
1662c2c66affSColin Finck         goto done;
1663c2c66affSColin Finck     }
1664c2c66affSColin Finck 
1665c2c66affSColin Finck     config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1666c2c66affSColin Finck     offset = sizeof(*hdr);
1667c2c66affSColin Finck     if (offset + sizeof(DWORD) > size) goto done;
1668c2c66affSColin Finck     len = *(DWORD *)((char *)hdr + offset);
1669c2c66affSColin Finck     offset += sizeof(DWORD);
1670c2c66affSColin Finck     if (len && hdr->flags & PROXY_TYPE_PROXY)
1671c2c66affSColin Finck     {
1672c2c66affSColin Finck         if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1673c2c66affSColin Finck         copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1674c2c66affSColin Finck     }
1675c2c66affSColin Finck     offset += len;
1676c2c66affSColin Finck     if (offset + sizeof(DWORD) > size) goto done;
1677c2c66affSColin Finck     len = *(DWORD *)((char *)hdr + offset);
1678c2c66affSColin Finck     offset += sizeof(DWORD);
1679c2c66affSColin Finck     if (len && (hdr->flags & PROXY_TYPE_PROXY))
1680c2c66affSColin Finck     {
1681c2c66affSColin Finck         if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1682c2c66affSColin Finck         copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1683c2c66affSColin Finck     }
1684c2c66affSColin Finck     offset += len;
1685c2c66affSColin Finck     if (offset + sizeof(DWORD) > size) goto done;
1686c2c66affSColin Finck     len = *(DWORD *)((char *)hdr + offset);
1687c2c66affSColin Finck     offset += sizeof(DWORD);
1688c2c66affSColin Finck     if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1689c2c66affSColin Finck     {
1690c2c66affSColin Finck         if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1691c2c66affSColin Finck         copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1692c2c66affSColin Finck     }
1693c2c66affSColin Finck     ret = TRUE;
1694c2c66affSColin Finck 
1695c2c66affSColin Finck done:
1696c2c66affSColin Finck     RegCloseKey( hkey );
1697c2c66affSColin Finck     heap_free( hdr );
1698c2c66affSColin Finck     if (!ret)
1699c2c66affSColin Finck     {
1700c2c66affSColin Finck         GlobalFree( config->lpszAutoConfigUrl );
1701c2c66affSColin Finck         config->lpszAutoConfigUrl = NULL;
1702c2c66affSColin Finck         GlobalFree( config->lpszProxy );
1703c2c66affSColin Finck         config->lpszProxy = NULL;
1704c2c66affSColin Finck         GlobalFree( config->lpszProxyBypass );
1705c2c66affSColin Finck         config->lpszProxyBypass = NULL;
1706c2c66affSColin Finck     }
1707c2c66affSColin Finck     else set_last_error( ERROR_SUCCESS );
1708c2c66affSColin Finck     return ret;
1709c2c66affSColin Finck }
1710c2c66affSColin Finck 
1711c2c66affSColin Finck static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1712c2c66affSColin Finck {
1713c2c66affSColin Finck     const char *p;
1714c2c66affSColin Finck     WCHAR *q;
1715c2c66affSColin Finck     int len;
1716c2c66affSColin Finck 
1717c2c66affSColin Finck     info->dwAccessType    = WINHTTP_ACCESS_TYPE_NO_PROXY;
1718c2c66affSColin Finck     info->lpszProxy       = NULL;
1719c2c66affSColin Finck     info->lpszProxyBypass = NULL;
1720c2c66affSColin Finck 
1721c2c66affSColin Finck     TRACE("%s\n", debugstr_a( result ));
1722c2c66affSColin Finck 
1723c2c66affSColin Finck     p = result;
1724c2c66affSColin Finck     while (*p == ' ') p++;
1725c2c66affSColin Finck     len = strlen( p );
1726c2c66affSColin Finck     if (len >= 5 && !strncasecmp( p, "PROXY", sizeof("PROXY") - 1 ))
1727c2c66affSColin Finck     {
1728c2c66affSColin Finck         p += 5;
1729c2c66affSColin Finck         while (*p == ' ') p++;
1730c2c66affSColin Finck         if (!*p || *p == ';') return TRUE;
1731c2c66affSColin Finck         if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1732c2c66affSColin Finck         info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1733c2c66affSColin Finck         for (; *q; q++)
1734c2c66affSColin Finck         {
1735c2c66affSColin Finck             if (*q == ' ' || *q == ';')
1736c2c66affSColin Finck             {
1737c2c66affSColin Finck                 *q = 0;
1738c2c66affSColin Finck                 break;
1739c2c66affSColin Finck             }
1740c2c66affSColin Finck         }
1741c2c66affSColin Finck     }
1742c2c66affSColin Finck     return TRUE;
1743c2c66affSColin Finck }
1744c2c66affSColin Finck 
1745c2c66affSColin Finck static char *download_script( const WCHAR *url, DWORD *out_size )
1746c2c66affSColin Finck {
1747c2c66affSColin Finck     static const WCHAR typeW[] = {'*','/','*',0};
1748c2c66affSColin Finck     static const WCHAR *acceptW[] = {typeW, NULL};
1749c2c66affSColin Finck     HINTERNET ses, con = NULL, req = NULL;
1750c2c66affSColin Finck     WCHAR *hostname;
1751c2c66affSColin Finck     URL_COMPONENTSW uc;
1752c2c66affSColin Finck     DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1753c2c66affSColin Finck     char *tmp, *buffer = NULL;
1754c2c66affSColin Finck 
1755c2c66affSColin Finck     *out_size = 0;
1756c2c66affSColin Finck 
1757c2c66affSColin Finck     memset( &uc, 0, sizeof(uc) );
1758c2c66affSColin Finck     uc.dwStructSize = sizeof(uc);
1759c2c66affSColin Finck     uc.dwHostNameLength = -1;
1760c2c66affSColin Finck     uc.dwUrlPathLength = -1;
1761c2c66affSColin Finck     if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1762c2c66affSColin Finck     if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1763c2c66affSColin Finck     memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1764c2c66affSColin Finck     hostname[uc.dwHostNameLength] = 0;
1765c2c66affSColin Finck 
1766c2c66affSColin Finck     if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1767c2c66affSColin Finck     if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1768c2c66affSColin Finck     if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1769c2c66affSColin Finck     if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1770c2c66affSColin Finck     if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1771c2c66affSColin Finck 
1772c2c66affSColin Finck     if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
1773c2c66affSColin Finck     if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1774c2c66affSColin Finck         &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1775c2c66affSColin Finck 
1776c2c66affSColin Finck     size = 4096;
1777c2c66affSColin Finck     if (!(buffer = heap_alloc( size ))) goto done;
1778c2c66affSColin Finck     to_read = size;
1779c2c66affSColin Finck     offset = 0;
1780c2c66affSColin Finck     for (;;)
1781c2c66affSColin Finck     {
1782c2c66affSColin Finck         if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1783c2c66affSColin Finck         if (!bytes_read) break;
1784c2c66affSColin Finck         to_read -= bytes_read;
1785c2c66affSColin Finck         offset += bytes_read;
1786c2c66affSColin Finck         *out_size += bytes_read;
1787c2c66affSColin Finck         if (!to_read)
1788c2c66affSColin Finck         {
1789c2c66affSColin Finck             to_read = size;
1790c2c66affSColin Finck             size *= 2;
1791c2c66affSColin Finck             if (!(tmp = heap_realloc( buffer, size ))) goto done;
1792c2c66affSColin Finck             buffer = tmp;
1793c2c66affSColin Finck         }
1794c2c66affSColin Finck     }
1795c2c66affSColin Finck 
1796c2c66affSColin Finck done:
1797c2c66affSColin Finck     WinHttpCloseHandle( req );
1798c2c66affSColin Finck     WinHttpCloseHandle( con );
1799c2c66affSColin Finck     WinHttpCloseHandle( ses );
1800c2c66affSColin Finck     heap_free( hostname );
1801c2c66affSColin Finck     if (!buffer) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1802c2c66affSColin Finck     return buffer;
1803c2c66affSColin Finck }
1804c2c66affSColin Finck 
1805c2c66affSColin Finck struct AUTO_PROXY_SCRIPT_BUFFER
1806c2c66affSColin Finck {
1807c2c66affSColin Finck     DWORD dwStructSize;
1808c2c66affSColin Finck     LPSTR lpszScriptBuffer;
1809c2c66affSColin Finck     DWORD dwScriptBufferSize;
1810c2c66affSColin Finck };
1811c2c66affSColin Finck 
1812c2c66affSColin Finck BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
1813c2c66affSColin Finck BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
1814c2c66affSColin Finck BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
1815c2c66affSColin Finck 
1816c2c66affSColin Finck static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1817c2c66affSColin Finck {
1818c2c66affSColin Finck     BOOL ret;
1819c2c66affSColin Finck     char *result, *urlA;
1820c2c66affSColin Finck     DWORD len_result;
1821c2c66affSColin Finck     struct AUTO_PROXY_SCRIPT_BUFFER buffer;
1822c2c66affSColin Finck     URL_COMPONENTSW uc;
1823c2c66affSColin Finck 
1824c2c66affSColin Finck     buffer.dwStructSize = sizeof(buffer);
1825c2c66affSColin Finck     buffer.lpszScriptBuffer = script;
1826c2c66affSColin Finck     buffer.dwScriptBufferSize = size;
1827c2c66affSColin Finck 
1828c2c66affSColin Finck     if (!(urlA = strdupWA( url ))) return FALSE;
1829c2c66affSColin Finck     if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
1830c2c66affSColin Finck     {
1831c2c66affSColin Finck         heap_free( urlA );
1832c2c66affSColin Finck         return FALSE;
1833c2c66affSColin Finck     }
1834c2c66affSColin Finck 
1835c2c66affSColin Finck     memset( &uc, 0, sizeof(uc) );
1836c2c66affSColin Finck     uc.dwStructSize = sizeof(uc);
1837c2c66affSColin Finck     uc.dwHostNameLength = -1;
1838c2c66affSColin Finck 
1839c2c66affSColin Finck     if (WinHttpCrackUrl( url, 0, 0, &uc ))
1840c2c66affSColin Finck     {
1841c2c66affSColin Finck         char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength );
1842c2c66affSColin Finck 
1843c2c66affSColin Finck         if ((ret = InternetGetProxyInfo( urlA, strlen(urlA),
1844c2c66affSColin Finck                         hostnameA, strlen(hostnameA), &result, &len_result )))
1845c2c66affSColin Finck         {
1846c2c66affSColin Finck             ret = parse_script_result( result, info );
1847c2c66affSColin Finck             heap_free( result );
1848c2c66affSColin Finck         }
1849c2c66affSColin Finck 
1850c2c66affSColin Finck         heap_free( hostnameA );
1851c2c66affSColin Finck     }
1852c2c66affSColin Finck     heap_free( urlA );
1853c2c66affSColin Finck     return InternetDeInitializeAutoProxyDll( NULL, 0 );
1854c2c66affSColin Finck }
1855c2c66affSColin Finck 
1856c2c66affSColin Finck /***********************************************************************
1857c2c66affSColin Finck  *          WinHttpGetProxyForUrl (winhttp.@)
1858c2c66affSColin Finck  */
1859c2c66affSColin Finck BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1860c2c66affSColin Finck                                    WINHTTP_PROXY_INFO *info )
1861c2c66affSColin Finck {
1862c2c66affSColin Finck     WCHAR *detected_pac_url = NULL;
1863c2c66affSColin Finck     const WCHAR *pac_url;
1864c2c66affSColin Finck     session_t *session;
1865c2c66affSColin Finck     char *script;
1866c2c66affSColin Finck     DWORD size;
1867c2c66affSColin Finck     BOOL ret = FALSE;
1868c2c66affSColin Finck 
1869c2c66affSColin Finck     TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1870c2c66affSColin Finck 
1871c2c66affSColin Finck     if (!(session = (session_t *)grab_object( hsession )))
1872c2c66affSColin Finck     {
1873c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
1874c2c66affSColin Finck         return FALSE;
1875c2c66affSColin Finck     }
1876c2c66affSColin Finck     if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
1877c2c66affSColin Finck     {
1878c2c66affSColin Finck         release_object( &session->hdr );
1879c2c66affSColin Finck         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1880c2c66affSColin Finck         return FALSE;
1881c2c66affSColin Finck     }
1882c2c66affSColin Finck     if (!url || !options || !info ||
1883c2c66affSColin Finck         !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
1884c2c66affSColin Finck         ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
1885c2c66affSColin Finck         ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
1886c2c66affSColin Finck          (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
1887c2c66affSColin Finck     {
1888c2c66affSColin Finck         release_object( &session->hdr );
1889c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1890c2c66affSColin Finck         return FALSE;
1891c2c66affSColin Finck     }
1892c2c66affSColin Finck     if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
1893c2c66affSColin Finck         !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
1894c2c66affSColin Finck         goto done;
1895c2c66affSColin Finck 
1896c2c66affSColin Finck     if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
1897c2c66affSColin Finck     else pac_url = detected_pac_url;
1898c2c66affSColin Finck 
1899c2c66affSColin Finck     if ((script = download_script( pac_url, &size )))
1900c2c66affSColin Finck     {
1901c2c66affSColin Finck         ret = run_script( script, size, url, info );
1902c2c66affSColin Finck         heap_free( script );
1903c2c66affSColin Finck     }
1904c2c66affSColin Finck 
1905c2c66affSColin Finck done:
1906c2c66affSColin Finck     GlobalFree( detected_pac_url );
1907c2c66affSColin Finck     release_object( &session->hdr );
1908c2c66affSColin Finck     if (ret) set_last_error( ERROR_SUCCESS );
1909c2c66affSColin Finck     return ret;
1910c2c66affSColin Finck }
1911c2c66affSColin Finck 
1912c2c66affSColin Finck /***********************************************************************
1913c2c66affSColin Finck  *          WinHttpSetDefaultProxyConfiguration (winhttp.@)
1914c2c66affSColin Finck  */
1915c2c66affSColin Finck BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1916c2c66affSColin Finck {
1917c2c66affSColin Finck     LONG l;
1918c2c66affSColin Finck     HKEY key;
1919c2c66affSColin Finck     BOOL ret = FALSE;
1920c2c66affSColin Finck     const WCHAR *src;
1921c2c66affSColin Finck 
1922c2c66affSColin Finck     TRACE("%p\n", info);
1923c2c66affSColin Finck 
1924c2c66affSColin Finck     if (!info)
1925c2c66affSColin Finck     {
1926c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1927c2c66affSColin Finck         return FALSE;
1928c2c66affSColin Finck     }
1929c2c66affSColin Finck     switch (info->dwAccessType)
1930c2c66affSColin Finck     {
1931c2c66affSColin Finck     case WINHTTP_ACCESS_TYPE_NO_PROXY:
1932c2c66affSColin Finck         break;
1933c2c66affSColin Finck     case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1934c2c66affSColin Finck         if (!info->lpszProxy)
1935c2c66affSColin Finck         {
1936c2c66affSColin Finck             set_last_error( ERROR_INVALID_PARAMETER );
1937c2c66affSColin Finck             return FALSE;
1938c2c66affSColin Finck         }
1939c2c66affSColin Finck         /* Only ASCII characters are allowed */
1940c2c66affSColin Finck         for (src = info->lpszProxy; *src; src++)
1941c2c66affSColin Finck             if (*src > 0x7f)
1942c2c66affSColin Finck             {
1943c2c66affSColin Finck                 set_last_error( ERROR_INVALID_PARAMETER );
1944c2c66affSColin Finck                 return FALSE;
1945c2c66affSColin Finck             }
1946c2c66affSColin Finck         if (info->lpszProxyBypass)
1947c2c66affSColin Finck         {
1948c2c66affSColin Finck             for (src = info->lpszProxyBypass; *src; src++)
1949c2c66affSColin Finck                 if (*src > 0x7f)
1950c2c66affSColin Finck                 {
1951c2c66affSColin Finck                     set_last_error( ERROR_INVALID_PARAMETER );
1952c2c66affSColin Finck                     return FALSE;
1953c2c66affSColin Finck                 }
1954c2c66affSColin Finck         }
1955c2c66affSColin Finck         break;
1956c2c66affSColin Finck     default:
1957c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
1958c2c66affSColin Finck         return FALSE;
1959c2c66affSColin Finck     }
1960c2c66affSColin Finck 
1961c2c66affSColin Finck     l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1962c2c66affSColin Finck         KEY_WRITE, NULL, &key, NULL );
1963c2c66affSColin Finck     if (!l)
1964c2c66affSColin Finck     {
1965c2c66affSColin Finck         DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
1966c2c66affSColin Finck         BYTE *buf;
1967c2c66affSColin Finck 
1968c2c66affSColin Finck         if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1969c2c66affSColin Finck         {
1970c2c66affSColin Finck             size += strlenW( info->lpszProxy );
1971c2c66affSColin Finck             if (info->lpszProxyBypass)
1972c2c66affSColin Finck                 size += strlenW( info->lpszProxyBypass );
1973c2c66affSColin Finck         }
1974c2c66affSColin Finck         buf = heap_alloc( size );
1975c2c66affSColin Finck         if (buf)
1976c2c66affSColin Finck         {
1977c2c66affSColin Finck             struct connection_settings_header *hdr =
1978c2c66affSColin Finck                 (struct connection_settings_header *)buf;
1979c2c66affSColin Finck             DWORD *len = (DWORD *)(hdr + 1);
1980c2c66affSColin Finck 
1981c2c66affSColin Finck             hdr->magic = WINHTTP_SETTINGS_MAGIC;
1982c2c66affSColin Finck             hdr->unknown = 0;
1983c2c66affSColin Finck             if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1984c2c66affSColin Finck             {
1985c2c66affSColin Finck                 BYTE *dst;
1986c2c66affSColin Finck 
1987c2c66affSColin Finck                 hdr->flags = PROXY_TYPE_PROXY;
1988c2c66affSColin Finck                 *len++ = strlenW( info->lpszProxy );
1989c2c66affSColin Finck                 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
1990c2c66affSColin Finck                     src++, dst++)
1991c2c66affSColin Finck                     *dst = *src;
1992c2c66affSColin Finck                 len = (DWORD *)dst;
1993c2c66affSColin Finck                 if (info->lpszProxyBypass)
1994c2c66affSColin Finck                 {
1995c2c66affSColin Finck                     *len++ = strlenW( info->lpszProxyBypass );
1996c2c66affSColin Finck                     for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
1997c2c66affSColin Finck                         src++, dst++)
1998c2c66affSColin Finck                         *dst = *src;
1999c2c66affSColin Finck                 }
2000c2c66affSColin Finck                 else
2001c2c66affSColin Finck                     *len++ = 0;
2002c2c66affSColin Finck             }
2003c2c66affSColin Finck             else
2004c2c66affSColin Finck             {
2005c2c66affSColin Finck                 hdr->flags = PROXY_TYPE_DIRECT;
2006c2c66affSColin Finck                 *len++ = 0;
2007c2c66affSColin Finck                 *len++ = 0;
2008c2c66affSColin Finck             }
2009c2c66affSColin Finck             l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
2010c2c66affSColin Finck             if (!l)
2011c2c66affSColin Finck                 ret = TRUE;
2012c2c66affSColin Finck             heap_free( buf );
2013c2c66affSColin Finck         }
2014c2c66affSColin Finck         RegCloseKey( key );
2015c2c66affSColin Finck     }
2016c2c66affSColin Finck     if (ret) set_last_error( ERROR_SUCCESS );
2017c2c66affSColin Finck     return ret;
2018c2c66affSColin Finck }
2019c2c66affSColin Finck 
2020c2c66affSColin Finck /***********************************************************************
2021c2c66affSColin Finck  *          WinHttpSetStatusCallback (winhttp.@)
2022c2c66affSColin Finck  */
2023c2c66affSColin Finck WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
2024c2c66affSColin Finck                                                          DWORD flags, DWORD_PTR reserved )
2025c2c66affSColin Finck {
2026c2c66affSColin Finck     object_header_t *hdr;
2027c2c66affSColin Finck     WINHTTP_STATUS_CALLBACK ret;
2028c2c66affSColin Finck 
2029c2c66affSColin Finck     TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
2030c2c66affSColin Finck 
2031c2c66affSColin Finck     if (!(hdr = grab_object( handle )))
2032c2c66affSColin Finck     {
2033c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
2034c2c66affSColin Finck         return WINHTTP_INVALID_STATUS_CALLBACK;
2035c2c66affSColin Finck     }
2036c2c66affSColin Finck     ret = hdr->callback;
2037c2c66affSColin Finck     hdr->callback = callback;
2038c2c66affSColin Finck     hdr->notify_mask = flags;
2039c2c66affSColin Finck 
2040c2c66affSColin Finck     release_object( hdr );
2041c2c66affSColin Finck     set_last_error( ERROR_SUCCESS );
2042c2c66affSColin Finck     return ret;
2043c2c66affSColin Finck }
2044c2c66affSColin Finck 
2045c2c66affSColin Finck /***********************************************************************
2046c2c66affSColin Finck  *          WinHttpSetTimeouts (winhttp.@)
2047c2c66affSColin Finck  */
2048c2c66affSColin Finck BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
2049c2c66affSColin Finck {
2050c2c66affSColin Finck     BOOL ret = TRUE;
2051c2c66affSColin Finck     object_header_t *hdr;
2052c2c66affSColin Finck     request_t *request;
2053c2c66affSColin Finck     session_t *session;
2054c2c66affSColin Finck 
2055c2c66affSColin Finck     TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
2056c2c66affSColin Finck 
2057c2c66affSColin Finck     if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
2058c2c66affSColin Finck     {
2059c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
2060c2c66affSColin Finck         return FALSE;
2061c2c66affSColin Finck     }
2062c2c66affSColin Finck 
2063c2c66affSColin Finck     if (!(hdr = grab_object( handle )))
2064c2c66affSColin Finck     {
2065c2c66affSColin Finck         set_last_error( ERROR_INVALID_HANDLE );
2066c2c66affSColin Finck         return FALSE;
2067c2c66affSColin Finck     }
2068c2c66affSColin Finck 
2069c2c66affSColin Finck     switch(hdr->type)
2070c2c66affSColin Finck     {
2071c2c66affSColin Finck         case WINHTTP_HANDLE_TYPE_REQUEST:
2072c2c66affSColin Finck             request = (request_t *)hdr;
2073c2c66affSColin Finck             request->connect_timeout = connect;
2074c2c66affSColin Finck 
2075c2c66affSColin Finck             if (resolve < 0) resolve = 0;
2076c2c66affSColin Finck             request->resolve_timeout = resolve;
2077c2c66affSColin Finck 
2078c2c66affSColin Finck             if (send < 0) send = 0;
2079c2c66affSColin Finck             request->send_timeout = send;
2080c2c66affSColin Finck 
2081c2c66affSColin Finck             if (receive < 0) receive = 0;
2082c2c66affSColin Finck             request->recv_timeout = receive;
2083c2c66affSColin Finck 
2084c2c66affSColin Finck             if (request->netconn)
2085c2c66affSColin Finck             {
2086c2c66affSColin Finck                 if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE;
2087c2c66affSColin Finck                 if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE;
2088c2c66affSColin Finck             }
2089c2c66affSColin Finck             break;
2090c2c66affSColin Finck 
2091c2c66affSColin Finck         case WINHTTP_HANDLE_TYPE_SESSION:
2092c2c66affSColin Finck             session = (session_t *)hdr;
2093c2c66affSColin Finck             session->connect_timeout = connect;
2094c2c66affSColin Finck 
2095c2c66affSColin Finck             if (resolve < 0) resolve = 0;
2096c2c66affSColin Finck             session->resolve_timeout = resolve;
2097c2c66affSColin Finck 
2098c2c66affSColin Finck             if (send < 0) send = 0;
2099c2c66affSColin Finck             session->send_timeout = send;
2100c2c66affSColin Finck 
2101c2c66affSColin Finck             if (receive < 0) receive = 0;
2102c2c66affSColin Finck             session->recv_timeout = receive;
2103c2c66affSColin Finck             break;
2104c2c66affSColin Finck 
2105c2c66affSColin Finck         default:
2106c2c66affSColin Finck             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2107c2c66affSColin Finck             ret = FALSE;
2108c2c66affSColin Finck     }
2109c2c66affSColin Finck     release_object( hdr );
2110c2c66affSColin Finck     if (ret) set_last_error( ERROR_SUCCESS );
2111c2c66affSColin Finck     return ret;
2112c2c66affSColin Finck }
2113c2c66affSColin Finck 
2114c2c66affSColin Finck static const WCHAR wkday[7][4] =
2115c2c66affSColin Finck     {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
2116c2c66affSColin Finck      {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
2117c2c66affSColin Finck static const WCHAR month[12][4] =
2118c2c66affSColin Finck     {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
2119c2c66affSColin Finck      {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
2120c2c66affSColin Finck      {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
2121c2c66affSColin Finck 
2122c2c66affSColin Finck /***********************************************************************
2123c2c66affSColin Finck  *           WinHttpTimeFromSystemTime (WININET.@)
2124c2c66affSColin Finck  */
2125c2c66affSColin Finck BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2126c2c66affSColin Finck {
2127c2c66affSColin Finck     static const WCHAR format[] =
2128c2c66affSColin Finck         {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2129c2c66affSColin Finck          '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
2130c2c66affSColin Finck 
2131c2c66affSColin Finck     TRACE("%p, %p\n", time, string);
2132c2c66affSColin Finck 
2133c2c66affSColin Finck     if (!time || !string)
2134c2c66affSColin Finck     {
2135c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
2136c2c66affSColin Finck         return FALSE;
2137c2c66affSColin Finck     }
2138c2c66affSColin Finck 
2139c2c66affSColin Finck     sprintfW( string, format,
2140c2c66affSColin Finck               wkday[time->wDayOfWeek],
2141c2c66affSColin Finck               time->wDay,
2142c2c66affSColin Finck               month[time->wMonth - 1],
2143c2c66affSColin Finck               time->wYear,
2144c2c66affSColin Finck               time->wHour,
2145c2c66affSColin Finck               time->wMinute,
2146c2c66affSColin Finck               time->wSecond );
2147c2c66affSColin Finck 
2148c2c66affSColin Finck     set_last_error( ERROR_SUCCESS );
2149c2c66affSColin Finck     return TRUE;
2150c2c66affSColin Finck }
2151c2c66affSColin Finck 
2152c2c66affSColin Finck /***********************************************************************
2153c2c66affSColin Finck  *           WinHttpTimeToSystemTime (WININET.@)
2154c2c66affSColin Finck  */
2155c2c66affSColin Finck BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2156c2c66affSColin Finck {
2157c2c66affSColin Finck     unsigned int i;
2158c2c66affSColin Finck     const WCHAR *s = string;
2159c2c66affSColin Finck     WCHAR *end;
2160c2c66affSColin Finck 
2161c2c66affSColin Finck     TRACE("%s, %p\n", debugstr_w(string), time);
2162c2c66affSColin Finck 
2163c2c66affSColin Finck     if (!string || !time)
2164c2c66affSColin Finck     {
2165c2c66affSColin Finck         set_last_error( ERROR_INVALID_PARAMETER );
2166c2c66affSColin Finck         return FALSE;
2167c2c66affSColin Finck     }
2168c2c66affSColin Finck 
2169c2c66affSColin Finck     /* Windows does this too */
2170c2c66affSColin Finck     GetSystemTime( time );
2171c2c66affSColin Finck 
2172c2c66affSColin Finck     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2173c2c66affSColin Finck      *  a SYSTEMTIME structure.
2174c2c66affSColin Finck      */
2175c2c66affSColin Finck 
2176c2c66affSColin Finck     set_last_error( ERROR_SUCCESS );
2177c2c66affSColin Finck 
2178c2c66affSColin Finck     while (*s && !isalphaW( *s )) s++;
2179c2c66affSColin Finck     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2180c2c66affSColin Finck     time->wDayOfWeek = 7;
2181c2c66affSColin Finck 
2182c2c66affSColin Finck     for (i = 0; i < 7; i++)
2183c2c66affSColin Finck     {
2184c2c66affSColin Finck         if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
2185c2c66affSColin Finck             toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
2186c2c66affSColin Finck             toupperW( wkday[i][2] ) == toupperW( s[2] ) )
2187c2c66affSColin Finck         {
2188c2c66affSColin Finck             time->wDayOfWeek = i;
2189c2c66affSColin Finck             break;
2190c2c66affSColin Finck         }
2191c2c66affSColin Finck     }
2192c2c66affSColin Finck 
2193c2c66affSColin Finck     if (time->wDayOfWeek > 6) return TRUE;
2194c2c66affSColin Finck     while (*s && !isdigitW( *s )) s++;
2195c2c66affSColin Finck     time->wDay = strtolW( s, &end, 10 );
2196c2c66affSColin Finck     s = end;
2197c2c66affSColin Finck 
2198c2c66affSColin Finck     while (*s && !isalphaW( *s )) s++;
2199c2c66affSColin Finck     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2200c2c66affSColin Finck     time->wMonth = 0;
2201c2c66affSColin Finck 
2202c2c66affSColin Finck     for (i = 0; i < 12; i++)
2203c2c66affSColin Finck     {
2204c2c66affSColin Finck         if (toupperW( month[i][0]) == toupperW( s[0] ) &&
2205c2c66affSColin Finck             toupperW( month[i][1]) == toupperW( s[1] ) &&
2206c2c66affSColin Finck             toupperW( month[i][2]) == toupperW( s[2] ) )
2207c2c66affSColin Finck         {
2208c2c66affSColin Finck             time->wMonth = i + 1;
2209c2c66affSColin Finck             break;
2210c2c66affSColin Finck         }
2211c2c66affSColin Finck     }
2212c2c66affSColin Finck     if (time->wMonth == 0) return TRUE;
2213c2c66affSColin Finck 
2214c2c66affSColin Finck     while (*s && !isdigitW( *s )) s++;
2215c2c66affSColin Finck     if (*s == '\0') return TRUE;
2216c2c66affSColin Finck     time->wYear = strtolW( s, &end, 10 );
2217c2c66affSColin Finck     s = end;
2218c2c66affSColin Finck 
2219c2c66affSColin Finck     while (*s && !isdigitW( *s )) s++;
2220c2c66affSColin Finck     if (*s == '\0') return TRUE;
2221c2c66affSColin Finck     time->wHour = strtolW( s, &end, 10 );
2222c2c66affSColin Finck     s = end;
2223c2c66affSColin Finck 
2224c2c66affSColin Finck     while (*s && !isdigitW( *s )) s++;
2225c2c66affSColin Finck     if (*s == '\0') return TRUE;
2226c2c66affSColin Finck     time->wMinute = strtolW( s, &end, 10 );
2227c2c66affSColin Finck     s = end;
2228c2c66affSColin Finck 
2229c2c66affSColin Finck     while (*s && !isdigitW( *s )) s++;
2230c2c66affSColin Finck     if (*s == '\0') return TRUE;
2231c2c66affSColin Finck     time->wSecond = strtolW( s, &end, 10 );
2232c2c66affSColin Finck 
2233c2c66affSColin Finck     time->wMilliseconds = 0;
2234c2c66affSColin Finck     return TRUE;
2235c2c66affSColin Finck }
2236