diff --git a/AspNetCoreModule.sln b/AspNetCoreModule.sln index 54c32b50f6..ff2f980680 100644 --- a/AspNetCoreModule.sln +++ b/AspNetCoreModule.sln @@ -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 diff --git a/src/AspNetCore/AspNetCore.vcxproj b/src/AspNetCore/AspNetCore.vcxproj index 63c5065e2b..261f9f0947 100644 --- a/src/AspNetCore/AspNetCore.vcxproj +++ b/src/AspNetCore/AspNetCore.vcxproj @@ -176,9 +176,11 @@ + + diff --git a/src/AspNetCore/Inc/inprocessapplication.h b/src/AspNetCore/Inc/inprocessapplication.h index ca36067d11..c80ac757fb 100644 --- a/src/AspNetCore/Inc/inprocessapplication.h +++ b/src/AspNetCore/Inc/inprocessapplication.h @@ -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; diff --git a/src/AspNetCore/Inc/inprocessstoredcontext.h b/src/AspNetCore/Inc/inprocessstoredcontext.h new file mode 100644 index 0000000000..01a6045609 --- /dev/null +++ b/src/AspNetCore/Inc/inprocessstoredcontext.h @@ -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; +}; + diff --git a/src/AspNetCore/Src/forwardinghandler.cxx b/src/AspNetCore/Src/forwardinghandler.cxx index e49f8b1d0a..13ebc415b3 100644 --- a/src/AspNetCore/Src/forwardinghandler.cxx +++ b/src/AspNetCore/Src/forwardinghandler.cxx @@ -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(static_cast(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 diff --git a/src/AspNetCore/Src/inprocessapplication.cxx b/src/AspNetCore/Src/inprocessapplication.cxx index 56aa94c7c1..d65c2a23f7 100644 --- a/src/AspNetCore/Src/inprocessapplication.cxx +++ b/src/AspNetCore/Src/inprocessapplication.cxx @@ -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); diff --git a/src/AspNetCore/Src/inprocessstoredcontext.cxx b/src/AspNetCore/Src/inprocessstoredcontext.cxx new file mode 100644 index 0000000000..27704b6c96 --- /dev/null +++ b/src/AspNetCore/Src/inprocessstoredcontext.cxx @@ -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 + ); +} \ No newline at end of file diff --git a/src/AspNetCore/Src/precomp.hxx b/src/AspNetCore/Src/precomp.hxx index 8a8121dbec..403d949256 100644 --- a/src/AspNetCore/Src/precomp.hxx +++ b/src/AspNetCore/Src/precomp.hxx @@ -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" diff --git a/src/AspNetCore/Src/proxymodule.cxx b/src/AspNetCore/Src/proxymodule.cxx index 3ee33002d7..45f16a68e5 100644 --- a/src/AspNetCore/Src/proxymodule.cxx +++ b/src/AspNetCore/Src/proxymodule.cxx @@ -122,9 +122,9 @@ Failed: __override REQUEST_NOTIFICATION_STATUS CProxyModule::OnAsyncCompletion( - IHttpContext * pHttpContext, - DWORD dwNotification, - BOOL fPostNotification, + IHttpContext *, + DWORD, + BOOL, IHttpEventProvider *, IHttpCompletionInfo * pCompletionInfo )