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,
1793 DWORD dwInternalFlags)
1795 BOOL bSuccess = FALSE;
1796 LPWININETAPPINFOW hIC = NULL;
1797 LPWININETHTTPSESSIONW lpwhs = NULL;
1798 HINTERNET handle = NULL;
1802 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1803 if( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1806 hIC->hdr.dwContext = dwContext;
1808 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
1811 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1815 handle = WININET_AllocHandle( &lpwhs->hdr );
1818 ERR("Failed to alloc handle\n");
1819 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1824 * According to my tests. The name is not resolved until a request is sent
1827 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1828 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1830 lpwhs->hdr.htype = WH_HHTTPSESSION;
1831 lpwhs->hdr.lpwhparent = &hIC->hdr;
1832 lpwhs->hdr.dwFlags = dwFlags;
1833 lpwhs->hdr.dwContext = dwContext;
1834 lpwhs->hdr.dwInternalFlags = dwInternalFlags;
1835 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1836 if(strchrW(hIC->lpszProxy, ' '))
1837 FIXME("Several proxies not implemented.\n");
1838 if(hIC->lpszProxyBypass)
1839 FIXME("Proxy bypass is ignored.\n");
1841 if (NULL != lpszServerName)
1842 lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
1843 if (NULL != lpszUserName)
1844 lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
1845 lpwhs->nServerPort = nServerPort;
1847 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1848 if (hIC->lpfnStatusCB && !(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
1850 INTERNET_ASYNC_RESULT iar;
1852 iar.dwResult = (DWORD)handle;
1853 iar.dwError = ERROR_SUCCESS;
1855 SendAsyncCallback(hIC, hInternet, dwContext,
1856 INTERNET_STATUS_HANDLE_CREATED, &iar,
1857 sizeof(INTERNET_ASYNC_RESULT));
1863 if (!bSuccess && lpwhs)
1865 HeapFree(GetProcessHeap(), 0, lpwhs);
1866 WININET_FreeHandle( handle );
1871 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1875 TRACE("%p --> %p\n", hInternet, handle);
1880 /***********************************************************************
1881 * HTTP_OpenConnection (internal)
1883 * Connect to a web server
1890 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
1892 BOOL bSuccess = FALSE;
1893 LPWININETHTTPSESSIONW lpwhs;
1894 LPWININETAPPINFOW hIC = NULL;
1899 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1901 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1905 lpwhs = (LPWININETHTTPSESSIONW)lpwhr->hdr.lpwhparent;
1907 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1908 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1909 INTERNET_STATUS_CONNECTING_TO_SERVER,
1910 &(lpwhs->socketAddress),
1911 sizeof(struct sockaddr_in));
1913 if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1916 WARN("Socket creation failed\n");
1920 if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1921 sizeof(lpwhs->socketAddress)))
1923 WARN("Unable to connect to host (%s)\n", strerror(errno));
1927 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1928 INTERNET_STATUS_CONNECTED_TO_SERVER,
1929 &(lpwhs->socketAddress),
1930 sizeof(struct sockaddr_in));
1935 TRACE("%d <--\n", bSuccess);
1940 /***********************************************************************
1941 * HTTP_GetResponseHeaders (internal)
1943 * Read server response
1950 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
1953 WCHAR buffer[MAX_REPLY_LEN];
1954 DWORD buflen = MAX_REPLY_LEN;
1955 BOOL bSuccess = FALSE;
1957 WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1958 static const WCHAR szStatus[] = {'S','t','a','t','u','s',0};
1959 static const WCHAR szHttp[] = { 'H','T','T','P',0 };
1960 char bufferA[MAX_REPLY_LEN];
1964 if (!NETCON_connected(&lpwhr->netConnection))
1968 * HACK peek at the buffer
1970 NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1973 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1975 buflen = MAX_REPLY_LEN;
1976 memset(buffer, 0, MAX_REPLY_LEN);
1977 if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1979 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1981 if (strncmpW(buffer, szHttp, 4) != 0)
1985 HTTP_ProcessHeader(lpwhr, szStatus, buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1987 /* Parse each response line */
1990 buflen = MAX_REPLY_LEN;
1991 if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1993 TRACE("got line %s, now interpretting\n", debugstr_a(bufferA));
1994 MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1995 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1998 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
2020 /***********************************************************************
2021 * HTTP_InterpretHttpHeader (internal)
2023 * Parse server response
2030 INT stripSpaces(LPCWSTR lpszSrc, LPWSTR lpszStart, INT *len)
2037 while (*lpszSrc == ' ' && *lpszSrc != '\0')
2041 while(*lpsztmp != '\0')
2043 if (*lpsztmp != ' ')
2044 srclen = lpsztmp - lpszSrc + 1;
2049 *len = min(*len, srclen);
2050 strncpyW(lpszStart, lpszSrc, *len);
2051 lpszStart[*len] = '\0';
2057 BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen)
2060 BOOL bSuccess = FALSE;
2067 pd = strchrW(buffer, ':');
2071 if (stripSpaces(buffer, field, &fieldlen) > 0)
2073 if (stripSpaces(pd+1, value, &valuelen) > 0)
2078 TRACE("%d: field(%s) Value(%s)\n", bSuccess, debugstr_w(field), debugstr_w(value));
2083 /***********************************************************************
2084 * HTTP_GetStdHeaderIndex (internal)
2086 * Lookup field index in standard http header array
2088 * FIXME: This should be stuffed into a hash table
2090 INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField)
2093 static const WCHAR szContentLength[] = {
2094 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
2095 static const WCHAR szStatus[] = {'S','t','a','t','u','s',0};
2096 static const WCHAR szContentType[] = {
2097 'C','o','n','t','e','n','t','-','T','y','p','e',0};
2098 static const WCHAR szLastModified[] = {
2099 'L','a','s','t','-','M','o','d','i','f','i','e','d',0};
2100 static const WCHAR szLocation[] = {'L','o','c','a','t','i','o','n',0};
2101 static const WCHAR szAccept[] = {'A','c','c','e','p','t',0};
2102 static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0};
2103 static const WCHAR szContentTrans[] = { 'C','o','n','t','e','n','t','-',
2104 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
2105 static const WCHAR szDate[] = { 'D','a','t','e',0};
2106 static const WCHAR szServer[] = { 'S','e','r','v','e','r',0};
2107 static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0};
2108 static const WCHAR szETag[] = { 'E','T','a','g',0};
2109 static const WCHAR szAcceptRanges[] = {
2110 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
2111 static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
2112 static const WCHAR szMimeVersion[] = {
2113 'M','i','m','e','-','V','e','r','s','i','o','n', 0};
2114 static const WCHAR szPragma[] = { 'P','r','a','g','m','a', 0};
2115 static const WCHAR szCacheControl[] = {
2116 'C','a','c','h','e','-','C','o','n','t','r','o','l',0};
2117 static const WCHAR szUserAgent[] = { 'U','s','e','r','-','A','g','e','n','t',0};
2118 static const WCHAR szProxyAuth[] = {
2119 'P','r','o','x','y','-',
2120 'A','u','t','h','e','n','t','i','c','a','t','e', 0};
2122 if (!strcmpiW(lpszField, szContentLength))
2123 index = HTTP_QUERY_CONTENT_LENGTH;
2124 else if (!strcmpiW(lpszField,szStatus))
2125 index = HTTP_QUERY_STATUS_CODE;
2126 else if (!strcmpiW(lpszField,szContentType))
2127 index = HTTP_QUERY_CONTENT_TYPE;
2128 else if (!strcmpiW(lpszField,szLastModified))
2129 index = HTTP_QUERY_LAST_MODIFIED;
2130 else if (!strcmpiW(lpszField,szLocation))
2131 index = HTTP_QUERY_LOCATION;
2132 else if (!strcmpiW(lpszField,szAccept))
2133 index = HTTP_QUERY_ACCEPT;
2134 else if (!strcmpiW(lpszField,szReferer))
2135 index = HTTP_QUERY_REFERER;
2136 else if (!strcmpiW(lpszField,szContentTrans))
2137 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
2138 else if (!strcmpiW(lpszField,szDate))
2139 index = HTTP_QUERY_DATE;
2140 else if (!strcmpiW(lpszField,szServer))
2141 index = HTTP_QUERY_SERVER;
2142 else if (!strcmpiW(lpszField,szConnection))
2143 index = HTTP_QUERY_CONNECTION;
2144 else if (!strcmpiW(lpszField,szETag))
2145 index = HTTP_QUERY_ETAG;
2146 else if (!strcmpiW(lpszField,szAcceptRanges))
2147 index = HTTP_QUERY_ACCEPT_RANGES;
2148 else if (!strcmpiW(lpszField,szExpires))
2149 index = HTTP_QUERY_EXPIRES;
2150 else if (!strcmpiW(lpszField,szMimeVersion))
2151 index = HTTP_QUERY_MIME_VERSION;
2152 else if (!strcmpiW(lpszField,szPragma))
2153 index = HTTP_QUERY_PRAGMA;
2154 else if (!strcmpiW(lpszField,szCacheControl))
2155 index = HTTP_QUERY_CACHE_CONTROL;
2156 else if (!strcmpiW(lpszField,szUserAgent))
2157 index = HTTP_QUERY_USER_AGENT;
2158 else if (!strcmpiW(lpszField,szProxyAuth))
2159 index = HTTP_QUERY_PROXY_AUTHENTICATE;
2162 TRACE("Couldn't find %s in standard header table\n", debugstr_w(lpszField));
2169 /***********************************************************************
2170 * HTTP_ProcessHeader (internal)
2172 * Stuff header into header tables according to <dwModifier>
2176 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2178 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
2180 LPHTTPHEADERW lphttpHdr = NULL;
2181 BOOL bSuccess = FALSE;
2184 TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), (unsigned int)dwModifier);
2186 /* Adjust modifier flags */
2187 if (dwModifier & COALESCEFLASG)
2188 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2190 /* Try to get index into standard header array */
2191 index = HTTP_GetStdHeaderIndex(field);
2194 lphttpHdr = &lpwhr->StdHeaders[index];
2196 else /* Find or create new custom header */
2198 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2201 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2205 lphttpHdr = &lpwhr->pCustHeaders[index];
2211 hdr.lpszField = (LPWSTR)field;
2212 hdr.lpszValue = (LPWSTR)value;
2213 hdr.wFlags = hdr.wCount = 0;
2215 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2216 hdr.wFlags |= HDR_ISREQUEST;
2218 return HTTP_InsertCustomHeader(lpwhr, &hdr);
2222 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2223 lphttpHdr->wFlags |= HDR_ISREQUEST;
2225 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2227 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2231 if (!lpwhr->StdHeaders[index].lpszField)
2233 lphttpHdr->lpszField = WININET_strdupW(field);
2235 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2236 lphttpHdr->wFlags |= HDR_ISREQUEST;
2239 slen = strlenW(value) + 1;
2240 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen*sizeof(WCHAR));
2241 if (lphttpHdr->lpszValue)
2243 strcpyW(lphttpHdr->lpszValue, value);
2248 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2251 else if (lphttpHdr->lpszValue)
2253 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2258 len = strlenW(value);
2262 /* if custom header delete from array */
2263 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
2264 lphttpHdr->lpszValue = NULL;
2269 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2272 lphttpHdr->lpszValue = lpsztmp;
2273 strcpyW(lpsztmp, value);
2278 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2279 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2283 else if (dwModifier & COALESCEFLASG)
2288 INT origlen = strlenW(lphttpHdr->lpszValue);
2289 INT valuelen = strlenW(value);
2291 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2294 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2296 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2299 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2302 len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2304 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2307 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2310 lphttpHdr->lpszValue[origlen] = ch;
2314 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
2315 lphttpHdr->lpszValue[len] = '\0';
2320 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2321 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2325 TRACE("<-- %d\n",bSuccess);
2330 /***********************************************************************
2331 * HTTP_CloseConnection (internal)
2333 * Close socket connection
2336 VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr)
2340 LPWININETHTTPSESSIONW lpwhs = NULL;
2341 LPWININETAPPINFOW hIC = NULL;
2344 TRACE("%p\n",lpwhr);
2346 handle = WININET_FindHandle( &lpwhr->hdr );
2347 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2348 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2350 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2351 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2353 if (NETCON_connected(&lpwhr->netConnection))
2355 NETCON_close(&lpwhr->netConnection);
2358 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
2359 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2363 /***********************************************************************
2364 * HTTP_CloseHTTPRequestHandle (internal)
2366 * Deallocate request handle
2369 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQW lpwhr)
2372 LPWININETHTTPSESSIONW lpwhs = NULL;
2373 LPWININETAPPINFOW hIC = NULL;
2378 if (NETCON_connected(&lpwhr->netConnection))
2379 HTTP_CloseConnection(lpwhr);
2381 handle = WININET_FindHandle( &lpwhr->hdr );
2382 lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2383 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2385 SendAsyncCallback(hIC, handle, lpwhr->hdr.dwContext,
2386 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
2389 if (lpwhr->lpszPath)
2390 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2391 if (lpwhr->lpszVerb)
2392 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2393 if (lpwhr->lpszHostName)
2394 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2396 for (i = 0; i <= HTTP_QUERY_MAX; i++)
2398 if (lpwhr->StdHeaders[i].lpszField)
2399 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2400 if (lpwhr->StdHeaders[i].lpszValue)
2401 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2404 for (i = 0; i < lpwhr->nCustHeaders; i++)
2406 if (lpwhr->pCustHeaders[i].lpszField)
2407 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2408 if (lpwhr->pCustHeaders[i].lpszValue)
2409 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2412 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2413 HeapFree(GetProcessHeap(), 0, lpwhr);
2415 /* If this handle was opened with InternetOpenUrl, we need to close the parent to prevent
2418 if(lpwhs->hdr.dwInternalFlags & INET_OPENURL)
2420 handle = WININET_FindHandle( &lpwhs->hdr );
2421 InternetCloseHandle(handle);
2426 /***********************************************************************
2427 * HTTP_CloseHTTPSessionHandle (internal)
2429 * Deallocate session handle
2432 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONW lpwhs)
2434 LPWININETAPPINFOW hIC = NULL;
2437 TRACE("%p\n", lpwhs);
2439 hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2441 /* Don't send a handle closing callback if this handle was created with InternetOpenUrl */
2442 if(!(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
2444 handle = WININET_FindHandle( &lpwhs->hdr );
2445 SendAsyncCallback(hIC, handle, lpwhs->hdr.dwContext,
2446 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
2450 if (lpwhs->lpszServerName)
2451 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2452 if (lpwhs->lpszUserName)
2453 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2454 HeapFree(GetProcessHeap(), 0, lpwhs);
2458 /***********************************************************************
2459 * HTTP_GetCustomHeaderIndex (internal)
2461 * Return index of custom header from header array
2464 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField)
2468 TRACE("%s\n", debugstr_w(lpszField));
2470 for (index = 0; index < lpwhr->nCustHeaders; index++)
2472 if (!strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
2477 if (index >= lpwhr->nCustHeaders)
2480 TRACE("Return: %d\n", index);
2485 /***********************************************************************
2486 * HTTP_InsertCustomHeader (internal)
2488 * Insert header into array
2491 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
2494 LPHTTPHEADERW lph = NULL;
2497 TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
2498 count = lpwhr->nCustHeaders + 1;
2500 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
2502 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
2506 lpwhr->pCustHeaders = lph;
2507 lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField);
2508 lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue);
2509 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2510 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2511 lpwhr->nCustHeaders++;
2516 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2523 /***********************************************************************
2524 * HTTP_DeleteCustomHeader (internal)
2526 * Delete header from array
2527 * If this function is called, the indexs may change.
2529 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index)
2531 if( lpwhr->nCustHeaders <= 0 )
2533 if( lpwhr->nCustHeaders >= index )
2535 lpwhr->nCustHeaders--;
2537 memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2538 (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
2539 memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
2544 /***********************************************************************
2545 * IsHostInProxyBypassList (@)
2550 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2552 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);