426 lines
10 KiB
C++
426 lines
10 KiB
C++
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
makeconn.cxx
|
||
|
||
Abstract:
|
||
|
||
This file contains the MakeConnection method
|
||
|
||
Contents:
|
||
CFsm_MakeConnection::RunSM
|
||
HTTP_REQUEST_HANDLE_OBJECT::MakeConnection_Fsm
|
||
|
||
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"
|
||
|
||
//
|
||
// HTTP Request Handle Object methods
|
||
//
|
||
|
||
|
||
DWORD
|
||
CFsm_MakeConnection::RunSM(
|
||
IN CFsm * Fsm
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
Fsm -
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_HTTP,
|
||
Dword,
|
||
"CFsm_MakeConnection::RunSM",
|
||
"%#x",
|
||
Fsm
|
||
));
|
||
|
||
START_SENDREQ_PERF();
|
||
|
||
CFsm_MakeConnection * stateMachine = (CFsm_MakeConnection *)Fsm;
|
||
HTTP_REQUEST_HANDLE_OBJECT * pRequest;
|
||
DWORD error;
|
||
|
||
pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
|
||
|
||
switch (Fsm->GetState()) {
|
||
case FSM_STATE_INIT:
|
||
case FSM_STATE_CONTINUE:
|
||
error = pRequest->MakeConnection_Fsm(stateMachine);
|
||
break;
|
||
|
||
default:
|
||
error = ERROR_WINHTTP_INTERNAL_ERROR;
|
||
Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
|
||
|
||
INET_ASSERT(FALSE);
|
||
|
||
break;
|
||
}
|
||
|
||
STOP_SENDREQ_PERF();
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
DWORD
|
||
HTTP_REQUEST_HANDLE_OBJECT::MakeConnection_Fsm(
|
||
IN CFsm_MakeConnection * Fsm
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
Fsm -
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_HTTP,
|
||
Dword,
|
||
"HTTP_REQUEST_HANDLE_OBJECT::MakeConnection_Fsm",
|
||
"%#x",
|
||
Fsm
|
||
));
|
||
|
||
PERF_ENTER(MakeConnection_Fsm);
|
||
|
||
CFsm_MakeConnection & fsm = *Fsm;
|
||
FSM_STATE state = fsm.GetState();
|
||
DWORD error = fsm.GetError();
|
||
|
||
INTERNET_HANDLE_OBJECT * pInternet;
|
||
pInternet = GetRootHandle (this);
|
||
|
||
if (state == FSM_STATE_INIT) {
|
||
if (GetAuthState() == AUTHSTATE_NEEDTUNNEL) {
|
||
state = FSM_STATE_1;
|
||
} else if (IsTalkingToSecureServerViaProxy()) {
|
||
state = FSM_STATE_3;
|
||
} else {
|
||
state = FSM_STATE_6;
|
||
}
|
||
} else {
|
||
state = fsm.GetFunctionState();
|
||
}
|
||
switch (state) {
|
||
case FSM_STATE_1:
|
||
|
||
//
|
||
// If we're attempting to do NTLM authentication using Proxy tunnelling
|
||
// and we don't have a keep-alive socket to use, then create one
|
||
//
|
||
|
||
if (!(IsWantKeepAlive() && (_Socket != NULL) && _Socket->IsOpen())) {
|
||
fsm.SetFunctionState(FSM_STATE_2);
|
||
error = OpenProxyTunnel();
|
||
if ((error != ERROR_SUCCESS)
|
||
|| ((GetStatusCode() != HTTP_STATUS_OK) && (GetStatusCode() != 0))) {
|
||
goto quit;
|
||
}
|
||
} else {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// fall through
|
||
//
|
||
|
||
case FSM_STATE_2:
|
||
if ((error != ERROR_SUCCESS)
|
||
|| ((GetStatusCode() != HTTP_STATUS_OK) && (GetStatusCode() != 0))) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// Bind Socket Object with Proper HostName,
|
||
// so we can check for valid common name
|
||
// in the handshake.
|
||
//
|
||
|
||
if (_Socket->IsSecure()) {
|
||
/* SCLE ref */
|
||
error = ((ICSecureSocket *)_Socket)->SetHostName(GetHostName(), pInternet->GetSslSessionCache());
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Undo the proxy-ified info found in this Request Object, make it seem like
|
||
// we're doing a connect connection, since we're about to do something like it
|
||
// ( a tunnelled connection through the firewall )
|
||
//
|
||
|
||
error = SetServerInfoWithScheme(INTERNET_SCHEME_HTTP, FALSE);
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
LPSTR urlPath;
|
||
DWORD urlPathLength;
|
||
|
||
//
|
||
// get URL-path again if it was changed during tunnel creation
|
||
//
|
||
|
||
error = CrackUrl(GetURL(),
|
||
lstrlen(GetURL()),
|
||
FALSE, // don't escape URL-path
|
||
NULL, // don't care about scheme type
|
||
NULL, // or scheme name
|
||
NULL, // or scheme name length
|
||
NULL, // or host name
|
||
NULL, // or host name length
|
||
NULL, // or port
|
||
NULL, // or user name
|
||
NULL, // or user name length
|
||
NULL, // or password
|
||
NULL, // or password length
|
||
&urlPath,
|
||
&urlPathLength,
|
||
NULL, // don't care about extra
|
||
NULL, // or extra length
|
||
NULL
|
||
);
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
if (LockHeaders())
|
||
{
|
||
ModifyRequest(HTTP_METHOD_TYPE_GET,
|
||
urlPath,
|
||
urlPathLength,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
UnlockHeaders();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto quit;
|
||
}
|
||
|
||
//SetProxyNTLMTunnelling(FALSE);
|
||
SetRequestUsingProxy(FALSE); // don't generate proxy stuff.
|
||
break;
|
||
|
||
case FSM_STATE_3:
|
||
|
||
//
|
||
// Hack for SSL2 Client Hello bug in IIS Servers.
|
||
// Need to ReOpen connection after failure with
|
||
// a Client Hello Message.
|
||
//
|
||
|
||
if (_Socket != NULL) {
|
||
((ICSecureSocket *)_Socket)->SetProviderIndex(0);
|
||
}
|
||
|
||
attempt_ssl_connect:
|
||
|
||
//
|
||
// Attempt to do the connect
|
||
//
|
||
|
||
fsm.SetFunctionState(FSM_STATE_4);
|
||
error = OpenProxyTunnel();
|
||
if (error == ERROR_IO_PENDING) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// fall through
|
||
//
|
||
|
||
case FSM_STATE_4:
|
||
if ((error != ERROR_SUCCESS) || (GetStatusCode() != HTTP_STATUS_OK)) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// Bind Socket Object with Proper HostName,
|
||
// so we can check for valid common name
|
||
// in the handshake.
|
||
//
|
||
|
||
INET_ASSERT(_Socket->IsSecure());
|
||
|
||
/* SCLE ref */
|
||
error = ((ICSecureSocket *)_Socket)->SetHostName(GetHostName(), pInternet->GetSslSessionCache());
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// if the app wants a secure channel (PCT/SSL) then we must negotiate
|
||
// the security here
|
||
//
|
||
|
||
//
|
||
// dwProviderIndex will be managed by SecureHandshakeWithServer,
|
||
// And will be set to 0 when we can't try anymore.
|
||
//
|
||
|
||
DWORD asyncFlags;
|
||
|
||
//
|
||
// find out if we're async. N.B. see Assumes
|
||
//
|
||
|
||
asyncFlags = IsAsyncHandle() ? SF_NON_BLOCKING : 0;
|
||
|
||
//
|
||
// If we're Posting or sending data, make sure
|
||
// the SSL connection knows about it, for the
|
||
// purposes of generating errors.
|
||
//
|
||
|
||
if ((GetMethodType() == HTTP_METHOD_TYPE_POST)
|
||
|| (GetMethodType() == HTTP_METHOD_TYPE_PUT)) {
|
||
asyncFlags |= SF_SENDING_DATA;
|
||
}
|
||
|
||
fsm.SetFunctionState(FSM_STATE_5);
|
||
error = ((ICSecureSocket *)_Socket)->SecureHandshakeWithServer(
|
||
(asyncFlags | SF_ENCRYPT),
|
||
&fsm.m_bAttemptReconnect);
|
||
if (error == ERROR_IO_PENDING) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// fall through
|
||
//
|
||
|
||
case FSM_STATE_5:
|
||
if (error != ERROR_SUCCESS) {
|
||
|
||
if (error == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED)
|
||
{
|
||
if (_Socket->IsSecure())
|
||
{
|
||
if(m_pSecurityInfo)
|
||
{
|
||
/* SCLE ref */
|
||
m_pSecurityInfo->Release();
|
||
}
|
||
/* SCLE ref */
|
||
m_pSecurityInfo = ((ICSecureSocket *)_Socket)->GetSecurityEntry();
|
||
}
|
||
}
|
||
|
||
//
|
||
// we disconnected the socket and we won't attempt to reconnect. We
|
||
// need to release the connection to balance the connection limiter
|
||
//
|
||
|
||
if (!fsm.m_bAttemptReconnect)
|
||
{
|
||
ReleaseConnection(TRUE, // bClose
|
||
FALSE, // bIndicate
|
||
TRUE // bDispose
|
||
);
|
||
}
|
||
else
|
||
{
|
||
_Socket->Disconnect();
|
||
}
|
||
}
|
||
|
||
//
|
||
// SSL2 hack for old IIS servers.
|
||
// We re-open the socket, and call again.
|
||
//
|
||
|
||
if (fsm.m_bAttemptReconnect) {
|
||
goto attempt_ssl_connect;
|
||
}
|
||
break;
|
||
|
||
case FSM_STATE_6:
|
||
fsm.SetFunctionState(FSM_STATE_7);
|
||
error = OpenConnection(FALSE, FALSE);
|
||
if (error == ERROR_IO_PENDING) {
|
||
break;
|
||
}
|
||
|
||
case FSM_STATE_7:
|
||
//dprintf("HTTP connect took %d msec\n", GetTickCount() - _dwQuerySetCookieHeader);
|
||
//hack
|
||
if (error == ERROR_SUCCESS &&
|
||
_Socket &&
|
||
_Socket->IsSecure() &&
|
||
m_pSecurityInfo == NULL
|
||
)
|
||
{
|
||
/* SCLE ref */
|
||
m_pSecurityInfo = ((ICSecureSocket *)_Socket)->GetSecurityEntry();
|
||
}
|
||
break;
|
||
|
||
default:
|
||
|
||
INET_ASSERT(FALSE);
|
||
|
||
error = ERROR_WINHTTP_INTERNAL_ERROR;
|
||
break;
|
||
}
|
||
|
||
quit:
|
||
|
||
if (error != ERROR_IO_PENDING) {
|
||
fsm.SetDone();
|
||
// PERF_LEAVE(MakeConnection_Fsm);
|
||
|
||
}
|
||
PERF_LEAVE(MakeConnection_Fsm);
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|