winhttp: Reimplement WinHttpCrackUrl.
[wine] / dlls / winhttp / session.c
1 /*
2  * Copyright 2008 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wine/debug.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winhttp.h"
28 #include "wincrypt.h"
29
30 #include "winhttp_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
33
34 void set_last_error( DWORD error )
35 {
36     /* FIXME */
37     SetLastError( error );
38 }
39
40 DWORD get_last_error( void )
41 {
42     /* FIXME */
43     return GetLastError();
44 }
45
46 void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
47 {
48     TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
49
50     if (hdr->notify_mask & status) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
51 }
52
53 /***********************************************************************
54  *          WinHttpCheckPlatform (winhttp.@)
55  */
56 BOOL WINAPI WinHttpCheckPlatform( void )
57 {
58     TRACE("\n");
59     return TRUE;
60 }
61
62 /***********************************************************************
63  *          session_destroy (internal)
64  */
65 static void session_destroy( object_header_t *hdr )
66 {
67     session_t *session = (session_t *)hdr;
68     struct list *item, *next;
69     domain_t *domain;
70
71     TRACE("%p\n", session);
72
73     LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
74     {
75         domain = LIST_ENTRY( item, domain_t, entry );
76         delete_domain( domain );
77     }
78     heap_free( session->agent );
79     heap_free( session->proxy_server );
80     heap_free( session->proxy_bypass );
81     heap_free( session->proxy_username );
82     heap_free( session->proxy_password );
83     heap_free( session );
84 }
85
86 static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
87 {
88     switch (option)
89     {
90     case WINHTTP_OPTION_REDIRECT_POLICY:
91     {
92         if (!buffer || *buflen < sizeof(DWORD))
93         {
94             *buflen = sizeof(DWORD);
95             set_last_error( ERROR_INSUFFICIENT_BUFFER );
96             return FALSE;
97         }
98
99         *(DWORD *)buffer = hdr->redirect_policy;
100         *buflen = sizeof(DWORD);
101         return TRUE;
102     }
103     default:
104         FIXME("unimplemented option %u\n", option);
105         set_last_error( ERROR_INVALID_PARAMETER );
106         return FALSE;
107     }
108 }
109
110 static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
111 {
112     switch (option)
113     {
114     case WINHTTP_OPTION_PROXY:
115     {
116         WINHTTP_PROXY_INFO *pi = buffer;
117
118         FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
119         return TRUE;
120     }
121     case WINHTTP_OPTION_REDIRECT_POLICY:
122     {
123         DWORD policy;
124
125         if (buflen != sizeof(policy))
126         {
127             set_last_error( ERROR_INSUFFICIENT_BUFFER );
128             return FALSE;
129         }
130
131         policy = *(DWORD *)buffer;
132         TRACE("0x%x\n", policy);
133         hdr->redirect_policy = policy;
134         return TRUE;
135     }
136     case WINHTTP_OPTION_DISABLE_FEATURE:
137         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
138         return FALSE;
139     default:
140         FIXME("unimplemented option %u\n", option);
141         set_last_error( ERROR_INVALID_PARAMETER );
142         return FALSE;
143     }
144 }
145
146 static const object_vtbl_t session_vtbl =
147 {
148     session_destroy,
149     session_query_option,
150     session_set_option
151 };
152
153 /***********************************************************************
154  *          WinHttpOpen (winhttp.@)
155  */
156 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
157 {
158     session_t *session;
159     HINTERNET handle = NULL;
160
161     TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
162
163     if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
164
165     session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
166     session->hdr.vtbl = &session_vtbl;
167     session->hdr.flags = flags;
168     session->hdr.refs = 1;
169     session->access = access;
170     session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
171     list_init( &session->cookie_cache );
172
173     if (agent && !(session->agent = strdupW( agent ))) goto end;
174     if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
175     if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
176
177     if (!(handle = alloc_handle( &session->hdr ))) goto end;
178     session->hdr.handle = handle;
179
180 end:
181     release_object( &session->hdr );
182     TRACE("returning %p\n", handle);
183     return handle;
184 }
185
186 /***********************************************************************
187  *          connect_destroy (internal)
188  */
189 static void connect_destroy( object_header_t *hdr )
190 {
191     connect_t *connect = (connect_t *)hdr;
192
193     TRACE("%p\n", connect);
194
195     release_object( &connect->session->hdr );
196
197     heap_free( connect->hostname );
198     heap_free( connect->servername );
199     heap_free( connect->username );
200     heap_free( connect->password );
201     heap_free( connect );
202 }
203
204 static const object_vtbl_t connect_vtbl =
205 {
206     connect_destroy,
207     NULL,
208     NULL
209 };
210
211 /***********************************************************************
212  *          WinHttpConnect (winhttp.@)
213  */
214 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
215 {
216     connect_t *connect;
217     session_t *session;
218     HINTERNET hconnect = NULL;
219
220     TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
221
222     if (!server)
223     {
224         set_last_error( ERROR_INVALID_PARAMETER );
225         return NULL;
226     }
227     if (!(session = (session_t *)grab_object( hsession )))
228     {
229         set_last_error( ERROR_INVALID_HANDLE );
230         return NULL;
231     }
232     if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
233     {
234         release_object( &session->hdr );
235         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
236         return NULL;
237     }
238     if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
239     {
240         release_object( &session->hdr );
241         return NULL;
242     }
243     connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
244     connect->hdr.vtbl = &connect_vtbl;
245     connect->hdr.refs = 1;
246     connect->hdr.flags = session->hdr.flags;
247     connect->hdr.callback = session->hdr.callback;
248     connect->hdr.notify_mask = session->hdr.notify_mask;
249     connect->hdr.context = session->hdr.context;
250
251     addref_object( &session->hdr );
252     connect->session = session;
253     list_add_head( &session->hdr.children, &connect->hdr.entry );
254
255     if (server && !(connect->hostname = strdupW( server ))) goto end;
256     connect->hostport = port ? port : (connect->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
257
258     if (server && !(connect->servername = strdupW( server ))) goto end;
259     connect->serverport = port ? port : (connect->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80);
260
261     if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
262     connect->hdr.handle = hconnect;
263
264     send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
265
266 end:
267     release_object( &connect->hdr );
268
269     TRACE("returning %p\n", hconnect);
270     return hconnect;
271 }
272
273 /***********************************************************************
274  *          request_destroy (internal)
275  */
276 static void request_destroy( object_header_t *hdr )
277 {
278     request_t *request = (request_t *)hdr;
279     int i;
280
281     TRACE("%p\n", request);
282
283     release_object( &request->connect->hdr );
284
285     heap_free( request->verb );
286     heap_free( request->path );
287     heap_free( request->version );
288     heap_free( request->raw_headers );
289     heap_free( request->status_text );
290     for (i = 0; i < request->num_headers; i++)
291     {
292         heap_free( request->headers[i].field );
293         heap_free( request->headers[i].value );
294     }
295     heap_free( request->headers );
296     heap_free( request );
297 }
298
299 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
300 {
301     switch (option)
302     {
303     case WINHTTP_OPTION_SECURITY_FLAGS:
304     {
305         DWORD flags;
306
307         if (!buffer || *buflen < sizeof(flags))
308         {
309             *buflen = sizeof(flags);
310             set_last_error( ERROR_INSUFFICIENT_BUFFER );
311             return FALSE;
312         }
313
314         flags = 0;
315         if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
316         *(DWORD *)buffer = flags;
317         *buflen = sizeof(flags);
318         return TRUE;
319     }
320     case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
321     {
322         const CERT_CONTEXT *cert;
323         request_t *request = (request_t *)hdr;
324
325         if (!buffer || *buflen < sizeof(cert))
326         {
327             *buflen = sizeof(cert);
328             set_last_error( ERROR_INSUFFICIENT_BUFFER );
329             return FALSE;
330         }
331
332         if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
333         *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
334         *buflen = sizeof(cert);
335         return TRUE;
336     }
337     case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
338     {
339         if (!buffer || *buflen < sizeof(DWORD))
340         {
341             *buflen = sizeof(DWORD);
342             set_last_error( ERROR_INSUFFICIENT_BUFFER );
343             return FALSE;
344         }
345
346         *(DWORD *)buffer = 128; /* FIXME */
347         *buflen = sizeof(DWORD);
348         return TRUE;
349     }
350     default:
351         FIXME("unimplemented option %u\n", option);
352         set_last_error( ERROR_INVALID_PARAMETER );
353         return FALSE;
354     }
355 }
356
357 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
358 {
359     switch (option)
360     {
361     case WINHTTP_OPTION_PROXY:
362     {
363         WINHTTP_PROXY_INFO *pi = buffer;
364
365         FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
366         return TRUE;
367     }
368     case WINHTTP_OPTION_DISABLE_FEATURE:
369     {
370         DWORD disable;
371
372         if (buflen != sizeof(DWORD))
373         {
374             set_last_error( ERROR_INSUFFICIENT_BUFFER );
375             return FALSE;
376         }
377
378         disable = *(DWORD *)buffer;
379         TRACE("0x%x\n", disable);
380         hdr->disable_flags |= disable;
381         return TRUE;
382     }
383     case WINHTTP_OPTION_AUTOLOGON_POLICY:
384     {
385         DWORD policy;
386
387         if (buflen != sizeof(DWORD))
388         {
389             set_last_error( ERROR_INSUFFICIENT_BUFFER );
390             return FALSE;
391         }
392
393         policy = *(DWORD *)buffer;
394         TRACE("0x%x\n", policy);
395         hdr->logon_policy = policy;
396         return TRUE;
397     }
398     case WINHTTP_OPTION_REDIRECT_POLICY:
399     {
400         DWORD policy;
401
402         if (buflen != sizeof(DWORD))
403         {
404             set_last_error( ERROR_INSUFFICIENT_BUFFER );
405             return FALSE;
406         }
407
408         policy = *(DWORD *)buffer;
409         TRACE("0x%x\n", policy);
410         hdr->redirect_policy = policy;
411         return TRUE;
412     }
413     default:
414         FIXME("unimplemented option %u\n", option);
415         set_last_error( ERROR_INVALID_PARAMETER );
416         return TRUE;
417     }
418 }
419
420 static const object_vtbl_t request_vtbl =
421 {
422     request_destroy,
423     request_query_option,
424     request_set_option
425 };
426
427 /***********************************************************************
428  *          WinHttpOpenRequest (winhttp.@)
429  */
430 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
431                                      LPCWSTR referrer, LPCWSTR *types, DWORD flags )
432 {
433     request_t *request;
434     connect_t *connect;
435     HINTERNET hrequest = NULL;
436
437     TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
438           debugstr_w(version), debugstr_w(referrer), types, flags);
439
440     if (!(connect = (connect_t *)grab_object( hconnect )))
441     {
442         set_last_error( ERROR_INVALID_HANDLE );
443         return NULL;
444     }
445     if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
446     {
447         release_object( &connect->hdr );
448         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
449         return NULL;
450     }
451     if (!(request = heap_alloc_zero( sizeof(request_t) )))
452     {
453         release_object( &connect->hdr );
454         return NULL;
455     }
456     request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
457     request->hdr.vtbl = &request_vtbl;
458     request->hdr.refs = 1;
459     request->hdr.flags = flags;
460     request->hdr.callback = connect->hdr.callback;
461     request->hdr.notify_mask = connect->hdr.notify_mask;
462     request->hdr.context = connect->hdr.context;
463
464     addref_object( &connect->hdr );
465     request->connect = connect;
466     list_add_head( &connect->hdr.children, &request->hdr.entry );
467
468     if (!netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE )) goto end;
469
470     if (!verb || !verb[0]) verb = getW;
471     if (!object || !object[0]) object = slashW;
472     if (!version || !version[0]) version = http1_1;
473
474     if (!(request->verb = strdupW( verb ))) goto end;
475     if (!(request->path = strdupW( object ))) goto end;
476     if (!(request->version = strdupW( version ))) goto end;
477
478     if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
479     request->hdr.handle = hrequest;
480
481     send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
482
483 end:
484     release_object( &request->hdr );
485
486     TRACE("returning %p\n", hrequest);
487     return hrequest;
488 }
489
490 /***********************************************************************
491  *          WinHttpCloseHandle (winhttp.@)
492  */
493 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
494 {
495     object_header_t *hdr;
496
497     TRACE("%p\n", handle);
498
499     if (!(hdr = grab_object( handle )))
500     {
501         set_last_error( ERROR_INVALID_HANDLE );
502         return FALSE;
503     }
504     release_object( hdr );
505     free_handle( handle );
506     return TRUE;
507 }
508
509 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
510 {
511     BOOL ret = FALSE;
512
513     if (!buflen)
514     {
515         set_last_error( ERROR_INVALID_PARAMETER );
516         return FALSE;
517     }
518
519     switch (option)
520     {
521     case WINHTTP_OPTION_CONTEXT_VALUE:
522     {
523         if (!buffer || *buflen < sizeof(DWORD_PTR))
524         {
525             *buflen = sizeof(DWORD_PTR);
526             set_last_error( ERROR_INSUFFICIENT_BUFFER );
527             return FALSE;
528         }
529
530         *(DWORD_PTR *)buffer = hdr->context;
531         *buflen = sizeof(DWORD_PTR);
532         return TRUE;
533     }
534     default:
535         if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
536         else
537         {
538             FIXME("unimplemented option %u\n", option);
539             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
540             return FALSE;
541         }
542         break;
543     }
544     return ret;
545 }
546
547 /***********************************************************************
548  *          WinHttpQueryOption (winhttp.@)
549  */
550 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
551 {
552     BOOL ret = FALSE;
553     object_header_t *hdr;
554
555     TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
556
557     if (!(hdr = grab_object( handle )))
558     {
559         set_last_error( ERROR_INVALID_HANDLE );
560         return FALSE;
561     }
562
563     ret = query_option( hdr, option, buffer, buflen );
564
565     release_object( hdr );
566     return ret;
567 }
568
569 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
570 {
571     BOOL ret = TRUE;
572
573     if (!buffer)
574     {
575         set_last_error( ERROR_INVALID_PARAMETER );
576         return FALSE;
577     }
578
579     switch (option)
580     {
581     case WINHTTP_OPTION_CONTEXT_VALUE:
582     {
583         if (buflen != sizeof(DWORD_PTR))
584         {
585             set_last_error( ERROR_INSUFFICIENT_BUFFER );
586             return FALSE;
587         }
588
589         hdr->context = *(DWORD_PTR *)buffer;
590         return TRUE;
591     }
592     default:
593         if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
594         else
595         {
596             FIXME("unimplemented option %u\n", option);
597             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
598             return FALSE;
599         }
600         break;
601     }
602     return ret;
603 }
604
605 /***********************************************************************
606  *          WinHttpSetOption (winhttp.@)
607  */
608 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
609 {
610     BOOL ret = FALSE;
611     object_header_t *hdr;
612
613     TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
614
615     if (!(hdr = grab_object( handle )))
616     {
617         set_last_error( ERROR_INVALID_HANDLE );
618         return FALSE;
619     }
620
621     ret = set_option( hdr, option, buffer, buflen );
622
623     release_object( hdr );
624     return ret;
625 }
626
627 /***********************************************************************
628  *          WinHttpDetectAutoProxyConfigUrl (winhttp.@)
629  */
630 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
631 {
632     FIXME("0x%08x, %p\n", flags, url);
633
634     set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
635     return FALSE;
636 }
637
638 /***********************************************************************
639  *          WinHttpGetDefaultProxyConfiguration (winhttp.@)
640  */
641 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
642 {
643     FIXME("%p\n", info);
644
645     info->dwAccessType    = WINHTTP_ACCESS_TYPE_NO_PROXY;
646     info->lpszProxy       = NULL;
647     info->lpszProxyBypass = NULL;
648
649     return TRUE;
650 }
651
652 /***********************************************************************
653  *          WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
654  */
655 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
656 {
657     TRACE("%p\n", config);
658
659     if (!config)
660     {
661         set_last_error( ERROR_INVALID_PARAMETER );
662         return FALSE;
663     }
664
665     /* FIXME: read from HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings */
666
667     FIXME("returning no proxy used\n");
668     config->fAutoDetect       = FALSE;
669     config->lpszAutoConfigUrl = NULL;
670     config->lpszProxy         = NULL;
671     config->lpszProxyBypass   = NULL;
672
673     return TRUE;
674 }
675
676 /***********************************************************************
677  *          WinHttpGetProxyForUrl (winhttp.@)
678  */
679 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
680                                    WINHTTP_PROXY_INFO *info )
681 {
682     FIXME("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
683
684     set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
685     return FALSE;
686 }
687
688 /***********************************************************************
689  *          WinHttpSetDefaultProxyConfiguration (winhttp.@)
690  */
691 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
692 {
693     FIXME("%p [%u, %s, %s]\n", info, info->dwAccessType, debugstr_w(info->lpszProxy),
694           debugstr_w(info->lpszProxyBypass));
695     return TRUE;
696 }
697
698 /***********************************************************************
699  *          WinHttpSetStatusCallback (winhttp.@)
700  */
701 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
702                                                          DWORD flags, DWORD_PTR reserved )
703 {
704     object_header_t *hdr;
705     WINHTTP_STATUS_CALLBACK ret;
706
707     TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
708
709     if (!(hdr = grab_object( handle )))
710     {
711         set_last_error( ERROR_INVALID_HANDLE );
712         return WINHTTP_INVALID_STATUS_CALLBACK;
713     }
714     ret = hdr->callback;
715     hdr->callback = callback;
716     hdr->notify_mask = flags;
717
718     release_object( hdr );
719     return ret;
720 }
721
722 /***********************************************************************
723  *          WinHttpSetTimeouts (winhttp.@)
724  */
725 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
726 {
727     FIXME("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
728     return TRUE;
729 }
730
731 static const WCHAR wkday[7][4] =
732     {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
733      {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
734 static const WCHAR month[12][4] =
735     {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
736      {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
737      {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
738
739 /***********************************************************************
740  *           WinHttpTimeFromSystemTime (WININET.@)
741  */
742 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
743 {
744     static const WCHAR format[] =
745         {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
746          '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
747
748     TRACE("%p, %p\n", time, string);
749
750     if (!time || !string) return FALSE;
751
752     sprintfW( string, format,
753               wkday[time->wDayOfWeek],
754               time->wDay,
755               month[time->wMonth - 1],
756               time->wYear,
757               time->wHour,
758               time->wMinute,
759               time->wSecond );
760
761     return TRUE;
762 }
763
764 /***********************************************************************
765  *           WinHttpTimeToSystemTime (WININET.@)
766  */
767 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
768 {
769     unsigned int i;
770     const WCHAR *s = string;
771     WCHAR *end;
772
773     TRACE("%s, %p\n", debugstr_w(string), time);
774
775     if (!string || !time) return FALSE;
776
777     /* Windows does this too */
778     GetSystemTime( time );
779
780     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
781      *  a SYSTEMTIME structure.
782      */
783
784     while (*s && !isalphaW( *s )) s++;
785     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
786     time->wDayOfWeek = 7;
787
788     for (i = 0; i < 7; i++)
789     {
790         if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
791             toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
792             toupperW( wkday[i][2] ) == toupperW( s[2] ) )
793         {
794             time->wDayOfWeek = i;
795             break;
796         }
797     }
798
799     if (time->wDayOfWeek > 6) return TRUE;
800     while (*s && !isdigitW( *s )) s++;
801     time->wDay = strtolW( s, &end, 10 );
802     s = end;
803
804     while (*s && !isalphaW( *s )) s++;
805     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
806     time->wMonth = 0;
807
808     for (i = 0; i < 12; i++)
809     {
810         if (toupperW( month[i][0]) == toupperW( s[0] ) &&
811             toupperW( month[i][1]) == toupperW( s[1] ) &&
812             toupperW( month[i][2]) == toupperW( s[2] ) )
813         {
814             time->wMonth = i + 1;
815             break;
816         }
817     }
818     if (time->wMonth == 0) return TRUE;
819
820     while (*s && !isdigitW( *s )) s++;
821     if (*s == '\0') return TRUE;
822     time->wYear = strtolW( s, &end, 10 );
823     s = end;
824
825     while (*s && !isdigitW( *s )) s++;
826     if (*s == '\0') return TRUE;
827     time->wHour = strtolW( s, &end, 10 );
828     s = end;
829
830     while (*s && !isdigitW( *s )) s++;
831     if (*s == '\0') return TRUE;
832     time->wMinute = strtolW( s, &end, 10 );
833     s = end;
834
835     while (*s && !isdigitW( *s )) s++;
836     if (*s == '\0') return TRUE;
837     time->wSecond = strtolW( s, &end, 10 );
838     s = end;
839
840     time->wMilliseconds = 0;
841     return TRUE;
842 }