Example #1
0
REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler(
    IN IHttpContext* pHttpContext, 
    IN IHttpEventProvider* pProvider)
{
    HRESULT hr;
    CNodeHttpStoredContext* ctx = NULL;

    CheckError(this->applicationManager->Initialize(pHttpContext));

    this->applicationManager->GetEventProvider()->Log(L"iisnode received a new http request", WINEVENT_LEVEL_INFO);

    CheckError(this->applicationManager->Dispatch(pHttpContext, pProvider, &ctx));
    this->applicationManager->GetEventProvider()->Log(L"iisnode dispatched new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
    ASYNC_CONTEXT* async = ctx->GetAsyncContext();
    async->RunSynchronousContinuations();

    REQUEST_NOTIFICATION_STATUS result;
    if (0 == ctx->DecreasePendingAsyncOperationCount()) // decreases ref count set to 1 in the ctor of CNodeHttpStoredContext
    {
        result = ctx->GetRequestNotificationStatus();
    }
    else
    {
        result = RQ_NOTIFICATION_PENDING;
    }

    switch (result) 
    {
    default:
        this->applicationManager->GetEventProvider()->Log(
            L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler", 
            WINEVENT_LEVEL_VERBOSE, 
            ctx->GetActivityId());
        break;
    case RQ_NOTIFICATION_CONTINUE:
        this->applicationManager->GetEventProvider()->Log(
            L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_CONTINUE", 
            WINEVENT_LEVEL_VERBOSE, 
            ctx->GetActivityId());
        break;
    case RQ_NOTIFICATION_FINISH_REQUEST:
        this->applicationManager->GetEventProvider()->Log(
            L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_FINISH_REQUEST", 
            WINEVENT_LEVEL_VERBOSE, 
            ctx->GetActivityId());
        break;
    case RQ_NOTIFICATION_PENDING:
        this->applicationManager->GetEventProvider()->Log(
            L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_PENDING", 
            WINEVENT_LEVEL_VERBOSE, 
            ctx->GetActivityId());
        break;
    };

    return result;

Error:

    CNodeEventProvider* log = this->applicationManager->GetEventProvider();

    if (log)
    {
        if (ctx)
        {
            log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
        }
        else
        {
            log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO);
        }
    }

    if (ERROR_NOT_ENOUGH_QUOTA == hr)
    {
        CProtocolBridge::SendEmptyResponse(pHttpContext, 503, CNodeConstants::IISNODE_ERROR_NOT_ENOUGH_QUOTA, _T("Service Unavailable"), hr);
    }
    else if (ERROR_FILE_NOT_FOUND == hr)
    {
        CProtocolBridge::SendEmptyResponse(pHttpContext, 404, 0, _T("Not Found"), hr);
    }
    else if (ERROR_NOT_SUPPORTED == hr)
    {
        if (log)
        {
            log->Log(L"iisnode rejected websocket connection request", WINEVENT_LEVEL_INFO);
        }
        CProtocolBridge::SendEmptyResponse(pHttpContext, 501, 0, _T("Not Implemented"), hr);
    }
    else if (!CProtocolBridge::SendIisnodeError(pHttpContext, hr))
    {
        CProtocolBridge::SendEmptyResponse( pHttpContext, 
                                            500, 
                                            CNodeConstants::IISNODE_ERROR_ON_EXECUTE_REQ_HANDLER, 
                                            _T("Internal Server Error"), 
                                            hr );
    }

    return RQ_NOTIFICATION_FINISH_REQUEST;
}
REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler(
	IN IHttpContext* pHttpContext, 
	IN IHttpEventProvider* pProvider)
{
	HRESULT hr;
	CNodeHttpStoredContext* ctx = NULL;

	CheckError(this->applicationManager->Initialize(pHttpContext));

	this->applicationManager->GetEventProvider()->Log(L"iisnode received a new http request", WINEVENT_LEVEL_INFO);

	// reject websocket connections since iisnode does not support them
	// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#page-17

	PCSTR upgrade = pHttpContext->GetRequest()->GetHeader(HttpHeaderUpgrade, NULL);
	ErrorIf(upgrade && 0 == strcmp("websocket", upgrade), ERROR_NOT_SUPPORTED);		

	CheckError(this->applicationManager->Dispatch(pHttpContext, pProvider, &ctx));

	if (0 == ctx->DecreasePendingAsyncOperationCount()) // decreases ref count set to 1 in the ctor of CNodeHttpStoredContext
	{
		return ctx->GetRequestNotificationStatus();
	}
	else
	{
		return RQ_NOTIFICATION_PENDING;
	}

Error:

	CNodeEventProvider* log = this->applicationManager->GetEventProvider();

	if (log)
	{
		log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO);
	}

	if (ERROR_NOT_ENOUGH_QUOTA == hr)
	{
		CProtocolBridge::SendEmptyResponse(pHttpContext, 503, _T("Service Unavailable"), hr);
	}
	else if (ERROR_FILE_NOT_FOUND == hr)
	{
		CProtocolBridge::SendEmptyResponse(pHttpContext, 404, _T("Not Found"), hr);
	}
	else if (ERROR_NOT_SUPPORTED == hr)
	{
		if (log)
		{
			log->Log(L"iisnode rejected websocket connection request", WINEVENT_LEVEL_INFO);
		}
		CProtocolBridge::SendEmptyResponse(pHttpContext, 501, _T("Not Implemented"), hr);
	}
	else if (IISNODE_ERROR_UNRECOGNIZED_DEBUG_COMMAND == hr)
	{
		CProtocolBridge::SendSyncResponse(
			pHttpContext, 
			200, 
			"OK", 
			hr, 
			TRUE, 
			"Unrecognized debugging command. Supported commands are ?debug (default), ?brk, and ?kill.");
	}
	else if (IISNODE_ERROR_UNABLE_TO_FIND_DEBUGGING_PORT == hr)
	{
		CProtocolBridge::SendSyncResponse(
			pHttpContext, 
			200, 
			"OK", 
			hr, 
			TRUE, 
			"The debugger was unable to acquire a TCP port to establish communication with the debugee. "
			"This may be due to lack of free TCP ports in the range specified in the system.webServer/iisnode/@debuggerPortRange configuration "
			"section, or due to lack of permissions to create TCP listeners by the identity of the IIS worker process.");
	}
	else if (IISNODE_ERROR_UNABLE_TO_CONNECT_TO_DEBUGEE == hr)
	{
		CProtocolBridge::SendSyncResponse(
			pHttpContext, 
			200, 
			"OK", 
			hr, 
			TRUE, 
			"The debugger was unable to connect to the the debugee. "
			"This may be due to the debugee process terminating during startup (e.g. due to an unhandled exception) or "
			"failing to establish a TCP listener on the debugging port. ");
	}
	else
	{
		CProtocolBridge::SendEmptyResponse(pHttpContext, 500, _T("Internal Server Error"), hr);
	}

	return RQ_NOTIFICATION_FINISH_REQUEST;
}