[1/2] wininet: Reorder the http functions to avoid forward declarations.
Francois Gouget
fgouget at free.fr
Mon Jun 22 03:46:17 CDT 2009
---
dlls/wininet/http.c | 4801 +++++++++++++++++++++++------------------------
dlls/wininet/internet.h | 8 -
2 files changed, 2394 insertions(+), 2415 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index e1a7ddc..2c72827 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -176,113 +175,80 @@ struct gzip_stream_t {
BOOL end_of_data;
};
-static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
-static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear);
-static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, 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 LPWSTR HTTP_build_req( LPCWSTR *list, int len );
-static BOOL HTTP_HttpQueryInfoW(LPWININETHTTPREQW, DWORD, LPVOID, LPDWORD, LPDWORD);
-static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl);
-static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl);
-static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
-static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field);
-static void HTTP_DrainContent(WININETHTTPREQW *req);
-static BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr);
-static LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
-{
- int HeaderIndex = 0;
- HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
- if (HeaderIndex == -1)
- return NULL;
- else
- 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)
+/* read some more data into the read buffer (the read section must be held) */
+static BOOL read_more_data( WININETHTTPREQW *req, int maxlen )
{
- HeapFree(GetProcessHeap(), 0, address);
-}
+ int len;
-static void init_gzip_stream(WININETHTTPREQW *req)
-{
- gzip_stream_t *gzip_stream;
- int zres;
+ 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;
+ }
- 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;
+ if (maxlen == -1) maxlen = sizeof(req->read_buf);
- zres = inflateInit2(&gzip_stream->zstream, 0x1f);
- if(zres != Z_OK) {
- ERR("inflateInit failed: %d\n", zres);
- HeapFree(GetProcessHeap(), 0, gzip_stream);
- return;
- }
+ if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
+ maxlen - req->read_size, 0, &len ))
+ return FALSE;
- req->gzip_stream = gzip_stream;
+ req->read_size += len;
+ return TRUE;
}
-#else
-
-static void init_gzip_stream(WININETHTTPREQW *req)
+/* remove some amount of data from the read buffer (the read section must be held) */
+static void remove_data( WININETHTTPREQW *req, int count )
{
- ERR("gzip stream not supported, missing zlib.\n");
+ if (!(req->read_size -= count)) req->read_pos = 0;
+ else req->read_pos += count;
}
-#endif
-
-/* set the request content length based on the headers */
-static DWORD set_content_length( LPWININETHTTPREQW lpwhr )
+static BOOL read_line( WININETHTTPREQW *req, LPSTR buffer, DWORD *len )
{
- 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))
- lpwhr->dwContentLength = ~0u;
+ int count, bytes_read, pos = 0;
- size = sizeof(encoding);
- if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
- !strcmpiW(encoding, szChunked))
+ EnterCriticalSection( &req->read_section );
+ for (;;)
{
- lpwhr->dwContentLength = ~0u;
- lpwhr->read_chunked = TRUE;
- }
+ BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
- if(lpwhr->decoding) {
- int encoding_idx;
+ if (eol)
+ {
+ count = eol - (req->read_buf + req->read_pos);
+ bytes_read = count + 1;
+ }
+ else count = bytes_read = req->read_size;
- static const WCHAR gzipW[] = {'g','z','i','p',0};
+ 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;
- encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
- if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
- init_gzip_stream(lpwhr);
+ if (!read_more_data( req, -1 ) || !req->read_size)
+ {
+ *len = 0;
+ TRACE( "returning empty string\n" );
+ LeaveCriticalSection( &req->read_section );
+ return FALSE;
+ }
}
+ LeaveCriticalSection( &req->read_section );
- return lpwhr->dwContentLength;
+ 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;
}
+
/***********************************************************************
* HTTP_Tokenize (internal)
*
@@ -348,366 +314,498 @@ static void HTTP_FreeTokens(LPWSTR * token_array)
HeapFree(GetProcessHeap(), 0, token_array);
}
-/* **********************************************************************
- *
- * Helper functions for the HttpSendRequest(Ex) functions
- *
+
+/***********************************************************************
+ * HTTP_GetCustomHeaderIndex (internal)
+ *
+ * Return index of custom header from header array
+ *
*/
-static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
+static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField,
+ int requested_index, BOOL request_only)
{
- struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
- LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr;
+ DWORD index;
- TRACE("%p\n", lpwhr);
+ TRACE("%s\n", debugstr_w(lpszField));
- HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
- req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
- req->dwContentLength, req->bEndRequest);
+ for (index = 0; index < lpwhr->nCustHeaders; index++)
+ {
+ if (strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
+ continue;
- HeapFree(GetProcessHeap(), 0, req->lpszHeader);
+ if (request_only && !(lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
+ continue;
+
+ if (!request_only && (lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
+ continue;
+
+ if (requested_index == 0)
+ break;
+ requested_index --;
+ }
+
+ if (index >= lpwhr->nCustHeaders)
+ index = -1;
+
+ TRACE("Return: %d\n", index);
+ return index;
}
-static void HTTP_FixURL( LPWININETHTTPREQW lpwhr)
+
+static LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
{
- static const WCHAR szSlash[] = { '/',0 };
- static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
+ int HeaderIndex = 0;
+ HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
+ if (HeaderIndex == -1)
+ return NULL;
+ else
+ return &req->pCustHeaders[HeaderIndex];
+}
- /* If we don't have a path we set it to root */
- if (NULL == lpwhr->lpszPath)
- lpwhr->lpszPath = WININET_strdupW(szSlash);
- else /* remove \r and \n*/
+
+/***********************************************************************
+ * HTTP_InsertCustomHeader (internal)
+ *
+ * Insert header into array
+ *
+ */
+static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW 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;
+ if (count > 1)
+ lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
+ else
+ lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
+
+ if (NULL != lph)
{
- int nLen = strlenW(lpwhr->lpszPath);
- while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
- {
- nLen--;
- lpwhr->lpszPath[nLen]='\0';
- }
- /* Replace '\' with '/' */
- while (nLen>0) {
- nLen--;
- if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
- }
+ 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;
}
-
- if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
- lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
- && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
+ else
{
- WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0,
- (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
- *fixurl = '/';
- strcpyW(fixurl + 1, lpwhr->lpszPath);
- HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
- lpwhr->lpszPath = fixurl;
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
}
+
+ return r;
}
-static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
+
+/***********************************************************************
+ * HTTP_DeleteCustomHeader (internal)
+ *
+ * Delete header from array
+ * If this function is called, the indexs may change.
+ */
+static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index)
{
- LPWSTR requestString;
- DWORD len, n;
- LPCWSTR *req;
- UINT i;
- LPWSTR p;
+ if( lpwhr->nCustHeaders <= 0 )
+ return FALSE;
+ if( index >= lpwhr->nCustHeaders )
+ return FALSE;
+ lpwhr->nCustHeaders--;
- static const WCHAR szSpace[] = { ' ',0 };
- static const WCHAR szColon[] = { ':',' ',0 };
- static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszField);
+ HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszValue);
- /* allocate space for an array of all the string pointers to be added */
- len = (lpwhr->nCustHeaders)*4 + 10;
- req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
+ memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
+ (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
+ memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
- /* add the verb, path and HTTP version string */
- n = 0;
- req[n++] = verb;
- req[n++] = szSpace;
- req[n++] = path;
- req[n++] = szSpace;
- req[n++] = version;
+ return TRUE;
+}
- /* Append custom request headers */
- for (i = 0; i < lpwhr->nCustHeaders; i++)
- {
- if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
- {
- req[n++] = szCrLf;
- req[n++] = lpwhr->pCustHeaders[i].lpszField;
- req[n++] = szColon;
- req[n++] = lpwhr->pCustHeaders[i].lpszValue;
- TRACE("Adding custom header %s (%s)\n",
- debugstr_w(lpwhr->pCustHeaders[i].lpszField),
- debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
- }
- }
+/***********************************************************************
+ * HTTP_VerifyValidHeader (internal)
+ *
+ * Verify the given header is not invalid for the given http request
+ *
+ */
+static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field)
+{
+ /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
+ if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
+ return FALSE;
- if( n >= len )
- ERR("oops. buffer overrun\n");
+ return TRUE;
+}
- req[n] = NULL;
- requestString = HTTP_build_req( req, 4 );
- HeapFree( GetProcessHeap(), 0, req );
- /*
- * Set (header) termination string for request
- * Make sure there's exactly two new lines at the end of the request
- */
- p = &requestString[strlenW(requestString)-1];
- while ( (*p == '\n') || (*p == '\r') )
- p--;
- strcpyW( p+1, sztwocrlf );
-
- return requestString;
+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 void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr )
+
+/***********************************************************************
+ * HTTP_InterpretHttpHeader (internal)
+ *
+ * Parse server response
+ *
+ * RETURNS
+ *
+ * Pointer to array of field, value, NULL on success.
+ * NULL on error.
+ */
+static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
{
- int HeaderIndex;
- int numCookies = 0;
- LPHTTPHEADERW setCookieHeader;
+ LPWSTR * pTokenPair;
+ LPWSTR pszColon;
+ INT len;
- while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
- {
- setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
+ pTokenPair = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTokenPair)*3);
- if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
- {
- int len;
- static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
- LPWSTR buf_url;
- LPHTTPHEADERW Host;
+ pszColon = strchrW(buffer, ':');
+ /* must have two tokens */
+ if (!pszColon)
+ {
+ HTTP_FreeTokens(pTokenPair);
+ if (buffer[0])
+ TRACE("No ':' in line: %s\n", debugstr_w(buffer));
+ return NULL;
+ }
- 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, Host->lpszValue, lpwhr->lpszPath);
- InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
+ pTokenPair[0] = HeapAlloc(GetProcessHeap(), 0, (pszColon - buffer + 1) * sizeof(WCHAR));
+ if (!pTokenPair[0])
+ {
+ HTTP_FreeTokens(pTokenPair);
+ return NULL;
+ }
+ memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
+ pTokenPair[0][pszColon - buffer] = '\0';
- HeapFree(GetProcessHeap(), 0, buf_url);
- }
- numCookies++;
+ /* skip colon */
+ pszColon++;
+ len = strlenW(pszColon);
+ pTokenPair[1] = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+ if (!pTokenPair[1])
+ {
+ HTTP_FreeTokens(pTokenPair);
+ return NULL;
}
-}
+ memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
-static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
-{
- 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)]);
+ strip_spaces(pTokenPair[0]);
+ strip_spaces(pTokenPair[1]);
+
+ TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
+ return pTokenPair;
}
-static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue,
- struct HttpAuthInfo **ppAuthInfo,
- LPWSTR domain_and_username, LPWSTR password )
-{
- SECURITY_STATUS sec_status;
- struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
- BOOL first = FALSE;
+/***********************************************************************
+ * HTTP_ProcessHeader (internal)
+ *
+ * Stuff header into header tables according to <dwModifier>
+ *
+ */
- TRACE("%s\n", debugstr_w(pszAuthValue));
+#define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
- if (!pAuthInfo)
- {
- TimeStamp exp;
+static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
+{
+ LPHTTPHEADERW lphttpHdr = NULL;
+ BOOL bSuccess = FALSE;
+ INT index = -1;
+ BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
- first = TRUE;
- pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
- if (!pAuthInfo)
- return FALSE;
+ TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
- SecInvalidateHandle(&pAuthInfo->cred);
- SecInvalidateHandle(&pAuthInfo->ctx);
- memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
- pAuthInfo->attr = 0;
- pAuthInfo->auth_data = NULL;
- pAuthInfo->auth_data_len = 0;
- pAuthInfo->finished = FALSE;
+ /* REPLACE wins out over ADD */
+ if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+ dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
- if (is_basic_auth_value(pszAuthValue))
+ if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
+ index = -1;
+ else
+ index = HTTP_GetCustomHeaderIndex(lpwhr, field, 0, request_only);
+
+ if (index >= 0)
+ {
+ if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
{
- static const WCHAR szBasic[] = {'B','a','s','i','c',0};
- pAuthInfo->scheme = WININET_strdupW(szBasic);
- if (!pAuthInfo->scheme)
- {
- HeapFree(GetProcessHeap(), 0, pAuthInfo);
- return FALSE;
- }
+ return FALSE;
}
- else
+ lphttpHdr = &lpwhr->pCustHeaders[index];
+ }
+ else if (value)
+ {
+ HTTPHEADERW hdr;
+
+ hdr.lpszField = (LPWSTR)field;
+ hdr.lpszValue = (LPWSTR)value;
+ hdr.wFlags = hdr.wCount = 0;
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+ hdr.wFlags |= HDR_ISREQUEST;
+
+ return HTTP_InsertCustomHeader(lpwhr, &hdr);
+ }
+ /* no value to delete */
+ else return TRUE;
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+ lphttpHdr->wFlags |= HDR_ISREQUEST;
+ else
+ lphttpHdr->wFlags &= ~HDR_ISREQUEST;
+
+ if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+ {
+ HTTP_DeleteCustomHeader( lpwhr, index );
+
+ if (value)
{
- PVOID pAuthData;
- SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
+ HTTPHEADERW hdr;
- pAuthInfo->scheme = WININET_strdupW(pszAuthValue);
- if (!pAuthInfo->scheme)
- {
- HeapFree(GetProcessHeap(), 0, pAuthInfo);
- return FALSE;
- }
+ hdr.lpszField = (LPWSTR)field;
+ hdr.lpszValue = (LPWSTR)value;
+ hdr.wFlags = hdr.wCount = 0;
- if (domain_and_username)
- {
- WCHAR *user = strchrW(domain_and_username, '\\');
- WCHAR *domain = domain_and_username;
+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+ hdr.wFlags |= HDR_ISREQUEST;
- /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
+ return HTTP_InsertCustomHeader(lpwhr, &hdr);
+ }
- pAuthData = &nt_auth_identity;
+ return TRUE;
+ }
+ else if (dwModifier & COALESCEFLAGS)
+ {
+ LPWSTR lpsztmp;
+ WCHAR ch = 0;
+ INT len = 0;
+ INT origlen = strlenW(lphttpHdr->lpszValue);
+ INT valuelen = strlenW(value);
- if (user) user++;
- else
- {
- user = domain_and_username;
- domain = NULL;
- }
+ if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
+ {
+ ch = ',';
+ lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+ }
+ else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
+ {
+ ch = ';';
+ lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+ }
- 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;
+ len = origlen + valuelen + ((ch > 0) ? 2 : 0);
- sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
- SECPKG_CRED_OUTBOUND, 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)
+ lpsztmp = HeapReAlloc(GetProcessHeap(), 0, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
+ if (lpsztmp)
+ {
+ lphttpHdr->lpszValue = lpsztmp;
+ /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
+ if (ch > 0)
{
- WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
- debugstr_w(pAuthInfo->scheme), sec_status);
- HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
- HeapFree(GetProcessHeap(), 0, pAuthInfo);
- return FALSE;
+ lphttpHdr->lpszValue[origlen] = ch;
+ origlen++;
+ lphttpHdr->lpszValue[origlen] = ' ';
+ origlen++;
}
+
+ memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
+ lphttpHdr->lpszValue[len] = '\0';
+ bSuccess = TRUE;
+ }
+ else
+ {
+ WARN("HeapReAlloc (%d bytes) failed\n",len+1);
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
}
- *ppAuthInfo = pAuthInfo;
}
- else if (pAuthInfo->finished)
- return FALSE;
+ TRACE("<-- %d\n",bSuccess);
+ return bSuccess;
+}
- if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
- strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
+
+/***********************************************************************
+ * HTTP_clear_response_headers (internal)
+ *
+ * clear out any old response headers
+ */
+static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
+{
+ DWORD i;
+
+ for( i=0; i<lpwhr->nCustHeaders; i++)
{
- ERR("authentication scheme changed from %s to %s\n",
- debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
- return FALSE;
+ if( !lpwhr->pCustHeaders[i].lpszField )
+ continue;
+ if( !lpwhr->pCustHeaders[i].lpszValue )
+ continue;
+ if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST )
+ continue;
+ HTTP_DeleteCustomHeader( lpwhr, i );
+ i--;
}
+}
- if (is_basic_auth_value(pszAuthValue))
- {
- int userlen;
- int passlen;
- char *auth_data;
+/***********************************************************************
+ * HTTP_GetResponseHeaders (internal)
+ *
+ * Read server response
+ *
+ * RETURNS
+ *
+ * TRUE on success
+ * FALSE on error
+ */
+static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW 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 szHundred[] = {'1','0','0',0};
+ char bufferA[MAX_REPLY_LEN];
+ LPWSTR status_code, status_text;
+ DWORD cchMaxRawHeaders = 1024;
+ LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+ LPWSTR temp;
+ DWORD cchRawHeaders = 0;
- TRACE("basic authentication\n");
+ TRACE("-->\n");
- /* we don't cache credentials for basic authentication, so we can't
- * retrieve them if the application didn't pass us any credentials */
- if (!domain_and_username) return FALSE;
+ /* clear old response headers (eg. from a redirect response) */
+ if (clear) HTTP_clear_response_headers( lpwhr );
- 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);
+ if (!NETCON_connected(&lpwhr->netConnection))
+ goto lend;
- /* 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;
+ do {
+ /*
+ * 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 );
- 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);
+ /* split the version from the status code */
+ status_code = strchrW( buffer, ' ' );
+ if( !status_code )
+ goto lend;
+ *status_code++=0;
- pAuthInfo->auth_data = auth_data;
- pAuthInfo->auth_data_len = userlen + 1 + passlen;
- pAuthInfo->finished = TRUE;
+ /* split the status code from the status text */
+ status_text = strchrW( status_code, ' ' );
+ if( !status_text )
+ goto lend;
+ *status_text++=0;
- return TRUE;
- }
- else
- {
- LPCWSTR pszAuthData;
- SecBufferDesc out_desc, in_desc;
- SecBuffer out, in;
- unsigned char *buffer;
- ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
- ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
+ TRACE("version [%s] status code [%s] status text [%s]\n",
+ debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
- in.BufferType = SECBUFFER_TOKEN;
- in.cbBuffer = 0;
- in.pvBuffer = NULL;
+ } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */
- in_desc.ulVersion = 0;
- in_desc.cBuffers = 1;
- in_desc.pBuffers = ∈
+ /* Add status code */
+ HTTP_ProcessHeader(lpwhr, szStatus, status_code,
+ HTTP_ADDHDR_FLAG_REPLACE);
- pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
- if (*pszAuthData == ' ')
- {
- pszAuthData++;
- in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
- in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
- HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
- }
+ HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
+ HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
- buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
+ lpwhr->lpszVersion= WININET_strdupW(buffer);
+ lpwhr->lpszStatusText = WININET_strdupW(status_text);
- out.BufferType = SECBUFFER_TOKEN;
- out.cbBuffer = pAuthInfo->max_token;
- out.pvBuffer = buffer;
+ /* Restore the spaces */
+ *(status_code-1) = ' ';
+ *(status_text-1) = ' ';
- out_desc.ulVersion = 0;
- out_desc.cBuffers = 1;
- out_desc.pBuffers = &out;
+ /* regenerate raw headers */
+ 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';
- sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : 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,
- &pAuthInfo->attr, &pAuthInfo->exp);
- if (sec_status == SEC_E_OK)
- {
- pAuthInfo->finished = TRUE;
- pAuthInfo->auth_data = out.pvBuffer;
- pAuthInfo->auth_data_len = out.cbBuffer;
- TRACE("sending last auth packet\n");
- }
- else if (sec_status == SEC_I_CONTINUE_NEEDED)
- {
- pAuthInfo->auth_data = out.pvBuffer;
- pAuthInfo->auth_data_len = out.cbBuffer;
- TRACE("sending next auth packet\n");
- }
- else
+ /* Parse each response line */
+ do
+ {
+ buflen = MAX_REPLY_LEN;
+ if (read_line(lpwhr, bufferA, &buflen))
{
- ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
- pAuthInfo->finished = TRUE;
- HeapFree(GetProcessHeap(), 0, out.pvBuffer);
- return FALSE;
+ 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 );
+
+ pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
+ if (pFieldAndValue)
+ {
+ 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);
+ }
}
- }
+ else
+ {
+ cbreaks++;
+ if (cbreaks >= 2)
+ break;
+ }
+ }while(1);
- return TRUE;
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
+ lpwhr->lpszRawHeaders = lpszRawHeaders;
+ TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
+ bSuccess = TRUE;
+
+lend:
+
+ TRACE("<--\n");
+ if (bSuccess)
+ return rc;
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
+ return 0;
+ }
}
/***********************************************************************
@@ -804,7 +902,7 @@ BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
- if (!lpszHeader)
+ if (!lpszHeader)
return TRUE;
lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
@@ -853,343 +951,982 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
return r;
}
-/***********************************************************************
- * 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)
+
+
+static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr)
{
- TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
+ char szaddr[32];
+ LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
- if (lpBuffersOut)
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RESOLVING_NAME,
+ lpwhs->lpszServerName,
+ strlenW(lpwhs->lpszServerName)+1);
+
+ if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
+ &lpwhs->socketAddress))
{
- INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
return FALSE;
}
- return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
+ inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr,
+ szaddr, sizeof(szaddr));
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_NAME_RESOLVED,
+ szaddr, strlen(szaddr)+1);
+
+ TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
+ return TRUE;
}
-static BOOL HTTP_HttpEndRequestW(LPWININETHTTPREQW lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+/***********************************************************************
+ * HTTP_build_req (internal)
+ *
+ * concatenate all the strings in the request together
+ */
+static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
{
- BOOL rc = FALSE;
- INT responseLen;
- DWORD dwBufferSize;
- INTERNET_ASYNC_RESULT iar;
+ LPCWSTR *t;
+ LPWSTR str;
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+ for( t = list; *t ; t++ )
+ len += strlenW( *t );
+ len++;
- responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
- if (responseLen)
- rc = TRUE;
+ str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ *str = 0;
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
+ for( t = list; *t ; t++ )
+ strcatW( str, *t );
- /* process cookies here. Is this right? */
- HTTP_ProcessCookies(lpwhr);
+ return str;
+}
- if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
+{
+ LPWSTR requestString;
+ DWORD len, n;
+ LPCWSTR *req;
+ UINT i;
+ LPWSTR p;
- if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
+ static const WCHAR szSpace[] = { ' ',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 + 10;
+ req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
+
+ /* add the verb, path and HTTP version string */
+ n = 0;
+ req[n++] = verb;
+ req[n++] = szSpace;
+ req[n++] = path;
+ req[n++] = szSpace;
+ req[n++] = version;
+
+ /* Append custom request headers */
+ for (i = 0; i < lpwhr->nCustHeaders; i++)
{
- DWORD dwCode,dwCodeLength = sizeof(DWORD);
- if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) &&
- (dwCode == 302 || dwCode == 301 || dwCode == 303))
+ if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
{
- WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
- dwBufferSize=sizeof(szNewLocation);
- if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
- {
- /* redirects are always GETs */
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
- lpwhr->lpszVerb = WININET_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));
- rc = HTTP_HandleRedirect(lpwhr, new_url);
- if (rc)
- rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
- HeapFree( GetProcessHeap(), 0, new_url );
- }
- }
+ req[n++] = szCrLf;
+ req[n++] = lpwhr->pCustHeaders[i].lpszField;
+ req[n++] = szColon;
+ req[n++] = lpwhr->pCustHeaders[i].lpszValue;
+
+ TRACE("Adding custom header %s (%s)\n",
+ debugstr_w(lpwhr->pCustHeaders[i].lpszField),
+ debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
}
}
- iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
- iar.dwError = rc ? 0 : INTERNET_GetLastError();
+ if( n >= len )
+ ERR("oops. buffer overrun\n");
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_REQUEST_COMPLETE, &iar,
- sizeof(INTERNET_ASYNC_RESULT));
- return rc;
+ req[n] = NULL;
+ requestString = HTTP_build_req( req, 4 );
+ HeapFree( GetProcessHeap(), 0, req );
+
+ /*
+ * Set (header) termination string for request
+ * Make sure there's exactly two new lines at the end of the request
+ */
+ p = &requestString[strlenW(requestString)-1];
+ while ( (*p == '\n') || (*p == '\r') )
+ p--;
+ strcpyW( p+1, sztwocrlf );
+
+ return requestString;
}
-static void AsyncHttpEndRequestProc(WORKREQUEST *work)
+static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
{
- struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
- LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)work->hdr;
+ 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;
- TRACE("%p\n", lpwhr);
+ TRACE("\n");
- HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
+ 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 ) );
+
+ ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
+ HeapFree( GetProcessHeap(), 0, ascii_req );
+ if (!ret || cnt < 0)
+ return FALSE;
+
+ responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
+ if (!responseLen)
+ return FALSE;
+
+ return TRUE;
}
/***********************************************************************
- * HttpEndRequestW (WININET.@)
- *
- * Ends an HTTP request that was started by HttpSendRequestEx
+ * HTTPSESSION_Destroy (internal)
*
- * RETURNS
- * TRUE if successful
- * FALSE on failure
+ * Deallocate session handle
*
*/
-BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
- LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
+static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
{
- BOOL rc = FALSE;
- LPWININETHTTPREQW lpwhr;
+ LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
- TRACE("-->\n");
+ TRACE("%p\n", lpwhs);
- if (lpBuffersOut)
- {
- INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
+ WININET_Release(&lpwhs->lpAppInfo->hdr);
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
+ 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 (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;
+static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+{
+ switch(option) {
+ case INTERNET_OPTION_HANDLE_TYPE:
+ TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
- if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- WORKREQUEST work;
- struct WORKREQ_HTTPENDREQUESTW *request;
+ if (*size < sizeof(ULONG))
+ return ERROR_INSUFFICIENT_BUFFER;
- work.asyncproc = AsyncHttpEndRequestProc;
- work.hdr = WININET_AddRef( &lpwhr->hdr );
+ *size = sizeof(DWORD);
+ *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
+ return ERROR_SUCCESS;
+ }
- request = &work.u.HttpEndRequestW;
- request->dwFlags = dwFlags;
- request->dwContext = dwContext;
+ return INET_QueryOption(option, buffer, size, unicode);
+}
- INTERNET_AsyncCall(&work);
- INTERNET_SetLastError(ERROR_IO_PENDING);
+static DWORD HTTPSESSION_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size)
+{
+ WININETHTTPSESSIONW *ses = (WININETHTTPSESSIONW*)hdr;
+
+ switch(option) {
+ case INTERNET_OPTION_USERNAME:
+ {
+ HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
+ if (!(ses->lpszUserName = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+ return ERROR_SUCCESS;
+ }
+ case INTERNET_OPTION_PASSWORD:
+ {
+ HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
+ if (!(ses->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+ return ERROR_SUCCESS;
+ }
+ default: break;
}
- else
- rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
- WININET_Release( &lpwhr->hdr );
- TRACE("%i <--\n",rc);
- return rc;
+ return ERROR_INTERNET_INVALID_OPTION;
}
+static const HANDLEHEADERVtbl HTTPSESSIONVtbl = {
+ HTTPSESSION_Destroy,
+ NULL,
+ HTTPSESSION_QueryOption,
+ HTTPSESSION_SetOption,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
/***********************************************************************
- * HttpOpenRequestW (WININET.@)
+ * HTTP_Connect (internal)
*
- * Open a HTTP request handle
+ * Create http session handle
*
* RETURNS
- * HINTERNET a HTTP request handle on success
- * NULL on failure
+ * HINTERNET a session 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)
+HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
+ INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
+ LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
+ DWORD dwInternalFlags)
{
- LPWININETHTTPSESSIONW lpwhs;
+ LPWININETHTTPSESSIONW lpwhs = NULL;
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)
+ TRACE("-->\n");
+
+ if (!lpszServerName || !lpszServerName[0])
{
- int i;
- for(i=0;lpszAcceptTypes[i]!=NULL;i++)
- TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
- }
+ INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ goto lerror;
+ }
- lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
- if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ assert( hIC->hdr.htype == WH_HINIT );
+
+ lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
+ if (NULL == lpwhs)
{
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ goto lerror;
}
- /*
- * 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:
+ /*
+ * 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.refs = 1;
+ lpwhs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
+
+ WININET_AddRef( &hIC->hdr );
+ lpwhs->lpAppInfo = hIC;
+ list_add_head( &hIC->hdr.children, &lpwhs->hdr.entry );
+
+ handle = WININET_AllocHandle( &lpwhs->hdr );
+ if (NULL == handle)
+ {
+ ERR("Failed to alloc handle\n");
+ INTERNET_SetLastError(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);
+ }
+ if (lpszUserName && lpszUserName[0])
+ lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
+ if (lpszPassword && lpszPassword[0])
+ lpwhs->lpszPassword = WININET_strdupW(lpszPassword);
+ lpwhs->nServerPort = nServerPort;
+ lpwhs->nHostPort = nServerPort;
+
+ /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
+ if (!(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
+ {
+ INTERNET_SendCallback(&hIC->hdr, dwContext,
+ INTERNET_STATUS_HANDLE_CREATED, &handle,
+ sizeof(handle));
+ }
+
+lerror:
if( lpwhs )
WININET_Release( &lpwhs->hdr );
- TRACE("returning %p\n", handle);
+
+/*
+ * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
+ * windows
+ */
+
+ TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
return handle;
}
/***********************************************************************
- * HttpOpenRequestA (WININET.@)
+ * HTTP_OpenConnection (internal)
*
- * Open a HTTP request handle
+ * Connect to a web server
*
* RETURNS
- * HINTERNET a HTTP request handle on success
- * NULL on failure
*
+ * TRUE on success
+ * FALSE on failure
*/
-HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
- LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
- LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
- DWORD dwFlags, DWORD_PTR dwContext)
+static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
{
- LPWSTR szVerb = NULL, szObjectName = NULL;
- LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
- INT len, acceptTypesCount;
- HINTERNET rc = FALSE;
- LPCSTR *types;
+ BOOL bSuccess = FALSE;
+ LPWININETHTTPSESSIONW lpwhs;
+ LPWININETAPPINFOW hIC = NULL;
+ char szaddr[32];
- TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
- debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
- debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
- dwFlags, dwContext);
+ TRACE("-->\n");
- if (lpszVerb)
+
+ if (lpwhr->hdr.htype != WH_HHTTPREQ)
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 );
- szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
- if ( !szVerb )
- goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len);
+ INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ goto lend;
}
- if (lpszObjectName)
+ if (NETCON_connected(&lpwhr->netConnection))
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 );
- szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
- if ( !szObjectName )
- goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len );
+ bSuccess = TRUE;
+ goto lend;
}
+ if (!HTTP_ResolveName(lpwhr)) goto lend;
- if (lpszVersion)
+ lpwhs = lpwhr->lpHttpSession;
+
+ hIC = lpwhs->lpAppInfo;
+ inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_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))
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 );
- szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- if ( !szVersion )
- goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len );
+ WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
+ goto lend;
}
- if (lpszReferrer)
+ if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
+ sizeof(lpwhs->socketAddress)))
+ goto lend;
+
+ if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
{
- len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 );
- szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- if ( !szReferrer )
- goto end;
- MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len );
+ /* Note: we differ from Microsoft's WinINet here. they seem to have
+ * a bug that causes no status callbacks to be sent when starting
+ * a tunnel to a proxy server using the CONNECT verb. i believe our
+ * 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))
+ goto lend;
+
+ if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName))
+ {
+ WARN("Couldn't connect securely to host\n");
+ goto lend;
+ }
}
- if (lpszAcceptTypes)
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_CONNECTED_TO_SERVER,
+ szaddr, strlen(szaddr)+1);
+
+ bSuccess = TRUE;
+
+lend:
+ lpwhr->read_pos = lpwhr->read_size = 0;
+ lpwhr->read_chunked = FALSE;
+
+ TRACE("%d <--\n", bSuccess);
+ return bSuccess;
+}
+
+
+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 BOOL 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;
+ DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
+ INT index = -1;
+
+ /* Find requested header structure */
+ switch (level)
{
- acceptTypesCount = 0;
- types = lpszAcceptTypes;
- while (*types)
+ case HTTP_QUERY_CUSTOM:
+ if (!lpBuffer) return FALSE;
+ index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
+ break;
+
+ case HTTP_QUERY_CONTENT_LENGTH:
+ if(lpwhr->gzip_stream) {
+ INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
+ return FALSE;
+ }
+
+ index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
+ requested_index,request_only);
+ break;
+
+ case HTTP_QUERY_RAW_HEADERS_CRLF:
{
- __TRY
+ LPWSTR headers;
+ DWORD len = 0;
+ BOOL ret = FALSE;
+
+ 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)
{
- /* find out how many there are */
- if (*types && **types)
- {
- TRACE("accept type: %s\n", debugstr_a(*types));
- acceptTypesCount++;
- }
+ len += sizeof(WCHAR);
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ ret = FALSE;
}
- __EXCEPT_PAGE_FAULT
+ else if (lpBuffer)
{
- WARN("invalid accept type pointer\n");
+ 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)));
+ ret = TRUE;
}
- __ENDTRY;
- types++;
- }
- szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
- if (!szAcceptTypes) goto end;
+ *lpdwBufferLength = len;
- acceptTypesCount = 0;
- types = lpszAcceptTypes;
- while (*types)
+ if (request_only)
+ HeapFree(GetProcessHeap(), 0, headers);
+ return ret;
+ }
+ case HTTP_QUERY_RAW_HEADERS:
{
- __TRY
+ 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))
{
- if (*types && **types)
+ HTTP_FreeTokens(ppszRawHeaderLines);
+ *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ if (pszString)
+ {
+ for (i = 0; ppszRawHeaderLines[i]; i++)
{
- len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 );
- szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-
- MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len);
- acceptTypesCount++;
+ 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));
}
- __EXCEPT_PAGE_FAULT
+ *lpdwBufferLength = size * sizeof(WCHAR);
+ HTTP_FreeTokens(ppszRawHeaderLines);
+
+ return TRUE;
+ }
+ case HTTP_QUERY_STATUS_TEXT:
+ if (lpwhr->lpszStatusText)
+ {
+ DWORD len = strlenW(lpwhr->lpszStatusText);
+ if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
{
- /* ignore invalid pointer */
+ *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
}
- __ENDTRY;
- types++;
+ if (lpBuffer)
+ {
+ memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
+ TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
+ }
+ *lpdwBufferLength = len * sizeof(WCHAR);
+ return TRUE;
}
- szAcceptTypes[acceptTypesCount] = NULL;
+ break;
+ case HTTP_QUERY_VERSION:
+ if (lpwhr->lpszVersion)
+ {
+ DWORD len = strlenW(lpwhr->lpszVersion);
+ if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
+ {
+ *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ if (lpBuffer)
+ {
+ memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
+ TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
+ }
+ *lpdwBufferLength = len * sizeof(WCHAR);
+ return TRUE;
+ }
+ 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);
}
- rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
- szVersion, szReferrer,
- (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
+ if (index >= 0)
+ lphttpHdr = &lpwhr->pCustHeaders[index];
-end:
- if (szAcceptTypes)
+ /* Ensure header satisfies requested attributes */
+ if (!lphttpHdr ||
+ ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
+ (~lphttpHdr->wFlags & HDR_ISREQUEST)))
{
- acceptTypesCount = 0;
- while (szAcceptTypes[acceptTypesCount])
+ INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
+ return bSuccess;
+ }
+
+ 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);
+ bSuccess = TRUE;
+ }
+ 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;
+ 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);
+ }
+ else if (lphttpHdr->lpszValue)
+ {
+ DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
+
+ if (len > *lpdwBufferLength)
{
- HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
- acceptTypesCount++;
+ *lpdwBufferLength = len;
+ INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return bSuccess;
}
- HeapFree(GetProcessHeap(), 0, szAcceptTypes);
+ if (lpBuffer)
+ {
+ memcpy(lpBuffer, lphttpHdr->lpszValue, len);
+ TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
+ }
+ *lpdwBufferLength = len - sizeof(WCHAR);
+ bSuccess = TRUE;
}
- HeapFree(GetProcessHeap(), 0, szReferrer);
- HeapFree(GetProcessHeap(), 0, szVersion);
- HeapFree(GetProcessHeap(), 0, szObjectName);
- HeapFree(GetProcessHeap(), 0, szVerb);
+ return bSuccess;
+}
- return rc;
+/***********************************************************************
+ * 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)
+{
+ BOOL bSuccess = FALSE;
+ LPWININETHTTPREQW lpwhr;
+
+ if (TRACE_ON(wininet)) {
+#define FE(x) { x, #x }
+ static const wininet_flag_info query_flags[] = {
+ FE(HTTP_QUERY_MIME_VERSION),
+ FE(HTTP_QUERY_CONTENT_TYPE),
+ FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
+ FE(HTTP_QUERY_CONTENT_ID),
+ FE(HTTP_QUERY_CONTENT_DESCRIPTION),
+ FE(HTTP_QUERY_CONTENT_LENGTH),
+ FE(HTTP_QUERY_CONTENT_LANGUAGE),
+ FE(HTTP_QUERY_ALLOW),
+ FE(HTTP_QUERY_PUBLIC),
+ FE(HTTP_QUERY_DATE),
+ FE(HTTP_QUERY_EXPIRES),
+ FE(HTTP_QUERY_LAST_MODIFIED),
+ FE(HTTP_QUERY_MESSAGE_ID),
+ FE(HTTP_QUERY_URI),
+ FE(HTTP_QUERY_DERIVED_FROM),
+ FE(HTTP_QUERY_COST),
+ FE(HTTP_QUERY_LINK),
+ FE(HTTP_QUERY_PRAGMA),
+ FE(HTTP_QUERY_VERSION),
+ FE(HTTP_QUERY_STATUS_CODE),
+ FE(HTTP_QUERY_STATUS_TEXT),
+ FE(HTTP_QUERY_RAW_HEADERS),
+ FE(HTTP_QUERY_RAW_HEADERS_CRLF),
+ FE(HTTP_QUERY_CONNECTION),
+ FE(HTTP_QUERY_ACCEPT),
+ FE(HTTP_QUERY_ACCEPT_CHARSET),
+ FE(HTTP_QUERY_ACCEPT_ENCODING),
+ FE(HTTP_QUERY_ACCEPT_LANGUAGE),
+ FE(HTTP_QUERY_AUTHORIZATION),
+ FE(HTTP_QUERY_CONTENT_ENCODING),
+ FE(HTTP_QUERY_FORWARDED),
+ FE(HTTP_QUERY_FROM),
+ FE(HTTP_QUERY_IF_MODIFIED_SINCE),
+ FE(HTTP_QUERY_LOCATION),
+ FE(HTTP_QUERY_ORIG_URI),
+ FE(HTTP_QUERY_REFERER),
+ FE(HTTP_QUERY_RETRY_AFTER),
+ FE(HTTP_QUERY_SERVER),
+ FE(HTTP_QUERY_TITLE),
+ FE(HTTP_QUERY_USER_AGENT),
+ FE(HTTP_QUERY_WWW_AUTHENTICATE),
+ FE(HTTP_QUERY_PROXY_AUTHENTICATE),
+ FE(HTTP_QUERY_ACCEPT_RANGES),
+ FE(HTTP_QUERY_SET_COOKIE),
+ FE(HTTP_QUERY_COOKIE),
+ FE(HTTP_QUERY_REQUEST_METHOD),
+ FE(HTTP_QUERY_REFRESH),
+ FE(HTTP_QUERY_CONTENT_DISPOSITION),
+ FE(HTTP_QUERY_AGE),
+ FE(HTTP_QUERY_CACHE_CONTROL),
+ FE(HTTP_QUERY_CONTENT_BASE),
+ FE(HTTP_QUERY_CONTENT_LOCATION),
+ FE(HTTP_QUERY_CONTENT_MD5),
+ FE(HTTP_QUERY_CONTENT_RANGE),
+ FE(HTTP_QUERY_ETAG),
+ FE(HTTP_QUERY_HOST),
+ FE(HTTP_QUERY_IF_MATCH),
+ FE(HTTP_QUERY_IF_NONE_MATCH),
+ FE(HTTP_QUERY_IF_RANGE),
+ FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
+ FE(HTTP_QUERY_MAX_FORWARDS),
+ FE(HTTP_QUERY_PROXY_AUTHORIZATION),
+ FE(HTTP_QUERY_RANGE),
+ FE(HTTP_QUERY_TRANSFER_ENCODING),
+ FE(HTTP_QUERY_UPGRADE),
+ FE(HTTP_QUERY_VARY),
+ FE(HTTP_QUERY_VIA),
+ FE(HTTP_QUERY_WARNING),
+ FE(HTTP_QUERY_CUSTOM)
+ };
+ static const wininet_flag_info modifier_flags[] = {
+ FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
+ FE(HTTP_QUERY_FLAG_SYSTEMTIME),
+ FE(HTTP_QUERY_FLAG_NUMBER),
+ FE(HTTP_QUERY_FLAG_COALESCE)
+ };
+#undef FE
+ DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
+ 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(" 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 = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ goto lend;
+ }
+
+ if (lpBuffer == NULL)
+ *lpdwBufferLength = 0;
+ bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
+ lpBuffer, lpdwBufferLength, lpdwIndex);
+
+lend:
+ if( lpwhr )
+ WININET_Release( &lpwhr->hdr );
+
+ TRACE("%d <--\n", bSuccess);
+ return bSuccess;
+}
+
+/***********************************************************************
+ * 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;
+}
+
+static void HTTP_InsertCookies(LPWININETHTTPREQW 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);
+
+ HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
+ HeapFree(GetProcessHeap(), 0, lpszCookies);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, lpszUrl);
+}
+
+static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr )
+{
+ int HeaderIndex;
+ int numCookies = 0;
+ LPHTTPHEADERW setCookieHeader;
+
+ while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
+ {
+ setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
+
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
+ {
+ int len;
+ static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
+ LPWSTR buf_url;
+ LPHTTPHEADERW Host;
+
+ 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, Host->lpszValue, lpwhr->lpszPath);
+ InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
+
+ HeapFree(GetProcessHeap(), 0, buf_url);
+ }
+ numCookies++;
+ }
}
/***********************************************************************
@@ -1324,154 +2061,222 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
return n;
}
-/***********************************************************************
- * HTTP_InsertAuthorization
- *
- * Insert or delete the authorization field in the request header.
- */
-static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
+static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
{
- if (pAuthInfo)
+ 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 BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue,
+ struct HttpAuthInfo **ppAuthInfo,
+ LPWSTR domain_and_username, LPWSTR password )
+{
+ SECURITY_STATUS sec_status;
+ struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
+ BOOL first = FALSE;
+
+ TRACE("%s\n", debugstr_w(pszAuthValue));
+
+ if (!pAuthInfo)
{
- static const WCHAR wszSpace[] = {' ',0};
- static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
- unsigned int len;
- WCHAR *authorization = NULL;
+ TimeStamp exp;
- 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;
+ first = TRUE;
+ pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
+ if (!pAuthInfo)
+ return FALSE;
- strcpyW(authorization, pAuthInfo->scheme);
- strcatW(authorization, wszSpace);
- HTTP_EncodeBase64(pAuthInfo->auth_data,
- pAuthInfo->auth_data_len,
- authorization+strlenW(authorization));
+ SecInvalidateHandle(&pAuthInfo->cred);
+ SecInvalidateHandle(&pAuthInfo->ctx);
+ memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
+ pAuthInfo->attr = 0;
+ pAuthInfo->auth_data = NULL;
+ pAuthInfo->auth_data_len = 0;
+ pAuthInfo->finished = FALSE;
- /* 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))
+ if (is_basic_auth_value(pszAuthValue))
+ {
+ static const WCHAR szBasic[] = {'B','a','s','i','c',0};
+ pAuthInfo->scheme = WININET_strdupW(szBasic);
+ if (!pAuthInfo->scheme)
{
- HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
- pAuthInfo->auth_data = NULL;
- pAuthInfo->auth_data_len = 0;
+ HeapFree(GetProcessHeap(), 0, pAuthInfo);
+ return FALSE;
}
}
+ else
+ {
+ PVOID pAuthData;
+ SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
- TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
+ pAuthInfo->scheme = WININET_strdupW(pszAuthValue);
+ if (!pAuthInfo->scheme)
+ {
+ HeapFree(GetProcessHeap(), 0, pAuthInfo);
+ return FALSE;
+ }
- HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+ if (domain_and_username)
+ {
+ WCHAR *user = strchrW(domain_and_username, '\\');
+ WCHAR *domain = domain_and_username;
- HeapFree(GetProcessHeap(), 0, authorization);
- }
- return TRUE;
-}
+ /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
-static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req)
-{
- WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
- DWORD size;
+ pAuthData = &nt_auth_identity;
- size = sizeof(new_location);
- if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
+ if (user) user++;
+ else
+ {
+ 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);
+ }
+ else
+ /* use default credentials */
+ pAuthData = NULL;
+
+ sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
+ SECPKG_CRED_OUTBOUND, 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",
+ debugstr_w(pAuthInfo->scheme), sec_status);
+ HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
+ HeapFree(GetProcessHeap(), 0, pAuthInfo);
+ return FALSE;
+ }
+ }
+ *ppAuthInfo = pAuthInfo;
+ }
+ else if (pAuthInfo->finished)
+ return FALSE;
+
+ if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
+ strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
{
- if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
- strcpyW( url, new_location );
+ ERR("authentication scheme changed from %s to %s\n",
+ debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
+ return FALSE;
}
- else
+
+ if (is_basic_auth_value(pszAuthValue))
{
- 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 };
- WININETHTTPSESSIONW *session = req->lpHttpSession;
+ int userlen;
+ int passlen;
+ char *auth_data;
- size = 16; /* "https://" + sizeof(port#) + ":/\0" */
- size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
+ TRACE("basic authentication\n");
- if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
+ /* we don't cache credentials for basic authentication, so we can't
+ * retrieve them if the application didn't pass us any credentials */
+ if (!domain_and_username) return FALSE;
- 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;
-}
+ 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);
-/***********************************************************************
- * HTTP_DealWithProxy
- */
-static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
- LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
-{
- WCHAR buf[MAXHOSTNAME];
- WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
- static WCHAR szNul[] = { 0 };
- URL_COMPONENTSW UrlComponents;
- static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
- static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
+ /* 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;
- memset( &UrlComponents, 0, sizeof UrlComponents );
- UrlComponents.dwStructSize = sizeof UrlComponents;
- UrlComponents.lpszHostName = buf;
- UrlComponents.dwHostNameLength = MAXHOSTNAME;
+ 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);
- if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
- hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
- sprintfW(proxy, szFormat, hIC->lpszProxy);
+ pAuthInfo->auth_data = auth_data;
+ pAuthInfo->auth_data_len = userlen + 1 + passlen;
+ pAuthInfo->finished = TRUE;
+
+ return TRUE;
+ }
else
- strcpyW(proxy, hIC->lpszProxy);
- if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
- return FALSE;
- if( UrlComponents.dwHostNameLength == 0 )
- return FALSE;
+ {
+ LPCWSTR pszAuthData;
+ SecBufferDesc out_desc, in_desc;
+ SecBuffer out, in;
+ unsigned char *buffer;
+ ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
+ ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
- if( !lpwhr->lpszPath )
- lpwhr->lpszPath = szNul;
+ in.BufferType = SECBUFFER_TOKEN;
+ in.cbBuffer = 0;
+ in.pvBuffer = NULL;
- if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
- UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
+ in_desc.ulVersion = 0;
+ in_desc.cBuffers = 1;
+ in_desc.pBuffers = ∈
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
- lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
- lpwhs->nServerPort = UrlComponents.nPort;
+ pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
+ if (*pszAuthData == ' ')
+ {
+ pszAuthData++;
+ in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
+ in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
+ HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
+ }
- TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
- return TRUE;
-}
+ buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
-static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr)
-{
- char szaddr[32];
- LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
+ out.BufferType = SECBUFFER_TOKEN;
+ out.cbBuffer = pAuthInfo->max_token;
+ out.pvBuffer = buffer;
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_RESOLVING_NAME,
- lpwhs->lpszServerName,
- strlenW(lpwhs->lpszServerName)+1);
+ out_desc.ulVersion = 0;
+ out_desc.cBuffers = 1;
+ out_desc.pBuffers = &out;
- if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
- &lpwhs->socketAddress))
- {
- INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
- return FALSE;
+ sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : 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,
+ &pAuthInfo->attr, &pAuthInfo->exp);
+ if (sec_status == SEC_E_OK)
+ {
+ pAuthInfo->finished = TRUE;
+ pAuthInfo->auth_data = out.pvBuffer;
+ pAuthInfo->auth_data_len = out.cbBuffer;
+ TRACE("sending last auth packet\n");
+ }
+ else if (sec_status == SEC_I_CONTINUE_NEEDED)
+ {
+ pAuthInfo->auth_data = out.pvBuffer;
+ pAuthInfo->auth_data_len = out.cbBuffer;
+ TRACE("sending next auth packet\n");
+ }
+ else
+ {
+ ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
+ pAuthInfo->finished = TRUE;
+ HeapFree(GetProcessHeap(), 0, out.pvBuffer);
+ return FALSE;
+ }
}
- inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr,
- szaddr, sizeof(szaddr));
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_NAME_RESOLVED,
- szaddr, strlen(szaddr)+1);
-
- TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
return TRUE;
}
@@ -1798,78 +2603,6 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf
return ERROR_INTERNET_INVALID_OPTION;
}
-/* read some more data into the read buffer (the read section must be held) */
-static BOOL read_more_data( WININETHTTPREQW *req, int maxlen )
-{
- 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);
-
- if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
- maxlen - req->read_size, 0, &len ))
- return FALSE;
-
- req->read_size += len;
- return TRUE;
-}
-
-/* remove some amount of data from the read buffer (the read section must be held) */
-static void remove_data( WININETHTTPREQW *req, int count )
-{
- if (!(req->read_size -= count)) req->read_pos = 0;
- else req->read_pos += count;
-}
-
-static BOOL read_line( WININETHTTPREQW *req, LPSTR buffer, DWORD *len )
-{
- int count, bytes_read, pos = 0;
-
- 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;
- }
- 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 (!read_more_data( req, -1 ) || !req->read_size)
- {
- *len = 0;
- TRACE( "returning empty string\n" );
- LeaveCriticalSection( &req->read_section );
- 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;
-}
-
/* discard data contents until we reach end of line (the read section must be held) */
static BOOL discard_eol( WININETHTTPREQW *req )
{
@@ -2044,6 +2777,47 @@ static void HTTP_ReceiveRequestData(WININETHTTPREQW *req, BOOL first_notif)
sizeof(INTERNET_ASYNC_RESULT));
}
+/***********************************************************************
+ * HTTP_FinishedReading (internal)
+ *
+ * Called when all content from server has been read by client.
+ *
+ */
+static BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr)
+{
+ WCHAR szVersion[10];
+ WCHAR szConnectionResponse[20];
+ DWORD dwBufferSize = sizeof(szVersion);
+ BOOL keepalive = FALSE;
+
+ TRACE("\n");
+
+ /* 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) &&
+ !strcmpiW(szVersion, g_szHttp1_1))
+ {
+ keepalive = TRUE;
+ }
+
+ dwBufferSize = sizeof(szConnectionResponse);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
+ HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
+ {
+ keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
+ }
+
+ if (!keepalive)
+ {
+ HTTPREQ_CloseConnection(&lpwhr->hdr);
+ }
+
+ /* FIXME: store data in the URL cache here */
+
+ return TRUE;
+}
+
/* read data from the http connection (the read section must be held) */
static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
{
@@ -2351,949 +3125,6 @@ static const HANDLEHEADERVtbl HTTPREQVtbl = {
};
/***********************************************************************
- * HTTP_HttpOpenRequestW (internal)
- *
- * Open a HTTP request handle
- *
- * RETURNS
- * HINTERNET a HTTP request handle on success
- * NULL on failure
- *
- */
-HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
- LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
- LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
- DWORD dwFlags, DWORD_PTR dwContext)
-{
- LPWININETAPPINFOW hIC = NULL;
- LPWININETHTTPREQW lpwhr;
- LPWSTR lpszHostName = NULL;
- HINTERNET handle = NULL;
- static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
- DWORD len;
-
- TRACE("-->\n");
-
- assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
- hIC = lpwhs->lpAppInfo;
-
- lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
- if (NULL == lpwhr)
- {
- INTERNET_SetLastError(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)
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lend;
- }
-
- handle = WININET_AllocHandle( &lpwhr->hdr );
- if (NULL == handle)
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lend;
- }
-
- if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
- {
- 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 = WININET_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 = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
-
- if (lpszVersion)
- lpwhr->lpszVersion = WININET_strdupW(lpszVersion);
- else
- lpwhr->lpszVersion = WININET_strdupW(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);
- return handle;
-}
-
-/* read any content returned by the server so that the connection can be
- * reused */
-static void HTTP_DrainContent(WININETHTTPREQW *req)
-{
- DWORD bytes_read;
-
- if (!NETCON_connected(&req->netConnection)) return;
-
- if (req->dwContentLength == -1)
- {
- NETCON_close(&req->netConnection);
- 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 BOOL 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;
- DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
- INT index = -1;
-
- /* Find requested header structure */
- switch (level)
- {
- case HTTP_QUERY_CUSTOM:
- if (!lpBuffer) return FALSE;
- index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
- break;
-
- case HTTP_QUERY_CONTENT_LENGTH:
- if(lpwhr->gzip_stream) {
- INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
- return FALSE;
- }
-
- index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
- requested_index,request_only);
- break;
-
- case HTTP_QUERY_RAW_HEADERS_CRLF:
- {
- LPWSTR headers;
- DWORD len = 0;
- BOOL ret = FALSE;
-
- 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);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- ret = FALSE;
- }
- 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)));
- ret = TRUE;
- }
- *lpdwBufferLength = len;
-
- if (request_only)
- HeapFree(GetProcessHeap(), 0, headers);
- return ret;
- }
- 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);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
- 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 TRUE;
- }
- case HTTP_QUERY_STATUS_TEXT:
- if (lpwhr->lpszStatusText)
- {
- DWORD len = strlenW(lpwhr->lpszStatusText);
- if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
- {
- *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
- if (lpBuffer)
- {
- memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
- TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
- }
- *lpdwBufferLength = len * sizeof(WCHAR);
- return TRUE;
- }
- break;
- case HTTP_QUERY_VERSION:
- if (lpwhr->lpszVersion)
- {
- DWORD len = strlenW(lpwhr->lpszVersion);
- if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
- {
- *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
- if (lpBuffer)
- {
- memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
- TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
- }
- *lpdwBufferLength = len * sizeof(WCHAR);
- return TRUE;
- }
- 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)))
- {
- INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
- return bSuccess;
- }
-
- 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);
- bSuccess = TRUE;
- }
- 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;
- 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);
- }
- else if (lphttpHdr->lpszValue)
- {
- DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
-
- if (len > *lpdwBufferLength)
- {
- *lpdwBufferLength = len;
- INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return bSuccess;
- }
- if (lpBuffer)
- {
- memcpy(lpBuffer, lphttpHdr->lpszValue, len);
- TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
- }
- *lpdwBufferLength = len - sizeof(WCHAR);
- bSuccess = TRUE;
- }
- return bSuccess;
-}
-
-/***********************************************************************
- * 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)
-{
- BOOL bSuccess = FALSE;
- LPWININETHTTPREQW lpwhr;
-
- if (TRACE_ON(wininet)) {
-#define FE(x) { x, #x }
- static const wininet_flag_info query_flags[] = {
- FE(HTTP_QUERY_MIME_VERSION),
- FE(HTTP_QUERY_CONTENT_TYPE),
- FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
- FE(HTTP_QUERY_CONTENT_ID),
- FE(HTTP_QUERY_CONTENT_DESCRIPTION),
- FE(HTTP_QUERY_CONTENT_LENGTH),
- FE(HTTP_QUERY_CONTENT_LANGUAGE),
- FE(HTTP_QUERY_ALLOW),
- FE(HTTP_QUERY_PUBLIC),
- FE(HTTP_QUERY_DATE),
- FE(HTTP_QUERY_EXPIRES),
- FE(HTTP_QUERY_LAST_MODIFIED),
- FE(HTTP_QUERY_MESSAGE_ID),
- FE(HTTP_QUERY_URI),
- FE(HTTP_QUERY_DERIVED_FROM),
- FE(HTTP_QUERY_COST),
- FE(HTTP_QUERY_LINK),
- FE(HTTP_QUERY_PRAGMA),
- FE(HTTP_QUERY_VERSION),
- FE(HTTP_QUERY_STATUS_CODE),
- FE(HTTP_QUERY_STATUS_TEXT),
- FE(HTTP_QUERY_RAW_HEADERS),
- FE(HTTP_QUERY_RAW_HEADERS_CRLF),
- FE(HTTP_QUERY_CONNECTION),
- FE(HTTP_QUERY_ACCEPT),
- FE(HTTP_QUERY_ACCEPT_CHARSET),
- FE(HTTP_QUERY_ACCEPT_ENCODING),
- FE(HTTP_QUERY_ACCEPT_LANGUAGE),
- FE(HTTP_QUERY_AUTHORIZATION),
- FE(HTTP_QUERY_CONTENT_ENCODING),
- FE(HTTP_QUERY_FORWARDED),
- FE(HTTP_QUERY_FROM),
- FE(HTTP_QUERY_IF_MODIFIED_SINCE),
- FE(HTTP_QUERY_LOCATION),
- FE(HTTP_QUERY_ORIG_URI),
- FE(HTTP_QUERY_REFERER),
- FE(HTTP_QUERY_RETRY_AFTER),
- FE(HTTP_QUERY_SERVER),
- FE(HTTP_QUERY_TITLE),
- FE(HTTP_QUERY_USER_AGENT),
- FE(HTTP_QUERY_WWW_AUTHENTICATE),
- FE(HTTP_QUERY_PROXY_AUTHENTICATE),
- FE(HTTP_QUERY_ACCEPT_RANGES),
- FE(HTTP_QUERY_SET_COOKIE),
- FE(HTTP_QUERY_COOKIE),
- FE(HTTP_QUERY_REQUEST_METHOD),
- FE(HTTP_QUERY_REFRESH),
- FE(HTTP_QUERY_CONTENT_DISPOSITION),
- FE(HTTP_QUERY_AGE),
- FE(HTTP_QUERY_CACHE_CONTROL),
- FE(HTTP_QUERY_CONTENT_BASE),
- FE(HTTP_QUERY_CONTENT_LOCATION),
- FE(HTTP_QUERY_CONTENT_MD5),
- FE(HTTP_QUERY_CONTENT_RANGE),
- FE(HTTP_QUERY_ETAG),
- FE(HTTP_QUERY_HOST),
- FE(HTTP_QUERY_IF_MATCH),
- FE(HTTP_QUERY_IF_NONE_MATCH),
- FE(HTTP_QUERY_IF_RANGE),
- FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
- FE(HTTP_QUERY_MAX_FORWARDS),
- FE(HTTP_QUERY_PROXY_AUTHORIZATION),
- FE(HTTP_QUERY_RANGE),
- FE(HTTP_QUERY_TRANSFER_ENCODING),
- FE(HTTP_QUERY_UPGRADE),
- FE(HTTP_QUERY_VARY),
- FE(HTTP_QUERY_VIA),
- FE(HTTP_QUERY_WARNING),
- FE(HTTP_QUERY_CUSTOM)
- };
- static const wininet_flag_info modifier_flags[] = {
- FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
- FE(HTTP_QUERY_FLAG_SYSTEMTIME),
- FE(HTTP_QUERY_FLAG_NUMBER),
- FE(HTTP_QUERY_FLAG_COALESCE)
- };
-#undef FE
- DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
- 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(" 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 = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
- }
-
- if (lpBuffer == NULL)
- *lpdwBufferLength = 0;
- bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
- lpBuffer, lpdwBufferLength, lpdwIndex);
-
-lend:
- if( lpwhr )
- WININET_Release( &lpwhr->hdr );
-
- TRACE("%d <--\n", bSuccess);
- return bSuccess;
-}
-
-/***********************************************************************
- * 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;
-}
-
-/***********************************************************************
- * 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;
-
- TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
- lpBuffersOut, dwFlags, dwContext);
-
- if (lpBuffersIn)
- {
- BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
- if (lpBuffersIn->lpcszHeader)
- {
- 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);
- }
- else
- BuffersInW.lpcszHeader = NULL;
- BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
- BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
- BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
- BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
- BuffersInW.Next = NULL;
- }
-
- rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
-
- HeapFree(GetProcessHeap(),0,header);
-
- return rc;
-}
-
-/***********************************************************************
- * 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;
-
- TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
- lpBuffersOut, dwFlags, dwContext);
-
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
-
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- goto lend;
- }
-
- lpwhs = lpwhr->lpHttpSession;
- assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
- hIC = lpwhs->lpAppInfo;
- assert(hIC->hdr.htype == WH_HINIT);
-
- if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- WORKREQUEST workRequest;
- struct WORKREQ_HTTPSENDREQUESTW *req;
-
- 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;
- }
- else
- {
- req->lpszHeader = NULL;
- req->dwHeaderLength = 0;
- req->lpOptional = NULL;
- req->dwOptionalLength = 0;
- req->dwContentLength = 0;
- }
-
- req->bEndRequest = FALSE;
-
- INTERNET_AsyncCall(&workRequest);
- /*
- * This is from windows.
- */
- INTERNET_SetLastError(ERROR_IO_PENDING);
- }
- else
- {
- if (lpBuffersIn)
- ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
- lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
- lpBuffersIn->dwBufferTotal, FALSE);
- else
- ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
- }
-
-lend:
- if ( lpwhr )
- WININET_Release( &lpwhr->hdr );
-
- TRACE("<---\n");
- return ret;
-}
-
-/***********************************************************************
- * HttpSendRequestW (WININET.@)
- *
- * Sends the specified request to the HTTP server
- *
- * RETURNS
- * TRUE on success
- * FALSE on failure
- *
- */
-BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
- DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
-{
- LPWININETHTTPREQW lpwhr;
- LPWININETHTTPSESSIONW lpwhs = NULL;
- LPWININETAPPINFOW hIC = NULL;
- BOOL r;
-
- TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
- debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
-
- lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
- if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- r = FALSE;
- goto lend;
- }
-
- lpwhs = lpwhr->lpHttpSession;
- if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
- {
- INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
- r = FALSE;
- goto lend;
- }
-
- 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;
-
- workRequest.asyncproc = AsyncHttpSendRequestProc;
- workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
- req = &workRequest.u.HttpSendRequestW;
- if (lpszHeaders)
- {
- DWORD size;
-
- if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
- else size = dwHeaderLength * sizeof(WCHAR);
-
- 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;
-
- INTERNET_AsyncCall(&workRequest);
- /*
- * This is from windows.
- */
- INTERNET_SetLastError(ERROR_IO_PENDING);
- r = FALSE;
- }
- else
- {
- r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
- dwHeaderLength, lpOptional, dwOptionalLength,
- dwOptionalLength, TRUE);
- }
-lend:
- if( lpwhr )
- WININET_Release( &lpwhr->hdr );
- return r;
-}
-
-/***********************************************************************
- * 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;
-}
-
-/***********************************************************************
* HTTP_GetRedirectURL (internal)
*/
static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
@@ -3354,7 +3185,6 @@ static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
return combined_url;
}
-
/***********************************************************************
* HTTP_HandleRedirect (internal)
*/
@@ -3423,7 +3253,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
#if 0
/*
- * This upsets redirects to binary files on sourceforge.net
+ * 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.
@@ -3437,7 +3267,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
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)
@@ -3510,98 +3340,278 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
}
/***********************************************************************
- * HTTP_build_req (internal)
+ * HTTP_InsertAuthorization
*
- * concatenate all the strings in the request together
+ * Insert or delete the authorization field in the request header.
*/
-static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
+static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
{
- LPCWSTR *t;
- LPWSTR str;
+ if (pAuthInfo)
+ {
+ static const WCHAR wszSpace[] = {' ',0};
+ static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
+ unsigned int len;
+ WCHAR *authorization = NULL;
- for( t = list; *t ; t++ )
- len += strlenW( *t );
- len++;
+ 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;
- str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
- *str = 0;
+ strcpyW(authorization, pAuthInfo->scheme);
+ strcatW(authorization, wszSpace);
+ HTTP_EncodeBase64(pAuthInfo->auth_data,
+ pAuthInfo->auth_data_len,
+ authorization+strlenW(authorization));
- for( t = list; *t ; t++ )
- strcatW( str, *t );
+ /* 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;
+ }
+ }
- return str;
+ TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
+
+ HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+
+ HeapFree(GetProcessHeap(), 0, authorization);
+ }
+ return TRUE;
}
-static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
+/***********************************************************************
+ * IsHostInProxyBypassList (@)
+ *
+ * Undocumented
+ *
+ */
+BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
{
- 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;
+ FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
+ return FALSE;
+}
- TRACE("\n");
+static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req)
+{
+ WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
+ DWORD size;
- 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 );
+ size = sizeof(new_location);
+ if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
+ {
+ 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 };
+ WININETHTTPSESSIONW *session = req->lpHttpSession;
- 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 );
+ size = 16; /* "https://" + sizeof(port#) + ":/\0" */
+ size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
- TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
+ if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
- ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
- HeapFree( GetProcessHeap(), 0, ascii_req );
- if (!ret || cnt < 0)
- return FALSE;
+ 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;
+}
- responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
- if (!responseLen)
+/***********************************************************************
+ * HTTP_DealWithProxy
+ */
+static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
+ LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
+{
+ WCHAR buf[MAXHOSTNAME];
+ WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
+ static WCHAR szNul[] = { 0 };
+ URL_COMPONENTSW UrlComponents;
+ 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( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
+ hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
+ sprintfW(proxy, szFormat, hIC->lpszProxy);
+ else
+ strcpyW(proxy, hIC->lpszProxy);
+ if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
+ return FALSE;
+ if( UrlComponents.dwHostNameLength == 0 )
return FALSE;
+ if( !lpwhr->lpszPath )
+ lpwhr->lpszPath = szNul;
+
+ if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
+ UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
+
+ HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
+ lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
+ lpwhs->nServerPort = UrlComponents.nPort;
+
+ TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
return TRUE;
}
-static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr)
+/* read any content returned by the server so that the connection can be
+ * reused */
+static void HTTP_DrainContent(WININETHTTPREQW *req)
{
- static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
- LPWSTR lpszCookies, lpszUrl = NULL;
- DWORD nCookieSize, size;
- LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+ DWORD bytes_read;
- 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 (!NETCON_connected(&req->netConnection)) return;
- if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
+ if (req->dwContentLength == -1)
{
- int cnt = 0;
- static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
+ NETCON_close(&req->netConnection);
+ return;
+ }
- 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);
+ do
+ {
+ char buffer[2048];
+ if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
+ return;
+ } while (bytes_read);
+}
- HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
- HeapFree(GetProcessHeap(), 0, lpszCookies);
+#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(WININETHTTPREQW *req)
+{
+ gzip_stream_t *gzip_stream;
+ int 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;
+}
+
+#else
+
+static void init_gzip_stream(WININETHTTPREQW *req)
+{
+ ERR("gzip stream not supported, missing zlib.\n");
+}
+
+#endif
+
+/* set the request content length based on the headers */
+static DWORD set_content_length( LPWININETHTTPREQW 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))
+ lpwhr->dwContentLength = ~0u;
+
+ size = sizeof(encoding);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
+ !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;
+}
+
+static void HTTP_FixURL( LPWININETHTTPREQW 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);
+ else /* remove \r and \n*/
+ {
+ int nLen = strlenW(lpwhr->lpszPath);
+ while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
+ {
+ nLen--;
+ lpwhr->lpszPath[nLen]='\0';
+ }
+ /* Replace '\' with '/' */
+ while (nLen>0) {
+ nLen--;
+ if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
}
}
- HeapFree(GetProcessHeap(), 0, lpszUrl);
+
+ if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
+ lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
+ && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
+ {
+ WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0,
+ (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
+ *fixurl = '/';
+ strcpyW(fixurl + 1, lpwhr->lpszPath);
+ HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
+ lpwhr->lpszPath = fixurl;
+ }
}
/***********************************************************************
@@ -3713,7 +3723,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
else
requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
-
+
TRACE("Request header -> %s\n", debugstr_w(requestString) );
/* Send the request and store the results */
@@ -3753,14 +3763,14 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
+
if (cnt < 0)
goto lend;
-
+
responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
if (responseLen)
bSuccess = TRUE;
-
+
INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
sizeof(DWORD));
@@ -3904,798 +3914,775 @@ lend:
return bSuccess;
}
-/***********************************************************************
- * HTTPSESSION_Destroy (internal)
+/* **********************************************************************
*
- * Deallocate session handle
+ * Helper functions for the HttpSendRequest(Ex) functions
*
*/
-static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
+static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
{
- LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
+ struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
+ LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr;
- TRACE("%p\n", lpwhs);
+ TRACE("%p\n", lpwhr);
- WININET_Release(&lpwhs->lpAppInfo->hdr);
+ HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
+ req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
+ req->dwContentLength, req->bEndRequest);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
- HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
- HeapFree(GetProcessHeap(), 0, lpwhs);
+ HeapFree(GetProcessHeap(), 0, req->lpszHeader);
}
-static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+/***********************************************************************
+ * 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)
{
- switch(option) {
- case INTERNET_OPTION_HANDLE_TYPE:
- TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
+ BOOL ret = FALSE;
+ LPWININETHTTPREQW lpwhr;
+ LPWININETHTTPSESSIONW lpwhs;
+ LPWININETAPPINFOW hIC;
- if (*size < sizeof(ULONG))
- return ERROR_INSUFFICIENT_BUFFER;
+ TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+ lpBuffersOut, dwFlags, dwContext);
- *size = sizeof(DWORD);
- *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
- return ERROR_SUCCESS;
- }
+ lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
- return INET_QueryOption(option, buffer, size, unicode);
-}
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ goto lend;
+ }
-static DWORD HTTPSESSION_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size)
-{
- WININETHTTPSESSIONW *ses = (WININETHTTPSESSIONW*)hdr;
+ lpwhs = lpwhr->lpHttpSession;
+ assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
+ hIC = lpwhs->lpAppInfo;
+ assert(hIC->hdr.htype == WH_HINIT);
- switch(option) {
- case INTERNET_OPTION_USERNAME:
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
- HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
- if (!(ses->lpszUserName = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
- return ERROR_SUCCESS;
+ WORKREQUEST workRequest;
+ struct WORKREQ_HTTPSENDREQUESTW *req;
+
+ 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;
+ }
+ else
+ {
+ req->lpszHeader = NULL;
+ req->dwHeaderLength = 0;
+ req->lpOptional = NULL;
+ req->dwOptionalLength = 0;
+ req->dwContentLength = 0;
+ }
+
+ req->bEndRequest = FALSE;
+
+ INTERNET_AsyncCall(&workRequest);
+ /*
+ * This is from windows.
+ */
+ INTERNET_SetLastError(ERROR_IO_PENDING);
}
- case INTERNET_OPTION_PASSWORD:
+ else
{
- HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
- if (!(ses->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
- return ERROR_SUCCESS;
- }
- default: break;
+ if (lpBuffersIn)
+ ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+ lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
+ lpBuffersIn->dwBufferTotal, FALSE);
+ else
+ ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
}
- return ERROR_INTERNET_INVALID_OPTION;
-}
-
-static const HANDLEHEADERVtbl HTTPSESSIONVtbl = {
- HTTPSESSION_Destroy,
- NULL,
- HTTPSESSION_QueryOption,
- HTTPSESSION_SetOption,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
-};
+lend:
+ if ( lpwhr )
+ WININET_Release( &lpwhr->hdr );
+ TRACE("<---\n");
+ return ret;
+}
/***********************************************************************
- * HTTP_Connect (internal)
+ * HttpSendRequestExA (WININET.@)
*
- * Create http session handle
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers.
*
* RETURNS
- * HINTERNET a session handle on success
- * NULL on failure
- *
+ * Success: TRUE
+ * Failure: FALSE, call GetLastError() for more information.
*/
-HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
- INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
- LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
- DWORD dwInternalFlags)
+BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
+ LPINTERNET_BUFFERSA lpBuffersIn,
+ LPINTERNET_BUFFERSA lpBuffersOut,
+ DWORD dwFlags, DWORD_PTR dwContext)
{
- LPWININETHTTPSESSIONW lpwhs = NULL;
- HINTERNET handle = NULL;
-
- TRACE("-->\n");
-
- if (!lpszServerName || !lpszServerName[0])
- {
- INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
- goto lerror;
- }
-
- assert( hIC->hdr.htype == WH_HINIT );
-
- lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
- if (NULL == lpwhs)
- {
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lerror;
- }
-
- /*
- * 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.refs = 1;
- lpwhs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
-
- WININET_AddRef( &hIC->hdr );
- lpwhs->lpAppInfo = hIC;
- list_add_head( &hIC->hdr.children, &lpwhs->hdr.entry );
-
- handle = WININET_AllocHandle( &lpwhs->hdr );
- if (NULL == handle)
- {
- ERR("Failed to alloc handle\n");
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
- goto lerror;
- }
+ INTERNET_BUFFERSW BuffersInW;
+ BOOL rc = FALSE;
+ DWORD headerlen;
+ LPWSTR header = NULL;
- 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);
- }
- if (lpszUserName && lpszUserName[0])
- lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
- if (lpszPassword && lpszPassword[0])
- lpwhs->lpszPassword = WININET_strdupW(lpszPassword);
- lpwhs->nServerPort = nServerPort;
- lpwhs->nHostPort = nServerPort;
+ TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+ lpBuffersOut, dwFlags, dwContext);
- /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
- if (!(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
+ if (lpBuffersIn)
{
- INTERNET_SendCallback(&hIC->hdr, dwContext,
- INTERNET_STATUS_HANDLE_CREATED, &handle,
- sizeof(handle));
+ BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
+ if (lpBuffersIn->lpcszHeader)
+ {
+ 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);
+ }
+ else
+ BuffersInW.lpcszHeader = NULL;
+ BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
+ BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
+ BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
+ BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
+ BuffersInW.Next = NULL;
}
-lerror:
- if( lpwhs )
- WININET_Release( &lpwhs->hdr );
+ rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
-/*
- * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
- * windows
- */
+ HeapFree(GetProcessHeap(),0,header);
- TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
- return handle;
+ return rc;
}
-
/***********************************************************************
- * HTTP_OpenConnection (internal)
+ * HttpSendRequestW (WININET.@)
*
- * Connect to a web server
+ * Sends the specified request to the HTTP server
*
* RETURNS
+ * TRUE on success
+ * FALSE on failure
*
- * TRUE on success
- * FALSE on failure
*/
-static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
+BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
{
- BOOL bSuccess = FALSE;
- LPWININETHTTPSESSIONW lpwhs;
+ LPWININETHTTPREQW lpwhr;
+ LPWININETHTTPSESSIONW lpwhs = NULL;
LPWININETAPPINFOW hIC = NULL;
- char szaddr[32];
-
- TRACE("-->\n");
+ BOOL r;
+ TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
+ debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
- if (lpwhr->hdr.htype != WH_HHTTPREQ)
+ lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
{
- INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ r = FALSE;
goto lend;
}
- if (NETCON_connected(&lpwhr->netConnection))
+ lpwhs = lpwhr->lpHttpSession;
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
{
- bSuccess = TRUE;
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ r = FALSE;
goto lend;
}
- if (!HTTP_ResolveName(lpwhr)) goto lend;
-
- lpwhs = lpwhr->lpHttpSession;
hIC = lpwhs->lpAppInfo;
- inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_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))
+ if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
{
- WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ r = FALSE;
goto lend;
}
- if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
- sizeof(lpwhs->socketAddress)))
- goto lend;
-
- if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
+ if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
- /* Note: we differ from Microsoft's WinINet here. they seem to have
- * a bug that causes no status callbacks to be sent when starting
- * a tunnel to a proxy server using the CONNECT verb. i believe our
- * 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))
- goto lend;
+ WORKREQUEST workRequest;
+ struct WORKREQ_HTTPSENDREQUESTW *req;
- if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName))
+ workRequest.asyncproc = AsyncHttpSendRequestProc;
+ workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+ req = &workRequest.u.HttpSendRequestW;
+ if (lpszHeaders)
{
- WARN("Couldn't connect securely to host\n");
- goto lend;
- }
- }
-
- INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
- INTERNET_STATUS_CONNECTED_TO_SERVER,
- szaddr, strlen(szaddr)+1);
-
- bSuccess = TRUE;
-
-lend:
- lpwhr->read_pos = lpwhr->read_size = 0;
- lpwhr->read_chunked = FALSE;
-
- TRACE("%d <--\n", bSuccess);
- return bSuccess;
-}
+ DWORD size;
+ if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
+ else size = dwHeaderLength * sizeof(WCHAR);
-/***********************************************************************
- * HTTP_clear_response_headers (internal)
- *
- * clear out any old response headers
- */
-static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
-{
- DWORD i;
+ 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;
- for( i=0; i<lpwhr->nCustHeaders; i++)
+ INTERNET_AsyncCall(&workRequest);
+ /*
+ * This is from windows.
+ */
+ INTERNET_SetLastError(ERROR_IO_PENDING);
+ r = FALSE;
+ }
+ else
{
- if( !lpwhr->pCustHeaders[i].lpszField )
- continue;
- if( !lpwhr->pCustHeaders[i].lpszValue )
- continue;
- if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST )
- continue;
- HTTP_DeleteCustomHeader( lpwhr, i );
- i--;
+ r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
+ dwHeaderLength, lpOptional, dwOptionalLength,
+ dwOptionalLength, TRUE);
}
+lend:
+ if( lpwhr )
+ WININET_Release( &lpwhr->hdr );
+ return r;
}
/***********************************************************************
- * HTTP_GetResponseHeaders (internal)
+ * HttpSendRequestA (WININET.@)
*
- * Read server response
+ * Sends the specified request to the HTTP server
*
* RETURNS
+ * TRUE on success
+ * FALSE on failure
*
- * TRUE on success
- * FALSE on error
*/
-static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear)
+BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
{
- INT cbreaks = 0;
- WCHAR buffer[MAX_REPLY_LEN];
- DWORD buflen = MAX_REPLY_LEN;
- BOOL bSuccess = FALSE;
- INT rc = 0;
- static const WCHAR szHundred[] = {'1','0','0',0};
- char bufferA[MAX_REPLY_LEN];
- LPWSTR status_code, status_text;
- DWORD cchMaxRawHeaders = 1024;
- LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
- LPWSTR temp;
- DWORD cchRawHeaders = 0;
-
- TRACE("-->\n");
-
- /* clear old response headers (eg. from a redirect response) */
- if (clear) HTTP_clear_response_headers( lpwhr );
-
- if (!NETCON_connected(&lpwhr->netConnection))
- goto lend;
-
- do {
- /*
- * 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 );
-
- /* split the version from the status code */
- status_code = strchrW( buffer, ' ' );
- if( !status_code )
- goto lend;
- *status_code++=0;
-
- /* split the status code from the status text */
- status_text = strchrW( status_code, ' ' );
- if( !status_text )
- goto lend;
- *status_text++=0;
-
- TRACE("version [%s] status code [%s] status text [%s]\n",
- debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
+ 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;
+}
- } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */
+static BOOL HTTP_HttpEndRequestW(LPWININETHTTPREQW lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+{
+ BOOL rc = FALSE;
+ INT responseLen;
+ DWORD dwBufferSize;
+ INTERNET_ASYNC_RESULT iar;
- /* Add status code */
- HTTP_ProcessHeader(lpwhr, szStatus, status_code,
- HTTP_ADDHDR_FLAG_REPLACE);
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
- HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
- HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
+ responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
+ if (responseLen)
+ rc = TRUE;
- lpwhr->lpszVersion= WININET_strdupW(buffer);
- lpwhr->lpszStatusText = WININET_strdupW(status_text);
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
- /* Restore the spaces */
- *(status_code-1) = ' ';
- *(status_text-1) = ' ';
+ /* process cookies here. Is this right? */
+ HTTP_ProcessCookies(lpwhr);
- /* regenerate raw headers */
- 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';
+ if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
- /* Parse each response line */
- do
+ if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
{
- buflen = MAX_REPLY_LEN;
- if (read_line(lpwhr, bufferA, &buflen))
+ DWORD dwCode,dwCodeLength = sizeof(DWORD);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) &&
+ (dwCode == 302 || dwCode == 301 || dwCode == 303))
{
- 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 );
-
- pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
- if (pFieldAndValue)
+ WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
+ dwBufferSize=sizeof(szNewLocation);
+ if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
{
- 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);
+ /* redirects are always GETs */
+ HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+ lpwhr->lpszVerb = WININET_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));
+ rc = HTTP_HandleRedirect(lpwhr, new_url);
+ if (rc)
+ rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
+ HeapFree( GetProcessHeap(), 0, new_url );
+ }
}
}
- else
- {
- cbreaks++;
- if (cbreaks >= 2)
- break;
- }
- }while(1);
-
- HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
- lpwhr->lpszRawHeaders = lpszRawHeaders;
- TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
- bSuccess = TRUE;
+ }
-lend:
+ iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
+ iar.dwError = rc ? 0 : INTERNET_GetLastError();
- TRACE("<--\n");
- if (bSuccess)
- return rc;
- else
- {
- HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
- return 0;
- }
+ INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+ INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+ sizeof(INTERNET_ASYNC_RESULT));
+ return rc;
}
-
-static void strip_spaces(LPWSTR start)
+static void AsyncHttpEndRequestProc(WORKREQUEST *work)
{
- LPWSTR str = start;
- LPWSTR end;
-
- while (*str == ' ' && *str != '\0')
- str++;
+ struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
+ LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)work->hdr;
- if (str != start)
- memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
+ TRACE("%p\n", lpwhr);
- end = start + strlenW(start) - 1;
- while (end >= start && *end == ' ')
- {
- *end = '\0';
- end--;
- }
+ HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
}
-
/***********************************************************************
- * HTTP_InterpretHttpHeader (internal)
+ * HttpEndRequestW (WININET.@)
*
- * Parse server response
+ * Ends an HTTP request that was started by HttpSendRequestEx
*
* RETURNS
+ * TRUE if successful
+ * FALSE on failure
*
- * Pointer to array of field, value, NULL on success.
- * NULL on error.
*/
-static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
+BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
+ LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
{
- LPWSTR * pTokenPair;
- LPWSTR pszColon;
- INT len;
+ BOOL rc = FALSE;
+ LPWININETHTTPREQW lpwhr;
- pTokenPair = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTokenPair)*3);
+ TRACE("-->\n");
- pszColon = strchrW(buffer, ':');
- /* must have two tokens */
- if (!pszColon)
+ if (lpBuffersOut)
{
- HTTP_FreeTokens(pTokenPair);
- if (buffer[0])
- TRACE("No ':' in line: %s\n", debugstr_w(buffer));
- return NULL;
+ INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
- pTokenPair[0] = HeapAlloc(GetProcessHeap(), 0, (pszColon - buffer + 1) * sizeof(WCHAR));
- if (!pTokenPair[0])
+ lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
+
+ if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
{
- HTTP_FreeTokens(pTokenPair);
- return NULL;
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ if (lpwhr)
+ WININET_Release( &lpwhr->hdr );
+ return FALSE;
}
- memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
- pTokenPair[0][pszColon - buffer] = '\0';
+ lpwhr->hdr.dwFlags |= dwFlags;
- /* skip colon */
- pszColon++;
- len = strlenW(pszColon);
- pTokenPair[1] = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
- if (!pTokenPair[1])
+ if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
{
- HTTP_FreeTokens(pTokenPair);
- return NULL;
- }
- memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
+ WORKREQUEST work;
+ struct WORKREQ_HTTPENDREQUESTW *request;
- strip_spaces(pTokenPair[0]);
- strip_spaces(pTokenPair[1]);
+ work.asyncproc = AsyncHttpEndRequestProc;
+ work.hdr = WININET_AddRef( &lpwhr->hdr );
- TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
- return pTokenPair;
+ request = &work.u.HttpEndRequestW;
+ request->dwFlags = dwFlags;
+ request->dwContext = dwContext;
+
+ INTERNET_AsyncCall(&work);
+ INTERNET_SetLastError(ERROR_IO_PENDING);
+ }
+ else
+ rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
+
+ WININET_Release( &lpwhr->hdr );
+ TRACE("%i <--\n",rc);
+ return rc;
}
/***********************************************************************
- * HTTP_ProcessHeader (internal)
+ * HttpEndRequestA (WININET.@)
*
- * Stuff header into header tables according to <dwModifier>
+ * Ends an HTTP request that was started by HttpSendRequestEx
+ *
+ * RETURNS
+ * TRUE if successful
+ * FALSE on failure
*
*/
-
-#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)
+BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
+ LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
{
- LPHTTPHEADERW lphttpHdr = NULL;
- BOOL bSuccess = FALSE;
- INT index = -1;
- BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
-
- TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
-
- /* REPLACE wins out over ADD */
- if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
- dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
-
- if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
- index = -1;
- else
- index = HTTP_GetCustomHeaderIndex(lpwhr, field, 0, request_only);
+ TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
- if (index >= 0)
+ if (lpBuffersOut)
{
- if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
- {
- return FALSE;
- }
- lphttpHdr = &lpwhr->pCustHeaders[index];
+ INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
- else if (value)
- {
- HTTPHEADERW hdr;
- hdr.lpszField = (LPWSTR)field;
- hdr.lpszValue = (LPWSTR)value;
- hdr.wFlags = hdr.wCount = 0;
+ return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
+}
- if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
- hdr.wFlags |= HDR_ISREQUEST;
+/***********************************************************************
+ * HTTP_HttpOpenRequestW (internal)
+ *
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
+ *
+ */
+HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
+ LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+ LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD_PTR dwContext)
+{
+ LPWININETAPPINFOW hIC = NULL;
+ LPWININETHTTPREQW lpwhr;
+ LPWSTR lpszHostName = NULL;
+ HINTERNET handle = NULL;
+ static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
+ DWORD len;
- return HTTP_InsertCustomHeader(lpwhr, &hdr);
- }
- /* no value to delete */
- else return TRUE;
+ TRACE("-->\n");
- if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
- lphttpHdr->wFlags |= HDR_ISREQUEST;
- else
- lphttpHdr->wFlags &= ~HDR_ISREQUEST;
+ assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
+ hIC = lpwhs->lpAppInfo;
- if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+ lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
+ if (NULL == lpwhr)
{
- HTTP_DeleteCustomHeader( lpwhr, index );
-
- if (value)
- {
- HTTPHEADERW hdr;
-
- hdr.lpszField = (LPWSTR)field;
- hdr.lpszValue = (LPWSTR)value;
- hdr.wFlags = hdr.wCount = 0;
+ INTERNET_SetLastError(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 );
- if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
- hdr.wFlags |= HDR_ISREQUEST;
+ WININET_AddRef( &lpwhs->hdr );
+ lpwhr->lpHttpSession = lpwhs;
+ list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
- return HTTP_InsertCustomHeader(lpwhr, &hdr);
- }
+ lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
+ (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
+ if (NULL == lpszHostName)
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ goto lend;
+ }
- return TRUE;
+ handle = WININET_AllocHandle( &lpwhr->hdr );
+ if (NULL == handle)
+ {
+ INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ goto lend;
}
- else if (dwModifier & COALESCEFLAGS)
+
+ if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
{
- LPWSTR lpsztmp;
- WCHAR ch = 0;
- INT len = 0;
- INT origlen = strlenW(lphttpHdr->lpszValue);
- INT valuelen = strlenW(value);
+ InternetCloseHandle( handle );
+ handle = NULL;
+ goto lend;
+ }
- if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
- {
- ch = ',';
- lphttpHdr->wFlags |= HDR_COMMADELIMITED;
- }
- else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
+ 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)
{
- ch = ';';
- lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+ ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
+ strcpyW(lpwhr->lpszPath,lpszObjectName);
}
+ }else {
+ static const WCHAR slashW[] = {'/',0};
- len = origlen + valuelen + ((ch > 0) ? 2 : 0);
+ lpwhr->lpszPath = WININET_strdupW(slashW);
+ }
- lpsztmp = HeapReAlloc(GetProcessHeap(), 0, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
- if (lpsztmp)
- {
- lphttpHdr->lpszValue = lpsztmp;
- /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
- if (ch > 0)
- {
- lphttpHdr->lpszValue[origlen] = ch;
- origlen++;
- lphttpHdr->lpszValue[origlen] = ' ';
- origlen++;
- }
+ if (lpszReferrer && *lpszReferrer)
+ HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
- memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
- lphttpHdr->lpszValue[len] = '\0';
- bSuccess = TRUE;
- }
- else
+ if (lpszAcceptTypes)
+ {
+ int i;
+ for (i = 0; lpszAcceptTypes[i]; i++)
{
- WARN("HeapReAlloc (%d bytes) failed\n",len+1);
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ 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));
}
}
- TRACE("<-- %d\n",bSuccess);
- return bSuccess;
-}
-
-/***********************************************************************
- * HTTP_FinishedReading (internal)
- *
- * Called when all content from server has been read by client.
- *
- */
-static BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr)
-{
- WCHAR szVersion[10];
- WCHAR szConnectionResponse[20];
- DWORD dwBufferSize = sizeof(szVersion);
- BOOL keepalive = FALSE;
+ lpwhr->lpszVerb = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
- TRACE("\n");
+ if (lpszVersion)
+ lpwhr->lpszVersion = WININET_strdupW(lpszVersion);
+ else
+ lpwhr->lpszVersion = WININET_strdupW(g_szHttp1_1);
- /* 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) &&
- !strcmpiW(szVersion, g_szHttp1_1))
+ if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
+ lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
+ lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
{
- keepalive = TRUE;
+ 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);
- dwBufferSize = sizeof(szConnectionResponse);
- if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
- HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
- {
- keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
- }
+ if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
+ lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
+ INTERNET_DEFAULT_HTTPS_PORT :
+ INTERNET_DEFAULT_HTTP_PORT);
- if (!keepalive)
- {
- HTTPREQ_CloseConnection(&lpwhr->hdr);
- }
+ if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
+ lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
+ INTERNET_DEFAULT_HTTPS_PORT :
+ INTERNET_DEFAULT_HTTP_PORT);
- /* FIXME: store data in the URL cache here */
+ if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
+ HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
- return TRUE;
-}
+ 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);
+ return handle;
+}
/***********************************************************************
- * HTTP_GetCustomHeaderIndex (internal)
+ * HttpOpenRequestW (WININET.@)
*
- * Return index of custom header from header array
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
*
*/
-static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField,
- int requested_index, BOOL request_only)
+HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
+ LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+ LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD_PTR dwContext)
{
- DWORD index;
-
- TRACE("%s\n", debugstr_w(lpszField));
+ LPWININETHTTPSESSIONW lpwhs;
+ HINTERNET handle = NULL;
- for (index = 0; index < lpwhr->nCustHeaders; index++)
+ 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)
{
- if (strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
- continue;
-
- if (request_only && !(lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
- continue;
-
- if (!request_only && (lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
- continue;
-
- if (requested_index == 0)
- break;
- requested_index --;
+ int i;
+ for(i=0;lpszAcceptTypes[i]!=NULL;i++)
+ TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
}
- if (index >= lpwhr->nCustHeaders)
- index = -1;
+ lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
+ if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
+ {
+ INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ goto lend;
+ }
- TRACE("Return: %d\n", index);
- return index;
+ /*
+ * 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;
}
/***********************************************************************
- * HTTP_InsertCustomHeader (internal)
+ * HttpOpenRequestA (WININET.@)
*
- * Insert header into array
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ * HINTERNET a HTTP request handle on success
+ * NULL on failure
*
*/
-static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
+HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
+ LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
+ LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
+ DWORD dwFlags, DWORD_PTR dwContext)
{
- INT count;
- LPHTTPHEADERW lph = NULL;
- BOOL r = FALSE;
+ LPWSTR szVerb = NULL, szObjectName = NULL;
+ LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
+ INT len, acceptTypesCount;
+ HINTERNET rc = FALSE;
+ LPCSTR *types;
- TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
- count = lpwhr->nCustHeaders + 1;
- if (count > 1)
- lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
- else
- lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
+ TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
+ debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
+ debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
+ dwFlags, dwContext);
- if (NULL != lph)
+ if (lpszVerb)
{
- 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;
+ len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 );
+ szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if ( !szVerb )
+ goto end;
+ MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len);
}
- else
+
+ if (lpszObjectName)
{
- INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+ len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 );
+ szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if ( !szObjectName )
+ goto end;
+ MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len );
}
- return r;
-}
-
-
-/***********************************************************************
- * HTTP_DeleteCustomHeader (internal)
- *
- * Delete header from array
- * If this function is called, the indexs may change.
- */
-static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index)
-{
- if( lpwhr->nCustHeaders <= 0 )
- return FALSE;
- if( index >= lpwhr->nCustHeaders )
- return FALSE;
- lpwhr->nCustHeaders--;
+ if (lpszVersion)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 );
+ szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if ( !szVersion )
+ goto end;
+ MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len );
+ }
- HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszField);
- HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszValue);
+ if (lpszReferrer)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 );
+ szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if ( !szReferrer )
+ goto end;
+ MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len );
+ }
- memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
- (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
- memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
+ if (lpszAcceptTypes)
+ {
+ 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;
- return TRUE;
-}
+ acceptTypesCount = 0;
+ types = lpszAcceptTypes;
+ while (*types)
+ {
+ __TRY
+ {
+ if (*types && **types)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 );
+ szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len);
+ acceptTypesCount++;
+ }
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ /* ignore invalid pointer */
+ }
+ __ENDTRY;
+ types++;
+ }
+ szAcceptTypes[acceptTypesCount] = NULL;
+ }
-/***********************************************************************
- * HTTP_VerifyValidHeader (internal)
- *
- * Verify the given header is not invalid for the given http request
- *
- */
-static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field)
-{
- /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
- if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
- return FALSE;
+ rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
+ szVersion, szReferrer,
+ (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
- return TRUE;
-}
+end:
+ if (szAcceptTypes)
+ {
+ acceptTypesCount = 0;
+ while (szAcceptTypes[acceptTypesCount])
+ {
+ HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
+ acceptTypesCount++;
+ }
+ HeapFree(GetProcessHeap(), 0, szAcceptTypes);
+ }
+ HeapFree(GetProcessHeap(), 0, szReferrer);
+ HeapFree(GetProcessHeap(), 0, szVersion);
+ HeapFree(GetProcessHeap(), 0, szObjectName);
+ HeapFree(GetProcessHeap(), 0, szVerb);
-/***********************************************************************
- * IsHostInProxyBypassList (@)
- *
- * Undocumented
- *
- */
-BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
-{
- FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
- return FALSE;
+ return rc;
}
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h
index 1d49eaa..e944434 100644
--- a/dlls/wininet/internet.h
+++ b/dlls/wininet/internet.h
@@ -389,14 +389,6 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest);
LPSTR INTERNET_GetResponseBuffer(void);
LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen);
-BOOLAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
- DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
- DWORD dwContentLength, BOOL bEndRequest);
-INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
- LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
- LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
- DWORD dwFlags, DWORD_PTR dwContext);
-
VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext,
DWORD dwInternetStatus, LPVOID lpvStatusInfo,
DWORD dwStatusInfoLength);
--
1.6.3.1
More information about the wine-patches
mailing list