Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ private RequestDelegate BuildErrorPageApplication(Exception exception)
{
context.Response.StatusCode = 500;
context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
context.Response.ContentType = "text/html; charset=utf-8";
return errorPage.ExecuteAsync(context);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<ItemGroup>
<Compile Include="$(SharedSourceRoot)RazorViews\*.cs" />
<Compile Include="$(SharedSourceRoot)StackTrace\**\*.cs" />
<Compile Include="$(SharedSourceRoot)ErrorPage\**\*.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
9 changes: 0 additions & 9 deletions src/Hosting/Hosting/src/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorPageHtml_Title" xml:space="preserve">
<value>Internal Server Error</value>
</data>
<data name="ErrorPageHtml_UnhandledException" xml:space="preserve">
<value>An error occurred while starting the application.</value>
</data>
<data name="ErrorPageHtml_UnknownLocation" xml:space="preserve">
<value>Unknown location</value>
</data>
<data name="WebHostBuilder_SingleInstance" xml:space="preserve">
<value>WebHostBuilder allows creation only of a single instance of WebHost</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY L"setCurrentDirectory"
#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE L"disableStartUpErrorPage"
#define CS_ENABLED L"enabled"
#define CS_ASPNETCORE_HANDLER_CALL_STARTUP_HOOK L"callStartupHook"

class ConfigurationSection: NonCopyable
{
Expand Down
49 changes: 31 additions & 18 deletions src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,34 @@
class ServerErrorHandler : public REQUEST_HANDLER
{
public:
ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, HINSTANCE module, bool disableStartupPage, int page) noexcept
: ServerErrorHandler(pContext, statusCode, subStatusCode, statusText, hr, module, disableStartupPage, page, std::vector<byte>())
{
}

ServerErrorHandler(IHttpContext &pContext, USHORT statusCode, USHORT subStatusCode, std::string statusText, HRESULT hr, HINSTANCE moduleInstance, bool disableStartupPage, int page) noexcept
ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, HINSTANCE module, bool disableStartupPage, int page, const std::vector<byte>& content) noexcept
: REQUEST_HANDLER(pContext),
m_pContext(pContext),
m_HR(hr),
m_disableStartupPage(disableStartupPage),
m_page(page),
m_moduleInstance(moduleInstance),
m_statusCode(statusCode),
m_subStatusCode(subStatusCode),
m_statusText(std::move(statusText))
m_pContext(pContext),
m_HR(hr),
m_disableStartupPage(disableStartupPage),
m_statusCode(statusCode),
m_subStatusCode(subStatusCode),
m_statusText(std::move(statusText)),
m_page(page),
m_ExceptionInfoContent(content),
m_moduleInstance(module)
{
}

REQUEST_NOTIFICATION_STATUS ExecuteRequestHandler() override
{
static std::string s_html500Page = GetHtml(m_moduleInstance, m_page);

WriteStaticResponse(m_pContext, s_html500Page, m_HR, m_disableStartupPage);
WriteStaticResponse(m_pContext, m_HR, m_disableStartupPage);

return RQ_NOTIFICATION_FINISH_REQUEST;
}

private:
void WriteStaticResponse(IHttpContext& pContext, std::string &page, HRESULT hr, bool disableStartupErrorPage) const
void WriteStaticResponse(IHttpContext& pContext, HRESULT hr, bool disableStartupErrorPage)
{
if (disableStartupErrorPage)
{
Expand All @@ -49,14 +52,23 @@ class ServerErrorHandler : public REQUEST_HANDLER
(USHORT)strlen("text/html"),
FALSE
);
dataChunk.DataChunkType = HttpDataChunkFromMemory;

dataChunk.FromMemory.pBuffer = page.data();
dataChunk.FromMemory.BufferLength = static_cast<ULONG>(page.size());
dataChunk.DataChunkType = HttpDataChunkFromMemory;
if (m_ExceptionInfoContent.size() > 0)
{
dataChunk.FromMemory.pBuffer = &m_ExceptionInfoContent[0];
dataChunk.FromMemory.BufferLength = static_cast<ULONG>(m_ExceptionInfoContent.size());
}
else
{
static std::string s_html500Page = GetHtml(m_moduleInstance, m_page);
dataChunk.FromMemory.pBuffer = s_html500Page.data();
dataChunk.FromMemory.BufferLength = static_cast<ULONG>(s_html500Page.size());
}

pResponse->WriteEntityChunkByReference(&dataChunk);
}

static
std::string
GetHtml(HMODULE module, int page)
{
Expand Down Expand Up @@ -91,12 +103,13 @@ class ServerErrorHandler : public REQUEST_HANDLER
}
}

IHttpContext &m_pContext;
IHttpContext& m_pContext;
HRESULT m_HR;
bool m_disableStartupPage;
int m_page;
HINSTANCE m_moduleInstance;
USHORT m_statusCode;
USHORT m_subStatusCode;
std::string m_statusText;
std::vector<byte> m_ExceptionInfoContent;
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ using ::testing::NiceMock;
// Externals defined in inprocess
BOOL g_fProcessDetach;
HANDLE g_hEventLog;
std::wstring g_exceptionEventLog;

namespace InprocessTests
{
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc

const auto handlerSettings = aspNetCoreSection->GetKeyValuePairs(CS_ASPNETCORE_HANDLER_SETTINGS);
m_fSetCurrentDirectory = equals_ignore_case(find_element(handlerSettings, CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY).value_or(L"true"), L"true");
m_fCallStartupHook = equals_ignore_case(find_element(handlerSettings, CS_ASPNETCORE_HANDLER_CALL_STARTUP_HOOK).value_or(L"true"), L"true");

m_dwStartupTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT) * 1000;
m_dwShutdownTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT) * 1000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ class InProcessOptions: NonCopyable
return m_fSetCurrentDirectory;
}

bool
QueryCallStartupHook() const
{
return m_fCallStartupHook;
}

bool
QueryWindowsAuthEnabled() const
{
Expand Down Expand Up @@ -116,6 +122,7 @@ class InProcessOptions: NonCopyable
bool m_fStdoutLogEnabled;
bool m_fDisableStartUpErrorPage;
bool m_fSetCurrentDirectory;
bool m_fCallStartupHook;
bool m_fWindowsAuthEnabled;
bool m_fBasicAuthEnabled;
bool m_fAnonymousAuthEnabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,28 @@ class StartupExceptionApplication : public InProcessApplicationBase
IHttpApplication& pApplication,
HINSTANCE moduleInstance,
BOOL disableLogs,
HRESULT hr)
HRESULT hr,
std::vector<byte>&& errorPageContent
)
: m_disableLogs(disableLogs),
m_HR(hr),
m_moduleInstance(moduleInstance),
m_errorPageContent(std::move(errorPageContent)),
InProcessApplicationBase(pServer, pApplication)
{
}

~StartupExceptionApplication() = default;

HRESULT CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler)
HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler)
{
*pRequestHandler = new ServerErrorHandler(*pHttpContext, 500, 30, "Internal Server Error", m_HR, m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML);
return S_OK;
}
*pRequestHandler = new ServerErrorHandler(*pHttpContext, 500, 30, "Internal Server Error", m_HR, m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML, m_errorPageContent);

std::string&
GetStaticHtml500Content()
{
return html500Page;
return S_OK;
}

private:
std::string html500Page;
std::vector<byte> m_errorPageContent;
BOOL m_disableLogs;
HRESULT m_HR;
HINSTANCE m_moduleInstance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ HINSTANCE g_hWinHttpModule;
HINSTANCE g_hAspNetCoreModule;
HANDLE g_hEventLog = NULL;
bool g_fInProcessApplicationCreated = false;
std::vector<byte> g_errorPageContent;
HINSTANCE g_hServerModule;

HRESULT
Expand Down Expand Up @@ -128,7 +129,7 @@ CreateApplication(
std::unique_ptr<InProcessOptions> options;
THROW_IF_FAILED(InProcessOptions::Create(*pServer, pSite, *pHttpApplication, options));
// Set the currently running application to a fake application that returns startup exceptions.
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr);
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr, std::move(g_errorPageContent));

RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline());
*ppApplication = pErrorApplication.release();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,26 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
LOG_INFOF(L"Setting current directory to %s", this->QueryApplicationPhysicalPath().c_str());
}

bool clrThreadExited;
if (m_pConfig->QueryCallStartupHook())
{
// Used to display developer exception page when there is an exception in main.
auto currentStartupHookEnv = Environment::GetEnvironmentVariableValue(DOTNETCORE_STARTUP_HOOK);

if (currentStartupHookEnv.has_value())
{
currentStartupHookEnv = currentStartupHookEnv.value() + L";" + ASPNETCORE_STARTUP_ASSEMBLY;
LOG_LAST_ERROR_IF(!SetEnvironmentVariable(DOTNETCORE_STARTUP_HOOK, currentStartupHookEnv.value().c_str()));
}
else
{
LOG_LAST_ERROR_IF(!SetEnvironmentVariable(DOTNETCORE_STARTUP_HOOK, ASPNETCORE_STARTUP_ASSEMBLY));
}
}

// Used to make .NET Runtime always log to event log when there is an unhandled exception.
LOG_LAST_ERROR_IF(SetEnvironmentVariable(L"COMPlus_UseEntryPointFilter", L"1"));

bool clrThreadExited;
{
auto redirectionOutput = LoggingHelpers::CreateOutputs(
m_pConfig->QueryStdoutLogEnabled(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ typedef BOOL(WINAPI * PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_ASYNC_COMPLETION_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
typedef void(WINAPI * PFN_REQUESTS_DRAINED_HANDLER) (void* pvShutdownHandlerContext);

#define DOTNETCORE_STARTUP_HOOK L"DOTNET_STARTUP_HOOKS"
#define ASPNETCORE_STARTUP_ASSEMBLY L"Microsoft.AspNetCore.Server.IIS"
class IN_PROCESS_APPLICATION : public InProcessApplicationBase
{
public:
Expand Down Expand Up @@ -58,7 +60,6 @@ class IN_PROCESS_APPLICATION : public InProcessApplicationBase
HRESULT
LoadManagedApplication();


void
QueueStop();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#include "inprocessapplication.h"
#include "inprocesshandler.h"
#include "requesthandler_config.h"
#include "EventLog.h"

extern bool g_fInProcessApplicationCreated;
extern std::vector<byte> g_errorPageContent;
extern IHttpServer* g_pHttpServer;

//
// Initialization export
Expand Down Expand Up @@ -236,7 +239,7 @@ http_read_request_bytes(
{
return E_FAIL;
}
IHttpRequest *pHttpRequest = (IHttpRequest*)pInProcessHandler->QueryHttpContext()->GetRequest();
IHttpRequest* pHttpRequest = (IHttpRequest*)pInProcessHandler->QueryHttpContext()->GetRequest();

// Check if there is anything to read
if (pHttpRequest->GetRemainingEntityBytes() > 0)
Expand Down Expand Up @@ -267,7 +270,7 @@ http_write_response_bytes(
_In_ BOOL* pfCompletionExpected
)
{
IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
IHttpResponse* pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
BOOL fAsync = TRUE;
BOOL fMoreData = TRUE;
DWORD dwBytesSent = 0;
Expand All @@ -291,7 +294,7 @@ http_flush_response_bytes(
_Out_ BOOL* pfCompletionExpected
)
{
IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
IHttpResponse* pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();

BOOL fAsync = TRUE;
DWORD dwBytesSent = 0;
Expand All @@ -316,7 +319,7 @@ http_websockets_read_bytes(
_In_ BOOL* pfCompletionPending
)
{
IHttpRequest3 *pHttpRequest = (IHttpRequest3*)pInProcessHandler->QueryHttpContext()->GetRequest();
IHttpRequest3* pHttpRequest = (IHttpRequest3*)pInProcessHandler->QueryHttpContext()->GetRequest();

BOOL fAsync = TRUE;

Expand All @@ -343,7 +346,7 @@ http_websockets_write_bytes(
_In_ BOOL* pfCompletionExpected
)
{
IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse();
IHttpResponse2* pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse();

BOOL fAsync = TRUE;
BOOL fMoreData = TRUE;
Expand Down Expand Up @@ -371,7 +374,7 @@ http_websockets_flush_bytes(
_In_ BOOL* pfCompletionExpected
)
{
IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse();
IHttpResponse2* pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse();

BOOL fAsync = TRUE;
BOOL fMoreData = TRUE;
Expand Down Expand Up @@ -504,4 +507,12 @@ set_main_handler(_In_ hostfxr_main_fn main)
IN_PROCESS_APPLICATION::SetMainCallback(main);
}

EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
VOID
http_set_startup_error_page_content(_In_ byte* errorPageContent, int length)
{
g_errorPageContent.resize(length);
memcpy(&g_errorPageContent[0], errorPageContent, length);
}

// End of export
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<Reference Include="Microsoft.AspNetCore.Authentication.Core" />
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
<Reference Include="Microsoft.Extensions.TypeNameHelper.Sources" />
<Reference Include="System.IO.Pipelines" />
<Reference Include="System.Security.Principal.Windows" />
</ItemGroup>
Expand Down
11 changes: 8 additions & 3 deletions src/Servers/IIS/IIS/src/Microsoft.AspNetCore.Server.IIS.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
Expand All @@ -14,8 +14,11 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\**\*.cs" />
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" />
<Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\**\*.cs" LinkBase="Shared\" />
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" LinkBase="Shared\"/>
<Compile Include="$(SharedSourceRoot)StackTrace\**\*.cs" LinkBase="Shared\" />
<Compile Include="$(SharedSourceRoot)RazorViews\*.cs" LinkBase="Shared\" />
<Compile Include="$(SharedSourceRoot)ErrorPage\*.cs" LinkBase="Shared\" />
</ItemGroup>

<Target Name="ValidateNativeComponentsBuilt" AfterTargets="Build" >
Expand All @@ -32,6 +35,8 @@
<Reference Include="Microsoft.AspNetCore.Authentication.Core" />
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
<Reference Include="Microsoft.Extensions.TypeNameHelper.Sources" />
<Reference Include="System.IO.Pipelines" />
<Reference Include="System.Security.Principal.Windows" />
</ItemGroup>
Expand Down
Loading