ReactOS 0.4.16-dev-311-g9382aa2
http.c
Go to the documentation of this file.
1#ifdef __REACTOS__
2#include "precomp.h"
3#include "zlib.h"
4#else/*
5 * Wininet - HTTP Implementation
6 *
7 * Copyright 1999 Corel Corporation
8 * Copyright 2002 CodeWeavers Inc.
9 * Copyright 2002 TransGaming Technologies Inc.
10 * Copyright 2004 Mike McCormack for CodeWeavers
11 * Copyright 2005 Aric Stewart for CodeWeavers
12 * Copyright 2006 Robert Shearman for CodeWeavers
13 * Copyright 2011 Jacek Caban for CodeWeavers
14 *
15 * Ulrich Czekalla
16 * David Hammerton
17 *
18 * This library is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU Lesser General Public
20 * License as published by the Free Software Foundation; either
21 * version 2.1 of the License, or (at your option) any later version.
22 *
23 * This library is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * Lesser General Public License for more details.
27 *
28 * You should have received a copy of the GNU Lesser General Public
29 * License along with this library; if not, write to the Free Software
30 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 */
32
33#include <stdlib.h>
34
35#include "winsock2.h"
36#include "ws2ipdef.h"
37
38#include <stdarg.h>
39#include <stdio.h>
40#include <time.h>
41#include <assert.h>
42#include <errno.h>
43#include <limits.h>
44
45#include "windef.h"
46#include "winbase.h"
47#include "wininet.h"
48#include "winerror.h"
49#include "winternl.h"
50#define NO_SHLWAPI_STREAM
51#define NO_SHLWAPI_REG
52#define NO_SHLWAPI_GDI
53#include "shlwapi.h"
54#include "sspi.h"
55#include "wincrypt.h"
56#include "winuser.h"
57
58#include "internet.h"
59#include "zlib.h"
60#include "resource.h"
61#include "wine/debug.h"
62#include "wine/exception.h"
63#endif /* defined(__REACTOS__) */
64
66
67#define HTTP_ADDHDR_FLAG_ADD 0x20000000
68#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
69#define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
70#define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
71#define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
72#define HTTP_ADDHDR_FLAG_REQ 0x02000000
73
74#define COLLECT_TIME 60000
75
77{
84 void *auth_data;
85 unsigned int auth_data_len;
86 BOOL finished; /* finished authenticating */
87};
88
89
91{
92 struct list entry;
93
99
100typedef struct _authorizationData
101{
102 struct list entry;
103
113
116
119{
120 0, 0, &authcache_cs,
122 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
123};
124static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
125
132static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
134static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
136
139{
140 0, 0, &connection_pool_cs,
142 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") }
143};
144static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 };
145
148
150{
152}
153
155{
157 return;
158
159#ifdef __REACTOS__
161#endif
162 list_remove(&server->entry);
163#ifdef __REACTOS__
165#endif
166
167 if(server->cert_chain)
168 CertFreeCertificateChain(server->cert_chain);
169 heap_free(server->name);
170 heap_free(server->scheme_host_port);
172}
173
175{
176 BOOL default_port;
177 size_t name_len, len;
178 WCHAR *buf;
179
180 name_len = lstrlenW(server->name);
181 len = name_len + 10 /* strlen("://:<port>") */ + ARRAY_SIZE(L"https");
182 buf = heap_alloc( len * sizeof(WCHAR) );
183 if(!buf)
184 return FALSE;
185
186 swprintf(buf, len, L"%s://%s:%u", server->is_https ? L"https" : L"http", server->name, server->port);
187 server->scheme_host_port = buf;
188
189 server->host_port = server->scheme_host_port + 7 /* strlen("http://") */;
190 if(server->is_https)
191 server->host_port++;
192
193 default_port = server->port == (server->is_https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT);
194 server->canon_host_port = default_port ? server->name : server->host_port;
195 return TRUE;
196}
197
199{
200 server_t *iter, *server = NULL;
201
203
205 if(iter->port == port && name.len == lstrlenW(iter->name) && !wcsnicmp(iter->name, name.str, name.len)
206 && iter->is_https == is_https) {
207 server = iter;
209 break;
210 }
211 }
212
213 if(!server && do_create) {
214 server = heap_alloc_zero(sizeof(*server));
215 if(server) {
216 server->ref = 2; /* list reference and return */
217 server->port = port;
218 server->is_https = is_https;
219 list_init(&server->conn_pool);
220 server->name = heap_strndupW(name.str, name.len);
221 if(server->name && process_host_port(server)) {
223 }else {
225 server = NULL;
226 }
227 }
228 }
229
231
232 return server;
233}
234
236{
237 netconn_t *netconn, *netconn_safe;
238 server_t *server, *server_safe;
239 BOOL remaining = FALSE;
240 DWORD64 now;
241
242#ifdef __REACTOS__
243 now = GetTickCount();
244#else
246#endif
247
249 LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) {
250 if(collect_type > COLLECT_TIMEOUT || netconn->keep_until < now) {
251 TRACE("freeing %p\n", netconn);
252 list_remove(&netconn->pool_entry);
254 }else {
255 remaining = TRUE;
256 }
257 }
258
259 if(collect_type == COLLECT_CLEANUP) {
260 list_remove(&server->entry);
261 list_init(&server->entry);
263 }
264 }
265
266 return remaining;
267}
268
270{
271 BOOL remaining_conns;
272
273 do {
274 /* FIXME: Use more sophisticated method */
275 Sleep(5000);
276
278
279 remaining_conns = collect_connections(COLLECT_TIMEOUT);
280 if(!remaining_conns)
282
284 }while(remaining_conns);
285
287}
288
289/***********************************************************************
290 * HTTP_GetHeader (internal)
291 *
292 * Headers section must be held
293 */
295{
296 int HeaderIndex = 0;
297 HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
298 if (HeaderIndex == -1)
299 return NULL;
300 else
301 return &req->custHeaders[HeaderIndex];
302}
303
305{
307 WCHAR *ret = NULL;
308
310 if ((header = HTTP_GetHeader( req, L"Host" ))) ret = heap_strdupW( header->lpszValue );
311 else ret = heap_strdupW( req->server->canon_host_port );
313 return ret;
314}
315
321};
322
323typedef struct {
325
330
331 enum {
338 CHUNKED_STREAM_STATE_ERROR
341
343{
344 stream->vtbl->destroy(stream);
345}
346
348{
351 req->read_pos = req->read_size = req->netconn_stream.content_read = 0;
352 req->read_gzip = FALSE;
353}
354
355static void remove_header( http_request_t *request, const WCHAR *str, BOOL from_request )
356{
357 int index;
358 EnterCriticalSection( &request->headers_section );
359 index = HTTP_GetCustomHeaderIndex( request, str, 0, from_request );
361 LeaveCriticalSection( &request->headers_section );
362}
363
364typedef struct {
373
375{
376 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
377 return gzip_stream->end_of_data
378 || (!gzip_stream->buf_size && gzip_stream->parent_stream->vtbl->end_of_data(gzip_stream->parent_stream, req));
379}
380
382 DWORD *read, BOOL allow_blocking)
383{
384 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
385 z_stream *zstream = &gzip_stream->zstream;
386 DWORD current_read, ret_read = 0;
387 int zres;
389
390 TRACE("(%d %x)\n", size, allow_blocking);
391
392 while(size && !gzip_stream->end_of_data) {
393 if(!gzip_stream->buf_size) {
394 if(gzip_stream->buf_pos) {
395 if(gzip_stream->buf_size)
396 memmove(gzip_stream->buf, gzip_stream->buf+gzip_stream->buf_pos, gzip_stream->buf_size);
397 gzip_stream->buf_pos = 0;
398 }
399 res = gzip_stream->parent_stream->vtbl->read(gzip_stream->parent_stream, req, gzip_stream->buf+gzip_stream->buf_size,
400 sizeof(gzip_stream->buf)-gzip_stream->buf_size, &current_read, allow_blocking);
401 if(res != ERROR_SUCCESS)
402 break;
403
404 gzip_stream->buf_size += current_read;
405 if(!current_read) {
406 WARN("unexpected end of data\n");
407 gzip_stream->end_of_data = TRUE;
408 break;
409 }
410 }
411
412 zstream->next_in = gzip_stream->buf+gzip_stream->buf_pos;
413 zstream->avail_in = gzip_stream->buf_size;
414 zstream->next_out = buf+ret_read;
415 zstream->avail_out = size;
416 zres = inflate(&gzip_stream->zstream, 0);
417 current_read = size - zstream->avail_out;
418 size -= current_read;
419 ret_read += current_read;
420 gzip_stream->buf_size -= zstream->next_in - (gzip_stream->buf+gzip_stream->buf_pos);
421 gzip_stream->buf_pos = zstream->next_in-gzip_stream->buf;
422 if(zres == Z_STREAM_END) {
423 TRACE("end of data\n");
424 gzip_stream->end_of_data = TRUE;
425 inflateEnd(zstream);
426 }else if(zres != Z_OK) {
427 WARN("inflate failed %d: %s\n", zres, debugstr_a(zstream->msg));
428 if(!ret_read)
430 break;
431 }
432
433 if(ret_read)
434 allow_blocking = FALSE;
435 }
436
437 TRACE("read %u bytes\n", ret_read);
438 if(ret_read)
440 *read = ret_read;
441 return res;
442}
443
445{
446 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
447 return gzip_stream->parent_stream->vtbl->drain_content(gzip_stream->parent_stream, req, allow_blocking);
448}
449
451{
452 gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
453
455
456 if(!gzip_stream->end_of_data)
457 inflateEnd(&gzip_stream->zstream);
458 heap_free(gzip_stream);
459}
460
463 gzip_read,
466};
467
469{
470 return heap_alloc(items*size);
471}
472
473static void wininet_zfree(voidpf opaque, voidpf address)
474{
476}
477
479{
480 gzip_stream_t *gzip_stream;
481 int zres;
482
483 gzip_stream = heap_alloc_zero(sizeof(gzip_stream_t));
484 if(!gzip_stream)
485 return ERROR_OUTOFMEMORY;
486
487 gzip_stream->stream.vtbl = &gzip_stream_vtbl;
488 gzip_stream->zstream.zalloc = wininet_zalloc;
489 gzip_stream->zstream.zfree = wininet_zfree;
490
491 zres = inflateInit2(&gzip_stream->zstream, is_gzip ? 0x1f : -15);
492 if(zres != Z_OK) {
493 ERR("inflateInit failed: %d\n", zres);
494 heap_free(gzip_stream);
495 return ERROR_OUTOFMEMORY;
496 }
497
498 remove_header(req, L"Content-Length", FALSE);
499
500 if(req->read_size) {
501 memcpy(gzip_stream->buf, req->read_buf+req->read_pos, req->read_size);
502 gzip_stream->buf_size = req->read_size;
503 req->read_pos = req->read_size = 0;
504 }
505
506 req->read_gzip = TRUE;
507 gzip_stream->parent_stream = req->data_stream;
508 req->data_stream = &gzip_stream->stream;
509 return ERROR_SUCCESS;
510}
511
512/***********************************************************************
513 * HTTP_FreeTokens (internal)
514 *
515 * Frees table of pointers.
516 */
517static void HTTP_FreeTokens(LPWSTR * token_array)
518{
519 int i;
520 for (i = 0; token_array[i]; i++) heap_free(token_array[i]);
521 heap_free(token_array);
522}
523
525{
526 /* If we don't have a path we set it to root */
527 if (NULL == request->path)
528 request->path = heap_strdupW(L"/");
529 else /* remove \r and \n*/
530 {
531 int nLen = lstrlenW(request->path);
532 while ((nLen >0 ) && ((request->path[nLen-1] == '\r')||(request->path[nLen-1] == '\n')))
533 {
534 nLen--;
535 request->path[nLen]='\0';
536 }
537 /* Replace '\' with '/' */
538 while (nLen>0) {
539 nLen--;
540 if (request->path[nLen] == '\\') request->path[nLen]='/';
541 }
542 }
543
545 request->path, lstrlenW(request->path), L"http://", lstrlenW(L"http://") )
546 && request->path[0] != '/') /* not an absolute path ?? --> fix it !! */
547 {
548 WCHAR *fixurl = heap_alloc((lstrlenW(request->path) + 2)*sizeof(WCHAR));
549 *fixurl = '/';
550 lstrcpyW(fixurl + 1, request->path);
552 request->path = fixurl;
553 }
554}
555
557 const WCHAR *path, const WCHAR *version, BOOL use_cr)
558{
559 LPWSTR requestString;
560 DWORD len, n;
561 LPCWSTR *req;
562 UINT i;
563
564 EnterCriticalSection( &request->headers_section );
565
566 /* allocate space for an array of all the string pointers to be added */
567 len = request->nCustHeaders * 5 + 10;
568 if (!(req = heap_alloc( len * sizeof(const WCHAR *) )))
569 {
570 LeaveCriticalSection( &request->headers_section );
571 return NULL;
572 }
573
574 /* add the verb, path and HTTP version string */
575 n = 0;
576 req[n++] = verb;
577 req[n++] = L" ";
578 req[n++] = path;
579 req[n++] = L" ";
580 req[n++] = version;
581 if (use_cr)
582 req[n++] = L"\r";
583 req[n++] = L"\n";
584
585 /* Append custom request headers */
586 for (i = 0; i < request->nCustHeaders; i++)
587 {
588 if (request->custHeaders[i].wFlags & HDR_ISREQUEST)
589 {
590 req[n++] = request->custHeaders[i].lpszField;
591 req[n++] = L": ";
592 req[n++] = request->custHeaders[i].lpszValue;
593 if (use_cr)
594 req[n++] = L"\r";
595 req[n++] = L"\n";
596
597 TRACE("Adding custom header %s (%s)\n",
598 debugstr_w(request->custHeaders[i].lpszField),
599 debugstr_w(request->custHeaders[i].lpszValue));
600 }
601 }
602 if (use_cr)
603 req[n++] = L"\r";
604 req[n++] = L"\n";
605 req[n] = NULL;
606
607 requestString = HTTP_build_req( req, 4 );
608 heap_free( req );
609 LeaveCriticalSection( &request->headers_section );
610 return requestString;
611}
612
614{
615 const WCHAR **req;
616 WCHAR *ret, buf[14];
617 DWORD i, n = 0;
618
619 EnterCriticalSection( &request->headers_section );
620
621 if (!(req = heap_alloc( (request->nCustHeaders * 5 + 8) * sizeof(WCHAR *) )))
622 {
623 LeaveCriticalSection( &request->headers_section );
624 return NULL;
625 }
626
627 if (request->status_code)
628 {
629 req[n++] = request->version;
630 swprintf(buf, ARRAY_SIZE(buf), L" %u ", request->status_code);
631 req[n++] = buf;
632 req[n++] = request->statusText;
633 if (use_cr)
634 req[n++] = L"\r";
635 req[n++] = L"\n";
636 }
637
638 for(i = 0; i < request->nCustHeaders; i++)
639 {
640 if(!(request->custHeaders[i].wFlags & HDR_ISREQUEST)
641 && wcscmp(request->custHeaders[i].lpszField, L"Status"))
642 {
643 req[n++] = request->custHeaders[i].lpszField;
644 req[n++] = L": ";
645 req[n++] = request->custHeaders[i].lpszValue;
646 if(use_cr)
647 req[n++] = L"\r";
648 req[n++] = L"\n";
649
650 TRACE("Adding custom header %s (%s)\n",
651 debugstr_w(request->custHeaders[i].lpszField),
652 debugstr_w(request->custHeaders[i].lpszValue));
653 }
654 }
655 if(use_cr)
656 req[n++] = L"\r";
657 req[n++] = L"\n";
658 req[n] = NULL;
659
660 ret = HTTP_build_req(req, 0);
661 heap_free(req);
662 LeaveCriticalSection( &request->headers_section );
663 return ret;
664}
665
667{
668 int HeaderIndex;
669 int numCookies = 0;
670 LPHTTPHEADERW setCookieHeader;
671 WCHAR *path, *tmp;
672
674 return;
675
677 if (!path)
678 return;
679
680 tmp = wcsrchr(path, '/');
681 if (tmp && tmp[1]) tmp[1] = 0;
682
683 EnterCriticalSection( &request->headers_section );
684
685 while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, L"Set-Cookie", numCookies++, FALSE)) != -1)
686 {
687 const WCHAR *data;
689
690 setCookieHeader = &request->custHeaders[HeaderIndex];
691
692 if (!setCookieHeader->lpszValue)
693 continue;
694
695 data = wcschr(setCookieHeader->lpszValue, '=');
696 if(!data)
697 continue;
698
699 name = substr(setCookieHeader->lpszValue, data - setCookieHeader->lpszValue);
700 data++;
702 }
703
704 LeaveCriticalSection( &request->headers_section );
706}
707
709{
710 LPWSTR str = start;
711 LPWSTR end;
712
713 while (*str == ' ')
714 str++;
715
716 if (str != start)
717 memmove(start, str, sizeof(WCHAR) * (lstrlenW(str) + 1));
718
719 end = start + lstrlenW(start) - 1;
720 while (end >= start && *end == ' ')
721 {
722 *end = '\0';
723 end--;
724 }
725}
726
727static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
728{
729 static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
730 static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */
731 BOOL is_basic;
732 is_basic = !wcsnicmp(pszAuthValue, szBasic, ARRAY_SIZE(szBasic)) &&
733 ((pszAuthValue[ARRAY_SIZE(szBasic)] == ' ') || !pszAuthValue[ARRAY_SIZE(szBasic)]);
734 if (is_basic && pszRealm)
735 {
737 LPCWSTR ptr = &pszAuthValue[ARRAY_SIZE(szBasic)];
738 LPCWSTR realm;
739 ptr++;
740 *pszRealm=NULL;
741 token = wcschr(ptr,'=');
742 if (!token)
743 return TRUE;
744 realm = ptr;
745 while (*realm == ' ')
746 realm++;
747 if(!wcsnicmp(realm, szRealm, ARRAY_SIZE(szRealm)) &&
748 (realm[ARRAY_SIZE(szRealm)] == ' ' || realm[ARRAY_SIZE(szRealm)] == '='))
749 {
750 token++;
751 while (*token == ' ')
752 token++;
753 if (*token == '\0')
754 return TRUE;
755 *pszRealm = heap_strdupW(token);
756 strip_spaces(*pszRealm);
757 }
758 }
759
760 return is_basic;
761}
762
764{
765 if (!authinfo) return;
766
771
772 heap_free(authinfo->auth_data);
775}
776
777static UINT retrieve_cached_basic_authorization(http_request_t *req, const WCHAR *host, const WCHAR *realm, char **auth_data)
778{
780 UINT rc = 0;
781
782 TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm));
783
786 {
787 if (!wcsicmp(host, ad->host) && (!realm || !wcscmp(realm, ad->realm)))
788 {
789 char *colon;
791
792 TRACE("Authorization found in cache\n");
793 *auth_data = heap_alloc(ad->authorizationLen);
794 memcpy(*auth_data,ad->authorization,ad->authorizationLen);
795 rc = ad->authorizationLen;
796
797 /* update session username and password to reflect current credentials */
798 colon = strchr(ad->authorization, ':');
799 length = colon - ad->authorization;
800
803
805 length++;
807 break;
808 }
809 }
811 return rc;
812}
813
814static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len)
815{
816 struct list *cursor;
818
819 TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
820
823 {
825 if (!wcsicmp(host,check->host) && !wcscmp(realm,check->realm))
826 {
827 ad = check;
828 break;
829 }
830 }
831
832 if (ad)
833 {
834 TRACE("Found match in cache, replacing\n");
836 ad->authorization = heap_alloc(auth_data_len);
837 memcpy(ad->authorization, auth_data, auth_data_len);
838 ad->authorizationLen = auth_data_len;
839 }
840 else
841 {
843 ad->host = heap_strdupW(host);
844 ad->realm = heap_strdupW(realm);
845 ad->authorization = heap_alloc(auth_data_len);
846 memcpy(ad->authorization, auth_data, auth_data_len);
847 ad->authorizationLen = auth_data_len;
849 TRACE("authorization cached\n");
850 }
852}
853
855 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
856{
858
859 TRACE("Looking for authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
860
863 if(!wcsicmp(host, ad->host) && !wcsicmp(scheme, ad->scheme)) {
864 TRACE("Authorization found in cache\n");
865
866 nt_auth_identity->User = heap_strdupW(ad->user);
867 nt_auth_identity->Password = heap_strdupW(ad->password);
868 nt_auth_identity->Domain = heap_alloc(sizeof(WCHAR)*ad->domain_len);
869 if(!nt_auth_identity->User || !nt_auth_identity->Password ||
870 (!nt_auth_identity->Domain && ad->domain_len)) {
871 heap_free(nt_auth_identity->User);
872 heap_free(nt_auth_identity->Password);
873 heap_free(nt_auth_identity->Domain);
874 break;
875 }
876
877 nt_auth_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
878 nt_auth_identity->UserLength = ad->user_len;
879 nt_auth_identity->PasswordLength = ad->password_len;
880 memcpy(nt_auth_identity->Domain, ad->domain, sizeof(WCHAR)*ad->domain_len);
881 nt_auth_identity->DomainLength = ad->domain_len;
883 return TRUE;
884 }
885 }
887
888 return FALSE;
889}
890
892 SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
893{
895 BOOL found = FALSE;
896
897 TRACE("Caching authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
898
901 if(!wcsicmp(host, ad->host) && !wcsicmp(scheme, ad->scheme)) {
902 found = TRUE;
903 break;
904 }
905
906 if(found) {
907 heap_free(ad->user);
908 heap_free(ad->password);
909 heap_free(ad->domain);
910 } else {
911 ad = heap_alloc(sizeof(authorizationData));
912 if(!ad) {
914 return;
915 }
916
917 ad->host = heap_strdupW(host);
920 }
921
922 ad->user = heap_strndupW(nt_auth_identity->User, nt_auth_identity->UserLength);
923 ad->password = heap_strndupW(nt_auth_identity->Password, nt_auth_identity->PasswordLength);
924 ad->domain = heap_strndupW(nt_auth_identity->Domain, nt_auth_identity->DomainLength);
925 ad->user_len = nt_auth_identity->UserLength;
926 ad->password_len = nt_auth_identity->PasswordLength;
927 ad->domain_len = nt_auth_identity->DomainLength;
928
929 if(!ad->host || !ad->scheme || !ad->user || !ad->password
930 || (nt_auth_identity->Domain && !ad->domain)) {
931 heap_free(ad->host);
932 heap_free(ad->scheme);
933 heap_free(ad->user);
934 heap_free(ad->password);
935 heap_free(ad->domain);
936 list_remove(&ad->entry);
937 heap_free(ad);
938 }
939
941}
942
944{
945 authorizationData *ad, *sa_safe;
946 basicAuthorizationData *basic, *basic_safe;
947
949
951 {
952 heap_free(basic->host);
953 heap_free(basic->realm);
954 heap_free(basic->authorization);
955
956 list_remove(&basic->entry);
957 heap_free(basic);
958 }
959
961 {
962 heap_free(ad->host);
963 heap_free(ad->scheme);
964 heap_free(ad->user);
965 heap_free(ad->password);
966 heap_free(ad->domain);
967 list_remove(&ad->entry);
968 heap_free(ad);
969 }
970
972}
973
975 struct HttpAuthInfo **ppAuthInfo,
976 LPWSTR domain_and_username, LPWSTR password,
977 LPWSTR host )
978{
979 SECURITY_STATUS sec_status;
980 struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
981 BOOL first = FALSE;
982 LPWSTR szRealm = NULL;
983
984 TRACE("%s\n", debugstr_w(pszAuthValue));
985
986 if (!pAuthInfo)
987 {
989
990 first = TRUE;
991 pAuthInfo = heap_alloc(sizeof(*pAuthInfo));
992 if (!pAuthInfo)
993 return FALSE;
994
995 SecInvalidateHandle(&pAuthInfo->cred);
996 SecInvalidateHandle(&pAuthInfo->ctx);
997 memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
998 pAuthInfo->attr = 0;
999 pAuthInfo->auth_data = NULL;
1000 pAuthInfo->auth_data_len = 0;
1001 pAuthInfo->finished = FALSE;
1002
1003 if (is_basic_auth_value(pszAuthValue,NULL))
1004 {
1005 pAuthInfo->scheme = heap_strdupW(L"Basic");
1006 if (!pAuthInfo->scheme)
1007 {
1008 heap_free(pAuthInfo);
1009 return FALSE;
1010 }
1011 }
1012 else
1013 {
1014 PVOID pAuthData;
1015 SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
1016
1017 pAuthInfo->scheme = heap_strdupW(pszAuthValue);
1018 if (!pAuthInfo->scheme)
1019 {
1020 heap_free(pAuthInfo);
1021 return FALSE;
1022 }
1023
1024 if (domain_and_username)
1025 {
1026 WCHAR *user = wcschr(domain_and_username, '\\');
1027 WCHAR *domain = domain_and_username;
1028
1029 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
1030
1031 pAuthData = &nt_auth_identity;
1032
1033 if (user) user++;
1034 else
1035 {
1036 user = domain_and_username;
1037 domain = NULL;
1038 }
1039
1040 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1041 nt_auth_identity.User = user;
1042 nt_auth_identity.UserLength = lstrlenW(nt_auth_identity.User);
1043 nt_auth_identity.Domain = domain;
1044 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
1045 nt_auth_identity.Password = password;
1046 nt_auth_identity.PasswordLength = lstrlenW(nt_auth_identity.Password);
1047
1048 cache_authorization(host, pAuthInfo->scheme, &nt_auth_identity);
1049 }
1050 else if(retrieve_cached_authorization(host, pAuthInfo->scheme, &nt_auth_identity))
1051 pAuthData = &nt_auth_identity;
1052 else
1053 /* use default credentials */
1054 pAuthData = NULL;
1055
1056 sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
1058 pAuthData, NULL,
1059 NULL, &pAuthInfo->cred,
1060 &exp);
1061
1062 if(pAuthData && !domain_and_username) {
1063 heap_free(nt_auth_identity.User);
1064 heap_free(nt_auth_identity.Domain);
1065 heap_free(nt_auth_identity.Password);
1066 }
1067
1068 if (sec_status == SEC_E_OK)
1069 {
1070 PSecPkgInfoW sec_pkg_info;
1071 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
1072 if (sec_status == SEC_E_OK)
1073 {
1074 pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
1075 FreeContextBuffer(sec_pkg_info);
1076 }
1077 }
1078 if (sec_status != SEC_E_OK)
1079 {
1080 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
1081 debugstr_w(pAuthInfo->scheme), sec_status);
1082 heap_free(pAuthInfo->scheme);
1083 heap_free(pAuthInfo);
1084 return FALSE;
1085 }
1086 }
1087 *ppAuthInfo = pAuthInfo;
1088 }
1089 else if (pAuthInfo->finished)
1090 return FALSE;
1091
1092 if ((lstrlenW(pszAuthValue) < lstrlenW(pAuthInfo->scheme)) ||
1093 wcsnicmp(pszAuthValue, pAuthInfo->scheme, lstrlenW(pAuthInfo->scheme)))
1094 {
1095 ERR("authentication scheme changed from %s to %s\n",
1096 debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
1097 return FALSE;
1098 }
1099
1100 if (is_basic_auth_value(pszAuthValue,&szRealm))
1101 {
1102 int userlen;
1103 int passlen;
1104 char *auth_data = NULL;
1105 UINT auth_data_len = 0;
1106
1107 TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
1108
1109 if (!domain_and_username)
1110 {
1111 if (host && szRealm)
1113 if (auth_data_len == 0)
1114 {
1115 heap_free(szRealm);
1116 return FALSE;
1117 }
1118 }
1119 else
1120 {
1121 userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
1123
1124 /* length includes a nul terminator, which will be re-used for the ':' */
1125 auth_data = heap_alloc(userlen + 1 + passlen);
1126 if (!auth_data)
1127 {
1128 heap_free(szRealm);
1129 return FALSE;
1130 }
1131
1132 WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
1133 auth_data[userlen] = ':';
1134 WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
1135 auth_data_len = userlen + 1 + passlen;
1136 if (host && szRealm)
1138 }
1139
1140 pAuthInfo->auth_data = auth_data;
1141 pAuthInfo->auth_data_len = auth_data_len;
1142 pAuthInfo->finished = TRUE;
1143 heap_free(szRealm);
1144 return TRUE;
1145 }
1146 else
1147 {
1148 LPCWSTR pszAuthData;
1149 SecBufferDesc out_desc, in_desc;
1150 SecBuffer out, in;
1151 unsigned char *buffer;
1154
1155 in.BufferType = SECBUFFER_TOKEN;
1156 in.cbBuffer = 0;
1157 in.pvBuffer = NULL;
1158
1159 in_desc.ulVersion = 0;
1160 in_desc.cBuffers = 1;
1161 in_desc.pBuffers = &in;
1162
1163 pszAuthData = pszAuthValue + lstrlenW(pAuthInfo->scheme);
1164 if (*pszAuthData == ' ')
1165 {
1166 pszAuthData++;
1167 in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
1168 in.pvBuffer = heap_alloc(in.cbBuffer);
1169 HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
1170 }
1171
1172 buffer = heap_alloc(pAuthInfo->max_token);
1173
1174 out.BufferType = SECBUFFER_TOKEN;
1175 out.cbBuffer = pAuthInfo->max_token;
1176 out.pvBuffer = buffer;
1177
1178 out_desc.ulVersion = 0;
1179 out_desc.cBuffers = 1;
1180 out_desc.pBuffers = &out;
1181
1182 sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
1183 first ? NULL : &pAuthInfo->ctx,
1184 first ? request->server->name : NULL,
1185 context_req, 0, SECURITY_NETWORK_DREP,
1186 in.pvBuffer ? &in_desc : NULL,
1187 0, &pAuthInfo->ctx, &out_desc,
1188 &pAuthInfo->attr, &pAuthInfo->exp);
1189 if (sec_status == SEC_E_OK)
1190 {
1191 pAuthInfo->finished = TRUE;
1192 pAuthInfo->auth_data = out.pvBuffer;
1193 pAuthInfo->auth_data_len = out.cbBuffer;
1194 TRACE("sending last auth packet\n");
1195 }
1196 else if (sec_status == SEC_I_CONTINUE_NEEDED)
1197 {
1198 pAuthInfo->auth_data = out.pvBuffer;
1199 pAuthInfo->auth_data_len = out.cbBuffer;
1200 TRACE("sending next auth packet\n");
1201 }
1202 else
1203 {
1204 ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
1205 heap_free(out.pvBuffer);
1206 destroy_authinfo(pAuthInfo);
1207 *ppAuthInfo = NULL;
1208 return FALSE;
1209 }
1210 }
1211
1212 return TRUE;
1213}
1214
1215/***********************************************************************
1216 * HTTP_HttpAddRequestHeadersW (internal)
1217 */
1219 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1220{
1221 LPWSTR lpszStart;
1222 LPWSTR lpszEnd;
1223 LPWSTR buffer;
1225
1226 TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
1227
1228 if( dwHeaderLength == ~0U )
1229 len = lstrlenW(lpszHeader);
1230 else
1231 len = dwHeaderLength;
1232 buffer = heap_alloc(sizeof(WCHAR)*(len+1));
1233 lstrcpynW( buffer, lpszHeader, len + 1);
1234
1235 lpszStart = buffer;
1236
1237 do
1238 {
1239 LPWSTR * pFieldAndValue;
1240
1241 lpszEnd = lpszStart;
1242
1243 while (*lpszEnd != '\0')
1244 {
1245 if (*lpszEnd == '\r' || *lpszEnd == '\n')
1246 break;
1247 lpszEnd++;
1248 }
1249
1250 if (*lpszStart == '\0')
1251 break;
1252
1253 if (*lpszEnd == '\r' || *lpszEnd == '\n')
1254 {
1255 *lpszEnd = '\0';
1256 lpszEnd++; /* Jump over newline */
1257 }
1258 TRACE("interpreting header %s\n", debugstr_w(lpszStart));
1259 if (*lpszStart == '\0')
1260 {
1261 /* Skip 0-length headers */
1262 lpszStart = lpszEnd;
1264 continue;
1265 }
1266 pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
1267 if (pFieldAndValue)
1268 {
1269 res = HTTP_ProcessHeader(request, pFieldAndValue[0],
1270 pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
1271 HTTP_FreeTokens(pFieldAndValue);
1272 }
1273
1274 lpszStart = lpszEnd;
1275 } while (res == ERROR_SUCCESS);
1276
1278 return res;
1279}
1280
1281/***********************************************************************
1282 * HttpAddRequestHeadersW (WININET.@)
1283 *
1284 * Adds one or more HTTP header to the request handler
1285 *
1286 * NOTE
1287 * On Windows if dwHeaderLength includes the trailing '\0', then
1288 * HttpAddRequestHeadersW() adds it too. However this results in an
1289 * invalid HTTP header which is rejected by some servers so we probably
1290 * don't need to match Windows on that point.
1291 *
1292 * RETURNS
1293 * TRUE on success
1294 * FALSE on failure
1295 *
1296 */
1298 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1299{
1302
1303 TRACE("%p, %s, %u, %08x\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
1304
1305 if (!lpszHeader)
1306 return TRUE;
1307
1308 request = (http_request_t*) get_handle_object( hHttpRequest );
1309 if (request && request->hdr.htype == WH_HHTTPREQ)
1310 res = HTTP_HttpAddRequestHeadersW( request, lpszHeader, dwHeaderLength, dwModifier );
1311 if( request )
1313
1314 if(res != ERROR_SUCCESS)
1316 return res == ERROR_SUCCESS;
1317}
1318
1319/***********************************************************************
1320 * HttpAddRequestHeadersA (WININET.@)
1321 *
1322 * Adds one or more HTTP header to the request handler
1323 *
1324 * RETURNS
1325 * TRUE on success
1326 * FALSE on failure
1327 *
1328 */
1330 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1331{
1332 WCHAR *headers = NULL;
1333 BOOL r;
1334
1335 TRACE("%p, %s, %u, %08x\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
1336
1337 if(lpszHeader)
1338 headers = heap_strndupAtoW(lpszHeader, dwHeaderLength, &dwHeaderLength);
1339
1340 r = HttpAddRequestHeadersW(hHttpRequest, headers, dwHeaderLength, dwModifier);
1341
1343 return r;
1344}
1345
1346static void free_accept_types( WCHAR **accept_types )
1347{
1348 WCHAR *ptr, **types = accept_types;
1349
1350 if (!types) return;
1351 while ((ptr = *types))
1352 {
1353 heap_free( ptr );
1354 types++;
1355 }
1356 heap_free( accept_types );
1357}
1358
1359static WCHAR **convert_accept_types( const char **accept_types )
1360{
1361 unsigned int count;
1362 const char **types = accept_types;
1363 WCHAR **typesW;
1364 BOOL invalid_pointer = FALSE;
1365
1366 if (!types) return NULL;
1367 count = 0;
1368 while (*types)
1369 {
1370 __TRY
1371 {
1372 /* find out how many there are */
1373 if (*types && **types)
1374 {
1375 TRACE("accept type: %s\n", debugstr_a(*types));
1376 count++;
1377 }
1378 }
1380 {
1381 WARN("invalid accept type pointer\n");
1382 invalid_pointer = TRUE;
1383 }
1384 __ENDTRY;
1385 types++;
1386 }
1387 if (invalid_pointer) return NULL;
1388 if (!(typesW = heap_alloc( sizeof(WCHAR *) * (count + 1) ))) return NULL;
1389 count = 0;
1390 types = accept_types;
1391 while (*types)
1392 {
1393 if (*types && **types) typesW[count++] = heap_strdupAtoW( *types );
1394 types++;
1395 }
1396 typesW[count] = NULL;
1397 return typesW;
1398}
1399
1400/***********************************************************************
1401 * HttpOpenRequestA (WININET.@)
1402 *
1403 * Open a HTTP request handle
1404 *
1405 * RETURNS
1406 * HINTERNET a HTTP request handle on success
1407 * NULL on failure
1408 *
1409 */
1411 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
1412 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
1413 DWORD dwFlags, DWORD_PTR dwContext)
1414{
1415 LPWSTR szVerb = NULL, szObjectName = NULL;
1416 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
1417 HINTERNET rc = NULL;
1418
1419 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1420 debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
1421 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
1422 dwFlags, dwContext);
1423
1424 if (lpszVerb)
1425 {
1426 szVerb = heap_strdupAtoW(lpszVerb);
1427 if ( !szVerb )
1428 goto end;
1429 }
1430
1431 if (lpszObjectName)
1432 {
1433 szObjectName = heap_strdupAtoW(lpszObjectName);
1434 if ( !szObjectName )
1435 goto end;
1436 }
1437
1438 if (lpszVersion)
1439 {
1440 szVersion = heap_strdupAtoW(lpszVersion);
1441 if ( !szVersion )
1442 goto end;
1443 }
1444
1445 if (lpszReferrer)
1446 {
1447 szReferrer = heap_strdupAtoW(lpszReferrer);
1448 if ( !szReferrer )
1449 goto end;
1450 }
1451
1452 szAcceptTypes = convert_accept_types( lpszAcceptTypes );
1453 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer,
1454 (const WCHAR **)szAcceptTypes, dwFlags, dwContext);
1455
1456end:
1457 free_accept_types(szAcceptTypes);
1458 heap_free(szReferrer);
1460 heap_free(szObjectName);
1461 heap_free(szVerb);
1462 return rc;
1463}
1464
1465/***********************************************************************
1466 * HTTP_EncodeBase64
1467 */
1468static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 )
1469{
1470 UINT n = 0, x;
1471 static const CHAR HTTP_Base64Enc[] =
1472 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1473
1474 while( len > 0 )
1475 {
1476 /* first 6 bits, all from bin[0] */
1477 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
1478 x = (bin[0] & 3) << 4;
1479
1480 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
1481 if( len == 1 )
1482 {
1483 base64[n++] = HTTP_Base64Enc[x];
1484 base64[n++] = '=';
1485 base64[n++] = '=';
1486 break;
1487 }
1488 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
1489 x = ( bin[1] & 0x0f ) << 2;
1490
1491 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1492 if( len == 2 )
1493 {
1494 base64[n++] = HTTP_Base64Enc[x];
1495 base64[n++] = '=';
1496 break;
1497 }
1498 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
1499
1500 /* last 6 bits, all from bin [2] */
1501 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
1502 bin += 3;
1503 len -= 3;
1504 }
1505 base64[n] = 0;
1506 return n;
1507}
1508
1509static const signed char HTTP_Base64Dec[] =
1510{
1511 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1512 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1513 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1514 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1515 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1516 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1517 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1518 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1519};
1520
1521/***********************************************************************
1522 * HTTP_DecodeBase64
1523 */
1525{
1526 unsigned int n = 0;
1527
1528 while(*base64)
1529 {
1530 signed char in[4];
1531
1532 if (base64[0] >= ARRAY_SIZE(HTTP_Base64Dec) ||
1533 ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
1534 base64[1] >= ARRAY_SIZE(HTTP_Base64Dec) ||
1535 ((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
1536 {
1537 WARN("invalid base64: %s\n", debugstr_w(base64));
1538 return 0;
1539 }
1540 if (bin)
1541 bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4);
1542 n++;
1543
1544 if ((base64[2] == '=') && (base64[3] == '='))
1545 break;
1546 if (base64[2] > ARRAY_SIZE(HTTP_Base64Dec) ||
1547 ((in[2] = HTTP_Base64Dec[base64[2]]) == -1))
1548 {
1549 WARN("invalid base64: %s\n", debugstr_w(&base64[2]));
1550 return 0;
1551 }
1552 if (bin)
1553 bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2);
1554 n++;
1555
1556 if (base64[3] == '=')
1557 break;
1558 if (base64[3] > ARRAY_SIZE(HTTP_Base64Dec) ||
1559 ((in[3] = HTTP_Base64Dec[base64[3]]) == -1))
1560 {
1561 WARN("invalid base64: %s\n", debugstr_w(&base64[3]));
1562 return 0;
1563 }
1564 if (bin)
1565 bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1566 n++;
1567
1568 base64 += 4;
1569 }
1570
1571 return n;
1572}
1573
1574static WCHAR *encode_auth_data( const WCHAR *scheme, const char *data, UINT data_len )
1575{
1576 WCHAR *ret;
1577 UINT len, scheme_len = lstrlenW( scheme );
1578
1579 /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1580 len = scheme_len + 1 + ((data_len + 2) * 4) / 3;
1581 if (!(ret = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
1582 memcpy( ret, scheme, scheme_len * sizeof(WCHAR) );
1583 ret[scheme_len] = ' ';
1584 HTTP_EncodeBase64( data, data_len, ret + scheme_len + 1 );
1585 return ret;
1586}
1587
1588
1589/***********************************************************************
1590 * HTTP_InsertAuthorization
1591 *
1592 * Insert or delete the authorization field in the request header.
1593 */
1595{
1596 WCHAR *host, *authorization = NULL;
1597
1598 if (pAuthInfo)
1599 {
1600 if (pAuthInfo->auth_data_len)
1601 {
1602 if (!(authorization = encode_auth_data(pAuthInfo->scheme, pAuthInfo->auth_data, pAuthInfo->auth_data_len)))
1603 return FALSE;
1604
1605 /* clear the data as it isn't valid now that it has been sent to the
1606 * server, unless it's Basic authentication which doesn't do
1607 * connection tracking */
1608 if (wcsicmp(pAuthInfo->scheme, L"Basic"))
1609 {
1610 heap_free(pAuthInfo->auth_data);
1611 pAuthInfo->auth_data = NULL;
1612 pAuthInfo->auth_data_len = 0;
1613 }
1614 }
1615
1616 TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1617
1618 HTTP_ProcessHeader(request, header, authorization,
1620 heap_free(authorization);
1621 }
1622 else
1623 {
1624 UINT data_len;
1625 char *data;
1626
1627 /* Don't use cached credentials when a username or Authorization was specified */
1628 if ((request->session->userName && request->session->userName[0]) || wcscmp(header, L"Authorization"))
1629 return TRUE;
1630
1631 if (!(host = get_host_header(request)))
1632 return TRUE;
1633
1635 {
1636 TRACE("Found cached basic authorization for %s\n", debugstr_w(host));
1637
1638 if (!(authorization = encode_auth_data(L"Basic", data, data_len)))
1639 {
1640 heap_free(data);
1641 heap_free(host);
1642 return FALSE;
1643 }
1644
1645 TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1646
1647 HTTP_ProcessHeader(request, header, authorization,
1649 heap_free(data);
1650 heap_free(authorization);
1651 }
1652 heap_free(host);
1653 }
1654 return TRUE;
1655}
1656
1658{
1659 DWORD size, len;
1660 WCHAR *url;
1661
1663 size = len + lstrlenW(req->path) + 1;
1664 if(*req->path != '/')
1665 size++;
1666 url = heap_alloc(size * sizeof(WCHAR));
1667 if(!url)
1668 return NULL;
1669
1670 memcpy(url, req->server->scheme_host_port, len*sizeof(WCHAR));
1671 if(*req->path != '/')
1672 url[len++] = '/';
1673
1674 lstrcpyW(url+len, req->path);
1675
1676 TRACE("url=%s\n", debugstr_w(url));
1677 return url;
1678}
1679
1681{
1682 const WCHAR *dot, *ptr;
1683 int len;
1684
1685 if(domain.len == ARRAY_SIZE(L"<local>")-1 && !wcsnicmp(domain.str, L"<local>", domain.len) && !wcschr(server, '.' ))
1686 return TRUE;
1687
1688 if(domain.len && *domain.str != '*')
1689 return domain.len == lstrlenW(server) && !wcsnicmp(server, domain.str, domain.len);
1690
1691 if(domain.len < 2 || domain.str[1] != '.')
1692 return FALSE;
1693
1694 /* For a hostname to match a wildcard, the last domain must match
1695 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
1696 * hostname is www.foo.a.b, it matches, but a.b does not.
1697 */
1698 dot = wcschr(server, '.');
1699 if(!dot)
1700 return FALSE;
1701
1702 len = lstrlenW(dot + 1);
1703 if(len < domain.len - 2)
1704 return FALSE;
1705
1706 /* The server's domain is longer than the wildcard, so it
1707 * could be a subdomain. Compare the last portion of the
1708 * server's domain.
1709 */
1710 ptr = dot + 1 + len - domain.len + 2;
1711 if(!wcsnicmp(ptr, domain.str+2, domain.len-2))
1712 /* This is only a match if the preceding character is
1713 * a '.', i.e. that it is a matching domain. E.g.
1714 * if domain is '*.b.c' and server is 'www.ab.c' they
1715 * do not match.
1716 */
1717 return *(ptr - 1) == '.';
1718
1719 return len == domain.len-2 && !wcsnicmp(dot + 1, domain.str + 2, len);
1720}
1721
1723{
1724 LPCWSTR ptr;
1725 BOOL ret = FALSE;
1726
1727 if (!lpwai->proxyBypass) return FALSE;
1728 ptr = lpwai->proxyBypass;
1729 while(1) {
1730 LPCWSTR tmp = ptr;
1731
1732 ptr = wcschr( ptr, ';' );
1733 if (!ptr)
1734 ptr = wcschr( tmp, ' ' );
1735 if (!ptr)
1736 ptr = tmp + lstrlenW(tmp);
1737 ret = HTTP_DomainMatches( server, substr(tmp, ptr-tmp) );
1738 if (ret || !*ptr)
1739 break;
1740 ptr++;
1741 }
1742 return ret;
1743}
1744
1745/***********************************************************************
1746 * HTTP_DealWithProxy
1747 */
1749{
1750 static WCHAR szNul[] = L"";
1751 URL_COMPONENTSW UrlComponents = { sizeof(UrlComponents) };
1752 server_t *new_server = NULL;
1753 WCHAR *proxy;
1754
1756 if(!proxy)
1757 return FALSE;
1759 proxy, lstrlenW(L"http://"), L"http://", lstrlenW(L"http://"))) {
1760 WCHAR *proxy_url = heap_alloc(lstrlenW(proxy)*sizeof(WCHAR) + sizeof(L"http://"));
1761 if(!proxy_url) {
1763 return FALSE;
1764 }
1765 lstrcpyW(proxy_url, L"http://");
1766 lstrcatW(proxy_url, proxy);
1768 proxy = proxy_url;
1769 }
1770
1771 UrlComponents.dwHostNameLength = 1;
1772 if(InternetCrackUrlW(proxy, 0, 0, &UrlComponents) && UrlComponents.dwHostNameLength) {
1773 if( !request->path )
1774 request->path = szNul;
1775
1776 new_server = get_server(substr(UrlComponents.lpszHostName, UrlComponents.dwHostNameLength),
1777 UrlComponents.nPort, UrlComponents.nScheme == INTERNET_SCHEME_HTTPS, TRUE);
1778 }
1780 if(!new_server)
1781 return FALSE;
1782
1783 request->proxy = new_server;
1784
1785 TRACE("proxy server=%s port=%d\n", debugstr_w(new_server->name), new_server->port);
1786 return TRUE;
1787}
1788
1790{
1791 server_t *server = request->proxy ? request->proxy : request->server;
1792 int addr_len;
1793
1794 if(server->addr_len)
1795 return ERROR_SUCCESS;
1796
1799 server->name,
1800 (lstrlenW(server->name)+1) * sizeof(WCHAR));
1801
1802 addr_len = sizeof(server->addr);
1803 if (!GetAddress(server->name, server->port, (SOCKADDR*)&server->addr, &addr_len, server->addr_str))
1805
1806 server->addr_len = addr_len;
1809 server->addr_str, strlen(server->addr_str)+1);
1810
1811 TRACE("resolved %s to %s\n", debugstr_w(server->name), server->addr_str);
1812 return ERROR_SUCCESS;
1813}
1814
1816{
1817 const WCHAR *host, *scheme;
1818 WCHAR *buf, *ptr;
1819 size_t len;
1820
1821 host = req->server->canon_host_port;
1822
1823 if (req->server->is_https)
1824 scheme = L"https://";
1825 else
1826 scheme = L"http://";
1827
1828 len = lstrlenW(scheme) + lstrlenW(host) + (req->path[0] != '/' ? 1 : 0) + lstrlenW(req->path);
1829 ptr = buf = heap_alloc((len+1) * sizeof(WCHAR));
1830 if(buf) {
1832 ptr += lstrlenW(ptr);
1833
1834 lstrcpyW(ptr, host);
1835 ptr += lstrlenW(ptr);
1836
1837 if(req->path[0] != '/')
1838 *ptr++ = '/';
1839
1840 lstrcpyW(ptr, req->path);
1841 ptr += lstrlenW(ptr);
1842 *ptr = 0;
1843 }
1844
1845 return buf;
1846}
1847
1848
1849/***********************************************************************
1850 * HTTPREQ_Destroy (internal)
1851 *
1852 * Deallocate request handle
1853 *
1854 */
1856{
1858 DWORD i;
1859
1860 TRACE("\n");
1861
1862 if(request->hCacheFile)
1863 CloseHandle(request->hCacheFile);
1864 if(request->req_file)
1865 req_file_release(request->req_file);
1866
1867 request->headers_section.DebugInfo->Spare[0] = 0;
1868 DeleteCriticalSection( &request->headers_section );
1869 request->read_section.DebugInfo->Spare[0] = 0;
1870 DeleteCriticalSection( &request->read_section );
1871 WININET_Release(&request->session->hdr);
1872
1873 destroy_authinfo(request->authInfo);
1874 destroy_authinfo(request->proxyAuthInfo);
1875
1876 if(request->server)
1877 server_release(request->server);
1878 if(request->proxy)
1879 server_release(request->proxy);
1880
1884 heap_free(request->statusText);
1885
1886 for (i = 0; i < request->nCustHeaders; i++)
1887 {
1888 heap_free(request->custHeaders[i].lpszField);
1889 heap_free(request->custHeaders[i].lpszValue);
1890 }
1891 destroy_data_stream(request->data_stream);
1892 heap_free(request->custHeaders);
1893}
1894
1896{
1897 TRACE("%p %p %x\n",req, req->netconn, reuse);
1898
1899 if(!is_valid_netconn(req->netconn))
1900 return;
1901
1902#ifndef __REACTOS__
1903 if(reuse && req->netconn->keep_alive) {
1904 BOOL run_collector;
1905
1907
1910 req->netconn = NULL;
1911
1912 run_collector = !collector_running;
1914
1916
1917 if(run_collector) {
1918 HANDLE thread = NULL;
1920
1921 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)WININET_hModule, &module);
1922 if(module)
1924 if(!thread) {
1928
1929 if(module)
1931 }
1932 else
1934 }
1935 return;
1936 }
1937#else
1938 /* Silence unused function warning */
1940#endif
1941
1944
1945 close_netconn(req->netconn);
1946
1949}
1950
1952{
1953 WCHAR szVersion[10];
1954 WCHAR szConnectionResponse[20];
1955 DWORD dwBufferSize = sizeof(szVersion);
1956 BOOL keepalive = FALSE;
1957
1958 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1959 * the connection is keep-alive by default */
1961 && !wcsicmp(szVersion, L"HTTP/1.1"))
1962 {
1963 keepalive = TRUE;
1964 }
1965
1966 dwBufferSize = sizeof(szConnectionResponse);
1967 if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS
1968 || HTTP_HttpQueryInfoW(request, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS)
1969 {
1970 keepalive = !wcsicmp(szConnectionResponse, L"Keep-Alive");
1971 }
1972
1973 return keepalive;
1974}
1975
1977{
1979
1981}
1982
1983static DWORD str_to_buffer(const WCHAR *str, void *buffer, DWORD *size, BOOL unicode)
1984{
1985 int len;
1986 if (unicode)
1987 {
1988 WCHAR *buf = buffer;
1989
1990 if (str) len = lstrlenW(str);
1991 else len = 0;
1992 if (*size < (len + 1) * sizeof(WCHAR))
1993 {
1994 *size = (len + 1) * sizeof(WCHAR);
1996 }
1997 if (str) lstrcpyW(buf, str);
1998 else buf[0] = 0;
1999
2000 *size = len;
2001 return ERROR_SUCCESS;
2002 }
2003 else
2004 {
2005 char *buf = buffer;
2006
2007 if (str) len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
2008 else len = 1;
2009 if (*size < len)
2010 {
2011 *size = len;
2013 }
2014 if (str) WideCharToMultiByte(CP_ACP, 0, str, -1, buf, *size, NULL, NULL);
2015 else buf[0] = 0;
2016
2017 *size = len - 1;
2018 return ERROR_SUCCESS;
2019 }
2020}
2021
2023{
2025 DWORD len;
2026
2028 if(!context)
2029 return ERROR_NOT_SUPPORTED;
2030
2031 memset(info, 0, sizeof(*info));
2032 info->ftExpiry = context->pCertInfo->NotAfter;
2033 info->ftStart = context->pCertInfo->NotBefore;
2034 len = CertNameToStrA(context->dwCertEncodingType,
2035 &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0);
2036 info->lpszSubjectInfo = LocalAlloc(0, len);
2037 if(info->lpszSubjectInfo)
2038 CertNameToStrA(context->dwCertEncodingType,
2040 info->lpszSubjectInfo, len);
2041 len = CertNameToStrA(context->dwCertEncodingType,
2042 &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0);
2043 info->lpszIssuerInfo = LocalAlloc(0, len);
2044 if(info->lpszIssuerInfo)
2045 CertNameToStrA(context->dwCertEncodingType,
2047 info->lpszIssuerInfo, len);
2048 info->dwKeySize = NETCON_GetCipherStrength(req->netconn);
2049
2051 return ERROR_SUCCESS;
2052}
2053
2055{
2057
2058 switch(option) {
2060 {
2062
2063 FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
2064
2068 /* FIXME: can't get a SOCKET from our connection since we don't use
2069 * winsock
2070 */
2071 info->Socket = 0;
2072 /* FIXME: get source port from req->netConnection */
2073 info->SourcePort = 0;
2074 info->DestPort = req->server->port;
2075 info->Flags = 0;
2076 if (HTTP_KeepAlive(req))
2077 info->Flags |= IDSI_FLAG_KEEP_ALIVE;
2078 if (req->proxy)
2079 info->Flags |= IDSI_FLAG_PROXY;
2080 if (is_valid_netconn(req->netconn) && req->netconn->secure)
2081 info->Flags |= IDSI_FLAG_SECURE;
2082
2083 return ERROR_SUCCESS;
2084 }
2085
2086 case 98:
2087 TRACE("Queried undocumented option 98, forwarding to INTERNET_OPTION_SECURITY_FLAGS\n");
2088 /* fall through */
2090 {
2091 DWORD flags;
2092
2093 if (*size < sizeof(ULONG))
2095
2096 *size = sizeof(DWORD);
2098 *(DWORD *)buffer = flags;
2099
2100 TRACE("INTERNET_OPTION_SECURITY_FLAGS %x\n", flags);
2101 return ERROR_SUCCESS;
2102 }
2103
2105 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
2106
2107 if (*size < sizeof(ULONG))
2109
2110 *size = sizeof(DWORD);
2112 return ERROR_SUCCESS;
2113
2114 case INTERNET_OPTION_URL: {
2115 WCHAR *url;
2116 DWORD res;
2117
2118 TRACE("INTERNET_OPTION_URL\n");
2119
2120 url = compose_request_url(req);
2121 if(!url)
2122 return ERROR_OUTOFMEMORY;
2123
2124 res = str_to_buffer(url, buffer, size, unicode);
2125 heap_free(url);
2126 return res;
2127 }
2129 return str_to_buffer(req->session->appInfo->agent, buffer, size, unicode);
2131 return str_to_buffer(req->session->userName, buffer, size, unicode);
2133 return str_to_buffer(req->session->password, buffer, size, unicode);
2135 return str_to_buffer(req->session->appInfo->proxyUsername, buffer, size, unicode);
2137 return str_to_buffer(req->session->appInfo->proxyPassword, buffer, size, unicode);
2138
2142 DWORD nbytes, error;
2143 BOOL ret;
2144
2145 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
2146
2147 if(!req->req_file)
2148 return ERROR_FILE_NOT_FOUND;
2149
2150 if (*size < sizeof(*ts))
2151 {
2152 *size = sizeof(*ts);
2154 }
2155
2156 nbytes = 0;
2157 ret = GetUrlCacheEntryInfoW(req->req_file->url, NULL, &nbytes);
2158 error = GetLastError();
2160 {
2161 if (!(info = heap_alloc(nbytes)))
2162 return ERROR_OUTOFMEMORY;
2163
2164 GetUrlCacheEntryInfoW(req->req_file->url, info, &nbytes);
2165
2166 ts->ftExpires = info->ExpireTime;
2167 ts->ftLastModified = info->LastModifiedTime;
2168
2169 heap_free(info);
2170 *size = sizeof(*ts);
2171 return ERROR_SUCCESS;
2172 }
2173 return error;
2174 }
2175
2177 DWORD req_size;
2178
2179 TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
2180
2181 if(!req->req_file) {
2182 *size = 0;
2184 }
2185
2186 if(unicode) {
2187 req_size = (lstrlenW(req->req_file->file_name)+1) * sizeof(WCHAR);
2188 if(*size < req_size)
2190
2191 *size = req_size;
2193 return ERROR_SUCCESS;
2194 }else {
2195 req_size = WideCharToMultiByte(CP_ACP, 0, req->req_file->file_name, -1, NULL, 0, NULL, NULL);
2196 if (req_size > *size)
2198
2200 -1, buffer, *size, NULL, NULL);
2201 return ERROR_SUCCESS;
2202 }
2203 }
2204
2206 if(!req->netconn)
2208
2209 if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) {
2212 }
2213
2215 }
2217 DWORD err;
2218 int needed;
2219 char subject[64];
2220 char issuer[64];
2221 char effective[64];
2222 char expiration[64];
2223 char protocol[64];
2224 char signature[64];
2225 char encryption[64];
2226 char privacy[64];
2227 char bits[16];
2228 char strength[16];
2229 char start_date[32];
2230 char start_time[32];
2231 char expiry_date[32];
2232 char expiry_time[32];
2233 SYSTEMTIME start, expiry;
2235
2236 if(!size)
2238
2239 if(!req->netconn) {
2240 *size = 0;
2242 }
2243
2244 if(!buffer) {
2245 *size = 1;
2247 }
2248
2249 if((err = get_security_cert_struct(req, &info)))
2250 return err;
2251
2252 LoadStringA(WININET_hModule, IDS_CERT_SUBJECT, subject, sizeof(subject));
2254 LoadStringA(WININET_hModule, IDS_CERT_EFFECTIVE, effective, sizeof(effective));
2255 LoadStringA(WININET_hModule, IDS_CERT_EXPIRATION, expiration, sizeof(expiration));
2258 LoadStringA(WININET_hModule, IDS_CERT_ENCRYPTION, encryption, sizeof(encryption));
2259 LoadStringA(WININET_hModule, IDS_CERT_PRIVACY, privacy, sizeof(privacy));
2261 strength, sizeof(strength));
2263
2264 FileTimeToSystemTime(&info.ftStart, &start);
2265 FileTimeToSystemTime(&info.ftExpiry, &expiry);
2266 GetDateFormatA(LOCALE_USER_DEFAULT, 0, &start, NULL, start_date, sizeof(start_date));
2267 GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &start, NULL, start_time, sizeof(start_time));
2268 GetDateFormatA(LOCALE_USER_DEFAULT, 0, &expiry, NULL, expiry_date, sizeof(expiry_date));
2269 GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &expiry, NULL, expiry_time, sizeof(expiry_time));
2270
2271 needed = _scprintf("%s:\r\n%s\r\n"
2272 "%s:\r\n%s\r\n"
2273 "%s:\t%s %s\r\n"
2274 "%s:\t%s %s\r\n"
2275 "%s:\t(null)\r\n"
2276 "%s:\t(null)\r\n"
2277 "%s:\t(null)\r\n"
2278 "%s:\t%s (%u %s)",
2279 subject, info.lpszSubjectInfo,
2280 issuer, info.lpszIssuerInfo,
2281 effective, start_date, start_time,
2282 expiration, expiry_date, expiry_time,
2283 protocol, signature, encryption,
2284 privacy, strength, info.dwKeySize, bits);
2285
2286 if(needed < *size) {
2288 *size = snprintf(buffer, *size,
2289 "%s:\r\n%s\r\n"
2290 "%s:\r\n%s\r\n"
2291 "%s:\t%s %s\r\n"
2292 "%s:\t%s %s\r\n"
2293 "%s:\t(null)\r\n"
2294 "%s:\t(null)\r\n"
2295 "%s:\t(null)\r\n"
2296 "%s:\t%s (%u %s)",
2297 subject, info.lpszSubjectInfo,
2298 issuer, info.lpszIssuerInfo,
2299 effective, start_date, start_time,
2300 expiration, expiry_date, expiry_time,
2301 protocol, signature, encryption,
2302 privacy, strength, info.dwKeySize, bits);
2303 }else {
2305 *size = 1;
2306 }
2307
2308 LocalFree(info.lpszSubjectInfo);
2309 LocalFree(info.lpszIssuerInfo);
2310 LocalFree(info.lpszProtocolName);
2311 LocalFree(info.lpszSignatureAlgName);
2312 LocalFree(info.lpszEncryptionAlgName);
2313 return err;
2314 }
2316 if (*size < sizeof(DWORD))
2318
2319 *size = sizeof(DWORD);
2320 *(DWORD *)buffer = req->connect_timeout;
2321 return ERROR_SUCCESS;
2323 DWORD flags = 0;
2324
2325 if (*size < sizeof(DWORD))
2327
2328 /* FIXME: Add support for:
2329 * INTERNET_REQFLAG_FROM_CACHE
2330 * INTERNET_REQFLAG_CACHE_WRITE_DISABLED
2331 */
2332
2333 if(req->proxy)
2335 if(!req->status_code)
2337
2338 TRACE("INTERNET_OPTION_REQUEST_FLAGS returning %x\n", flags);
2339
2340 *size = sizeof(DWORD);
2341 *(DWORD*)buffer = flags;
2342 return ERROR_SUCCESS;
2343 }
2345 TRACE("INTERNET_OPTION_ERROR_MASK\n");
2346
2347 if (*size < sizeof(ULONG))
2349
2350 *(ULONG*)buffer = hdr->ErrorMask;
2351 *size = sizeof(ULONG);
2352 return ERROR_SUCCESS;
2353 }
2354
2355 return INET_QueryOption(hdr, option, buffer, size, unicode);
2356}
2357
2359{
2361
2362 switch(option) {
2363 case 99: /* Undocumented, seems to be INTERNET_OPTION_SECURITY_FLAGS with argument validation */
2364 TRACE("Undocumented option 99\n");
2365
2366 if (!buffer || size != sizeof(DWORD))
2370
2371 /* fall through */
2373 {
2374 DWORD flags;
2375
2376 if (!buffer || size != sizeof(DWORD))
2378 flags = *(DWORD *)buffer;
2379 TRACE("INTERNET_OPTION_SECURITY_FLAGS %08x\n", flags);
2381 req->security_flags |= flags;
2382 if(is_valid_netconn(req->netconn))
2383 req->netconn->security_flags |= flags;
2384 return ERROR_SUCCESS;
2385 }
2387 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
2388 req->connect_timeout = *(DWORD *)buffer;
2389 return ERROR_SUCCESS;
2390
2392 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
2393 req->send_timeout = *(DWORD *)buffer;
2394 return ERROR_SUCCESS;
2395
2397 if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER;
2398 req->receive_timeout = *(DWORD *)buffer;
2399 return ERROR_SUCCESS;
2400
2402 heap_free(req->session->userName);
2403 if (!(req->session->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
2404 return ERROR_SUCCESS;
2405
2407 heap_free(req->session->password);
2408 if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
2409 return ERROR_SUCCESS;
2410
2414 return ERROR_SUCCESS;
2415
2419 return ERROR_SUCCESS;
2420
2421 }
2422
2423 return INET_SetOption(hdr, option, buffer, size);
2424}
2425
2427{
2428 WCHAR *header;
2429 DWORD header_len;
2430 BOOL res;
2431
2432 TRACE("%p\n", req);
2433
2434 CloseHandle(req->hCacheFile);
2435 req->hCacheFile = NULL;
2436
2438 header_len = (header ? lstrlenW(header) : 0);
2441 header, header_len, NULL, 0);
2442 if(res)
2443 req->req_file->is_committed = TRUE;
2444 else
2445 WARN("CommitUrlCacheEntry failed: %u\n", GetLastError());
2447}
2448
2450{
2452 WCHAR *url;
2453 BOOL b = TRUE;
2454
2455 /* FIXME: We should free previous cache file earlier */
2456 if(req->req_file) {
2458 req->req_file = NULL;
2459 }
2460 if(req->hCacheFile) {
2461 CloseHandle(req->hCacheFile);
2462 req->hCacheFile = NULL;
2463 }
2464
2466 b = FALSE;
2467
2468 if(b) {
2469 int header_idx;
2470
2472
2473 header_idx = HTTP_GetCustomHeaderIndex(req, L"Cache-Control", 0, FALSE);
2474 if(header_idx != -1) {
2475 WCHAR *ptr;
2476
2477 for(ptr=req->custHeaders[header_idx].lpszValue; *ptr; ) {
2478 WCHAR *end;
2479
2480 while(*ptr==' ' || *ptr=='\t')
2481 ptr++;
2482
2483 end = wcschr(ptr, ',');
2484 if(!end)
2485 end = ptr + lstrlenW(ptr);
2486
2487 if(!wcsnicmp(ptr, L"no-cache", ARRAY_SIZE(L"no-cache")-1)
2488 || !wcsnicmp(ptr, L"no-store", ARRAY_SIZE(L"no-store")-1)) {
2489 b = FALSE;
2490 break;
2491 }
2492
2493 ptr = end;
2494 if(*ptr == ',')
2495 ptr++;
2496 }
2497 }
2498
2500 }
2501
2502 if(!b) {
2503 if(!(req->hdr.dwFlags & INTERNET_FLAG_NEED_FILE))
2504 return;
2505
2506 FIXME("INTERNET_FLAG_NEED_FILE is not supported correctly\n");
2507 }
2508
2509 url = compose_request_url(req);
2510 if(!url) {
2511 WARN("Could not get URL\n");
2512 return;
2513 }
2514
2515 b = CreateUrlCacheEntryW(url, req->contentLength == ~0 ? 0 : req->contentLength, NULL, file_name, 0);
2516 if(!b) {
2517 WARN("Could not create cache entry: %08x\n", GetLastError());
2518 return;
2519 }
2520
2522 req->req_file->url = url;
2523
2526 if(req->hCacheFile == INVALID_HANDLE_VALUE) {
2527 WARN("Could not create file: %u\n", GetLastError());
2528 req->hCacheFile = NULL;
2529 return;
2530 }
2531
2532 if(req->read_size) {
2533 DWORD written;
2534
2535 b = WriteFile(req->hCacheFile, req->read_buf+req->read_pos, req->read_size, &written, NULL);
2536 if(!b)
2537 FIXME("WriteFile failed: %u\n", GetLastError());
2538
2539 if(req->data_stream->vtbl->end_of_data(req->data_stream, req))
2540 commit_cache_entry(req);
2541 }
2542}
2543
2544/* read some more data into the read buffer (the read section must be held) */
2545static DWORD read_more_data( http_request_t *req, int maxlen )
2546{
2547 DWORD res;
2548 int len;
2549
2550 if (req->read_pos)
2551 {
2552 /* move existing data to the start of the buffer */
2553 if(req->read_size)
2554 memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
2555 req->read_pos = 0;
2556 }
2557
2558 if (maxlen == -1) maxlen = sizeof(req->read_buf);
2559
2560 res = NETCON_recv( req->netconn, req->read_buf + req->read_size,
2561 maxlen - req->read_size, TRUE, &len );
2562 if(res == ERROR_SUCCESS)
2563 req->read_size += len;
2564
2565 return res;
2566}
2567
2568/* remove some amount of data from the read buffer (the read section must be held) */
2569static void remove_data( http_request_t *req, int count )
2570{
2571 if (!(req->read_size -= count)) req->read_pos = 0;
2572 else req->read_pos += count;
2573}
2574
2576{
2577 int count, bytes_read, pos = 0;
2578 DWORD res;
2579
2581 for (;;)
2582 {
2583 BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
2584
2585 if (eol)
2586 {
2587 count = eol - (req->read_buf + req->read_pos);
2588 bytes_read = count + 1;
2589 }
2590 else count = bytes_read = req->read_size;
2591
2592 count = min( count, *len - pos );
2593 memcpy( buffer + pos, req->read_buf + req->read_pos, count );
2594 pos += count;
2595 remove_data( req, bytes_read );
2596 if (eol) break;
2597
2598 if ((res = read_more_data( req, -1 )))
2599 {
2600 WARN( "read failed %u\n", res );
2602 return res;
2603 }
2604 if (!req->read_size)
2605 {
2606 *len = 0;
2607 TRACE( "returning empty string\n" );
2609 return ERROR_SUCCESS;
2610 }
2611 }
2613
2614 if (pos < *len)
2615 {
2616 if (pos && buffer[pos - 1] == '\r') pos--;
2617 *len = pos + 1;
2618 }
2619 buffer[*len - 1] = 0;
2620 TRACE( "returning %s\n", debugstr_a(buffer));
2621 return ERROR_SUCCESS;
2622}
2623
2624/* check if we have reached the end of the data to read (the read section must be held) */
2626{
2627 return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req);
2628}
2629
2631{
2632 DWORD res;
2633
2634 res = req->data_stream->vtbl->read(req->data_stream, req, buf, size, read, allow_blocking);
2635 if(res != ERROR_SUCCESS)
2636 *read = 0;
2637 assert(*read <= size);
2638
2639 if(req->hCacheFile) {
2640 if(*read) {
2641 BOOL bres;
2642 DWORD written;
2643
2644 bres = WriteFile(req->hCacheFile, buf, *read, &written, NULL);
2645 if(!bres)
2646 FIXME("WriteFile failed: %u\n", GetLastError());
2647 }
2648
2649 if((res == ERROR_SUCCESS && !*read) || req->data_stream->vtbl->end_of_data(req->data_stream, req))
2650 commit_cache_entry(req);
2651 }
2652
2653 return res;
2654}
2655
2656/* fetch some more data into the read buffer (the read section must be held) */
2658{
2659 DWORD res, read=0;
2660
2661 if(req->read_size == sizeof(req->read_buf))
2662 return ERROR_SUCCESS;
2663
2664 if(req->read_pos) {
2665 if(req->read_size)
2666 memmove(req->read_buf, req->read_buf+req->read_pos, req->read_size);
2667 req->read_pos = 0;
2668 }
2669
2670 res = read_http_stream(req, req->read_buf+req->read_size, sizeof(req->read_buf) - req->read_size,
2671 &read, allow_blocking);
2672 if(res != ERROR_SUCCESS)
2673 return res;
2674
2675 req->read_size += read;
2676
2677 TRACE("read %u bytes, read_size %u\n", read, req->read_size);
2678 if(read_bytes)
2679 *read_bytes = read;
2680 return res;
2681}
2682
2684{
2685 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
2686 return netconn_stream->content_read == netconn_stream->content_length || !is_valid_netconn(req->netconn);
2687}
2688
2690 DWORD *read, BOOL allow_blocking)
2691{
2692 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
2694 int ret = 0;
2695
2696 size = min(size, netconn_stream->content_length-netconn_stream->content_read);
2697
2698 if(size && is_valid_netconn(req->netconn)) {
2699 res = NETCON_recv(req->netconn, buf, size, allow_blocking, &ret);
2700 if(res == ERROR_SUCCESS) {
2701 if(!ret)
2702 netconn_stream->content_length = netconn_stream->content_read;
2703 netconn_stream->content_read += ret;
2704 }
2705 }
2706
2707 TRACE("res %u read %u bytes\n", res, ret);
2708 *read = ret;
2709 return res;
2710}
2711
2713{
2714 netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
2715 BYTE buf[1024];
2716 int len, res;
2717 size_t size;
2718
2719 if(netconn_stream->content_length == ~0)
2720 return WSAEISCONN;
2721
2722 while(netconn_stream->content_read < netconn_stream->content_length) {
2723 size = min(sizeof(buf), netconn_stream->content_length-netconn_stream->content_read);
2724 res = NETCON_recv(req->netconn, buf, size, allow_blocking, &len);
2725 if(res)
2726 return res;
2727 if(!len)
2728 return WSAECONNABORTED;
2729
2730 netconn_stream->content_read += len;
2731 }
2732
2733 return ERROR_SUCCESS;
2734}
2735
2737{
2738}
2739
2745};
2746
2748{
2749 assert(stream->buf_size);
2750
2751 stream->buf_size--;
2752 return stream->buf[stream->buf_pos++];
2753}
2754
2756{
2757 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2758 switch(chunked_stream->state) {
2759 case CHUNKED_STREAM_STATE_DISCARD_EOL_AT_END:
2760 case CHUNKED_STREAM_STATE_END_OF_STREAM:
2761 case CHUNKED_STREAM_STATE_ERROR:
2762 return TRUE;
2763 default:
2764 return FALSE;
2765 }
2766}
2767
2769 DWORD *read, BOOL allow_blocking)
2770{
2771 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2772 DWORD ret_read = 0, res = ERROR_SUCCESS;
2773 BOOL continue_read = TRUE;
2774 int read_bytes;
2775 char ch;
2776
2777 do {
2778 TRACE("state %d\n", chunked_stream->state);
2779
2780 /* Ensure that we have data in the buffer for states that need it. */
2781 if(!chunked_stream->buf_size) {
2782 BOOL blocking_read = allow_blocking;
2783
2784 switch(chunked_stream->state) {
2785 case CHUNKED_STREAM_STATE_DISCARD_EOL_AT_END:
2786 case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_SIZE:
2787 /* never allow blocking after 0 chunk size */
2788 if(!chunked_stream->chunk_size)
2789 blocking_read = FALSE;
2790 /* fall through */
2791 case CHUNKED_STREAM_STATE_READING_CHUNK_SIZE:
2792 case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA:
2793 chunked_stream->buf_pos = 0;
2794 res = NETCON_recv(req->netconn, chunked_stream->buf, sizeof(chunked_stream->buf), blocking_read, &read_bytes);
2795 if(res == ERROR_SUCCESS && read_bytes) {
2796 chunked_stream->buf_size += read_bytes;
2797 }else if(res == WSAEWOULDBLOCK) {
2798 if(ret_read || allow_blocking)
2800 continue_read = FALSE;
2801 continue;
2802 }else {
2803 chunked_stream->state = CHUNKED_STREAM_STATE_ERROR;
2804 }
2805 break;
2806 default:
2807 break;
2808 }
2809 }
2810
2811 switch(chunked_stream->state) {
2812 case CHUNKED_STREAM_STATE_READING_CHUNK_SIZE:
2813 ch = next_chunked_data_char(chunked_stream);
2814
2815 if(ch >= '0' && ch <= '9') {
2816 chunked_stream->chunk_size = chunked_stream->chunk_size * 16 + ch - '0';
2817 }else if(ch >= 'a' && ch <= 'f') {
2818 chunked_stream->chunk_size = chunked_stream->chunk_size * 16 + ch - 'a' + 10;
2819 }else if (ch >= 'A' && ch <= 'F') {
2820 chunked_stream->chunk_size = chunked_stream->chunk_size * 16 + ch - 'A' + 10;
2821 }else if (ch == ';' || ch == '\r' || ch == '\n') {
2822 TRACE("reading %u byte chunk\n", chunked_stream->chunk_size);
2823 chunked_stream->buf_size++;
2824 chunked_stream->buf_pos--;
2825 if(req->contentLength == ~0) req->contentLength = chunked_stream->chunk_size;
2826 else req->contentLength += chunked_stream->chunk_size;
2827 chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_SIZE;
2828 }
2829 break;
2830
2831 case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_SIZE:
2832 ch = next_chunked_data_char(chunked_stream);
2833 if(ch == '\n')
2834 chunked_stream->state = chunked_stream->chunk_size
2835 ? CHUNKED_STREAM_STATE_READING_CHUNK
2836 : CHUNKED_STREAM_STATE_DISCARD_EOL_AT_END;
2837 else if(ch != '\r')
2838 WARN("unexpected char '%c'\n", ch);
2839 break;
2840
2841 case CHUNKED_STREAM_STATE_READING_CHUNK:
2842 assert(chunked_stream->chunk_size);
2843 if(!size) {
2844 continue_read = FALSE;
2845 break;
2846 }
2847 read_bytes = min(size, chunked_stream->chunk_size);
2848
2849 if(chunked_stream->buf_size) {
2850 if(read_bytes > chunked_stream->buf_size)
2851 read_bytes = chunked_stream->buf_size;
2852
2853 memcpy(buf+ret_read, chunked_stream->buf+chunked_stream->buf_pos, read_bytes);
2854 chunked_stream->buf_pos += read_bytes;
2855 chunked_stream->buf_size -= read_bytes;
2856 }else {
2857 res = NETCON_recv(req->netconn, (char*)buf+ret_read, read_bytes,
2858 allow_blocking, (int*)&read_bytes);
2859 if(res != ERROR_SUCCESS) {
2860 continue_read = FALSE;
2861 break;
2862 }
2863
2864 if(!read_bytes) {
2865 chunked_stream->state = CHUNKED_STREAM_STATE_ERROR;
2866 continue;
2867 }
2868 }
2869
2870 chunked_stream->chunk_size -= read_bytes;
2871 size -= read_bytes;
2872 ret_read += read_bytes;
2873 if(!chunked_stream->chunk_size)
2874 chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA;
2875 allow_blocking = FALSE;
2876 break;
2877
2878 case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA:
2879 ch = next_chunked_data_char(chunked_stream);
2880 if(ch == '\n')
2881 chunked_stream->state = CHUNKED_STREAM_STATE_READING_CHUNK_SIZE;
2882 else if(ch != '\r')
2883 WARN("unexpected char '%c'\n", ch);
2884 break;
2885
2886 case CHUNKED_STREAM_STATE_DISCARD_EOL_AT_END:
2887 ch = next_chunked_data_char(chunked_stream);
2888 if(ch == '\n')
2889 chunked_stream->state = CHUNKED_STREAM_STATE_END_OF_STREAM;
2890 else if(ch != '\r')
2891 WARN("unexpected char '%c'\n", ch);
2892 break;
2893
2894 case CHUNKED_STREAM_STATE_END_OF_STREAM:
2895 case CHUNKED_STREAM_STATE_ERROR:
2896 continue_read = FALSE;
2897 break;
2898 }
2899 } while(continue_read);
2900
2901 if(ret_read)
2903 if(res != ERROR_SUCCESS)
2904 return res;
2905
2906 TRACE("read %d bytes\n", ret_read);
2907 *read = ret_read;
2908 return ERROR_SUCCESS;
2909}
2910
2912{
2913 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2914 BYTE buf[1024];
2915 DWORD size, res;
2916
2917 while(chunked_stream->state != CHUNKED_STREAM_STATE_END_OF_STREAM
2918 && chunked_stream->state != CHUNKED_STREAM_STATE_ERROR) {
2919 res = chunked_read(stream, req, buf, sizeof(buf), &size, allow_blocking);
2920 if(res != ERROR_SUCCESS)
2921 return res;
2922 }
2923
2924 if(chunked_stream->state != CHUNKED_STREAM_STATE_END_OF_STREAM)
2925 return ERROR_NO_DATA;
2926 return ERROR_SUCCESS;
2927}
2928
2930{
2931 chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
2932 heap_free(chunked_stream);
2933}
2934
2940};
2941
2942/* set the request content length based on the headers */
2944{
2945 WCHAR contentLength[32];
2946 WCHAR encoding[20];
2947 DWORD size;
2948
2949 if(request->status_code == HTTP_STATUS_NO_CONTENT || !wcscmp(request->verb, L"HEAD")) {
2950 request->contentLength = request->netconn_stream.content_length = 0;
2951 return ERROR_SUCCESS;
2952 }
2953
2954 size = sizeof(contentLength);
2956 contentLength, &size, NULL) != ERROR_SUCCESS ||
2957 !StrToInt64ExW(contentLength, STIF_DEFAULT, (LONGLONG*)&request->contentLength)) {
2958 request->contentLength = ~0;
2959 }
2960
2961 request->netconn_stream.content_length = request->contentLength;
2962 request->netconn_stream.content_read = request->read_size;
2963
2964 size = sizeof(encoding);
2966 !wcsicmp(encoding, L"chunked"))
2967 {
2968 chunked_stream_t *chunked_stream;
2969
2970 chunked_stream = heap_alloc(sizeof(*chunked_stream));
2971 if(!chunked_stream)
2972 return ERROR_OUTOFMEMORY;
2973
2974 chunked_stream->data_stream.vtbl = &chunked_stream_vtbl;
2975 chunked_stream->buf_size = chunked_stream->buf_pos = 0;
2976 chunked_stream->chunk_size = 0;
2977 chunked_stream->state = CHUNKED_STREAM_STATE_READING_CHUNK_SIZE;
2978
2979 if(request->read_size) {
2981 chunked_stream->buf_size = request->read_size;
2983 }
2984
2985 request->data_stream = &chunked_stream->data_stream;
2986 request->contentLength = ~0;
2987 }
2988
2989 if(request->hdr.decoding) {
2990 int encoding_idx;
2991
2992 EnterCriticalSection( &request->headers_section );
2993
2994 encoding_idx = HTTP_GetCustomHeaderIndex(request, L"Content-Encoding", 0, FALSE);
2995 if(encoding_idx != -1) {
2996 if(!wcsicmp(request->custHeaders[encoding_idx].lpszValue, L"gzip")) {
2997 HTTP_DeleteCustomHeader(request, encoding_idx);
2998 LeaveCriticalSection( &request->headers_section );
2999 return init_gzip_stream(request, TRUE);
3000 }
3001 if(!wcsicmp(request->custHeaders[encoding_idx].lpszValue, L"deflate")) {
3002 HTTP_DeleteCustomHeader(request, encoding_idx);
3003 LeaveCriticalSection( &request->headers_section );
3005 }
3006 }
3007
3008 LeaveCriticalSection( &request->headers_section );
3009 }
3010
3011 return ERROR_SUCCESS;
3012}
3013
3015{
3017
3018 iar.dwResult = result;
3019 iar.dwError = error;
3020
3022 sizeof(INTERNET_ASYNC_RESULT));
3023}
3024
3026{
3027 DWORD res, read = 0;
3028
3029 TRACE("%p\n", req);
3030
3032
3033 res = refill_read_buffer(req, FALSE, &read);
3034 if(res == ERROR_SUCCESS)
3035 read += req->read_size;
3036
3038
3039 if(res != WSAEWOULDBLOCK && (res != ERROR_SUCCESS || !read)) {
3040 WARN("res %u read %u, closing connection\n", res, read);
3042 }
3043
3044 if(res != ERROR_SUCCESS && res != WSAEWOULDBLOCK) {
3045 send_request_complete(req, 0, res);
3046 return;
3047 }
3048
3050}
3051
3052/* read data from the http connection (the read section must be held) */
3053static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL allow_blocking)
3054{
3055 DWORD current_read = 0, ret_read = 0;
3057
3059
3060 if(req->read_size) {
3061 ret_read = min(size, req->read_size);
3062 memcpy(buffer, req->read_buf+req->read_pos, ret_read);
3063 req->read_size -= ret_read;
3064 req->read_pos += ret_read;
3065 allow_blocking = FALSE;
3066 }
3067
3068 if(ret_read < size) {
3069 res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, &current_read, allow_blocking);
3070 if(res == ERROR_SUCCESS)
3071 ret_read += current_read;
3072 else if(res == WSAEWOULDBLOCK && ret_read)
3074 }
3075
3077
3078 *read = ret_read;
3079 TRACE( "retrieved %u bytes (res %u)\n", ret_read, res );
3080
3081 if(res != WSAEWOULDBLOCK) {
3082 if(res != ERROR_SUCCESS)
3084 else if(!ret_read && drain_content(req, FALSE) == ERROR_SUCCESS)
3086 }
3087
3088 return res;
3089}
3090
3092{
3093 DWORD res;
3094
3095 TRACE("%p\n", req->netconn);
3096
3097 if(!is_valid_netconn(req->netconn))
3098 return ERROR_NO_DATA;
3099
3100 if(!wcscmp(req->verb, L"HEAD"))
3101 return ERROR_SUCCESS;
3102
3104 res = req->data_stream->vtbl->drain_content(req->data_stream, req, blocking);
3106 return res;
3107}
3108
3109typedef struct {
3111 void *buf;
3116
3118{
3120 http_request_t *req = (http_request_t*)task->hdr.hdr;
3121 DWORD res = ERROR_SUCCESS, read = task->read_pos, complete_arg = 0;
3122
3123 TRACE("req %p buf %p size %u read_pos %u ret_read %p\n", req, task->buf, task->size, task->read_pos, task->ret_read);
3124
3125 if(task->buf) {
3127 while (read < task->size) {
3128 res = HTTPREQ_Read(req, (char*)task->buf + read, task->size - read, &read_bytes, TRUE);
3129 if (res != ERROR_SUCCESS || !read_bytes)
3130 break;
3131 read += read_bytes;
3132 }
3133 }else {
3135 res = refill_read_buffer(req, TRUE, &read);
3137
3138 if(task->ret_read)
3139 complete_arg = read; /* QueryDataAvailable reports read bytes in request complete notification */
3140 if(res != ERROR_SUCCESS || !read)
3142 }
3143
3144 TRACE("res %u read %u\n", res, read);
3145
3146 if(task->ret_read)
3147 *task->ret_read = read;
3148
3149 /* FIXME: We should report bytes transferred before decoding content. */
3151
3152 if(res != ERROR_SUCCESS)
3153 complete_arg = res;
3154 send_request_complete(req, res == ERROR_SUCCESS, complete_arg);
3155}
3156
3157static DWORD async_read(http_request_t *req, void *buf, DWORD size, DWORD read_pos, DWORD *ret_read)
3158{
3159 read_file_task_t *task;
3160
3161 task = alloc_async_task(&req->hdr, async_read_file_proc, sizeof(*task));
3162 if(!task)
3163 return ERROR_OUTOFMEMORY;
3164
3165 task->buf = buf;
3166 task->size = size;
3167 task->read_pos = read_pos;
3168 task->ret_read = ret_read;
3169
3170 INTERNET_AsyncCall(&task->hdr);
3171 return ERROR_IO_PENDING;
3172}
3173
3176{
3178 DWORD res = ERROR_SUCCESS, read = 0, cread, error = ERROR_SUCCESS;
3179 BOOL allow_blocking, notify_received = FALSE;
3180
3181 TRACE("(%p %p %u %x)\n", req, buf, size, flags);
3182
3183 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
3184 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
3185
3186 allow_blocking = !(req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC);
3187
3188 if(allow_blocking || TryEnterCriticalSection(&req->read_section)) {
3189 if(allow_blocking)
3191 if(hdr->dwError == ERROR_SUCCESS)
3192 hdr->dwError = INTERNET_HANDLE_IN_USE;
3193 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
3195
3196 if(req->read_size) {
3197 read = min(size, req->read_size);
3198 memcpy(buf, req->read_buf + req->read_pos, read);
3199 req->read_size -= read;
3200 req->read_pos += read;
3201 }
3202
3203 if(read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) {
3207 notify_received = TRUE;
3208
3209 while(read < size) {
3210 res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread, allow_blocking);
3211 read += cread;
3212 if (res != ERROR_SUCCESS || !cread)
3213 break;
3214 }
3215 }
3216
3217 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
3218 hdr->dwError = ERROR_SUCCESS;
3219 else
3220 error = hdr->dwError;
3221
3223 }else {
3225 }
3226
3227 if(res == WSAEWOULDBLOCK) {
3228 if(!(flags & IRF_NO_WAIT))
3229 return async_read(req, buf, size, read, ret_read);
3230 if(!read)
3231 return async_read(req, NULL, 0, 0, NULL);
3233 }
3234
3235 *ret_read = read;
3236 if (res != ERROR_SUCCESS)
3237 return res;
3238
3239 if(notify_received)
3241 &read, sizeof(read));
3242 return error;
3243}
3244
3246{
3247 DWORD res;
3249
3251
3252 *written = 0;
3253 res = NETCON_send(request->netconn, buffer, size, 0, (LPINT)written);
3254 if (res == ERROR_SUCCESS)
3255 request->bytesWritten += *written;
3256
3258 return res;
3259}
3260
3262{
3265 BOOL allow_blocking, notify_received = FALSE;
3266
3267 TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
3268
3269 if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
3270 FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
3271
3272 *available = 0;
3273 allow_blocking = !(req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC);
3274
3275 if(allow_blocking || TryEnterCriticalSection(&req->read_section)) {
3276 if(allow_blocking)
3278 if(hdr->dwError == ERROR_SUCCESS)
3279 hdr->dwError = INTERNET_HANDLE_IN_USE;
3280 else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
3282
3283 avail = req->read_size;
3284
3285 if(!avail && !end_of_read_data(req)) {
3289 notify_received = TRUE;
3290
3291 res = refill_read_buffer(req, allow_blocking, &avail);
3292 }
3293
3294 if(hdr->dwError == INTERNET_HANDLE_IN_USE)
3295 hdr->dwError = ERROR_SUCCESS;
3296 else
3297 error = hdr->dwError;
3298
3300 }else {
3302 }
3303
3304 if(res == WSAEWOULDBLOCK)
3305 return async_read(req, NULL, 0, 0, available);
3306
3307 if (res != ERROR_SUCCESS)
3308 return res;
3309
3310 *available = avail;
3311 if(notify_received)
3313 &avail, sizeof(avail));
3314 return error;
3315}
3316
3318{
3320
3321 TRACE("(%p)\n", req);
3322
3323 if(!req->req_file) {
3324 WARN("No cache file name available\n");
3325 return ERROR_FILE_NOT_FOUND;
3326 }
3327
3328 *ret = req_file_addref(req->req_file);
3329 return ERROR_SUCCESS;
3330}
3331
3340 NULL,
3342};
3343
3344/***********************************************************************
3345 * HTTP_HttpOpenRequestW (internal)
3346 *
3347 * Open a HTTP request handle
3348 *
3349 * RETURNS
3350 * HINTERNET a HTTP request handle on success
3351 * NULL on failure
3352 *
3353 */
3355 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3356 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3357 DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret)
3358{
3359 appinfo_t *hIC = session->appInfo;
3361 DWORD port, len;
3362
3363 TRACE("-->\n");
3364
3366 if(!request)
3367 return ERROR_OUTOFMEMORY;
3368
3369 request->hdr.htype = WH_HHTTPREQ;
3370 request->hdr.dwFlags = dwFlags;
3371 request->hdr.dwContext = dwContext;
3372 request->hdr.decoding = session->hdr.decoding;
3373 request->contentLength = ~0;
3374
3375 request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl;
3376 request->data_stream = &request->netconn_stream.data_stream;
3380
3381 InitializeCriticalSection( &request->headers_section );
3382 request->headers_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.headers_section");
3383
3384 InitializeCriticalSection( &request->read_section );
3385 request->read_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.read_section");
3386
3388 request->session = session;
3389 list_add_head( &session->hdr.children, &request->hdr.entry );
3390
3391 port = session->hostPort;
3393 port = (session->hdr.dwFlags & INTERNET_FLAG_SECURE) ?
3395
3396 request->server = get_server(substrz(session->hostName), port, (dwFlags & INTERNET_FLAG_SECURE) != 0, TRUE);
3397 if(!request->server) {
3399 return ERROR_OUTOFMEMORY;
3400 }
3401
3406
3407 if (lpszObjectName && *lpszObjectName) {
3408 HRESULT rc;
3409 WCHAR dummy;
3410
3411 len = 1;
3412 rc = UrlCanonicalizeW(lpszObjectName, &dummy, &len, URL_ESCAPE_SPACES_ONLY);
3413 if (rc != E_POINTER)
3414 len = lstrlenW(lpszObjectName)+1;
3415 request->path = heap_alloc(len*sizeof(WCHAR));
3416 rc = UrlCanonicalizeW(lpszObjectName, request->path, &len,
3418 if (rc != S_OK)
3419 {
3420 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
3421 lstrcpyW(request->path,lpszObjectName);
3422 }
3423 }else {
3424 request->path = heap_strdupW(L"/");
3425 }
3426
3427 if (lpszReferrer && *lpszReferrer)
3429
3430 if (lpszAcceptTypes)
3431 {
3432 int i;
3433 for (i = 0; lpszAcceptTypes[i]; i++)
3434 {
3435 if (!*lpszAcceptTypes[i]) continue;
3436 HTTP_ProcessHeader(request, L"Accept", lpszAcceptTypes[i],
3440 }
3441 }
3442
3443 request->verb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : L"GET");
3444 request->version = heap_strdupW(lpszVersion && *lpszVersion ? lpszVersion : L"HTTP/1.1");
3445
3446 if (hIC->proxy && hIC->proxy[0] && !HTTP_ShouldBypassProxy(hIC, session->hostName))
3448
3449 INTERNET_SendCallback(&session->hdr, dwContext,
3451 sizeof(HINTERNET));
3452
3453 TRACE("<-- (%p)\n", request);
3454
3455 *ret = request->hdr.hInternet;
3456 return ERROR_SUCCESS;
3457}
3458
3459/***********************************************************************
3460 * HttpOpenRequestW (WININET.@)
3461 *
3462 * Open a HTTP request handle
3463 *
3464 * RETURNS
3465 * HINTERNET a HTTP request handle on success
3466 * NULL on failure
3467 *
3468 */
3470 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
3471 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
3472 DWORD dwFlags, DWORD_PTR dwContext)
3473{
3476 DWORD res;
3477
3478 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
3479 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
3480 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
3481 dwFlags, dwContext);
3482 if(lpszAcceptTypes!=NULL)
3483 {
3484 int i;
3485 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
3486 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
3487 }
3488
3489 session = (http_session_t*) get_handle_object( hHttpSession );
3490 if (NULL == session || session->hdr.htype != WH_HHTTPSESSION)
3491 {
3493 goto lend;
3494 }
3495
3496 /*
3497 * My tests seem to show that the windows version does not
3498 * become asynchronous until after this point. And anyhow
3499 * if this call was asynchronous then how would you get the
3500 * necessary HINTERNET pointer returned by this function.
3501 *
3502 */
3503 res = HTTP_HttpOpenRequestW(session, lpszVerb, lpszObjectName,
3504 lpszVersion, lpszReferrer, lpszAcceptTypes,
3505 dwFlags, dwContext, &handle);
3506lend:
3507 if( session )
3509 TRACE("returning %p\n", handle);
3510 if(res != ERROR_SUCCESS)
3512 return handle;
3513}
3514
3515static const LPCWSTR header_lookup[] = {
3516 L"Mime-Version", /* HTTP_QUERY_MIME_VERSION = 0 */
3517 L"Content-Type", /* HTTP_QUERY_CONTENT_TYPE = 1 */
3518 L"Content-Transfer-Encoding", /* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
3519 L"Content-ID", /* HTTP_QUERY_CONTENT_ID = 3 */
3520 NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
3521 L"Content-Length", /* HTTP_QUERY_CONTENT_LENGTH = 5 */
3522 L"Content-Language", /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
3523 L"Allow", /* HTTP_QUERY_ALLOW = 7 */
3524 L"Public", /* HTTP_QUERY_PUBLIC = 8 */
3525 L"Date", /* HTTP_QUERY_DATE = 9 */
3526 L"Expires", /* HTTP_QUERY_EXPIRES = 10 */
3527 L"Last-Modified", /* HTTP_QUERY_LAST_MODIFIED = 11 */
3528 NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
3529 L"URI", /* HTTP_QUERY_URI = 13 */
3530 L"From", /* HTTP_QUERY_DERIVED_FROM = 14 */
3531 NULL, /* HTTP_QUERY_COST = 15 */
3532 NULL, /* HTTP_QUERY_LINK = 16 */
3533 L"Pragma", /* HTTP_QUERY_PRAGMA = 17 */
3534 NULL, /* HTTP_QUERY_VERSION = 18 */
3535 L"Status", /* HTTP_QUERY_STATUS_CODE = 19 */
3536 NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
3537 NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
3538 NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
3539 L"Connection", /* HTTP_QUERY_CONNECTION = 23 */
3540 L"Accept", /* HTTP_QUERY_ACCEPT = 24 */
3541 L"Accept-Charset", /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
3542 L"Accept-Encoding", /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
3543 L"Accept-Language", /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
3544 L"Authorization", /* HTTP_QUERY_AUTHORIZATION = 28 */
3545 L"Content-Encoding", /* HTTP_QUERY_CONTENT_ENCODING = 29 */
3546 NULL, /* HTTP_QUERY_FORWARDED = 30 */
3547 NULL, /* HTTP_QUERY_FROM = 31 */
3548 L"If-Modified-Since", /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
3549 L"Location", /* HTTP_QUERY_LOCATION = 33 */
3550 NULL, /* HTTP_QUERY_ORIG_URI = 34 */
3551 L"Referer", /* HTTP_QUERY_REFERER = 35 */
3552 L"Retry-After", /* HTTP_QUERY_RETRY_AFTER = 36 */
3553 L"Server", /* HTTP_QUERY_SERVER = 37 */
3554 NULL, /* HTTP_TITLE = 38 */
3555 L"User-Agent", /* HTTP_QUERY_USER_AGENT = 39 */
3556 L"WWW-Authenticate", /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
3557 L"Proxy-Authenticate", /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
3558 L"Accept-Ranges", /* HTTP_QUERY_ACCEPT_RANGES = 42 */
3559 L"Set-Cookie", /* HTTP_QUERY_SET_COOKIE = 43 */
3560 L"Cookie", /* HTTP_QUERY_COOKIE = 44 */
3561 NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
3562 NULL, /* HTTP_QUERY_REFRESH = 46 */
3563 L"Content-Disposition", /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
3564 L"Age", /* HTTP_QUERY_AGE = 48 */
3565 L"Cache-Control", /* HTTP_QUERY_CACHE_CONTROL = 49 */
3566 L"Content-Base", /* HTTP_QUERY_CONTENT_BASE = 50 */
3567 L"Content-Location", /* HTTP_QUERY_CONTENT_LOCATION = 51 */
3568 L"Content-MD5", /* HTTP_QUERY_CONTENT_MD5 = 52 */
3569 L"Content-Range", /* HTTP_QUERY_CONTENT_RANGE = 53 */
3570 L"ETag", /* HTTP_QUERY_ETAG = 54 */
3571 L"Host", /* HTTP_QUERY_HOST = 55 */
3572 L"If-Match", /* HTTP_QUERY_IF_MATCH = 56 */
3573 L"If-None-Match", /* HTTP_QUERY_IF_NONE_MATCH = 57 */
3574 L"If-Range", /* HTTP_QUERY_IF_RANGE = 58 */
3575 L"If-Unmodified-Since", /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
3576 L"Max-Forwards", /* HTTP_QUERY_MAX_FORWARDS = 60 */
3577 L"Proxy-Authorization", /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
3578 L"Range", /* HTTP_QUERY_RANGE = 62 */
3579 L"Transfer-Encoding", /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
3580 L"Upgrade", /* HTTP_QUERY_UPGRADE = 64 */
3581 L"Vary", /* HTTP_QUERY_VARY = 65 */
3582 L"Via", /* HTTP_QUERY_VIA = 66 */
3583 L"Warning", /* HTTP_QUERY_WARNING = 67 */
3584 L"Expect", /* HTTP_QUERY_EXPECT = 68 */
3585 L"Proxy-Connection", /* HTTP_QUERY_PROXY_CONNECTION = 69 */
3586 L"Unless-Modified-Since", /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
3587};
3588
3589/***********************************************************************
3590 * HTTP_HttpQueryInfoW (internal)
3591 */
3594{
3595 LPHTTPHEADERW lphttpHdr = NULL;
3597 INT requested_index = lpdwIndex ? *lpdwIndex : 0;
3598 DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
3599 INT index = -1;
3600
3601 EnterCriticalSection( &request->headers_section );
3602
3603 /* Find requested header structure */
3604 switch (level)
3605 {
3606 case HTTP_QUERY_CUSTOM:
3607 if (!lpBuffer)
3608 {
3609 LeaveCriticalSection( &request->headers_section );
3611 }
3612 index = HTTP_GetCustomHeaderIndex(request, lpBuffer, requested_index, request_only);
3613 break;
3615 {
3617 DWORD len = 0;
3619
3620 if (request_only)
3622 else
3624 if (!headers)
3625 {
3626 LeaveCriticalSection( &request->headers_section );
3627 return ERROR_OUTOFMEMORY;
3628 }
3629
3630 len = lstrlenW(headers) * sizeof(WCHAR);
3631 if (len + sizeof(WCHAR) > *lpdwBufferLength)
3632 {
3633 len += sizeof(WCHAR);
3635 }
3636 else if (lpBuffer)
3637 {
3638 memcpy(lpBuffer, headers, len + sizeof(WCHAR));
3639 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
3641 }
3643
3645 LeaveCriticalSection( &request->headers_section );
3646 return res;
3647 }
3649 {
3651 DWORD len;
3652
3653 if (request_only)
3655 else
3657
3658 if (!headers)
3659 {
3660 LeaveCriticalSection( &request->headers_section );
3661 return ERROR_OUTOFMEMORY;
3662 }
3663
3664 len = lstrlenW(headers) * sizeof(WCHAR);
3665 if (len > *lpdwBufferLength)
3666 {
3669 LeaveCriticalSection( &request->headers_section );
3671 }
3672
3673 if (lpBuffer)
3674 {
3675 DWORD i;
3676
3677 TRACE("returning data: %s\n", debugstr_wn(headers, len / sizeof(WCHAR)));
3678
3679 for (i = 0; i < len / sizeof(WCHAR); i++)
3680 {
3681 if (headers[i] == '\n')
3682 headers[i] = 0;
3683 }