Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

685 lines
18 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
add.cxx
Abstract:
This file contains the implementation of the HttpAddRequestHeadersA API.
The following functions are exported by this module:
HttpAddRequestHeadersA
WinHttpAddRequestHeaders
Author:
Keith Moore (keithmo) 16-Nov-1994
Revision History:
Modified to make HttpAddRequestHeadersA remotable. madana (2/8/95)
--*/
#include <wininetp.h>
#include "httpp.h"
//
// private manifests
//
#define VALID_ADD_FLAGS (HTTP_ADDREQ_FLAG_ADD_IF_NEW \
| HTTP_ADDREQ_FLAG_ADD \
| HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA \
| HTTP_ADDREQ_FLAG_REPLACE \
| HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON \
)
//
// functions
//
INTERNETAPI
BOOL
WINAPI
HttpAddRequestHeadersA(
IN HINTERNET hRequest,
IN LPCSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwModifiers
)
/*++
Routine Description:
Appends additional header(s) to an HTTP request handle
Arguments:
hRequest - An open HTTP request handle returned by HttpOpenRequest()
lpszHeaders - The headers to append to the request. Each header must be
terminated by a CR/LF pair.
dwHeadersLength - The length (in characters) of the headers. If this is -1L
then lpszHeaders is assumed to be zero terminated (ASCIIZ)
dwModifiers - flags controlling operation. Can be one or more of:
HTTP_ADDREQ_FLAG_ADD_IF_NEW
- add the header, but only if it does not already
exist. Index must be zero
HTTP_ADDREQ_FLAG_ADD
- if HTTP_ADDREQ_FLAG_REPLACE is set, but the header
is not found and this flag is set then the header
is added, so long as there is a valid header-value
HTTP_ADDREQ_FLAG_COALESCE
HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON
HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA
- concatenate headers of same name. E.g. if we
already have "Accept: text/html" then adding
"Accept: text/*" will create
"Accept: text/html, text/*"
HTTP_ADDREQ_FLAG_REPLACE
- replaces the named header. Only one header can be
supplied. If header-value is empty then the header
is removed
Return Value:
Success - TRUE
The header was appended successfully
Failure - FALSE
The operation failed. Error status is available by calling
GetLastError()
--*/
{
DEBUG_ENTER((DBG_API,
Bool,
"HttpAddRequestHeadersA",
"%#x, %.80q, %d, %#x",
hRequest,
lpszHeaders,
dwHeadersLength,
dwModifiers
));
DWORD error;
HINTERNET hRequestMapped = NULL;
DWORD nestingLevel = 0;
if (!GlobalDataInitialized) {
error = ERROR_WINHTTP_NOT_INITIALIZED;
goto done;
}
//
// get the thread info
//
LPINTERNET_THREAD_INFO lpThreadInfo;
lpThreadInfo = InternetGetThreadInfo();
if (lpThreadInfo == NULL) {
error = ERROR_WINHTTP_INTERNAL_ERROR;
goto done;
}
//
// map the handle
//
error = MapHandleToAddress(hRequest, (LPVOID *)&hRequestMapped, FALSE);
if (error != ERROR_SUCCESS) {
goto quit;
}
_InternetIncNestingCount();
nestingLevel = 1;
//
// validate handle
//
BOOL isLocal;
BOOL isAsync;
error = RIsHandleLocal(hRequestMapped,
&isLocal,
&isAsync,
TypeHttpRequestHandle
);
if (error != ERROR_SUCCESS) {
goto quit;
}
//
// validate parameters
//
INET_ASSERT(!(
(lpszHeaders == NULL)
|| (*lpszHeaders == '\0')
|| (dwHeadersLength == 0)
|| (dwModifiers & (HTTP_ADDREQ_FLAGS_MASK & ~VALID_ADD_FLAGS))) );
INET_ASSERT(error == ERROR_SUCCESS);
//
// BUGBUG - we should determine whether the app is trying to give us a bogus
// header, and whether the header conforms to the format:
//
// "<header>[:[ <value>]]"
//
if (dwHeadersLength == (DWORD)-1)
{
dwHeadersLength = (DWORD)lstrlen(lpszHeaders);
}
if (error == ERROR_SUCCESS) {
error = wHttpAddRequestHeaders(hRequestMapped,
lpszHeaders,
dwHeadersLength,
dwModifiers
);
}
quit:
_InternetDecNestingCount(nestingLevel);
done:
if (error != ERROR_SUCCESS) {
DEBUG_ERROR(HTTP, error);
SetLastError(error);
}
if (hRequestMapped != NULL) {
DereferenceObject((LPVOID)hRequestMapped);
}
DEBUG_LEAVE(error == ERROR_SUCCESS);
return error == ERROR_SUCCESS;
}
INTERNETAPI
BOOL
WINAPI
WinHttpAddRequestHeaders(
IN HINTERNET hRequest,
IN LPCWSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwModifiers
)
/*++
Routine Description:
Appends additional header(s) to an HTTP request handle.
Arguments:
hHttpRequest - An open HTTP request handle returned by HttpOpenRequest().
lpszHeaders - The headers to append to the request. Each header must be
terminated by a CR/LF pair.
dwHeadersLength - The length (in characters) of the headers. If this is
-1L, then lpszHeaders is assumed to be zero terminated (ASCIIZ).
dwModifiers -
Return Value:
TRUE - The header was appended successfully.
FALSE - The operation failed. Error status is available by calling
GetLastError().
Comments:
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"WinHttpAddRequestHeaders",
"%#x, %.80wq, %d, %#x",
hRequest,
lpszHeaders,
dwHeadersLength,
dwModifiers
));
DWORD dwErr = ERROR_SUCCESS;
BOOL fResult = FALSE;
if (!lpszHeaders
|| *lpszHeaders==L'\0'
|| !dwHeadersLength
|| ((dwHeadersLength == -1)
? IsBadStringPtrW(lpszHeaders, (UINT_PTR)-1)
: IsBadReadPtr(lpszHeaders, dwHeadersLength))
|| (dwModifiers & (HTTP_ADDREQ_FLAGS_MASK & ~VALID_ADD_FLAGS)))
{
dwErr = ERROR_INVALID_PARAMETER;
}
else
{
MEMORYPACKET mpHeaders;
ALLOC_MB(lpszHeaders, (dwHeadersLength==-1L ? 0 : dwHeadersLength), mpHeaders);
if (mpHeaders.psStr)
{
UNICODE_TO_ANSI(lpszHeaders, mpHeaders);
fResult = HttpAddRequestHeadersA(hRequest, mpHeaders.psStr, mpHeaders.dwSize, dwModifiers);
}
else
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
}
if (dwErr!=ERROR_SUCCESS)
{
SetLastError(dwErr);
DEBUG_ERROR(HTTP, dwErr);
}
DEBUG_LEAVE_API(fResult);
return fResult;
}
#define DEFAULT_BEGIN_SIZE 8
#define EXPAND_SIZE 8
static const CHAR IsValidHeaderNameChar[] =
{
// 0 1 2 3 4 5 6 7
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
// ' ' '"'
FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
// '(' ')' ',' '/'
FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
// ':' ';' '<' '=' '>' '?'
TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
// '@'
FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
// '[' '\' ']'
TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
// '{'' '}' DEL
TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
};
BOOL IsValidHeaderName(LPCWSTR lpszHeaderName)
{
WCHAR wch;
int nIndex=0;
for ( ; (wch=lpszHeaderName[nIndex]) != 0; nIndex++)
{
if ((wch > ARRAY_ELEMENTS(IsValidHeaderNameChar))
|| !IsValidHeaderNameChar[wch])
{
return FALSE;
}
}
return TRUE;
}
typedef struct _headerrec
{
LPSTR lpName;
int nName;
LPSTR lpValue;
int nValue;
}
HEADER_REC;
PUBLIC
DWORD
wHttpAddRequestHeaders(
IN HINTERNET hRequest,
IN LPCSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwModifiers
)
/*++
Routine Description:
Worker function to append additional header(s) to an HTTP request handle
Arguents:
hRequest - handle of HTTP request
lpszHeaders - pointer to buffer containing one or more headers
dwHeadersLength - length of lpszHeaders. Cannot be -1 at this stage
dwModifiers - flags controlling operation
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
The header string(s) was bad after all
ERROR_WINHTTP_INCORRECT_HANDLE_STATE
We can't add headers to this object at this time
ERROR_HTTP_HEADER_NOT_FOUND
We were asked to replace a header, but couldn't find it
ERROR_HTTP_HEADER_ALREADY_EXISTS
We were asked to add a header, only if one of the same name
doesn't already exist. It does
--*/
{
//
// dwHeadersLength cannot be -1 or 0 at this stage. Nor can lpszHeaders be
// NULL
//
INET_ASSERT(lpszHeaders != NULL);
INET_ASSERT(dwHeadersLength != (DWORD)-1);
INET_ASSERT(dwHeadersLength != 0);
DEBUG_ENTER((DBG_HTTP,
Dword,
"wHttpAddRequestHeaders",
"%#x, %#x [%.80q], %d, %#x",
hRequest,
lpszHeaders,
lpszHeaders,
dwHeadersLength,
dwModifiers
));
//
// get the underlying object and check that we can add headers
//
HTTP_REQUEST_HANDLE_OBJECT * pRequest;
pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequest;
HEADER_REC* pHeaders = NULL;
DWORD error;
if (!IS_VALID_HTTP_STATE(pRequest, ADD, TRUE))
{
error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
goto quit;
}
DWORD offset;
LPSTR header;
offset = 0;
header = (LPSTR)lpszHeaders;
int nCount = DEFAULT_BEGIN_SIZE;
pHeaders = (HEADER_REC *)ALLOCATE_FIXED_MEMORY (sizeof(HEADER_REC)*nCount);
int nHeader = 0;
if (!pHeaders)
{
error = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
error = ERROR_SUCCESS;
do
{
//
// first time: ignore any empty strings; subsequent time: clean off any
// trailing line termination
//
while ((offset < dwHeadersLength)
&& ((lpszHeaders[offset] == '\r') || (lpszHeaders[offset] == '\n')))
{
++offset;
}
if (offset == dwHeadersLength)
{
//
// even if app tried adding empty line(s), we return success
//
error = ERROR_SUCCESS;
break;
}
DWORD length;
DWORD nameLength;
DWORD valueLength;
LPSTR value;
nameLength = 0;
valueLength = 0;
value = NULL;
//
// break the header into header-name, header-value pairs. Exclude CR-LF
// from the header-value (if present)
//
for (length = 0, header = (LPSTR)&lpszHeaders[offset];
offset < dwHeadersLength;
++length, ++offset)
{
char ch = header[length];
if (ch == '\r')
{
//
// end of this particular header?
//
if (((offset+2) < dwHeadersLength)
&& nameLength
&& (header[length+1] == '\n')
&& ((header[length+2] == ' ')
|| (header[length+2] == '\t'))
)
{
//LWS allowing header to spill over to next line
length+=2;
offset+=2;
}
else
{
break;
}
}
else if (ch == '\n')
{
//
// end of this particular header?
//
break;
}
else if (ch == ':')
{
if (nameLength == 0)
{
//
// found end of header name
//
nameLength = length;
value = &header[length];
}
}
if (nameLength == 0)
{
if ((ch > ARRAY_ELEMENTS(IsValidHeaderNameChar))
|| !IsValidHeaderNameChar[ch])
{
error = ERROR_INVALID_PARAMETER;
goto quit;
}
}
}
if (length == 0)
{
//
// empty string
//
continue;
}
else if (nameLength == 0)
{
//
// entry consists of just header-name (e.g. "Accept[\r\n]")
//
nameLength = length;
}
else
{
//
// find the start of the header-value
//
valueLength = (DWORD) (header + length - value);
//ideally we wouldn't eat through all the leading white space or : in the
// header value because they may be significant.
// Don't know of any examples though, so can keep it as such.
//
// N.B. We are allowing any mixture of ':' and ' ' between header
// name and value, but this is probably not a big deal...
//
while ((*value == ':') || (*value == ' ') && (valueLength != 0))
{
++value;
--valueLength;
}
}
if (!value
&& !(dwModifiers & (HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD_IF_NEW)))
{
error = ERROR_INVALID_PARAMETER;
goto quit;
}
pHeaders[nHeader].lpName = header;
pHeaders[nHeader].nName = nameLength;
pHeaders[nHeader].lpValue = value;
pHeaders[nHeader].nValue = valueLength;
if (++nHeader >= nCount)
{
nCount += EXPAND_SIZE;
HEADER_REC* pNewHeaders = (HEADER_REC *)REALLOCATE_MEMORY(pHeaders, sizeof(HEADER_REC)*nCount);
if (pNewHeaders)
pHeaders = pNewHeaders;
else
{
FREE_MEMORY(pHeaders);
pHeaders = NULL;
error = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
}
}
while (error == ERROR_SUCCESS);
for (int nIndex=0; nIndex<nHeader; nIndex++)
{
if (dwModifiers
& (HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD_IF_NEW))
{
//
// replace or remove the header
//
error = pRequest->ReplaceRequestHeader(
pHeaders[nIndex].lpName,
pHeaders[nIndex].nName,
pHeaders[nIndex].lpValue,
pHeaders[nIndex].nValue,
dwModifiers & HTTP_ADDREQ_INDEX_MASK,
dwModifiers & HTTP_ADDREQ_FLAGS_MASK
);
}
else
{
//
// add a single, unterminated header string to the request headers.
// Since these headers came from the app, we don't trust it to get
// the header termination right (number & type of line terminators)
// so we add it ourselves
//
error = pRequest->AddRequestHeader(
pHeaders[nIndex].lpName,
pHeaders[nIndex].nName,
pHeaders[nIndex].lpValue,
pHeaders[nIndex].nValue,
dwModifiers & HTTP_ADDREQ_INDEX_MASK,
dwModifiers & HTTP_ADDREQ_FLAGS_MASK
);
}
if (error != ERROR_SUCCESS)
break;
}
quit:
if (pHeaders)
{
FREE_MEMORY(pHeaders);
}
DEBUG_LEAVE(error);
return error;
}