Windows2003-3790/inetcore/wininet/http/sendapi.cxx
2020-09-30 16:53:55 +02:00

826 lines
21 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
sendapi.cxx
Abstract:
This file contains the implementation of the HttpSendRequestA API.
Contents:
HttpSendRequestA
HttpSendRequestW
HttpSendRequestExA
HttpSendRequestExW
HttpEndRequestA
HttpEndRequestW
HttpWrapSendRequest
Author:
Keith Moore (keithmo) 16-Nov-1994
Revision History:
29-Apr-97 rfirth
Conversion to FSM
--*/
#include <wininetp.h>
#include <perfdiag.hxx>
#include "httpp.h"
//
// private prototypes
//
PRIVATE
BOOL
HttpWrapSendRequest(
IN HINTERNET hRequest,
IN LPCSTR lpszHeaders OPTIONAL,
IN DWORD dwHeadersLength,
IN LPVOID lpOptional OPTIONAL,
IN DWORD dwOptionalLength,
IN DWORD dwOptionalLengthTotal,
IN AR_TYPE arRequest
);
//
// functions
//
INTERNETAPI_(BOOL) HttpSendRequestA(
IN HINTERNET hRequest,
IN LPCSTR lpszHeaders OPTIONAL,
IN DWORD dwHeadersLength,
IN LPVOID lpOptional OPTIONAL,
IN DWORD dwOptionalLength
)
/*++
Routine Description:
Sends the specified request to the HTTP server.
Arguments:
hRequest - An open HTTP request handle returned by
HttpOpenRequest()
lpszHeaders - Additional headers to be appended to the request.
This may be NULL if there are no additional
headers to append
dwHeadersLength - The length (in characters) of the additional
headers. If this is -1L and lpszAdditional is
non-NULL, then lpszAdditional is assumed to be
zero terminated (ASCIIZ)
lpOptionalData - Any optional data to send immediately after the
request headers. This is typically used for POST
operations. This may be NULL if there is no
optional data to send
dwOptionalDataLength - The length (in BYTEs) of the optional data. This
may be zero if there is no optional data to send
Return Value:
BOOL
Success - TRUE
Failure - FALSE. For more information call GetLastError(). If the
request was async, then GetLastError() will return
ERROR_IO_PENDING which means that the operation initially
succeeded, and that the caller should wait for the status
callback to discover the final success/failure status
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpSendRequestA",
"%#x, %.80q, %d, %#x, %d",
hRequest,
lpszHeaders,
dwHeadersLength,
lpOptional,
dwOptionalLength
));
BOOL fRet= HttpWrapSendRequest(
hRequest,
lpszHeaders,
dwHeadersLength,
lpOptional,
dwOptionalLength,
0,
AR_HTTP_SEND_REQUEST
);
DEBUG_LEAVE_API(fRet);
return fRet;
}
INTERNETAPI_(BOOL) HttpSendRequestW(
IN HINTERNET hRequest,
IN LPCWSTR lpszHeaders OPTIONAL,
IN DWORD dwHeadersLength,
IN LPVOID lpOptional OPTIONAL,
IN DWORD dwOptionalLength
)
/*++
Routine Description:
Sends the specified request to the HTTP server.
Arguments:
hRequest - An open HTTP request handle returned by
HttpOpenRequest()
lpszHeaders - Additional headers to be appended to the request.
This may be NULL if there are no additional
headers to append
dwHeadersLength - The length (in characters) of the additional
headers. If this is -1L and lpszAdditional is
non-NULL, then lpszAdditional is assumed to be
zero terminated (ASCIIZ)
lpOptionalData - Any optional data to send immediately after the
request headers. This is typically used for POST
operations. This may be NULL if there is no
optional data to send
dwOptionalDataLength - The length (in BYTEs) of the optional data. This
may be zero if there is no optional data to send
Return Value:
BOOL
Success - TRUE
Failure - FALSE. For more information call GetLastError(). If the
request was async, then GetLastError() will return
ERROR_IO_PENDING which means that the operation initially
succeeded, and that the caller should wait for the status
callback to discover the final success/failure status
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpSendRequestW",
"%#x, %.80wq, %d, %#x, %d",
hRequest,
lpszHeaders,
dwHeadersLength,
lpOptional,
dwOptionalLength
));
DWORD dwErr = ERROR_SUCCESS;
BOOL fResult = FALSE;
MEMORYPACKET mpHeaders;
if (!hRequest)
{
dwErr = ERROR_INVALID_HANDLE;
goto cleanup;
}
if (lpszHeaders)
{
ALLOC_MB(lpszHeaders, dwHeadersLength, mpHeaders);
if (!mpHeaders.psStr)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
UNICODE_TO_ANSI(lpszHeaders, mpHeaders);
}
fResult = HttpWrapSendRequest(hRequest, mpHeaders.psStr, mpHeaders.dwSize,
lpOptional, dwOptionalLength, 0, AR_HTTP_SEND_REQUEST);
cleanup:
if (dwErr!=ERROR_SUCCESS)
{
SetLastError(dwErr);
DEBUG_ERROR(HTTP, dwErr);
}
DEBUG_LEAVE_API(fResult);
return fResult;
}
INTERNETAPI_(BOOL) HttpSendRequestExA(
IN HINTERNET hRequest,
IN LPINTERNET_BUFFERSA lpBuffersIn OPTIONAL,
OUT LPINTERNET_BUFFERSA lpBuffersOut OPTIONAL,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
description-of-function.
Arguments:
hRequest -
lpBuffersIn -
lpBuffersOut -
dwFlags -
dwContext -
Return Value:
WINAPI
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpSendRequestExA",
"%#x, %#x, %#x, %#x, %#x",
hRequest,
lpBuffersIn,
lpBuffersOut,
dwFlags,
dwContext
));
DWORD error = ERROR_SUCCESS;
LPCSTR lpszHeaders = NULL;
DWORD dwHeadersLength = 0;
LPVOID lpOptional = NULL;
DWORD dwOptionalLength = 0;
DWORD dwOptionalLengthTotal = 0;
BOOL fRet = FALSE;
if ( lpBuffersOut )
{
error = ERROR_INVALID_PARAMETER;
goto quit;
}
if ( lpBuffersIn )
{
if ( IsBadReadPtr(lpBuffersIn, sizeof(INTERNET_BUFFERSA)) ||
lpBuffersIn->dwStructSize != sizeof(INTERNET_BUFFERSA) )
{
error = ERROR_INVALID_PARAMETER;
goto quit;
}
lpszHeaders = lpBuffersIn->lpcszHeader;
dwHeadersLength = lpBuffersIn->dwHeadersLength;
lpOptional = lpBuffersIn->lpvBuffer;
dwOptionalLength = lpBuffersIn->dwBufferLength;
dwOptionalLengthTotal = lpBuffersIn->dwBufferTotal;
}
fRet= HttpWrapSendRequest(
hRequest,
lpszHeaders,
dwHeadersLength,
lpOptional,
dwOptionalLength,
dwOptionalLengthTotal,
AR_HTTP_BEGIN_SEND_REQUEST
);
quit:
if ( error != ERROR_SUCCESS )
{
SetLastError(error);
DEBUG_ERROR(HTTP, error);
fRet = FALSE;
}
DEBUG_LEAVE_API(fRet);
return fRet;
}
INTERNETAPI_(BOOL) HttpSendRequestExW(
IN HINTERNET hRequest,
IN LPINTERNET_BUFFERSW lpBuffersIn OPTIONAL,
OUT LPINTERNET_BUFFERSW lpBuffersOut OPTIONAL,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
description-of-function.
Arguments:
hRequest -
lpBuffersIn -
lpBuffersOut -
dwFlags -
dwContext -
Return Value:
BOOL
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpSendRequestExW",
"%#x, %#x, %#x, %#x, %#x",
hRequest,
lpBuffersIn,
lpBuffersOut,
dwFlags,
dwContext
));
DWORD dwErr = ERROR_SUCCESS;
BOOL fResult = FALSE;
MEMORYPACKET mpHeaders;
LPVOID pOptional = NULL;
DWORD dwOptionalLength = 0;
DWORD dwOptionalLengthTotal = 0;
if (!hRequest)
{
dwErr = ERROR_INVALID_HANDLE;
}
else if (lpBuffersOut)
{
dwErr = ERROR_INVALID_PARAMETER;
}
else
{
if ( lpBuffersIn )
{
if (IsBadReadPtr(lpBuffersIn, sizeof(INTERNET_BUFFERS))
||
(lpBuffersIn->dwStructSize != sizeof(INTERNET_BUFFERSW)))
{
dwErr = ERROR_INVALID_PARAMETER;
goto cleanup;
}
if (lpBuffersIn->lpcszHeader)
{
ALLOC_MB(lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, mpHeaders);
if (!mpHeaders.psStr)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
UNICODE_TO_ANSI(lpBuffersIn->lpcszHeader, mpHeaders);
}
pOptional = lpBuffersIn->lpvBuffer;
dwOptionalLength = lpBuffersIn->dwBufferLength;
dwOptionalLengthTotal = lpBuffersIn->dwBufferTotal;
}
fResult = HttpWrapSendRequest(
hRequest,
mpHeaders.psStr,
mpHeaders.dwSize,
pOptional,
dwOptionalLength,
dwOptionalLengthTotal,
AR_HTTP_BEGIN_SEND_REQUEST
);
}
cleanup:
if (dwErr!=ERROR_SUCCESS)
{
SetLastError(dwErr);
DEBUG_ERROR(HTTP, dwErr);
}
DEBUG_LEAVE_API(fResult);
return fResult;
}
INTERNETAPI_(BOOL) HttpEndRequestA(
IN HINTERNET hRequest,
OUT LPINTERNET_BUFFERSA lpBuffersOut OPTIONAL,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
description-of-function.
Arguments:
hRequest -
lpBuffersOut -
dwFlags -
dwContext -
Return Value:
WINAPI
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpEndRequestA",
"%#x, %#x, %#x, %#x",
hRequest,
lpBuffersOut,
dwFlags,
dwContext
));
DWORD error = ERROR_SUCCESS;
IN LPCSTR lpszHeaders = NULL;
IN DWORD dwHeadersLength = 0;
IN LPVOID lpOptional = NULL;
IN DWORD dwOptionalLength = 0;
BOOL fRet = FALSE;
if ( lpBuffersOut )
{
error = ERROR_INVALID_PARAMETER;
goto quit;
}
fRet= HttpWrapSendRequest(
hRequest,
NULL,
0,
NULL,
0,
0,
AR_HTTP_END_SEND_REQUEST
);
quit:
if ( error != ERROR_SUCCESS )
{
SetLastError(error);
DEBUG_ERROR(HTTP, error);
fRet = FALSE;
}
DEBUG_LEAVE_API(fRet);
return fRet;
}
INTERNETAPI_(BOOL) HttpEndRequestW(
IN HINTERNET hRequest,
OUT LPINTERNET_BUFFERSW lpBuffersOut OPTIONAL,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
description-of-function.
Arguments:
hRequest -
lpBuffersOut -
dwFlags -
dwContext -
Return Value:
BOOL
--*/
{
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpEndRequestW",
"%#x, %#x, %#x, %#x",
hRequest,
lpBuffersOut,
dwFlags,
dwContext
));
DWORD dwErr = ERROR_SUCCESS;
BOOL fResult = FALSE;
if (!hRequest)
{
dwErr = ERROR_INVALID_HANDLE;
}
else if (lpBuffersOut)
{
dwErr = ERROR_INVALID_PARAMETER;
}
else
{
fResult = HttpWrapSendRequest(hRequest, NULL, 0, NULL, 0, 0, AR_HTTP_END_SEND_REQUEST);
}
if (dwErr!=ERROR_SUCCESS)
{
SetLastError(dwErr);
DEBUG_ERROR(HTTP, dwErr);
}
DEBUG_LEAVE_API(fResult);
return fResult;
}
PRIVATE
BOOL
HttpWrapSendRequest(
IN HINTERNET hRequest,
IN LPCSTR lpszHeaders OPTIONAL,
IN DWORD dwHeadersLength,
IN LPVOID lpOptional OPTIONAL,
IN DWORD dwOptionalLength,
IN DWORD dwOptionalLengthTotal,
IN AR_TYPE arRequest
)
/*++
Routine Description:
Sends the specified request to the HTTP server.
Arguments:
hRequest - An open HTTP request handle returned by
HttpOpenRequest()
lpszHeaders - Additional headers to be appended to the request.
This may be NULL if there are no additional
headers to append
dwHeadersLength - The length (in characters) of the additional
headers. If this is -1L and lpszAdditional is
non-NULL, then lpszAdditional is assumed to be
zero terminated (ASCIIZ)
lpOptionalData - Any optional data to send immediately after the
request headers. This is typically used for POST
operations. This may be NULL if there is no
optional data to send
dwOptionalDataLength - The length (in BYTEs) of the optional data. This
may be zero if there is no optional data to send
dwOptionalLengthTotal - Total length need to be sent for File Upload.
arRequest - Which API the caller is making,
assumed to be HttpEndRequestA, HttpSendRequestExA, or
HttpSendRequestA
Return Value:
BOOL
Success - TRUE
Failure - FALSE. For more information call GetLastError(). If the
request was async, then GetLastError() will return
ERROR_IO_PENDING which means that the operation initially
succeeded, and that the caller should wait for the status
callback to discover the final success/failure status
Comments:
--*/
{
DEBUG_ENTER((DBG_HTTP,
Bool,
"HttpWrapSendRequest",
"%#x, %.80q, %d, %#x, %d, %d",
hRequest,
lpszHeaders,
dwHeadersLength,
lpOptional,
dwOptionalLength,
dwOptionalLengthTotal
));
PERF_ENTER(HttpWrapSendRequest);
DWORD error = ERROR_SUCCESS;
HINTERNET hRequestMapped = NULL;
BOOL bDeref = TRUE;
if (!GlobalDataInitialized) {
error = ERROR_INTERNET_NOT_INITIALIZED;
goto done;
}
//
// we will need the thread info for several items
//
LPINTERNET_THREAD_INFO lpThreadInfo;
lpThreadInfo = InternetGetThreadInfo();
if (lpThreadInfo == NULL) {
error = ERROR_INTERNET_INTERNAL_ERROR;
goto done;
}
//
// the only FSMs that can come before this one are InternetOpenUrl() or
// HttpSendRequest() when we are performing nested send for https://
// tunnelling through proxy
//
INET_ASSERT((lpThreadInfo->Fsm == NULL)
|| (lpThreadInfo->Fsm->GetType() == FSM_TYPE_PARSE_HTTP_URL)
|| (lpThreadInfo->Fsm->GetType() == FSM_TYPE_OPEN_PROXY_TUNNEL)
);
INET_ASSERT( arRequest == AR_HTTP_SEND_REQUEST ||
arRequest == AR_HTTP_BEGIN_SEND_REQUEST ||
arRequest == AR_HTTP_END_SEND_REQUEST );
//
// map the handle
//
error = MapHandleToAddress(hRequest, (LPVOID *)&hRequestMapped, FALSE);
if ((error != ERROR_SUCCESS) && (hRequestMapped == NULL)) {
goto quit;
}
//
// Cast it to the object that we know. We are going to do caching
// semantics with this
//
HTTP_REQUEST_HANDLE_OBJECT * pRequest;
pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequestMapped;
//
// set the context and handle info & reset the error variables
//
_InternetSetContext(lpThreadInfo,
((INTERNET_HANDLE_OBJECT *)hRequestMapped)->GetContext()
);
_InternetSetObjectHandle(lpThreadInfo, hRequest, hRequestMapped);
_InternetClearLastError(lpThreadInfo);
//
// quit now if the handle was invalid
//
if (error != ERROR_SUCCESS) {
goto quit;
}
//
// use RIsHandleLocal() to discover 4 things:
//
// 1. Handle is valid
// 2. Handle is of expected type (HTTP Request in this case)
// 3. Handle is local or remote
// 4. Handle supports async I/O
//
BOOL isLocal;
BOOL isAsync;
error = RIsHandleLocal(hRequestMapped,
&isLocal,
&isAsync,
TypeHttpRequestHandle
);
if (error != ERROR_SUCCESS) {
goto quit;
}
//
// For SEND_REQUEST, and BEGIN_SEND_REQUEST, we need
// to do some basic initalization
//
if ( arRequest == AR_HTTP_SEND_REQUEST ||
arRequest == AR_HTTP_BEGIN_SEND_REQUEST)
{
BOOL fGoneOffline = FALSE;
error = pRequest->InitBeginSendRequest(lpszHeaders,
dwHeadersLength,
&lpOptional,
&dwOptionalLength,
dwOptionalLengthTotal,
&fGoneOffline
);
if ( error != ERROR_SUCCESS || fGoneOffline )
{
if ( error == ERROR_INTERNET_CACHE_SUCCESS )
{
error = ERROR_SUCCESS;
}
goto quit;
}
}
//
// send the request to the server. This may involve redirections and user
// authentication
//
//error = DoFsm(new CFsm_HttpSendRequest(lpOptional, dwOptionalLength, pRequest, arRequest));
//if (error == ERROR_IO_PENDING) {
// bDeref = FALSE;
//}
CFsm_HttpSendRequest * pFsm;
pFsm = new CFsm_HttpSendRequest(lpOptional, dwOptionalLength, pRequest, arRequest);
if (pFsm != NULL) {
if (isAsync && !lpThreadInfo->IsAsyncWorkerThread) {
error = pFsm->QueueWorkItem();
} else {
error = DoFsm(pFsm);
}
if (error == ERROR_IO_PENDING) {
bDeref = FALSE;
}
} else {
error = ERROR_NOT_ENOUGH_MEMORY;
}
quit:
//
// if we went async don't deref the handle
//
if (bDeref && (hRequestMapped != NULL)) {
DereferenceObject((LPVOID)hRequestMapped);
}
done:
BOOL success = TRUE;
// SetLastError must be called after PERF_LEAVE !!!
PERF_LEAVE(HttpWrapSendRequest);
if (error != ERROR_SUCCESS) {
SetLastError(error);
DEBUG_ERROR(HTTP, error);
success = FALSE;
}
DEBUG_LEAVE(success);
return success;
}