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
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
49 #define NO_SHLWAPI_STREAM
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
58 static const WCHAR g_szHttp[] = {' ','H','T','T','P','/','1','.','0',0 };
59 static const WCHAR g_szHost[] = {'\r','\n','H','o','s','t',':',' ',0 };
60 static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0};
61 static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0};
62 static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0};
65 #define HTTPHEADER g_szHttp
66 #define HTTPHOSTHEADER g_szHost
67 #define MAXHOSTNAME 100
68 #define MAX_FIELD_VALUE_LEN 256
69 #define MAX_FIELD_LEN 256
71 #define HTTP_REFERER g_szReferer
72 #define HTTP_ACCEPT g_szAccept
73 #define HTTP_USERAGENT g_szUserAgent
75 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
76 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
77 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
78 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
79 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
80 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
81 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
84 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
85 int HTTP_WriteDataToStream(LPWININETHTTPREQW lpwhr,
86 void *Buffer, int BytesToWrite);
87 int HTTP_ReadDataFromStream(LPWININETHTTPREQW lpwhr,
88 void *Buffer, int BytesToRead);
89 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr);
90 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
91 void HTTP_CloseConnection(LPWININETHTTPREQW lpwhr);
92 BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen);
93 INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField);
94 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr);
95 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField);
96 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index);
98 /***********************************************************************
99 * HttpAddRequestHeadersW (WININET.@)
101 * Adds one or more HTTP header to the request handler
108 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
109 LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
114 WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
115 BOOL bSuccess = FALSE;
116 LPWININETHTTPREQW lpwhr;
118 TRACE("%p, %s, %li, %li\n", hHttpRequest, debugstr_w(lpszHeader), dwHeaderLength,
121 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
123 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
125 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
132 TRACE("copying header: %s\n", debugstr_w(lpszHeader));
133 buffer = WININET_strdupW(lpszHeader);
140 while (*lpszEnd != '\0')
142 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
147 if (*lpszEnd == '\0')
152 TRACE("interpreting header %s\n", debugstr_w(lpszStart));
153 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
154 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
156 lpszStart = lpszEnd + 2; /* Jump over \0\n */
160 HeapFree(GetProcessHeap(), 0, buffer);
164 /***********************************************************************
165 * HttpAddRequestHeadersA (WININET.@)
167 * Adds one or more HTTP header to the request handler
174 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
175 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
181 TRACE("%p, %s, %li, %li\n", hHttpRequest, debugstr_a(lpszHeader), dwHeaderLength,
184 len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
185 hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
186 MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
187 if( dwHeaderLength != -1 )
188 dwHeaderLength = len;
190 r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
192 HeapFree( GetProcessHeap(), 0, hdr );
197 /***********************************************************************
198 * HttpEndRequestA (WININET.@)
200 * Ends an HTTP request that was started by HttpSendRequestEx
207 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut,
208 DWORD dwFlags, DWORD dwContext)
214 /***********************************************************************
215 * HttpEndRequestW (WININET.@)
217 * Ends an HTTP request that was started by HttpSendRequestEx
224 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut,
225 DWORD dwFlags, DWORD dwContext)
231 /***********************************************************************
232 * HttpOpenRequestW (WININET.@)
234 * Open a HTTP request handle
237 * HINTERNET a HTTP request handle on success
241 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
242 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
243 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
244 DWORD dwFlags, DWORD dwContext)
246 LPWININETHTTPSESSIONW lpwhs;
247 LPWININETAPPINFOW hIC = NULL;
248 HINTERNET handle = NULL;
250 TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession,
251 debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
252 debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
254 if(lpszAcceptTypes!=NULL)
257 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
258 TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
261 lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
262 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
264 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
267 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
270 * My tests seem to show that the windows version does not
271 * become asynchronous until after this point. And anyhow
272 * if this call was asynchronous then how would you get the
273 * necessary HINTERNET pointer returned by this function.
275 * I am leaving this here just in case I am wrong
277 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
281 WORKREQUEST workRequest;
282 struct WORKREQ_HTTPOPENREQUESTW *req;
284 workRequest.asyncall = HTTPOPENREQUESTW;
285 workRequest.handle = hHttpSession;
286 req = &workRequest.u.HttpOpenRequestW;
287 req->lpszVerb = WININET_strdupW(lpszVerb);
288 req->lpszObjectName = WININET_strdupW(lpszObjectName);
290 req->lpszVersion = WININET_strdupW(lpszVersion);
292 req->lpszVersion = 0;
294 req->lpszReferrer = WININET_strdupW(lpszReferrer);
296 req->lpszReferrer = 0;
297 req->lpszAcceptTypes = lpszAcceptTypes;
298 req->dwFlags = dwFlags;
299 req->dwContext = dwContext;
301 INTERNET_AsyncCall(&workRequest);
305 handle = HTTP_HttpOpenRequestW(hHttpSession, lpszVerb, lpszObjectName,
306 lpszVersion, lpszReferrer, lpszAcceptTypes,
309 TRACE("returning %p\n", handle);
314 /***********************************************************************
315 * HttpOpenRequestA (WININET.@)
317 * Open a HTTP request handle
320 * HINTERNET a HTTP request handle on success
324 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
325 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
326 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
327 DWORD dwFlags, DWORD dwContext)
329 LPWSTR szVerb = NULL, szObjectName = NULL;
330 LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
332 INT acceptTypesCount;
333 HINTERNET rc = FALSE;
334 TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession,
335 debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
336 debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
341 len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 );
342 szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
345 MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len);
350 len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 );
351 szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
354 MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len );
359 len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 );
360 szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
363 MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len );
368 len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 );
369 szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
372 MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len );
375 acceptTypesCount = 0;
378 /* find out how many there are */
379 while (lpszAcceptTypes[acceptTypesCount])
381 szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
382 acceptTypesCount = 0;
383 while (lpszAcceptTypes[acceptTypesCount])
385 len = MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
387 szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
388 if (!szAcceptTypes[acceptTypesCount] )
390 MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
391 -1, szAcceptTypes[acceptTypesCount], len );
394 szAcceptTypes[acceptTypesCount] = NULL;
396 else szAcceptTypes = 0;
398 rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
399 szVersion, szReferrer,
400 (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
405 acceptTypesCount = 0;
406 while (szAcceptTypes[acceptTypesCount])
408 HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
411 HeapFree(GetProcessHeap(), 0, szAcceptTypes);
413 if (szReferrer) HeapFree(GetProcessHeap(), 0, szReferrer);
414 if (szVersion) HeapFree(GetProcessHeap(), 0, szVersion);
415 if (szObjectName) HeapFree(GetProcessHeap(), 0, szObjectName);
416 if (szVerb) HeapFree(GetProcessHeap(), 0, szVerb);
421 /***********************************************************************
424 static UINT HTTP_Base64( LPCWSTR bin, LPWSTR base64 )
427 static LPSTR HTTP_Base64Enc =
428 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
432 /* first 6 bits, all from bin[0] */
433 base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
434 x = (bin[0] & 3) << 4;
436 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
439 base64[n++] = HTTP_Base64Enc[x];
444 base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
445 x = ( bin[1] & 0x0f ) << 2;
447 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
450 base64[n++] = HTTP_Base64Enc[x];
454 base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
456 /* last 6 bits, all from bin [2] */
457 base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
464 /***********************************************************************
465 * HTTP_EncodeBasicAuth
467 * Encode the basic authentication string for HTTP 1.1
469 static LPWSTR HTTP_EncodeBasicAuth( LPCWSTR username, LPCWSTR password)
473 static const WCHAR szBasic[] = {'B','a','s','i','c',' ',0};
474 static const WCHAR szColon[] = {':',0};
476 len = lstrlenW( username ) + 1 + lstrlenW ( password ) + 1;
477 in = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
481 len = lstrlenW(szBasic) +
482 (lstrlenW( username ) + 1 + lstrlenW ( password ))*2 + 1 + 1;
483 out = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
486 lstrcpyW( in, username );
487 lstrcatW( in, szColon );
488 lstrcatW( in, password );
489 lstrcpyW( out, szBasic );
490 HTTP_Base64( in, &out[strlenW(out)] );
492 HeapFree( GetProcessHeap(), 0, in );
497 /***********************************************************************
498 * HTTP_InsertProxyAuthorization
500 * Insert the basic authorization field in the request header
502 BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr,
503 LPCWSTR username, LPCWSTR password )
507 static const WCHAR szProxyAuthorization[] = {
508 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
510 hdr.lpszValue = HTTP_EncodeBasicAuth( username, password );
511 hdr.lpszField = (WCHAR *)szProxyAuthorization;
512 hdr.wFlags = HDR_ISREQUEST;
517 TRACE("Inserting %s = %s\n",
518 debugstr_w( hdr.lpszField ), debugstr_w( hdr.lpszValue ) );
520 /* remove the old proxy authorization header */
521 index = HTTP_GetCustomHeaderIndex( lpwhr, hdr.lpszField );
523 HTTP_DeleteCustomHeader( lpwhr, index );
525 HTTP_InsertCustomHeader(lpwhr, &hdr);
526 HeapFree( GetProcessHeap(), 0, hdr.lpszValue );
531 /***********************************************************************
534 static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
535 LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
537 WCHAR buf[MAXHOSTNAME];
538 WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
540 static const WCHAR szNul[] = { 0 };
541 URL_COMPONENTSW UrlComponents;
542 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 }, szSlash[] = { '/',0 } ;
543 static const WCHAR szFormat1[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
544 static const WCHAR szFormat2[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
547 memset( &UrlComponents, 0, sizeof UrlComponents );
548 UrlComponents.dwStructSize = sizeof UrlComponents;
549 UrlComponents.lpszHostName = buf;
550 UrlComponents.dwHostNameLength = MAXHOSTNAME;
552 if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
553 buf,strlenW(szHttp),szHttp,strlenW(szHttp)) )
554 sprintfW(proxy, szFormat1, hIC->lpszProxy);
557 if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
559 if( UrlComponents.dwHostNameLength == 0 )
562 if( !lpwhr->lpszPath )
563 lpwhr->lpszPath = (LPWSTR)szNul;
564 TRACE("server='%s' path='%s'\n",
565 debugstr_w(lpwhs->lpszServerName), debugstr_w(lpwhr->lpszPath));
566 /* for constant 15 see above */
567 len = strlenW(lpwhs->lpszServerName) + strlenW(lpwhr->lpszPath) + 15;
568 url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
570 if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
571 UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
573 sprintfW(url, szFormat2, lpwhs->lpszServerName, lpwhs->nServerPort);
575 if( lpwhr->lpszPath[0] != '/' )
576 strcatW( url, szSlash );
577 strcatW(url, lpwhr->lpszPath);
578 if(lpwhr->lpszPath != szNul)
579 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
580 lpwhr->lpszPath = url;
581 /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
582 lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
583 lpwhs->nServerPort = UrlComponents.nPort;
588 /***********************************************************************
589 * HTTP_HttpOpenRequestW (internal)
591 * Open a HTTP request handle
594 * HINTERNET a HTTP request handle on success
598 HINTERNET WINAPI HTTP_HttpOpenRequestW(HINTERNET hHttpSession,
599 LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
600 LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
601 DWORD dwFlags, DWORD dwContext)
603 LPWININETHTTPSESSIONW lpwhs;
604 LPWININETAPPINFOW hIC = NULL;
605 LPWININETHTTPREQW lpwhr;
607 LPWSTR lpszUrl = NULL;
610 static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0};
615 lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
616 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
618 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
622 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
624 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
627 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
630 handle = WININET_AllocHandle( &lpwhr->hdr );
633 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
634 HeapFree( GetProcessHeap(), 0, lpwhr );
638 lpwhr->hdr.htype = WH_HHTTPREQ;
639 lpwhr->hdr.lpwhparent = &lpwhs->hdr;
640 lpwhr->hdr.dwFlags = dwFlags;
641 lpwhr->hdr.dwContext = dwContext;
642 NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE);
644 if (NULL != lpszObjectName && strlenW(lpszObjectName)) {
648 rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
650 len = strlenW(lpszObjectName)+1;
651 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
652 rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
653 URL_ESCAPE_SPACES_ONLY);
656 ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(lpszObjectName),rc);
657 strcpyW(lpwhr->lpszPath,lpszObjectName);
661 if (NULL != lpszReferrer && strlenW(lpszReferrer))
662 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
664 if(lpszAcceptTypes!=NULL)
667 for(i=0;lpszAcceptTypes[i]!=NULL;i++)
668 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
671 if (NULL == lpszVerb)
673 static const WCHAR szGet[] = {'G','E','T',0};
674 lpwhr->lpszVerb = WININET_strdupW(szGet);
676 else if (strlenW(lpszVerb))
677 lpwhr->lpszVerb = WININET_strdupW(lpszVerb);
679 if (NULL != lpszReferrer && strlenW(lpszReferrer))
681 WCHAR buf[MAXHOSTNAME];
682 URL_COMPONENTSW UrlComponents;
684 memset( &UrlComponents, 0, sizeof UrlComponents );
685 UrlComponents.dwStructSize = sizeof UrlComponents;
686 UrlComponents.lpszHostName = buf;
687 UrlComponents.dwHostNameLength = MAXHOSTNAME;
689 InternetCrackUrlW(lpszReferrer, 0, 0, &UrlComponents);
690 if (strlenW(UrlComponents.lpszHostName))
691 lpwhr->lpszHostName = WININET_strdupW(UrlComponents.lpszHostName);
693 lpwhr->lpszHostName = WININET_strdupW(lpwhs->lpszServerName);
695 if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
696 HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
701 static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0 };
703 len = strlenW(hIC->lpszAgent) + strlenW(user_agent);
704 agent_header = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
705 sprintfW(agent_header, user_agent, hIC->lpszAgent );
707 HttpAddRequestHeadersW(handle, agent_header, strlenW(agent_header),
708 HTTP_ADDREQ_FLAG_ADD);
709 HeapFree(GetProcessHeap(), 0, agent_header);
712 len = strlenW(lpwhr->lpszHostName) + strlenW(szUrlForm);
713 lpszUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
714 sprintfW( lpszUrl, szUrlForm, lpwhr->lpszHostName );
716 if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
719 static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
720 static const WCHAR szcrlf[] = {'\r','\n',0};
722 lpszCookies = HeapAlloc(GetProcessHeap(), 0, (nCookieSize + 1 + 8)*sizeof(WCHAR));
724 cnt += sprintfW(lpszCookies, szCookie);
725 InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
726 strcatW(lpszCookies, szcrlf);
728 HttpAddRequestHeadersW(handle, lpszCookies, strlenW(lpszCookies),
729 HTTP_ADDREQ_FLAG_ADD);
730 HeapFree(GetProcessHeap(), 0, lpszCookies);
732 HeapFree(GetProcessHeap(), 0, lpszUrl);
736 if (hIC->lpfnStatusCB)
738 INTERNET_ASYNC_RESULT iar;
740 iar.dwResult = (DWORD)handle;
741 iar.dwError = ERROR_SUCCESS;
743 SendAsyncCallback(hIC, hHttpSession, dwContext,
744 INTERNET_STATUS_HANDLE_CREATED, &iar,
745 sizeof(INTERNET_ASYNC_RESULT));
749 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
753 * According to my tests. The name is not resolved until a request is Opened
755 SendAsyncCallback(hIC, hHttpSession, dwContext,
756 INTERNET_STATUS_RESOLVING_NAME,
757 lpwhs->lpszServerName,
758 strlenW(lpwhs->lpszServerName)+1);
759 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
760 &lpwhs->phostent, &lpwhs->socketAddress))
762 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
766 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
767 INTERNET_STATUS_NAME_RESOLVED,
768 &(lpwhs->socketAddress),
769 sizeof(struct sockaddr_in));
771 TRACE("<-- %p\n", handle);
776 /***********************************************************************
777 * HttpQueryInfoW (WININET.@)
779 * Queries for information about an HTTP request
786 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
787 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
789 LPHTTPHEADERW lphttpHdr = NULL;
790 BOOL bSuccess = FALSE;
791 LPWININETHTTPREQW lpwhr;
792 static const WCHAR szFmt[] = { '%','s',':',' ','%','s','%','s',0 };
793 static const WCHAR szcrlf[] = { '\r','\n',0 };
794 static const WCHAR sznul[] = { 0 };
796 if (TRACE_ON(wininet)) {
797 #define FE(x) { x, #x }
798 static const wininet_flag_info query_flags[] = {
799 FE(HTTP_QUERY_MIME_VERSION),
800 FE(HTTP_QUERY_CONTENT_TYPE),
801 FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
802 FE(HTTP_QUERY_CONTENT_ID),
803 FE(HTTP_QUERY_CONTENT_DESCRIPTION),
804 FE(HTTP_QUERY_CONTENT_LENGTH),
805 FE(HTTP_QUERY_CONTENT_LANGUAGE),
806 FE(HTTP_QUERY_ALLOW),
807 FE(HTTP_QUERY_PUBLIC),
809 FE(HTTP_QUERY_EXPIRES),
810 FE(HTTP_QUERY_LAST_MODIFIED),
811 FE(HTTP_QUERY_MESSAGE_ID),
813 FE(HTTP_QUERY_DERIVED_FROM),
816 FE(HTTP_QUERY_PRAGMA),
817 FE(HTTP_QUERY_VERSION),
818 FE(HTTP_QUERY_STATUS_CODE),
819 FE(HTTP_QUERY_STATUS_TEXT),
820 FE(HTTP_QUERY_RAW_HEADERS),
821 FE(HTTP_QUERY_RAW_HEADERS_CRLF),
822 FE(HTTP_QUERY_CONNECTION),
823 FE(HTTP_QUERY_ACCEPT),
824 FE(HTTP_QUERY_ACCEPT_CHARSET),
825 FE(HTTP_QUERY_ACCEPT_ENCODING),
826 FE(HTTP_QUERY_ACCEPT_LANGUAGE),
827 FE(HTTP_QUERY_AUTHORIZATION),
828 FE(HTTP_QUERY_CONTENT_ENCODING),
829 FE(HTTP_QUERY_FORWARDED),
831 FE(HTTP_QUERY_IF_MODIFIED_SINCE),
832 FE(HTTP_QUERY_LOCATION),
833 FE(HTTP_QUERY_ORIG_URI),
834 FE(HTTP_QUERY_REFERER),
835 FE(HTTP_QUERY_RETRY_AFTER),
836 FE(HTTP_QUERY_SERVER),
837 FE(HTTP_QUERY_TITLE),
838 FE(HTTP_QUERY_USER_AGENT),
839 FE(HTTP_QUERY_WWW_AUTHENTICATE),
840 FE(HTTP_QUERY_PROXY_AUTHENTICATE),
841 FE(HTTP_QUERY_ACCEPT_RANGES),
842 FE(HTTP_QUERY_SET_COOKIE),
843 FE(HTTP_QUERY_COOKIE),
844 FE(HTTP_QUERY_REQUEST_METHOD),
845 FE(HTTP_QUERY_REFRESH),
846 FE(HTTP_QUERY_CONTENT_DISPOSITION),
848 FE(HTTP_QUERY_CACHE_CONTROL),
849 FE(HTTP_QUERY_CONTENT_BASE),
850 FE(HTTP_QUERY_CONTENT_LOCATION),
851 FE(HTTP_QUERY_CONTENT_MD5),
852 FE(HTTP_QUERY_CONTENT_RANGE),
855 FE(HTTP_QUERY_IF_MATCH),
856 FE(HTTP_QUERY_IF_NONE_MATCH),
857 FE(HTTP_QUERY_IF_RANGE),
858 FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
859 FE(HTTP_QUERY_MAX_FORWARDS),
860 FE(HTTP_QUERY_PROXY_AUTHORIZATION),
861 FE(HTTP_QUERY_RANGE),
862 FE(HTTP_QUERY_TRANSFER_ENCODING),
863 FE(HTTP_QUERY_UPGRADE),
866 FE(HTTP_QUERY_WARNING),
867 FE(HTTP_QUERY_CUSTOM)
869 static const wininet_flag_info modifier_flags[] = {
870 FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
871 FE(HTTP_QUERY_FLAG_SYSTEMTIME),
872 FE(HTTP_QUERY_FLAG_NUMBER),
873 FE(HTTP_QUERY_FLAG_COALESCE)
876 DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
877 DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
880 TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
881 TRACE(" Attribute:");
882 for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
883 if (query_flags[i].val == info) {
884 DPRINTF(" %s", query_flags[i].name);
888 if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
889 DPRINTF(" Unknown (%08lx)", info);
892 DPRINTF(" Modifier:");
893 for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
894 if (modifier_flags[i].val & info_mod) {
895 DPRINTF(" %s", modifier_flags[i].name);
896 info_mod &= ~ modifier_flags[i].val;
901 DPRINTF(" Unknown (%08lx)", info_mod);
906 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
907 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
909 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
913 /* Find requested header structure */
914 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
916 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPWSTR)lpBuffer);
921 lphttpHdr = &lpwhr->pCustHeaders[index];
925 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
927 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
929 INT i, delim, size = 0, cnt = 0;
931 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
933 /* Calculate length of custom reuqest headers */
934 for (i = 0; i < lpwhr->nCustHeaders; i++)
936 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
937 lpwhr->pCustHeaders[i].lpszValue)
939 size += strlenW(lpwhr->pCustHeaders[i].lpszField) +
940 strlenW(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
944 /* Calculate the length of stadard request headers */
945 for (i = 0; i <= HTTP_QUERY_MAX; i++)
947 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
948 lpwhr->StdHeaders[i].lpszValue)
950 size += strlenW(lpwhr->StdHeaders[i].lpszField) +
951 strlenW(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
956 if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
958 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
959 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
963 /* Append standard request heades */
964 for (i = 0; i <= HTTP_QUERY_MAX; i++)
966 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
967 lpwhr->StdHeaders[i].lpszField &&
968 lpwhr->StdHeaders[i].lpszValue)
970 cnt += sprintfW((WCHAR*)lpBuffer + cnt, szFmt,
971 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
972 index == HTTP_QUERY_RAW_HEADERS_CRLF ? szcrlf : sznul );
976 /* Append custom request heades */
977 for (i = 0; i < lpwhr->nCustHeaders; i++)
979 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
980 lpwhr->pCustHeaders[i].lpszField &&
981 lpwhr->pCustHeaders[i].lpszValue)
983 cnt += sprintfW((WCHAR*)lpBuffer + cnt, szFmt,
984 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
985 index == HTTP_QUERY_RAW_HEADERS_CRLF ? szcrlf : sznul);
989 strcpyW((WCHAR*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? szcrlf : sznul);
991 *lpdwBufferLength = (cnt + delim) * sizeof(WCHAR);
995 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
997 lphttpHdr = &lpwhr->StdHeaders[index];
1003 /* Ensure header satisifies requested attributes */
1004 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
1005 (~lphttpHdr->wFlags & HDR_ISREQUEST))
1008 /* coalesce value to reuqested type */
1009 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
1011 *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
1014 TRACE(" returning number : %d\n", *(int *)lpBuffer);
1016 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
1022 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
1024 tmpTM = *gmtime(&tmpTime);
1025 STHook = (SYSTEMTIME *) lpBuffer;
1029 STHook->wDay = tmpTM.tm_mday;
1030 STHook->wHour = tmpTM.tm_hour;
1031 STHook->wMilliseconds = 0;
1032 STHook->wMinute = tmpTM.tm_min;
1033 STHook->wDayOfWeek = tmpTM.tm_wday;
1034 STHook->wMonth = tmpTM.tm_mon + 1;
1035 STHook->wSecond = tmpTM.tm_sec;
1036 STHook->wYear = tmpTM.tm_year;
1040 TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
1041 STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
1042 STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
1044 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
1046 if (*lpdwIndex >= lphttpHdr->wCount)
1048 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
1052 /* Copy strncpyW(lpBuffer, lphttpHdr[*lpdwIndex], len); */
1058 INT len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
1060 if (len > *lpdwBufferLength)
1062 *lpdwBufferLength = len;
1063 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1067 memcpy(lpBuffer, lphttpHdr->lpszValue, len);
1068 *lpdwBufferLength = len - sizeof(WCHAR);
1071 TRACE(" returning string : '%s'\n", debugstr_w(lpBuffer));
1075 TRACE("%d <--\n", bSuccess);
1079 /***********************************************************************
1080 * HttpQueryInfoA (WININET.@)
1082 * Queries for information about an HTTP request
1089 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1090 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1096 if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
1097 (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
1099 return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
1100 lpdwBufferLength, lpdwIndex );
1103 len = (*lpdwBufferLength)*sizeof(WCHAR);
1104 bufferW = HeapAlloc( GetProcessHeap(), 0, len );
1105 result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
1109 len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR),
1110 lpBuffer, *lpdwBufferLength, NULL, NULL );
1111 *lpdwBufferLength = len * sizeof(WCHAR);
1113 HeapFree(GetProcessHeap(), 0, bufferW );
1118 /***********************************************************************
1119 * HttpSendRequestExA (WININET.@)
1121 * Sends the specified request to the HTTP server and allows chunked
1124 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
1125 LPINTERNET_BUFFERSA lpBuffersIn,
1126 LPINTERNET_BUFFERSA lpBuffersOut,
1127 DWORD dwFlags, DWORD dwContext)
1129 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
1130 lpBuffersOut, dwFlags, dwContext);
1134 /***********************************************************************
1135 * HttpSendRequestA (WININET.@)
1137 * Sends the specified request to the HTTP server
1144 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1145 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1147 LPWININETHTTPREQW lpwhr;
1148 LPWININETHTTPSESSIONW lpwhs = NULL;
1149 LPWININETAPPINFOW hIC = NULL;
1151 TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest,
1152 lpszHeaders, debugstr_w(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength);
1154 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
1155 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1157 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1161 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1162 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1164 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1168 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1169 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1171 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1175 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1177 WORKREQUEST workRequest;
1178 struct WORKREQ_HTTPSENDREQUESTW *req;
1180 workRequest.asyncall = HTTPSENDREQUESTW;
1181 workRequest.handle = hHttpRequest;
1182 req = &workRequest.u.HttpSendRequestW;
1184 req->lpszHeader = WININET_strdupW(lpszHeaders);
1186 req->lpszHeader = 0;
1187 req->dwHeaderLength = dwHeaderLength;
1188 req->lpOptional = lpOptional;
1189 req->dwOptionalLength = dwOptionalLength;
1191 INTERNET_AsyncCall(&workRequest);
1193 * This is from windows.
1195 SetLastError(ERROR_IO_PENDING);
1200 return HTTP_HttpSendRequestW(hHttpRequest, lpszHeaders,
1201 dwHeaderLength, lpOptional, dwOptionalLength);
1205 /***********************************************************************
1206 * HttpSendRequestW (WININET.@)
1208 * Sends the specified request to the HTTP server
1215 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1216 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1219 LPWSTR szHeaders=NULL;
1220 DWORD nLen=dwHeaderLength;
1221 if(lpszHeaders!=NULL)
1223 nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
1224 szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
1225 MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
1227 result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
1229 HeapFree(GetProcessHeap(),0,szHeaders);
1233 /***********************************************************************
1234 * HTTP_HandleRedirect (internal)
1236 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl, LPCWSTR lpszHeaders,
1237 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
1239 LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1240 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1246 /* if it's an absolute path, keep the same session info */
1247 strcpyW(path,lpszUrl);
1249 else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
1251 TRACE("Redirect through proxy\n");
1252 strcpyW(path,lpszUrl);
1256 URL_COMPONENTSW urlComponents;
1257 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
1258 WCHAR password[1024], extra[1024];
1259 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
1260 urlComponents.lpszScheme = protocol;
1261 urlComponents.dwSchemeLength = 32;
1262 urlComponents.lpszHostName = hostName;
1263 urlComponents.dwHostNameLength = MAXHOSTNAME;
1264 urlComponents.lpszUserName = userName;
1265 urlComponents.dwUserNameLength = 1024;
1266 urlComponents.lpszPassword = password;
1267 urlComponents.dwPasswordLength = 1024;
1268 urlComponents.lpszUrlPath = path;
1269 urlComponents.dwUrlPathLength = 2048;
1270 urlComponents.lpszExtraInfo = extra;
1271 urlComponents.dwExtraInfoLength = 1024;
1272 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
1275 if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1276 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1280 * This upsets redirects to binary files on sourceforge.net
1281 * and gives an html page instead of the target file
1282 * Examination of the HTTP request sent by native wininet.dll
1283 * reveals that it doesn't send a referrer in that case.
1284 * Maybe there's a flag that enables this, or maybe a referrer
1285 * shouldn't be added in case of a redirect.
1288 /* consider the current host as the referrer */
1289 if (NULL != lpwhs->lpszServerName && strlenW(lpwhs->lpszServerName))
1290 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
1291 HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
1292 HTTP_ADDHDR_FLAG_ADD_IF_NEW);
1295 if (NULL != lpwhs->lpszServerName)
1296 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1297 lpwhs->lpszServerName = WININET_strdupW(hostName);
1298 if (NULL != lpwhs->lpszUserName)
1299 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1300 lpwhs->lpszUserName = WININET_strdupW(userName);
1301 lpwhs->nServerPort = urlComponents.nPort;
1303 if (NULL != lpwhr->lpszHostName)
1304 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1305 lpwhr->lpszHostName=WININET_strdupW(hostName);
1307 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1308 INTERNET_STATUS_RESOLVING_NAME,
1309 lpwhs->lpszServerName,
1310 strlenW(lpwhs->lpszServerName)+1);
1312 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1313 &lpwhs->phostent, &lpwhs->socketAddress))
1315 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1319 SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
1320 INTERNET_STATUS_NAME_RESOLVED,
1321 &(lpwhs->socketAddress),
1322 sizeof(struct sockaddr_in));
1327 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1328 lpwhr->lpszPath=NULL;
1334 rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
1335 if (rc != E_POINTER)
1336 needed = strlenW(path)+1;
1337 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
1338 rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
1339 URL_ESCAPE_SPACES_ONLY);
1342 ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(path),rc);
1343 strcpyW(lpwhr->lpszPath,path);
1347 handle = WININET_FindHandle( &lpwhr->hdr );
1348 return HttpSendRequestW(handle, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
1351 /***********************************************************************
1352 * HTTP_HttpSendRequestW (internal)
1354 * Sends the specified request to the HTTP server
1361 BOOL WINAPI HTTP_HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1362 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1366 BOOL bSuccess = FALSE;
1367 LPWSTR requestString = NULL;
1368 LPWSTR lpszHeaders_r_n = NULL; /* lpszHeaders with atleast one pair of \r\n at the end */
1369 INT requestStringLen;
1371 INT headerLength = 0;
1372 LPWININETHTTPREQW lpwhr;
1373 LPWININETHTTPSESSIONW lpwhs = NULL;
1374 LPWININETAPPINFOW hIC = NULL;
1375 BOOL loop_next = FALSE;
1376 int CustHeaderIndex;
1378 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
1380 /* Verify our tree of internet handles */
1381 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
1382 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1384 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1388 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1389 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
1391 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1395 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1396 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
1398 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1402 /* Clear any error information */
1403 INTERNET_SetLastError(0);
1406 /* We must have a verb */
1407 if (NULL == lpwhr->lpszVerb)
1412 /* if we are using optional stuff, we must add the fixed header of that option length */
1413 if (lpOptional && dwOptionalLength)
1415 char contentLengthStr[sizeof("Content-Length: ") + 20 /* int */ + 2 /* \n\r */];
1416 sprintf(contentLengthStr, "Content-Length: %li\r\n", dwOptionalLength);
1417 HttpAddRequestHeadersA(hHttpRequest, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD);
1422 static const WCHAR szSlash[] = { '/',0 };
1423 static const WCHAR szSpace[] = { ' ',0 };
1424 static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
1425 static const WCHAR szcrlf[] = {'\r','\n', 0};
1426 static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
1427 static const WCHAR szSetCookie[] = {'S','e','t','-','C','o','o','k','i','e',0 };
1429 TRACE("Going to url %s %s\n", debugstr_w(lpwhr->lpszHostName), debugstr_w(lpwhr->lpszPath));
1432 /* If we don't have a path we set it to root */
1433 if (NULL == lpwhr->lpszPath)
1434 lpwhr->lpszPath = WININET_strdupW(szSlash);
1436 if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
1437 lpwhr->lpszPath, strlenW(szHttp), szHttp, strlenW(szHttp) )
1438 && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
1440 WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0,
1441 (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
1443 strcpyW(fixurl + 1, lpwhr->lpszPath);
1444 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
1445 lpwhr->lpszPath = fixurl;
1448 /* Calculate length of request string */
1450 strlenW(lpwhr->lpszVerb) +
1451 strlenW(lpwhr->lpszPath) +
1452 strlenW(HTTPHEADER) +
1453 5; /* " \r\n\r\n" */
1455 /* add "\r\n" to end of lpszHeaders if needed */
1458 int len = strlenW(lpszHeaders);
1460 /* Check if the string is terminated with \r\n, but not if
1461 * the string is less that 2 characters long, because then
1462 * we would be looking at memory before the beginning of
1463 * the string. Besides, if it is less than 2 characters
1464 * long, then clearly, its not terminated with \r\n.
1466 if ((len > 2) && (memcmp(lpszHeaders + (len - 2), szcrlf, sizeof szcrlf) == 0))
1468 lpszHeaders_r_n = WININET_strdupW(lpszHeaders);
1472 TRACE("Adding \r\n to lpszHeaders.\n");
1473 lpszHeaders_r_n = HeapAlloc( GetProcessHeap(), 0,
1474 (len + 3)*sizeof(WCHAR) );
1475 strcpyW( lpszHeaders_r_n, lpszHeaders );
1476 strcatW( lpszHeaders_r_n, szcrlf );
1480 /* Add length of passed headers */
1483 headerLength = -1 == dwHeaderLength ? strlenW(lpszHeaders_r_n) : dwHeaderLength;
1484 requestStringLen += headerLength + 2; /* \r\n */
1488 /* if there isa proxy username and password, add it to the headers */
1489 if( hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword ) )
1491 HTTP_InsertProxyAuthorization( lpwhr, hIC->lpszProxyUsername, hIC->lpszProxyPassword );
1494 /* Calculate length of custom request headers */
1495 for (i = 0; i < lpwhr->nCustHeaders; i++)
1497 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1499 requestStringLen += strlenW(lpwhr->pCustHeaders[i].lpszField) +
1500 strlenW(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
1504 /* Calculate the length of standard request headers */
1505 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1507 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1509 requestStringLen += strlenW(lpwhr->StdHeaders[i].lpszField) +
1510 strlenW(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
1514 if (lpwhr->lpszHostName)
1515 requestStringLen += (strlenW(HTTPHOSTHEADER) + strlenW(lpwhr->lpszHostName));
1517 /* if there is optional data to send, add the length */
1520 requestStringLen += dwOptionalLength;
1523 /* Allocate string to hold entire request */
1524 requestString = HeapAlloc(GetProcessHeap(), 0, (requestStringLen + 1)*sizeof(WCHAR));
1525 if (NULL == requestString)
1527 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1531 /* Build request string */
1532 strcpyW(requestString, lpwhr->lpszVerb);
1533 strcatW(requestString, szSpace);
1534 strcatW(requestString, lpwhr->lpszPath);
1535 strcatW(requestString, HTTPHEADER );
1536 cnt = strlenW(requestString);
1538 /* Append standard request headers */
1539 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1541 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1543 static const WCHAR szFmt[] = { '\r','\n','%','s',':',' ','%','s', 0};
1544 cnt += sprintfW(requestString + cnt, szFmt,
1545 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1546 TRACE("Adding header %s (%s)\n",
1547 debugstr_w(lpwhr->StdHeaders[i].lpszField),
1548 debugstr_w(lpwhr->StdHeaders[i].lpszValue));
1552 /* Append custom request heades */
1553 for (i = 0; i < lpwhr->nCustHeaders; i++)
1555 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1557 static const WCHAR szFmt[] = { '\r','\n','%','s',':',' ','%','s', 0};
1558 cnt += sprintfW(requestString + cnt, szFmt,
1559 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1560 TRACE("Adding custom header %s (%s)\n",
1561 debugstr_w(lpwhr->pCustHeaders[i].lpszField),
1562 debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
1566 if (lpwhr->lpszHostName)
1568 static const WCHAR szFmt[] = { '%','s','%','s',0 };
1569 cnt += sprintfW(requestString + cnt, szFmt, HTTPHOSTHEADER, lpwhr->lpszHostName);
1572 /* Append passed request headers */
1573 if (lpszHeaders_r_n)
1575 strcpyW(requestString + cnt, szcrlf);
1577 strcpyW(requestString + cnt, lpszHeaders_r_n);
1578 cnt += headerLength;
1579 /* only add \r\n if not already present */
1580 if (memcmp((requestString + cnt) - 2, szcrlf, sizeof szcrlf) != 0)
1582 strcpyW(requestString + cnt, szcrlf);
1587 /* Set (header) termination string for request */
1588 if (memcmp((requestString + cnt) - 4, sztwocrlf, sizeof sztwocrlf) != 0)
1589 { /* only add it if the request string doesn't already
1590 have the thing.. (could happen if the custom header
1592 strcpyW(requestString + cnt, szcrlf);
1596 requestStringLen -= 2;
1598 /* if optional data, append it */
1601 memcpy(requestString + cnt, lpOptional, dwOptionalLength*sizeof(WCHAR));
1602 cnt += dwOptionalLength;
1603 /* we also have to decrease the expected string length by two,
1604 * since we won't be adding on those following \r\n's */
1605 requestStringLen -= 2;
1608 { /* if there is no optional data, add on another \r\n just to be safe */
1609 /* termination for request */
1610 strcpyW(requestString + cnt, szcrlf);
1614 TRACE("(%s) len(%d)\n", debugstr_w(requestString), requestStringLen);
1615 /* Send the request and store the results */
1616 if (!HTTP_OpenConnection(lpwhr))
1619 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1620 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1622 /* send the request as ASCII */
1627 ascii_len = WideCharToMultiByte( CP_ACP, 0, requestString,
1628 requestStringLen, NULL, 0, NULL, NULL );
1629 ascii_req = HeapAlloc( GetProcessHeap(), 0, ascii_len );
1630 WideCharToMultiByte( CP_ACP, 0, requestString, requestStringLen,
1631 ascii_req, ascii_len, NULL, NULL );
1632 NETCON_send(&lpwhr->netConnection, ascii_req, ascii_len, 0, &cnt);
1633 HeapFree( GetProcessHeap(), 0, ascii_req );
1637 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1638 INTERNET_STATUS_REQUEST_SENT,
1639 &requestStringLen,sizeof(DWORD));
1641 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1642 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1647 responseLen = HTTP_GetResponseHeaders(lpwhr);
1651 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1652 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1655 /* process headers here. Is this right? */
1656 CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSetCookie);
1657 if (CustHeaderIndex >= 0)
1659 LPHTTPHEADERW setCookieHeader;
1660 int nPosStart = 0, nPosEnd = 0, len;
1661 static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0};
1663 setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex];
1665 while (setCookieHeader->lpszValue[nPosEnd] != '\0')
1667 LPWSTR buf_cookie, cookie_name, cookie_data;
1669 LPWSTR domain = NULL;
1671 while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
1672 setCookieHeader->lpszValue[nPosEnd] != '\0')
1676 if (setCookieHeader->lpszValue[nPosEnd] == ';')
1678 /* fixme: not case sensitive, strcasestr is gnu only */
1679 int nDomainPosEnd = 0;
1680 int nDomainPosStart = 0, nDomainLength = 0;
1681 static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0};
1682 LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain);
1684 { /* they have specified their own domain, lets use it */
1685 while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
1686 lpszDomain[nDomainPosEnd] != '\0')
1690 nDomainPosStart = strlenW(szDomain);
1691 nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
1692 domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR));
1693 strncpyW(domain, &lpszDomain[nDomainPosStart], nDomainLength);
1694 domain[nDomainLength] = '\0';
1697 if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
1698 buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR));
1699 strncpyW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart));
1700 buf_cookie[(nPosEnd - nPosStart)] = '\0';
1701 TRACE("%s\n", debugstr_w(buf_cookie));
1702 while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
1706 if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
1708 HeapFree(GetProcessHeap(), 0, buf_cookie);
1712 cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR));
1713 strncpyW(cookie_name, buf_cookie, nEqualPos);
1714 cookie_name[nEqualPos] = '\0';
1715 cookie_data = &buf_cookie[nEqualPos + 1];
1718 len = strlenW((domain ? domain : lpwhr->lpszHostName)) + strlenW(lpwhr->lpszPath) + 9;
1719 buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1720 sprintfW(buf_url, szFmt, (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */
1721 InternetSetCookieW(buf_url, cookie_name, cookie_data);
1723 HeapFree(GetProcessHeap(), 0, buf_url);
1724 HeapFree(GetProcessHeap(), 0, buf_cookie);
1725 HeapFree(GetProcessHeap(), 0, cookie_name);
1726 if (domain) HeapFree(GetProcessHeap(), 0, domain);
1727 nPosStart = nPosEnd;
1736 HeapFree(GetProcessHeap(), 0, requestString);
1739 HeapFree(GetProcessHeap(), 0, lpszHeaders_r_n);
1741 /* TODO: send notification for P3P header */
1743 if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1745 DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1746 if(HttpQueryInfoW(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1747 (dwCode==302 || dwCode==301))
1749 WCHAR szNewLocation[2048];
1750 DWORD dwBufferSize=2048;
1752 if(HttpQueryInfoW(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1754 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1755 INTERNET_STATUS_REDIRECT, szNewLocation,
1757 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1758 dwHeaderLength, lpOptional, dwOptionalLength);
1763 if (hIC->lpfnStatusCB)
1765 INTERNET_ASYNC_RESULT iar;
1767 iar.dwResult = (DWORD)bSuccess;
1768 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1770 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1771 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1772 sizeof(INTERNET_ASYNC_RESULT));
1780 /***********************************************************************
1781 * HTTP_Connect (internal)
1783 * Create http session handle
1786 * HINTERNET a session handle on success
1790 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCWSTR lpszServerName,
1791 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1792 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1794 BOOL bSuccess = FALSE;
1795 LPWININETAPPINFOW hIC = NULL;
1796 LPWININETHTTPSESSIONW lpwhs = NULL;
1797 HINTERNET handle = NULL;
1801 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1802 if( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1805 hIC->hdr.dwContext = dwContext;
1807 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
1810 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1814 handle = WININET_AllocHandle( &lpwhs->hdr );
1817 ERR("Failed to alloc handle\n");
1818 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1823 * According to my tests. The name is not resolved until a request is sent
1826 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1827 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1829 lpwhs->hdr.htype = WH_HHTTPSESSION;
1830 lpwhs->hdr.lpwhparent = &hIC->hdr;
1831 lpwhs->hdr.dwFlags = dwFlags;
1832 lpwhs->hdr.dwContext = dwContext;
1833 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1834 if(strchrW(hIC->lpszProxy, ' '))
1835 FIXME("Several proxies not implemented.\n");
1836 if(hIC->lpszProxyBypass)
1837 FIXME("Proxy bypass is ignored.\n");
1839 if (NULL != lpszServerName)
1840 lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
1841 if (NULL != lpszUserName)
1842 lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
1843 lpwhs->nServerPort = nServerPort;
1845 if (hIC->lpfnStatusCB)
1847 INTERNET_ASYNC_RESULT iar;
1849 iar.dwResult = (DWORD)handle;
1850 iar.dwError = ERROR_SUCCESS;
1852 SendAsyncCallback(hIC, hInternet, dwContext,
1853 INTERNET_STATUS_HANDLE_CREATED, &iar,
1854 sizeof(INTERNET_ASYNC_RESULT));
1860 if (!bSuccess && lpwhs)
1862 HeapFree(GetProcessHeap(), 0, lpwhs);
1863 WININET_FreeHandle( handle );
1868 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1872 TRACE("%p --> %p\n", hInternet, handle);
1877 /***********************************************************************
1878 * HTTP_OpenConnection (internal)
1880 * Connect to a web server
1887 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
1889 BOOL bSuccess = FALSE;
1890 LPWININETHTTPSESSIONW lpwhs;
1891 LPWININETAPPINFOW hIC = NULL;
1896 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1898 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1902 lpwhs = (LPWININETHTTPSESSIONW)lpwhr->hdr.lpwhparent;
1904 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1905 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1906 INTERNET_STATUS_CONNECTING_TO_SERVER,
1907 &(lpwhs->socketAddress),
1908 sizeof(struct sockaddr_in));
1910 if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1913 WARN("Socket creation failed\n");
1917 if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1918 sizeof(lpwhs->socketAddress)))
1920 WARN("Unable to connect to host (%s)\n", strerror(errno));
1924 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1925 INTERNET_STATUS_CONNECTED_TO_SERVER,
1926 &(lpwhs->socketAddress),
1927 sizeof(struct sockaddr_in));
1932 TRACE("%d <--\n", bSuccess);
1937 /***********************************************************************
1938 * HTTP_GetResponseHeaders (internal)
1940 * Read server response
1947 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
1950 WCHAR buffer[MAX_REPLY_LEN];
1951 DWORD buflen = MAX_REPLY_LEN;
1952 BOOL bSuccess = FALSE;
1954 WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1955 static const WCHAR szStatus[] = {'S','t','a','t','u','s',0};
1956 static const WCHAR szHttp[] = { 'H','T','T','P',0 };
1957 char bufferA[MAX_REPLY_LEN];
1961 if (!NETCON_connected(&lpwhr->netConnection))
1965 * HACK peek at the buffer
1967 NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1970 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1972 buflen = MAX_REPLY_LEN;
1973 memset(buffer, 0, MAX_REPLY_LEN);
1974 if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1976 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1978 if (strncmpW(buffer, szHttp, 4) != 0)
1982 HTTP_ProcessHeader(lpwhr, szStatus, buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1984 /* Parse each response line */
1987 buflen = MAX_REPLY_LEN;
1988 if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1990 TRACE("got line %s, now interpretting\n", debugstr_a(bufferA));
1991 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1992 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1995 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
2017 /***********************************************************************
2018 * HTTP_InterpretHttpHeader (internal)
2020 * Parse server response
2027 INT stripSpaces(LPCWSTR lpszSrc, LPWSTR lpszStart, INT *len)
2034 while (*lpszSrc == ' ' && *lpszSrc != '\0')
2038 while(*lpsztmp != '\0')
2040 if (*lpsztmp != ' ')
2041 srclen = lpsztmp - lpszSrc + 1;
2046 *len = min(*len, srclen);
2047 strncpyW(lpszStart, lpszSrc, *len);
2048 lpszStart[*len] = '\0';
2054 BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen)
2057 BOOL bSuccess = FALSE;
2064 pd = strchrW(buffer, ':');
2068 if (stripSpaces(buffer, field, &fieldlen) > 0)
2070 if (stripSpaces(pd+1, value, &valuelen) > 0)
2075 TRACE("%d: field(%s) Value(%s)\n", bSuccess, debugstr_w(field), debugstr_w(value));
2080 /***********************************************************************
2081 * HTTP_GetStdHeaderIndex (internal)
2083 * Lookup field index in standard http header array
2085 * FIXME: This should be stuffed into a hash table
2087 INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField)
2090 static const WCHAR szContentLength[] = {
2091 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
2092 static const WCHAR szStatus[] = {'S','t','a','t','u','s',0};
2093 static const WCHAR szContentType[] = {
2094 'C','o','n','t','e','n','t','-','T','y','p','e',0};
2095 static const WCHAR szLastModified[] = {
2096 'L','a','s','t','-','M','o','d','i','f','i','e','d',0};
2097 static const WCHAR szLocation[] = {'L','o','c','a','t','i','o','n',0};
2098 static const WCHAR szAccept[] = {'A','c','c','e','p','t',0};
2099 static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0};
2100 static const WCHAR szContentTrans[] = { 'C','o','n','t','e','n','t','-',
2101 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
2102 static const WCHAR szDate[] = { 'D','a','t','e',0};
2103 static const WCHAR szServer[] = { 'S','e','r','v','e','r',0};
2104 static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0};
2105 static const WCHAR szETag[] = { 'E','T','a','g',0};
2106 static const WCHAR szAcceptRanges[] = {
2107 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
2108 static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
2109 static const WCHAR szMimeVersion[] = {
2110 'M','i','m','e','-','V','e','r','s','i','o','n', 0};
2111 static const WCHAR szPragma[] = { 'P','r','a','g','m','a', 0};
2112 static const WCHAR szCacheControl[] = {
2113 'C','a','c','h','e','-','C','o','n','t','r','o','l',0};
2114 static const WCHAR szUserAgent[] = { 'U','s','e','r','-','A','g','e','n','t',0};
2115 static const WCHAR szProxyAuth[] = {
2116 'P','r','o','x','y','-',
2117 'A','u','t','h','e','n','t','i','c','a','t','e', 0};
2119 if (!strcmpiW(lpszField, szContentLength))
2120 index = HTTP_QUERY_CONTENT_LENGTH;
2121 else if (!strcmpiW(lpszField,szStatus))
2122 index = HTTP_QUERY_STATUS_CODE;
2123 else if (!strcmpiW(lpszField,szContentType))
2124 index = HTTP_QUERY_CONTENT_TYPE;
2125 else if (!strcmpiW(lpszField,szLastModified))
2126 index = HTTP_QUERY_LAST_MODIFIED;
2127 else if (!strcmpiW(lpszField,szLocation))
2128 index = HTTP_QUERY_LOCATION;
2129 else if (!strcmpiW(lpszField,szAccept))
2130 index = HTTP_QUERY_ACCEPT;
2131 else if (!strcmpiW(lpszField,szReferer))
2132 index = HTTP_QUERY_REFERER;
2133 else if (!strcmpiW(lpszField,szContentTrans))
2134 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
2135 else if (!strcmpiW(lpszField,szDate))
2136 index = HTTP_QUERY_DATE;
2137 else if (!strcmpiW(lpszField,szServer))
2138 index = HTTP_QUERY_SERVER;
2139 else if (!strcmpiW(lpszField,szConnection))
2140 index = HTTP_QUERY_CONNECTION;
2141 else if (!strcmpiW(lpszField,szETag))
2142 index = HTTP_QUERY_ETAG;
2143 else if (!strcmpiW(lpszField,szAcceptRanges))
2144 index = HTTP_QUERY_ACCEPT_RANGES;
2145 else if (!strcmpiW(lpszField,szExpires))
2146 index = HTTP_QUERY_EXPIRES;
2147 else if (!strcmpiW(lpszField,szMimeVersion))
2148 index = HTTP_QUERY_MIME_VERSION;
2149 else if (!strcmpiW(lpszField,szPragma))
2150 index = HTTP_QUERY_PRAGMA;
2151 else if (!strcmpiW(lpszField,szCacheControl))
2152 index = HTTP_QUERY_CACHE_CONTROL;
2153 else if (!strcmpiW(lpszField,szUserAgent))
2154 index = HTTP_QUERY_USER_AGENT;
2155 else if (!strcmpiW(lpszField,szProxyAuth))
2156 index = HTTP_QUERY_PROXY_AUTHENTICATE;
2159 TRACE("Couldn't find %s in standard header table\n", debugstr_w(lpszField));
2166 /***********************************************************************
2167 * HTTP_ProcessHeader (internal)
2169 * Stuff header into header tables according to <dwModifier>
2173 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2175 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
2177 LPHTTPHEADERW lphttpHdr = NULL;
2178 BOOL bSuccess = FALSE;
2181 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), (unsigned int)dwModifier);
2183 /* Adjust modifier flags */
2184 if (dwModifier & COALESCEFLASG)
2185 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2187 /* Try to get index into standard header array */
2188 index = HTTP_GetStdHeaderIndex(field);
2191 lphttpHdr = &lpwhr->StdHeaders[index];
2193 else /* Find or create new custom header */
2195 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2198 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2202 lphttpHdr = &lpwhr->pCustHeaders[index];
2208 hdr.lpszField = (LPWSTR)field;
2209 hdr.lpszValue = (LPWSTR)value;
2210 hdr.wFlags = hdr.wCount = 0;
2212 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2213 hdr.wFlags |= HDR_ISREQUEST;
2215 return HTTP_InsertCustomHeader(lpwhr, &hdr);
2219 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2220 lphttpHdr->wFlags |= HDR_ISREQUEST;
2222 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2224 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2228 if (!lpwhr->StdHeaders[index].lpszField)
2230 lphttpHdr->lpszField = WININET_strdupW(field);
2232 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2233 lphttpHdr->wFlags |= HDR_ISREQUEST;
2236 slen = strlenW(value) + 1;
2237 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen*sizeof(WCHAR));
2238 if (lphttpHdr->lpszValue)
2240 strcpyW(lphttpHdr->lpszValue, value);
2245 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2248 else if (lphttpHdr->lpszValue)
2250 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2255 len = strlenW(value);
2259 /* if custom header delete from array */
2260 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
2261 lphttpHdr->lpszValue = NULL;
2266 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2269 lphttpHdr->lpszValue = lpsztmp;
2270 strcpyW(lpsztmp, value);
2275 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2276 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2280 else if (dwModifier & COALESCEFLASG)
2285 INT origlen = strlenW(lphttpHdr->lpszValue);
2286 INT valuelen = strlenW(value);
2288 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2291 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2293 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2296 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2299 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2301 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2304 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2307 lphttpHdr->lpszValue[origlen] = ch;
2311 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
2312 lphttpHdr->lpszValue[len] = '\0';
2317 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2318 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2322 TRACE("<-- %d\n",bSuccess);
2327 /***********************************************************************
2328 * HTTP_CloseConnection (internal)
2330 * Close socket connection
2333 VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr)
2337 LPWININETHTTPSESSIONW lpwhs = NULL;
2338 LPWININETAPPINFOW hIC = NULL;
2341 TRACE("%p\n",lpwhr);
2343 handle = WININET_FindHandle( &lpwhr->hdr );
2344 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2345 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2347 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2348 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2350 if (NETCON_connected(&lpwhr->netConnection))
2352 NETCON_close(&lpwhr->netConnection);
2355 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2356 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2360 /***********************************************************************
2361 * HTTP_CloseHTTPRequestHandle (internal)
2363 * Deallocate request handle
2366 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQW lpwhr)
2369 LPWININETHTTPSESSIONW lpwhs = NULL;
2370 LPWININETAPPINFOW hIC = NULL;
2375 if (NETCON_connected(&lpwhr->netConnection))
2376 HTTP_CloseConnection(lpwhr);
2378 handle = WININET_FindHandle( &lpwhr->hdr );
2379 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2380 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2382 SendAsyncCallback(hIC, handle, lpwhr->hdr.dwContext,
2383 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
2386 if (lpwhr->lpszPath)
2387 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2388 if (lpwhr->lpszVerb)
2389 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2390 if (lpwhr->lpszHostName)
2391 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2393 for (i = 0; i <= HTTP_QUERY_MAX; i++)
2395 if (lpwhr->StdHeaders[i].lpszField)
2396 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2397 if (lpwhr->StdHeaders[i].lpszValue)
2398 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2401 for (i = 0; i < lpwhr->nCustHeaders; i++)
2403 if (lpwhr->pCustHeaders[i].lpszField)
2404 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2405 if (lpwhr->pCustHeaders[i].lpszValue)
2406 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2409 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2410 HeapFree(GetProcessHeap(), 0, lpwhr);
2414 /***********************************************************************
2415 * HTTP_CloseHTTPSessionHandle (internal)
2417 * Deallocate session handle
2420 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONW lpwhs)
2422 LPWININETAPPINFOW hIC = NULL;
2425 TRACE("%p\n", lpwhs);
2427 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2429 handle = WININET_FindHandle( &lpwhs->hdr );
2430 SendAsyncCallback(hIC, handle, lpwhs->hdr.dwContext,
2431 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
2434 if (lpwhs->lpszServerName)
2435 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2436 if (lpwhs->lpszUserName)
2437 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2438 HeapFree(GetProcessHeap(), 0, lpwhs);
2442 /***********************************************************************
2443 * HTTP_GetCustomHeaderIndex (internal)
2445 * Return index of custom header from header array
2448 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField)
2452 TRACE("%s\n", debugstr_w(lpszField));
2454 for (index = 0; index < lpwhr->nCustHeaders; index++)
2456 if (!strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
2461 if (index >= lpwhr->nCustHeaders)
2464 TRACE("Return: %d\n", index);
2469 /***********************************************************************
2470 * HTTP_InsertCustomHeader (internal)
2472 * Insert header into array
2475 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
2478 LPHTTPHEADERW lph = NULL;
2481 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
2482 count = lpwhr->nCustHeaders + 1;
2484 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
2486 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
2490 lpwhr->pCustHeaders = lph;
2491 lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField);
2492 lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue);
2493 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2494 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2495 lpwhr->nCustHeaders++;
2500 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2507 /***********************************************************************
2508 * HTTP_DeleteCustomHeader (internal)
2510 * Delete header from array
2511 * If this function is called, the indexs may change.
2513 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index)
2515 if( lpwhr->nCustHeaders <= 0 )
2517 if( lpwhr->nCustHeaders >= index )
2519 lpwhr->nCustHeaders--;
2521 memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2522 (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
2523 memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
2528 /***********************************************************************
2529 * IsHostInProxyBypassList (@)
2534 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2536 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);