2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 TransGaming Technologies Inc.
7 * Copyright 2004 Mike McCormack for CodeWeavers
8 * Copyright 2005 Aric Stewart for CodeWeavers
9 * Copyright 2006 Robert Shearman for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
32 #if defined(__MINGW32__) || defined (_MSC_VER)
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
40 #ifdef HAVE_ARPA_INET_H
41 # include <arpa/inet.h>
59 #define NO_SHLWAPI_STREAM
60 #define NO_SHLWAPI_REG
61 #define NO_SHLWAPI_STRFCNS
62 #define NO_SHLWAPI_GDI
68 #include "wine/debug.h"
69 #include "wine/exception.h"
70 #include "wine/unicode.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
74 static const WCHAR g_szHttp1_0
[] = {'H','T','T','P','/','1','.','0',0};
75 static const WCHAR g_szHttp1_1
[] = {'H','T','T','P','/','1','.','1',0};
76 static const WCHAR hostW
[] = { 'H','o','s','t',0 };
77 static const WCHAR szAuthorization
[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
78 static const WCHAR szProxy_Authorization
[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
79 static const WCHAR szStatus
[] = { 'S','t','a','t','u','s',0 };
80 static const WCHAR szKeepAlive
[] = {'K','e','e','p','-','A','l','i','v','e',0};
81 static const WCHAR szGET
[] = { 'G','E','T', 0 };
82 static const WCHAR szCrLf
[] = {'\r','\n', 0};
84 static const WCHAR szAccept
[] = { 'A','c','c','e','p','t',0 };
85 static const WCHAR szAccept_Charset
[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
86 static const WCHAR szAccept_Encoding
[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
87 static const WCHAR szAccept_Language
[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
88 static const WCHAR szAccept_Ranges
[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
89 static const WCHAR szAge
[] = { 'A','g','e',0 };
90 static const WCHAR szAllow
[] = { 'A','l','l','o','w',0 };
91 static const WCHAR szCache_Control
[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
92 static const WCHAR szConnection
[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
93 static const WCHAR szContent_Base
[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
94 static const WCHAR szContent_Encoding
[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
95 static const WCHAR szContent_ID
[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
96 static const WCHAR szContent_Language
[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
97 static const WCHAR szContent_Length
[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
98 static const WCHAR szContent_Location
[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
99 static const WCHAR szContent_MD5
[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
100 static const WCHAR szContent_Range
[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
101 static const WCHAR szContent_Transfer_Encoding
[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
102 static const WCHAR szContent_Type
[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
103 static const WCHAR szCookie
[] = { 'C','o','o','k','i','e',0 };
104 static const WCHAR szDate
[] = { 'D','a','t','e',0 };
105 static const WCHAR szFrom
[] = { 'F','r','o','m',0 };
106 static const WCHAR szETag
[] = { 'E','T','a','g',0 };
107 static const WCHAR szExpect
[] = { 'E','x','p','e','c','t',0 };
108 static const WCHAR szExpires
[] = { 'E','x','p','i','r','e','s',0 };
109 static const WCHAR szIf_Match
[] = { 'I','f','-','M','a','t','c','h',0 };
110 static const WCHAR szIf_Modified_Since
[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
111 static const WCHAR szIf_None_Match
[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
112 static const WCHAR szIf_Range
[] = { 'I','f','-','R','a','n','g','e',0 };
113 static const WCHAR szIf_Unmodified_Since
[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
114 static const WCHAR szLast_Modified
[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
115 static const WCHAR szLocation
[] = { 'L','o','c','a','t','i','o','n',0 };
116 static const WCHAR szMax_Forwards
[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
117 static const WCHAR szMime_Version
[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
118 static const WCHAR szPragma
[] = { 'P','r','a','g','m','a',0 };
119 static const WCHAR szProxy_Authenticate
[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
120 static const WCHAR szProxy_Connection
[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
121 static const WCHAR szPublic
[] = { 'P','u','b','l','i','c',0 };
122 static const WCHAR szRange
[] = { 'R','a','n','g','e',0 };
123 static const WCHAR szReferer
[] = { 'R','e','f','e','r','e','r',0 };
124 static const WCHAR szRetry_After
[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
125 static const WCHAR szServer
[] = { 'S','e','r','v','e','r',0 };
126 static const WCHAR szSet_Cookie
[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
127 static const WCHAR szTransfer_Encoding
[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
128 static const WCHAR szUnless_Modified_Since
[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
129 static const WCHAR szUpgrade
[] = { 'U','p','g','r','a','d','e',0 };
130 static const WCHAR szURI
[] = { 'U','R','I',0 };
131 static const WCHAR szUser_Agent
[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
132 static const WCHAR szVary
[] = { 'V','a','r','y',0 };
133 static const WCHAR szVia
[] = { 'V','i','a',0 };
134 static const WCHAR szWarning
[] = { 'W','a','r','n','i','n','g',0 };
135 static const WCHAR szWWW_Authenticate
[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
137 #define MAXHOSTNAME 100
138 #define MAX_FIELD_VALUE_LEN 256
139 #define MAX_FIELD_LEN 256
141 #define HTTP_REFERER szReferer
142 #define HTTP_ACCEPT szAccept
143 #define HTTP_USERAGENT szUser_Agent
145 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
146 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
147 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
148 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
149 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
150 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
151 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
153 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
164 unsigned int auth_data_len
;
165 BOOL finished
; /* finished authenticating */
169 struct gzip_stream_t
{
179 static BOOL
HTTP_OpenConnection(http_request_t
*req
);
180 static BOOL
HTTP_GetResponseHeaders(http_request_t
*req
, BOOL clear
);
181 static BOOL
HTTP_ProcessHeader(http_request_t
*req
, LPCWSTR field
, LPCWSTR value
, DWORD dwModifier
);
182 static LPWSTR
* HTTP_InterpretHttpHeader(LPCWSTR buffer
);
183 static BOOL
HTTP_InsertCustomHeader(http_request_t
*req
, LPHTTPHEADERW lpHdr
);
184 static INT
HTTP_GetCustomHeaderIndex(http_request_t
*req
, LPCWSTR lpszField
, INT index
, BOOL Request
);
185 static BOOL
HTTP_DeleteCustomHeader(http_request_t
*req
, DWORD index
);
186 static LPWSTR
HTTP_build_req( LPCWSTR
*list
, int len
);
187 static BOOL
HTTP_HttpQueryInfoW(http_request_t
*, DWORD
, LPVOID
, LPDWORD
, LPDWORD
);
188 static LPWSTR
HTTP_GetRedirectURL(http_request_t
*req
, LPCWSTR lpszUrl
);
189 static BOOL
HTTP_HandleRedirect(http_request_t
*req
, LPCWSTR lpszUrl
);
190 static UINT
HTTP_DecodeBase64(LPCWSTR base64
, LPSTR bin
);
191 static BOOL
HTTP_VerifyValidHeader(http_request_t
*req
, LPCWSTR field
);
192 static void HTTP_DrainContent(http_request_t
*req
);
193 static BOOL
HTTP_FinishedReading(http_request_t
*req
);
195 static LPHTTPHEADERW
HTTP_GetHeader(http_request_t
*req
, LPCWSTR head
)
198 HeaderIndex
= HTTP_GetCustomHeaderIndex(req
, head
, 0, TRUE
);
199 if (HeaderIndex
== -1)
202 return &req
->pCustHeaders
[HeaderIndex
];
207 static voidpf
wininet_zalloc(voidpf opaque
, uInt items
, uInt size
)
209 return HeapAlloc(GetProcessHeap(), 0, items
*size
);
212 static void wininet_zfree(voidpf opaque
, voidpf address
)
214 HeapFree(GetProcessHeap(), 0, address
);
217 static void init_gzip_stream(http_request_t
*req
)
219 gzip_stream_t
*gzip_stream
;
222 gzip_stream
= HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t
));
223 gzip_stream
->zstream
.zalloc
= wininet_zalloc
;
224 gzip_stream
->zstream
.zfree
= wininet_zfree
;
225 gzip_stream
->zstream
.opaque
= NULL
;
226 gzip_stream
->zstream
.next_in
= NULL
;
227 gzip_stream
->zstream
.avail_in
= 0;
228 gzip_stream
->zstream
.next_out
= NULL
;
229 gzip_stream
->zstream
.avail_out
= 0;
230 gzip_stream
->buf_pos
= 0;
231 gzip_stream
->buf_size
= 0;
232 gzip_stream
->end_of_data
= FALSE
;
234 zres
= inflateInit2(&gzip_stream
->zstream
, 0x1f);
236 ERR("inflateInit failed: %d\n", zres
);
237 HeapFree(GetProcessHeap(), 0, gzip_stream
);
241 req
->gzip_stream
= gzip_stream
;
246 static void init_gzip_stream(http_request_t
*req
)
248 ERR("gzip stream not supported, missing zlib.\n");
253 /* set the request content length based on the headers */
254 static DWORD
set_content_length( http_request_t
*lpwhr
)
256 static const WCHAR szChunked
[] = {'c','h','u','n','k','e','d',0};
260 size
= sizeof(lpwhr
->dwContentLength
);
261 if (!HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_FLAG_NUMBER
|HTTP_QUERY_CONTENT_LENGTH
,
262 &lpwhr
->dwContentLength
, &size
, NULL
))
263 lpwhr
->dwContentLength
= ~0u;
265 size
= sizeof(encoding
);
266 if (HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_TRANSFER_ENCODING
, encoding
, &size
, NULL
) &&
267 !strcmpiW(encoding
, szChunked
))
269 lpwhr
->dwContentLength
= ~0u;
270 lpwhr
->read_chunked
= TRUE
;
273 if(lpwhr
->decoding
) {
276 static const WCHAR gzipW
[] = {'g','z','i','p',0};
278 encoding_idx
= HTTP_GetCustomHeaderIndex(lpwhr
, szContent_Encoding
, 0, FALSE
);
279 if(encoding_idx
!= -1 && !strcmpiW(lpwhr
->pCustHeaders
[encoding_idx
].lpszValue
, gzipW
))
280 init_gzip_stream(lpwhr
);
283 return lpwhr
->dwContentLength
;
286 /***********************************************************************
287 * HTTP_Tokenize (internal)
289 * Tokenize a string, allocating memory for the tokens.
291 static LPWSTR
* HTTP_Tokenize(LPCWSTR string
, LPCWSTR token_string
)
293 LPWSTR
* token_array
;
300 /* empty string has no tokens */
304 for (i
= 0; string
[i
]; i
++)
306 if (!strncmpW(string
+i
, token_string
, strlenW(token_string
)))
310 /* we want to skip over separators, but not the null terminator */
311 for (j
= 0; j
< strlenW(token_string
) - 1; j
++)
319 /* add 1 for terminating NULL */
320 token_array
= HeapAlloc(GetProcessHeap(), 0, (tokens
+1) * sizeof(*token_array
));
321 token_array
[tokens
] = NULL
;
324 for (i
= 0; i
< tokens
; i
++)
327 next_token
= strstrW(string
, token_string
);
328 if (!next_token
) next_token
= string
+strlenW(string
);
329 len
= next_token
- string
;
330 token_array
[i
] = HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
331 memcpy(token_array
[i
], string
, len
*sizeof(WCHAR
));
332 token_array
[i
][len
] = '\0';
333 string
= next_token
+strlenW(token_string
);
338 /***********************************************************************
339 * HTTP_FreeTokens (internal)
341 * Frees memory returned from HTTP_Tokenize.
343 static void HTTP_FreeTokens(LPWSTR
* token_array
)
346 for (i
= 0; token_array
[i
]; i
++)
347 HeapFree(GetProcessHeap(), 0, token_array
[i
]);
348 HeapFree(GetProcessHeap(), 0, token_array
);
351 /* **********************************************************************
353 * Helper functions for the HttpSendRequest(Ex) functions
356 static void AsyncHttpSendRequestProc(WORKREQUEST
*workRequest
)
358 struct WORKREQ_HTTPSENDREQUESTW
const *req
= &workRequest
->u
.HttpSendRequestW
;
359 http_request_t
*lpwhr
= (http_request_t
*) workRequest
->hdr
;
361 TRACE("%p\n", lpwhr
);
363 HTTP_HttpSendRequestW(lpwhr
, req
->lpszHeader
,
364 req
->dwHeaderLength
, req
->lpOptional
, req
->dwOptionalLength
,
365 req
->dwContentLength
, req
->bEndRequest
);
367 HeapFree(GetProcessHeap(), 0, req
->lpszHeader
);
370 static void HTTP_FixURL(http_request_t
*lpwhr
)
372 static const WCHAR szSlash
[] = { '/',0 };
373 static const WCHAR szHttp
[] = { 'h','t','t','p',':','/','/', 0 };
375 /* If we don't have a path we set it to root */
376 if (NULL
== lpwhr
->lpszPath
)
377 lpwhr
->lpszPath
= heap_strdupW(szSlash
);
378 else /* remove \r and \n*/
380 int nLen
= strlenW(lpwhr
->lpszPath
);
381 while ((nLen
>0 ) && ((lpwhr
->lpszPath
[nLen
-1] == '\r')||(lpwhr
->lpszPath
[nLen
-1] == '\n')))
384 lpwhr
->lpszPath
[nLen
]='\0';
386 /* Replace '\' with '/' */
389 if (lpwhr
->lpszPath
[nLen
] == '\\') lpwhr
->lpszPath
[nLen
]='/';
393 if(CSTR_EQUAL
!= CompareStringW( LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
,
394 lpwhr
->lpszPath
, strlenW(lpwhr
->lpszPath
), szHttp
, strlenW(szHttp
) )
395 && lpwhr
->lpszPath
[0] != '/') /* not an absolute path ?? --> fix it !! */
397 WCHAR
*fixurl
= HeapAlloc(GetProcessHeap(), 0,
398 (strlenW(lpwhr
->lpszPath
) + 2)*sizeof(WCHAR
));
400 strcpyW(fixurl
+ 1, lpwhr
->lpszPath
);
401 HeapFree( GetProcessHeap(), 0, lpwhr
->lpszPath
);
402 lpwhr
->lpszPath
= fixurl
;
406 static LPWSTR
HTTP_BuildHeaderRequestString( http_request_t
*lpwhr
, LPCWSTR verb
, LPCWSTR path
, LPCWSTR version
)
408 LPWSTR requestString
;
414 static const WCHAR szSpace
[] = { ' ',0 };
415 static const WCHAR szColon
[] = { ':',' ',0 };
416 static const WCHAR sztwocrlf
[] = {'\r','\n','\r','\n', 0};
418 /* allocate space for an array of all the string pointers to be added */
419 len
= (lpwhr
->nCustHeaders
)*4 + 10;
420 req
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(LPCWSTR
) );
422 /* add the verb, path and HTTP version string */
430 /* Append custom request headers */
431 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
433 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
436 req
[n
++] = lpwhr
->pCustHeaders
[i
].lpszField
;
438 req
[n
++] = lpwhr
->pCustHeaders
[i
].lpszValue
;
440 TRACE("Adding custom header %s (%s)\n",
441 debugstr_w(lpwhr
->pCustHeaders
[i
].lpszField
),
442 debugstr_w(lpwhr
->pCustHeaders
[i
].lpszValue
));
447 ERR("oops. buffer overrun\n");
450 requestString
= HTTP_build_req( req
, 4 );
451 HeapFree( GetProcessHeap(), 0, req
);
454 * Set (header) termination string for request
455 * Make sure there's exactly two new lines at the end of the request
457 p
= &requestString
[strlenW(requestString
)-1];
458 while ( (*p
== '\n') || (*p
== '\r') )
460 strcpyW( p
+1, sztwocrlf
);
462 return requestString
;
465 static void HTTP_ProcessCookies( http_request_t
*lpwhr
)
469 LPHTTPHEADERW setCookieHeader
;
471 while((HeaderIndex
= HTTP_GetCustomHeaderIndex(lpwhr
, szSet_Cookie
, numCookies
, FALSE
)) != -1)
473 setCookieHeader
= &lpwhr
->pCustHeaders
[HeaderIndex
];
475 if (!(lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_NO_COOKIES
) && setCookieHeader
->lpszValue
)
478 static const WCHAR szFmt
[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
482 Host
= HTTP_GetHeader(lpwhr
, hostW
);
483 len
= lstrlenW(Host
->lpszValue
) + 9 + lstrlenW(lpwhr
->lpszPath
);
484 buf_url
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
485 sprintfW(buf_url
, szFmt
, Host
->lpszValue
, lpwhr
->lpszPath
);
486 InternetSetCookieW(buf_url
, NULL
, setCookieHeader
->lpszValue
);
488 HeapFree(GetProcessHeap(), 0, buf_url
);
494 static inline BOOL
is_basic_auth_value( LPCWSTR pszAuthValue
)
496 static const WCHAR szBasic
[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
497 return !strncmpiW(pszAuthValue
, szBasic
, ARRAYSIZE(szBasic
)) &&
498 ((pszAuthValue
[ARRAYSIZE(szBasic
)] == ' ') || !pszAuthValue
[ARRAYSIZE(szBasic
)]);
501 static BOOL
HTTP_DoAuthorization( http_request_t
*lpwhr
, LPCWSTR pszAuthValue
,
502 struct HttpAuthInfo
**ppAuthInfo
,
503 LPWSTR domain_and_username
, LPWSTR password
)
505 SECURITY_STATUS sec_status
;
506 struct HttpAuthInfo
*pAuthInfo
= *ppAuthInfo
;
509 TRACE("%s\n", debugstr_w(pszAuthValue
));
516 pAuthInfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo
));
520 SecInvalidateHandle(&pAuthInfo
->cred
);
521 SecInvalidateHandle(&pAuthInfo
->ctx
);
522 memset(&pAuthInfo
->exp
, 0, sizeof(pAuthInfo
->exp
));
524 pAuthInfo
->auth_data
= NULL
;
525 pAuthInfo
->auth_data_len
= 0;
526 pAuthInfo
->finished
= FALSE
;
528 if (is_basic_auth_value(pszAuthValue
))
530 static const WCHAR szBasic
[] = {'B','a','s','i','c',0};
531 pAuthInfo
->scheme
= heap_strdupW(szBasic
);
532 if (!pAuthInfo
->scheme
)
534 HeapFree(GetProcessHeap(), 0, pAuthInfo
);
541 SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity
;
543 pAuthInfo
->scheme
= heap_strdupW(pszAuthValue
);
544 if (!pAuthInfo
->scheme
)
546 HeapFree(GetProcessHeap(), 0, pAuthInfo
);
550 if (domain_and_username
)
552 WCHAR
*user
= strchrW(domain_and_username
, '\\');
553 WCHAR
*domain
= domain_and_username
;
555 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
557 pAuthData
= &nt_auth_identity
;
562 user
= domain_and_username
;
566 nt_auth_identity
.Flags
= SEC_WINNT_AUTH_IDENTITY_UNICODE
;
567 nt_auth_identity
.User
= user
;
568 nt_auth_identity
.UserLength
= strlenW(nt_auth_identity
.User
);
569 nt_auth_identity
.Domain
= domain
;
570 nt_auth_identity
.DomainLength
= domain
? user
- domain
- 1 : 0;
571 nt_auth_identity
.Password
= password
;
572 nt_auth_identity
.PasswordLength
= strlenW(nt_auth_identity
.Password
);
575 /* use default credentials */
578 sec_status
= AcquireCredentialsHandleW(NULL
, pAuthInfo
->scheme
,
579 SECPKG_CRED_OUTBOUND
, NULL
,
581 NULL
, &pAuthInfo
->cred
,
583 if (sec_status
== SEC_E_OK
)
585 PSecPkgInfoW sec_pkg_info
;
586 sec_status
= QuerySecurityPackageInfoW(pAuthInfo
->scheme
, &sec_pkg_info
);
587 if (sec_status
== SEC_E_OK
)
589 pAuthInfo
->max_token
= sec_pkg_info
->cbMaxToken
;
590 FreeContextBuffer(sec_pkg_info
);
593 if (sec_status
!= SEC_E_OK
)
595 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
596 debugstr_w(pAuthInfo
->scheme
), sec_status
);
597 HeapFree(GetProcessHeap(), 0, pAuthInfo
->scheme
);
598 HeapFree(GetProcessHeap(), 0, pAuthInfo
);
602 *ppAuthInfo
= pAuthInfo
;
604 else if (pAuthInfo
->finished
)
607 if ((strlenW(pszAuthValue
) < strlenW(pAuthInfo
->scheme
)) ||
608 strncmpiW(pszAuthValue
, pAuthInfo
->scheme
, strlenW(pAuthInfo
->scheme
)))
610 ERR("authentication scheme changed from %s to %s\n",
611 debugstr_w(pAuthInfo
->scheme
), debugstr_w(pszAuthValue
));
615 if (is_basic_auth_value(pszAuthValue
))
621 TRACE("basic authentication\n");
623 /* we don't cache credentials for basic authentication, so we can't
624 * retrieve them if the application didn't pass us any credentials */
625 if (!domain_and_username
) return FALSE
;
627 userlen
= WideCharToMultiByte(CP_UTF8
, 0, domain_and_username
, lstrlenW(domain_and_username
), NULL
, 0, NULL
, NULL
);
628 passlen
= WideCharToMultiByte(CP_UTF8
, 0, password
, lstrlenW(password
), NULL
, 0, NULL
, NULL
);
630 /* length includes a nul terminator, which will be re-used for the ':' */
631 auth_data
= HeapAlloc(GetProcessHeap(), 0, userlen
+ 1 + passlen
);
635 WideCharToMultiByte(CP_UTF8
, 0, domain_and_username
, -1, auth_data
, userlen
, NULL
, NULL
);
636 auth_data
[userlen
] = ':';
637 WideCharToMultiByte(CP_UTF8
, 0, password
, -1, &auth_data
[userlen
+1], passlen
, NULL
, NULL
);
639 pAuthInfo
->auth_data
= auth_data
;
640 pAuthInfo
->auth_data_len
= userlen
+ 1 + passlen
;
641 pAuthInfo
->finished
= TRUE
;
648 SecBufferDesc out_desc
, in_desc
;
650 unsigned char *buffer
;
651 ULONG context_req
= ISC_REQ_CONNECTION
| ISC_REQ_USE_DCE_STYLE
|
652 ISC_REQ_MUTUAL_AUTH
| ISC_REQ_DELEGATE
;
654 in
.BufferType
= SECBUFFER_TOKEN
;
658 in_desc
.ulVersion
= 0;
659 in_desc
.cBuffers
= 1;
660 in_desc
.pBuffers
= &in
;
662 pszAuthData
= pszAuthValue
+ strlenW(pAuthInfo
->scheme
);
663 if (*pszAuthData
== ' ')
666 in
.cbBuffer
= HTTP_DecodeBase64(pszAuthData
, NULL
);
667 in
.pvBuffer
= HeapAlloc(GetProcessHeap(), 0, in
.cbBuffer
);
668 HTTP_DecodeBase64(pszAuthData
, in
.pvBuffer
);
671 buffer
= HeapAlloc(GetProcessHeap(), 0, pAuthInfo
->max_token
);
673 out
.BufferType
= SECBUFFER_TOKEN
;
674 out
.cbBuffer
= pAuthInfo
->max_token
;
675 out
.pvBuffer
= buffer
;
677 out_desc
.ulVersion
= 0;
678 out_desc
.cBuffers
= 1;
679 out_desc
.pBuffers
= &out
;
681 sec_status
= InitializeSecurityContextW(first
? &pAuthInfo
->cred
: NULL
,
682 first
? NULL
: &pAuthInfo
->ctx
,
683 first
? lpwhr
->lpHttpSession
->lpszServerName
: NULL
,
684 context_req
, 0, SECURITY_NETWORK_DREP
,
685 in
.pvBuffer
? &in_desc
: NULL
,
686 0, &pAuthInfo
->ctx
, &out_desc
,
687 &pAuthInfo
->attr
, &pAuthInfo
->exp
);
688 if (sec_status
== SEC_E_OK
)
690 pAuthInfo
->finished
= TRUE
;
691 pAuthInfo
->auth_data
= out
.pvBuffer
;
692 pAuthInfo
->auth_data_len
= out
.cbBuffer
;
693 TRACE("sending last auth packet\n");
695 else if (sec_status
== SEC_I_CONTINUE_NEEDED
)
697 pAuthInfo
->auth_data
= out
.pvBuffer
;
698 pAuthInfo
->auth_data_len
= out
.cbBuffer
;
699 TRACE("sending next auth packet\n");
703 ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status
);
704 pAuthInfo
->finished
= TRUE
;
705 HeapFree(GetProcessHeap(), 0, out
.pvBuffer
);
713 /***********************************************************************
714 * HTTP_HttpAddRequestHeadersW (internal)
716 static BOOL
HTTP_HttpAddRequestHeadersW(http_request_t
*lpwhr
,
717 LPCWSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
722 BOOL bSuccess
= FALSE
;
725 TRACE("copying header: %s\n", debugstr_wn(lpszHeader
, dwHeaderLength
));
727 if( dwHeaderLength
== ~0U )
728 len
= strlenW(lpszHeader
);
730 len
= dwHeaderLength
;
731 buffer
= HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR
)*(len
+1) );
732 lstrcpynW( buffer
, lpszHeader
, len
+ 1);
738 LPWSTR
* pFieldAndValue
;
742 while (*lpszEnd
!= '\0')
744 if (*lpszEnd
== '\r' || *lpszEnd
== '\n')
749 if (*lpszStart
== '\0')
752 if (*lpszEnd
== '\r' || *lpszEnd
== '\n')
755 lpszEnd
++; /* Jump over newline */
757 TRACE("interpreting header %s\n", debugstr_w(lpszStart
));
758 if (*lpszStart
== '\0')
760 /* Skip 0-length headers */
765 pFieldAndValue
= HTTP_InterpretHttpHeader(lpszStart
);
768 bSuccess
= HTTP_VerifyValidHeader(lpwhr
, pFieldAndValue
[0]);
770 bSuccess
= HTTP_ProcessHeader(lpwhr
, pFieldAndValue
[0],
771 pFieldAndValue
[1], dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
772 HTTP_FreeTokens(pFieldAndValue
);
778 HeapFree(GetProcessHeap(), 0, buffer
);
783 /***********************************************************************
784 * HttpAddRequestHeadersW (WININET.@)
786 * Adds one or more HTTP header to the request handler
789 * On Windows if dwHeaderLength includes the trailing '\0', then
790 * HttpAddRequestHeadersW() adds it too. However this results in an
791 * invalid Http header which is rejected by some servers so we probably
792 * don't need to match Windows on that point.
799 BOOL WINAPI
HttpAddRequestHeadersW(HINTERNET hHttpRequest
,
800 LPCWSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
802 BOOL bSuccess
= FALSE
;
803 http_request_t
*lpwhr
;
805 TRACE("%p, %s, %i, %i\n", hHttpRequest
, debugstr_wn(lpszHeader
, dwHeaderLength
), dwHeaderLength
, dwModifier
);
810 lpwhr
= (http_request_t
*) WININET_GetObject( hHttpRequest
);
811 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
813 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
816 bSuccess
= HTTP_HttpAddRequestHeadersW( lpwhr
, lpszHeader
, dwHeaderLength
, dwModifier
);
819 WININET_Release( &lpwhr
->hdr
);
824 /***********************************************************************
825 * HttpAddRequestHeadersA (WININET.@)
827 * Adds one or more HTTP header to the request handler
834 BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
835 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
841 TRACE("%p, %s, %i, %i\n", hHttpRequest
, debugstr_an(lpszHeader
, dwHeaderLength
), dwHeaderLength
, dwModifier
);
843 len
= MultiByteToWideChar( CP_ACP
, 0, lpszHeader
, dwHeaderLength
, NULL
, 0 );
844 hdr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
845 MultiByteToWideChar( CP_ACP
, 0, lpszHeader
, dwHeaderLength
, hdr
, len
);
846 if( dwHeaderLength
!= ~0U )
847 dwHeaderLength
= len
;
849 r
= HttpAddRequestHeadersW( hHttpRequest
, hdr
, dwHeaderLength
, dwModifier
);
851 HeapFree( GetProcessHeap(), 0, hdr
);
856 /***********************************************************************
857 * HttpEndRequestA (WININET.@)
859 * Ends an HTTP request that was started by HttpSendRequestEx
866 BOOL WINAPI
HttpEndRequestA(HINTERNET hRequest
,
867 LPINTERNET_BUFFERSA lpBuffersOut
, DWORD dwFlags
, DWORD_PTR dwContext
)
869 TRACE("(%p, %p, %08x, %08lx)\n", hRequest
, lpBuffersOut
, dwFlags
, dwContext
);
873 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
877 return HttpEndRequestW(hRequest
, NULL
, dwFlags
, dwContext
);
880 static BOOL
HTTP_HttpEndRequestW(http_request_t
*lpwhr
, DWORD dwFlags
, DWORD_PTR dwContext
)
885 INTERNET_ASYNC_RESULT iar
;
887 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
888 INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
890 responseLen
= HTTP_GetResponseHeaders(lpwhr
, TRUE
);
894 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
895 INTERNET_STATUS_RESPONSE_RECEIVED
, &responseLen
, sizeof(DWORD
));
897 /* process cookies here. Is this right? */
898 HTTP_ProcessCookies(lpwhr
);
900 if (!set_content_length( lpwhr
)) HTTP_FinishedReading(lpwhr
);
902 if (!(lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_NO_AUTO_REDIRECT
))
904 DWORD dwCode
,dwCodeLength
= sizeof(DWORD
);
905 if (HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_FLAG_NUMBER
|HTTP_QUERY_STATUS_CODE
, &dwCode
, &dwCodeLength
, NULL
) &&
906 (dwCode
== 302 || dwCode
== 301 || dwCode
== 303))
908 WCHAR
*new_url
, szNewLocation
[INTERNET_MAX_URL_LENGTH
];
909 dwBufferSize
=sizeof(szNewLocation
);
910 if (HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_LOCATION
, szNewLocation
, &dwBufferSize
, NULL
))
912 /* redirects are always GETs */
913 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
914 lpwhr
->lpszVerb
= heap_strdupW(szGET
);
915 HTTP_DrainContent(lpwhr
);
916 if ((new_url
= HTTP_GetRedirectURL( lpwhr
, szNewLocation
)))
918 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REDIRECT
,
919 new_url
, (strlenW(new_url
) + 1) * sizeof(WCHAR
));
920 rc
= HTTP_HandleRedirect(lpwhr
, new_url
);
922 rc
= HTTP_HttpSendRequestW(lpwhr
, NULL
, 0, NULL
, 0, 0, TRUE
);
923 HeapFree( GetProcessHeap(), 0, new_url
);
929 iar
.dwResult
= (DWORD_PTR
)lpwhr
->hdr
.hInternet
;
930 iar
.dwError
= rc
? 0 : INTERNET_GetLastError();
932 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
933 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
934 sizeof(INTERNET_ASYNC_RESULT
));
938 static void AsyncHttpEndRequestProc(WORKREQUEST
*work
)
940 struct WORKREQ_HTTPENDREQUESTW
const *req
= &work
->u
.HttpEndRequestW
;
941 http_request_t
*lpwhr
= (http_request_t
*)work
->hdr
;
943 TRACE("%p\n", lpwhr
);
945 HTTP_HttpEndRequestW(lpwhr
, req
->dwFlags
, req
->dwContext
);
948 /***********************************************************************
949 * HttpEndRequestW (WININET.@)
951 * Ends an HTTP request that was started by HttpSendRequestEx
958 BOOL WINAPI
HttpEndRequestW(HINTERNET hRequest
,
959 LPINTERNET_BUFFERSW lpBuffersOut
, DWORD dwFlags
, DWORD_PTR dwContext
)
962 http_request_t
*lpwhr
;
968 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
972 lpwhr
= (http_request_t
*) WININET_GetObject( hRequest
);
974 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
976 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
978 WININET_Release( &lpwhr
->hdr
);
981 lpwhr
->hdr
.dwFlags
|= dwFlags
;
983 if (lpwhr
->lpHttpSession
->lpAppInfo
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
986 struct WORKREQ_HTTPENDREQUESTW
*request
;
988 work
.asyncproc
= AsyncHttpEndRequestProc
;
989 work
.hdr
= WININET_AddRef( &lpwhr
->hdr
);
991 request
= &work
.u
.HttpEndRequestW
;
992 request
->dwFlags
= dwFlags
;
993 request
->dwContext
= dwContext
;
995 INTERNET_AsyncCall(&work
);
996 INTERNET_SetLastError(ERROR_IO_PENDING
);
999 rc
= HTTP_HttpEndRequestW(lpwhr
, dwFlags
, dwContext
);
1001 WININET_Release( &lpwhr
->hdr
);
1002 TRACE("%i <--\n",rc
);
1006 /***********************************************************************
1007 * HttpOpenRequestW (WININET.@)
1009 * Open a HTTP request handle
1012 * HINTERNET a HTTP request handle on success
1016 HINTERNET WINAPI
HttpOpenRequestW(HINTERNET hHttpSession
,
1017 LPCWSTR lpszVerb
, LPCWSTR lpszObjectName
, LPCWSTR lpszVersion
,
1018 LPCWSTR lpszReferrer
, LPCWSTR
*lpszAcceptTypes
,
1019 DWORD dwFlags
, DWORD_PTR dwContext
)
1021 http_session_t
*lpwhs
;
1022 HINTERNET handle
= NULL
;
1024 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession
,
1025 debugstr_w(lpszVerb
), debugstr_w(lpszObjectName
),
1026 debugstr_w(lpszVersion
), debugstr_w(lpszReferrer
), lpszAcceptTypes
,
1027 dwFlags
, dwContext
);
1028 if(lpszAcceptTypes
!=NULL
)
1031 for(i
=0;lpszAcceptTypes
[i
]!=NULL
;i
++)
1032 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes
[i
]));
1035 lpwhs
= (http_session_t
*) WININET_GetObject( hHttpSession
);
1036 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
1038 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1043 * My tests seem to show that the windows version does not
1044 * become asynchronous until after this point. And anyhow
1045 * if this call was asynchronous then how would you get the
1046 * necessary HINTERNET pointer returned by this function.
1049 handle
= HTTP_HttpOpenRequestW(lpwhs
, lpszVerb
, lpszObjectName
,
1050 lpszVersion
, lpszReferrer
, lpszAcceptTypes
,
1051 dwFlags
, dwContext
);
1054 WININET_Release( &lpwhs
->hdr
);
1055 TRACE("returning %p\n", handle
);
1060 /***********************************************************************
1061 * HttpOpenRequestA (WININET.@)
1063 * Open a HTTP request handle
1066 * HINTERNET a HTTP request handle on success
1070 HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
1071 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
1072 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
1073 DWORD dwFlags
, DWORD_PTR dwContext
)
1075 LPWSTR szVerb
= NULL
, szObjectName
= NULL
;
1076 LPWSTR szVersion
= NULL
, szReferrer
= NULL
, *szAcceptTypes
= NULL
;
1077 INT acceptTypesCount
;
1078 HINTERNET rc
= FALSE
;
1081 TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession
,
1082 debugstr_a(lpszVerb
), debugstr_a(lpszObjectName
),
1083 debugstr_a(lpszVersion
), debugstr_a(lpszReferrer
), lpszAcceptTypes
,
1084 dwFlags
, dwContext
);
1088 szVerb
= heap_strdupAtoW(lpszVerb
);
1095 szObjectName
= heap_strdupAtoW(lpszObjectName
);
1096 if ( !szObjectName
)
1102 szVersion
= heap_strdupAtoW(lpszVersion
);
1109 szReferrer
= heap_strdupAtoW(lpszReferrer
);
1114 if (lpszAcceptTypes
)
1116 acceptTypesCount
= 0;
1117 types
= lpszAcceptTypes
;
1122 /* find out how many there are */
1123 if (*types
&& **types
)
1125 TRACE("accept type: %s\n", debugstr_a(*types
));
1131 WARN("invalid accept type pointer\n");
1136 szAcceptTypes
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
*) * (acceptTypesCount
+1));
1137 if (!szAcceptTypes
) goto end
;
1139 acceptTypesCount
= 0;
1140 types
= lpszAcceptTypes
;
1145 if (*types
&& **types
)
1146 szAcceptTypes
[acceptTypesCount
++] = heap_strdupAtoW(*types
);
1150 /* ignore invalid pointer */
1155 szAcceptTypes
[acceptTypesCount
] = NULL
;
1158 rc
= HttpOpenRequestW(hHttpSession
, szVerb
, szObjectName
,
1159 szVersion
, szReferrer
,
1160 (LPCWSTR
*)szAcceptTypes
, dwFlags
, dwContext
);
1165 acceptTypesCount
= 0;
1166 while (szAcceptTypes
[acceptTypesCount
])
1168 HeapFree(GetProcessHeap(), 0, szAcceptTypes
[acceptTypesCount
]);
1171 HeapFree(GetProcessHeap(), 0, szAcceptTypes
);
1173 HeapFree(GetProcessHeap(), 0, szReferrer
);
1174 HeapFree(GetProcessHeap(), 0, szVersion
);
1175 HeapFree(GetProcessHeap(), 0, szObjectName
);
1176 HeapFree(GetProcessHeap(), 0, szVerb
);
1181 /***********************************************************************
1184 static UINT
HTTP_EncodeBase64( LPCSTR bin
, unsigned int len
, LPWSTR base64
)
1187 static const CHAR HTTP_Base64Enc
[] =
1188 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1192 /* first 6 bits, all from bin[0] */
1193 base64
[n
++] = HTTP_Base64Enc
[(bin
[0] & 0xfc) >> 2];
1194 x
= (bin
[0] & 3) << 4;
1196 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
1199 base64
[n
++] = HTTP_Base64Enc
[x
];
1204 base64
[n
++] = HTTP_Base64Enc
[ x
| ( (bin
[1]&0xf0) >> 4 ) ];
1205 x
= ( bin
[1] & 0x0f ) << 2;
1207 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1210 base64
[n
++] = HTTP_Base64Enc
[x
];
1214 base64
[n
++] = HTTP_Base64Enc
[ x
| ( (bin
[2]&0xc0 ) >> 6 ) ];
1216 /* last 6 bits, all from bin [2] */
1217 base64
[n
++] = HTTP_Base64Enc
[ bin
[2] & 0x3f ];
1225 #define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \
1226 ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \
1227 ((x) >= '0' && (x) <= '9') ? (x) - '0' + 52 : \
1228 ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1)
1229 static const signed char HTTP_Base64Dec
[256] =
1231 CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9),
1232 CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19),
1233 CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29),
1234 CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39),
1235 CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49),
1236 CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59),
1237 CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69),
1238 CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79),
1239 CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89),
1240 CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99),
1241 CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109),
1242 CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119),
1243 CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129),
1244 CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139),
1245 CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149),
1246 CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159),
1247 CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169),
1248 CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179),
1249 CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189),
1250 CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199),
1251 CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209),
1252 CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219),
1253 CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229),
1254 CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239),
1255 CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249),
1256 CH(250),CH(251),CH(252),CH(253),CH(254),CH(255),
1260 /***********************************************************************
1263 static UINT
HTTP_DecodeBase64( LPCWSTR base64
, LPSTR bin
)
1271 if (base64
[0] >= ARRAYSIZE(HTTP_Base64Dec
) ||
1272 ((in
[0] = HTTP_Base64Dec
[base64
[0]]) == -1) ||
1273 base64
[1] >= ARRAYSIZE(HTTP_Base64Dec
) ||
1274 ((in
[1] = HTTP_Base64Dec
[base64
[1]]) == -1))
1276 WARN("invalid base64: %s\n", debugstr_w(base64
));
1280 bin
[n
] = (unsigned char) (in
[0] << 2 | in
[1] >> 4);
1283 if ((base64
[2] == '=') && (base64
[3] == '='))
1285 if (base64
[2] > ARRAYSIZE(HTTP_Base64Dec
) ||
1286 ((in
[2] = HTTP_Base64Dec
[base64
[2]]) == -1))
1288 WARN("invalid base64: %s\n", debugstr_w(&base64
[2]));
1292 bin
[n
] = (unsigned char) (in
[1] << 4 | in
[2] >> 2);
1295 if (base64
[3] == '=')
1297 if (base64
[3] > ARRAYSIZE(HTTP_Base64Dec
) ||
1298 ((in
[3] = HTTP_Base64Dec
[base64
[3]]) == -1))
1300 WARN("invalid base64: %s\n", debugstr_w(&base64
[3]));
1304 bin
[n
] = (unsigned char) (((in
[2] << 6) & 0xc0) | in
[3]);
1313 /***********************************************************************
1314 * HTTP_InsertAuthorization
1316 * Insert or delete the authorization field in the request header.
1318 static BOOL
HTTP_InsertAuthorization( http_request_t
*lpwhr
, struct HttpAuthInfo
*pAuthInfo
, LPCWSTR header
)
1322 static const WCHAR wszSpace
[] = {' ',0};
1323 static const WCHAR wszBasic
[] = {'B','a','s','i','c',0};
1325 WCHAR
*authorization
= NULL
;
1327 if (pAuthInfo
->auth_data_len
)
1329 /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1330 len
= strlenW(pAuthInfo
->scheme
)+1+((pAuthInfo
->auth_data_len
+2)*4)/3;
1331 authorization
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
1335 strcpyW(authorization
, pAuthInfo
->scheme
);
1336 strcatW(authorization
, wszSpace
);
1337 HTTP_EncodeBase64(pAuthInfo
->auth_data
,
1338 pAuthInfo
->auth_data_len
,
1339 authorization
+strlenW(authorization
));
1341 /* clear the data as it isn't valid now that it has been sent to the
1342 * server, unless it's Basic authentication which doesn't do
1343 * connection tracking */
1344 if (strcmpiW(pAuthInfo
->scheme
, wszBasic
))
1346 HeapFree(GetProcessHeap(), 0, pAuthInfo
->auth_data
);
1347 pAuthInfo
->auth_data
= NULL
;
1348 pAuthInfo
->auth_data_len
= 0;
1352 TRACE("Inserting authorization: %s\n", debugstr_w(authorization
));
1354 HTTP_ProcessHeader(lpwhr
, header
, authorization
, HTTP_ADDHDR_FLAG_REQ
| HTTP_ADDHDR_FLAG_REPLACE
);
1356 HeapFree(GetProcessHeap(), 0, authorization
);
1361 static WCHAR
*HTTP_BuildProxyRequestUrl(http_request_t
*req
)
1363 WCHAR new_location
[INTERNET_MAX_URL_LENGTH
], *url
;
1366 size
= sizeof(new_location
);
1367 if (HTTP_HttpQueryInfoW(req
, HTTP_QUERY_LOCATION
, new_location
, &size
, NULL
))
1369 if (!(url
= HeapAlloc( GetProcessHeap(), 0, size
+ sizeof(WCHAR
) ))) return NULL
;
1370 strcpyW( url
, new_location
);
1374 static const WCHAR slash
[] = { '/',0 };
1375 static const WCHAR format
[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
1376 static const WCHAR formatSSL
[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 };
1377 http_session_t
*session
= req
->lpHttpSession
;
1379 size
= 16; /* "https://" + sizeof(port#) + ":/\0" */
1380 size
+= strlenW( session
->lpszHostName
) + strlenW( req
->lpszPath
);
1382 if (!(url
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return NULL
;
1384 if (req
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
)
1385 sprintfW( url
, formatSSL
, session
->lpszHostName
, session
->nHostPort
);
1387 sprintfW( url
, format
, session
->lpszHostName
, session
->nHostPort
);
1388 if (req
->lpszPath
[0] != '/') strcatW( url
, slash
);
1389 strcatW( url
, req
->lpszPath
);
1391 TRACE("url=%s\n", debugstr_w(url
));
1395 /***********************************************************************
1396 * HTTP_DealWithProxy
1398 static BOOL
HTTP_DealWithProxy(appinfo_t
*hIC
, http_session_t
*lpwhs
, http_request_t
*lpwhr
)
1400 WCHAR buf
[MAXHOSTNAME
];
1401 WCHAR proxy
[MAXHOSTNAME
+ 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
1402 static WCHAR szNul
[] = { 0 };
1403 URL_COMPONENTSW UrlComponents
;
1404 static const WCHAR szHttp
[] = { 'h','t','t','p',':','/','/',0 };
1405 static const WCHAR szFormat
[] = { 'h','t','t','p',':','/','/','%','s',0 };
1407 memset( &UrlComponents
, 0, sizeof UrlComponents
);
1408 UrlComponents
.dwStructSize
= sizeof UrlComponents
;
1409 UrlComponents
.lpszHostName
= buf
;
1410 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
1412 if( CSTR_EQUAL
!= CompareStringW(LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
,
1413 hIC
->lpszProxy
,strlenW(szHttp
),szHttp
,strlenW(szHttp
)) )
1414 sprintfW(proxy
, szFormat
, hIC
->lpszProxy
);
1416 strcpyW(proxy
, hIC
->lpszProxy
);
1417 if( !InternetCrackUrlW(proxy
, 0, 0, &UrlComponents
) )
1419 if( UrlComponents
.dwHostNameLength
== 0 )
1422 if( !lpwhr
->lpszPath
)
1423 lpwhr
->lpszPath
= szNul
;
1425 if(UrlComponents
.nPort
== INTERNET_INVALID_PORT_NUMBER
)
1426 UrlComponents
.nPort
= INTERNET_DEFAULT_HTTP_PORT
;
1428 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1429 lpwhs
->lpszServerName
= heap_strdupW(UrlComponents
.lpszHostName
);
1430 lpwhs
->nServerPort
= UrlComponents
.nPort
;
1432 TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs
->lpszServerName
), lpwhs
->nServerPort
);
1436 #ifndef INET6_ADDRSTRLEN
1437 #define INET6_ADDRSTRLEN 46
1440 static BOOL
HTTP_ResolveName(http_request_t
*lpwhr
)
1442 char szaddr
[INET6_ADDRSTRLEN
];
1443 http_session_t
*lpwhs
= lpwhr
->lpHttpSession
;
1446 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
1447 INTERNET_STATUS_RESOLVING_NAME
,
1448 lpwhs
->lpszServerName
,
1449 strlenW(lpwhs
->lpszServerName
)+1);
1451 lpwhs
->sa_len
= sizeof(lpwhs
->socketAddress
);
1452 if (!GetAddress(lpwhs
->lpszServerName
, lpwhs
->nServerPort
,
1453 (struct sockaddr
*)&lpwhs
->socketAddress
, &lpwhs
->sa_len
))
1455 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1459 switch (lpwhs
->socketAddress
.ss_family
)
1462 addr
= &((struct sockaddr_in
*)&lpwhs
->socketAddress
)->sin_addr
;
1465 addr
= &((struct sockaddr_in6
*)&lpwhs
->socketAddress
)->sin6_addr
;
1468 WARN("unsupported family %d\n", lpwhs
->socketAddress
.ss_family
);
1469 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1472 inet_ntop(lpwhs
->socketAddress
.ss_family
, addr
, szaddr
, sizeof(szaddr
));
1473 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
1474 INTERNET_STATUS_NAME_RESOLVED
,
1475 szaddr
, strlen(szaddr
)+1);
1477 TRACE("resolved %s to %s\n", debugstr_w(lpwhs
->lpszServerName
), szaddr
);
1482 /***********************************************************************
1483 * HTTPREQ_Destroy (internal)
1485 * Deallocate request handle
1488 static void HTTPREQ_Destroy(object_header_t
*hdr
)
1490 http_request_t
*lpwhr
= (http_request_t
*) hdr
;
1495 if(lpwhr
->hCacheFile
)
1496 CloseHandle(lpwhr
->hCacheFile
);
1498 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszCacheFile
);
1500 DeleteCriticalSection( &lpwhr
->read_section
);
1501 WININET_Release(&lpwhr
->lpHttpSession
->hdr
);
1503 if (lpwhr
->pAuthInfo
)
1505 if (SecIsValidHandle(&lpwhr
->pAuthInfo
->ctx
))
1506 DeleteSecurityContext(&lpwhr
->pAuthInfo
->ctx
);
1507 if (SecIsValidHandle(&lpwhr
->pAuthInfo
->cred
))
1508 FreeCredentialsHandle(&lpwhr
->pAuthInfo
->cred
);
1510 HeapFree(GetProcessHeap(), 0, lpwhr
->pAuthInfo
->auth_data
);
1511 HeapFree(GetProcessHeap(), 0, lpwhr
->pAuthInfo
->scheme
);
1512 HeapFree(GetProcessHeap(), 0, lpwhr
->pAuthInfo
);
1513 lpwhr
->pAuthInfo
= NULL
;
1516 if (lpwhr
->pProxyAuthInfo
)
1518 if (SecIsValidHandle(&lpwhr
->pProxyAuthInfo
->ctx
))
1519 DeleteSecurityContext(&lpwhr
->pProxyAuthInfo
->ctx
);
1520 if (SecIsValidHandle(&lpwhr
->pProxyAuthInfo
->cred
))
1521 FreeCredentialsHandle(&lpwhr
->pProxyAuthInfo
->cred
);
1523 HeapFree(GetProcessHeap(), 0, lpwhr
->pProxyAuthInfo
->auth_data
);
1524 HeapFree(GetProcessHeap(), 0, lpwhr
->pProxyAuthInfo
->scheme
);
1525 HeapFree(GetProcessHeap(), 0, lpwhr
->pProxyAuthInfo
);
1526 lpwhr
->pProxyAuthInfo
= NULL
;
1529 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1530 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1531 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszRawHeaders
);
1532 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVersion
);
1533 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszStatusText
);
1535 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1537 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1538 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1541 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1542 HeapFree(GetProcessHeap(), 0, lpwhr
);
1545 static void HTTPREQ_CloseConnection(object_header_t
*hdr
)
1547 http_request_t
*lpwhr
= (http_request_t
*) hdr
;
1549 TRACE("%p\n",lpwhr
);
1552 if(lpwhr
->gzip_stream
) {
1553 inflateEnd(&lpwhr
->gzip_stream
->zstream
);
1554 HeapFree(GetProcessHeap(), 0, lpwhr
->gzip_stream
);
1555 lpwhr
->gzip_stream
= NULL
;
1559 if (!NETCON_connected(&lpwhr
->netConnection
))
1562 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
1563 INTERNET_STATUS_CLOSING_CONNECTION
, 0, 0);
1565 NETCON_close(&lpwhr
->netConnection
);
1567 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
1568 INTERNET_STATUS_CONNECTION_CLOSED
, 0, 0);
1571 static BOOL
HTTP_GetRequestURL(http_request_t
*req
, LPWSTR buf
)
1573 LPHTTPHEADERW host_header
;
1575 static const WCHAR formatW
[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1577 host_header
= HTTP_GetHeader(req
, hostW
);
1581 sprintfW(buf
, formatW
, host_header
->lpszValue
, req
->lpszPath
); /* FIXME */
1585 static DWORD
HTTPREQ_QueryOption(object_header_t
*hdr
, DWORD option
, void *buffer
, DWORD
*size
, BOOL unicode
)
1587 http_request_t
*req
= (http_request_t
*)hdr
;
1590 case INTERNET_OPTION_SECURITY_FLAGS
:
1592 http_session_t
*lpwhs
;
1593 lpwhs
= req
->lpHttpSession
;
1595 if (*size
< sizeof(ULONG
))
1596 return ERROR_INSUFFICIENT_BUFFER
;
1598 *size
= sizeof(DWORD
);
1599 if (lpwhs
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
)
1600 *(DWORD
*)buffer
= SECURITY_FLAG_SECURE
;
1602 *(DWORD
*)buffer
= 0;
1603 FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD
*)buffer
);
1604 return ERROR_SUCCESS
;
1607 case INTERNET_OPTION_HANDLE_TYPE
:
1608 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1610 if (*size
< sizeof(ULONG
))
1611 return ERROR_INSUFFICIENT_BUFFER
;
1613 *size
= sizeof(DWORD
);
1614 *(DWORD
*)buffer
= INTERNET_HANDLE_TYPE_HTTP_REQUEST
;
1615 return ERROR_SUCCESS
;
1617 case INTERNET_OPTION_URL
: {
1618 WCHAR url
[INTERNET_MAX_URL_LENGTH
];
1623 static const WCHAR httpW
[] = {'h','t','t','p',':','/','/',0};
1625 TRACE("INTERNET_OPTION_URL\n");
1627 host
= HTTP_GetHeader(req
, hostW
);
1628 strcpyW(url
, httpW
);
1629 strcatW(url
, host
->lpszValue
);
1630 if (NULL
!= (pch
= strchrW(url
+ strlenW(httpW
), ':')))
1632 strcatW(url
, req
->lpszPath
);
1634 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url
));
1637 len
= (strlenW(url
)+1) * sizeof(WCHAR
);
1639 return ERROR_INSUFFICIENT_BUFFER
;
1642 strcpyW(buffer
, url
);
1643 return ERROR_SUCCESS
;
1645 len
= WideCharToMultiByte(CP_ACP
, 0, url
, -1, buffer
, *size
, NULL
, NULL
);
1647 return ERROR_INSUFFICIENT_BUFFER
;
1650 return ERROR_SUCCESS
;
1654 case INTERNET_OPTION_CACHE_TIMESTAMPS
: {
1655 INTERNET_CACHE_ENTRY_INFOW
*info
;
1656 INTERNET_CACHE_TIMESTAMPS
*ts
= buffer
;
1657 WCHAR url
[INTERNET_MAX_URL_LENGTH
];
1658 DWORD nbytes
, error
;
1661 TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
1663 if (*size
< sizeof(*ts
))
1665 *size
= sizeof(*ts
);
1666 return ERROR_INSUFFICIENT_BUFFER
;
1669 HTTP_GetRequestURL(req
, url
);
1670 ret
= GetUrlCacheEntryInfoW(url
, NULL
, &nbytes
);
1671 error
= GetLastError();
1672 if (!ret
&& error
== ERROR_INSUFFICIENT_BUFFER
)
1674 if (!(info
= HeapAlloc(GetProcessHeap(), 0, nbytes
)))
1675 return ERROR_OUTOFMEMORY
;
1677 GetUrlCacheEntryInfoW(url
, info
, &nbytes
);
1679 ts
->ftExpires
= info
->ExpireTime
;
1680 ts
->ftLastModified
= info
->LastModifiedTime
;
1682 HeapFree(GetProcessHeap(), 0, info
);
1683 *size
= sizeof(*ts
);
1684 return ERROR_SUCCESS
;
1689 case INTERNET_OPTION_DATAFILE_NAME
: {
1692 TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
1694 if(!req
->lpszCacheFile
) {
1696 return ERROR_INTERNET_ITEM_NOT_FOUND
;
1700 req_size
= (lstrlenW(req
->lpszCacheFile
)+1) * sizeof(WCHAR
);
1701 if(*size
< req_size
)
1702 return ERROR_INSUFFICIENT_BUFFER
;
1705 memcpy(buffer
, req
->lpszCacheFile
, *size
);
1706 return ERROR_SUCCESS
;
1708 req_size
= WideCharToMultiByte(CP_ACP
, 0, req
->lpszCacheFile
, -1, NULL
, 0, NULL
, NULL
);
1709 if (req_size
> *size
)
1710 return ERROR_INSUFFICIENT_BUFFER
;
1712 *size
= WideCharToMultiByte(CP_ACP
, 0, req
->lpszCacheFile
,
1713 -1, buffer
, *size
, NULL
, NULL
);
1714 return ERROR_SUCCESS
;
1718 case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT
: {
1719 PCCERT_CONTEXT context
;
1721 if(*size
< sizeof(INTERNET_CERTIFICATE_INFOW
)) {
1722 *size
= sizeof(INTERNET_CERTIFICATE_INFOW
);
1723 return ERROR_INSUFFICIENT_BUFFER
;
1726 context
= (PCCERT_CONTEXT
)NETCON_GetCert(&(req
->netConnection
));
1728 INTERNET_CERTIFICATE_INFOW
*info
= (INTERNET_CERTIFICATE_INFOW
*)buffer
;
1731 memset(info
, 0, sizeof(INTERNET_CERTIFICATE_INFOW
));
1732 info
->ftExpiry
= context
->pCertInfo
->NotAfter
;
1733 info
->ftStart
= context
->pCertInfo
->NotBefore
;
1735 len
= CertNameToStrW(context
->dwCertEncodingType
,
1736 &context
->pCertInfo
->Subject
, CERT_SIMPLE_NAME_STR
, NULL
, 0);
1737 info
->lpszSubjectInfo
= LocalAlloc(0, len
*sizeof(WCHAR
));
1738 if(info
->lpszSubjectInfo
)
1739 CertNameToStrW(context
->dwCertEncodingType
,
1740 &context
->pCertInfo
->Subject
, CERT_SIMPLE_NAME_STR
,
1741 info
->lpszSubjectInfo
, len
);
1742 len
= CertNameToStrW(context
->dwCertEncodingType
,
1743 &context
->pCertInfo
->Issuer
, CERT_SIMPLE_NAME_STR
, NULL
, 0);
1744 info
->lpszIssuerInfo
= LocalAlloc(0, len
*sizeof(WCHAR
));
1745 if (info
->lpszIssuerInfo
)
1746 CertNameToStrW(context
->dwCertEncodingType
,
1747 &context
->pCertInfo
->Issuer
, CERT_SIMPLE_NAME_STR
,
1748 info
->lpszIssuerInfo
, len
);
1750 INTERNET_CERTIFICATE_INFOA
*infoA
= (INTERNET_CERTIFICATE_INFOA
*)info
;
1752 len
= CertNameToStrA(context
->dwCertEncodingType
,
1753 &context
->pCertInfo
->Subject
, CERT_SIMPLE_NAME_STR
, NULL
, 0);
1754 infoA
->lpszSubjectInfo
= LocalAlloc(0, len
);
1755 if(infoA
->lpszSubjectInfo
)
1756 CertNameToStrA(context
->dwCertEncodingType
,
1757 &context
->pCertInfo
->Subject
, CERT_SIMPLE_NAME_STR
,
1758 infoA
->lpszSubjectInfo
, len
);
1759 len
= CertNameToStrA(context
->dwCertEncodingType
,
1760 &context
->pCertInfo
->Issuer
, CERT_SIMPLE_NAME_STR
, NULL
, 0);
1761 infoA
->lpszIssuerInfo
= LocalAlloc(0, len
);
1762 if(infoA
->lpszIssuerInfo
)
1763 CertNameToStrA(context
->dwCertEncodingType
,
1764 &context
->pCertInfo
->Issuer
, CERT_SIMPLE_NAME_STR
,
1765 infoA
->lpszIssuerInfo
, len
);
1769 * Contrary to MSDN, these do not appear to be set.
1771 * lpszSignatureAlgName
1772 * lpszEncryptionAlgName
1775 CertFreeCertificateContext(context
);
1776 return ERROR_SUCCESS
;
1781 return INET_QueryOption(option
, buffer
, size
, unicode
);
1784 static DWORD
HTTPREQ_SetOption(object_header_t
*hdr
, DWORD option
, void *buffer
, DWORD size
)
1786 http_request_t
*req
= (http_request_t
*)hdr
;
1789 case INTERNET_OPTION_SEND_TIMEOUT
:
1790 case INTERNET_OPTION_RECEIVE_TIMEOUT
:
1791 TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
1793 if (size
!= sizeof(DWORD
))
1794 return ERROR_INVALID_PARAMETER
;
1796 return NETCON_set_timeout(&req
->netConnection
, option
== INTERNET_OPTION_SEND_TIMEOUT
,
1799 case INTERNET_OPTION_USERNAME
:
1800 HeapFree(GetProcessHeap(), 0, req
->lpHttpSession
->lpszUserName
);
1801 if (!(req
->lpHttpSession
->lpszUserName
= heap_strdupW(buffer
))) return ERROR_OUTOFMEMORY
;
1802 return ERROR_SUCCESS
;
1804 case INTERNET_OPTION_PASSWORD
:
1805 HeapFree(GetProcessHeap(), 0, req
->lpHttpSession
->lpszPassword
);
1806 if (!(req
->lpHttpSession
->lpszPassword
= heap_strdupW(buffer
))) return ERROR_OUTOFMEMORY
;
1807 return ERROR_SUCCESS
;
1808 case INTERNET_OPTION_HTTP_DECODING
:
1809 if(size
!= sizeof(BOOL
))
1810 return ERROR_INVALID_PARAMETER
;
1811 req
->decoding
= *(BOOL
*)buffer
;
1812 return ERROR_SUCCESS
;
1815 return ERROR_INTERNET_INVALID_OPTION
;
1818 /* read some more data into the read buffer (the read section must be held) */
1819 static BOOL
read_more_data( http_request_t
*req
, int maxlen
)
1825 /* move existing data to the start of the buffer */
1827 memmove( req
->read_buf
, req
->read_buf
+ req
->read_pos
, req
->read_size
);
1831 if (maxlen
== -1) maxlen
= sizeof(req
->read_buf
);
1833 if(!NETCON_recv( &req
->netConnection
, req
->read_buf
+ req
->read_size
,
1834 maxlen
- req
->read_size
, 0, &len
))
1837 req
->read_size
+= len
;
1841 /* remove some amount of data from the read buffer (the read section must be held) */
1842 static void remove_data( http_request_t
*req
, int count
)
1844 if (!(req
->read_size
-= count
)) req
->read_pos
= 0;
1845 else req
->read_pos
+= count
;
1848 static BOOL
read_line( http_request_t
*req
, LPSTR buffer
, DWORD
*len
)
1850 int count
, bytes_read
, pos
= 0;
1852 EnterCriticalSection( &req
->read_section
);
1855 BYTE
*eol
= memchr( req
->read_buf
+ req
->read_pos
, '\n', req
->read_size
);
1859 count
= eol
- (req
->read_buf
+ req
->read_pos
);
1860 bytes_read
= count
+ 1;
1862 else count
= bytes_read
= req
->read_size
;
1864 count
= min( count
, *len
- pos
);
1865 memcpy( buffer
+ pos
, req
->read_buf
+ req
->read_pos
, count
);
1867 remove_data( req
, bytes_read
);
1870 if (!read_more_data( req
, -1 ) || !req
->read_size
)
1873 TRACE( "returning empty string\n" );
1874 LeaveCriticalSection( &req
->read_section
);
1878 LeaveCriticalSection( &req
->read_section
);
1882 if (pos
&& buffer
[pos
- 1] == '\r') pos
--;
1885 buffer
[*len
- 1] = 0;
1886 TRACE( "returning %s\n", debugstr_a(buffer
));
1890 /* discard data contents until we reach end of line (the read section must be held) */
1891 static BOOL
discard_eol( http_request_t
*req
)
1895 BYTE
*eol
= memchr( req
->read_buf
+ req
->read_pos
, '\n', req
->read_size
);
1898 remove_data( req
, (eol
+ 1) - (req
->read_buf
+ req
->read_pos
) );
1901 req
->read_pos
= req
->read_size
= 0; /* discard everything */
1902 if (!read_more_data( req
, -1 )) return FALSE
;
1903 } while (req
->read_size
);
1907 /* read the size of the next chunk (the read section must be held) */
1908 static BOOL
start_next_chunk( http_request_t
*req
)
1910 DWORD chunk_size
= 0;
1912 if (!req
->dwContentLength
) return TRUE
;
1913 if (req
->dwContentLength
== req
->dwContentRead
)
1915 /* read terminator for the previous chunk */
1916 if (!discard_eol( req
)) return FALSE
;
1917 req
->dwContentLength
= ~0u;
1918 req
->dwContentRead
= 0;
1922 while (req
->read_size
)
1924 char ch
= req
->read_buf
[req
->read_pos
];
1925 if (ch
>= '0' && ch
<= '9') chunk_size
= chunk_size
* 16 + ch
- '0';
1926 else if (ch
>= 'a' && ch
<= 'f') chunk_size
= chunk_size
* 16 + ch
- 'a' + 10;
1927 else if (ch
>= 'A' && ch
<= 'F') chunk_size
= chunk_size
* 16 + ch
- 'A' + 10;
1928 else if (ch
== ';' || ch
== '\r' || ch
== '\n')
1930 TRACE( "reading %u byte chunk\n", chunk_size
);
1931 req
->dwContentLength
= chunk_size
;
1932 req
->dwContentRead
= 0;
1933 if (!discard_eol( req
)) return FALSE
;
1936 remove_data( req
, 1 );
1938 if (!read_more_data( req
, -1 )) return FALSE
;
1939 if (!req
->read_size
)
1941 req
->dwContentLength
= req
->dwContentRead
= 0;
1947 /* check if we have reached the end of the data to read (the read section must be held) */
1948 static BOOL
end_of_read_data( http_request_t
*req
)
1950 if (req
->gzip_stream
) return req
->gzip_stream
->end_of_data
&& !req
->gzip_stream
->buf_size
;
1951 if (req
->read_chunked
) return (req
->dwContentLength
== 0);
1952 if (req
->dwContentLength
== ~0u) return FALSE
;
1953 return (req
->dwContentLength
== req
->dwContentRead
);
1956 /* fetch some more data into the read buffer (the read section must be held) */
1957 static BOOL
refill_buffer( http_request_t
*req
)
1959 int len
= sizeof(req
->read_buf
);
1961 if (req
->read_chunked
&& (req
->dwContentLength
== ~0u || req
->dwContentLength
== req
->dwContentRead
))
1963 if (!start_next_chunk( req
)) return FALSE
;
1966 if (req
->dwContentLength
!= ~0u) len
= min( len
, req
->dwContentLength
- req
->dwContentRead
);
1967 if (len
<= req
->read_size
) return TRUE
;
1969 if (!read_more_data( req
, len
)) return FALSE
;
1970 if (!req
->read_size
) req
->dwContentLength
= req
->dwContentRead
= 0;
1974 static DWORD
read_gzip_data(http_request_t
*req
, BYTE
*buf
, int size
, BOOL sync
, int *read_ret
)
1976 DWORD ret
= ERROR_SUCCESS
;
1980 z_stream
*zstream
= &req
->gzip_stream
->zstream
;
1983 while(read
< size
&& !req
->gzip_stream
->end_of_data
) {
1984 if(!req
->read_size
) {
1985 if(!sync
|| !refill_buffer(req
))
1989 zstream
->next_in
= req
->read_buf
+req
->read_pos
;
1990 zstream
->avail_in
= req
->read_size
;
1991 zstream
->next_out
= buf
+read
;
1992 zstream
->avail_out
= size
-read
;
1993 zres
= inflate(zstream
, Z_FULL_FLUSH
);
1994 read
= size
- zstream
->avail_out
;
1995 remove_data(req
, req
->read_size
-zstream
->avail_in
);
1996 if(zres
== Z_STREAM_END
) {
1997 TRACE("end of data\n");
1998 req
->gzip_stream
->end_of_data
= TRUE
;
1999 }else if(zres
!= Z_OK
) {
2000 WARN("inflate failed %d\n", zres
);
2002 ret
= ERROR_INTERNET_DECODING_FAILED
;
2012 static void refill_gzip_buffer(http_request_t
*req
)
2017 if(!req
->gzip_stream
|| !req
->read_size
|| req
->gzip_stream
->buf_size
== sizeof(req
->gzip_stream
->buf
))
2020 if(req
->gzip_stream
->buf_pos
) {
2021 if(req
->gzip_stream
->buf_size
)
2022 memmove(req
->gzip_stream
->buf
, req
->gzip_stream
->buf
+ req
->gzip_stream
->buf_pos
, req
->gzip_stream
->buf_size
);
2023 req
->gzip_stream
->buf_pos
= 0;
2026 res
= read_gzip_data(req
, req
->gzip_stream
->buf
+ req
->gzip_stream
->buf_size
,
2027 sizeof(req
->gzip_stream
->buf
) - req
->gzip_stream
->buf_size
, FALSE
, &len
);
2028 if(res
== ERROR_SUCCESS
)
2029 req
->gzip_stream
->buf_size
+= len
;
2032 /* return the size of data available to be read immediately (the read section must be held) */
2033 static DWORD
get_avail_data( http_request_t
*req
)
2035 if (req
->gzip_stream
) {
2036 refill_gzip_buffer(req
);
2037 return req
->gzip_stream
->buf_size
;
2039 if (req
->read_chunked
&& (req
->dwContentLength
== ~0u || req
->dwContentLength
== req
->dwContentRead
))
2041 return min( req
->read_size
, req
->dwContentLength
- req
->dwContentRead
);
2044 static void HTTP_ReceiveRequestData(http_request_t
*req
, BOOL first_notif
)
2046 INTERNET_ASYNC_RESULT iar
;
2050 EnterCriticalSection( &req
->read_section
);
2051 if (refill_buffer( req
)) {
2052 iar
.dwResult
= (DWORD_PTR
)req
->hdr
.hInternet
;
2053 iar
.dwError
= first_notif
? 0 : get_avail_data(req
);
2056 iar
.dwError
= INTERNET_GetLastError();
2058 LeaveCriticalSection( &req
->read_section
);
2060 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2061 sizeof(INTERNET_ASYNC_RESULT
));
2064 /* read data from the http connection (the read section must be held) */
2065 static DWORD
HTTPREQ_Read(http_request_t
*req
, void *buffer
, DWORD size
, DWORD
*read
, BOOL sync
)
2067 BOOL finished_reading
= FALSE
;
2068 int len
, bytes_read
= 0;
2069 DWORD ret
= ERROR_SUCCESS
;
2071 EnterCriticalSection( &req
->read_section
);
2073 if (req
->read_chunked
&& (req
->dwContentLength
== ~0u || req
->dwContentLength
== req
->dwContentRead
))
2075 if (!start_next_chunk( req
)) goto done
;
2078 if(req
->gzip_stream
) {
2079 if(req
->gzip_stream
->buf_size
) {
2080 bytes_read
= min(req
->gzip_stream
->buf_size
, size
);
2081 memcpy(buffer
, req
->gzip_stream
->buf
+ req
->gzip_stream
->buf_pos
, bytes_read
);
2082 req
->gzip_stream
->buf_pos
+= bytes_read
;
2083 req
->gzip_stream
->buf_size
-= bytes_read
;
2084 }else if(!req
->read_size
&& !req
->gzip_stream
->end_of_data
) {
2088 if(size
> bytes_read
) {
2089 ret
= read_gzip_data(req
, (BYTE
*)buffer
+bytes_read
, size
-bytes_read
, sync
, &len
);
2090 if(ret
== ERROR_SUCCESS
)
2094 finished_reading
= req
->gzip_stream
->end_of_data
&& !req
->gzip_stream
->buf_size
;
2096 if (req
->dwContentLength
!= ~0u) size
= min( size
, req
->dwContentLength
- req
->dwContentRead
);
2098 if (req
->read_size
) {
2099 bytes_read
= min( req
->read_size
, size
);
2100 memcpy( buffer
, req
->read_buf
+ req
->read_pos
, bytes_read
);
2101 remove_data( req
, bytes_read
);
2104 if (size
> bytes_read
&& (!bytes_read
|| sync
)) {
2105 if (NETCON_recv( &req
->netConnection
, (char *)buffer
+ bytes_read
, size
- bytes_read
,
2106 sync
? MSG_WAITALL
: 0, &len
))
2108 /* always return success, even if the network layer returns an error */
2111 finished_reading
= !bytes_read
&& req
->dwContentRead
== req
->dwContentLength
;
2114 req
->dwContentRead
+= bytes_read
;
2117 TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read
, req
->dwContentRead
, req
->dwContentLength
);
2118 LeaveCriticalSection( &req
->read_section
);
2120 if(ret
== ERROR_SUCCESS
&& req
->lpszCacheFile
) {
2122 DWORD dwBytesWritten
;
2124 res
= WriteFile(req
->hCacheFile
, buffer
, bytes_read
, &dwBytesWritten
, NULL
);
2126 WARN("WriteFile failed: %u\n", GetLastError());
2129 if(finished_reading
)
2130 HTTP_FinishedReading(req
);
2136 static DWORD
HTTPREQ_ReadFile(object_header_t
*hdr
, void *buffer
, DWORD size
, DWORD
*read
)
2138 http_request_t
*req
= (http_request_t
*)hdr
;
2139 return HTTPREQ_Read(req
, buffer
, size
, read
, TRUE
);
2142 static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST
*workRequest
)
2144 struct WORKREQ_INTERNETREADFILEEXA
const *data
= &workRequest
->u
.InternetReadFileExA
;
2145 http_request_t
*req
= (http_request_t
*)workRequest
->hdr
;
2146 INTERNET_ASYNC_RESULT iar
;
2149 TRACE("INTERNETREADFILEEXA %p\n", workRequest
->hdr
);
2151 res
= HTTPREQ_Read(req
, data
->lpBuffersOut
->lpvBuffer
,
2152 data
->lpBuffersOut
->dwBufferLength
, &data
->lpBuffersOut
->dwBufferLength
, TRUE
);
2154 iar
.dwResult
= res
== ERROR_SUCCESS
;
2157 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
,
2158 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2159 sizeof(INTERNET_ASYNC_RESULT
));
2162 static DWORD
HTTPREQ_ReadFileExA(object_header_t
*hdr
, INTERNET_BUFFERSA
*buffers
,
2163 DWORD flags
, DWORD_PTR context
)
2165 http_request_t
*req
= (http_request_t
*)hdr
;
2168 if (flags
& ~(IRF_ASYNC
|IRF_NO_WAIT
))
2169 FIXME("these dwFlags aren't implemented: 0x%x\n", flags
& ~(IRF_ASYNC
|IRF_NO_WAIT
));
2171 if (buffers
->dwStructSize
!= sizeof(*buffers
))
2172 return ERROR_INVALID_PARAMETER
;
2174 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2176 if ((hdr
->dwFlags
& INTERNET_FLAG_ASYNC
) && !get_avail_data(req
))
2178 WORKREQUEST workRequest
;
2180 if (TryEnterCriticalSection( &req
->read_section
))
2182 if (get_avail_data(req
))
2184 res
= HTTPREQ_Read(req
, buffers
->lpvBuffer
, buffers
->dwBufferLength
,
2185 &buffers
->dwBufferLength
, FALSE
);
2186 LeaveCriticalSection( &req
->read_section
);
2189 LeaveCriticalSection( &req
->read_section
);
2192 workRequest
.asyncproc
= HTTPREQ_AsyncReadFileExAProc
;
2193 workRequest
.hdr
= WININET_AddRef(&req
->hdr
);
2194 workRequest
.u
.InternetReadFileExA
.lpBuffersOut
= buffers
;
2196 INTERNET_AsyncCall(&workRequest
);
2198 return ERROR_IO_PENDING
;
2201 res
= HTTPREQ_Read(req
, buffers
->lpvBuffer
, buffers
->dwBufferLength
, &buffers
->dwBufferLength
,
2202 !(flags
& IRF_NO_WAIT
));
2205 if (res
== ERROR_SUCCESS
) {
2206 DWORD size
= buffers
->dwBufferLength
;
2207 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2208 &size
, sizeof(size
));
2214 static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST
*workRequest
)
2216 struct WORKREQ_INTERNETREADFILEEXW
const *data
= &workRequest
->u
.InternetReadFileExW
;
2217 http_request_t
*req
= (http_request_t
*)workRequest
->hdr
;
2218 INTERNET_ASYNC_RESULT iar
;
2221 TRACE("INTERNETREADFILEEXW %p\n", workRequest
->hdr
);
2223 res
= HTTPREQ_Read(req
, data
->lpBuffersOut
->lpvBuffer
,
2224 data
->lpBuffersOut
->dwBufferLength
, &data
->lpBuffersOut
->dwBufferLength
, TRUE
);
2226 iar
.dwResult
= res
== ERROR_SUCCESS
;
2229 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
,
2230 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2231 sizeof(INTERNET_ASYNC_RESULT
));
2234 static DWORD
HTTPREQ_ReadFileExW(object_header_t
*hdr
, INTERNET_BUFFERSW
*buffers
,
2235 DWORD flags
, DWORD_PTR context
)
2238 http_request_t
*req
= (http_request_t
*)hdr
;
2241 if (flags
& ~(IRF_ASYNC
|IRF_NO_WAIT
))
2242 FIXME("these dwFlags aren't implemented: 0x%x\n", flags
& ~(IRF_ASYNC
|IRF_NO_WAIT
));
2244 if (buffers
->dwStructSize
!= sizeof(*buffers
))
2245 return ERROR_INVALID_PARAMETER
;
2247 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2249 if (hdr
->dwFlags
& INTERNET_FLAG_ASYNC
)
2251 WORKREQUEST workRequest
;
2253 if (TryEnterCriticalSection( &req
->read_section
))
2255 if (get_avail_data(req
))
2257 res
= HTTPREQ_Read(req
, buffers
->lpvBuffer
, buffers
->dwBufferLength
,
2258 &buffers
->dwBufferLength
, FALSE
);
2259 LeaveCriticalSection( &req
->read_section
);
2262 LeaveCriticalSection( &req
->read_section
);
2265 workRequest
.asyncproc
= HTTPREQ_AsyncReadFileExWProc
;
2266 workRequest
.hdr
= WININET_AddRef(&req
->hdr
);
2267 workRequest
.u
.InternetReadFileExW
.lpBuffersOut
= buffers
;
2269 INTERNET_AsyncCall(&workRequest
);
2271 return ERROR_IO_PENDING
;
2274 res
= HTTPREQ_Read(req
, buffers
->lpvBuffer
, buffers
->dwBufferLength
, &buffers
->dwBufferLength
,
2275 !(flags
& IRF_NO_WAIT
));
2278 if (res
== ERROR_SUCCESS
) {
2279 DWORD size
= buffers
->dwBufferLength
;
2280 INTERNET_SendCallback(&req
->hdr
, req
->hdr
.dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2281 &size
, sizeof(size
));
2287 static BOOL
HTTPREQ_WriteFile(object_header_t
*hdr
, const void *buffer
, DWORD size
, DWORD
*written
)
2290 http_request_t
*lpwhr
= (http_request_t
*)hdr
;
2292 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
2295 if ((ret
= NETCON_send(&lpwhr
->netConnection
, buffer
, size
, 0, (LPINT
)written
)))
2296 lpwhr
->dwBytesWritten
+= *written
;
2298 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_SENT
, written
, sizeof(DWORD
));
2302 static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST
*workRequest
)
2304 http_request_t
*req
= (http_request_t
*)workRequest
->hdr
;
2306 HTTP_ReceiveRequestData(req
, FALSE
);
2309 static DWORD
HTTPREQ_QueryDataAvailable(object_header_t
*hdr
, DWORD
*available
, DWORD flags
, DWORD_PTR ctx
)
2311 http_request_t
*req
= (http_request_t
*)hdr
;
2313 TRACE("(%p %p %x %lx)\n", req
, available
, flags
, ctx
);
2315 if (req
->lpHttpSession
->lpAppInfo
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2317 WORKREQUEST workRequest
;
2319 /* never wait, if we can't enter the section we queue an async request right away */
2320 if (TryEnterCriticalSection( &req
->read_section
))
2322 if ((*available
= get_avail_data( req
))) goto done
;
2323 if (end_of_read_data( req
)) goto done
;
2324 LeaveCriticalSection( &req
->read_section
);
2327 workRequest
.asyncproc
= HTTPREQ_AsyncQueryDataAvailableProc
;
2328 workRequest
.hdr
= WININET_AddRef( &req
->hdr
);
2330 INTERNET_AsyncCall(&workRequest
);
2332 return ERROR_IO_PENDING
;
2335 EnterCriticalSection( &req
->read_section
);
2337 if (!(*available
= get_avail_data( req
)) && !end_of_read_data( req
))
2339 refill_buffer( req
);
2340 *available
= get_avail_data( req
);
2344 if (*available
== sizeof(req
->read_buf
) && !req
->gzip_stream
) /* check if we have even more pending in the socket */
2347 if (NETCON_query_data_available(&req
->netConnection
, &extra
))
2348 *available
= min( *available
+ extra
, req
->dwContentLength
- req
->dwContentRead
);
2350 LeaveCriticalSection( &req
->read_section
);
2352 TRACE( "returning %u\n", *available
);
2353 return ERROR_SUCCESS
;
2356 static const object_vtbl_t HTTPREQVtbl
= {
2358 HTTPREQ_CloseConnection
,
2359 HTTPREQ_QueryOption
,
2362 HTTPREQ_ReadFileExA
,
2363 HTTPREQ_ReadFileExW
,
2365 HTTPREQ_QueryDataAvailable
,
2369 /***********************************************************************
2370 * HTTP_HttpOpenRequestW (internal)
2372 * Open a HTTP request handle
2375 * HINTERNET a HTTP request handle on success
2379 HINTERNET WINAPI
HTTP_HttpOpenRequestW(http_session_t
*lpwhs
,
2380 LPCWSTR lpszVerb
, LPCWSTR lpszObjectName
, LPCWSTR lpszVersion
,
2381 LPCWSTR lpszReferrer
, LPCWSTR
*lpszAcceptTypes
,
2382 DWORD dwFlags
, DWORD_PTR dwContext
)
2384 appinfo_t
*hIC
= NULL
;
2385 http_request_t
*lpwhr
;
2386 LPWSTR lpszHostName
= NULL
;
2387 HINTERNET handle
= NULL
;
2388 static const WCHAR szHostForm
[] = {'%','s',':','%','u',0};
2393 assert( lpwhs
->hdr
.htype
== WH_HHTTPSESSION
);
2394 hIC
= lpwhs
->lpAppInfo
;
2396 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(http_request_t
));
2399 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2402 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
2403 lpwhr
->hdr
.vtbl
= &HTTPREQVtbl
;
2404 lpwhr
->hdr
.dwFlags
= dwFlags
;
2405 lpwhr
->hdr
.dwContext
= dwContext
;
2406 lpwhr
->hdr
.refs
= 1;
2407 lpwhr
->hdr
.lpfnStatusCB
= lpwhs
->hdr
.lpfnStatusCB
;
2408 lpwhr
->hdr
.dwInternalFlags
= lpwhs
->hdr
.dwInternalFlags
& INET_CALLBACKW
;
2409 lpwhr
->dwContentLength
= ~0u;
2410 InitializeCriticalSection( &lpwhr
->read_section
);
2412 WININET_AddRef( &lpwhs
->hdr
);
2413 lpwhr
->lpHttpSession
= lpwhs
;
2414 list_add_head( &lpwhs
->hdr
.children
, &lpwhr
->hdr
.entry
);
2416 lpszHostName
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) *
2417 (strlenW(lpwhs
->lpszHostName
) + 7 /* length of ":65535" + 1 */));
2418 if (NULL
== lpszHostName
)
2420 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2424 handle
= WININET_AllocHandle( &lpwhr
->hdr
);
2427 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2431 if (!NETCON_init(&lpwhr
->netConnection
, dwFlags
& INTERNET_FLAG_SECURE
))
2433 InternetCloseHandle( handle
);
2438 if (lpszObjectName
&& *lpszObjectName
) {
2442 rc
= UrlEscapeW(lpszObjectName
, NULL
, &len
, URL_ESCAPE_SPACES_ONLY
);
2443 if (rc
!= E_POINTER
)
2444 len
= strlenW(lpszObjectName
)+1;
2445 lpwhr
->lpszPath
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
2446 rc
= UrlEscapeW(lpszObjectName
, lpwhr
->lpszPath
, &len
,
2447 URL_ESCAPE_SPACES_ONLY
);
2450 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName
),rc
);
2451 strcpyW(lpwhr
->lpszPath
,lpszObjectName
);
2454 static const WCHAR slashW
[] = {'/',0};
2456 lpwhr
->lpszPath
= heap_strdupW(slashW
);
2459 if (lpszReferrer
&& *lpszReferrer
)
2460 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDHDR_FLAG_REQ
);
2462 if (lpszAcceptTypes
)
2465 for (i
= 0; lpszAcceptTypes
[i
]; i
++)
2467 if (!*lpszAcceptTypes
[i
]) continue;
2468 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, lpszAcceptTypes
[i
],
2469 HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
|
2470 HTTP_ADDHDR_FLAG_REQ
|
2471 (i
== 0 ? HTTP_ADDHDR_FLAG_REPLACE
: 0));
2475 lpwhr
->lpszVerb
= heap_strdupW(lpszVerb
&& *lpszVerb
? lpszVerb
: szGET
);
2476 lpwhr
->lpszVersion
= heap_strdupW(lpszVersion
? lpszVersion
: g_szHttp1_1
);
2478 if (lpwhs
->nHostPort
!= INTERNET_INVALID_PORT_NUMBER
&&
2479 lpwhs
->nHostPort
!= INTERNET_DEFAULT_HTTP_PORT
&&
2480 lpwhs
->nHostPort
!= INTERNET_DEFAULT_HTTPS_PORT
)
2482 sprintfW(lpszHostName
, szHostForm
, lpwhs
->lpszHostName
, lpwhs
->nHostPort
);
2483 HTTP_ProcessHeader(lpwhr
, hostW
, lpszHostName
,
2484 HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDHDR_FLAG_REQ
);
2487 HTTP_ProcessHeader(lpwhr
, hostW
, lpwhs
->lpszHostName
,
2488 HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDHDR_FLAG_REQ
);
2490 if (lpwhs
->nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
2491 lpwhs
->nServerPort
= (dwFlags
& INTERNET_FLAG_SECURE
?
2492 INTERNET_DEFAULT_HTTPS_PORT
:
2493 INTERNET_DEFAULT_HTTP_PORT
);
2495 if (lpwhs
->nHostPort
== INTERNET_INVALID_PORT_NUMBER
)
2496 lpwhs
->nHostPort
= (dwFlags
& INTERNET_FLAG_SECURE
?
2497 INTERNET_DEFAULT_HTTPS_PORT
:
2498 INTERNET_DEFAULT_HTTP_PORT
);
2500 if (NULL
!= hIC
->lpszProxy
&& hIC
->lpszProxy
[0] != 0)
2501 HTTP_DealWithProxy( hIC
, lpwhs
, lpwhr
);
2503 INTERNET_SendCallback(&lpwhs
->hdr
, dwContext
,
2504 INTERNET_STATUS_HANDLE_CREATED
, &handle
,
2508 HeapFree(GetProcessHeap(), 0, lpszHostName
);
2510 WININET_Release( &lpwhr
->hdr
);
2512 TRACE("<-- %p (%p)\n", handle
, lpwhr
);
2516 /* read any content returned by the server so that the connection can be
2518 static void HTTP_DrainContent(http_request_t
*req
)
2522 if (!NETCON_connected(&req
->netConnection
)) return;
2524 if (req
->dwContentLength
== -1)
2526 NETCON_close(&req
->netConnection
);
2533 if (HTTPREQ_Read(req
, buffer
, sizeof(buffer
), &bytes_read
, TRUE
) != ERROR_SUCCESS
)
2535 } while (bytes_read
);
2538 static const LPCWSTR header_lookup
[] = {
2539 szMime_Version
, /* HTTP_QUERY_MIME_VERSION = 0 */
2540 szContent_Type
, /* HTTP_QUERY_CONTENT_TYPE = 1 */
2541 szContent_Transfer_Encoding
,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
2542 szContent_ID
, /* HTTP_QUERY_CONTENT_ID = 3 */
2543 NULL
, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
2544 szContent_Length
, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
2545 szContent_Language
, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
2546 szAllow
, /* HTTP_QUERY_ALLOW = 7 */
2547 szPublic
, /* HTTP_QUERY_PUBLIC = 8 */
2548 szDate
, /* HTTP_QUERY_DATE = 9 */
2549 szExpires
, /* HTTP_QUERY_EXPIRES = 10 */
2550 szLast_Modified
, /* HTTP_QUERY_LAST_MODIFIED = 11 */
2551 NULL
, /* HTTP_QUERY_MESSAGE_ID = 12 */
2552 szURI
, /* HTTP_QUERY_URI = 13 */
2553 szFrom
, /* HTTP_QUERY_DERIVED_FROM = 14 */
2554 NULL
, /* HTTP_QUERY_COST = 15 */
2555 NULL
, /* HTTP_QUERY_LINK = 16 */
2556 szPragma
, /* HTTP_QUERY_PRAGMA = 17 */
2557 NULL
, /* HTTP_QUERY_VERSION = 18 */
2558 szStatus
, /* HTTP_QUERY_STATUS_CODE = 19 */
2559 NULL
, /* HTTP_QUERY_STATUS_TEXT = 20 */
2560 NULL
, /* HTTP_QUERY_RAW_HEADERS = 21 */
2561 NULL
, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
2562 szConnection
, /* HTTP_QUERY_CONNECTION = 23 */
2563 szAccept
, /* HTTP_QUERY_ACCEPT = 24 */
2564 szAccept_Charset
, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
2565 szAccept_Encoding
, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
2566 szAccept_Language
, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
2567 szAuthorization
, /* HTTP_QUERY_AUTHORIZATION = 28 */
2568 szContent_Encoding
, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
2569 NULL
, /* HTTP_QUERY_FORWARDED = 30 */
2570 NULL
, /* HTTP_QUERY_FROM = 31 */
2571 szIf_Modified_Since
, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
2572 szLocation
, /* HTTP_QUERY_LOCATION = 33 */
2573 NULL
, /* HTTP_QUERY_ORIG_URI = 34 */
2574 szReferer
, /* HTTP_QUERY_REFERER = 35 */
2575 szRetry_After
, /* HTTP_QUERY_RETRY_AFTER = 36 */
2576 szServer
, /* HTTP_QUERY_SERVER = 37 */
2577 NULL
, /* HTTP_TITLE = 38 */
2578 szUser_Agent
, /* HTTP_QUERY_USER_AGENT = 39 */
2579 szWWW_Authenticate
, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
2580 szProxy_Authenticate
, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
2581 szAccept_Ranges
, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
2582 szSet_Cookie
, /* HTTP_QUERY_SET_COOKIE = 43 */
2583 szCookie
, /* HTTP_QUERY_COOKIE = 44 */
2584 NULL
, /* HTTP_QUERY_REQUEST_METHOD = 45 */
2585 NULL
, /* HTTP_QUERY_REFRESH = 46 */
2586 NULL
, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
2587 szAge
, /* HTTP_QUERY_AGE = 48 */
2588 szCache_Control
, /* HTTP_QUERY_CACHE_CONTROL = 49 */
2589 szContent_Base
, /* HTTP_QUERY_CONTENT_BASE = 50 */
2590 szContent_Location
, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
2591 szContent_MD5
, /* HTTP_QUERY_CONTENT_MD5 = 52 */
2592 szContent_Range
, /* HTTP_QUERY_CONTENT_RANGE = 53 */
2593 szETag
, /* HTTP_QUERY_ETAG = 54 */
2594 hostW
, /* HTTP_QUERY_HOST = 55 */
2595 szIf_Match
, /* HTTP_QUERY_IF_MATCH = 56 */
2596 szIf_None_Match
, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
2597 szIf_Range
, /* HTTP_QUERY_IF_RANGE = 58 */
2598 szIf_Unmodified_Since
, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
2599 szMax_Forwards
, /* HTTP_QUERY_MAX_FORWARDS = 60 */
2600 szProxy_Authorization
, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
2601 szRange
, /* HTTP_QUERY_RANGE = 62 */
2602 szTransfer_Encoding
, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
2603 szUpgrade
, /* HTTP_QUERY_UPGRADE = 64 */
2604 szVary
, /* HTTP_QUERY_VARY = 65 */
2605 szVia
, /* HTTP_QUERY_VIA = 66 */
2606 szWarning
, /* HTTP_QUERY_WARNING = 67 */
2607 szExpect
, /* HTTP_QUERY_EXPECT = 68 */
2608 szProxy_Connection
, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
2609 szUnless_Modified_Since
, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
2612 #define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
2614 /***********************************************************************
2615 * HTTP_HttpQueryInfoW (internal)
2617 static BOOL
HTTP_HttpQueryInfoW(http_request_t
*lpwhr
, DWORD dwInfoLevel
,
2618 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
2620 LPHTTPHEADERW lphttpHdr
= NULL
;
2621 BOOL bSuccess
= FALSE
;
2622 BOOL request_only
= dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
;
2623 INT requested_index
= lpdwIndex
? *lpdwIndex
: 0;
2624 DWORD level
= (dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
);
2627 /* Find requested header structure */
2630 case HTTP_QUERY_CUSTOM
:
2631 if (!lpBuffer
) return FALSE
;
2632 index
= HTTP_GetCustomHeaderIndex(lpwhr
, lpBuffer
, requested_index
, request_only
);
2635 case HTTP_QUERY_CONTENT_LENGTH
:
2636 if(lpwhr
->gzip_stream
) {
2637 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
2641 index
= HTTP_GetCustomHeaderIndex(lpwhr
, header_lookup
[level
],
2642 requested_index
,request_only
);
2645 case HTTP_QUERY_RAW_HEADERS_CRLF
:
2652 headers
= HTTP_BuildHeaderRequestString(lpwhr
, lpwhr
->lpszVerb
, lpwhr
->lpszPath
, lpwhr
->lpszVersion
);
2654 headers
= lpwhr
->lpszRawHeaders
;
2657 len
= strlenW(headers
) * sizeof(WCHAR
);
2659 if (len
+ sizeof(WCHAR
) > *lpdwBufferLength
)
2661 len
+= sizeof(WCHAR
);
2662 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2668 memcpy(lpBuffer
, headers
, len
+ sizeof(WCHAR
));
2671 len
= strlenW(szCrLf
) * sizeof(WCHAR
);
2672 memcpy(lpBuffer
, szCrLf
, sizeof(szCrLf
));
2674 TRACE("returning data: %s\n", debugstr_wn(lpBuffer
, len
/ sizeof(WCHAR
)));
2677 *lpdwBufferLength
= len
;
2680 HeapFree(GetProcessHeap(), 0, headers
);
2683 case HTTP_QUERY_RAW_HEADERS
:
2685 LPWSTR
* ppszRawHeaderLines
= HTTP_Tokenize(lpwhr
->lpszRawHeaders
, szCrLf
);
2687 LPWSTR pszString
= lpBuffer
;
2689 for (i
= 0; ppszRawHeaderLines
[i
]; i
++)
2690 size
+= strlenW(ppszRawHeaderLines
[i
]) + 1;
2692 if (size
+ 1 > *lpdwBufferLength
/sizeof(WCHAR
))
2694 HTTP_FreeTokens(ppszRawHeaderLines
);
2695 *lpdwBufferLength
= (size
+ 1) * sizeof(WCHAR
);
2696 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2701 for (i
= 0; ppszRawHeaderLines
[i
]; i
++)
2703 DWORD len
= strlenW(ppszRawHeaderLines
[i
]);
2704 memcpy(pszString
, ppszRawHeaderLines
[i
], (len
+1)*sizeof(WCHAR
));
2708 TRACE("returning data: %s\n", debugstr_wn(lpBuffer
, size
));
2710 *lpdwBufferLength
= size
* sizeof(WCHAR
);
2711 HTTP_FreeTokens(ppszRawHeaderLines
);
2715 case HTTP_QUERY_STATUS_TEXT
:
2716 if (lpwhr
->lpszStatusText
)
2718 DWORD len
= strlenW(lpwhr
->lpszStatusText
);
2719 if (len
+ 1 > *lpdwBufferLength
/sizeof(WCHAR
))
2721 *lpdwBufferLength
= (len
+ 1) * sizeof(WCHAR
);
2722 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2727 memcpy(lpBuffer
, lpwhr
->lpszStatusText
, (len
+ 1) * sizeof(WCHAR
));
2728 TRACE("returning data: %s\n", debugstr_wn(lpBuffer
, len
));
2730 *lpdwBufferLength
= len
* sizeof(WCHAR
);
2734 case HTTP_QUERY_VERSION
:
2735 if (lpwhr
->lpszVersion
)
2737 DWORD len
= strlenW(lpwhr
->lpszVersion
);
2738 if (len
+ 1 > *lpdwBufferLength
/sizeof(WCHAR
))
2740 *lpdwBufferLength
= (len
+ 1) * sizeof(WCHAR
);
2741 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2746 memcpy(lpBuffer
, lpwhr
->lpszVersion
, (len
+ 1) * sizeof(WCHAR
));
2747 TRACE("returning data: %s\n", debugstr_wn(lpBuffer
, len
));
2749 *lpdwBufferLength
= len
* sizeof(WCHAR
);
2753 case HTTP_QUERY_CONTENT_ENCODING
:
2754 index
= HTTP_GetCustomHeaderIndex(lpwhr
, header_lookup
[lpwhr
->gzip_stream
? HTTP_QUERY_CONTENT_TYPE
: level
],
2755 requested_index
,request_only
);
2758 assert (LAST_TABLE_HEADER
== (HTTP_QUERY_UNLESS_MODIFIED_SINCE
+ 1));
2760 if (level
< LAST_TABLE_HEADER
&& header_lookup
[level
])
2761 index
= HTTP_GetCustomHeaderIndex(lpwhr
, header_lookup
[level
],
2762 requested_index
,request_only
);
2766 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
2768 /* Ensure header satisfies requested attributes */
2770 ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
2771 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
)))
2773 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
2777 if (lpdwIndex
&& level
!= HTTP_QUERY_STATUS_CODE
) (*lpdwIndex
)++;
2779 /* coalesce value to requested type */
2780 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
&& lpBuffer
)
2782 *(int *)lpBuffer
= atoiW(lphttpHdr
->lpszValue
);
2783 TRACE(" returning number: %d\n", *(int *)lpBuffer
);
2786 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
&& lpBuffer
)
2792 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
2794 tmpTM
= *gmtime(&tmpTime
);
2795 STHook
= (SYSTEMTIME
*)lpBuffer
;
2796 STHook
->wDay
= tmpTM
.tm_mday
;
2797 STHook
->wHour
= tmpTM
.tm_hour
;
2798 STHook
->wMilliseconds
= 0;
2799 STHook
->wMinute
= tmpTM
.tm_min
;
2800 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
2801 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
2802 STHook
->wSecond
= tmpTM
.tm_sec
;
2803 STHook
->wYear
= tmpTM
.tm_year
;
2806 TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
2807 STHook
->wYear
, STHook
->wMonth
, STHook
->wDay
, STHook
->wDayOfWeek
,
2808 STHook
->wHour
, STHook
->wMinute
, STHook
->wSecond
, STHook
->wMilliseconds
);
2810 else if (lphttpHdr
->lpszValue
)
2812 DWORD len
= (strlenW(lphttpHdr
->lpszValue
) + 1) * sizeof(WCHAR
);
2814 if (len
> *lpdwBufferLength
)
2816 *lpdwBufferLength
= len
;
2817 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2822 memcpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
2823 TRACE(" returning string: %s\n", debugstr_w(lpBuffer
));
2825 *lpdwBufferLength
= len
- sizeof(WCHAR
);
2831 /***********************************************************************
2832 * HttpQueryInfoW (WININET.@)
2834 * Queries for information about an HTTP request
2841 BOOL WINAPI
HttpQueryInfoW(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
2842 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
2844 BOOL bSuccess
= FALSE
;
2845 http_request_t
*lpwhr
;
2847 if (TRACE_ON(wininet
)) {
2848 #define FE(x) { x, #x }
2849 static const wininet_flag_info query_flags
[] = {
2850 FE(HTTP_QUERY_MIME_VERSION
),
2851 FE(HTTP_QUERY_CONTENT_TYPE
),
2852 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING
),
2853 FE(HTTP_QUERY_CONTENT_ID
),
2854 FE(HTTP_QUERY_CONTENT_DESCRIPTION
),
2855 FE(HTTP_QUERY_CONTENT_LENGTH
),
2856 FE(HTTP_QUERY_CONTENT_LANGUAGE
),
2857 FE(HTTP_QUERY_ALLOW
),
2858 FE(HTTP_QUERY_PUBLIC
),
2859 FE(HTTP_QUERY_DATE
),
2860 FE(HTTP_QUERY_EXPIRES
),
2861 FE(HTTP_QUERY_LAST_MODIFIED
),
2862 FE(HTTP_QUERY_MESSAGE_ID
),
2864 FE(HTTP_QUERY_DERIVED_FROM
),
2865 FE(HTTP_QUERY_COST
),
2866 FE(HTTP_QUERY_LINK
),
2867 FE(HTTP_QUERY_PRAGMA
),
2868 FE(HTTP_QUERY_VERSION
),
2869 FE(HTTP_QUERY_STATUS_CODE
),
2870 FE(HTTP_QUERY_STATUS_TEXT
),
2871 FE(HTTP_QUERY_RAW_HEADERS
),
2872 FE(HTTP_QUERY_RAW_HEADERS_CRLF
),
2873 FE(HTTP_QUERY_CONNECTION
),
2874 FE(HTTP_QUERY_ACCEPT
),
2875 FE(HTTP_QUERY_ACCEPT_CHARSET
),
2876 FE(HTTP_QUERY_ACCEPT_ENCODING
),
2877 FE(HTTP_QUERY_ACCEPT_LANGUAGE
),
2878 FE(HTTP_QUERY_AUTHORIZATION
),
2879 FE(HTTP_QUERY_CONTENT_ENCODING
),
2880 FE(HTTP_QUERY_FORWARDED
),
2881 FE(HTTP_QUERY_FROM
),
2882 FE(HTTP_QUERY_IF_MODIFIED_SINCE
),
2883 FE(HTTP_QUERY_LOCATION
),
2884 FE(HTTP_QUERY_ORIG_URI
),
2885 FE(HTTP_QUERY_REFERER
),
2886 FE(HTTP_QUERY_RETRY_AFTER
),
2887 FE(HTTP_QUERY_SERVER
),
2888 FE(HTTP_QUERY_TITLE
),
2889 FE(HTTP_QUERY_USER_AGENT
),
2890 FE(HTTP_QUERY_WWW_AUTHENTICATE
),
2891 FE(HTTP_QUERY_PROXY_AUTHENTICATE
),
2892 FE(HTTP_QUERY_ACCEPT_RANGES
),
2893 FE(HTTP_QUERY_SET_COOKIE
),
2894 FE(HTTP_QUERY_COOKIE
),
2895 FE(HTTP_QUERY_REQUEST_METHOD
),
2896 FE(HTTP_QUERY_REFRESH
),
2897 FE(HTTP_QUERY_CONTENT_DISPOSITION
),
2899 FE(HTTP_QUERY_CACHE_CONTROL
),
2900 FE(HTTP_QUERY_CONTENT_BASE
),
2901 FE(HTTP_QUERY_CONTENT_LOCATION
),
2902 FE(HTTP_QUERY_CONTENT_MD5
),
2903 FE(HTTP_QUERY_CONTENT_RANGE
),
2904 FE(HTTP_QUERY_ETAG
),
2905 FE(HTTP_QUERY_HOST
),
2906 FE(HTTP_QUERY_IF_MATCH
),
2907 FE(HTTP_QUERY_IF_NONE_MATCH
),
2908 FE(HTTP_QUERY_IF_RANGE
),
2909 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE
),
2910 FE(HTTP_QUERY_MAX_FORWARDS
),
2911 FE(HTTP_QUERY_PROXY_AUTHORIZATION
),
2912 FE(HTTP_QUERY_RANGE
),
2913 FE(HTTP_QUERY_TRANSFER_ENCODING
),
2914 FE(HTTP_QUERY_UPGRADE
),
2915 FE(HTTP_QUERY_VARY
),
2917 FE(HTTP_QUERY_WARNING
),
2918 FE(HTTP_QUERY_CUSTOM
)
2920 static const wininet_flag_info modifier_flags
[] = {
2921 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS
),
2922 FE(HTTP_QUERY_FLAG_SYSTEMTIME
),
2923 FE(HTTP_QUERY_FLAG_NUMBER
),
2924 FE(HTTP_QUERY_FLAG_COALESCE
)
2927 DWORD info_mod
= dwInfoLevel
& HTTP_QUERY_MODIFIER_FLAGS_MASK
;
2928 DWORD info
= dwInfoLevel
& HTTP_QUERY_HEADER_MASK
;
2931 TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest
, dwInfoLevel
, dwInfoLevel
);
2932 TRACE(" Attribute:");
2933 for (i
= 0; i
< (sizeof(query_flags
) / sizeof(query_flags
[0])); i
++) {
2934 if (query_flags
[i
].val
== info
) {
2935 TRACE(" %s", query_flags
[i
].name
);
2939 if (i
== (sizeof(query_flags
) / sizeof(query_flags
[0]))) {
2940 TRACE(" Unknown (%08x)", info
);
2943 TRACE(" Modifier:");
2944 for (i
= 0; i
< (sizeof(modifier_flags
) / sizeof(modifier_flags
[0])); i
++) {
2945 if (modifier_flags
[i
].val
& info_mod
) {
2946 TRACE(" %s", modifier_flags
[i
].name
);
2947 info_mod
&= ~ modifier_flags
[i
].val
;
2952 TRACE(" Unknown (%08x)", info_mod
);
2957 lpwhr
= (http_request_t
*) WININET_GetObject( hHttpRequest
);
2958 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
2960 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
2964 if (lpBuffer
== NULL
)
2965 *lpdwBufferLength
= 0;
2966 bSuccess
= HTTP_HttpQueryInfoW( lpwhr
, dwInfoLevel
,
2967 lpBuffer
, lpdwBufferLength
, lpdwIndex
);
2971 WININET_Release( &lpwhr
->hdr
);
2973 TRACE("%d <--\n", bSuccess
);
2977 /***********************************************************************
2978 * HttpQueryInfoA (WININET.@)
2980 * Queries for information about an HTTP request
2987 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
2988 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
2994 if((dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
) ||
2995 (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
))
2997 return HttpQueryInfoW( hHttpRequest
, dwInfoLevel
, lpBuffer
,
2998 lpdwBufferLength
, lpdwIndex
);
3004 len
= (*lpdwBufferLength
)*sizeof(WCHAR
);
3005 if ((dwInfoLevel
& HTTP_QUERY_HEADER_MASK
) == HTTP_QUERY_CUSTOM
)
3007 alloclen
= MultiByteToWideChar( CP_ACP
, 0, lpBuffer
, -1, NULL
, 0 ) * sizeof(WCHAR
);
3013 bufferW
= HeapAlloc( GetProcessHeap(), 0, alloclen
);
3014 /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3015 if ((dwInfoLevel
& HTTP_QUERY_HEADER_MASK
) == HTTP_QUERY_CUSTOM
)
3016 MultiByteToWideChar( CP_ACP
, 0, lpBuffer
, -1, bufferW
, alloclen
/ sizeof(WCHAR
) );
3023 result
= HttpQueryInfoW( hHttpRequest
, dwInfoLevel
, bufferW
,
3027 len
= WideCharToMultiByte( CP_ACP
,0, bufferW
, len
/ sizeof(WCHAR
) + 1,
3028 lpBuffer
, *lpdwBufferLength
, NULL
, NULL
);
3029 *lpdwBufferLength
= len
- 1;
3031 TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer
));
3034 /* since the strings being returned from HttpQueryInfoW should be
3035 * only ASCII characters, it is reasonable to assume that all of
3036 * the Unicode characters can be reduced to a single byte */
3037 *lpdwBufferLength
= len
/ sizeof(WCHAR
);
3039 HeapFree(GetProcessHeap(), 0, bufferW
);
3044 /***********************************************************************
3045 * HttpSendRequestExA (WININET.@)
3047 * Sends the specified request to the HTTP server and allows chunked
3052 * Failure: FALSE, call GetLastError() for more information.
3054 BOOL WINAPI
HttpSendRequestExA(HINTERNET hRequest
,
3055 LPINTERNET_BUFFERSA lpBuffersIn
,
3056 LPINTERNET_BUFFERSA lpBuffersOut
,
3057 DWORD dwFlags
, DWORD_PTR dwContext
)
3059 INTERNET_BUFFERSW BuffersInW
;
3062 LPWSTR header
= NULL
;
3064 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest
, lpBuffersIn
,
3065 lpBuffersOut
, dwFlags
, dwContext
);
3069 BuffersInW
.dwStructSize
= sizeof(LPINTERNET_BUFFERSW
);
3070 if (lpBuffersIn
->lpcszHeader
)
3072 headerlen
= MultiByteToWideChar(CP_ACP
,0,lpBuffersIn
->lpcszHeader
,
3073 lpBuffersIn
->dwHeadersLength
,0,0);
3074 header
= HeapAlloc(GetProcessHeap(),0,headerlen
*sizeof(WCHAR
));
3075 if (!(BuffersInW
.lpcszHeader
= header
))
3077 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
3080 BuffersInW
.dwHeadersLength
= MultiByteToWideChar(CP_ACP
, 0,
3081 lpBuffersIn
->lpcszHeader
, lpBuffersIn
->dwHeadersLength
,
3085 BuffersInW
.lpcszHeader
= NULL
;
3086 BuffersInW
.dwHeadersTotal
= lpBuffersIn
->dwHeadersTotal
;
3087 BuffersInW
.lpvBuffer
= lpBuffersIn
->lpvBuffer
;
3088 BuffersInW
.dwBufferLength
= lpBuffersIn
->dwBufferLength
;
3089 BuffersInW
.dwBufferTotal
= lpBuffersIn
->dwBufferTotal
;
3090 BuffersInW
.Next
= NULL
;
3093 rc
= HttpSendRequestExW(hRequest
, lpBuffersIn
? &BuffersInW
: NULL
, NULL
, dwFlags
, dwContext
);
3095 HeapFree(GetProcessHeap(),0,header
);
3100 /***********************************************************************
3101 * HttpSendRequestExW (WININET.@)
3103 * Sends the specified request to the HTTP server and allows chunked
3108 * Failure: FALSE, call GetLastError() for more information.
3110 BOOL WINAPI
HttpSendRequestExW(HINTERNET hRequest
,
3111 LPINTERNET_BUFFERSW lpBuffersIn
,
3112 LPINTERNET_BUFFERSW lpBuffersOut
,
3113 DWORD dwFlags
, DWORD_PTR dwContext
)
3116 http_request_t
*lpwhr
;
3117 http_session_t
*lpwhs
;
3120 TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest
, lpBuffersIn
,
3121 lpBuffersOut
, dwFlags
, dwContext
);
3123 lpwhr
= (http_request_t
*) WININET_GetObject( hRequest
);
3125 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
3127 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
3131 lpwhs
= lpwhr
->lpHttpSession
;
3132 assert(lpwhs
->hdr
.htype
== WH_HHTTPSESSION
);
3133 hIC
= lpwhs
->lpAppInfo
;
3134 assert(hIC
->hdr
.htype
== WH_HINIT
);
3136 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
3138 WORKREQUEST workRequest
;
3139 struct WORKREQ_HTTPSENDREQUESTW
*req
;
3141 workRequest
.asyncproc
= AsyncHttpSendRequestProc
;
3142 workRequest
.hdr
= WININET_AddRef( &lpwhr
->hdr
);
3143 req
= &workRequest
.u
.HttpSendRequestW
;
3146 /* FIXME: this should use dwHeadersLength or may not be necessary at all */
3147 req
->lpszHeader
= heap_strdupW(lpBuffersIn
->lpcszHeader
);
3148 req
->dwHeaderLength
= lpBuffersIn
->dwHeadersLength
;
3149 req
->lpOptional
= lpBuffersIn
->lpvBuffer
;
3150 req
->dwOptionalLength
= lpBuffersIn
->dwBufferLength
;
3151 req
->dwContentLength
= lpBuffersIn
->dwBufferTotal
;
3155 req
->lpszHeader
= NULL
;
3156 req
->dwHeaderLength
= 0;
3157 req
->lpOptional
= NULL
;
3158 req
->dwOptionalLength
= 0;
3159 req
->dwContentLength
= 0;
3162 req
->bEndRequest
= FALSE
;
3164 INTERNET_AsyncCall(&workRequest
);
3166 * This is from windows.
3168 INTERNET_SetLastError(ERROR_IO_PENDING
);
3173 ret
= HTTP_HttpSendRequestW(lpwhr
, lpBuffersIn
->lpcszHeader
, lpBuffersIn
->dwHeadersLength
,
3174 lpBuffersIn
->lpvBuffer
, lpBuffersIn
->dwBufferLength
,
3175 lpBuffersIn
->dwBufferTotal
, FALSE
);
3177 ret
= HTTP_HttpSendRequestW(lpwhr
, NULL
, 0, NULL
, 0, 0, FALSE
);
3182 WININET_Release( &lpwhr
->hdr
);
3188 /***********************************************************************
3189 * HttpSendRequestW (WININET.@)
3191 * Sends the specified request to the HTTP server
3198 BOOL WINAPI
HttpSendRequestW(HINTERNET hHttpRequest
, LPCWSTR lpszHeaders
,
3199 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
3201 http_request_t
*lpwhr
;
3202 http_session_t
*lpwhs
= NULL
;
3203 appinfo_t
*hIC
= NULL
;
3206 TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest
,
3207 debugstr_wn(lpszHeaders
, dwHeaderLength
), dwHeaderLength
, lpOptional
, dwOptionalLength
);
3209 lpwhr
= (http_request_t
*) WININET_GetObject( hHttpRequest
);
3210 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
3212 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
3217 lpwhs
= lpwhr
->lpHttpSession
;
3218 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
3220 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
3225 hIC
= lpwhs
->lpAppInfo
;
3226 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
3228 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
3233 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
3235 WORKREQUEST workRequest
;
3236 struct WORKREQ_HTTPSENDREQUESTW
*req
;
3238 workRequest
.asyncproc
= AsyncHttpSendRequestProc
;
3239 workRequest
.hdr
= WININET_AddRef( &lpwhr
->hdr
);
3240 req
= &workRequest
.u
.HttpSendRequestW
;
3245 if (dwHeaderLength
== ~0u) size
= (strlenW(lpszHeaders
) + 1) * sizeof(WCHAR
);
3246 else size
= dwHeaderLength
* sizeof(WCHAR
);
3248 req
->lpszHeader
= HeapAlloc(GetProcessHeap(), 0, size
);
3249 memcpy(req
->lpszHeader
, lpszHeaders
, size
);
3252 req
->lpszHeader
= 0;
3253 req
->dwHeaderLength
= dwHeaderLength
;
3254 req
->lpOptional
= lpOptional
;
3255 req
->dwOptionalLength
= dwOptionalLength
;
3256 req
->dwContentLength
= dwOptionalLength
;
3257 req
->bEndRequest
= TRUE
;
3259 INTERNET_AsyncCall(&workRequest
);
3261 * This is from windows.
3263 INTERNET_SetLastError(ERROR_IO_PENDING
);
3268 r
= HTTP_HttpSendRequestW(lpwhr
, lpszHeaders
,
3269 dwHeaderLength
, lpOptional
, dwOptionalLength
,
3270 dwOptionalLength
, TRUE
);
3274 WININET_Release( &lpwhr
->hdr
);
3278 /***********************************************************************
3279 * HttpSendRequestA (WININET.@)
3281 * Sends the specified request to the HTTP server
3288 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
3289 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
3292 LPWSTR szHeaders
=NULL
;
3293 DWORD nLen
=dwHeaderLength
;
3294 if(lpszHeaders
!=NULL
)
3296 nLen
=MultiByteToWideChar(CP_ACP
,0,lpszHeaders
,dwHeaderLength
,NULL
,0);
3297 szHeaders
=HeapAlloc(GetProcessHeap(),0,nLen
*sizeof(WCHAR
));
3298 MultiByteToWideChar(CP_ACP
,0,lpszHeaders
,dwHeaderLength
,szHeaders
,nLen
);
3300 result
=HttpSendRequestW(hHttpRequest
, szHeaders
, nLen
, lpOptional
, dwOptionalLength
);
3301 HeapFree(GetProcessHeap(),0,szHeaders
);
3305 /***********************************************************************
3306 * HTTP_GetRedirectURL (internal)
3308 static LPWSTR
HTTP_GetRedirectURL(http_request_t
*lpwhr
, LPCWSTR lpszUrl
)
3310 static WCHAR szHttp
[] = {'h','t','t','p',0};
3311 static WCHAR szHttps
[] = {'h','t','t','p','s',0};
3312 http_session_t
*lpwhs
= lpwhr
->lpHttpSession
;
3313 URL_COMPONENTSW urlComponents
;
3314 DWORD url_length
= 0;
3316 LPWSTR combined_url
;
3318 urlComponents
.dwStructSize
= sizeof(URL_COMPONENTSW
);
3319 urlComponents
.lpszScheme
= (lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
) ? szHttps
: szHttp
;
3320 urlComponents
.dwSchemeLength
= 0;
3321 urlComponents
.lpszHostName
= lpwhs
->lpszHostName
;
3322 urlComponents
.dwHostNameLength
= 0;
3323 urlComponents
.nPort
= lpwhs
->nHostPort
;
3324 urlComponents
.lpszUserName
= lpwhs
->lpszUserName
;
3325 urlComponents
.dwUserNameLength
= 0;
3326 urlComponents
.lpszPassword
= NULL
;
3327 urlComponents
.dwPasswordLength
= 0;
3328 urlComponents
.lpszUrlPath
= lpwhr
->lpszPath
;
3329 urlComponents
.dwUrlPathLength
= 0;
3330 urlComponents
.lpszExtraInfo
= NULL
;
3331 urlComponents
.dwExtraInfoLength
= 0;
3333 if (!InternetCreateUrlW(&urlComponents
, 0, NULL
, &url_length
) &&
3334 (GetLastError() != ERROR_INSUFFICIENT_BUFFER
))
3337 orig_url
= HeapAlloc(GetProcessHeap(), 0, url_length
);
3339 /* convert from bytes to characters */
3340 url_length
= url_length
/ sizeof(WCHAR
) - 1;
3341 if (!InternetCreateUrlW(&urlComponents
, 0, orig_url
, &url_length
))
3343 HeapFree(GetProcessHeap(), 0, orig_url
);
3348 if (!InternetCombineUrlW(orig_url
, lpszUrl
, NULL
, &url_length
, ICU_ENCODE_SPACES_ONLY
) &&
3349 (GetLastError() != ERROR_INSUFFICIENT_BUFFER
))
3351 HeapFree(GetProcessHeap(), 0, orig_url
);
3354 combined_url
= HeapAlloc(GetProcessHeap(), 0, url_length
* sizeof(WCHAR
));
3356 if (!InternetCombineUrlW(orig_url
, lpszUrl
, combined_url
, &url_length
, ICU_ENCODE_SPACES_ONLY
))
3358 HeapFree(GetProcessHeap(), 0, orig_url
);
3359 HeapFree(GetProcessHeap(), 0, combined_url
);
3362 HeapFree(GetProcessHeap(), 0, orig_url
);
3363 return combined_url
;
3367 /***********************************************************************
3368 * HTTP_HandleRedirect (internal)
3370 static BOOL
HTTP_HandleRedirect(http_request_t
*lpwhr
, LPCWSTR lpszUrl
)
3372 http_session_t
*lpwhs
= lpwhr
->lpHttpSession
;
3373 appinfo_t
*hIC
= lpwhs
->lpAppInfo
;
3374 BOOL using_proxy
= hIC
->lpszProxy
&& hIC
->lpszProxy
[0];
3375 WCHAR path
[INTERNET_MAX_URL_LENGTH
];
3380 /* if it's an absolute path, keep the same session info */
3381 lstrcpynW(path
, lpszUrl
, INTERNET_MAX_URL_LENGTH
);
3385 URL_COMPONENTSW urlComponents
;
3386 WCHAR protocol
[32], hostName
[MAXHOSTNAME
], userName
[1024];
3387 static WCHAR szHttp
[] = {'h','t','t','p',0};
3388 static WCHAR szHttps
[] = {'h','t','t','p','s',0};
3394 urlComponents
.dwStructSize
= sizeof(URL_COMPONENTSW
);
3395 urlComponents
.lpszScheme
= protocol
;
3396 urlComponents
.dwSchemeLength
= 32;
3397 urlComponents
.lpszHostName
= hostName
;
3398 urlComponents
.dwHostNameLength
= MAXHOSTNAME
;
3399 urlComponents
.lpszUserName
= userName
;
3400 urlComponents
.dwUserNameLength
= 1024;
3401 urlComponents
.lpszPassword
= NULL
;
3402 urlComponents
.dwPasswordLength
= 0;
3403 urlComponents
.lpszUrlPath
= path
;
3404 urlComponents
.dwUrlPathLength
= 2048;
3405 urlComponents
.lpszExtraInfo
= NULL
;
3406 urlComponents
.dwExtraInfoLength
= 0;
3407 if(!InternetCrackUrlW(lpszUrl
, strlenW(lpszUrl
), 0, &urlComponents
))
3410 if (!strncmpW(szHttp
, urlComponents
.lpszScheme
, strlenW(szHttp
)) &&
3411 (lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
))
3413 TRACE("redirect from secure page to non-secure page\n");
3414 /* FIXME: warn about from secure redirect to non-secure page */
3415 lpwhr
->hdr
.dwFlags
&= ~INTERNET_FLAG_SECURE
;
3417 if (!strncmpW(szHttps
, urlComponents
.lpszScheme
, strlenW(szHttps
)) &&
3418 !(lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
))
3420 TRACE("redirect from non-secure page to secure page\n");
3421 /* FIXME: notify about redirect to secure page */
3422 lpwhr
->hdr
.dwFlags
|= INTERNET_FLAG_SECURE
;
3425 if (urlComponents
.nPort
== INTERNET_INVALID_PORT_NUMBER
)
3427 if (lstrlenW(protocol
)>4) /*https*/
3428 urlComponents
.nPort
= INTERNET_DEFAULT_HTTPS_PORT
;
3430 urlComponents
.nPort
= INTERNET_DEFAULT_HTTP_PORT
;
3435 * This upsets redirects to binary files on sourceforge.net
3436 * and gives an html page instead of the target file
3437 * Examination of the HTTP request sent by native wininet.dll
3438 * reveals that it doesn't send a referrer in that case.
3439 * Maybe there's a flag that enables this, or maybe a referrer
3440 * shouldn't be added in case of a redirect.
3443 /* consider the current host as the referrer */
3444 if (lpwhs
->lpszServerName
&& *lpwhs
->lpszServerName
)
3445 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpwhs
->lpszServerName
,
3446 HTTP_ADDHDR_FLAG_REQ
|HTTP_ADDREQ_FLAG_REPLACE
|
3447 HTTP_ADDHDR_FLAG_ADD_IF_NEW
);
3450 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszHostName
);
3451 if (urlComponents
.nPort
!= INTERNET_DEFAULT_HTTP_PORT
&&
3452 urlComponents
.nPort
!= INTERNET_DEFAULT_HTTPS_PORT
)
3455 static const WCHAR fmt
[] = {'%','s',':','%','i',0};
3456 len
= lstrlenW(hostName
);
3457 len
+= 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
3458 lpwhs
->lpszHostName
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
3459 sprintfW(lpwhs
->lpszHostName
, fmt
, hostName
, urlComponents
.nPort
);
3462 lpwhs
->lpszHostName
= heap_strdupW(hostName
);
3464 HTTP_ProcessHeader(lpwhr
, hostW
, lpwhs
->lpszHostName
, HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
| HTTP_ADDHDR_FLAG_REQ
);
3466 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
3467 lpwhs
->lpszUserName
= NULL
;
3469 lpwhs
->lpszUserName
= heap_strdupW(userName
);
3473 if (strcmpiW(lpwhs
->lpszServerName
, hostName
) || lpwhs
->nServerPort
!= urlComponents
.nPort
)
3475 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
3476 lpwhs
->lpszServerName
= heap_strdupW(hostName
);
3477 lpwhs
->nServerPort
= urlComponents
.nPort
;
3479 NETCON_close(&lpwhr
->netConnection
);
3480 if (!HTTP_ResolveName(lpwhr
)) return FALSE
;
3481 if (!NETCON_init(&lpwhr
->netConnection
, lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
)) return FALSE
;
3482 lpwhr
->read_pos
= lpwhr
->read_size
= 0;
3483 lpwhr
->read_chunked
= FALSE
;
3487 TRACE("Redirect through proxy\n");
3490 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
3491 lpwhr
->lpszPath
=NULL
;
3497 rc
= UrlEscapeW(path
, NULL
, &needed
, URL_ESCAPE_SPACES_ONLY
);
3498 if (rc
!= E_POINTER
)
3499 needed
= strlenW(path
)+1;
3500 lpwhr
->lpszPath
= HeapAlloc(GetProcessHeap(), 0, needed
*sizeof(WCHAR
));
3501 rc
= UrlEscapeW(path
, lpwhr
->lpszPath
, &needed
,
3502 URL_ESCAPE_SPACES_ONLY
);
3505 ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path
),rc
);
3506 strcpyW(lpwhr
->lpszPath
,path
);
3510 /* Remove custom content-type/length headers on redirects. */
3511 index
= HTTP_GetCustomHeaderIndex(lpwhr
, szContent_Type
, 0, TRUE
);
3513 HTTP_DeleteCustomHeader(lpwhr
, index
);
3514 index
= HTTP_GetCustomHeaderIndex(lpwhr
, szContent_Length
, 0, TRUE
);
3516 HTTP_DeleteCustomHeader(lpwhr
, index
);
3521 /***********************************************************************
3522 * HTTP_build_req (internal)
3524 * concatenate all the strings in the request together
3526 static LPWSTR
HTTP_build_req( LPCWSTR
*list
, int len
)
3531 for( t
= list
; *t
; t
++ )
3532 len
+= strlenW( *t
);
3535 str
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
3538 for( t
= list
; *t
; t
++ )
3544 static BOOL
HTTP_SecureProxyConnect(http_request_t
*lpwhr
)
3547 LPWSTR requestString
;
3553 static const WCHAR szConnect
[] = {'C','O','N','N','E','C','T',0};
3554 static const WCHAR szFormat
[] = {'%','s',':','%','d',0};
3555 http_session_t
*lpwhs
= lpwhr
->lpHttpSession
;
3559 lpszPath
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW( lpwhs
->lpszHostName
) + 13)*sizeof(WCHAR
) );
3560 sprintfW( lpszPath
, szFormat
, lpwhs
->lpszHostName
, lpwhs
->nHostPort
);
3561 requestString
= HTTP_BuildHeaderRequestString( lpwhr
, szConnect
, lpszPath
, g_szHttp1_1
);
3562 HeapFree( GetProcessHeap(), 0, lpszPath
);
3564 len
= WideCharToMultiByte( CP_ACP
, 0, requestString
, -1,
3565 NULL
, 0, NULL
, NULL
);
3566 len
--; /* the nul terminator isn't needed */
3567 ascii_req
= HeapAlloc( GetProcessHeap(), 0, len
);
3568 WideCharToMultiByte( CP_ACP
, 0, requestString
, -1,
3569 ascii_req
, len
, NULL
, NULL
);
3570 HeapFree( GetProcessHeap(), 0, requestString
);
3572 TRACE("full request -> %s\n", debugstr_an( ascii_req
, len
) );
3574 ret
= NETCON_send( &lpwhr
->netConnection
, ascii_req
, len
, 0, &cnt
);
3575 HeapFree( GetProcessHeap(), 0, ascii_req
);
3576 if (!ret
|| cnt
< 0)
3579 responseLen
= HTTP_GetResponseHeaders( lpwhr
, TRUE
);
3586 static void HTTP_InsertCookies(http_request_t
*lpwhr
)
3588 static const WCHAR szUrlForm
[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
3589 LPWSTR lpszCookies
, lpszUrl
= NULL
;
3590 DWORD nCookieSize
, size
;
3591 LPHTTPHEADERW Host
= HTTP_GetHeader(lpwhr
, hostW
);
3593 size
= (strlenW(Host
->lpszValue
) + strlenW(szUrlForm
) + strlenW(lpwhr
->lpszPath
)) * sizeof(WCHAR
);
3594 if (!(lpszUrl
= HeapAlloc(GetProcessHeap(), 0, size
))) return;
3595 sprintfW( lpszUrl
, szUrlForm
, Host
->lpszValue
, lpwhr
->lpszPath
);
3597 if (InternetGetCookieW(lpszUrl
, NULL
, NULL
, &nCookieSize
))
3600 static const WCHAR szCookie
[] = {'C','o','o','k','i','e',':',' ',0};
3602 size
= sizeof(szCookie
) + nCookieSize
* sizeof(WCHAR
) + sizeof(szCrLf
);
3603 if ((lpszCookies
= HeapAlloc(GetProcessHeap(), 0, size
)))
3605 cnt
+= sprintfW(lpszCookies
, szCookie
);
3606 InternetGetCookieW(lpszUrl
, NULL
, lpszCookies
+ cnt
, &nCookieSize
);
3607 strcatW(lpszCookies
, szCrLf
);
3609 HTTP_HttpAddRequestHeadersW(lpwhr
, lpszCookies
, strlenW(lpszCookies
), HTTP_ADDREQ_FLAG_REPLACE
);
3610 HeapFree(GetProcessHeap(), 0, lpszCookies
);
3613 HeapFree(GetProcessHeap(), 0, lpszUrl
);
3616 /***********************************************************************
3617 * HTTP_HttpSendRequestW (internal)
3619 * Sends the specified request to the HTTP server
3626 BOOL WINAPI
HTTP_HttpSendRequestW(http_request_t
*lpwhr
, LPCWSTR lpszHeaders
,
3627 DWORD dwHeaderLength
, LPVOID lpOptional
, DWORD dwOptionalLength
,
3628 DWORD dwContentLength
, BOOL bEndRequest
)
3631 BOOL bSuccess
= FALSE
, redirected
= FALSE
;
3632 LPWSTR requestString
= NULL
;
3635 INTERNET_ASYNC_RESULT iar
;
3636 static const WCHAR szPost
[] = { 'P','O','S','T',0 };
3637 static const WCHAR szContentLength
[] =
3638 { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
3639 WCHAR contentLengthStr
[sizeof szContentLength
/2 /* includes \r\n */ + 20 /* int */ ];
3641 TRACE("--> %p\n", lpwhr
);
3643 assert(lpwhr
->hdr
.htype
== WH_HHTTPREQ
);
3645 /* if the verb is NULL default to GET */
3646 if (!lpwhr
->lpszVerb
)
3647 lpwhr
->lpszVerb
= heap_strdupW(szGET
);
3649 if (dwContentLength
|| strcmpW(lpwhr
->lpszVerb
, szGET
))
3651 sprintfW(contentLengthStr
, szContentLength
, dwContentLength
);
3652 HTTP_HttpAddRequestHeadersW(lpwhr
, contentLengthStr
, -1L, HTTP_ADDREQ_FLAG_REPLACE
);
3653 lpwhr
->dwBytesToWrite
= dwContentLength
;
3655 if (lpwhr
->lpHttpSession
->lpAppInfo
->lpszAgent
)
3657 WCHAR
*agent_header
;
3658 static const WCHAR user_agent
[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0};
3661 len
= strlenW(lpwhr
->lpHttpSession
->lpAppInfo
->lpszAgent
) + strlenW(user_agent
);
3662 agent_header
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3663 sprintfW(agent_header
, user_agent
, lpwhr
->lpHttpSession
->lpAppInfo
->lpszAgent
);
3665 HTTP_HttpAddRequestHeadersW(lpwhr
, agent_header
, strlenW(agent_header
), HTTP_ADDREQ_FLAG_ADD_IF_NEW
);
3666 HeapFree(GetProcessHeap(), 0, agent_header
);
3668 if (lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_PRAGMA_NOCACHE
)
3670 static const WCHAR pragma_nocache
[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0};
3671 HTTP_HttpAddRequestHeadersW(lpwhr
, pragma_nocache
, strlenW(pragma_nocache
), HTTP_ADDREQ_FLAG_ADD_IF_NEW
);
3673 if ((lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_NO_CACHE_WRITE
) && !strcmpW(lpwhr
->lpszVerb
, szPost
))
3675 static const WCHAR cache_control
[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
3676 ' ','n','o','-','c','a','c','h','e','\r','\n',0};
3677 HTTP_HttpAddRequestHeadersW(lpwhr
, cache_control
, strlenW(cache_control
), HTTP_ADDREQ_FLAG_ADD_IF_NEW
);
3687 /* like native, just in case the caller forgot to call InternetReadFile
3688 * for all the data */
3689 HTTP_DrainContent(lpwhr
);
3690 lpwhr
->dwContentRead
= 0;
3692 if (TRACE_ON(wininet
))
3694 LPHTTPHEADERW Host
= HTTP_GetHeader(lpwhr
, hostW
);
3695 TRACE("Going to url %s %s\n", debugstr_w(Host
->lpszValue
), debugstr_w(lpwhr
->lpszPath
));
3699 if (lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_KEEP_CONNECTION
)
3701 HTTP_ProcessHeader(lpwhr
, szConnection
, szKeepAlive
, HTTP_ADDHDR_FLAG_REQ
| HTTP_ADDHDR_FLAG_REPLACE
);
3703 HTTP_InsertAuthorization(lpwhr
, lpwhr
->pAuthInfo
, szAuthorization
);
3704 HTTP_InsertAuthorization(lpwhr
, lpwhr
->pProxyAuthInfo
, szProxy_Authorization
);
3706 if (!(lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_NO_COOKIES
))
3707 HTTP_InsertCookies(lpwhr
);
3709 /* add the headers the caller supplied */
3710 if( lpszHeaders
&& dwHeaderLength
)
3712 HTTP_HttpAddRequestHeadersW(lpwhr
, lpszHeaders
, dwHeaderLength
,
3713 HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDHDR_FLAG_REPLACE
);
3716 if (lpwhr
->lpHttpSession
->lpAppInfo
->lpszProxy
&& lpwhr
->lpHttpSession
->lpAppInfo
->lpszProxy
[0])
3718 WCHAR
*url
= HTTP_BuildProxyRequestUrl(lpwhr
);
3719 requestString
= HTTP_BuildHeaderRequestString(lpwhr
, lpwhr
->lpszVerb
, url
, lpwhr
->lpszVersion
);
3720 HeapFree(GetProcessHeap(), 0, url
);
3723 requestString
= HTTP_BuildHeaderRequestString(lpwhr
, lpwhr
->lpszVerb
, lpwhr
->lpszPath
, lpwhr
->lpszVersion
);
3726 TRACE("Request header -> %s\n", debugstr_w(requestString
) );
3728 /* Send the request and store the results */
3729 if (!HTTP_OpenConnection(lpwhr
))
3732 /* send the request as ASCII, tack on the optional data */
3733 if (!lpOptional
|| redirected
)
3734 dwOptionalLength
= 0;
3735 len
= WideCharToMultiByte( CP_ACP
, 0, requestString
, -1,
3736 NULL
, 0, NULL
, NULL
);
3737 ascii_req
= HeapAlloc( GetProcessHeap(), 0, len
+ dwOptionalLength
);
3738 WideCharToMultiByte( CP_ACP
, 0, requestString
, -1,
3739 ascii_req
, len
, NULL
, NULL
);
3741 memcpy( &ascii_req
[len
-1], lpOptional
, dwOptionalLength
);
3742 len
= (len
+ dwOptionalLength
- 1);
3744 TRACE("full request -> %s\n", debugstr_a(ascii_req
) );
3746 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
3747 INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
3749 NETCON_send(&lpwhr
->netConnection
, ascii_req
, len
, 0, &cnt
);
3750 HeapFree( GetProcessHeap(), 0, ascii_req
);
3752 lpwhr
->dwBytesWritten
= dwOptionalLength
;
3754 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
3755 INTERNET_STATUS_REQUEST_SENT
,
3756 &len
, sizeof(DWORD
));
3763 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
3764 INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
3769 responseLen
= HTTP_GetResponseHeaders(lpwhr
, TRUE
);
3773 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
3774 INTERNET_STATUS_RESPONSE_RECEIVED
, &responseLen
,
3777 HTTP_ProcessCookies(lpwhr
);
3779 if (!set_content_length( lpwhr
)) HTTP_FinishedReading(lpwhr
);
3781 dwBufferSize
= sizeof(dwStatusCode
);
3782 if (!HTTP_HttpQueryInfoW(lpwhr
,HTTP_QUERY_FLAG_NUMBER
|HTTP_QUERY_STATUS_CODE
,
3783 &dwStatusCode
,&dwBufferSize
,NULL
))
3786 if (!(lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_NO_AUTO_REDIRECT
) && bSuccess
)
3788 WCHAR
*new_url
, szNewLocation
[INTERNET_MAX_URL_LENGTH
];
3789 dwBufferSize
=sizeof(szNewLocation
);
3790 if ((dwStatusCode
==HTTP_STATUS_REDIRECT
|| dwStatusCode
==HTTP_STATUS_MOVED
) &&
3791 HTTP_HttpQueryInfoW(lpwhr
,HTTP_QUERY_LOCATION
,szNewLocation
,&dwBufferSize
,NULL
))
3793 /* redirects are always GETs */
3794 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
3795 lpwhr
->lpszVerb
= heap_strdupW(szGET
);
3797 HTTP_DrainContent(lpwhr
);
3798 if ((new_url
= HTTP_GetRedirectURL( lpwhr
, szNewLocation
)))
3800 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REDIRECT
,
3801 new_url
, (strlenW(new_url
) + 1) * sizeof(WCHAR
));
3802 bSuccess
= HTTP_HandleRedirect(lpwhr
, new_url
);
3805 HeapFree(GetProcessHeap(), 0, requestString
);
3808 HeapFree( GetProcessHeap(), 0, new_url
);
3813 if (!(lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_NO_AUTH
) && bSuccess
)
3815 WCHAR szAuthValue
[2048];
3817 if (dwStatusCode
== HTTP_STATUS_DENIED
)
3820 while (HTTP_HttpQueryInfoW(lpwhr
,HTTP_QUERY_WWW_AUTHENTICATE
,szAuthValue
,&dwBufferSize
,&dwIndex
))
3822 if (HTTP_DoAuthorization(lpwhr
, szAuthValue
,
3824 lpwhr
->lpHttpSession
->lpszUserName
,
3825 lpwhr
->lpHttpSession
->lpszPassword
))
3832 if (dwStatusCode
== HTTP_STATUS_PROXY_AUTH_REQ
)
3835 while (HTTP_HttpQueryInfoW(lpwhr
,HTTP_QUERY_PROXY_AUTHENTICATE
,szAuthValue
,&dwBufferSize
,&dwIndex
))
3837 if (HTTP_DoAuthorization(lpwhr
, szAuthValue
,
3838 &lpwhr
->pProxyAuthInfo
,
3839 lpwhr
->lpHttpSession
->lpAppInfo
->lpszProxyUsername
,
3840 lpwhr
->lpHttpSession
->lpAppInfo
->lpszProxyPassword
))
3855 WCHAR url
[INTERNET_MAX_URL_LENGTH
];
3856 WCHAR cacheFileName
[MAX_PATH
+1];
3859 b
= HTTP_GetRequestURL(lpwhr
, url
);
3861 WARN("Could not get URL\n");
3865 b
= CreateUrlCacheEntryW(url
, lpwhr
->dwContentLength
> 0 ? lpwhr
->dwContentLength
: 0, NULL
, cacheFileName
, 0);
3867 lpwhr
->lpszCacheFile
= heap_strdupW(cacheFileName
);
3868 lpwhr
->hCacheFile
= CreateFileW(lpwhr
->lpszCacheFile
, GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3869 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3870 if(lpwhr
->hCacheFile
== INVALID_HANDLE_VALUE
) {
3871 WARN("Could not create file: %u\n", GetLastError());
3872 lpwhr
->hCacheFile
= NULL
;
3875 WARN("Could not create cache entry: %08x\n", GetLastError());
3881 HeapFree(GetProcessHeap(), 0, requestString
);
3883 /* TODO: send notification for P3P header */
3885 if (lpwhr
->lpHttpSession
->lpAppInfo
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
3889 if (lpwhr
->dwBytesWritten
== lpwhr
->dwBytesToWrite
) HTTP_ReceiveRequestData(lpwhr
, TRUE
);
3892 iar
.dwResult
= (DWORD_PTR
)lpwhr
->hdr
.hInternet
;
3895 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
3896 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
3897 sizeof(INTERNET_ASYNC_RESULT
));
3902 iar
.dwResult
= (DWORD_PTR
)lpwhr
->hdr
.hInternet
;
3903 iar
.dwError
= INTERNET_GetLastError();
3905 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
3906 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
3907 sizeof(INTERNET_ASYNC_RESULT
));
3912 if (bSuccess
) INTERNET_SetLastError(ERROR_SUCCESS
);
3916 /***********************************************************************
3917 * HTTPSESSION_Destroy (internal)
3919 * Deallocate session handle
3922 static void HTTPSESSION_Destroy(object_header_t
*hdr
)
3924 http_session_t
*lpwhs
= (http_session_t
*) hdr
;
3926 TRACE("%p\n", lpwhs
);
3928 WININET_Release(&lpwhs
->lpAppInfo
->hdr
);
3930 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszHostName
);
3931 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
3932 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszPassword
);
3933 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
3934 HeapFree(GetProcessHeap(), 0, lpwhs
);
3937 static DWORD
HTTPSESSION_QueryOption(object_header_t
*hdr
, DWORD option
, void *buffer
, DWORD
*size
, BOOL unicode
)
3940 case INTERNET_OPTION_HANDLE_TYPE
:
3941 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
3943 if (*size
< sizeof(ULONG
))
3944 return ERROR_INSUFFICIENT_BUFFER
;
3946 *size
= sizeof(DWORD
);
3947 *(DWORD
*)buffer
= INTERNET_HANDLE_TYPE_CONNECT_HTTP
;
3948 return ERROR_SUCCESS
;
3951 return INET_QueryOption(option
, buffer
, size
, unicode
);
3954 static DWORD
HTTPSESSION_SetOption(object_header_t
*hdr
, DWORD option
, void *buffer
, DWORD size
)
3956 http_session_t
*ses
= (http_session_t
*)hdr
;
3959 case INTERNET_OPTION_USERNAME
:
3961 HeapFree(GetProcessHeap(), 0, ses
->lpszUserName
);
3962 if (!(ses
->lpszUserName
= heap_strdupW(buffer
))) return ERROR_OUTOFMEMORY
;
3963 return ERROR_SUCCESS
;
3965 case INTERNET_OPTION_PASSWORD
:
3967 HeapFree(GetProcessHeap(), 0, ses
->lpszPassword
);
3968 if (!(ses
->lpszPassword
= heap_strdupW(buffer
))) return ERROR_OUTOFMEMORY
;
3969 return ERROR_SUCCESS
;
3974 return ERROR_INTERNET_INVALID_OPTION
;
3977 static const object_vtbl_t HTTPSESSIONVtbl
= {
3978 HTTPSESSION_Destroy
,
3980 HTTPSESSION_QueryOption
,
3981 HTTPSESSION_SetOption
,
3990 /***********************************************************************
3991 * HTTP_Connect (internal)
3993 * Create http session handle
3996 * HINTERNET a session handle on success
4000 HINTERNET
HTTP_Connect(appinfo_t
*hIC
, LPCWSTR lpszServerName
,
4001 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
4002 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD_PTR dwContext
,
4003 DWORD dwInternalFlags
)
4005 http_session_t
*lpwhs
= NULL
;
4006 HINTERNET handle
= NULL
;
4010 if (!lpszServerName
|| !lpszServerName
[0])
4012 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
4016 assert( hIC
->hdr
.htype
== WH_HINIT
);
4018 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(http_session_t
));
4021 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
4026 * According to my tests. The name is not resolved until a request is sent
4029 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
4030 lpwhs
->hdr
.vtbl
= &HTTPSESSIONVtbl
;
4031 lpwhs
->hdr
.dwFlags
= dwFlags
;
4032 lpwhs
->hdr
.dwContext
= dwContext
;
4033 lpwhs
->hdr
.dwInternalFlags
= dwInternalFlags
| (hIC
->hdr
.dwInternalFlags
& INET_CALLBACKW
);
4034 lpwhs
->hdr
.refs
= 1;
4035 lpwhs
->hdr
.lpfnStatusCB
= hIC
->hdr
.lpfnStatusCB
;
4037 WININET_AddRef( &hIC
->hdr
);
4038 lpwhs
->lpAppInfo
= hIC
;
4039 list_add_head( &hIC
->hdr
.children
, &lpwhs
->hdr
.entry
);
4041 handle
= WININET_AllocHandle( &lpwhs
->hdr
);
4044 ERR("Failed to alloc handle\n");
4045 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
4049 if(hIC
->lpszProxy
&& hIC
->dwAccessType
== INTERNET_OPEN_TYPE_PROXY
) {
4050 if(strchrW(hIC
->lpszProxy
, ' '))
4051 FIXME("Several proxies not implemented.\n");
4052 if(hIC
->lpszProxyBypass
)
4053 FIXME("Proxy bypass is ignored.\n");
4055 if (lpszServerName
&& lpszServerName
[0])
4057 lpwhs
->lpszServerName
= heap_strdupW(lpszServerName
);
4058 lpwhs
->lpszHostName
= heap_strdupW(lpszServerName
);
4060 if (lpszUserName
&& lpszUserName
[0])
4061 lpwhs
->lpszUserName
= heap_strdupW(lpszUserName
);
4062 if (lpszPassword
&& lpszPassword
[0])
4063 lpwhs
->lpszPassword
= heap_strdupW(lpszPassword
);
4064 lpwhs
->nServerPort
= nServerPort
;
4065 lpwhs
->nHostPort
= nServerPort
;
4067 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
4068 if (!(lpwhs
->hdr
.dwInternalFlags
& INET_OPENURL
))
4070 INTERNET_SendCallback(&hIC
->hdr
, dwContext
,
4071 INTERNET_STATUS_HANDLE_CREATED
, &handle
,
4077 WININET_Release( &lpwhs
->hdr
);
4080 * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
4084 TRACE("%p --> %p (%p)\n", hIC
, handle
, lpwhs
);
4089 /***********************************************************************
4090 * HTTP_OpenConnection (internal)
4092 * Connect to a web server
4099 static BOOL
HTTP_OpenConnection(http_request_t
*lpwhr
)
4101 BOOL bSuccess
= FALSE
;
4102 http_session_t
*lpwhs
;
4103 appinfo_t
*hIC
= NULL
;
4104 char szaddr
[INET6_ADDRSTRLEN
];
4110 if (lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
4112 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
4116 if (NETCON_connected(&lpwhr
->netConnection
))
4121 if (!HTTP_ResolveName(lpwhr
)) goto lend
;
4123 lpwhs
= lpwhr
->lpHttpSession
;
4125 hIC
= lpwhs
->lpAppInfo
;
4126 switch (lpwhs
->socketAddress
.ss_family
)
4129 addr
= &((struct sockaddr_in
*)&lpwhs
->socketAddress
)->sin_addr
;
4132 addr
= &((struct sockaddr_in6
*)&lpwhs
->socketAddress
)->sin6_addr
;
4135 WARN("unsupported family %d\n", lpwhs
->socketAddress
.ss_family
);
4136 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
4139 inet_ntop(lpwhs
->socketAddress
.ss_family
, addr
, szaddr
, sizeof(szaddr
));
4140 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
4141 INTERNET_STATUS_CONNECTING_TO_SERVER
,
4145 if (!NETCON_create(&lpwhr
->netConnection
, lpwhs
->socketAddress
.ss_family
,
4148 WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
4152 if (!NETCON_connect(&lpwhr
->netConnection
, (struct sockaddr
*)&lpwhs
->socketAddress
,
4156 if (lpwhr
->hdr
.dwFlags
& INTERNET_FLAG_SECURE
)
4158 /* Note: we differ from Microsoft's WinINet here. they seem to have
4159 * a bug that causes no status callbacks to be sent when starting
4160 * a tunnel to a proxy server using the CONNECT verb. i believe our
4161 * behaviour to be more correct and to not cause any incompatibilities
4162 * because using a secure connection through a proxy server is a rare
4163 * case that would be hard for anyone to depend on */
4164 if (hIC
->lpszProxy
&& !HTTP_SecureProxyConnect(lpwhr
))
4167 if (!NETCON_secure_connect(&lpwhr
->netConnection
, lpwhs
->lpszHostName
))
4169 WARN("Couldn't connect securely to host\n");
4174 INTERNET_SendCallback(&lpwhr
->hdr
, lpwhr
->hdr
.dwContext
,
4175 INTERNET_STATUS_CONNECTED_TO_SERVER
,
4176 szaddr
, strlen(szaddr
)+1);
4181 lpwhr
->read_pos
= lpwhr
->read_size
= 0;
4182 lpwhr
->read_chunked
= FALSE
;
4184 TRACE("%d <--\n", bSuccess
);
4189 /***********************************************************************
4190 * HTTP_clear_response_headers (internal)
4192 * clear out any old response headers
4194 static void HTTP_clear_response_headers( http_request_t
*lpwhr
)
4198 for( i
=0; i
<lpwhr
->nCustHeaders
; i
++)
4200 if( !lpwhr
->pCustHeaders
[i
].lpszField
)
4202 if( !lpwhr
->pCustHeaders
[i
].lpszValue
)
4204 if ( lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
4206 HTTP_DeleteCustomHeader( lpwhr
, i
);
4211 /***********************************************************************
4212 * HTTP_GetResponseHeaders (internal)
4214 * Read server response
4221 static INT
HTTP_GetResponseHeaders(http_request_t
*lpwhr
, BOOL clear
)
4224 WCHAR buffer
[MAX_REPLY_LEN
];
4225 DWORD buflen
= MAX_REPLY_LEN
;
4226 BOOL bSuccess
= FALSE
;
4228 char bufferA
[MAX_REPLY_LEN
];
4229 LPWSTR status_code
= NULL
, status_text
= NULL
;
4230 DWORD cchMaxRawHeaders
= 1024;
4231 LPWSTR lpszRawHeaders
= HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders
+1)*sizeof(WCHAR
));
4233 DWORD cchRawHeaders
= 0;
4234 BOOL codeHundred
= FALSE
;
4238 /* clear old response headers (eg. from a redirect response) */
4239 if (clear
) HTTP_clear_response_headers( lpwhr
);
4241 if (!NETCON_connected(&lpwhr
->netConnection
))
4245 static const WCHAR szHundred
[] = {'1','0','0',0};
4247 * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
4249 buflen
= MAX_REPLY_LEN
;
4250 if (!read_line(lpwhr
, bufferA
, &buflen
))
4253 MultiByteToWideChar( CP_ACP
, 0, bufferA
, buflen
, buffer
, MAX_REPLY_LEN
);
4254 /* check is this a status code line? */
4255 if (!strncmpW(buffer
, g_szHttp1_0
, 4))
4257 /* split the version from the status code */
4258 status_code
= strchrW( buffer
, ' ' );
4263 /* split the status code from the status text */
4264 status_text
= strchrW( status_code
, ' ' );
4269 TRACE("version [%s] status code [%s] status text [%s]\n",
4270 debugstr_w(buffer
), debugstr_w(status_code
), debugstr_w(status_text
) );
4272 codeHundred
= (!strcmpW(status_code
, szHundred
));
4274 else if (!codeHundred
)
4276 FIXME("Non status line at head of response (%s)\n",debugstr_w(buffer
));
4279 } while (codeHundred
);
4281 /* Add status code */
4282 HTTP_ProcessHeader(lpwhr
, szStatus
, status_code
,
4283 HTTP_ADDHDR_FLAG_REPLACE
);
4285 HeapFree(GetProcessHeap(),0,lpwhr
->lpszVersion
);
4286 HeapFree(GetProcessHeap(),0,lpwhr
->lpszStatusText
);
4288 lpwhr
->lpszVersion
= heap_strdupW(buffer
);
4289 lpwhr
->lpszStatusText
= heap_strdupW(status_text
);
4291 /* Restore the spaces */
4292 *(status_code
-1) = ' ';
4293 *(status_text
-1) = ' ';
4295 /* regenerate raw headers */
4296 while (cchRawHeaders
+ buflen
+ strlenW(szCrLf
) > cchMaxRawHeaders
)
4297 cchMaxRawHeaders
*= 2;
4298 temp
= HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders
, (cchMaxRawHeaders
+1)*sizeof(WCHAR
));
4299 if (temp
== NULL
) goto lend
;
4300 lpszRawHeaders
= temp
;
4301 memcpy(lpszRawHeaders
+cchRawHeaders
, buffer
, (buflen
-1)*sizeof(WCHAR
));
4302 cchRawHeaders
+= (buflen
-1);
4303 memcpy(lpszRawHeaders
+cchRawHeaders
, szCrLf
, sizeof(szCrLf
));
4304 cchRawHeaders
+= sizeof(szCrLf
)/sizeof(szCrLf
[0])-1;
4305 lpszRawHeaders
[cchRawHeaders
] = '\0';
4307 /* Parse each response line */
4310 buflen
= MAX_REPLY_LEN
;
4311 if (read_line(lpwhr
, bufferA
, &buflen
))
4313 LPWSTR
* pFieldAndValue
;
4315 TRACE("got line %s, now interpreting\n", debugstr_a(bufferA
));
4317 if (!bufferA
[0]) break;
4318 MultiByteToWideChar( CP_ACP
, 0, bufferA
, buflen
, buffer
, MAX_REPLY_LEN
);
4320 pFieldAndValue
= HTTP_InterpretHttpHeader(buffer
);
4323 while (cchRawHeaders
+ buflen
+ strlenW(szCrLf
) > cchMaxRawHeaders
)
4324 cchMaxRawHeaders
*= 2;
4325 temp
= HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders
, (cchMaxRawHeaders
+1)*sizeof(WCHAR
));
4326 if (temp
== NULL
) goto lend
;
4327 lpszRawHeaders
= temp
;
4328 memcpy(lpszRawHeaders
+cchRawHeaders
, buffer
, (buflen
-1)*sizeof(WCHAR
));
4329 cchRawHeaders
+= (buflen
-1);
4330 memcpy(lpszRawHeaders
+cchRawHeaders
, szCrLf
, sizeof(szCrLf
));
4331 cchRawHeaders
+= sizeof(szCrLf
)/sizeof(szCrLf
[0])-1;
4332 lpszRawHeaders
[cchRawHeaders
] = '\0';
4334 HTTP_ProcessHeader(lpwhr
, pFieldAndValue
[0], pFieldAndValue
[1],
4335 HTTP_ADDREQ_FLAG_ADD
);
4337 HTTP_FreeTokens(pFieldAndValue
);
4348 /* make sure the response header is terminated with an empty line. Some apps really
4349 truly care about that empty line being there for some reason. Just add it to the
4351 if (cchRawHeaders
+ strlenW(szCrLf
) > cchMaxRawHeaders
)
4353 cchMaxRawHeaders
= cchRawHeaders
+ strlenW(szCrLf
);
4354 temp
= HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders
, (cchMaxRawHeaders
+ 1) * sizeof(WCHAR
));
4355 if (temp
== NULL
) goto lend
;
4356 lpszRawHeaders
= temp
;
4359 memcpy(&lpszRawHeaders
[cchRawHeaders
], szCrLf
, sizeof(szCrLf
));
4361 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszRawHeaders
);
4362 lpwhr
->lpszRawHeaders
= lpszRawHeaders
;
4363 TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders
));
4373 HeapFree(GetProcessHeap(), 0, lpszRawHeaders
);
4379 static void strip_spaces(LPWSTR start
)
4384 while (*str
== ' ' && *str
!= '\0')
4388 memmove(start
, str
, sizeof(WCHAR
) * (strlenW(str
) + 1));
4390 end
= start
+ strlenW(start
) - 1;
4391 while (end
>= start
&& *end
== ' ')
4399 /***********************************************************************
4400 * HTTP_InterpretHttpHeader (internal)
4402 * Parse server response
4406 * Pointer to array of field, value, NULL on success.
4409 static LPWSTR
* HTTP_InterpretHttpHeader(LPCWSTR buffer
)
4411 LPWSTR
* pTokenPair
;
4415 pTokenPair
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pTokenPair
)*3);
4417 pszColon
= strchrW(buffer
, ':');
4418 /* must have two tokens */
4421 HTTP_FreeTokens(pTokenPair
);
4423 TRACE("No ':' in line: %s\n", debugstr_w(buffer
));
4427 pTokenPair
[0] = HeapAlloc(GetProcessHeap(), 0, (pszColon
- buffer
+ 1) * sizeof(WCHAR
));
4430 HTTP_FreeTokens(pTokenPair
);
4433 memcpy(pTokenPair
[0], buffer
, (pszColon
- buffer
) * sizeof(WCHAR
));
4434 pTokenPair
[0][pszColon
- buffer
] = '\0';
4438 len
= strlenW(pszColon
);
4439 pTokenPair
[1] = HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
4442 HTTP_FreeTokens(pTokenPair
);
4445 memcpy(pTokenPair
[1], pszColon
, (len
+ 1) * sizeof(WCHAR
));
4447 strip_spaces(pTokenPair
[0]);
4448 strip_spaces(pTokenPair
[1]);
4450 TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair
[0]), debugstr_w(pTokenPair
[1]));
4454 /***********************************************************************
4455 * HTTP_ProcessHeader (internal)
4457 * Stuff header into header tables according to <dwModifier>
4461 #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
4463 static BOOL
HTTP_ProcessHeader(http_request_t
*lpwhr
, LPCWSTR field
, LPCWSTR value
, DWORD dwModifier
)
4465 LPHTTPHEADERW lphttpHdr
= NULL
;
4466 BOOL bSuccess
= FALSE
;
4468 BOOL request_only
= dwModifier
& HTTP_ADDHDR_FLAG_REQ
;
4470 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field
), debugstr_w(value
), dwModifier
);
4472 /* REPLACE wins out over ADD */
4473 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
4474 dwModifier
&= ~HTTP_ADDHDR_FLAG_ADD
;
4476 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD
)
4479 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
, 0, request_only
);
4483 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
4487 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
4493 hdr
.lpszField
= (LPWSTR
)field
;
4494 hdr
.lpszValue
= (LPWSTR
)value
;
4495 hdr
.wFlags
= hdr
.wCount
= 0;
4497 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
4498 hdr
.wFlags
|= HDR_ISREQUEST
;
4500 return HTTP_InsertCustomHeader(lpwhr
, &hdr
);
4502 /* no value to delete */
4505 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
4506 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
4508 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
4510 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
4512 HTTP_DeleteCustomHeader( lpwhr
, index
);
4518 hdr
.lpszField
= (LPWSTR
)field
;
4519 hdr
.lpszValue
= (LPWSTR
)value
;
4520 hdr
.wFlags
= hdr
.wCount
= 0;
4522 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
4523 hdr
.wFlags
|= HDR_ISREQUEST
;
4525 return HTTP_InsertCustomHeader(lpwhr
, &hdr
);
4530 else if (dwModifier
& COALESCEFLAGS
)
4535 INT origlen
= strlenW(lphttpHdr
->lpszValue
);
4536 INT valuelen
= strlenW(value
);
4538 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
4541 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
4543 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
4546 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
4549 len
= origlen
+ valuelen
+ ((ch
> 0) ? 2 : 0);
4551 lpsztmp
= HeapReAlloc(GetProcessHeap(), 0, lphttpHdr
->lpszValue
, (len
+1)*sizeof(WCHAR
));
4554 lphttpHdr
->lpszValue
= lpsztmp
;
4555 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
4558 lphttpHdr
->lpszValue
[origlen
] = ch
;
4560 lphttpHdr
->lpszValue
[origlen
] = ' ';
4564 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
*sizeof(WCHAR
));
4565 lphttpHdr
->lpszValue
[len
] = '\0';
4570 WARN("HeapReAlloc (%d bytes) failed\n",len
+1);
4571 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
4574 TRACE("<-- %d\n",bSuccess
);
4579 /***********************************************************************
4580 * HTTP_FinishedReading (internal)
4582 * Called when all content from server has been read by client.
4585 static BOOL
HTTP_FinishedReading(http_request_t
*lpwhr
)
4587 WCHAR szVersion
[10];
4588 WCHAR szConnectionResponse
[20];
4589 DWORD dwBufferSize
= sizeof(szVersion
);
4590 BOOL keepalive
= FALSE
;
4594 /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
4595 * the connection is keep-alive by default */
4596 if (HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_VERSION
, szVersion
,
4597 &dwBufferSize
, NULL
) &&
4598 !strcmpiW(szVersion
, g_szHttp1_1
))
4603 dwBufferSize
= sizeof(szConnectionResponse
);
4604 if (HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_PROXY_CONNECTION
, szConnectionResponse
, &dwBufferSize
, NULL
) ||
4605 HTTP_HttpQueryInfoW(lpwhr
, HTTP_QUERY_CONNECTION
, szConnectionResponse
, &dwBufferSize
, NULL
))
4607 keepalive
= !strcmpiW(szConnectionResponse
, szKeepAlive
);
4612 HTTPREQ_CloseConnection(&lpwhr
->hdr
);
4615 /* FIXME: store data in the URL cache here */
4621 /***********************************************************************
4622 * HTTP_GetCustomHeaderIndex (internal)
4624 * Return index of custom header from header array
4627 static INT
HTTP_GetCustomHeaderIndex(http_request_t
*lpwhr
, LPCWSTR lpszField
,
4628 int requested_index
, BOOL request_only
)
4632 TRACE("%s\n", debugstr_w(lpszField
));
4634 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
4636 if (strcmpiW(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
4639 if (request_only
&& !(lpwhr
->pCustHeaders
[index
].wFlags
& HDR_ISREQUEST
))
4642 if (!request_only
&& (lpwhr
->pCustHeaders
[index
].wFlags
& HDR_ISREQUEST
))
4645 if (requested_index
== 0)
4650 if (index
>= lpwhr
->nCustHeaders
)
4653 TRACE("Return: %d\n", index
);
4658 /***********************************************************************
4659 * HTTP_InsertCustomHeader (internal)
4661 * Insert header into array
4664 static BOOL
HTTP_InsertCustomHeader(http_request_t
*lpwhr
, LPHTTPHEADERW lpHdr
)
4667 LPHTTPHEADERW lph
= NULL
;
4670 TRACE("--> %s: %s\n", debugstr_w(lpHdr
->lpszField
), debugstr_w(lpHdr
->lpszValue
));
4671 count
= lpwhr
->nCustHeaders
+ 1;
4673 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERW
) * count
);
4675 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERW
) * count
);
4679 lpwhr
->pCustHeaders
= lph
;
4680 lpwhr
->pCustHeaders
[count
-1].lpszField
= heap_strdupW(lpHdr
->lpszField
);
4681 lpwhr
->pCustHeaders
[count
-1].lpszValue
= heap_strdupW(lpHdr
->lpszValue
);
4682 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
4683 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
4684 lpwhr
->nCustHeaders
++;
4689 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
4696 /***********************************************************************
4697 * HTTP_DeleteCustomHeader (internal)
4699 * Delete header from array
4700 * If this function is called, the indexs may change.
4702 static BOOL
HTTP_DeleteCustomHeader(http_request_t
*lpwhr
, DWORD index
)
4704 if( lpwhr
->nCustHeaders
<= 0 )
4706 if( index
>= lpwhr
->nCustHeaders
)
4708 lpwhr
->nCustHeaders
--;
4710 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[index
].lpszField
);
4711 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[index
].lpszValue
);
4713 memmove( &lpwhr
->pCustHeaders
[index
], &lpwhr
->pCustHeaders
[index
+1],
4714 (lpwhr
->nCustHeaders
- index
)* sizeof(HTTPHEADERW
) );
4715 memset( &lpwhr
->pCustHeaders
[lpwhr
->nCustHeaders
], 0, sizeof(HTTPHEADERW
) );
4721 /***********************************************************************
4722 * HTTP_VerifyValidHeader (internal)
4724 * Verify the given header is not invalid for the given http request
4727 static BOOL
HTTP_VerifyValidHeader(http_request_t
*lpwhr
, LPCWSTR field
)
4729 /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
4730 if (!strcmpW(lpwhr
->lpszVersion
, g_szHttp1_0
) && !strcmpiW(field
, szAccept_Encoding
))
4736 /***********************************************************************
4737 * IsHostInProxyBypassList (@)
4742 BOOL WINAPI
IsHostInProxyBypassList(DWORD flags
, LPCSTR szHost
, DWORD length
)
4744 FIXME("STUB: flags=%d host=%s length=%d\n",flags
,szHost
,length
);