Fix shutdown race (#1031)
This commit is contained in:
parent
f7936ac062
commit
86fed4de5f
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "irequesthandler.h"
|
||||
|
||||
enum APPLICATION_STATUS
|
||||
|
|
@ -54,3 +55,18 @@ public:
|
|||
_In_ IHttpContext *pHttpContext,
|
||||
_Out_ IREQUEST_HANDLER **pRequestHandler) = 0;
|
||||
};
|
||||
|
||||
struct IAPPLICATION_DELETER
|
||||
{
|
||||
void operator ()(IAPPLICATION* application) const
|
||||
{
|
||||
application->DereferenceApplication();
|
||||
}
|
||||
};
|
||||
|
||||
template< class APPLICATION >
|
||||
std::unique_ptr<APPLICATION, IAPPLICATION_DELETER> ReferenceApplication(APPLICATION* application)
|
||||
{
|
||||
application->ReferenceApplication();
|
||||
return std::unique_ptr<APPLICATION, IAPPLICATION_DELETER>(application);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -208,98 +208,11 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
|
|||
s_Application = NULL;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_APPLICATION::OnAsyncCompletion(
|
||||
DWORD cbCompletion,
|
||||
HRESULT hrCompletionStatus,
|
||||
IN_PROCESS_HANDLER* pInProcessHandler
|
||||
)
|
||||
{
|
||||
REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE;
|
||||
|
||||
ReferenceApplication();
|
||||
|
||||
if (pInProcessHandler->QueryIsManagedRequestComplete())
|
||||
{
|
||||
// means PostCompletion has been called and this is the associated callback.
|
||||
dwRequestNotificationStatus = pInProcessHandler->QueryAsyncCompletionStatus();
|
||||
}
|
||||
else if (m_fBlockCallbacksIntoManaged)
|
||||
{
|
||||
// this can potentially happen in ungraceful shutdown.
|
||||
// Or something really wrong happening with async completions
|
||||
// At this point, managed is in a shutting down state and we cannot send a request to it.
|
||||
pInProcessHandler->QueryHttpContext()->GetResponse()->SetStatus(503,
|
||||
"Server has been shutdown",
|
||||
0,
|
||||
(ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
|
||||
dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call the managed handler for async completion.
|
||||
dwRequestNotificationStatus = m_AsyncCompletionHandler(pInProcessHandler->QueryManagedHttpContext(), hrCompletionStatus, cbCompletion);
|
||||
}
|
||||
|
||||
DereferenceApplication();
|
||||
|
||||
return dwRequestNotificationStatus;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_APPLICATION::OnExecuteRequest(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ IN_PROCESS_HANDLER* pInProcessHandler
|
||||
)
|
||||
{
|
||||
REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE;
|
||||
PFN_REQUEST_HANDLER pRequestHandler = NULL;
|
||||
|
||||
ReferenceApplication();
|
||||
pRequestHandler = m_RequestHandler;
|
||||
|
||||
if (pRequestHandler == NULL)
|
||||
{
|
||||
//
|
||||
// return error as the application did not register callback
|
||||
//
|
||||
if (ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::IsEnabled(pHttpContext->GetTraceContext()))
|
||||
{
|
||||
ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::RaiseEvent(pHttpContext->GetTraceContext(),
|
||||
NULL,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
pHttpContext->GetResponse()->SetStatus(500,
|
||||
"Internal Server Error",
|
||||
0,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
|
||||
dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else if (m_status != APPLICATION_STATUS::RUNNING || m_fBlockCallbacksIntoManaged)
|
||||
{
|
||||
pHttpContext->GetResponse()->SetStatus(503,
|
||||
"Server is currently shutting down.",
|
||||
0,
|
||||
(ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
|
||||
dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwRequestNotificationStatus = pRequestHandler(pInProcessHandler, m_RequestHandlerContext);
|
||||
}
|
||||
|
||||
DereferenceApplication();
|
||||
|
||||
return dwRequestNotificationStatus;
|
||||
}
|
||||
|
||||
VOID
|
||||
IN_PROCESS_APPLICATION::SetCallbackHandles(
|
||||
_In_ PFN_REQUEST_HANDLER request_handler,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER async_completion_handler,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
)
|
||||
|
|
@ -673,7 +586,7 @@ IN_PROCESS_APPLICATION::CreateHandler(
|
|||
HRESULT hr = S_OK;
|
||||
IREQUEST_HANDLER* pHandler = NULL;
|
||||
|
||||
pHandler = new IN_PROCESS_HANDLER(pHttpContext, this);
|
||||
pHandler = new IN_PROCESS_HANDLER(::ReferenceApplication(this), pHttpContext, m_RequestHandler, m_RequestHandlerContext, m_AsyncCompletionHandler);
|
||||
|
||||
if (pHandler == NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "InProcessApplicationBase.h"
|
||||
#include "inprocesshandler.h"
|
||||
#include "requesthandler_config.h"
|
||||
#include "IOutputManager.h"
|
||||
|
||||
class IN_PROCESS_HANDLER;
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext);
|
||||
typedef BOOL(WINAPI * PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_ASYNC_COMPLETION_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
|
||||
|
||||
class IN_PROCESS_APPLICATION : public InProcessApplicationBase
|
||||
{
|
||||
|
|
@ -32,7 +32,7 @@ public:
|
|||
SetCallbackHandles(
|
||||
_In_ PFN_REQUEST_HANDLER request_callback,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_callback,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER managed_context_callback,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER managed_context_callback,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
);
|
||||
|
|
@ -60,20 +60,6 @@ public:
|
|||
HRESULT hr
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnAsyncCompletion(
|
||||
DWORD cbCompletion,
|
||||
HRESULT hrCompletionStatus,
|
||||
IN_PROCESS_HANDLER* pInProcessHandler
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnExecuteRequest
|
||||
(
|
||||
IHttpContext* pHttpContext,
|
||||
IN_PROCESS_HANDLER* pInProcessHandler
|
||||
);
|
||||
|
||||
VOID
|
||||
StopCallsIntoManaged(
|
||||
VOID
|
||||
|
|
@ -117,6 +103,12 @@ public:
|
|||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
bool
|
||||
QueryBlockCallbacksIntoManaged() const
|
||||
{
|
||||
return m_fBlockCallbacksIntoManaged;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
IHttpServer & m_pHttpServer;
|
||||
|
|
@ -132,7 +124,7 @@ private:
|
|||
PFN_SHUTDOWN_HANDLER m_ShutdownHandler;
|
||||
VOID* m_ShutdownHandlerContext;
|
||||
|
||||
PFN_MANAGED_CONTEXT_HANDLER m_AsyncCompletionHandler;
|
||||
PFN_ASYNC_COMPLETION_HANDLER m_AsyncCompletionHandler;
|
||||
|
||||
// The event that gets triggered when managed initialization is complete
|
||||
HANDLE m_pInitalizeEvent;
|
||||
|
|
|
|||
|
|
@ -10,20 +10,22 @@
|
|||
ALLOC_CACHE_HANDLER * IN_PROCESS_HANDLER::sm_pAlloc = NULL;
|
||||
|
||||
IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
|
||||
_In_ std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> pApplication,
|
||||
_In_ IHttpContext *pW3Context,
|
||||
_In_ IN_PROCESS_APPLICATION *pApplication
|
||||
): m_pW3Context(pW3Context),
|
||||
m_requestNotificationStatus(RQ_NOTIFICATION_PENDING),
|
||||
m_pApplication(pApplication),
|
||||
m_fManagedRequestComplete(FALSE)
|
||||
_In_ PFN_REQUEST_HANDLER pRequestHandler,
|
||||
_In_ void * pRequestHandlerContext,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER pAsyncCompletion
|
||||
): m_pManagedHttpContext(nullptr),
|
||||
m_requestNotificationStatus(RQ_NOTIFICATION_PENDING),
|
||||
m_fManagedRequestComplete(FALSE),
|
||||
m_pW3Context(pW3Context),
|
||||
m_pApplication(std::move(pApplication)),
|
||||
m_pRequestHandler(pRequestHandler),
|
||||
m_pRequestHandlerContext(pRequestHandlerContext),
|
||||
m_pAsyncCompletionHandler(pAsyncCompletion)
|
||||
{
|
||||
}
|
||||
|
||||
IN_PROCESS_HANDLER::~IN_PROCESS_HANDLER()
|
||||
{
|
||||
//todo
|
||||
}
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_HANDLER::OnExecuteRequestHandler()
|
||||
|
|
@ -38,8 +40,32 @@ IN_PROCESS_HANDLER::OnExecuteRequestHandler()
|
|||
L"InProcess Application");
|
||||
}
|
||||
|
||||
//SetHttpSysDisconnectCallback();
|
||||
return m_pApplication->OnExecuteRequest(m_pW3Context, this);
|
||||
if (m_pRequestHandler == NULL)
|
||||
{
|
||||
//
|
||||
// return error as the application did not register callback
|
||||
//
|
||||
if (ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::IsEnabled(m_pW3Context->GetTraceContext()))
|
||||
{
|
||||
ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::RaiseEvent(m_pW3Context->GetTraceContext(),
|
||||
NULL,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
m_pW3Context->GetResponse()->SetStatus(500,
|
||||
"Internal Server Error",
|
||||
0,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
|
||||
return RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else if (m_pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING || m_pApplication->
|
||||
QueryBlockCallbacksIntoManaged())
|
||||
{
|
||||
return ServerShutdownMessage();
|
||||
}
|
||||
|
||||
return m_pRequestHandler(this, m_pRequestHandlerContext);
|
||||
}
|
||||
|
||||
__override
|
||||
|
|
@ -49,9 +75,28 @@ IN_PROCESS_HANDLER::OnAsyncCompletion(
|
|||
HRESULT hrCompletionStatus
|
||||
)
|
||||
{
|
||||
// OnAsyncCompletion must call into the application if there was a error. We will redo calls
|
||||
// to Read/Write if we called cancelIo on the IHttpContext.
|
||||
return m_pApplication->OnAsyncCompletion(cbCompletion, hrCompletionStatus, this);
|
||||
if (m_fManagedRequestComplete)
|
||||
{
|
||||
// means PostCompletion has been called and this is the associated callback.
|
||||
return m_requestNotificationStatus;
|
||||
}
|
||||
if (m_pApplication->QueryBlockCallbacksIntoManaged())
|
||||
{
|
||||
// this can potentially happen in ungraceful shutdown.
|
||||
// Or something really wrong happening with async completions
|
||||
// At this point, managed is in a shutting down state and we cannot send a request to it.
|
||||
return ServerShutdownMessage();
|
||||
}
|
||||
|
||||
// Call the managed handler for async completion.
|
||||
return m_pAsyncCompletionHandler(m_pManagedHttpContext, hrCompletionStatus, cbCompletion);
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS IN_PROCESS_HANDLER::ServerShutdownMessage() const
|
||||
{
|
||||
m_pW3Context->GetResponse()->SetStatus(503, "Server has been shutdown", 0,
|
||||
(ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
|
||||
return RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
@ -60,31 +105,6 @@ IN_PROCESS_HANDLER::TerminateRequest(
|
|||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fClientInitiated);
|
||||
//todo
|
||||
}
|
||||
|
||||
PVOID
|
||||
IN_PROCESS_HANDLER::QueryManagedHttpContext(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_pManagedHttpContext;
|
||||
}
|
||||
|
||||
BOOL
|
||||
IN_PROCESS_HANDLER::QueryIsManagedRequestComplete(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_fManagedRequestComplete;
|
||||
}
|
||||
|
||||
IHttpContext*
|
||||
IN_PROCESS_HANDLER::QueryHttpContext(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_pW3Context;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
@ -95,14 +115,6 @@ IN_PROCESS_HANDLER::IndicateManagedRequestComplete(
|
|||
m_fManagedRequestComplete = TRUE;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_HANDLER::QueryAsyncCompletionStatus(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_requestNotificationStatus;
|
||||
}
|
||||
|
||||
VOID
|
||||
IN_PROCESS_HANDLER::SetAsyncCompletionStatus(
|
||||
REQUEST_NOTIFICATION_STATUS requestNotificationStatus
|
||||
|
|
@ -165,7 +177,7 @@ HRESULT
|
|||
}
|
||||
|
||||
hr = sm_pAlloc->Initialize(sizeof(IN_PROCESS_HANDLER),
|
||||
64); // nThreshold
|
||||
64); // nThreshold
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "requesthandler.h"
|
||||
#include <memory>
|
||||
#include "iapplication.h"
|
||||
#include "inprocessapplication.h"
|
||||
|
||||
class IN_PROCESS_APPLICATION;
|
||||
|
||||
|
|
@ -11,10 +15,13 @@ class IN_PROCESS_HANDLER : public REQUEST_HANDLER
|
|||
{
|
||||
public:
|
||||
IN_PROCESS_HANDLER(
|
||||
_In_ std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> pApplication,
|
||||
_In_ IHttpContext *pW3Context,
|
||||
_In_ IN_PROCESS_APPLICATION *pApplication);
|
||||
_In_ PFN_REQUEST_HANDLER pRequestHandler,
|
||||
_In_ void * pRequestHandlerContext,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER pAsyncCompletion);
|
||||
|
||||
~IN_PROCESS_HANDLER() override;
|
||||
~IN_PROCESS_HANDLER() override = default;
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
|
|
@ -32,37 +39,25 @@ public:
|
|||
TerminateRequest(
|
||||
bool fClientInitiated
|
||||
) override;
|
||||
|
||||
PVOID
|
||||
QueryManagedHttpContext(
|
||||
|
||||
IHttpContext*
|
||||
QueryHttpContext(
|
||||
VOID
|
||||
);
|
||||
) const
|
||||
{
|
||||
return m_pW3Context;
|
||||
}
|
||||
|
||||
VOID
|
||||
SetManagedHttpContext(
|
||||
PVOID pManagedHttpContext
|
||||
);
|
||||
|
||||
IHttpContext*
|
||||
QueryHttpContext(
|
||||
VOID
|
||||
);
|
||||
|
||||
BOOL
|
||||
QueryIsManagedRequestComplete(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
IndicateManagedRequestComplete(
|
||||
VOID
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
QueryAsyncCompletionStatus(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
SetAsyncCompletionStatus(
|
||||
REQUEST_NOTIFICATION_STATUS requestNotificationStatus
|
||||
|
|
@ -76,12 +71,18 @@ public:
|
|||
HRESULT
|
||||
StaticInitialize(VOID);
|
||||
|
||||
|
||||
private:
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
ServerShutdownMessage() const;
|
||||
|
||||
PVOID m_pManagedHttpContext;
|
||||
BOOL m_fManagedRequestComplete;
|
||||
REQUEST_NOTIFICATION_STATUS m_requestNotificationStatus;
|
||||
IHttpContext* m_pW3Context;
|
||||
IN_PROCESS_APPLICATION* m_pApplication;
|
||||
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> m_pApplication;
|
||||
PFN_REQUEST_HANDLER m_pRequestHandler;
|
||||
void* m_pRequestHandlerContext;
|
||||
PFN_ASYNC_COMPLETION_HANDLER m_pAsyncCompletionHandler;
|
||||
|
||||
static ALLOC_CACHE_HANDLER * sm_pAlloc;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ register_callbacks(
|
|||
_In_ IN_PROCESS_APPLICATION* pInProcessApplication,
|
||||
_In_ PFN_REQUEST_HANDLER request_handler,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER async_completion_handler,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue