Changes async calls to use OnAsyncComplete event pattern (#184)

This commit is contained in:
Justin Kotalik 2017-10-17 16:06:59 -07:00 committed by GitHub
parent 7117147a09
commit 68014a7acd
9 changed files with 360 additions and 19 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26815.1
VisualStudioVersion = 15.0.26815.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCore\AspNetCore.vcxproj", "{439824F9-1455-4CC4-BD79-B44FA0A16552}"
ProjectSection(ProjectDependencies) = postProject
@ -102,4 +102,7 @@ Global
{030225D8-4EE8-47E5-B692-2A96B3B51A38} = {02F461DC-5166-4E88-AAD5-CF110016A647}
{4062EA94-75F5-4691-86DC-C8594BA896DE} = {02F461DC-5166-4E88-AAD5-CF110016A647}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0967E9B4-FEE7-40D7-860A-23E340E65840}
EndGlobalSection
EndGlobal

View File

@ -176,9 +176,11 @@
<ClInclude Include="Inc\fx_ver.h" />
<ClInclude Include="Inc\inprocessapplication.h" />
<ClInclude Include="Inc\outprocessapplication.h" />
<ClInclude Include="Inc\inprocessstoredcontext.h" />
<ClInclude Include="Src\precomp.hxx" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Src\inprocessstoredcontext.cxx" />
<ClCompile Include="Src\inprocessapplication.cxx" />
<ClCompile Include="Src\outprocessapplication.cxx" />
<ClCompile Include="Src\application.cxx" />

View File

@ -6,6 +6,7 @@
typedef void(*request_handler_cb) (int error, IHttpContext* pHttpContext, void* pvCompletionContext);
typedef REQUEST_NOTIFICATION_STATUS(*PFN_REQUEST_HANDLER) (IHttpContext* pHttpContext, void* pvRequstHandlerContext);
typedef BOOL(*PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
typedef REQUEST_NOTIFICATION_STATUS(*PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
#include "application.h"
@ -39,6 +40,7 @@ public:
SetCallbackHandles(
_In_ PFN_REQUEST_HANDLER request_callback,
_In_ PFN_SHUTDOWN_HANDLER shutdown_callback,
_In_ PFN_MANAGED_CONTEXT_HANDLER managed_context_callback,
_In_ VOID* pvRequstHandlerContext,
_In_ VOID* pvShutdownHandlerContext
);
@ -54,6 +56,13 @@ public:
VOID
);
REQUEST_NOTIFICATION_STATUS
OnAsyncCompletion(
IHttpContext* pHttpContext,
DWORD cbCompletion,
HRESULT hrCompletionStatus
);
static
IN_PROCESS_APPLICATION*
GetInstance(
@ -76,6 +85,8 @@ private:
PFN_SHUTDOWN_HANDLER m_ShutdownHandler;
VOID* m_ShutdownHandlerContext;
PFN_MANAGED_CONTEXT_HANDLER m_AsyncCompletionHandler;
// The event that gets triggered when managed initialization is complete
HANDLE m_pInitalizeEvent;
@ -84,6 +95,7 @@ private:
BOOL m_fManagedAppLoaded;
BOOL m_fLoadManagedAppError;
BOOL m_fIsWebSocketsConnection;
static IN_PROCESS_APPLICATION* s_Application;

View File

@ -0,0 +1,67 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once
class IN_PROCESS_STORED_CONTEXT : public IHttpStoredContext
{
public:
IN_PROCESS_STORED_CONTEXT(
IHttpContext* pHttpContext,
PVOID pvManagedContext
);
~IN_PROCESS_STORED_CONTEXT();
virtual
VOID
CleanupStoredContext(
VOID
)
{
delete this;
}
virtual
VOID
OnClientDisconnected(
VOID
)
{
}
virtual
VOID
OnListenerEvicted(
VOID
)
{
}
PVOID
QueryManagedHttpContext(
VOID
);
IHttpContext*
QueryHttpContext(
VOID
);
static
HRESULT
GetInProcessStoredContext(
IHttpContext* pHttpContext,
IN_PROCESS_STORED_CONTEXT** ppInProcessStoredContext
);
static
HRESULT
SetInProcessStoredContext(
IHttpContext* pHttpContext,
IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext
);
private:
PVOID m_pManagedHttpContext;
IHttpContext* m_pHttpContext;
};

View File

@ -1143,11 +1143,6 @@ FORWARDING_HANDLER::OnExecuteRequestHandler(
{
case HOSTING_IN_PROCESS:
{
// Allow reading and writing to simultaneously
((IHttpContext3*)m_pW3Context)->EnableFullDuplex();
// Disable response buffering by default, we'll do a write behind buffering in managed code
((IHttpResponse2*)m_pW3Context->GetResponse())->DisableBuffering();
hr = ((IN_PROCESS_APPLICATION*)m_pApplication)->LoadManagedApplication();
if (FAILED(hr))
@ -1570,7 +1565,28 @@ REQUEST_NOTIFICATION_STATUS
reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(hrCompletionStatus)));
}
if (m_pApplication->QueryConfig()->QueryHostingModel() == HOSTING_OUT_PROCESS)
if (m_pApplication->QueryConfig()->QueryHostingModel() == HOSTING_IN_PROCESS)
{
if (FAILED(hrCompletionStatus))
{
return RQ_NOTIFICATION_FINISH_REQUEST;
}
else
{
// For now we are assuming we are in our own self contained box.
// TODO refactor Finished and Failure sections to handle in process and out of process failure.
// TODO verify that websocket's OnAsyncCompletion is not calling this.
IN_PROCESS_APPLICATION* application = (IN_PROCESS_APPLICATION*)m_pApplication;
if (application == NULL)
{
hr = E_FAIL;
return RQ_NOTIFICATION_FINISH_REQUEST;
}
return application->OnAsyncCompletion(m_pW3Context, cbCompletion, hrCompletionStatus);
}
}
else if (m_pApplication->QueryConfig()->QueryHostingModel() == HOSTING_OUT_PROCESS)
{
//
// Take a reference so that object does not go away as a result of

View File

@ -14,6 +14,7 @@ VOID
register_callbacks(
_In_ PFN_REQUEST_HANDLER request_handler,
_In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
_In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
_In_ VOID* pvRequstHandlerContext,
_In_ VOID* pvShutdownHandlerContext
)
@ -21,6 +22,7 @@ register_callbacks(
IN_PROCESS_APPLICATION::GetInstance()->SetCallbackHandles(
request_handler,
shutdown_handler,
async_completion_handler,
pvRequstHandlerContext,
pvShutdownHandlerContext
);
@ -56,10 +58,34 @@ EXTERN_C __MIDL_DECLSPEC_DLLEXPORT VOID http_set_response_status_code(
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_post_completion(
_In_ IHttpContext* pHttpContext
_In_ IHttpContext* pHttpContext,
DWORD cbBytes
)
{
return pHttpContext->PostCompletion(0);
return pHttpContext->PostCompletion(cbBytes);
}
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_set_managed_context(
_In_ IHttpContext* pHttpContext,
_In_ PVOID pvManagedContext
)
{
HRESULT hr;
IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext = new IN_PROCESS_STORED_CONTEXT(pHttpContext, pvManagedContext);
if (pInProcessStoredContext == NULL)
{
return E_OUTOFMEMORY;
}
hr = IN_PROCESS_STORED_CONTEXT::SetInProcessStoredContext(pHttpContext, pInProcessStoredContext);
if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED))
{
hr = S_OK;
}
return hr;
}
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
@ -104,6 +130,92 @@ http_get_application_full_path()
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_read_request_bytes(
_In_ IHttpContext* pHttpContext,
_Out_ CHAR* pvBuffer,
_In_ DWORD dwCbBuffer,
_Out_ DWORD* pdwBytesReceived,
_Out_ BOOL* pfCompletionPending
)
{
HRESULT hr;
if (pHttpContext == NULL)
{
return E_FAIL;
}
if (dwCbBuffer == 0)
{
return E_FAIL;
}
IHttpRequest *pHttpRequest = (IHttpRequest*)pHttpContext->GetRequest();
BOOL fAsync = TRUE;
hr = pHttpRequest->ReadEntityBody(
pvBuffer,
dwCbBuffer,
fAsync,
pdwBytesReceived,
pfCompletionPending);
if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
{
// We reached the end of the data
hr = S_OK;
}
return hr;
}
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_write_response_bytes(
_In_ IHttpContext* pHttpContext,
_In_ HTTP_DATA_CHUNK* pDataChunks,
_In_ DWORD dwChunks,
_In_ BOOL* pfCompletionExpected
)
{
IHttpResponse *pHttpResponse = (IHttpResponse*)pHttpContext->GetResponse();
BOOL fAsync = TRUE;
BOOL fMoreData = TRUE;
DWORD dwBytesSent = 0;
HRESULT hr = pHttpResponse->WriteEntityChunks(
pDataChunks,
dwChunks,
fAsync,
fMoreData,
&dwBytesSent,
pfCompletionExpected);
return hr;
}
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_flush_response_bytes(
_In_ IHttpContext* pHttpContext,
_Out_ BOOL* pfCompletionExpected
)
{
IHttpResponse *pHttpResponse = (IHttpResponse*)pHttpContext->GetResponse();
BOOL fAsync = TRUE;
BOOL fMoreData = TRUE;
DWORD dwBytesSent = 0;
HRESULT hr = pHttpResponse->Flush(
fAsync,
fMoreData,
&dwBytesSent,
pfCompletionExpected);
return hr;
}
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_websockets_read_bytes(
_In_ IHttpContext* pHttpContext,
_In_ CHAR* pvBuffer,
_In_ DWORD cbBuffer,
@ -137,10 +249,10 @@ http_read_request_bytes(
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_write_response_bytes(
http_websockets_write_bytes(
_In_ IHttpContext* pHttpContext,
_In_ HTTP_DATA_CHUNK* pDataChunks,
_In_ DWORD nChunks,
_In_ DWORD dwChunks,
_In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
_In_ VOID* pvCompletionContext,
_In_ BOOL* pfCompletionExpected
@ -154,7 +266,7 @@ http_write_response_bytes(
HRESULT hr = pHttpResponse->WriteEntityChunks(
pDataChunks,
nChunks,
dwChunks,
fAsync,
fMoreData,
pfnCompletionCallback,
@ -167,7 +279,7 @@ http_write_response_bytes(
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_flush_response_bytes(
http_websockets_flush_bytes(
_In_ IHttpContext* pHttpContext,
_In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
_In_ VOID* pvCompletionContext,
@ -189,24 +301,71 @@ http_flush_response_bytes(
pfCompletionExpected);
return hr;
}
// End of export
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_enable_websockets(
_In_ IHttpContext* pHttpContext
)
{
if (!g_fWebSocketSupported)
{
return E_FAIL;
}
((IHttpContext3*)pHttpContext)->EnableFullDuplex();
((IHttpResponse2*)pHttpContext->GetResponse())->DisableBuffering();
return S_OK;
}
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT
http_cancel_io(
_In_ IHttpContext* pHttpContext
)
{
return pHttpContext->CancelIo();
}
// End of export
IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION():
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION() :
m_ProcessExitCode ( 0 ),
m_fManagedAppLoaded ( FALSE ),
m_fLoadManagedAppError ( FALSE )
{
}
IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION()
{
Recycle();
}
REQUEST_NOTIFICATION_STATUS
IN_PROCESS_APPLICATION::OnAsyncCompletion(
IHttpContext* pHttpContext,
DWORD cbCompletion,
HRESULT hrCompletionStatus
)
{
HRESULT hr;
IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext = NULL;
hr = IN_PROCESS_STORED_CONTEXT::GetInProcessStoredContext(pHttpContext, &pInProcessStoredContext);
if (FAILED(hr))
{
// Finish the request as we couldn't get the callback
pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 19, hr);
return RQ_NOTIFICATION_FINISH_REQUEST;
}
// Call the managed handler for async completion.
return m_AsyncCompletionHandler(pInProcessStoredContext->QueryManagedHttpContext(), hrCompletionStatus, cbCompletion);
}
BOOL
IN_PROCESS_APPLICATION::DirectoryExists(
_In_ STRU *pstrPath
@ -289,6 +448,7 @@ 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_ VOID* pvRequstHandlerContext,
_In_ VOID* pvShutdownHandlerContext
)
@ -297,6 +457,7 @@ IN_PROCESS_APPLICATION::SetCallbackHandles(
m_RequstHandlerContext = pvRequstHandlerContext;
m_ShutdownHandler = shutdown_handler;
m_ShutdownHandlerContext = pvShutdownHandlerContext;
m_AsyncCompletionHandler = async_completion_handler;
// Initialization complete
SetEvent(m_pInitalizeEvent);

View File

@ -0,0 +1,79 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#include "precomp.hxx"
IN_PROCESS_STORED_CONTEXT::IN_PROCESS_STORED_CONTEXT(
IHttpContext* pHttpContext,
PVOID pMangedHttpContext
)
{
m_pManagedHttpContext = pMangedHttpContext;
m_pHttpContext = pHttpContext;
}
IN_PROCESS_STORED_CONTEXT::~IN_PROCESS_STORED_CONTEXT()
{
}
PVOID
IN_PROCESS_STORED_CONTEXT::QueryManagedHttpContext(
VOID
)
{
return m_pManagedHttpContext;
}
IHttpContext*
IN_PROCESS_STORED_CONTEXT::QueryHttpContext(
VOID
)
{
return m_pHttpContext;
}
HRESULT
IN_PROCESS_STORED_CONTEXT::GetInProcessStoredContext(
IHttpContext* pHttpContext,
IN_PROCESS_STORED_CONTEXT** ppInProcessStoredContext
)
{
if (pHttpContext == NULL)
{
return E_FAIL;
}
if (ppInProcessStoredContext == NULL)
{
return E_FAIL;
}
*ppInProcessStoredContext = (IN_PROCESS_STORED_CONTEXT*)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleId);
if (*ppInProcessStoredContext == NULL)
{
return E_FAIL;
}
return S_OK;
}
HRESULT
IN_PROCESS_STORED_CONTEXT::SetInProcessStoredContext(
IHttpContext* pHttpContext,
IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext
)
{
if (pHttpContext == NULL)
{
return E_FAIL;
}
if (pInProcessStoredContext == NULL)
{
return E_FAIL;
}
return pHttpContext->GetModuleContextContainer()->SetModuleContext(
pInProcessStoredContext,
g_pModuleId
);
}

View File

@ -120,6 +120,7 @@ inline bool IsSpace(char ch)
#include "filewatcher.h"
#include "application.h"
#include "applicationmanager.h"
#include "inprocessstoredcontext.h"
#include "inprocessapplication.h"
#include "outprocessapplication.h"
#include "resource.h"

View File

@ -122,9 +122,9 @@ Failed:
__override
REQUEST_NOTIFICATION_STATUS
CProxyModule::OnAsyncCompletion(
IHttpContext * pHttpContext,
DWORD dwNotification,
BOOL fPostNotification,
IHttpContext *,
DWORD,
BOOL,
IHttpEventProvider *,
IHttpCompletionInfo * pCompletionInfo
)