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
)