#include "config.h"
#include "wine/port.h"
+#if defined(__MINGW32__) || defined (_MSC_VER)
+#include <ws2tcpip.h>
+#endif
+
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#include <time.h>
#include <assert.h>
+#ifdef HAVE_ZLIB
+# include <zlib.h>
+#endif
#include "windef.h"
#include "winbase.h"
#define NO_SHLWAPI_GDI
#include "shlwapi.h"
#include "sspi.h"
+#include "wincrypt.h"
#include "internet.h"
#include "wine/debug.h"
+#include "wine/exception.h"
#include "wine/unicode.h"
#include "inet_ntop.c"
WINE_DEFAULT_DEBUG_CHANNEL(wininet);
-static const WCHAR g_szHttp1_0[] = {' ','H','T','T','P','/','1','.','0',0 };
-static const WCHAR g_szHttp1_1[] = {' ','H','T','T','P','/','1','.','1',0 };
-static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0};
-static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0};
-static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0};
-static const WCHAR szHost[] = { 'H','o','s','t',0 };
+static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0};
+static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0};
+static const WCHAR szOK[] = {'O','K',0};
+static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0};
+static const WCHAR hostW[] = { 'H','o','s','t',0 };
static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 };
static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0};
+static const WCHAR szGET[] = { 'G','E','T', 0 };
+static const WCHAR szHEAD[] = { 'H','E','A','D', 0 };
+static const WCHAR szCrLf[] = {'\r','\n', 0};
+
+static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
+static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
+static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
+static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
+static const WCHAR szAge[] = { 'A','g','e',0 };
+static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
+static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
+static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
+static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
+static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
+static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
+static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
+static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
+static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
+static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
+static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
+static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
+static const WCHAR szDate[] = { 'D','a','t','e',0 };
+static const WCHAR szFrom[] = { 'F','r','o','m',0 };
+static const WCHAR szETag[] = { 'E','T','a','g',0 };
+static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
+static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
+static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
+static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
+static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
+static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
+static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
+static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
+static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
+static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
+static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
+static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
+static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
+static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
+static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
+static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
+static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
+static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
+static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
+static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
+static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
+static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
+static const WCHAR szURI[] = { 'U','R','I',0 };
+static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
+static const WCHAR szVary[] = { 'V','a','r','y',0 };
+static const WCHAR szVia[] = { 'V','i','a',0 };
+static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
+static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
#define MAXHOSTNAME 100
#define MAX_FIELD_VALUE_LEN 256
#define MAX_FIELD_LEN 256
-#define HTTP_REFERER g_szReferer
-#define HTTP_ACCEPT g_szAccept
-#define HTTP_USERAGENT g_szUserAgent
+#define HTTP_REFERER szReferer
+#define HTTP_ACCEPT szAccept
+#define HTTP_USERAGENT szUser_Agent
#define HTTP_ADDHDR_FLAG_ADD 0x20000000
#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
CtxtHandle ctx;
TimeStamp exp;
ULONG attr;
+ ULONG max_token;
void *auth_data;
unsigned int auth_data_len;
BOOL finished; /* finished authenticating */
};
-static void HTTP_CloseConnection(LPWININETHANDLEHEADER hdr);
-static void HTTP_CloseHTTPRequestHandle(LPWININETHANDLEHEADER hdr);
-static void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr);
-static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
-static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr);
-static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
+
+struct gzip_stream_t {
+#ifdef HAVE_ZLIB
+ z_stream zstream;
+#endif
+ BYTE buf[8192];
+ DWORD buf_size;
+ DWORD buf_pos;
+ BOOL end_of_data;
+};
+
+typedef struct _authorizationData
+{
+ struct list entry;
+
+ LPWSTR lpszwHost;
+ LPWSTR lpszwRealm;
+ LPSTR lpszAuthorization;
+ UINT AuthorizationLen;
+} authorizationData;
+
+static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
+
+static CRITICAL_SECTION authcache_cs;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+ 0, 0, &authcache_cs,
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
+};
+static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
+
+static DWORD HTTP_OpenConnection(http_request_t *req);
+static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
+static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
-static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr);
-static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, INT index, BOOL Request);
-static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index);
+static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
+static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
+static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
-static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD
- dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD
- lpdwIndex);
-static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl);
+static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
+static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
-static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field);
-
+static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
+static void HTTP_DrainContent(http_request_t *req);
+static BOOL HTTP_FinishedReading(http_request_t *req);
-LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
+static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
{
int HeaderIndex = 0;
HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
return &req->pCustHeaders[HeaderIndex];
}
+#ifdef HAVE_ZLIB
+
+static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, items*size);
+}
+
+static void wininet_zfree(voidpf opaque, voidpf address)
+{
+ HeapFree(GetProcessHeap(), 0, address);
+}
+
+static void init_gzip_stream(http_request_t *req)
+{
+ gzip_stream_t *gzip_stream;
+ int index, zres;
+
+ gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t));
+ gzip_stream->zstream.zalloc = wininet_zalloc;
+ gzip_stream->zstream.zfree = wininet_zfree;
+ gzip_stream->zstream.opaque = NULL;
+ gzip_stream->zstream.next_in = NULL;
+ gzip_stream->zstream.avail_in = 0;
+ gzip_stream->zstream.next_out = NULL;
+ gzip_stream->zstream.avail_out = 0;
+ gzip_stream->buf_pos = 0;
+ gzip_stream->buf_size = 0;
+ gzip_stream->end_of_data = FALSE;
+
+ zres = inflateInit2(&gzip_stream->zstream, 0x1f);
+ if(zres != Z_OK) {
+ ERR("inflateInit failed: %d\n", zres);
+ HeapFree(GetProcessHeap(), 0, gzip_stream);
+ return;
+ }
+
+ req->gzip_stream = gzip_stream;
+
+ index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
+ if(index != -1)
+ HTTP_DeleteCustomHeader(req, index);
+}
+
+#else
+
+static void init_gzip_stream(http_request_t *req)
+{
+ ERR("gzip stream not supported, missing zlib.\n");
+}
+
+#endif
+
+/* set the request content length based on the headers */
+static DWORD set_content_length( http_request_t *lpwhr )
+{
+ static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
+ WCHAR encoding[20];
+ DWORD size;
+
+ size = sizeof(lpwhr->dwContentLength);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+ &lpwhr->dwContentLength, &size, NULL) != ERROR_SUCCESS)
+ lpwhr->dwContentLength = ~0u;
+
+ size = sizeof(encoding);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS &&
+ !strcmpiW(encoding, szChunked))
+ {
+ lpwhr->dwContentLength = ~0u;
+ lpwhr->read_chunked = TRUE;
+ }
+
+ if(lpwhr->decoding) {
+ int encoding_idx;
+
+ static const WCHAR gzipW[] = {'g','z','i','p',0};
+
+ encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
+ if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
+ init_gzip_stream(lpwhr);
+ }
+
+ return lpwhr->dwContentLength;
+}
+
/***********************************************************************
* HTTP_Tokenize (internal)
*
int i;
LPCWSTR next_token;
- /* empty string has no tokens */
- if (*string)
- tokens++;
- /* count tokens */
- for (i = 0; string[i]; i++)
- if (!strncmpW(string+i, token_string, strlenW(token_string)))
- {
- DWORD j;
+ if (string)
+ {
+ /* empty string has no tokens */
+ if (*string)
tokens++;
- /* we want to skip over separators, but not the null terminator */
- for (j = 0; j < strlenW(token_string) - 1; j++)
- if (!string[i+j])
- break;
- i += j;
+ /* count tokens */
+ for (i = 0; string[i]; i++)
+ {
+ if (!strncmpW(string+i, token_string, strlenW(token_string)))
+ {
+ DWORD j;
+ tokens++;
+ /* we want to skip over separators, but not the null terminator */
+ for (j = 0; j < strlenW(token_string) - 1; j++)
+ if (!string[i+j])
+ break;
+ i += j;
+ }
}
+ }
/* add 1 for terminating NULL */
token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array));
HeapFree(GetProcessHeap(), 0, token_array);
}
-/* **********************************************************************
- *
- * Helper functions for the HttpSendRequest(Ex) functions
- *
- */
-static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
-{
- struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
- LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr;
-
- TRACE("%p\n", lpwhr);
-
- HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
- req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
- req->dwContentLength, req->bEndRequest);
-
- HeapFree(GetProcessHeap(), 0, req->lpszHeader);
-}
-
-static void HTTP_FixVerb( LPWININETHTTPREQW lpwhr )
-{
- /* if the verb is NULL default to GET */
- if (NULL == lpwhr->lpszVerb)
- {
- static const WCHAR szGET[] = { 'G','E','T', 0 };
- lpwhr->lpszVerb = WININET_strdupW(szGET);
- }
-}
-
-static void HTTP_FixURL( LPWININETHTTPREQW lpwhr)
+static void HTTP_FixURL(http_request_t *lpwhr)
{
static const WCHAR szSlash[] = { '/',0 };
static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
/* If we don't have a path we set it to root */
if (NULL == lpwhr->lpszPath)
- lpwhr->lpszPath = WININET_strdupW(szSlash);
+ lpwhr->lpszPath = heap_strdupW(szSlash);
else /* remove \r and \n*/
{
int nLen = strlenW(lpwhr->lpszPath);
}
}
-static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, BOOL http1_1 )
+static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
{
LPWSTR requestString;
DWORD len, n;
LPCWSTR *req;
- INT i;
+ UINT i;
LPWSTR p;
static const WCHAR szSpace[] = { ' ',0 };
- static const WCHAR szcrlf[] = {'\r','\n', 0};
static const WCHAR szColon[] = { ':',' ',0 };
static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
/* allocate space for an array of all the string pointers to be added */
- len = (lpwhr->nCustHeaders)*4 + 9;
+ len = (lpwhr->nCustHeaders)*4 + 10;
req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
/* add the verb, path and HTTP version string */
req[n++] = verb;
req[n++] = szSpace;
req[n++] = path;
- req[n++] = http1_1 ? g_szHttp1_1 : g_szHttp1_0;
+ req[n++] = szSpace;
+ req[n++] = version;
- /* Append custom request heades */
+ /* Append custom request headers */
for (i = 0; i < lpwhr->nCustHeaders; i++)
{
if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
{
- req[n++] = szcrlf;
+ req[n++] = szCrLf;
req[n++] = lpwhr->pCustHeaders[i].lpszField;
req[n++] = szColon;
req[n++] = lpwhr->pCustHeaders[i].lpszValue;
return requestString;
}
-static void HTTP_ProcessHeaders( LPWININETHTTPREQW lpwhr )
+static void HTTP_ProcessCookies( http_request_t *lpwhr )
{
- static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
int HeaderIndex;
+ int numCookies = 0;
LPHTTPHEADERW setCookieHeader;
- HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, 0, FALSE);
- if (HeaderIndex == -1)
- return;
- setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
-
- if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
+ while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
{
- int nPosStart = 0, nPosEnd = 0, len;
- static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0};
+ setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
- while (setCookieHeader->lpszValue[nPosEnd] != '\0')
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
{
- LPWSTR buf_cookie, cookie_name, cookie_data;
+ int len;
+ static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
LPWSTR buf_url;
- LPWSTR domain = NULL;
LPHTTPHEADERW Host;
- int nEqualPos = 0;
- while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
- setCookieHeader->lpszValue[nPosEnd] != '\0')
- {
- nPosEnd++;
- }
- if (setCookieHeader->lpszValue[nPosEnd] == ';')
- {
- /* fixme: not case sensitive, strcasestr is gnu only */
- int nDomainPosEnd = 0;
- int nDomainPosStart = 0, nDomainLength = 0;
- static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0};
- LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain);
- if (lpszDomain)
- { /* they have specified their own domain, lets use it */
- while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
- lpszDomain[nDomainPosEnd] != '\0')
- {
- nDomainPosEnd++;
- }
- nDomainPosStart = strlenW(szDomain);
- nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
- domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR));
- lstrcpynW(domain, &lpszDomain[nDomainPosStart], nDomainLength + 1);
- }
- }
- if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
- buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR));
- lstrcpynW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart) + 1);
- TRACE("%s\n", debugstr_w(buf_cookie));
- while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
- {
- nEqualPos++;
- }
- if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
- {
- HeapFree(GetProcessHeap(), 0, buf_cookie);
- break;
- }
-
- cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR));
- lstrcpynW(cookie_name, buf_cookie, nEqualPos + 1);
- cookie_data = &buf_cookie[nEqualPos + 1];
-
- Host = HTTP_GetHeader(lpwhr,szHost);
- len = lstrlenW((domain ? domain : (Host?Host->lpszValue:NULL))) +
- strlenW(lpwhr->lpszPath) + 9;
+ Host = HTTP_GetHeader(lpwhr, hostW);
+ len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath);
buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
- sprintfW(buf_url, szFmt, (domain ? domain : (Host?Host->lpszValue:NULL))); /* FIXME PATH!!! */
- InternetSetCookieW(buf_url, cookie_name, cookie_data);
+ sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath);
+ InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
HeapFree(GetProcessHeap(), 0, buf_url);
- HeapFree(GetProcessHeap(), 0, buf_cookie);
- HeapFree(GetProcessHeap(), 0, cookie_name);
- HeapFree(GetProcessHeap(), 0, domain);
- nPosStart = nPosEnd;
}
+ numCookies++;
+ }
+}
+
+static void strip_spaces(LPWSTR start)
+{
+ LPWSTR str = start;
+ LPWSTR end;
+
+ while (*str == ' ' && *str != '\0')
+ str++;
+
+ if (str != start)
+ memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
+
+ end = start + strlenW(start) - 1;
+ while (end >= start && *end == ' ')
+ {
+ *end = '\0';
+ end--;
}
}
-static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
+static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
{
static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
- return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
- ((pszAuthValue[ARRAYSIZE(szBasic)] != ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
+ static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */
+ BOOL is_basic;
+ is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
+ ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
+ if (is_basic && pszRealm)
+ {
+ LPCWSTR token;
+ LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)];
+ LPCWSTR realm;
+ ptr++;
+ *pszRealm=NULL;
+ token = strchrW(ptr,'=');
+ if (!token)
+ return TRUE;
+ realm = ptr;
+ while (*realm == ' ' && *realm != '\0')
+ realm++;
+ if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) &&
+ (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '='))
+ {
+ token++;
+ while (*token == ' ' && *token != '\0')
+ token++;
+ if (*token == '\0')
+ return TRUE;
+ *pszRealm = heap_strdupW(token);
+ strip_spaces(*pszRealm);
+ }
+ }
+
+ return is_basic;
+}
+
+static void destroy_authinfo( struct HttpAuthInfo *authinfo )
+{
+ if (!authinfo) return;
+
+ if (SecIsValidHandle(&authinfo->ctx))
+ DeleteSecurityContext(&authinfo->ctx);
+ if (SecIsValidHandle(&authinfo->cred))
+ FreeCredentialsHandle(&authinfo->cred);
+
+ HeapFree(GetProcessHeap(), 0, authinfo->auth_data);
+ HeapFree(GetProcessHeap(), 0, authinfo->scheme);
+ HeapFree(GetProcessHeap(), 0, authinfo);
+}
+
+static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data)
+{
+ authorizationData *ad;
+ UINT rc = 0;
+
+ TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm));
+
+ EnterCriticalSection(&authcache_cs);
+ LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, authorizationData, entry)
+ {
+ if (!strcmpiW(host,ad->lpszwHost) && !strcmpW(realm,ad->lpszwRealm))
+ {
+ TRACE("Authorization found in cache\n");
+ *auth_data = HeapAlloc(GetProcessHeap(),0,ad->AuthorizationLen);
+ memcpy(*auth_data,ad->lpszAuthorization,ad->AuthorizationLen);
+ rc = ad->AuthorizationLen;
+ break;
+ }
+ }
+ LeaveCriticalSection(&authcache_cs);
+ return rc;
+}
+
+static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len)
+{
+ struct list *cursor;
+ authorizationData* ad = NULL;
+
+ TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
+
+ EnterCriticalSection(&authcache_cs);
+ LIST_FOR_EACH(cursor, &basicAuthorizationCache)
+ {
+ authorizationData *check = LIST_ENTRY(cursor,authorizationData,entry);
+ if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm))
+ {
+ ad = check;
+ break;
+ }
+ }
+
+ if (ad)
+ {
+ TRACE("Found match in cache, replacing\n");
+ HeapFree(GetProcessHeap(),0,ad->lpszAuthorization);
+ ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len);
+ memcpy(ad->lpszAuthorization, auth_data, auth_data_len);
+ ad->AuthorizationLen = auth_data_len;
+ }
+ else
+ {
+ ad = HeapAlloc(GetProcessHeap(),0,sizeof(authorizationData));
+ ad->lpszwHost = heap_strdupW(host);
+ ad->lpszwRealm = heap_strdupW(realm);
+ ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len);
+ memcpy(ad->lpszAuthorization, auth_data, auth_data_len);
+ ad->AuthorizationLen = auth_data_len;
+ list_add_head(&basicAuthorizationCache,&ad->entry);
+ TRACE("authorization cached\n");
+ }
+ LeaveCriticalSection(&authcache_cs);
}
-static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue,
+static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
struct HttpAuthInfo **ppAuthInfo,
- LPWSTR domain_and_username, LPWSTR password )
+ LPWSTR domain_and_username, LPWSTR password,
+ LPWSTR host )
{
SECURITY_STATUS sec_status;
struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
BOOL first = FALSE;
+ LPWSTR szRealm = NULL;
TRACE("%s\n", debugstr_w(pszAuthValue));
- if (!domain_and_username) return FALSE;
-
if (!pAuthInfo)
{
TimeStamp exp;
pAuthInfo->auth_data_len = 0;
pAuthInfo->finished = FALSE;
- if (is_basic_auth_value(pszAuthValue))
+ if (is_basic_auth_value(pszAuthValue,NULL))
{
static const WCHAR szBasic[] = {'B','a','s','i','c',0};
- pAuthInfo->scheme = WININET_strdupW(szBasic);
+ pAuthInfo->scheme = heap_strdupW(szBasic);
if (!pAuthInfo->scheme)
{
HeapFree(GetProcessHeap(), 0, pAuthInfo);
}
else
{
+ PVOID pAuthData;
SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
- WCHAR *user = strchrW(domain_and_username, '\\');
- WCHAR *domain = domain_and_username;
- pAuthInfo->scheme = WININET_strdupW(pszAuthValue);
+ pAuthInfo->scheme = heap_strdupW(pszAuthValue);
if (!pAuthInfo->scheme)
{
HeapFree(GetProcessHeap(), 0, pAuthInfo);
return FALSE;
}
- if (user) user++;
- else
+ if (domain_and_username)
{
- user = domain_and_username;
- domain = NULL;
- }
- nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
- nt_auth_identity.User = user;
- nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
- nt_auth_identity.Domain = domain;
- nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
- nt_auth_identity.Password = password;
- nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
+ WCHAR *user = strchrW(domain_and_username, '\\');
+ WCHAR *domain = domain_and_username;
+
+ /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
+
+ pAuthData = &nt_auth_identity;
+
+ if (user) user++;
+ else
+ {
+ user = domain_and_username;
+ domain = NULL;
+ }
- /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
+ nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+ nt_auth_identity.User = user;
+ nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
+ nt_auth_identity.Domain = domain;
+ nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
+ nt_auth_identity.Password = password;
+ nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
+ }
+ else
+ /* use default credentials */
+ pAuthData = NULL;
sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
SECPKG_CRED_OUTBOUND, NULL,
- &nt_auth_identity, NULL,
+ pAuthData, NULL,
NULL, &pAuthInfo->cred,
&exp);
+ if (sec_status == SEC_E_OK)
+ {
+ PSecPkgInfoW sec_pkg_info;
+ sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
+ if (sec_status == SEC_E_OK)
+ {
+ pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
+ FreeContextBuffer(sec_pkg_info);
+ }
+ }
if (sec_status != SEC_E_OK)
{
WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
return FALSE;
}
- if (is_basic_auth_value(pszAuthValue))
+ if (is_basic_auth_value(pszAuthValue,&szRealm))
{
- int userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
- int passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
- char *auth_data;
+ int userlen;
+ int passlen;
+ char *auth_data = NULL;
+ UINT auth_data_len = 0;
- TRACE("basic authentication\n");
+ TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
- /* length includes a nul terminator, which will be re-used for the ':' */
- auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
- if (!auth_data)
- return FALSE;
+ if (!domain_and_username)
+ {
+ if (host && szRealm)
+ auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data);
+ if (auth_data_len == 0)
+ {
+ HeapFree(GetProcessHeap(),0,szRealm);
+ return FALSE;
+ }
+ }
+ else
+ {
+ userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
+ passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
+
+ /* length includes a nul terminator, which will be re-used for the ':' */
+ auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
+ if (!auth_data)
+ {
+ HeapFree(GetProcessHeap(),0,szRealm);
+ return FALSE;
+ }
- WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
- auth_data[userlen] = ':';
- WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
+ auth_data[userlen] = ':';
+ WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
+ auth_data_len = userlen + 1 + passlen;
+ if (host && szRealm)
+ cache_basic_authorization(host, szRealm, auth_data, auth_data_len);
+ }
pAuthInfo->auth_data = auth_data;
- pAuthInfo->auth_data_len = userlen + 1 + passlen;
+ pAuthInfo->auth_data_len = auth_data_len;
pAuthInfo->finished = TRUE;
+ HeapFree(GetProcessHeap(),0,szRealm);
return TRUE;
}
HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
}
- buffer = HeapAlloc(GetProcessHeap(), 0, 0x100);
+ buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
out.BufferType = SECBUFFER_TOKEN;
- out.cbBuffer = 0x100;
+ out.cbBuffer = pAuthInfo->max_token;
out.pvBuffer = buffer;
out_desc.ulVersion = 0;
out_desc.pBuffers = &out;
sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
- first ? NULL : &pAuthInfo->ctx, NULL,
+ first ? NULL : &pAuthInfo->ctx,
+ first ? lpwhr->lpHttpSession->lpszServerName : NULL,
context_req, 0, SECURITY_NETWORK_DREP,
in.pvBuffer ? &in_desc : NULL,
0, &pAuthInfo->ctx, &out_desc,
{
ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
HeapFree(GetProcessHeap(), 0, out.pvBuffer);
+ destroy_authinfo(pAuthInfo);
+ *ppAuthInfo = NULL;
return FALSE;
}
}
/***********************************************************************
* HTTP_HttpAddRequestHeadersW (internal)
*/
-static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr,
+static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
{
LPWSTR lpszStart;
LPWSTR lpszEnd;
LPWSTR buffer;
- BOOL bSuccess = FALSE;
- DWORD len;
+ DWORD len, res = ERROR_HTTP_INVALID_HEADER;
- TRACE("copying header: %s\n", debugstr_w(lpszHeader));
+ TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
if( dwHeaderLength == ~0U )
len = strlenW(lpszHeader);
while (*lpszEnd != '\0')
{
- if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
+ if (*lpszEnd == '\r' || *lpszEnd == '\n')
break;
lpszEnd++;
}
if (*lpszStart == '\0')
break;
- if (*lpszEnd == '\r')
+ if (*lpszEnd == '\r' || *lpszEnd == '\n')
{
*lpszEnd = '\0';
- lpszEnd += 2; /* Jump over \r\n */
+ lpszEnd++; /* Jump over newline */
}
TRACE("interpreting header %s\n", debugstr_w(lpszStart));
+ if (*lpszStart == '\0')
+ {
+ /* Skip 0-length headers */
+ lpszStart = lpszEnd;
+ res = ERROR_SUCCESS;
+ continue;
+ }
pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
if (pFieldAndValue)
{
- bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
- if (bSuccess)
- bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
+ res = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
+ if (res == ERROR_SUCCESS)
+ res = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
HTTP_FreeTokens(pFieldAndValue);
}
lpszStart = lpszEnd;
- } while (bSuccess);
+ } while (res == ERROR_SUCCESS);
HeapFree(GetProcessHeap(), 0, buffer);
- return bSuccess;
+ return res;
}
/***********************************************************************
*
* Adds one or more HTTP header to the request handler
*
+ * NOTE
+ * On Windows if dwHeaderLength includes the trailing '\0', then
+ * HttpAddRequestHeadersW() adds it too. However this results in an
+ * invalid Http header which is rejected by some servers so we probably
+ * don't need to match Windows on that point.
+ *
* RETURNS
* TRUE on success
* FALSE on failure
BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
{
- BOOL bSuccess = FALSE;
- LPWININETHTTPREQW lpwhr;
+ http_request_t *lpwhr;
+ DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
- TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_w(lpszHeader), dwHeaderLength,
- dwModifier);
+ TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
if (!lpszHeader)
return TRUE;
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
- }
- bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
-lend:
+ lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
+ if (lpwhr && lpwhr->hdr.htype == WH_HHTTPREQ)
+ res = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
if( lpwhr )
WININET_Release( &lpwhr->hdr );
- return bSuccess;
+ if(res != ERROR_SUCCESS)
+ SetLastError(res);
+ return res == ERROR_SUCCESS;
}
/***********************************************************************
LPWSTR hdr;
BOOL r;
- TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_a(lpszHeader), dwHeaderLength,
- dwModifier);
+ TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
return r;
}
-/* read any content returned by the server so that the connection can be
- * resued */
-static void HTTP_DrainContent(LPWININETHTTPREQW lpwhr)
-{
- DWORD bytes_read;
-
- if (!NETCON_connected(&lpwhr->netConnection)) return;
-
- if (lpwhr->dwContentLength == -1)
- NETCON_close(&lpwhr->netConnection);
-
- do
- {
- char buffer[2048];
- if (!INTERNET_ReadFile(&lpwhr->hdr, buffer, sizeof(buffer), &bytes_read,
- TRUE, FALSE))
- return;
- } while (bytes_read);
-}
-
/***********************************************************************
- * HttpEndRequestA (WININET.@)
- *
- * Ends an HTTP request that was started by HttpSendRequestEx
- *
- * RETURNS
- * TRUE if successful
- * FALSE on failure
- *
- */
-BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
- LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
-{
- LPINTERNET_BUFFERSA ptr;
- LPINTERNET_BUFFERSW lpBuffersOutW,ptrW;
- BOOL rc = FALSE;
-
- TRACE("(%p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersOut, dwFlags,
- dwContext);
-
- ptr = lpBuffersOut;
- if (ptr)
- lpBuffersOutW = (LPINTERNET_BUFFERSW)HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY, sizeof(INTERNET_BUFFERSW));
- else
- lpBuffersOutW = NULL;
-
- ptrW = lpBuffersOutW;
- while (ptr)
- {
- if (ptr->lpvBuffer && ptr->dwBufferLength)
- ptrW->lpvBuffer = HeapAlloc(GetProcessHeap(),0,ptr->dwBufferLength);
- ptrW->dwBufferLength = ptr->dwBufferLength;
- ptrW->dwBufferTotal= ptr->dwBufferTotal;
-
- if (ptr->Next)
- ptrW->Next = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
- sizeof(INTERNET_BUFFERSW));
-
- ptr = ptr->Next;
- ptrW = ptrW->Next;
- }
-
- rc = HttpEndRequestW(hRequest, lpBuffersOutW, dwFlags, dwContext);
-
- if (lpBuffersOutW)
- {
- ptrW = lpBuffersOutW;
- while (ptrW)
- {
- LPINTERNET_BUFFERSW ptrW2;
-
- FIXME("Do we need to translate info out of these buffer?\n");
-
- HeapFree(GetProcessHeap(),0,(LPVOID)ptrW->lpvBuffer);
- ptrW2 = ptrW->Next;
- HeapFree(GetProcessHeap(),0,ptrW);
- ptrW = ptrW2;
- }
- }
-
- return rc;
-}
-
-/***********************************************************************
- * HttpEndRequestW (WININET.@)
- *
- * Ends an HTTP request that was started by HttpSendRequestEx
- *
- * RETURNS
- * TRUE if successful
- * FALSE on failure
- *
- */
-BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
- LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
-{
- BOOL rc = FALSE;
- LPWININETHTTPREQW lpwhr;
- INT responseLen;
- DWORD dwBufferSize;
-
- TRACE("-->\n");
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
-
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- if (lpwhr)
- WININET_Release( &lpwhr->hdr );
- return FALSE;
- }
-
- lpwhr->hdr.dwFlags |= dwFlags;
- lpwhr->hdr.dwContext = dwContext;
-
- /* We appear to do nothing with lpBuffersOut.. is that correct? */
-
- SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
- responseLen = HTTP_GetResponseHeaders(lpwhr);
- if (responseLen)
- rc = TRUE;
-
- SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
-
- /* process headers here. Is this right? */
- HTTP_ProcessHeaders(lpwhr);
-
- dwBufferSize = sizeof(lpwhr->dwContentLength);
- if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
- &lpwhr->dwContentLength,&dwBufferSize,NULL))
- lpwhr->dwContentLength = -1;
-
- if (lpwhr->dwContentLength == 0)
- HTTP_FinishedReading(lpwhr);
-
- if(!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
- {
- DWORD dwCode,dwCodeLength=sizeof(DWORD);
- if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) &&
- (dwCode==302 || dwCode==301))
- {
- WCHAR szNewLocation[2048];
- dwBufferSize=sizeof(szNewLocation);
- if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL))
- {
- static const WCHAR szGET[] = { 'G','E','T', 0 };
- /* redirects are always GETs */
- HeapFree(GetProcessHeap(),0,lpwhr->lpszVerb);
- lpwhr->lpszVerb = WININET_strdupW(szGET);
- HTTP_DrainContent(lpwhr);
- rc = HTTP_HandleRedirect(lpwhr, szNewLocation);
- if (rc)
- rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
- }
- }
- }
-
- WININET_Release( &lpwhr->hdr );
- TRACE("%i <--\n",rc);
- return rc;
-}
-
-/***********************************************************************
- * HttpOpenRequestW (WININET.@)
- *
- * Open a HTTP request handle
- *
- * RETURNS
- * HINTERNET a HTTP request handle on success
- * NULL on failure
- *
- */
-HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
- LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
- LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
- DWORD dwFlags, DWORD_PTR dwContext)
-{
- LPWININETHTTPSESSIONW lpwhs;
- HINTERNET handle = NULL;
-
- TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
- debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
- debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
- dwFlags, dwContext);
- if(lpszAcceptTypes!=NULL)
- {
- int i;
- for(i=0;lpszAcceptTypes[i]!=NULL;i++)
- TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
- }
-
- lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
- if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
- }
-
- /*
- * My tests seem to show that the windows version does not
- * become asynchronous until after this point. And anyhow
- * if this call was asynchronous then how would you get the
- * necessary HINTERNET pointer returned by this function.
- *
- */
- handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
- lpszVersion, lpszReferrer, lpszAcceptTypes,
- dwFlags, dwContext);
-lend:
- if( lpwhs )
- WININET_Release( &lpwhs->hdr );
- TRACE("returning %p\n", handle);
- return handle;
-}
-
-
-/***********************************************************************
- * HttpOpenRequestA (WININET.@)
+ * HttpOpenRequestA (WININET.@)
*
* Open a HTTP request handle
*
{
LPWSTR szVerb = NULL, szObjectName = NULL;
LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
- INT len;
INT acceptTypesCount;
HINTERNET rc = FALSE;
+ LPCSTR *types;
+
TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
if (lpszVerb)
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 );
- szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ szVerb = heap_strdupAtoW(lpszVerb);
if ( !szVerb )
goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len);
}
if (lpszObjectName)
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 );
- szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ szObjectName = heap_strdupAtoW(lpszObjectName);
if ( !szObjectName )
goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len );
}
if (lpszVersion)
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 );
- szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ szVersion = heap_strdupAtoW(lpszVersion);
if ( !szVersion )
goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len );
}
if (lpszReferrer)
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 );
- szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ szReferrer = heap_strdupAtoW(lpszReferrer);
if ( !szReferrer )
goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len );
}
- acceptTypesCount = 0;
if (lpszAcceptTypes)
{
- /* find out how many there are */
- while (lpszAcceptTypes[acceptTypesCount] && *lpszAcceptTypes[acceptTypesCount])
- acceptTypesCount++;
+ acceptTypesCount = 0;
+ types = lpszAcceptTypes;
+ while (*types)
+ {
+ __TRY
+ {
+ /* find out how many there are */
+ if (*types && **types)
+ {
+ TRACE("accept type: %s\n", debugstr_a(*types));
+ acceptTypesCount++;
+ }
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ WARN("invalid accept type pointer\n");
+ }
+ __ENDTRY;
+ types++;
+ }
szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
+ if (!szAcceptTypes) goto end;
+
acceptTypesCount = 0;
- while (lpszAcceptTypes[acceptTypesCount] && *lpszAcceptTypes[acceptTypesCount])
- {
- len = MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
- -1, NULL, 0 );
- szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- if (!szAcceptTypes[acceptTypesCount] )
- goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszAcceptTypes[acceptTypesCount],
- -1, szAcceptTypes[acceptTypesCount], len );
- acceptTypesCount++;
+ types = lpszAcceptTypes;
+ while (*types)
+ {
+ __TRY
+ {
+ if (*types && **types)
+ szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ /* ignore invalid pointer */
+ }
+ __ENDTRY;
+ types++;
}
szAcceptTypes[acceptTypesCount] = NULL;
}
- else szAcceptTypes = 0;
rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
szVersion, szReferrer,
{
signed char in[4];
- if (base64[0] > ARRAYSIZE(HTTP_Base64Dec) ||
+ if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) ||
((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
- base64[1] > ARRAYSIZE(HTTP_Base64Dec) ||
+ base64[1] >= ARRAYSIZE(HTTP_Base64Dec) ||
((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
{
WARN("invalid base64: %s\n", debugstr_w(base64));
}
/***********************************************************************
- * HTTP_InsertAuthorizationForHeader
+ * HTTP_InsertAuthorization
*
* Insert or delete the authorization field in the request header.
*/
-static BOOL HTTP_InsertAuthorizationForHeader( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
+static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
{
- WCHAR *authorization = NULL;
-
- if (pAuthInfo && pAuthInfo->auth_data_len)
+ if (pAuthInfo)
{
static const WCHAR wszSpace[] = {' ',0};
static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
unsigned int len;
+ WCHAR *authorization = NULL;
- /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
- len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
- authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
- if (!authorization)
- return FALSE;
+ if (pAuthInfo->auth_data_len)
+ {
+ /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
+ len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
+ authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
+ if (!authorization)
+ return FALSE;
- strcpyW(authorization, pAuthInfo->scheme);
- strcatW(authorization, wszSpace);
- HTTP_EncodeBase64(pAuthInfo->auth_data,
- pAuthInfo->auth_data_len,
- authorization+strlenW(authorization));
+ strcpyW(authorization, pAuthInfo->scheme);
+ strcatW(authorization, wszSpace);
+ HTTP_EncodeBase64(pAuthInfo->auth_data,
+ pAuthInfo->auth_data_len,
+ authorization+strlenW(authorization));
- /* clear the data as it isn't valid now that it has been sent to the
- * server, unless it's Basic authentication which doesn't do
- * connection tracking */
- if (strcmpiW(pAuthInfo->scheme, wszBasic))
- {
- HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
- pAuthInfo->auth_data = NULL;
- pAuthInfo->auth_data_len = 0;
+ /* clear the data as it isn't valid now that it has been sent to the
+ * server, unless it's Basic authentication which doesn't do
+ * connection tracking */
+ if (strcmpiW(pAuthInfo->scheme, wszBasic))
+ {
+ HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
+ pAuthInfo->auth_data = NULL;
+ pAuthInfo->auth_data_len = 0;
+ }
}
- }
- TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
+ TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
- HTTP_ProcessHeader(lpwhr, header, authorization,
- HTTP_ADDHDR_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
-
- HeapFree(GetProcessHeap(), 0, authorization);
+ HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+ HeapFree(GetProcessHeap(), 0, authorization);
+ }
return TRUE;
}
-/***********************************************************************
- * HTTP_InsertAuthorization
- *
- * Insert the authorization field in the request header
- */
-static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr )
+static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
{
- return HTTP_InsertAuthorizationForHeader(lpwhr, lpwhr->pAuthInfo, szAuthorization);
-}
+ WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
+ DWORD size;
-/***********************************************************************
- * HTTP_InsertProxyAuthorization
- *
- * Insert the proxy authorization field in the request header
- */
-static BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr )
-{
- return HTTP_InsertAuthorizationForHeader(lpwhr, lpwhr->pProxyAuthInfo, szProxy_Authorization);
+ size = sizeof(new_location);
+ if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS)
+ {
+ if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
+ strcpyW( url, new_location );
+ }
+ else
+ {
+ static const WCHAR slash[] = { '/',0 };
+ static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
+ static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 };
+ http_session_t *session = req->lpHttpSession;
+
+ size = 16; /* "https://" + sizeof(port#) + ":/\0" */
+ size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
+
+ if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
+
+ if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
+ sprintfW( url, formatSSL, session->lpszHostName, session->nHostPort );
+ else
+ sprintfW( url, format, session->lpszHostName, session->nHostPort );
+ if (req->lpszPath[0] != '/') strcatW( url, slash );
+ strcatW( url, req->lpszPath );
+ }
+ TRACE("url=%s\n", debugstr_w(url));
+ return url;
}
/***********************************************************************
* HTTP_DealWithProxy
*/
-static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
- LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
+static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr)
{
WCHAR buf[MAXHOSTNAME];
+ WCHAR protoProxy[MAXHOSTNAME + 15];
+ DWORD protoProxyLen = sizeof(protoProxy) / sizeof(protoProxy[0]);
WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
- WCHAR* url;
static WCHAR szNul[] = { 0 };
URL_COMPONENTSW UrlComponents;
- static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 }, szSlash[] = { '/',0 } ;
- static const WCHAR szFormat1[] = { 'h','t','t','p',':','/','/','%','s',0 };
- static const WCHAR szFormat2[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
- int len;
+ static const WCHAR protoHttp[] = { 'h','t','t','p',0 };
+ static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
+ static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
memset( &UrlComponents, 0, sizeof UrlComponents );
UrlComponents.dwStructSize = sizeof UrlComponents;
UrlComponents.lpszHostName = buf;
UrlComponents.dwHostNameLength = MAXHOSTNAME;
+ if (!INTERNET_FindProxyForProtocol(hIC->lpszProxy, protoHttp, protoProxy, &protoProxyLen))
+ return FALSE;
if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
- hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
- sprintfW(proxy, szFormat1, hIC->lpszProxy);
+ protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
+ sprintfW(proxy, szFormat, protoProxy);
else
- strcpyW(proxy, hIC->lpszProxy);
+ strcpyW(proxy, protoProxy);
if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
return FALSE;
if( UrlComponents.dwHostNameLength == 0 )
if( !lpwhr->lpszPath )
lpwhr->lpszPath = szNul;
- TRACE("server=%s path=%s\n",
- debugstr_w(lpwhs->lpszHostName), debugstr_w(lpwhr->lpszPath));
- /* for constant 15 see above */
- len = strlenW(lpwhs->lpszHostName) + strlenW(lpwhr->lpszPath) + 15;
- url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
- sprintfW(url, szFormat2, lpwhs->lpszHostName, lpwhs->nHostPort);
-
- if( lpwhr->lpszPath[0] != '/' )
- strcatW( url, szSlash );
- strcatW(url, lpwhr->lpszPath);
- if(lpwhr->lpszPath != szNul)
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
- lpwhr->lpszPath = url;
-
HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
- lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
+ lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName);
lpwhs->nServerPort = UrlComponents.nPort;
+ TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
return TRUE;
}
-static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr)
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+static DWORD HTTP_ResolveName(http_request_t *lpwhr)
{
- char szaddr[32];
- LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
+ char szaddr[INET6_ADDRSTRLEN];
+ http_session_t *lpwhs = lpwhr->lpHttpSession;
+ const void *addr;
INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
INTERNET_STATUS_RESOLVING_NAME,
lpwhs->lpszServerName,
- strlenW(lpwhs->lpszServerName)+1);
+ (strlenW(lpwhs->lpszServerName)+1) * sizeof(WCHAR));
+ lpwhs->sa_len = sizeof(lpwhs->socketAddress);
if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
- &lpwhs->socketAddress))
+ (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len))
+ return ERROR_INTERNET_NAME_NOT_RESOLVED;
+
+ switch (lpwhs->socketAddress.ss_family)
{
- INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
- return FALSE;
+ case AF_INET:
+ addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
+ break;
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
+ break;
+ default:
+ WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
+ return ERROR_INTERNET_NAME_NOT_RESOLVED;
}
-
- inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr,
- szaddr, sizeof(szaddr));
+ inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
INTERNET_STATUS_NAME_RESOLVED,
szaddr, strlen(szaddr)+1);
- return TRUE;
+
+ TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
+ return ERROR_SUCCESS;
}
+
/***********************************************************************
- * HTTP_HttpOpenRequestW (internal)
- *
- * Open a HTTP request handle
+ * HTTPREQ_Destroy (internal)
*
- * RETURNS
- * HINTERNET a HTTP request handle on success
- * NULL on failure
+ * Deallocate request handle
*
*/
-HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
- LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
- LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
- DWORD dwFlags, DWORD_PTR dwContext)
+static void HTTPREQ_Destroy(object_header_t *hdr)
{
- LPWININETAPPINFOW hIC = NULL;
- LPWININETHTTPREQW lpwhr;
- LPWSTR lpszCookies;
- LPWSTR lpszUrl = NULL;
- DWORD nCookieSize;
- HINTERNET handle = NULL;
- static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0};
- DWORD len;
- LPHTTPHEADERW Host;
+ http_request_t *lpwhr = (http_request_t*) hdr;
+ DWORD i;
- TRACE("-->\n");
+ TRACE("\n");
- assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
- hIC = lpwhs->lpAppInfo;
+ if(lpwhr->hCacheFile)
+ CloseHandle(lpwhr->hCacheFile);
- lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
- if (NULL == lpwhr)
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lend;
- }
- lpwhr->hdr.htype = WH_HHTTPREQ;
- lpwhr->hdr.dwFlags = dwFlags;
- lpwhr->hdr.dwContext = dwContext;
- lpwhr->hdr.dwRefCount = 1;
- lpwhr->hdr.close_connection = HTTP_CloseConnection;
- lpwhr->hdr.destroy = HTTP_CloseHTTPRequestHandle;
- lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB;
- lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW;
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
- WININET_AddRef( &lpwhs->hdr );
- lpwhr->lpHttpSession = lpwhs;
- list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
+ DeleteCriticalSection( &lpwhr->read_section );
+ WININET_Release(&lpwhr->lpHttpSession->hdr);
- handle = WININET_AllocHandle( &lpwhr->hdr );
- if (NULL == handle)
+ destroy_authinfo(lpwhr->pAuthInfo);
+ destroy_authinfo(lpwhr->pProxyAuthInfo);
+
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
+
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
{
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lend;
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
}
- if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
- {
- InternetCloseHandle( handle );
- handle = NULL;
- goto lend;
+#ifdef HAVE_ZLIB
+ if(lpwhr->gzip_stream) {
+ if(!lpwhr->gzip_stream->end_of_data)
+ inflateEnd(&lpwhr->gzip_stream->zstream);
+ HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream);
}
+#endif
- if (NULL != lpszObjectName && strlenW(lpszObjectName)) {
- HRESULT rc;
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
+ HeapFree(GetProcessHeap(), 0, lpwhr);
+}
- len = 0;
- rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
- if (rc != E_POINTER)
- len = strlenW(lpszObjectName)+1;
- lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
- rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
- URL_ESCAPE_SPACES_ONLY);
- if (rc)
- {
- ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
- strcpyW(lpwhr->lpszPath,lpszObjectName);
- }
- }
+static void HTTPREQ_CloseConnection(object_header_t *hdr)
+{
+ http_request_t *lpwhr = (http_request_t*) hdr;
- if (NULL != lpszReferrer && strlenW(lpszReferrer))
- HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
+ TRACE("%p\n",lpwhr);
- if (lpszAcceptTypes)
+ if (!NETCON_connected(&lpwhr->netConnection))
+ return;
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
+
+ NETCON_close(&lpwhr->netConnection);
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
+}
+
+static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
+{
+ LPHTTPHEADERW host_header;
+
+ static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
+
+ host_header = HTTP_GetHeader(req, hostW);
+ if(!host_header)
+ return FALSE;
+
+ sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
+ return TRUE;
+}
+
+static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
+{
+ WCHAR szVersion[10];
+ WCHAR szConnectionResponse[20];
+ DWORD dwBufferSize = sizeof(szVersion);
+ BOOL keepalive = FALSE;
+
+ /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
+ * the connection is keep-alive by default */
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS
+ && !strcmpiW(szVersion, g_szHttp1_1))
{
- int i;
- for (i = 0; lpszAcceptTypes[i]; i++)
- {
- if (!*lpszAcceptTypes[i]) continue;
- HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
- HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
- HTTP_ADDHDR_FLAG_REQ |
- (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
- }
+ keepalive = TRUE;
}
- if (NULL == lpszVerb)
+ dwBufferSize = sizeof(szConnectionResponse);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS
+ || HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS)
{
- static const WCHAR szGet[] = {'G','E','T',0};
- lpwhr->lpszVerb = WININET_strdupW(szGet);
+ keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
}
- else if (strlenW(lpszVerb))
- lpwhr->lpszVerb = WININET_strdupW(lpszVerb);
- if (NULL != lpszReferrer && strlenW(lpszReferrer))
- {
- WCHAR buf[MAXHOSTNAME];
- URL_COMPONENTSW UrlComponents;
+ return keepalive;
+}
- memset( &UrlComponents, 0, sizeof UrlComponents );
- UrlComponents.dwStructSize = sizeof UrlComponents;
- UrlComponents.lpszHostName = buf;
- UrlComponents.dwHostNameLength = MAXHOSTNAME;
+static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+{
+ http_request_t *req = (http_request_t*)hdr;
- InternetCrackUrlW(lpszReferrer, 0, 0, &UrlComponents);
- if (strlenW(UrlComponents.lpszHostName))
- HTTP_ProcessHeader(lpwhr, szHost, UrlComponents.lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
- }
- else
- HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
+ switch(option) {
+ case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
+ {
+ http_session_t *lpwhs = req->lpHttpSession;
+ INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
- if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
- lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
- INTERNET_DEFAULT_HTTPS_PORT :
- INTERNET_DEFAULT_HTTP_PORT);
- lpwhs->nHostPort = lpwhs->nServerPort;
+ FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
- if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
- HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
+ if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
+ return ERROR_INSUFFICIENT_BUFFER;
+ *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
+ /* FIXME: can't get a SOCKET from our connection since we don't use
+ * winsock
+ */
+ info->Socket = 0;
+ /* FIXME: get source port from req->netConnection */
+ info->SourcePort = 0;
+ info->DestPort = lpwhs->nHostPort;
+ info->Flags = 0;
+ if (HTTP_KeepAlive(req))
+ info->Flags |= IDSI_FLAG_KEEP_ALIVE;
+ if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0)
+ info->Flags |= IDSI_FLAG_PROXY;
+ if (req->netConnection.useSSL)
+ info->Flags |= IDSI_FLAG_SECURE;
+
+ return ERROR_SUCCESS;
+ }
- if (hIC->lpszAgent)
+ case INTERNET_OPTION_SECURITY_FLAGS:
{
- WCHAR *agent_header;
- static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0 };
+ http_session_t *lpwhs;
+ lpwhs = req->lpHttpSession;
- len = strlenW(hIC->lpszAgent) + strlenW(user_agent);
- agent_header = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
- sprintfW(agent_header, user_agent, hIC->lpszAgent );
+ if (*size < sizeof(ULONG))
+ return ERROR_INSUFFICIENT_BUFFER;
- HTTP_HttpAddRequestHeadersW(lpwhr, agent_header, strlenW(agent_header),
- HTTP_ADDREQ_FLAG_ADD);
- HeapFree(GetProcessHeap(), 0, agent_header);
+ *size = sizeof(DWORD);
+ if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE)
+ *(DWORD*)buffer = SECURITY_FLAG_SECURE;
+ else
+ *(DWORD*)buffer = 0;
+ FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer);
+ return ERROR_SUCCESS;
}
- Host = HTTP_GetHeader(lpwhr,szHost);
+ case INTERNET_OPTION_HANDLE_TYPE:
+ TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
- len = lstrlenW(Host->lpszValue) + strlenW(szUrlForm);
- lpszUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
- sprintfW( lpszUrl, szUrlForm, Host->lpszValue );
+ if (*size < sizeof(ULONG))
+ return ERROR_INSUFFICIENT_BUFFER;
- if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) &&
- InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
- {
- int cnt = 0;
- static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
- static const WCHAR szcrlf[] = {'\r','\n',0};
+ *size = sizeof(DWORD);
+ *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
+ return ERROR_SUCCESS;
- lpszCookies = HeapAlloc(GetProcessHeap(), 0, (nCookieSize + 1 + 8)*sizeof(WCHAR));
+ case INTERNET_OPTION_URL: {
+ WCHAR url[INTERNET_MAX_URL_LENGTH];
+ HTTPHEADERW *host;
+ DWORD len;
+ WCHAR *pch;
- cnt += sprintfW(lpszCookies, szCookie);
- InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
- strcatW(lpszCookies, szcrlf);
+ static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
- HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies),
- HTTP_ADDREQ_FLAG_ADD);
- HeapFree(GetProcessHeap(), 0, lpszCookies);
- }
- HeapFree(GetProcessHeap(), 0, lpszUrl);
+ TRACE("INTERNET_OPTION_URL\n");
+ host = HTTP_GetHeader(req, hostW);
+ strcpyW(url, httpW);
+ strcatW(url, host->lpszValue);
+ if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
+ *pch = 0;
+ strcatW(url, req->lpszPath);
- INTERNET_SendCallback(&lpwhs->hdr, dwContext,
- INTERNET_STATUS_HANDLE_CREATED, &handle,
- sizeof(handle));
+ TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
- /*
- * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
- */
+ if(unicode) {
+ len = (strlenW(url)+1) * sizeof(WCHAR);
+ if(*size < len)
+ return ERROR_INSUFFICIENT_BUFFER;
- if (!HTTP_ResolveName(lpwhr))
- {
- InternetCloseHandle( handle );
- handle = NULL;
+ *size = len;
+ strcpyW(buffer, url);
+ return ERROR_SUCCESS;
+ }else {
+ len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
+ if(len > *size)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ *size = len;
+ return ERROR_SUCCESS;
+ }
}
-lend:
- if( lpwhr )
- WININET_Release( &lpwhr->hdr );
+ case INTERNET_OPTION_CACHE_TIMESTAMPS: {
+ INTERNET_CACHE_ENTRY_INFOW *info;
+ INTERNET_CACHE_TIMESTAMPS *ts = buffer;
+ WCHAR url[INTERNET_MAX_URL_LENGTH];
+ DWORD nbytes, error;
+ BOOL ret;
- TRACE("<-- %p (%p)\n", handle, lpwhr);
- return handle;
-}
+ TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
-static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
-static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
-static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
-static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
-static const WCHAR szAge[] = { 'A','g','e',0 };
-static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
-static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
-static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
-static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
-static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
-static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
-static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
-static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
-static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
-static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
-static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
-static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
-static const WCHAR szDate[] = { 'D','a','t','e',0 };
-static const WCHAR szFrom[] = { 'F','r','o','m',0 };
-static const WCHAR szETag[] = { 'E','T','a','g',0 };
-static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
-static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
-static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
-static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
-static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
-static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
-static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
-static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
-static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
-static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
-static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
-static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
-static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
-static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
-static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
-static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
-static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
-static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
-static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
-static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
-static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
-static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
-static const WCHAR szURI[] = { 'U','R','I',0 };
-static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
-static const WCHAR szVary[] = { 'V','a','r','y',0 };
-static const WCHAR szVia[] = { 'V','i','a',0 };
-static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
-static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
+ if (*size < sizeof(*ts))
+ {
+ *size = sizeof(*ts);
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+ nbytes = 0;
+ HTTP_GetRequestURL(req, url);
+ ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
+ error = GetLastError();
+ if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
+ {
+ if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes)))
+ return ERROR_OUTOFMEMORY;
-static const LPCWSTR header_lookup[] = {
- szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */
- szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */
- szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
- szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */
- NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
- szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
- szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
- szAllow, /* HTTP_QUERY_ALLOW = 7 */
- szPublic, /* HTTP_QUERY_PUBLIC = 8 */
- szDate, /* HTTP_QUERY_DATE = 9 */
- szExpires, /* HTTP_QUERY_EXPIRES = 10 */
- szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */
- NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
- szURI, /* HTTP_QUERY_URI = 13 */
- szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */
- NULL, /* HTTP_QUERY_COST = 15 */
- NULL, /* HTTP_QUERY_LINK = 16 */
- szPragma, /* HTTP_QUERY_PRAGMA = 17 */
- NULL, /* HTTP_QUERY_VERSION = 18 */
- szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */
- NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
- NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
- NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
- szConnection, /* HTTP_QUERY_CONNECTION = 23 */
- szAccept, /* HTTP_QUERY_ACCEPT = 24 */
- szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
- szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
- szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
- szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */
- szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
- NULL, /* HTTP_QUERY_FORWARDED = 30 */
- NULL, /* HTTP_QUERY_FROM = 31 */
- szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
- szLocation, /* HTTP_QUERY_LOCATION = 33 */
- NULL, /* HTTP_QUERY_ORIG_URI = 34 */
- szReferer, /* HTTP_QUERY_REFERER = 35 */
- szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */
- szServer, /* HTTP_QUERY_SERVER = 37 */
- NULL, /* HTTP_TITLE = 38 */
- szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */
- szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
- szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
- szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
- szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */
- szCookie, /* HTTP_QUERY_COOKIE = 44 */
- NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
- NULL, /* HTTP_QUERY_REFRESH = 46 */
- NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
- szAge, /* HTTP_QUERY_AGE = 48 */
- szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */
- szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */
- szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
- szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */
- szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */
- szETag, /* HTTP_QUERY_ETAG = 54 */
- szHost, /* HTTP_QUERY_HOST = 55 */
- szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */
- szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
- szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */
- szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
- szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */
- szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
- szRange, /* HTTP_QUERY_RANGE = 62 */
- szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
- szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */
- szVary, /* HTTP_QUERY_VARY = 65 */
- szVia, /* HTTP_QUERY_VIA = 66 */
- szWarning, /* HTTP_QUERY_WARNING = 67 */
- szExpect, /* HTTP_QUERY_EXPECT = 68 */
- szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
- szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
-};
+ GetUrlCacheEntryInfoW(url, info, &nbytes);
-#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
+ ts->ftExpires = info->ExpireTime;
+ ts->ftLastModified = info->LastModifiedTime;
-/***********************************************************************
- * HTTP_HttpQueryInfoW (internal)
- */
-static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel,
- LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
-{
- LPHTTPHEADERW lphttpHdr = NULL;
- BOOL bSuccess = FALSE;
- BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
- INT requested_index = lpdwIndex ? *lpdwIndex : 0;
- INT level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
- INT index = -1;
+ HeapFree(GetProcessHeap(), 0, info);
+ *size = sizeof(*ts);
+ return ERROR_SUCCESS;
+ }
+ return error;
+ }
- /* Find requested header structure */
- switch (level)
- {
- case HTTP_QUERY_CUSTOM:
- index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
- break;
+ case INTERNET_OPTION_DATAFILE_NAME: {
+ DWORD req_size;
- case HTTP_QUERY_RAW_HEADERS_CRLF:
- {
- LPWSTR headers;
- DWORD len;
- BOOL ret;
+ TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
- if (request_only)
- headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, FALSE);
- else
- headers = lpwhr->lpszRawHeaders;
+ if(!req->lpszCacheFile) {
+ *size = 0;
+ return ERROR_INTERNET_ITEM_NOT_FOUND;
+ }
- len = strlenW(headers);
- if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
- {
- *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- ret = FALSE;
- } else
- {
- memcpy(lpBuffer, headers, (len+1)*sizeof(WCHAR));
- *lpdwBufferLength = len * sizeof(WCHAR);
+ if(unicode) {
+ req_size = (lstrlenW(req->lpszCacheFile)+1) * sizeof(WCHAR);
+ if(*size < req_size)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ *size = req_size;
+ memcpy(buffer, req->lpszCacheFile, *size);
+ return ERROR_SUCCESS;
+ }else {
+ req_size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile, -1, NULL, 0, NULL, NULL);
+ if (req_size > *size)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ *size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile,
+ -1, buffer, *size, NULL, NULL);
+ return ERROR_SUCCESS;
+ }
+ }
- TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len));
- ret = TRUE;
- }
+ case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
+ PCCERT_CONTEXT context;
- if (request_only)
- HeapFree(GetProcessHeap(), 0, headers);
- return ret;
+ if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
+ *size = sizeof(INTERNET_CERTIFICATE_INFOW);
+ return ERROR_INSUFFICIENT_BUFFER;
}
- case HTTP_QUERY_RAW_HEADERS:
- {
- static const WCHAR szCrLf[] = {'\r','\n',0};
- LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
- DWORD i, size = 0;
- LPWSTR pszString = (WCHAR*)lpBuffer;
-
- for (i = 0; ppszRawHeaderLines[i]; i++)
- size += strlenW(ppszRawHeaderLines[i]) + 1;
- if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
- {
- HTTP_FreeTokens(ppszRawHeaderLines);
- *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
+ context = (PCCERT_CONTEXT)NETCON_GetCert(&(req->netConnection));
+ if(context) {
+ INTERNET_CERTIFICATE_INFOW *info = (INTERNET_CERTIFICATE_INFOW*)buffer;
+ DWORD len;
- for (i = 0; ppszRawHeaderLines[i]; i++)
- {
- DWORD len = strlenW(ppszRawHeaderLines[i]);
- memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
- pszString += len+1;
+ memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
+ info->ftExpiry = context->pCertInfo->NotAfter;
+ info->ftStart = context->pCertInfo->NotBefore;
+ if(unicode) {
+ len = CertNameToStrW(context->dwCertEncodingType,
+ &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
+ info->lpszSubjectInfo = LocalAlloc(0, len*sizeof(WCHAR));
+ if(info->lpszSubjectInfo)
+ CertNameToStrW(context->dwCertEncodingType,
+ &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
+ info->lpszSubjectInfo, len);
+ len = CertNameToStrW(context->dwCertEncodingType,
+ &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
+ info->lpszIssuerInfo = LocalAlloc(0, len*sizeof(WCHAR));
+ if (info->lpszIssuerInfo)
+ CertNameToStrW(context->dwCertEncodingType,
+ &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
+ info->lpszIssuerInfo, len);
+ }else {
+ INTERNET_CERTIFICATE_INFOA *infoA = (INTERNET_CERTIFICATE_INFOA*)info;
+
+ len = CertNameToStrA(context->dwCertEncodingType,
+ &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
+ infoA->lpszSubjectInfo = LocalAlloc(0, len);
+ if(infoA->lpszSubjectInfo)
+ CertNameToStrA(context->dwCertEncodingType,
+ &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
+ infoA->lpszSubjectInfo, len);
+ len = CertNameToStrA(context->dwCertEncodingType,
+ &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
+ infoA->lpszIssuerInfo = LocalAlloc(0, len);
+ if(infoA->lpszIssuerInfo)
+ CertNameToStrA(context->dwCertEncodingType,
+ &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
+ infoA->lpszIssuerInfo, len);
}
- *pszString = '\0';
- TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size));
+ /*
+ * Contrary to MSDN, these do not appear to be set.
+ * lpszProtocolName
+ * lpszSignatureAlgName
+ * lpszEncryptionAlgName
+ * dwKeySize
+ */
+ CertFreeCertificateContext(context);
+ return ERROR_SUCCESS;
+ }
+ }
+ }
- *lpdwBufferLength = size * sizeof(WCHAR);
- HTTP_FreeTokens(ppszRawHeaderLines);
+ return INET_QueryOption(option, buffer, size, unicode);
+}
- return TRUE;
+static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
+{
+ http_request_t *req = (http_request_t*)hdr;
+
+ switch(option) {
+ case INTERNET_OPTION_SEND_TIMEOUT:
+ case INTERNET_OPTION_RECEIVE_TIMEOUT:
+ TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
+
+ if (size != sizeof(DWORD))
+ return ERROR_INVALID_PARAMETER;
+
+ return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT,
+ *(DWORD*)buffer);
+
+ case INTERNET_OPTION_USERNAME:
+ HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName);
+ if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+ return ERROR_SUCCESS;
+
+ case INTERNET_OPTION_PASSWORD:
+ HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword);
+ if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+ return ERROR_SUCCESS;
+ case INTERNET_OPTION_HTTP_DECODING:
+ if(size != sizeof(BOOL))
+ return ERROR_INVALID_PARAMETER;
+ req->decoding = *(BOOL*)buffer;
+ return ERROR_SUCCESS;
+ }
+
+ return ERROR_INTERNET_INVALID_OPTION;
+}
+
+/* read some more data into the read buffer (the read section must be held) */
+static DWORD read_more_data( http_request_t *req, int maxlen )
+{
+ DWORD res;
+ int len;
+
+ if (req->read_pos)
+ {
+ /* move existing data to the start of the buffer */
+ if(req->read_size)
+ memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
+ req->read_pos = 0;
+ }
+
+ if (maxlen == -1) maxlen = sizeof(req->read_buf);
+
+ res = NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
+ maxlen - req->read_size, 0, &len );
+ if(res == ERROR_SUCCESS)
+ req->read_size += len;
+
+ return res;
+}
+
+/* remove some amount of data from the read buffer (the read section must be held) */
+static void remove_data( http_request_t *req, int count )
+{
+ if (!(req->read_size -= count)) req->read_pos = 0;
+ else req->read_pos += count;
+}
+
+static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
+{
+ int count, bytes_read, pos = 0;
+ DWORD res;
+
+ EnterCriticalSection( &req->read_section );
+ for (;;)
+ {
+ BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
+
+ if (eol)
+ {
+ count = eol - (req->read_buf + req->read_pos);
+ bytes_read = count + 1;
}
- case HTTP_QUERY_STATUS_TEXT:
- if (lpwhr->lpszStatusText)
+ else count = bytes_read = req->read_size;
+
+ count = min( count, *len - pos );
+ memcpy( buffer + pos, req->read_buf + req->read_pos, count );
+ pos += count;
+ remove_data( req, bytes_read );
+ if (eol) break;
+
+ if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size)
{
- DWORD len = strlenW(lpwhr->lpszStatusText);
- if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
- {
- *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
- memcpy(lpBuffer, lpwhr->lpszStatusText, (len+1)*sizeof(WCHAR));
- *lpdwBufferLength = len * sizeof(WCHAR);
+ *len = 0;
+ TRACE( "returning empty string\n" );
+ LeaveCriticalSection( &req->read_section );
+ INTERNET_SetLastError(res);
+ return FALSE;
+ }
+ }
+ LeaveCriticalSection( &req->read_section );
+
+ if (pos < *len)
+ {
+ if (pos && buffer[pos - 1] == '\r') pos--;
+ *len = pos + 1;
+ }
+ buffer[*len - 1] = 0;
+ TRACE( "returning %s\n", debugstr_a(buffer));
+ return TRUE;
+}
- TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len));
+/* discard data contents until we reach end of line (the read section must be held) */
+static DWORD discard_eol( http_request_t *req )
+{
+ DWORD res;
- return TRUE;
+ do
+ {
+ BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
+ if (eol)
+ {
+ remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) );
+ break;
}
- break;
- case HTTP_QUERY_VERSION:
- if (lpwhr->lpszVersion)
+ req->read_pos = req->read_size = 0; /* discard everything */
+ if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res;
+ } while (req->read_size);
+ return ERROR_SUCCESS;
+}
+
+/* read the size of the next chunk (the read section must be held) */
+static DWORD start_next_chunk( http_request_t *req )
+{
+ DWORD chunk_size = 0, res;
+
+ if (!req->dwContentLength) return ERROR_SUCCESS;
+ if (req->dwContentLength == req->dwContentRead)
+ {
+ /* read terminator for the previous chunk */
+ if ((res = discard_eol( req )) != ERROR_SUCCESS) return res;
+ req->dwContentLength = ~0u;
+ req->dwContentRead = 0;
+ }
+ for (;;)
+ {
+ while (req->read_size)
{
- DWORD len = strlenW(lpwhr->lpszVersion);
- if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
+ char ch = req->read_buf[req->read_pos];
+ if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
+ else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
+ else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
+ else if (ch == ';' || ch == '\r' || ch == '\n')
{
- *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
+ TRACE( "reading %u byte chunk\n", chunk_size );
+ req->dwContentLength = chunk_size;
+ req->dwContentRead = 0;
+ return discard_eol( req );
}
- memcpy(lpBuffer, lpwhr->lpszVersion, (len+1)*sizeof(WCHAR));
- *lpdwBufferLength = len * sizeof(WCHAR);
+ remove_data( req, 1 );
+ }
+ if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res;
+ if (!req->read_size)
+ {
+ req->dwContentLength = req->dwContentRead = 0;
+ return ERROR_SUCCESS;
+ }
+ }
+}
- TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len));
+/* check if we have reached the end of the data to read (the read section must be held) */
+static BOOL end_of_read_data( http_request_t *req )
+{
+ if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
+ if (req->read_chunked) return (req->dwContentLength == 0);
+ if (req->dwContentLength == ~0u) return FALSE;
+ return (req->dwContentLength == req->dwContentRead);
+}
- return TRUE;
+/* fetch some more data into the read buffer (the read section must be held) */
+static DWORD refill_buffer( http_request_t *req )
+{
+ int len = sizeof(req->read_buf);
+ DWORD res;
+
+ if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
+ {
+ if ((res = start_next_chunk( req )) != ERROR_SUCCESS) return res;
+ }
+
+ if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead );
+ if (len <= req->read_size) return ERROR_SUCCESS;
+
+ if ((res = read_more_data( req, len )) != ERROR_SUCCESS) return res;
+ if (!req->read_size) req->dwContentLength = req->dwContentRead = 0;
+ return ERROR_SUCCESS;
+}
+
+static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret)
+{
+ DWORD ret = ERROR_SUCCESS;
+ int read = 0;
+
+#ifdef HAVE_ZLIB
+ z_stream *zstream = &req->gzip_stream->zstream;
+ DWORD buf_avail;
+ int zres;
+
+ while(read < size && !req->gzip_stream->end_of_data) {
+ if(!req->read_size) {
+ if(!sync || refill_buffer(req) != ERROR_SUCCESS)
+ break;
}
- break;
- default:
- assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
- if (level >= 0 && level < LAST_TABLE_HEADER && header_lookup[level])
- index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
- requested_index,request_only);
+ buf_avail = req->dwContentLength == ~0 ? req->read_size : min(req->read_size, req->dwContentLength-req->dwContentRead);
+
+ zstream->next_in = req->read_buf+req->read_pos;
+ zstream->avail_in = buf_avail;
+ zstream->next_out = buf+read;
+ zstream->avail_out = size-read;
+ zres = inflate(zstream, Z_FULL_FLUSH);
+ read = size - zstream->avail_out;
+ req->dwContentRead += buf_avail-zstream->avail_in;
+ remove_data(req, buf_avail-zstream->avail_in);
+ if(zres == Z_STREAM_END) {
+ TRACE("end of data\n");
+ req->gzip_stream->end_of_data = TRUE;
+ inflateEnd(&req->gzip_stream->zstream);
+ }else if(zres != Z_OK) {
+ WARN("inflate failed %d\n", zres);
+ if(!read)
+ ret = ERROR_INTERNET_DECODING_FAILED;
+ break;
+ }
}
+#endif
- if (index >= 0)
- lphttpHdr = &lpwhr->pCustHeaders[index];
+ *read_ret = read;
+ return ret;
+}
- /* Ensure header satisifies requested attributes */
- if (!lphttpHdr ||
- ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
- (~lphttpHdr->wFlags & HDR_ISREQUEST)))
+static void refill_gzip_buffer(http_request_t *req)
+{
+ DWORD res;
+ int len;
+
+ if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf))
+ return;
+
+ if(req->gzip_stream->buf_pos) {
+ if(req->gzip_stream->buf_size)
+ memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size);
+ req->gzip_stream->buf_pos = 0;
+ }
+
+ res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size,
+ sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len);
+ if(res == ERROR_SUCCESS)
+ req->gzip_stream->buf_size += len;
+}
+
+/* return the size of data available to be read immediately (the read section must be held) */
+static DWORD get_avail_data( http_request_t *req )
+{
+ if (req->gzip_stream) {
+ refill_gzip_buffer(req);
+ return req->gzip_stream->buf_size;
+ }
+ if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
+ return 0;
+ return min( req->read_size, req->dwContentLength - req->dwContentRead );
+}
+
+static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
+{
+ INTERNET_ASYNC_RESULT iar;
+ DWORD res;
+
+ TRACE("%p\n", req);
+
+ EnterCriticalSection( &req->read_section );
+ if ((res = refill_buffer( req )) == ERROR_SUCCESS) {
+ iar.dwResult = (DWORD_PTR)req->hdr.hInternet;
+ iar.dwError = first_notif ? 0 : get_avail_data(req);
+ }else {
+ iar.dwResult = 0;
+ iar.dwError = res;
+ }
+ LeaveCriticalSection( &req->read_section );
+
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+ sizeof(INTERNET_ASYNC_RESULT));
+}
+
+/* read data from the http connection (the read section must be held) */
+static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
+{
+ BOOL finished_reading = FALSE;
+ int len, bytes_read = 0;
+ DWORD ret = ERROR_SUCCESS;
+
+ EnterCriticalSection( &req->read_section );
+
+ if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
{
- INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
- return bSuccess;
+ if (start_next_chunk( req ) != ERROR_SUCCESS) goto done;
+ }
+
+ if(req->gzip_stream) {
+ if(req->gzip_stream->buf_size) {
+ bytes_read = min(req->gzip_stream->buf_size, size);
+ memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read);
+ req->gzip_stream->buf_pos += bytes_read;
+ req->gzip_stream->buf_size -= bytes_read;
+ }else if(!req->read_size && !req->gzip_stream->end_of_data) {
+ refill_buffer(req);
+ }
+
+ if(size > bytes_read) {
+ ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len);
+ if(ret == ERROR_SUCCESS)
+ bytes_read += len;
+ }
+
+ finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
+ }else {
+ if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
+
+ if (req->read_size) {
+ bytes_read = min( req->read_size, size );
+ memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
+ remove_data( req, bytes_read );
+ }
+
+ if (size > bytes_read && (!bytes_read || sync)) {
+ if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
+ sync ? MSG_WAITALL : 0, &len) == ERROR_SUCCESS)
+ bytes_read += len;
+ /* always return success, even if the network layer returns an error */
+ }
+
+ finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
+ req->dwContentRead += bytes_read;
}
+done:
+ *read = bytes_read;
+
+ TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
+ LeaveCriticalSection( &req->read_section );
+
+ if(ret == ERROR_SUCCESS && req->lpszCacheFile) {
+ BOOL res;
+ DWORD dwBytesWritten;
+
+ res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL);
+ if(!res)
+ WARN("WriteFile failed: %u\n", GetLastError());
+ }
+
+ if(finished_reading)
+ HTTP_FinishedReading(req);
+
+ return ret;
+}
+
+
+static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
+{
+ http_request_t *req = (http_request_t*)hdr;
+ return HTTPREQ_Read(req, buffer, size, read, TRUE);
+}
+
+static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
+{
+ struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
+ http_request_t *req = (http_request_t*)workRequest->hdr;
+ INTERNET_ASYNC_RESULT iar;
+ DWORD res;
+
+ TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
+
+ res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
+ data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
+
+ iar.dwResult = res == ERROR_SUCCESS;
+ iar.dwError = res;
+
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
+ INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+ sizeof(INTERNET_ASYNC_RESULT));
+}
+
+static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
+ DWORD flags, DWORD_PTR context)
+{
+ http_request_t *req = (http_request_t*)hdr;
+ DWORD res;
- if (lpdwIndex)
- (*lpdwIndex)++;
+ if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
+ FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
- /* coalesce value to reuqested type */
- if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
+ if (buffers->dwStructSize != sizeof(*buffers))
+ return ERROR_INVALID_PARAMETER;
+
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+ if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req))
{
- *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
- bSuccess = TRUE;
+ WORKREQUEST workRequest;
+
+ if (TryEnterCriticalSection( &req->read_section ))
+ {
+ if (get_avail_data(req))
+ {
+ res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
+ &buffers->dwBufferLength, FALSE);
+ LeaveCriticalSection( &req->read_section );
+ goto done;
+ }
+ LeaveCriticalSection( &req->read_section );
+ }
- TRACE(" returning number : %d\n", *(int *)lpBuffer);
+ workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
+ workRequest.hdr = WININET_AddRef(&req->hdr);
+ workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
+
+ INTERNET_AsyncCall(&workRequest);
+
+ return ERROR_IO_PENDING;
+ }
+
+ res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
+ !(flags & IRF_NO_WAIT));
+
+done:
+ if (res == ERROR_SUCCESS) {
+ DWORD size = buffers->dwBufferLength;
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
+ &size, sizeof(size));
}
- else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
+
+ return res;
+}
+
+static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
+{
+ struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
+ http_request_t *req = (http_request_t*)workRequest->hdr;
+ INTERNET_ASYNC_RESULT iar;
+ DWORD res;
+
+ TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
+
+ res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
+ data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
+
+ iar.dwResult = res == ERROR_SUCCESS;
+ iar.dwError = res;
+
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
+ INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+ sizeof(INTERNET_ASYNC_RESULT));
+}
+
+static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
+ DWORD flags, DWORD_PTR context)
+{
+
+ http_request_t *req = (http_request_t*)hdr;
+ DWORD res;
+
+ if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
+ FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
+
+ if (buffers->dwStructSize != sizeof(*buffers))
+ return ERROR_INVALID_PARAMETER;
+
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+ if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
{
- time_t tmpTime;
- struct tm tmpTM;
- SYSTEMTIME *STHook;
+ WORKREQUEST workRequest;
- tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
+ if (TryEnterCriticalSection( &req->read_section ))
+ {
+ if (get_avail_data(req))
+ {
+ res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
+ &buffers->dwBufferLength, FALSE);
+ LeaveCriticalSection( &req->read_section );
+ goto done;
+ }
+ LeaveCriticalSection( &req->read_section );
+ }
- tmpTM = *gmtime(&tmpTime);
- STHook = (SYSTEMTIME *) lpBuffer;
- if(STHook==NULL)
- return bSuccess;
-
- STHook->wDay = tmpTM.tm_mday;
- STHook->wHour = tmpTM.tm_hour;
- STHook->wMilliseconds = 0;
- STHook->wMinute = tmpTM.tm_min;
- STHook->wDayOfWeek = tmpTM.tm_wday;
- STHook->wMonth = tmpTM.tm_mon + 1;
- STHook->wSecond = tmpTM.tm_sec;
- STHook->wYear = tmpTM.tm_year;
-
- bSuccess = TRUE;
-
- TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
- STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
- STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
+ workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
+ workRequest.hdr = WININET_AddRef(&req->hdr);
+ workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
+
+ INTERNET_AsyncCall(&workRequest);
+
+ return ERROR_IO_PENDING;
}
- else if (lphttpHdr->lpszValue)
+
+ res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
+ !(flags & IRF_NO_WAIT));
+
+done:
+ if (res == ERROR_SUCCESS) {
+ DWORD size = buffers->dwBufferLength;
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
+ &size, sizeof(size));
+ }
+
+ return res;
+}
+
+static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
+{
+ DWORD res;
+ http_request_t *lpwhr = (http_request_t*)hdr;
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
+
+ *written = 0;
+ res = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written);
+ if (res == ERROR_SUCCESS)
+ lpwhr->dwBytesWritten += *written;
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
+ return res;
+}
+
+static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
+{
+ http_request_t *req = (http_request_t*)workRequest->hdr;
+
+ HTTP_ReceiveRequestData(req, FALSE);
+}
+
+static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
+{
+ http_request_t *req = (http_request_t*)hdr;
+
+ TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
+
+ if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
- DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
+ WORKREQUEST workRequest;
- if (len > *lpdwBufferLength)
+ /* never wait, if we can't enter the section we queue an async request right away */
+ if (TryEnterCriticalSection( &req->read_section ))
{
- *lpdwBufferLength = len;
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return bSuccess;
+ if ((*available = get_avail_data( req ))) goto done;
+ if (end_of_read_data( req )) goto done;
+ LeaveCriticalSection( &req->read_section );
}
- memcpy(lpBuffer, lphttpHdr->lpszValue, len);
- *lpdwBufferLength = len - sizeof(WCHAR);
- bSuccess = TRUE;
+ workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
+ workRequest.hdr = WININET_AddRef( &req->hdr );
+
+ INTERNET_AsyncCall(&workRequest);
+
+ return ERROR_IO_PENDING;
+ }
+
+ EnterCriticalSection( &req->read_section );
+
+ if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
+ {
+ refill_buffer( req );
+ *available = get_avail_data( req );
+ }
- TRACE(" returning string : %s\n", debugstr_w(lpBuffer));
+done:
+ if (*available == sizeof(req->read_buf) && !req->gzip_stream) /* check if we have even more pending in the socket */
+ {
+ DWORD extra;
+ if (NETCON_query_data_available(&req->netConnection, &extra))
+ *available = min( *available + extra, req->dwContentLength - req->dwContentRead );
}
- return bSuccess;
+ LeaveCriticalSection( &req->read_section );
+
+ TRACE( "returning %u\n", *available );
+ return ERROR_SUCCESS;
}
+static const object_vtbl_t HTTPREQVtbl = {
+ HTTPREQ_Destroy,
+ HTTPREQ_CloseConnection,
+ HTTPREQ_QueryOption,
+ HTTPREQ_SetOption,
+ HTTPREQ_ReadFile,
+ HTTPREQ_ReadFileExA,
+ HTTPREQ_ReadFileExW,
+ HTTPREQ_WriteFile,
+ HTTPREQ_QueryDataAvailable,
+ NULL
+};
+
/***********************************************************************
- * HttpQueryInfoW (WININET.@)
+ * HTTP_HttpOpenRequestW (internal)
*
- * Queries for information about an HTTP request
+ * Open a HTTP request handle
*
* RETURNS
- * TRUE on success
- * FALSE on failure
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
*
*/
-BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
- LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+static DWORD HTTP_HttpOpenRequestW(http_session_t *lpwhs,
+ LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+ LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret)
{
- BOOL bSuccess = FALSE;
- LPWININETHTTPREQW lpwhr;
+ appinfo_t *hIC = NULL;
+ http_request_t *lpwhr;
+ LPWSTR lpszHostName = NULL;
+ HINTERNET handle = NULL;
+ static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
+ DWORD len, res;
+
+ TRACE("-->\n");
+
+ assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
+ hIC = lpwhs->lpAppInfo;
+
+ lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t));
+ if (NULL == lpwhr)
+ {
+ res = ERROR_OUTOFMEMORY;
+ goto lend;
+ }
+ lpwhr->hdr.htype = WH_HHTTPREQ;
+ lpwhr->hdr.vtbl = &HTTPREQVtbl;
+ lpwhr->hdr.dwFlags = dwFlags;
+ lpwhr->hdr.dwContext = dwContext;
+ lpwhr->hdr.refs = 1;
+ lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB;
+ lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW;
+ lpwhr->dwContentLength = ~0u;
+ InitializeCriticalSection( &lpwhr->read_section );
+
+ WININET_AddRef( &lpwhs->hdr );
+ lpwhr->lpHttpSession = lpwhs;
+ list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
+
+ lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
+ (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
+ if (NULL == lpszHostName)
+ {
+ res = ERROR_OUTOFMEMORY;
+ goto lend;
+ }
+
+ handle = WININET_AllocHandle( &lpwhr->hdr );
+ if (NULL == handle)
+ {
+ res = ERROR_OUTOFMEMORY;
+ goto lend;
+ }
+
+ if ((res = NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) != ERROR_SUCCESS)
+ {
+ InternetCloseHandle( handle );
+ handle = NULL;
+ goto lend;
+ }
+
+ if (lpszObjectName && *lpszObjectName) {
+ HRESULT rc;
+
+ len = 0;
+ rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
+ if (rc != E_POINTER)
+ len = strlenW(lpszObjectName)+1;
+ lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
+ rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
+ URL_ESCAPE_SPACES_ONLY);
+ if (rc != S_OK)
+ {
+ ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
+ strcpyW(lpwhr->lpszPath,lpszObjectName);
+ }
+ }else {
+ static const WCHAR slashW[] = {'/',0};
+
+ lpwhr->lpszPath = heap_strdupW(slashW);
+ }
+
+ if (lpszReferrer && *lpszReferrer)
+ HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
+
+ if (lpszAcceptTypes)
+ {
+ int i;
+ for (i = 0; lpszAcceptTypes[i]; i++)
+ {
+ if (!*lpszAcceptTypes[i]) continue;
+ HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
+ HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
+ HTTP_ADDHDR_FLAG_REQ |
+ (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
+ }
+ }
+
+ lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
+ lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
+
+ if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
+ lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
+ lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
+ {
+ sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort);
+ HTTP_ProcessHeader(lpwhr, hostW, lpszHostName,
+ HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
+ }
+ else
+ HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
+ HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
+
+ if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
+ lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
+ INTERNET_DEFAULT_HTTPS_PORT :
+ INTERNET_DEFAULT_HTTP_PORT);
+
+ if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
+ lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
+ INTERNET_DEFAULT_HTTPS_PORT :
+ INTERNET_DEFAULT_HTTP_PORT);
+
+ if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
+ HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
+
+ INTERNET_SendCallback(&lpwhs->hdr, dwContext,
+ INTERNET_STATUS_HANDLE_CREATED, &handle,
+ sizeof(handle));
+
+lend:
+ HeapFree(GetProcessHeap(), 0, lpszHostName);
+ if( lpwhr )
+ WININET_Release( &lpwhr->hdr );
+
+ TRACE("<-- %p (%p)\n", handle, lpwhr);
+ *ret = handle;
+ return res;
+}
+
+/***********************************************************************
+ * HttpOpenRequestW (WININET.@)
+ *
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
+ *
+ */
+HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
+ LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+ LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD_PTR dwContext)
+{
+ http_session_t *lpwhs;
+ HINTERNET handle = NULL;
+ DWORD res;
+
+ TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
+ debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
+ debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
+ dwFlags, dwContext);
+ if(lpszAcceptTypes!=NULL)
+ {
+ int i;
+ for(i=0;lpszAcceptTypes[i]!=NULL;i++)
+ TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
+ }
+
+ lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ {
+ res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+ goto lend;
+ }
+
+ /*
+ * My tests seem to show that the windows version does not
+ * become asynchronous until after this point. And anyhow
+ * if this call was asynchronous then how would you get the
+ * necessary HINTERNET pointer returned by this function.
+ *
+ */
+ res = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
+ lpszVersion, lpszReferrer, lpszAcceptTypes,
+ dwFlags, dwContext, &handle);
+lend:
+ if( lpwhs )
+ WININET_Release( &lpwhs->hdr );
+ TRACE("returning %p\n", handle);
+ if(res != ERROR_SUCCESS)
+ SetLastError(res);
+ return handle;
+}
+
+/* read any content returned by the server so that the connection can be
+ * reused */
+static void HTTP_DrainContent(http_request_t *req)
+{
+ DWORD bytes_read;
+
+ if (!NETCON_connected(&req->netConnection)) return;
+
+ if (req->dwContentLength == -1)
+ {
+ NETCON_close(&req->netConnection);
+ return;
+ }
+ if (!strcmpW(req->lpszVerb, szHEAD)) return;
+
+ do
+ {
+ char buffer[2048];
+ if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
+ return;
+ } while (bytes_read);
+}
+
+static const LPCWSTR header_lookup[] = {
+ szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */
+ szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */
+ szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
+ szContent_ID, /* HTTP_QUERY_CONTENT_ID = 3 */
+ NULL, /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
+ szContent_Length, /* HTTP_QUERY_CONTENT_LENGTH = 5 */
+ szContent_Language, /* HTTP_QUERY_CONTENT_LANGUAGE = 6 */
+ szAllow, /* HTTP_QUERY_ALLOW = 7 */
+ szPublic, /* HTTP_QUERY_PUBLIC = 8 */
+ szDate, /* HTTP_QUERY_DATE = 9 */
+ szExpires, /* HTTP_QUERY_EXPIRES = 10 */
+ szLast_Modified, /* HTTP_QUERY_LAST_MODIFIED = 11 */
+ NULL, /* HTTP_QUERY_MESSAGE_ID = 12 */
+ szURI, /* HTTP_QUERY_URI = 13 */
+ szFrom, /* HTTP_QUERY_DERIVED_FROM = 14 */
+ NULL, /* HTTP_QUERY_COST = 15 */
+ NULL, /* HTTP_QUERY_LINK = 16 */
+ szPragma, /* HTTP_QUERY_PRAGMA = 17 */
+ NULL, /* HTTP_QUERY_VERSION = 18 */
+ szStatus, /* HTTP_QUERY_STATUS_CODE = 19 */
+ NULL, /* HTTP_QUERY_STATUS_TEXT = 20 */
+ NULL, /* HTTP_QUERY_RAW_HEADERS = 21 */
+ NULL, /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
+ szConnection, /* HTTP_QUERY_CONNECTION = 23 */
+ szAccept, /* HTTP_QUERY_ACCEPT = 24 */
+ szAccept_Charset, /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
+ szAccept_Encoding, /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
+ szAccept_Language, /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
+ szAuthorization, /* HTTP_QUERY_AUTHORIZATION = 28 */
+ szContent_Encoding, /* HTTP_QUERY_CONTENT_ENCODING = 29 */
+ NULL, /* HTTP_QUERY_FORWARDED = 30 */
+ NULL, /* HTTP_QUERY_FROM = 31 */
+ szIf_Modified_Since, /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
+ szLocation, /* HTTP_QUERY_LOCATION = 33 */
+ NULL, /* HTTP_QUERY_ORIG_URI = 34 */
+ szReferer, /* HTTP_QUERY_REFERER = 35 */
+ szRetry_After, /* HTTP_QUERY_RETRY_AFTER = 36 */
+ szServer, /* HTTP_QUERY_SERVER = 37 */
+ NULL, /* HTTP_TITLE = 38 */
+ szUser_Agent, /* HTTP_QUERY_USER_AGENT = 39 */
+ szWWW_Authenticate, /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
+ szProxy_Authenticate, /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
+ szAccept_Ranges, /* HTTP_QUERY_ACCEPT_RANGES = 42 */
+ szSet_Cookie, /* HTTP_QUERY_SET_COOKIE = 43 */
+ szCookie, /* HTTP_QUERY_COOKIE = 44 */
+ NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */
+ NULL, /* HTTP_QUERY_REFRESH = 46 */
+ NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
+ szAge, /* HTTP_QUERY_AGE = 48 */
+ szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */
+ szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */
+ szContent_Location, /* HTTP_QUERY_CONTENT_LOCATION = 51 */
+ szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */
+ szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */
+ szETag, /* HTTP_QUERY_ETAG = 54 */
+ hostW, /* HTTP_QUERY_HOST = 55 */
+ szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */
+ szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */
+ szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */
+ szIf_Unmodified_Since, /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
+ szMax_Forwards, /* HTTP_QUERY_MAX_FORWARDS = 60 */
+ szProxy_Authorization, /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
+ szRange, /* HTTP_QUERY_RANGE = 62 */
+ szTransfer_Encoding, /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
+ szUpgrade, /* HTTP_QUERY_UPGRADE = 64 */
+ szVary, /* HTTP_QUERY_VARY = 65 */
+ szVia, /* HTTP_QUERY_VIA = 66 */
+ szWarning, /* HTTP_QUERY_WARNING = 67 */
+ szExpect, /* HTTP_QUERY_EXPECT = 68 */
+ szProxy_Connection, /* HTTP_QUERY_PROXY_CONNECTION = 69 */
+ szUnless_Modified_Since, /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
+};
+
+#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
+
+/***********************************************************************
+ * HTTP_HttpQueryInfoW (internal)
+ */
+static DWORD HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
+ LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+{
+ LPHTTPHEADERW lphttpHdr = NULL;
+ BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
+ INT requested_index = lpdwIndex ? *lpdwIndex : 0;
+ DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
+ INT index = -1;
+
+ /* Find requested header structure */
+ switch (level)
+ {
+ case HTTP_QUERY_CUSTOM:
+ if (!lpBuffer) return ERROR_INVALID_PARAMETER;
+ index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
+ break;
+ case HTTP_QUERY_RAW_HEADERS_CRLF:
+ {
+ LPWSTR headers;
+ DWORD len = 0;
+ DWORD res = ERROR_INVALID_PARAMETER;
+
+ if (request_only)
+ headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
+ else
+ headers = lpwhr->lpszRawHeaders;
+
+ if (headers)
+ len = strlenW(headers) * sizeof(WCHAR);
+
+ if (len + sizeof(WCHAR) > *lpdwBufferLength)
+ {
+ len += sizeof(WCHAR);
+ res = ERROR_INSUFFICIENT_BUFFER;
+ }
+ else if (lpBuffer)
+ {
+ if (headers)
+ memcpy(lpBuffer, headers, len + sizeof(WCHAR));
+ else
+ {
+ len = strlenW(szCrLf) * sizeof(WCHAR);
+ memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
+ }
+ TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
+ res = ERROR_SUCCESS;
+ }
+ *lpdwBufferLength = len;
+
+ if (request_only)
+ HeapFree(GetProcessHeap(), 0, headers);
+ return res;
+ }
+ case HTTP_QUERY_RAW_HEADERS:
+ {
+ LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
+ DWORD i, size = 0;
+ LPWSTR pszString = lpBuffer;
+
+ for (i = 0; ppszRawHeaderLines[i]; i++)
+ size += strlenW(ppszRawHeaderLines[i]) + 1;
+
+ if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
+ {
+ HTTP_FreeTokens(ppszRawHeaderLines);
+ *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+ if (pszString)
+ {
+ for (i = 0; ppszRawHeaderLines[i]; i++)
+ {
+ DWORD len = strlenW(ppszRawHeaderLines[i]);
+ memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
+ pszString += len+1;
+ }
+ *pszString = '\0';
+ TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
+ }
+ *lpdwBufferLength = size * sizeof(WCHAR);
+ HTTP_FreeTokens(ppszRawHeaderLines);
+
+ return ERROR_SUCCESS;
+ }
+ case HTTP_QUERY_STATUS_TEXT:
+ if (lpwhr->lpszStatusText)
+ {
+ DWORD len = strlenW(lpwhr->lpszStatusText);
+ if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
+ {
+ *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+ if (lpBuffer)
+ {
+ memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
+ TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
+ }
+ *lpdwBufferLength = len * sizeof(WCHAR);
+ return ERROR_SUCCESS;
+ }
+ break;
+ case HTTP_QUERY_VERSION:
+ if (lpwhr->lpszVersion)
+ {
+ DWORD len = strlenW(lpwhr->lpszVersion);
+ if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
+ {
+ *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+ if (lpBuffer)
+ {
+ memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
+ TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
+ }
+ *lpdwBufferLength = len * sizeof(WCHAR);
+ return ERROR_SUCCESS;
+ }
+ break;
+ case HTTP_QUERY_CONTENT_ENCODING:
+ index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level],
+ requested_index,request_only);
+ break;
+ default:
+ assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
+
+ if (level < LAST_TABLE_HEADER && header_lookup[level])
+ index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
+ requested_index,request_only);
+ }
+
+ if (index >= 0)
+ lphttpHdr = &lpwhr->pCustHeaders[index];
+
+ /* Ensure header satisfies requested attributes */
+ if (!lphttpHdr ||
+ ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
+ (~lphttpHdr->wFlags & HDR_ISREQUEST)))
+ {
+ return ERROR_HTTP_HEADER_NOT_FOUND;
+ }
+
+ if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
+
+ /* coalesce value to requested type */
+ if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
+ {
+ *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
+ TRACE(" returning number: %d\n", *(int *)lpBuffer);
+ }
+ else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
+ {
+ time_t tmpTime;
+ struct tm tmpTM;
+ SYSTEMTIME *STHook;
+
+ tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
+
+ tmpTM = *gmtime(&tmpTime);
+ STHook = (SYSTEMTIME *)lpBuffer;
+ STHook->wDay = tmpTM.tm_mday;
+ STHook->wHour = tmpTM.tm_hour;
+ STHook->wMilliseconds = 0;
+ STHook->wMinute = tmpTM.tm_min;
+ STHook->wDayOfWeek = tmpTM.tm_wday;
+ STHook->wMonth = tmpTM.tm_mon + 1;
+ STHook->wSecond = tmpTM.tm_sec;
+ STHook->wYear = tmpTM.tm_year;
+
+ TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
+ STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
+ STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
+ }
+ else if (lphttpHdr->lpszValue)
+ {
+ DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
+
+ if (len > *lpdwBufferLength)
+ {
+ *lpdwBufferLength = len;
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+ if (lpBuffer)
+ {
+ memcpy(lpBuffer, lphttpHdr->lpszValue, len);
+ TRACE("! returning string: %s\n", debugstr_w(lpBuffer));
+ }
+ *lpdwBufferLength = len - sizeof(WCHAR);
+ }
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * HttpQueryInfoW (WININET.@)
+ *
+ * Queries for information about an HTTP request
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
+ LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+{
+ http_request_t *lpwhr;
+ DWORD res;
if (TRACE_ON(wininet)) {
#define FE(x) { x, #x }
DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
DWORD i;
- TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
- TRACE(" Attribute:");
- for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
- if (query_flags[i].val == info) {
- TRACE(" %s", query_flags[i].name);
- break;
- }
- }
- if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
- TRACE(" Unknown (%08x)", info);
- }
+ TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info);
+ TRACE(" Attribute:");
+ for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
+ if (query_flags[i].val == info) {
+ TRACE(" %s", query_flags[i].name);
+ break;
+ }
+ }
+ if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
+ TRACE(" Unknown (%08x)", info);
+ }
+
+ TRACE(" Modifier:");
+ for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
+ if (modifier_flags[i].val & info_mod) {
+ TRACE(" %s", modifier_flags[i].name);
+ info_mod &= ~ modifier_flags[i].val;
+ }
+ }
+
+ if (info_mod) {
+ TRACE(" Unknown (%08x)", info_mod);
+ }
+ TRACE("\n");
+ }
+
+ lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+ goto lend;
+ }
+
+ if (lpBuffer == NULL)
+ *lpdwBufferLength = 0;
+ res = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
+ lpBuffer, lpdwBufferLength, lpdwIndex);
+
+lend:
+ if( lpwhr )
+ WININET_Release( &lpwhr->hdr );
+
+ TRACE("%u <--\n", res);
+ if(res != ERROR_SUCCESS)
+ SetLastError(res);
+ return res == ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * HttpQueryInfoA (WININET.@)
+ *
+ * Queries for information about an HTTP request
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
+ LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+{
+ BOOL result;
+ DWORD len;
+ WCHAR* bufferW;
+
+ if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
+ (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
+ {
+ return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
+ lpdwBufferLength, lpdwIndex );
+ }
+
+ if (lpBuffer)
+ {
+ DWORD alloclen;
+ len = (*lpdwBufferLength)*sizeof(WCHAR);
+ if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
+ {
+ alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
+ if (alloclen < len)
+ alloclen = len;
+ }
+ else
+ alloclen = len;
+ bufferW = HeapAlloc( GetProcessHeap(), 0, alloclen );
+ /* buffer is in/out because of HTTP_QUERY_CUSTOM */
+ if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
+ MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
+ } else
+ {
+ bufferW = NULL;
+ len = 0;
+ }
+
+ result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
+ &len, lpdwIndex );
+ if( result )
+ {
+ len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
+ lpBuffer, *lpdwBufferLength, NULL, NULL );
+ *lpdwBufferLength = len - 1;
+
+ TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
+ }
+ else
+ /* since the strings being returned from HttpQueryInfoW should be
+ * only ASCII characters, it is reasonable to assume that all of
+ * the Unicode characters can be reduced to a single byte */
+ *lpdwBufferLength = len / sizeof(WCHAR);
+
+ HeapFree(GetProcessHeap(), 0, bufferW );
+
+ return result;
+}
+
+/***********************************************************************
+ * HTTP_GetRedirectURL (internal)
+ */
+static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
+{
+ static WCHAR szHttp[] = {'h','t','t','p',0};
+ static WCHAR szHttps[] = {'h','t','t','p','s',0};
+ http_session_t *lpwhs = lpwhr->lpHttpSession;
+ URL_COMPONENTSW urlComponents;
+ DWORD url_length = 0;
+ LPWSTR orig_url;
+ LPWSTR combined_url;
+
+ urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
+ urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
+ urlComponents.dwSchemeLength = 0;
+ urlComponents.lpszHostName = lpwhs->lpszHostName;
+ urlComponents.dwHostNameLength = 0;
+ urlComponents.nPort = lpwhs->nHostPort;
+ urlComponents.lpszUserName = lpwhs->lpszUserName;
+ urlComponents.dwUserNameLength = 0;
+ urlComponents.lpszPassword = NULL;
+ urlComponents.dwPasswordLength = 0;
+ urlComponents.lpszUrlPath = lpwhr->lpszPath;
+ urlComponents.dwUrlPathLength = 0;
+ urlComponents.lpszExtraInfo = NULL;
+ urlComponents.dwExtraInfoLength = 0;
+
+ if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
+ (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+ return NULL;
+
+ orig_url = HeapAlloc(GetProcessHeap(), 0, url_length);
+
+ /* convert from bytes to characters */
+ url_length = url_length / sizeof(WCHAR) - 1;
+ if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
+ {
+ HeapFree(GetProcessHeap(), 0, orig_url);
+ return NULL;
+ }
+
+ url_length = 0;
+ if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
+ (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+ {
+ HeapFree(GetProcessHeap(), 0, orig_url);
+ return NULL;
+ }
+ combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR));
+
+ if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
+ {
+ HeapFree(GetProcessHeap(), 0, orig_url);
+ HeapFree(GetProcessHeap(), 0, combined_url);
+ return NULL;
+ }
+ HeapFree(GetProcessHeap(), 0, orig_url);
+ return combined_url;
+}
+
+
+/***********************************************************************
+ * HTTP_HandleRedirect (internal)
+ */
+static DWORD HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
+{
+ http_session_t *lpwhs = lpwhr->lpHttpSession;
+ appinfo_t *hIC = lpwhs->lpAppInfo;
+ BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0];
+ WCHAR path[INTERNET_MAX_URL_LENGTH];
+ int index;
+
+ if(lpszUrl[0]=='/')
+ {
+ /* if it's an absolute path, keep the same session info */
+ lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
+ }
+ else
+ {
+ URL_COMPONENTSW urlComponents;
+ WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
+ static WCHAR szHttp[] = {'h','t','t','p',0};
+ static WCHAR szHttps[] = {'h','t','t','p','s',0};
+
+ userName[0] = 0;
+ hostName[0] = 0;
+ protocol[0] = 0;
+
+ urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
+ urlComponents.lpszScheme = protocol;
+ urlComponents.dwSchemeLength = 32;
+ urlComponents.lpszHostName = hostName;
+ urlComponents.dwHostNameLength = MAXHOSTNAME;
+ urlComponents.lpszUserName = userName;
+ urlComponents.dwUserNameLength = 1024;
+ urlComponents.lpszPassword = NULL;
+ urlComponents.dwPasswordLength = 0;
+ urlComponents.lpszUrlPath = path;
+ urlComponents.dwUrlPathLength = 2048;
+ urlComponents.lpszExtraInfo = NULL;
+ urlComponents.dwExtraInfoLength = 0;
+ if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
+ return INTERNET_GetLastError();
+
+ if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
+ (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
+ {
+ TRACE("redirect from secure page to non-secure page\n");
+ /* FIXME: warn about from secure redirect to non-secure page */
+ lpwhr->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
+ }
+ if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) &&
+ !(lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
+ {
+ TRACE("redirect from non-secure page to secure page\n");
+ /* FIXME: notify about redirect to secure page */
+ lpwhr->hdr.dwFlags |= INTERNET_FLAG_SECURE;
+ }
+
+ if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
+ {
+ if (lstrlenW(protocol)>4) /*https*/
+ urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
+ else /*http*/
+ urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
+ }
- TRACE(" Modifier:");
- for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
- if (modifier_flags[i].val & info_mod) {
- TRACE(" %s", modifier_flags[i].name);
- info_mod &= ~ modifier_flags[i].val;
- }
- }
-
- if (info_mod) {
- TRACE(" Unknown (%08x)", info_mod);
- }
- TRACE("\n");
+#if 0
+ /*
+ * This upsets redirects to binary files on sourceforge.net
+ * and gives an html page instead of the target file
+ * Examination of the HTTP request sent by native wininet.dll
+ * reveals that it doesn't send a referrer in that case.
+ * Maybe there's a flag that enables this, or maybe a referrer
+ * shouldn't be added in case of a redirect.
+ */
+
+ /* consider the current host as the referrer */
+ if (lpwhs->lpszServerName && *lpwhs->lpszServerName)
+ HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
+ HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
+ HTTP_ADDHDR_FLAG_ADD_IF_NEW);
+#endif
+
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
+ if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT &&
+ urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
+ {
+ int len;
+ static const WCHAR fmt[] = {'%','s',':','%','i',0};
+ len = lstrlenW(hostName);
+ len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
+ lpwhs->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
+ sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort);
+ }
+ else
+ lpwhs->lpszHostName = heap_strdupW(hostName);
+
+ HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
+
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
+ lpwhs->lpszUserName = NULL;
+ if (userName[0])
+ lpwhs->lpszUserName = heap_strdupW(userName);
+
+ if (!using_proxy)
+ {
+ if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort)
+ {
+ DWORD res;
+
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
+ lpwhs->lpszServerName = heap_strdupW(hostName);
+ lpwhs->nServerPort = urlComponents.nPort;
+
+ NETCON_close(&lpwhr->netConnection);
+ if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS)
+ return res;
+
+ res = NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE);
+ if (res != ERROR_SUCCESS)
+ return res;
+
+ lpwhr->read_pos = lpwhr->read_size = 0;
+ lpwhr->read_chunked = FALSE;
+ }
+ }
+ else
+ TRACE("Redirect through proxy\n");
}
-
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
+ lpwhr->lpszPath=NULL;
+ if (*path)
{
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
+ DWORD needed = 0;
+ HRESULT rc;
+
+ rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
+ if (rc != E_POINTER)
+ needed = strlenW(path)+1;
+ lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
+ rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
+ URL_ESCAPE_SPACES_ONLY);
+ if (rc != S_OK)
+ {
+ ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
+ strcpyW(lpwhr->lpszPath,path);
+ }
}
- if (lpBuffer == NULL)
- *lpdwBufferLength = 0;
- bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
- lpBuffer, lpdwBufferLength, lpdwIndex);
+ /* Remove custom content-type/length headers on redirects. */
+ index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Type, 0, TRUE);
+ if (0 <= index)
+ HTTP_DeleteCustomHeader(lpwhr, index);
+ index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Length, 0, TRUE);
+ if (0 <= index)
+ HTTP_DeleteCustomHeader(lpwhr, index);
-lend:
- if( lpwhr )
- WININET_Release( &lpwhr->hdr );
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * HTTP_build_req (internal)
+ *
+ * concatenate all the strings in the request together
+ */
+static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
+{
+ LPCWSTR *t;
+ LPWSTR str;
+
+ for( t = list; *t ; t++ )
+ len += strlenW( *t );
+ len++;
+
+ str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ *str = 0;
+
+ for( t = list; *t ; t++ )
+ strcatW( str, *t );
+
+ return str;
+}
+
+static DWORD HTTP_SecureProxyConnect(http_request_t *lpwhr)
+{
+ LPWSTR lpszPath;
+ LPWSTR requestString;
+ INT len;
+ INT cnt;
+ INT responseLen;
+ char *ascii_req;
+ DWORD res;
+ static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
+ static const WCHAR szFormat[] = {'%','s',':','%','d',0};
+ http_session_t *lpwhs = lpwhr->lpHttpSession;
+
+ TRACE("\n");
+
+ lpszPath = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( lpwhs->lpszHostName ) + 13)*sizeof(WCHAR) );
+ sprintfW( lpszPath, szFormat, lpwhs->lpszHostName, lpwhs->nHostPort );
+ requestString = HTTP_BuildHeaderRequestString( lpwhr, szConnect, lpszPath, g_szHttp1_1 );
+ HeapFree( GetProcessHeap(), 0, lpszPath );
+
+ len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
+ NULL, 0, NULL, NULL );
+ len--; /* the nul terminator isn't needed */
+ ascii_req = HeapAlloc( GetProcessHeap(), 0, len );
+ WideCharToMultiByte( CP_ACP, 0, requestString, -1,
+ ascii_req, len, NULL, NULL );
+ HeapFree( GetProcessHeap(), 0, requestString );
+
+ TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
+
+ res = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
+ HeapFree( GetProcessHeap(), 0, ascii_req );
+ if (res != ERROR_SUCCESS)
+ return res;
+
+ responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
+ if (!responseLen)
+ return ERROR_HTTP_INVALID_HEADER;
+
+ return ERROR_SUCCESS;
+}
+
+static void HTTP_InsertCookies(http_request_t *lpwhr)
+{
+ static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
+ LPWSTR lpszCookies, lpszUrl = NULL;
+ DWORD nCookieSize, size;
+ LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+
+ size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR);
+ if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return;
+ sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath);
+
+ if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
+ {
+ int cnt = 0;
+ static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
+
+ size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szCrLf);
+ if ((lpszCookies = HeapAlloc(GetProcessHeap(), 0, size)))
+ {
+ cnt += sprintfW(lpszCookies, szCookie);
+ InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
+ strcatW(lpszCookies, szCrLf);
- TRACE("%d <--\n", bSuccess);
- return bSuccess;
+ HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
+ HeapFree(GetProcessHeap(), 0, lpszCookies);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, lpszUrl);
}
/***********************************************************************
- * HttpQueryInfoA (WININET.@)
+ * HTTP_HttpSendRequestW (internal)
*
- * Queries for information about an HTTP request
+ * Sends the specified request to the HTTP server
*
* RETURNS
* TRUE on success
* FALSE on failure
*
*/
-BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
- LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+static DWORD HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
+ DWORD dwContentLength, BOOL bEndRequest)
{
- BOOL result;
- DWORD len;
- WCHAR* bufferW;
+ INT cnt;
+ BOOL redirected = FALSE;
+ LPWSTR requestString = NULL;
+ INT responseLen;
+ BOOL loop_next;
+ INTERNET_ASYNC_RESULT iar;
+ static const WCHAR szPost[] = { 'P','O','S','T',0 };
+ static const WCHAR szContentLength[] =
+ { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
+ WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
+ DWORD res;
- if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
- (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
+ TRACE("--> %p\n", lpwhr);
+
+ assert(lpwhr->hdr.htype == WH_HHTTPREQ);
+
+ /* if the verb is NULL default to GET */
+ if (!lpwhr->lpszVerb)
+ lpwhr->lpszVerb = heap_strdupW(szGET);
+
+ if (dwContentLength || strcmpW(lpwhr->lpszVerb, szGET))
{
- return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
- lpdwBufferLength, lpdwIndex );
+ sprintfW(contentLengthStr, szContentLength, dwContentLength);
+ HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
+ lpwhr->dwBytesToWrite = dwContentLength;
}
+ if (lpwhr->lpHttpSession->lpAppInfo->lpszAgent)
+ {
+ WCHAR *agent_header;
+ static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0};
+ int len;
- if (lpBuffer)
+ len = strlenW(lpwhr->lpHttpSession->lpAppInfo->lpszAgent) + strlenW(user_agent);
+ agent_header = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ sprintfW(agent_header, user_agent, lpwhr->lpHttpSession->lpAppInfo->lpszAgent);
+
+ HTTP_HttpAddRequestHeadersW(lpwhr, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
+ HeapFree(GetProcessHeap(), 0, agent_header);
+ }
+ if (lpwhr->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE)
{
- len = (*lpdwBufferLength)*sizeof(WCHAR);
- bufferW = HeapAlloc( GetProcessHeap(), 0, len );
- /* buffer is in/out because of HTTP_QUERY_CUSTOM */
- if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
- MultiByteToWideChar(CP_ACP,0,lpBuffer,-1,bufferW,len);
- } else
+ static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0};
+ HTTP_HttpAddRequestHeadersW(lpwhr, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
+ }
+ if ((lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(lpwhr->lpszVerb, szPost))
{
- bufferW = NULL;
- len = 0;
+ static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
+ ' ','n','o','-','c','a','c','h','e','\r','\n',0};
+ HTTP_HttpAddRequestHeadersW(lpwhr, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
}
- result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
- &len, lpdwIndex );
- if( result )
+ do
{
- len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
- lpBuffer, *lpdwBufferLength, NULL, NULL );
- *lpdwBufferLength = len - 1;
+ DWORD len;
+ char *ascii_req;
- TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
- }
- else
- /* since the strings being returned from HttpQueryInfoW should be
- * only ASCII characters, it is reasonable to assume that all of
- * the Unicode characters can be reduced to a single byte */
- *lpdwBufferLength = len / sizeof(WCHAR);
+ loop_next = FALSE;
- HeapFree(GetProcessHeap(), 0, bufferW );
+ /* like native, just in case the caller forgot to call InternetReadFile
+ * for all the data */
+ HTTP_DrainContent(lpwhr);
+ lpwhr->dwContentRead = 0;
- return result;
-}
+ if (TRACE_ON(wininet))
+ {
+ LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+ TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath));
+ }
-/***********************************************************************
- * HttpSendRequestExA (WININET.@)
- *
- * Sends the specified request to the HTTP server and allows chunked
- * transfers.
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE, call GetLastError() for more information.
- */
-BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
- LPINTERNET_BUFFERSA lpBuffersIn,
- LPINTERNET_BUFFERSA lpBuffersOut,
- DWORD dwFlags, DWORD_PTR dwContext)
-{
- INTERNET_BUFFERSW BuffersInW;
- BOOL rc = FALSE;
- DWORD headerlen;
- LPWSTR header = NULL;
+ HTTP_FixURL(lpwhr);
+ if (lpwhr->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION)
+ {
+ HTTP_ProcessHeader(lpwhr, szConnection, szKeepAlive, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+ }
+ HTTP_InsertAuthorization(lpwhr, lpwhr->pAuthInfo, szAuthorization);
+ HTTP_InsertAuthorization(lpwhr, lpwhr->pProxyAuthInfo, szProxy_Authorization);
- TRACE("(%p, %p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersIn,
- lpBuffersOut, dwFlags, dwContext);
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES))
+ HTTP_InsertCookies(lpwhr);
- if (lpBuffersIn)
- {
- BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
- if (lpBuffersIn->lpcszHeader)
+ /* add the headers the caller supplied */
+ if( lpszHeaders && dwHeaderLength )
{
- headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
- lpBuffersIn->dwHeadersLength,0,0);
- header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
- if (!(BuffersInW.lpcszHeader = header))
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- return FALSE;
- }
- BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
- lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
- header, headerlen);
+ HTTP_HttpAddRequestHeadersW(lpwhr, lpszHeaders, dwHeaderLength,
+ HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
+ }
+
+ if (lpwhr->lpHttpSession->lpAppInfo->lpszProxy && lpwhr->lpHttpSession->lpAppInfo->lpszProxy[0])
+ {
+ WCHAR *url = HTTP_BuildProxyRequestUrl(lpwhr);
+ requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, url, lpwhr->lpszVersion);
+ HeapFree(GetProcessHeap(), 0, url);
}
else
- BuffersInW.lpcszHeader = NULL;
- BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
- BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
- BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
- BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
- BuffersInW.Next = NULL;
- }
+ requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
- rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
+
+ TRACE("Request header -> %s\n", debugstr_w(requestString) );
- HeapFree(GetProcessHeap(),0,header);
+ /* Send the request and store the results */
+ if ((res = HTTP_OpenConnection(lpwhr)) != ERROR_SUCCESS)
+ goto lend;
- return rc;
-}
+ /* send the request as ASCII, tack on the optional data */
+ if (!lpOptional || redirected)
+ dwOptionalLength = 0;
+ len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
+ NULL, 0, NULL, NULL );
+ ascii_req = HeapAlloc( GetProcessHeap(), 0, len + dwOptionalLength );
+ WideCharToMultiByte( CP_ACP, 0, requestString, -1,
+ ascii_req, len, NULL, NULL );
+ if( lpOptional )
+ memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
+ len = (len + dwOptionalLength - 1);
+ ascii_req[len] = 0;
+ TRACE("full request -> %s\n", debugstr_a(ascii_req) );
-/***********************************************************************
- * HttpSendRequestExW (WININET.@)
- *
- * Sends the specified request to the HTTP server and allows chunked
- * transfers
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE, call GetLastError() for more information.
- */
-BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
- LPINTERNET_BUFFERSW lpBuffersIn,
- LPINTERNET_BUFFERSW lpBuffersOut,
- DWORD dwFlags, DWORD_PTR dwContext)
-{
- BOOL ret = FALSE;
- LPWININETHTTPREQW lpwhr;
- LPWININETHTTPSESSIONW lpwhs;
- LPWININETAPPINFOW hIC;
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
- TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
- lpBuffersOut, dwFlags, dwContext);
+ res = NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
+ HeapFree( GetProcessHeap(), 0, ascii_req );
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
+ lpwhr->dwBytesWritten = dwOptionalLength;
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
- }
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_REQUEST_SENT,
+ &len, sizeof(DWORD));
- lpwhs = lpwhr->lpHttpSession;
- assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
- hIC = lpwhs->lpAppInfo;
- assert(hIC->hdr.htype == WH_HINIT);
+ if (bEndRequest)
+ {
+ DWORD dwBufferSize;
+ DWORD dwStatusCode;
- if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- WORKREQUEST workRequest;
- struct WORKREQ_HTTPSENDREQUESTW *req;
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+ if (res != ERROR_SUCCESS)
+ goto lend;
+
+ responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
+ sizeof(DWORD));
- workRequest.asyncproc = AsyncHttpSendRequestProc;
- workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
- req = &workRequest.u.HttpSendRequestW;
- if (lpBuffersIn)
- {
- if (lpBuffersIn->lpcszHeader)
- /* FIXME: this should use dwHeadersLength or may not be necessary at all */
- req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader);
- else
- req->lpszHeader = NULL;
- req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
- req->lpOptional = lpBuffersIn->lpvBuffer;
- req->dwOptionalLength = lpBuffersIn->dwBufferLength;
- req->dwContentLength = lpBuffersIn->dwBufferTotal;
+ HTTP_ProcessCookies(lpwhr);
+
+ if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+
+ dwBufferSize = sizeof(dwStatusCode);
+ if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
+ &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS)
+ dwStatusCode = 0;
+
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen)
+ {
+ WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
+ dwBufferSize=sizeof(szNewLocation);
+ if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) &&
+ HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS)
+ {
+ if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
+ {
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+ lpwhr->lpszVerb = heap_strdupW(szGET);
+ }
+ HTTP_DrainContent(lpwhr);
+ if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
+ {
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
+ new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
+ res = HTTP_HandleRedirect(lpwhr, new_url);
+ if (res == ERROR_SUCCESS)
+ {
+ HeapFree(GetProcessHeap(), 0, requestString);
+ loop_next = TRUE;
+ }
+ HeapFree( GetProcessHeap(), 0, new_url );
+ }
+ redirected = TRUE;
+ }
+ }
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS)
+ {
+ WCHAR szAuthValue[2048];
+ dwBufferSize=2048;
+ if (dwStatusCode == HTTP_STATUS_DENIED)
+ {
+ LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+ DWORD dwIndex = 0;
+ while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
+ {
+ if (HTTP_DoAuthorization(lpwhr, szAuthValue,
+ &lpwhr->pAuthInfo,
+ lpwhr->lpHttpSession->lpszUserName,
+ lpwhr->lpHttpSession->lpszPassword,
+ Host->lpszValue))
+ {
+ HeapFree(GetProcessHeap(), 0, requestString);
+ loop_next = TRUE;
+ break;
+ }
+ }
+ }
+ if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
+ {
+ DWORD dwIndex = 0;
+ while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
+ {
+ if (HTTP_DoAuthorization(lpwhr, szAuthValue,
+ &lpwhr->pProxyAuthInfo,
+ lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername,
+ lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword,
+ NULL))
+ {
+ loop_next = TRUE;
+ break;
+ }
+ }
+ }
+ }
}
else
- {
- req->lpszHeader = NULL;
- req->dwHeaderLength = 0;
- req->lpOptional = NULL;
- req->dwOptionalLength = 0;
- req->dwContentLength = 0;
- }
+ res = ERROR_SUCCESS;
+ }
+ while (loop_next);
- req->bEndRequest = FALSE;
+ if(res == ERROR_SUCCESS) {
+ WCHAR url[INTERNET_MAX_URL_LENGTH];
+ WCHAR cacheFileName[MAX_PATH+1];
+ BOOL b;
- INTERNET_AsyncCall(&workRequest);
- /*
- * This is from windows.
- */
- INTERNET_SetLastError(ERROR_IO_PENDING);
+ b = HTTP_GetRequestURL(lpwhr, url);
+ if(!b) {
+ WARN("Could not get URL\n");
+ goto lend;
+ }
+
+ b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0);
+ if(b) {
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
+ CloseHandle(lpwhr->hCacheFile);
+
+ lpwhr->lpszCacheFile = heap_strdupW(cacheFileName);
+ lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) {
+ WARN("Could not create file: %u\n", GetLastError());
+ lpwhr->hCacheFile = NULL;
+ }
+ }else {
+ WARN("Could not create cache entry: %08x\n", GetLastError());
+ }
}
- else
+
+lend:
+
+ HeapFree(GetProcessHeap(), 0, requestString);
+
+ /* TODO: send notification for P3P header */
+
+ if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
- if (lpBuffersIn)
- ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
- lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
- lpBuffersIn->dwBufferTotal, FALSE);
+ if (res == ERROR_SUCCESS && lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite)
+ HTTP_ReceiveRequestData(lpwhr, TRUE);
else
- ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
- }
+ {
+ iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
+ iar.dwError = res;
-lend:
- if ( lpwhr )
- WININET_Release( &lpwhr->hdr );
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+ sizeof(INTERNET_ASYNC_RESULT));
+ }
+ }
- TRACE("<---\n");
- return ret;
+ TRACE("<--\n");
+ return res;
}
/***********************************************************************
- * HttpSendRequestW (WININET.@)
- *
- * Sends the specified request to the HTTP server
*
- * RETURNS
- * TRUE on success
- * FALSE on failure
+ * Helper functions for the HttpSendRequest(Ex) functions
*
*/
-BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
- DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
{
- LPWININETHTTPREQW lpwhr;
- LPWININETHTTPSESSIONW lpwhs = NULL;
- LPWININETAPPINFOW hIC = NULL;
- BOOL r;
+ struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
+ http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
- TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
- debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
+ TRACE("%p\n", lpwhr);
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- r = FALSE;
- goto lend;
- }
+ HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
+ req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
+ req->dwContentLength, req->bEndRequest);
- lpwhs = lpwhr->lpHttpSession;
- if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- r = FALSE;
- goto lend;
- }
+ HeapFree(GetProcessHeap(), 0, req->lpszHeader);
+}
- hIC = lpwhs->lpAppInfo;
- if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- r = FALSE;
- goto lend;
- }
- if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- WORKREQUEST workRequest;
- struct WORKREQ_HTTPSENDREQUESTW *req;
+static DWORD HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+{
+ INT responseLen;
+ DWORD dwBufferSize;
+ INTERNET_ASYNC_RESULT iar;
+ DWORD res = ERROR_SUCCESS;
- workRequest.asyncproc = AsyncHttpSendRequestProc;
- workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
- req = &workRequest.u.HttpSendRequestW;
- if (lpszHeaders)
- {
- req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, dwHeaderLength * sizeof(WCHAR));
- memcpy(req->lpszHeader, lpszHeaders, dwHeaderLength * sizeof(WCHAR));
- }
- else
- req->lpszHeader = 0;
- req->dwHeaderLength = dwHeaderLength;
- req->lpOptional = lpOptional;
- req->dwOptionalLength = dwOptionalLength;
- req->dwContentLength = dwOptionalLength;
- req->bEndRequest = TRUE;
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+ responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
+ if (!responseLen)
+ res = ERROR_HTTP_HEADER_NOT_FOUND;
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
- INTERNET_AsyncCall(&workRequest);
- /*
- * This is from windows.
- */
- INTERNET_SetLastError(ERROR_IO_PENDING);
- r = FALSE;
- }
- else
+ /* process cookies here. Is this right? */
+ HTTP_ProcessCookies(lpwhr);
+
+ if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
{
- r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
- dwHeaderLength, lpOptional, dwOptionalLength,
- dwOptionalLength, TRUE);
+ DWORD dwCode,dwCodeLength = sizeof(DWORD);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) == ERROR_SUCCESS
+ && (dwCode == 302 || dwCode == 301 || dwCode == 303))
+ {
+ WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
+ dwBufferSize=sizeof(szNewLocation);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS)
+ {
+ if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
+ {
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+ lpwhr->lpszVerb = heap_strdupW(szGET);
+ }
+ HTTP_DrainContent(lpwhr);
+ if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
+ {
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
+ new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
+ res = HTTP_HandleRedirect(lpwhr, new_url);
+ if (res == ERROR_SUCCESS)
+ res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
+ HeapFree( GetProcessHeap(), 0, new_url );
+ }
+ }
+ }
}
-lend:
- if( lpwhr )
- WININET_Release( &lpwhr->hdr );
- return r;
+
+ iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
+ iar.dwError = res;
+
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+ sizeof(INTERNET_ASYNC_RESULT));
+ return res;
}
/***********************************************************************
- * HttpSendRequestA (WININET.@)
+ * HttpEndRequestA (WININET.@)
*
- * Sends the specified request to the HTTP server
+ * Ends an HTTP request that was started by HttpSendRequestEx
*
* RETURNS
- * TRUE on success
- * FALSE on failure
+ * TRUE if successful
+ * FALSE on failure
*
*/
-BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
- DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
+ LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
{
- BOOL result;
- LPWSTR szHeaders=NULL;
- DWORD nLen=dwHeaderLength;
- if(lpszHeaders!=NULL)
+ TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
+
+ if (lpBuffersOut)
{
- nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
- szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
- MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
- result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
- HeapFree(GetProcessHeap(),0,szHeaders);
- return result;
+
+ return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
+}
+
+static void AsyncHttpEndRequestProc(WORKREQUEST *work)
+{
+ struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
+ http_request_t *lpwhr = (http_request_t*)work->hdr;
+
+ TRACE("%p\n", lpwhr);
+
+ HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
}
/***********************************************************************
- * HTTP_HandleRedirect (internal)
+ * HttpEndRequestW (WININET.@)
+ *
+ * Ends an HTTP request that was started by HttpSendRequestEx
+ *
+ * RETURNS
+ * TRUE if successful
+ * FALSE on failure
+ *
*/
-static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
+BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
+ LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
{
- LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
- LPWININETAPPINFOW hIC = lpwhs->lpAppInfo;
- WCHAR path[2048];
+ http_request_t *lpwhr;
+ DWORD res;
- if(lpszUrl[0]=='/')
- {
- /* if it's an absolute path, keep the same session info */
- lstrcpynW(path, lpszUrl, 2048);
- }
- else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
+ TRACE("-->\n");
+
+ if (lpBuffersOut)
{
- TRACE("Redirect through proxy\n");
- lstrcpynW(path, lpszUrl, 2048);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
- else
- {
- URL_COMPONENTSW urlComponents;
- WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
- static WCHAR szHttp[] = {'h','t','t','p',0};
- static WCHAR szHttps[] = {'h','t','t','p','s',0};
- DWORD url_length = 0;
- LPWSTR orig_url;
- LPWSTR combined_url;
-
- urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
- urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
- urlComponents.dwSchemeLength = 0;
- urlComponents.lpszHostName = lpwhs->lpszHostName;
- urlComponents.dwHostNameLength = 0;
- urlComponents.nPort = lpwhs->nHostPort;
- urlComponents.lpszUserName = lpwhs->lpszUserName;
- urlComponents.dwUserNameLength = 0;
- urlComponents.lpszPassword = NULL;
- urlComponents.dwPasswordLength = 0;
- urlComponents.lpszUrlPath = lpwhr->lpszPath;
- urlComponents.dwUrlPathLength = 0;
- urlComponents.lpszExtraInfo = NULL;
- urlComponents.dwExtraInfoLength = 0;
-
- if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
- (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
- return FALSE;
- orig_url = HeapAlloc(GetProcessHeap(), 0, url_length);
+ lpwhr = (http_request_t*) WININET_GetObject( hRequest );
- /* convert from bytes to characters */
- url_length = url_length / sizeof(WCHAR) - 1;
- if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
- {
- HeapFree(GetProcessHeap(), 0, orig_url);
- return FALSE;
- }
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ if (lpwhr)
+ WININET_Release( &lpwhr->hdr );
+ return FALSE;
+ }
+ lpwhr->hdr.dwFlags |= dwFlags;
- url_length = 0;
- if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
- (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
- {
- HeapFree(GetProcessHeap(), 0, orig_url);
- return FALSE;
- }
- combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR));
+ if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+ {
+ WORKREQUEST work;
+ struct WORKREQ_HTTPENDREQUESTW *request;
- if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
- {
- HeapFree(GetProcessHeap(), 0, orig_url);
- HeapFree(GetProcessHeap(), 0, combined_url);
- return FALSE;
- }
- HeapFree(GetProcessHeap(), 0, orig_url);
+ work.asyncproc = AsyncHttpEndRequestProc;
+ work.hdr = WININET_AddRef( &lpwhr->hdr );
- userName[0] = 0;
- hostName[0] = 0;
- protocol[0] = 0;
+ request = &work.u.HttpEndRequestW;
+ request->dwFlags = dwFlags;
+ request->dwContext = dwContext;
- urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
- urlComponents.lpszScheme = protocol;
- urlComponents.dwSchemeLength = 32;
- urlComponents.lpszHostName = hostName;
- urlComponents.dwHostNameLength = MAXHOSTNAME;
- urlComponents.lpszUserName = userName;
- urlComponents.dwUserNameLength = 1024;
- urlComponents.lpszPassword = NULL;
- urlComponents.dwPasswordLength = 0;
- urlComponents.lpszUrlPath = path;
- urlComponents.dwUrlPathLength = 2048;
- urlComponents.lpszExtraInfo = NULL;
- urlComponents.dwExtraInfoLength = 0;
- if(!InternetCrackUrlW(combined_url, strlenW(combined_url), 0, &urlComponents))
- {
- HeapFree(GetProcessHeap(), 0, combined_url);
- return FALSE;
- }
- HeapFree(GetProcessHeap(), 0, combined_url);
+ INTERNET_AsyncCall(&work);
+ res = ERROR_IO_PENDING;
+ }
+ else
+ res = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
- if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
- (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
- {
- TRACE("redirect from secure page to non-secure page\n");
- /* FIXME: warn about from secure redirect to non-secure page */
- lpwhr->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
- }
- if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) &&
- !(lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
- {
- TRACE("redirect from non-secure page to secure page\n");
- /* FIXME: notify about redirect to secure page */
- lpwhr->hdr.dwFlags |= INTERNET_FLAG_SECURE;
- }
+ WININET_Release( &lpwhr->hdr );
+ TRACE("%u <--\n", res);
+ if(res != ERROR_SUCCESS)
+ SetLastError(res);
+ return res == ERROR_SUCCESS;
+}
- if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
- {
- if (lstrlenW(protocol)>4) /*https*/
- urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
- else /*http*/
- urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
- }
+/***********************************************************************
+ * HttpSendRequestExA (WININET.@)
+ *
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE, call GetLastError() for more information.
+ */
+BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
+ LPINTERNET_BUFFERSA lpBuffersIn,
+ LPINTERNET_BUFFERSA lpBuffersOut,
+ DWORD dwFlags, DWORD_PTR dwContext)
+{
+ INTERNET_BUFFERSW BuffersInW;
+ BOOL rc = FALSE;
+ DWORD headerlen;
+ LPWSTR header = NULL;
-#if 0
- /*
- * This upsets redirects to binary files on sourceforge.net
- * and gives an html page instead of the target file
- * Examination of the HTTP request sent by native wininet.dll
- * reveals that it doesn't send a referrer in that case.
- * Maybe there's a flag that enables this, or maybe a referrer
- * shouldn't be added in case of a redirect.
- */
+ TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+ lpBuffersOut, dwFlags, dwContext);
- /* consider the current host as the referrer */
- if (NULL != lpwhs->lpszServerName && strlenW(lpwhs->lpszServerName))
- HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
- HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
- HTTP_ADDHDR_FLAG_ADD_IF_NEW);
-#endif
-
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
- lpwhs->lpszServerName = WININET_strdupW(hostName);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
- if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT &&
- urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
+ if (lpBuffersIn)
+ {
+ BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
+ if (lpBuffersIn->lpcszHeader)
{
- int len;
- static const WCHAR fmt[] = {'%','s',':','%','i',0};
- len = lstrlenW(hostName);
- len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
- lpwhs->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
- sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort);
+ headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
+ lpBuffersIn->dwHeadersLength,0,0);
+ header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
+ if (!(BuffersInW.lpcszHeader = header))
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return FALSE;
+ }
+ BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
+ lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+ header, headerlen);
}
else
- lpwhs->lpszHostName = WININET_strdupW(hostName);
-
- HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
-
-
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
- lpwhs->lpszUserName = NULL;
- if (userName[0])
- lpwhs->lpszUserName = WININET_strdupW(userName);
- lpwhs->nServerPort = urlComponents.nPort;
-
- if (!HTTP_ResolveName(lpwhr))
- return FALSE;
-
- NETCON_close(&lpwhr->netConnection);
-
- if (!NETCON_init(&lpwhr->netConnection,lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
- return FALSE;
+ BuffersInW.lpcszHeader = NULL;
+ BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
+ BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
+ BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
+ BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
+ BuffersInW.Next = NULL;
}
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
- lpwhr->lpszPath=NULL;
- if (strlenW(path))
- {
- DWORD needed = 0;
- HRESULT rc;
+ rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
- rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
- if (rc != E_POINTER)
- needed = strlenW(path)+1;
- lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
- rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
- URL_ESCAPE_SPACES_ONLY);
- if (rc)
- {
- ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
- strcpyW(lpwhr->lpszPath,path);
- }
- }
+ HeapFree(GetProcessHeap(),0,header);
- return TRUE;
+ return rc;
}
/***********************************************************************
- * HTTP_build_req (internal)
+ * HttpSendRequestExW (WININET.@)
*
- * concatenate all the strings in the request together
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE, call GetLastError() for more information.
*/
-static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
+BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
+ LPINTERNET_BUFFERSW lpBuffersIn,
+ LPINTERNET_BUFFERSW lpBuffersOut,
+ DWORD dwFlags, DWORD_PTR dwContext)
{
- LPCWSTR *t;
- LPWSTR str;
+ http_request_t *lpwhr;
+ http_session_t *lpwhs;
+ appinfo_t *hIC;
+ DWORD res;
- for( t = list; *t ; t++ )
- len += strlenW( *t );
- len++;
+ TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+ lpBuffersOut, dwFlags, dwContext);
- str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
- *str = 0;
+ lpwhr = (http_request_t*) WININET_GetObject( hRequest );
- for( t = list; *t ; t++ )
- strcatW( str, *t );
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+ goto lend;
+ }
- return str;
-}
+ lpwhs = lpwhr->lpHttpSession;
+ assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
+ hIC = lpwhs->lpAppInfo;
+ assert(hIC->hdr.htype == WH_HINIT);
-static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
-{
- LPWSTR lpszPath;
- LPWSTR requestString;
- INT len;
- INT cnt;
- INT responseLen;
- char *ascii_req;
- BOOL ret;
- static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
- static const WCHAR szFormat[] = {'%','s',':','%','d',0};
- LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+ {
+ WORKREQUEST workRequest;
+ struct WORKREQ_HTTPSENDREQUESTW *req;
- TRACE("\n");
+ workRequest.asyncproc = AsyncHttpSendRequestProc;
+ workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+ req = &workRequest.u.HttpSendRequestW;
+ if (lpBuffersIn)
+ {
+ DWORD size = 0;
- lpszPath = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( lpwhs->lpszHostName ) + 13)*sizeof(WCHAR) );
- sprintfW( lpszPath, szFormat, lpwhs->lpszHostName, lpwhs->nHostPort );
- requestString = HTTP_BuildHeaderRequestString( lpwhr, szConnect, lpszPath, FALSE );
- HeapFree( GetProcessHeap(), 0, lpszPath );
+ if (lpBuffersIn->lpcszHeader)
+ {
+ if (lpBuffersIn->dwHeadersLength == ~0u)
+ size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR);
+ else
+ size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR);
- len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
- NULL, 0, NULL, NULL );
- len--; /* the nul terminator isn't needed */
- ascii_req = HeapAlloc( GetProcessHeap(), 0, len );
- WideCharToMultiByte( CP_ACP, 0, requestString, -1,
- ascii_req, len, NULL, NULL );
- HeapFree( GetProcessHeap(), 0, requestString );
+ req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size );
+ memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size );
+ }
+ else req->lpszHeader = NULL;
- TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
+ req->dwHeaderLength = size / sizeof(WCHAR);
+ req->lpOptional = lpBuffersIn->lpvBuffer;
+ req->dwOptionalLength = lpBuffersIn->dwBufferLength;
+ req->dwContentLength = lpBuffersIn->dwBufferTotal;
+ }
+ else
+ {
+ req->lpszHeader = NULL;
+ req->dwHeaderLength = 0;
+ req->lpOptional = NULL;
+ req->dwOptionalLength = 0;
+ req->dwContentLength = 0;
+ }
- ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
- HeapFree( GetProcessHeap(), 0, ascii_req );
- if (!ret || cnt < 0)
- return FALSE;
+ req->bEndRequest = FALSE;
- responseLen = HTTP_GetResponseHeaders( lpwhr );
- if (!responseLen)
- return FALSE;
+ INTERNET_AsyncCall(&workRequest);
+ /*
+ * This is from windows.
+ */
+ res = ERROR_IO_PENDING;
+ }
+ else
+ {
+ if (lpBuffersIn)
+ res = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+ lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
+ lpBuffersIn->dwBufferTotal, FALSE);
+ else
+ res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
+ }
- return TRUE;
+lend:
+ if ( lpwhr )
+ WININET_Release( &lpwhr->hdr );
+
+ TRACE("<---\n");
+ SetLastError(res);
+ return res == ERROR_SUCCESS;
}
/***********************************************************************
- * HTTP_HttpSendRequestW (internal)
+ * HttpSendRequestW (WININET.@)
*
* Sends the specified request to the HTTP server
*
* FALSE on failure
*
*/
-BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
- DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
- DWORD dwContentLength, BOOL bEndRequest)
+BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
{
- INT cnt;
- BOOL bSuccess = FALSE;
- LPWSTR requestString = NULL;
- INT responseLen;
- BOOL loop_next;
- INTERNET_ASYNC_RESULT iar;
- static const WCHAR szClose[] = { 'C','l','o','s','e',0 };
- static const WCHAR szContentLength[] =
- { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
- WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
-
- TRACE("--> %p\n", lpwhr);
-
- assert(lpwhr->hdr.htype == WH_HHTTPREQ);
+ http_request_t *lpwhr;
+ http_session_t *lpwhs = NULL;
+ appinfo_t *hIC = NULL;
+ DWORD res = ERROR_SUCCESS;
- /* Clear any error information */
- INTERNET_SetLastError(0);
+ TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
+ debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
- HTTP_FixVerb(lpwhr);
-
- sprintfW(contentLengthStr, szContentLength, dwContentLength);
- HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
+ lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+ goto lend;
+ }
- do
+ lpwhs = lpwhr->lpHttpSession;
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
{
- DWORD len;
- char *ascii_req;
+ res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+ goto lend;
+ }
- loop_next = FALSE;
+ hIC = lpwhs->lpAppInfo;
+ if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
+ {
+ res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+ goto lend;
+ }
- /* like native, just in case the caller forgot to call InternetReadFile
- * for all the data */
- HTTP_DrainContent(lpwhr);
- lpwhr->dwContentRead = 0;
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+ {
+ WORKREQUEST workRequest;
+ struct WORKREQ_HTTPSENDREQUESTW *req;
- if (TRACE_ON(wininet))
+ workRequest.asyncproc = AsyncHttpSendRequestProc;
+ workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+ req = &workRequest.u.HttpSendRequestW;
+ if (lpszHeaders)
{
- LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost);
- TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath));
- }
-
- HTTP_FixURL(lpwhr);
- HTTP_ProcessHeader(lpwhr, szConnection,
- lpwhr->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION ? szKeepAlive : szClose,
- HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+ DWORD size;
- HTTP_InsertAuthorization(lpwhr);
- HTTP_InsertProxyAuthorization(lpwhr);
+ if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
+ else size = dwHeaderLength * sizeof(WCHAR);
- /* add the headers the caller supplied */
- if( lpszHeaders && dwHeaderLength )
- {
- HTTP_HttpAddRequestHeadersW(lpwhr, lpszHeaders, dwHeaderLength,
- HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
+ req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size);
+ memcpy(req->lpszHeader, lpszHeaders, size);
}
+ else
+ req->lpszHeader = 0;
+ req->dwHeaderLength = dwHeaderLength;
+ req->lpOptional = lpOptional;
+ req->dwOptionalLength = dwOptionalLength;
+ req->dwContentLength = dwOptionalLength;
+ req->bEndRequest = TRUE;
- requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, FALSE);
-
- TRACE("Request header -> %s\n", debugstr_w(requestString) );
-
- /* Send the request and store the results */
- if (!HTTP_OpenConnection(lpwhr))
- goto lend;
-
- /* send the request as ASCII, tack on the optional data */
- if( !lpOptional )
- dwOptionalLength = 0;
- len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
- NULL, 0, NULL, NULL );
- ascii_req = HeapAlloc( GetProcessHeap(), 0, len + dwOptionalLength );
- WideCharToMultiByte( CP_ACP, 0, requestString, -1,
- ascii_req, len, NULL, NULL );
- if( lpOptional )
- memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
- len = (len + dwOptionalLength - 1);
- ascii_req[len] = 0;
- TRACE("full request -> %s\n", debugstr_a(ascii_req) );
-
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
+ INTERNET_AsyncCall(&workRequest);
+ /*
+ * This is from windows.
+ */
+ res = ERROR_IO_PENDING;
+ }
+ else
+ {
+ res = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
+ dwHeaderLength, lpOptional, dwOptionalLength,
+ dwOptionalLength, TRUE);
+ }
+lend:
+ if( lpwhr )
+ WININET_Release( &lpwhr->hdr );
- NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
- HeapFree( GetProcessHeap(), 0, ascii_req );
+ SetLastError(res);
+ return res == ERROR_SUCCESS;
+}
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_REQUEST_SENT,
- &len, sizeof(DWORD));
+/***********************************************************************
+ * HttpSendRequestA (WININET.@)
+ *
+ * Sends the specified request to the HTTP server
+ *
+ * RETURNS
+ * TRUE on success
+ * FALSE on failure
+ *
+ */
+BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+{
+ BOOL result;
+ LPWSTR szHeaders=NULL;
+ DWORD nLen=dwHeaderLength;
+ if(lpszHeaders!=NULL)
+ {
+ nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
+ szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
+ }
+ result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
+ HeapFree(GetProcessHeap(),0,szHeaders);
+ return result;
+}
- if (bEndRequest)
- {
- DWORD dwBufferSize;
- DWORD dwStatusCode;
+/***********************************************************************
+ * HTTPSESSION_Destroy (internal)
+ *
+ * Deallocate session handle
+ *
+ */
+static void HTTPSESSION_Destroy(object_header_t *hdr)
+{
+ http_session_t *lpwhs = (http_session_t*) hdr;
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
- if (cnt < 0)
- goto lend;
-
- responseLen = HTTP_GetResponseHeaders(lpwhr);
- if (responseLen)
- bSuccess = TRUE;
-
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
- sizeof(DWORD));
+ TRACE("%p\n", lpwhs);
- HTTP_ProcessHeaders(lpwhr);
+ WININET_Release(&lpwhs->lpAppInfo->hdr);
- dwBufferSize = sizeof(lpwhr->dwContentLength);
- if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
- &lpwhr->dwContentLength,&dwBufferSize,NULL))
- lpwhr->dwContentLength = -1;
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
+ HeapFree(GetProcessHeap(), 0, lpwhs);
+}
- if (lpwhr->dwContentLength == 0)
- HTTP_FinishedReading(lpwhr);
+static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+{
+ switch(option) {
+ case INTERNET_OPTION_HANDLE_TYPE:
+ TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
- dwBufferSize = sizeof(dwStatusCode);
- if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
- &dwStatusCode,&dwBufferSize,NULL))
- dwStatusCode = 0;
+ if (*size < sizeof(ULONG))
+ return ERROR_INSUFFICIENT_BUFFER;
- if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
- {
- WCHAR szNewLocation[2048];
- dwBufferSize=sizeof(szNewLocation);
- if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) &&
- HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL))
- {
- HTTP_DrainContent(lpwhr);
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_REDIRECT, szNewLocation,
- dwBufferSize);
- bSuccess = HTTP_HandleRedirect(lpwhr, szNewLocation);
- if (bSuccess)
- {
- HeapFree(GetProcessHeap(), 0, requestString);
- loop_next = TRUE;
- }
- }
- }
- if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess)
- {
- WCHAR szAuthValue[2048];
- dwBufferSize=2048;
- if (dwStatusCode == HTTP_STATUS_DENIED)
- {
- DWORD dwIndex = 0;
- while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex))
- {
- if (HTTP_DoAuthorization(lpwhr, szAuthValue,
- &lpwhr->pAuthInfo,
- lpwhr->lpHttpSession->lpszUserName,
- lpwhr->lpHttpSession->lpszPassword))
- {
- loop_next = TRUE;
- break;
- }
- }
- }
- if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
- {
- DWORD dwIndex = 0;
- while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex))
- {
- if (HTTP_DoAuthorization(lpwhr, szAuthValue,
- &lpwhr->pProxyAuthInfo,
- lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername,
- lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword))
- {
- loop_next = TRUE;
- break;
- }
- }
- }
- }
- }
- else
- bSuccess = TRUE;
+ *size = sizeof(DWORD);
+ *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
+ return ERROR_SUCCESS;
}
- while (loop_next);
-lend:
+ return INET_QueryOption(option, buffer, size, unicode);
+}
- HeapFree(GetProcessHeap(), 0, requestString);
+static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
+{
+ http_session_t *ses = (http_session_t*)hdr;
- /* TODO: send notification for P3P header */
+ switch(option) {
+ case INTERNET_OPTION_USERNAME:
+ {
+ HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
+ if (!(ses->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+ return ERROR_SUCCESS;
+ }
+ case INTERNET_OPTION_PASSWORD:
+ {
+ HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
+ if (!(ses->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+ return ERROR_SUCCESS;
+ }
+ default: break;
+ }
- iar.dwResult = (DWORD)bSuccess;
- iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
+ return ERROR_INTERNET_INVALID_OPTION;
+}
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_REQUEST_COMPLETE, &iar,
- sizeof(INTERNET_ASYNC_RESULT));
+static const object_vtbl_t HTTPSESSIONVtbl = {
+ HTTPSESSION_Destroy,
+ NULL,
+ HTTPSESSION_QueryOption,
+ HTTPSESSION_SetOption,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
- TRACE("<--\n");
- return bSuccess;
-}
/***********************************************************************
* HTTP_Connect (internal)
* NULL on failure
*
*/
-HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
- INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
- LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
- DWORD dwInternalFlags)
+DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
+ INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
+ LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
+ DWORD dwInternalFlags, HINTERNET *ret)
{
- BOOL bSuccess = FALSE;
- LPWININETHTTPSESSIONW lpwhs = NULL;
+ http_session_t *lpwhs = NULL;
HINTERNET handle = NULL;
+ DWORD res = ERROR_SUCCESS;
TRACE("-->\n");
+ if (!lpszServerName || !lpszServerName[0])
+ return ERROR_INVALID_PARAMETER;
+
assert( hIC->hdr.htype == WH_HINIT );
- lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
- if (NULL == lpwhs)
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lerror;
- }
+ lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t));
+ if (!lpwhs)
+ return ERROR_OUTOFMEMORY;
/*
* According to my tests. The name is not resolved until a request is sent
*/
lpwhs->hdr.htype = WH_HHTTPSESSION;
+ lpwhs->hdr.vtbl = &HTTPSESSIONVtbl;
lpwhs->hdr.dwFlags = dwFlags;
lpwhs->hdr.dwContext = dwContext;
lpwhs->hdr.dwInternalFlags = dwInternalFlags | (hIC->hdr.dwInternalFlags & INET_CALLBACKW);
- lpwhs->hdr.dwRefCount = 1;
- lpwhs->hdr.close_connection = NULL;
- lpwhs->hdr.destroy = HTTP_CloseHTTPSessionHandle;
+ lpwhs->hdr.refs = 1;
lpwhs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
WININET_AddRef( &hIC->hdr );
if (NULL == handle)
{
ERR("Failed to alloc handle\n");
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lerror;
+ res = ERROR_OUTOFMEMORY;
+ goto lerror;
}
if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
- if(strchrW(hIC->lpszProxy, ' '))
- FIXME("Several proxies not implemented.\n");
if(hIC->lpszProxyBypass)
FIXME("Proxy bypass is ignored.\n");
}
if (lpszServerName && lpszServerName[0])
{
- lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
- lpwhs->lpszHostName = WININET_strdupW(lpszServerName);
+ lpwhs->lpszServerName = heap_strdupW(lpszServerName);
+ lpwhs->lpszHostName = heap_strdupW(lpszServerName);
}
if (lpszUserName && lpszUserName[0])
- lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
+ lpwhs->lpszUserName = heap_strdupW(lpszUserName);
if (lpszPassword && lpszPassword[0])
- lpwhs->lpszPassword = WININET_strdupW(lpszPassword);
+ lpwhs->lpszPassword = heap_strdupW(lpszPassword);
lpwhs->nServerPort = nServerPort;
lpwhs->nHostPort = nServerPort;
sizeof(handle));
}
- bSuccess = TRUE;
-
lerror:
if( lpwhs )
WININET_Release( &lpwhs->hdr );
*/
TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
- return handle;
+
+ if(res == ERROR_SUCCESS)
+ *ret = handle;
+ return res;
}
* TRUE on success
* FALSE on failure
*/
-static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
+static DWORD HTTP_OpenConnection(http_request_t *lpwhr)
{
- BOOL bSuccess = FALSE;
- LPWININETHTTPSESSIONW lpwhs;
- LPWININETAPPINFOW hIC = NULL;
- char szaddr[32];
+ http_session_t *lpwhs;
+ appinfo_t *hIC = NULL;
+ char szaddr[INET6_ADDRSTRLEN];
+ const void *addr;
+ DWORD res = ERROR_SUCCESS;
TRACE("-->\n");
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ if (lpwhr->hdr.htype != WH_HHTTPREQ)
{
- INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ res = ERROR_INVALID_PARAMETER;
goto lend;
}
if (NETCON_connected(&lpwhr->netConnection))
- {
- bSuccess = TRUE;
goto lend;
- }
+ if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) goto lend;
lpwhs = lpwhr->lpHttpSession;
hIC = lpwhs->lpAppInfo;
- inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr,
- szaddr, sizeof(szaddr));
+ switch (lpwhs->socketAddress.ss_family)
+ {
+ case AF_INET:
+ addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
+ break;
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
+ break;
+ default:
+ WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
+ return ERROR_INTERNET_NAME_NOT_RESOLVED;
+ }
+ inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
INTERNET_STATUS_CONNECTING_TO_SERVER,
szaddr,
strlen(szaddr)+1);
- if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.sin_family,
- SOCK_STREAM, 0))
+ res = NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family, SOCK_STREAM, 0);
+ if (res != ERROR_SUCCESS)
{
- WARN("Socket creation failed\n");
+ WARN("Socket creation failed: %u\n", res);
goto lend;
}
- if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
- sizeof(lpwhs->socketAddress)))
+ res = NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
+ lpwhs->sa_len);
+ if(res != ERROR_SUCCESS)
goto lend;
if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
* behaviour to be more correct and to not cause any incompatibilities
* because using a secure connection through a proxy server is a rare
* case that would be hard for anyone to depend on */
- if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr))
+ if (hIC->lpszProxy && (res = HTTP_SecureProxyConnect(lpwhr)) != ERROR_SUCCESS)
goto lend;
- if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName))
+ res = NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName);
+ if(res != ERROR_SUCCESS)
{
WARN("Couldn't connect securely to host\n");
goto lend;
INTERNET_STATUS_CONNECTED_TO_SERVER,
szaddr, strlen(szaddr)+1);
- bSuccess = TRUE;
-
lend:
- TRACE("%d <--\n", bSuccess);
- return bSuccess;
+ lpwhr->read_pos = lpwhr->read_size = 0;
+ lpwhr->read_chunked = FALSE;
+
+ TRACE("%d <--\n", res);
+ return res;
}
*
* clear out any old response headers
*/
-static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
+static void HTTP_clear_response_headers( http_request_t *lpwhr )
{
DWORD i;
* TRUE on success
* FALSE on error
*/
-static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
+static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
{
INT cbreaks = 0;
WCHAR buffer[MAX_REPLY_LEN];
DWORD buflen = MAX_REPLY_LEN;
BOOL bSuccess = FALSE;
INT rc = 0;
- static const WCHAR szCrLf[] = {'\r','\n',0};
char bufferA[MAX_REPLY_LEN];
- LPWSTR status_code, status_text;
+ LPWSTR status_code = NULL, status_text = NULL;
DWORD cchMaxRawHeaders = 1024;
- LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+ LPWSTR lpszRawHeaders = NULL;
+ LPWSTR temp;
DWORD cchRawHeaders = 0;
+ BOOL codeHundred = FALSE;
TRACE("-->\n");
/* clear old response headers (eg. from a redirect response) */
- HTTP_clear_response_headers( lpwhr );
+ if (clear) HTTP_clear_response_headers( lpwhr );
if (!NETCON_connected(&lpwhr->netConnection))
goto lend;
- /*
- * HACK peek at the buffer
- */
- NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
+ do {
+ static const WCHAR szHundred[] = {'1','0','0',0};
+ /*
+ * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
+ */
+ buflen = MAX_REPLY_LEN;
+ if (!read_line(lpwhr, bufferA, &buflen))
+ goto lend;
+ rc += buflen;
+ MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
+ /* check is this a status code line? */
+ if (!strncmpW(buffer, g_szHttp1_0, 4))
+ {
+ /* split the version from the status code */
+ status_code = strchrW( buffer, ' ' );
+ if( !status_code )
+ goto lend;
+ *status_code++=0;
- /*
- * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
- */
- buflen = MAX_REPLY_LEN;
- memset(buffer, 0, MAX_REPLY_LEN);
- if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
- goto lend;
- MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
+ /* split the status code from the status text */
+ status_text = strchrW( status_code, ' ' );
+ if( !status_text )
+ goto lend;
+ *status_text++=0;
- /* regenerate raw headers */
- while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
- {
- cchMaxRawHeaders *= 2;
- lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
- }
- memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
- cchRawHeaders += (buflen-1);
- memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
- cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
- lpszRawHeaders[cchRawHeaders] = '\0';
+ TRACE("version [%s] status code [%s] status text [%s]\n",
+ debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
- /* split the version from the status code */
- status_code = strchrW( buffer, ' ' );
- if( !status_code )
- goto lend;
- *status_code++=0;
+ codeHundred = (!strcmpW(status_code, szHundred));
+ }
+ else if (!codeHundred)
+ {
+ WARN("No status line at head of response (%s)\n", debugstr_w(buffer));
- /* split the status code from the status text */
- status_text = strchrW( status_code, ' ' );
- if( !status_text )
- goto lend;
- *status_text++=0;
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
- TRACE("version [%s] status code [%s] status text [%s]\n",
- debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
+ lpwhr->lpszVersion = heap_strdupW(g_szHttp1_0);
+ lpwhr->lpszStatusText = heap_strdupW(szOK);
+
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
+ lpwhr->lpszRawHeaders = heap_strdupW(szDefaultHeader);
+
+ bSuccess = TRUE;
+ goto lend;
+ }
+ } while (codeHundred);
+ /* Add status code */
HTTP_ProcessHeader(lpwhr, szStatus, status_code,
HTTP_ADDHDR_FLAG_REPLACE);
HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
- lpwhr->lpszVersion= WININET_strdupW(buffer);
- lpwhr->lpszStatusText = WININET_strdupW(status_text);
+ lpwhr->lpszVersion = heap_strdupW(buffer);
+ lpwhr->lpszStatusText = heap_strdupW(status_text);
+
+ /* Restore the spaces */
+ *(status_code-1) = ' ';
+ *(status_text-1) = ' ';
+
+ /* regenerate raw headers */
+ lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
+ if (!lpszRawHeaders) goto lend;
+
+ while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+ cchMaxRawHeaders *= 2;
+ temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+ if (temp == NULL) goto lend;
+ lpszRawHeaders = temp;
+ memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
+ cchRawHeaders += (buflen-1);
+ memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
+ cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
+ lpszRawHeaders[cchRawHeaders] = '\0';
/* Parse each response line */
do
{
buflen = MAX_REPLY_LEN;
- if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
+ if (read_line(lpwhr, bufferA, &buflen))
{
LPWSTR * pFieldAndValue;
TRACE("got line %s, now interpreting\n", debugstr_a(bufferA));
+
+ if (!bufferA[0]) break;
MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
- while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+ pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
+ if (pFieldAndValue)
{
- cchMaxRawHeaders *= 2;
- lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+ while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+ cchMaxRawHeaders *= 2;
+ temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+ if (temp == NULL) goto lend;
+ lpszRawHeaders = temp;
+ memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
+ cchRawHeaders += (buflen-1);
+ memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
+ cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
+ lpszRawHeaders[cchRawHeaders] = '\0';
+
+ HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1],
+ HTTP_ADDREQ_FLAG_ADD );
+
+ HTTP_FreeTokens(pFieldAndValue);
}
- memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
- cchRawHeaders += (buflen-1);
- memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
- cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
- lpszRawHeaders[cchRawHeaders] = '\0';
-
- pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
- if (!pFieldAndValue)
- break;
-
- HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1],
- HTTP_ADDREQ_FLAG_ADD );
-
- HTTP_FreeTokens(pFieldAndValue);
- }
+ }
else
{
cbreaks++;
}
}while(1);
+ /* make sure the response header is terminated with an empty line. Some apps really
+ truly care about that empty line being there for some reason. Just add it to the
+ header. */
+ if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
+ {
+ cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
+ temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
+ if (temp == NULL) goto lend;
+ lpszRawHeaders = temp;
+ }
+
+ memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
+
HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
lpwhr->lpszRawHeaders = lpszRawHeaders;
TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
if (bSuccess)
return rc;
else
- return 0;
-}
-
-
-static void strip_spaces(LPWSTR start)
-{
- LPWSTR str = start;
- LPWSTR end;
-
- while (*str == ' ' && *str != '\0')
- str++;
-
- if (str != start)
- memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
-
- end = start + strlenW(start) - 1;
- while (end >= start && *end == ' ')
{
- *end = '\0';
- end--;
+ HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
+ return 0;
}
}
-
/***********************************************************************
* HTTP_InterpretHttpHeader (internal)
*
#define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
-static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
+static DWORD HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
{
LPHTTPHEADERW lphttpHdr = NULL;
- BOOL bSuccess = FALSE;
INT index = -1;
BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
+ DWORD res = ERROR_HTTP_INVALID_HEADER;
TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
if (index >= 0)
{
if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
- {
- return FALSE;
- }
+ return ERROR_HTTP_INVALID_HEADER;
lphttpHdr = &lpwhr->pCustHeaders[index];
}
else if (value)
return HTTP_InsertCustomHeader(lpwhr, &hdr);
}
/* no value to delete */
- else return TRUE;
+ else return ERROR_SUCCESS;
if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
lphttpHdr->wFlags |= HDR_ISREQUEST;
return HTTP_InsertCustomHeader(lpwhr, &hdr);
}
- return TRUE;
+ return ERROR_SUCCESS;
}
else if (dwModifier & COALESCEFLAGS)
{
memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
lphttpHdr->lpszValue[len] = '\0';
- bSuccess = TRUE;
+ res = ERROR_SUCCESS;
}
else
{
WARN("HeapReAlloc (%d bytes) failed\n",len+1);
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ res = ERROR_OUTOFMEMORY;
}
}
- TRACE("<-- %d\n",bSuccess);
- return bSuccess;
-}
-
-
-/***********************************************************************
- * HTTP_CloseConnection (internal)
- *
- * Close socket connection
- *
- */
-static void HTTP_CloseConnection(LPWININETHANDLEHEADER hdr)
-{
- LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr;
- LPWININETHTTPSESSIONW lpwhs = NULL;
- LPWININETAPPINFOW hIC = NULL;
-
- TRACE("%p\n",lpwhr);
-
- if (!NETCON_connected(&lpwhr->netConnection))
- return;
-
- if (lpwhr->pAuthInfo)
- {
- DeleteSecurityContext(&lpwhr->pAuthInfo->ctx);
- FreeCredentialsHandle(&lpwhr->pAuthInfo->cred);
-
- HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data);
- HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->scheme);
- HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo);
- lpwhr->pAuthInfo = NULL;
- }
- if (lpwhr->pProxyAuthInfo)
- {
- DeleteSecurityContext(&lpwhr->pProxyAuthInfo->ctx);
- FreeCredentialsHandle(&lpwhr->pProxyAuthInfo->cred);
-
- HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->auth_data);
- HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->scheme);
- HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo);
- lpwhr->pProxyAuthInfo = NULL;
- }
-
- lpwhs = lpwhr->lpHttpSession;
- hIC = lpwhs->lpAppInfo;
-
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
-
- NETCON_close(&lpwhr->netConnection);
-
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
+ TRACE("<-- %d\n", res);
+ return res;
}
* Called when all content from server has been read by client.
*
*/
-BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr)
+static BOOL HTTP_FinishedReading(http_request_t *lpwhr)
{
- WCHAR szConnectionResponse[20];
- DWORD dwBufferSize = sizeof(szConnectionResponse);
+ BOOL keepalive = HTTP_KeepAlive(lpwhr);
TRACE("\n");
- if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse,
- &dwBufferSize, NULL) ||
- strcmpiW(szConnectionResponse, szKeepAlive))
+
+ if (!keepalive)
{
- HTTP_CloseConnection(&lpwhr->hdr);
+ HTTPREQ_CloseConnection(&lpwhr->hdr);
}
/* FIXME: store data in the URL cache here */
return TRUE;
}
-/***********************************************************************
- * HTTP_CloseHTTPRequestHandle (internal)
- *
- * Deallocate request handle
- *
- */
-static void HTTP_CloseHTTPRequestHandle(LPWININETHANDLEHEADER hdr)
-{
- DWORD i;
- LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr;
-
- TRACE("\n");
-
- WININET_Release(&lpwhr->lpHttpSession->hdr);
-
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
-
- for (i = 0; i < lpwhr->nCustHeaders; i++)
- {
- HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
- HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
- }
-
- HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
- HeapFree(GetProcessHeap(), 0, lpwhr);
-}
-
-
-/***********************************************************************
- * HTTP_CloseHTTPSessionHandle (internal)
- *
- * Deallocate session handle
- *
- */
-static void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr)
-{
- LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
-
- TRACE("%p\n", lpwhs);
-
- WININET_Release(&lpwhs->lpAppInfo->hdr);
-
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
- HeapFree(GetProcessHeap(), 0, lpwhs);
-}
-
/***********************************************************************
* HTTP_GetCustomHeaderIndex (internal)
* Return index of custom header from header array
*
*/
-static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField,
+static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField,
int requested_index, BOOL request_only)
{
DWORD index;
- TRACE("%s\n", debugstr_w(lpszField));
+ TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only);
for (index = 0; index < lpwhr->nCustHeaders; index++)
{
* Insert header into array
*
*/
-static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
+static DWORD HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
{
INT count;
LPHTTPHEADERW lph = NULL;
- BOOL r = FALSE;
TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
count = lpwhr->nCustHeaders + 1;
else
lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
- if (NULL != lph)
- {
- lpwhr->pCustHeaders = lph;
- lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField);
- lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue);
- lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
- lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
- lpwhr->nCustHeaders++;
- r = TRUE;
- }
- else
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- }
+ if (!lph)
+ return ERROR_OUTOFMEMORY;
- return r;
+ lpwhr->pCustHeaders = lph;
+ lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
+ lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
+ lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
+ lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
+ lpwhr->nCustHeaders++;
+
+ return ERROR_SUCCESS;
}
* Delete header from array
* If this function is called, the indexs may change.
*/
-static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index)
+static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index)
{
if( lpwhr->nCustHeaders <= 0 )
return FALSE;
return FALSE;
lpwhr->nCustHeaders--;
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszField);
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszValue);
+
memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
(lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
* Verify the given header is not invalid for the given http request
*
*/
-static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field)
+static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field)
{
- BOOL rc = TRUE;
-
/* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
- if (strcmpiW(field,szAccept_Encoding)==0)
- return FALSE;
+ if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
+ return ERROR_HTTP_INVALID_HEADER;
- return rc;
+ return ERROR_SUCCESS;
}
/***********************************************************************