winhttp: Add tests for WinHttpSetDefaultProxyConfiguration.
[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->callback && (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;
257
258     if (server && !(connect->servername = strdupW( server ))) goto end;
259     connect->serverport = port;
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     DWORD 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 (!(request->verb = strdupW( verb ))) goto end;
472
473     if (object)
474     {
475         WCHAR *path, *p;
476         unsigned int len;
477
478         len = strlenW( object ) + 1;
479         if (object[0] != '/') len++;
480         if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
481
482         if (object[0] != '/') *p++ = '/';
483         strcpyW( p, object );
484         request->path = path;
485     }
486     else if (!(request->path = strdupW( slashW ))) goto end;
487
488     if (!version || !version[0]) version = http1_1;
489     if (!(request->version = strdupW( version ))) goto end;
490
491     if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
492     request->hdr.handle = hrequest;
493
494     send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
495
496 end:
497     release_object( &request->hdr );
498
499     TRACE("returning %p\n", hrequest);
500     return hrequest;
501 }
502
503 /***********************************************************************
504  *          WinHttpCloseHandle (winhttp.@)
505  */
506 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
507 {
508     object_header_t *hdr;
509
510     TRACE("%p\n", handle);
511
512     if (!(hdr = grab_object( handle )))
513     {
514         set_last_error( ERROR_INVALID_HANDLE );
515         return FALSE;
516     }
517     release_object( hdr );
518     free_handle( handle );
519     return TRUE;
520 }
521
522 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
523 {
524     BOOL ret = FALSE;
525
526     if (!buflen)
527     {
528         set_last_error( ERROR_INVALID_PARAMETER );
529         return FALSE;
530     }
531
532     switch (option)
533     {
534     case WINHTTP_OPTION_CONTEXT_VALUE:
535     {
536         if (!buffer || *buflen < sizeof(DWORD_PTR))
537         {
538             *buflen = sizeof(DWORD_PTR);
539             set_last_error( ERROR_INSUFFICIENT_BUFFER );
540             return FALSE;
541         }
542
543         *(DWORD_PTR *)buffer = hdr->context;
544         *buflen = sizeof(DWORD_PTR);
545         return TRUE;
546     }
547     default:
548         if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
549         else
550         {
551             FIXME("unimplemented option %u\n", option);
552             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
553             return FALSE;
554         }
555         break;
556     }
557     return ret;
558 }
559
560 /***********************************************************************
561  *          WinHttpQueryOption (winhttp.@)
562  */
563 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
564 {
565     BOOL ret = FALSE;
566     object_header_t *hdr;
567
568     TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
569
570     if (!(hdr = grab_object( handle )))
571     {
572         set_last_error( ERROR_INVALID_HANDLE );
573         return FALSE;
574     }
575
576     ret = query_option( hdr, option, buffer, buflen );
577
578     release_object( hdr );
579     return ret;
580 }
581
582 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
583 {
584     BOOL ret = TRUE;
585
586     if (!buffer)
587     {
588         set_last_error( ERROR_INVALID_PARAMETER );
589         return FALSE;
590     }
591
592     switch (option)
593     {
594     case WINHTTP_OPTION_CONTEXT_VALUE:
595     {
596         if (buflen != sizeof(DWORD_PTR))
597         {
598             set_last_error( ERROR_INSUFFICIENT_BUFFER );
599             return FALSE;
600         }
601
602         hdr->context = *(DWORD_PTR *)buffer;
603         return TRUE;
604     }
605     default:
606         if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
607         else
608         {
609             FIXME("unimplemented option %u\n", option);
610             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
611             return FALSE;
612         }
613         break;
614     }
615     return ret;
616 }
617
618 /***********************************************************************
619  *          WinHttpSetOption (winhttp.@)
620  */
621 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
622 {
623     BOOL ret = FALSE;
624     object_header_t *hdr;
625
626     TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
627
628     if (!(hdr = grab_object( handle )))
629     {
630         set_last_error( ERROR_INVALID_HANDLE );
631         return FALSE;
632     }
633
634     ret = set_option( hdr, option, buffer, buflen );
635
636     release_object( hdr );
637     return ret;
638 }
639
640 /***********************************************************************
641  *          WinHttpDetectAutoProxyConfigUrl (winhttp.@)
642  */
643 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
644 {
645     FIXME("0x%08x, %p\n", flags, url);
646
647     set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
648     return FALSE;
649 }
650
651 /***********************************************************************
652  *          WinHttpGetDefaultProxyConfiguration (winhttp.@)
653  */
654 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
655 {
656     FIXME("%p\n", info);
657
658     info->dwAccessType    = WINHTTP_ACCESS_TYPE_NO_PROXY;
659     info->lpszProxy       = NULL;
660     info->lpszProxyBypass = NULL;
661
662     return TRUE;
663 }
664
665 /***********************************************************************
666  *          WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
667  */
668 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
669 {
670     TRACE("%p\n", config);
671
672     if (!config)
673     {
674         set_last_error( ERROR_INVALID_PARAMETER );
675         return FALSE;
676     }
677
678     /* FIXME: read from HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings */
679
680     FIXME("returning no proxy used\n");
681     config->fAutoDetect       = FALSE;
682     config->lpszAutoConfigUrl = NULL;
683     config->lpszProxy         = NULL;
684     config->lpszProxyBypass   = NULL;
685
686     return TRUE;
687 }
688
689 /***********************************************************************
690  *          WinHttpGetProxyForUrl (winhttp.@)
691  */
692 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
693                                    WINHTTP_PROXY_INFO *info )
694 {
695     FIXME("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
696
697     set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
698     return FALSE;
699 }
700
701 /***********************************************************************
702  *          WinHttpSetDefaultProxyConfiguration (winhttp.@)
703  */
704 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
705 {
706     FIXME("%p\n", info);
707     return TRUE;
708 }
709
710 /***********************************************************************
711  *          WinHttpSetStatusCallback (winhttp.@)
712  */
713 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
714                                                          DWORD flags, DWORD_PTR reserved )
715 {
716     object_header_t *hdr;
717     WINHTTP_STATUS_CALLBACK ret;
718
719     TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
720
721     if (!(hdr = grab_object( handle )))
722     {
723         set_last_error( ERROR_INVALID_HANDLE );
724         return WINHTTP_INVALID_STATUS_CALLBACK;
725     }
726     ret = hdr->callback;
727     hdr->callback = callback;
728     hdr->notify_mask = flags;
729
730     release_object( hdr );
731     return ret;
732 }
733
734 /***********************************************************************
735  *          WinHttpSetTimeouts (winhttp.@)
736  */
737 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
738 {
739     BOOL ret = TRUE;
740     request_t *request;
741
742     TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
743
744     if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
745     {
746         set_last_error( ERROR_INVALID_PARAMETER );
747         return FALSE;
748     }
749
750     FIXME("resolve and connect timeout not supported\n");
751
752     if (!(request = (request_t *)grab_object( handle )))
753     {
754         set_last_error( ERROR_INVALID_HANDLE );
755         return FALSE;
756     }
757
758     if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
759     {
760         release_object( &request->hdr );
761         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
762         return FALSE;
763     }
764
765     if (send < 0) send = 0;
766     if (netconn_set_timeout( &request->netconn, TRUE, send )) ret = FALSE;
767
768     if (receive < 0) receive = 0;
769     if (netconn_set_timeout( &request->netconn, FALSE, receive )) ret = FALSE;
770
771     release_object( &request->hdr );
772     return ret;
773 }
774
775 static const WCHAR wkday[7][4] =
776     {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
777      {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
778 static const WCHAR month[12][4] =
779     {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
780      {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
781      {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
782
783 /***********************************************************************
784  *           WinHttpTimeFromSystemTime (WININET.@)
785  */
786 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
787 {
788     static const WCHAR format[] =
789         {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
790          '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
791
792     TRACE("%p, %p\n", time, string);
793
794     if (!time || !string) return FALSE;
795
796     sprintfW( string, format,
797               wkday[time->wDayOfWeek],
798               time->wDay,
799               month[time->wMonth - 1],
800               time->wYear,
801               time->wHour,
802               time->wMinute,
803               time->wSecond );
804
805     return TRUE;
806 }
807
808 /***********************************************************************
809  *           WinHttpTimeToSystemTime (WININET.@)
810  */
811 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
812 {
813     unsigned int i;
814     const WCHAR *s = string;
815     WCHAR *end;
816
817     TRACE("%s, %p\n", debugstr_w(string), time);
818
819     if (!string || !time) return FALSE;
820
821     /* Windows does this too */
822     GetSystemTime( time );
823
824     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
825      *  a SYSTEMTIME structure.
826      */
827
828     while (*s && !isalphaW( *s )) s++;
829     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
830     time->wDayOfWeek = 7;
831
832     for (i = 0; i < 7; i++)
833     {
834         if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
835             toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
836             toupperW( wkday[i][2] ) == toupperW( s[2] ) )
837         {
838             time->wDayOfWeek = i;
839             break;
840         }
841     }
842
843     if (time->wDayOfWeek > 6) return TRUE;
844     while (*s && !isdigitW( *s )) s++;
845     time->wDay = strtolW( s, &end, 10 );
846     s = end;
847
848     while (*s && !isalphaW( *s )) s++;
849     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
850     time->wMonth = 0;
851
852     for (i = 0; i < 12; i++)
853     {
854         if (toupperW( month[i][0]) == toupperW( s[0] ) &&
855             toupperW( month[i][1]) == toupperW( s[1] ) &&
856             toupperW( month[i][2]) == toupperW( s[2] ) )
857         {
858             time->wMonth = i + 1;
859             break;
860         }
861     }
862     if (time->wMonth == 0) return TRUE;
863
864     while (*s && !isdigitW( *s )) s++;
865     if (*s == '\0') return TRUE;
866     time->wYear = strtolW( s, &end, 10 );
867     s = end;
868
869     while (*s && !isdigitW( *s )) s++;
870     if (*s == '\0') return TRUE;
871     time->wHour = strtolW( s, &end, 10 );
872     s = end;
873
874     while (*s && !isdigitW( *s )) s++;
875     if (*s == '\0') return TRUE;
876     time->wMinute = strtolW( s, &end, 10 );
877     s = end;
878
879     while (*s && !isdigitW( *s )) s++;
880     if (*s == '\0') return TRUE;
881     time->wSecond = strtolW( s, &end, 10 );
882     s = end;
883
884     time->wMilliseconds = 0;
885     return TRUE;
886 }