Пример #1
0
apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
{
	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);

	if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer == NULL)
		return APR_SUCCESS;

	IHttpContext *pHttpContext = rsc->m_pHttpContext;
	IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
	HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->m_pRequestRec->pool, sizeof(HTTP_DATA_CHUNK));

	pRawHttpResponse->EntityChunkCount = 0;

	// since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
	//
	void *reqbuf = pHttpContext->AllocateRequestMemory(length);

	memcpy(reqbuf, buf, length);

	pDataChunk->DataChunkType = HttpDataChunkFromMemory;
	pDataChunk->FromMemory.pBuffer = reqbuf;
	pDataChunk->FromMemory.BufferLength = length;

    CHAR szLength[21]; //Max length for a 64 bit int is 20

    ZeroMemory(szLength, sizeof(szLength));

    HRESULT hr = StringCchPrintfA(
            szLength, 
            sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
            length);

    if(FAILED(hr))
    {
		// not possible
    }

    hr = pHttpResponse->SetHeader(
            HttpHeaderContentLength, 
            szLength, 
            (USHORT)strlen(szLength),
            TRUE);

    if(FAILED(hr))
    {
		// possible, but there's nothing we can do
    }

	pHttpResponse->WriteEntityChunkByReference(pDataChunk);

	return APR_SUCCESS;
}
Пример #2
0
apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
{
	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);

	if(rsc == NULL || rsc->m_pRequestRec == NULL)
		return APR_SUCCESS;

	IHttpContext *pHttpContext = rsc->m_pHttpContext;
	IHttpRequest *pHttpRequest = pHttpContext->GetRequest();

    CHAR szLength[21]; //Max length for a 64 bit int is 20

    ZeroMemory(szLength, sizeof(szLength));

    HRESULT hr = StringCchPrintfA(
            szLength, 
            sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
            length);

    if(FAILED(hr))
    {
		// not possible
    }

    hr = pHttpRequest->SetHeader(
            HttpHeaderContentLength, 
            szLength, 
            (USHORT)strlen(szLength),
            TRUE);

    if(FAILED(hr))
    {
		// possible, but there's nothing we can do
    }

	// since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
	//
	void *reqbuf = pHttpContext->AllocateRequestMemory(length);

	memcpy(reqbuf, buf, length);

	pHttpRequest->InsertEntityBody(reqbuf, length);

	return APR_SUCCESS;
}
Пример #3
0
apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
{
	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);

	*readcnt = 0;

	if(rsc == NULL)
	{
		*is_eos = 1;
		return APR_SUCCESS;
	}

	IHttpContext *pHttpContext = rsc->m_pHttpContext;
	IHttpRequest *pRequest = pHttpContext->GetRequest();

	if(pRequest->GetRemainingEntityBytes() == 0)
	{
		*is_eos = 1;
		return APR_SUCCESS;
	}

	HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);

	if (FAILED(hr))
    {
        // End of data is okay.
        if (ERROR_HANDLE_EOF != (hr  & 0x0000FFFF))
        {
            // Set the error status.
            rsc->m_pProvider->SetErrorStatus( hr );
        }

		*is_eos = 1;
    }

	return APR_SUCCESS;
}
Пример #4
0
HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void** result, DWORD* resultSize, DWORD* resultLength)
{
	HRESULT hr;
	PCSTR originalUrl = NULL;
	USHORT originalUrlLength;
	DWORD remoteHostSize = INET6_ADDRSTRLEN + 1;
	char remoteHost[INET6_ADDRSTRLEN + 1];
	BOOL addXFF;
	char** serverVars;
	int serverVarCount;

	CheckNull(ctx);
	CheckNull(result);
	CheckNull(resultSize);
	CheckNull(resultLength);

	IHttpContext* context = ctx->GetHttpContext();

	DWORD bufferLength = CModuleConfiguration::GetInitialRequestBufferSize(context);
	DWORD offset = 0;
	IHttpRequest* request = context->GetRequest();
	HTTP_REQUEST* raw = request->GetRawHttpRequest();
	USHORT major, minor;
	const int tmpSize = 256;
	char tmp[tmpSize];
	PCSTR method = request->GetHttpMethod();
	
	ErrorIf(NULL == (*result = context->AllocateRequestMemory(bufferLength)), ERROR_NOT_ENOUGH_MEMORY);	

	// Determine whether response entity body is to be expected

	if (method && 0 == strcmpi("HEAD", method))
	{
		// HEAD requests do not have response entity body
		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4

		ctx->SetExpectResponseBody(FALSE);
	}
	
	// Request-Line

	CheckError(CHttpProtocol::Append(context, method, 0, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, " ", 1, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, ctx->GetTargetUrl(), ctx->GetTargetUrlLength(), result, &bufferLength, &offset));
	request->GetHttpVersion(&major, &minor);
	if (1 == major && 1 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.1\r\n", 11, result, &bufferLength, &offset));
	}
	else if (1 == major && 0 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.0\r\n", 11, result, &bufferLength, &offset));
	}
	else
	{
		sprintf(tmp, " HTTP/%d.%d\r\n", major, minor);
		CheckError(CHttpProtocol::Append(context, tmp, 0, result, &bufferLength, &offset));
	}

	// Known headers

	for (int i = 0; i < HttpHeaderRequestMaximum; i++)
	{
		if (raw->Headers.KnownHeaders[i].RawValueLength > 0)
		{
			CheckError(CHttpProtocol::Append(context, CHttpProtocol::httpRequestHeaders[i], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, raw->Headers.KnownHeaders[i].pRawValue, raw->Headers.KnownHeaders[i].RawValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
		}
	}

	// Unknown headers

	if (TRUE == (addXFF = CModuleConfiguration::GetEnableXFF(context)))
	{
		PSOCKADDR addr = request->GetRemoteAddress();
		DWORD addrSize = addr->sa_family == AF_INET ? sizeof SOCKADDR_IN : sizeof SOCKADDR_IN6;
		ErrorIf(0 != WSAAddressToString(addr, addrSize, NULL, remoteHost, &remoteHostSize), GetLastError());
	}

	for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++)
	{
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pName, raw->Headers.pUnknownHeaders[i].NameLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pRawValue, raw->Headers.pUnknownHeaders[i].RawValueLength, result, &bufferLength, &offset));

		if (addXFF && 15 == raw->Headers.pUnknownHeaders[i].NameLength && 0 == strcmpi("X-Forwarded-For", raw->Headers.pUnknownHeaders[i].pName))
		{
			// augment existing X-Forwarded-For header

			CheckError(CHttpProtocol::Append(context, ", ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, remoteHost, remoteHostSize - 1, result, &bufferLength, &offset));

			addXFF = FALSE;
		}

		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	if (addXFF)
	{
		// add a new X-Forwarded-For header

		CheckError(CHttpProtocol::Append(context, "X-Forwarded-For: ", 17, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, remoteHost, remoteHostSize - 1, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	// promote server variables

	CheckError(CModuleConfiguration::GetPromoteServerVars(context, &serverVars, &serverVarCount));
	while (serverVarCount)
	{
		serverVarCount--;
		PCSTR varValue;
		DWORD varValueLength;
		if (S_OK == context->GetServerVariable(serverVars[serverVarCount], &varValue, &varValueLength))
		{
			CheckError(CHttpProtocol::Append(context, "X-iisnode-", 10, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, serverVars[serverVarCount], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, varValue, varValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
		}
	}

	// CRLF

	CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));

	*resultSize = bufferLength;
	*resultLength = offset;

	return S_OK;
Error:
	
	if (NULL != result)
	{
		*result = NULL;
	}
	if (NULL != resultLength)
	{
		*resultLength = 0;
	}
	if (NULL != resultSize)
	{
		*resultSize = 0;
	}

	return hr;
}
Пример #5
0
BOOL CProtocolBridge::SendDevError(CNodeHttpStoredContext* context, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache)
{
	HRESULT hr;
	DWORD rawLogSize, htmlLogSize, htmlTotalSize;
	IHttpContext* ctx;
	char* rawLog;
	char* templ1;
	char* html;
	char* current;

	if (500 <= status && CModuleConfiguration::GetDevErrorsEnabled(context->GetHttpContext()) && NULL != context->GetNodeProcess())
	{
		// return a friendly HTTP 200 response with HTML entity body that contains error details 
		// and the content of node.exe stdout/err, if available

		ctx = context->GetHttpContext();		
		rawLog = context->GetNodeProcess()->TryGetLog(ctx, &rawLogSize);
		templ1 = 
			"<p>iisnode encountered an error when processing the request.</p><pre style=\"background-color: eeeeee\">"
			"HRESULT: 0x%x\n"
			"HTTP status: %d\n"
			"HTTP reason: %s</pre>"
			"<p>You are receiving this HTTP 200 response because <a href=""https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config"">"
			"system.webServer/iisnode/@devErrorsEnabled</a> configuration setting is 'true'.</p>"
			"<p>In addition to the log of stdout and stderr of the node.exe process, consider using "
			"<a href=""http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html"">debugging</a> "
			"and <a href=""http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html"">ETW traces</a> to further diagnose the problem.</p>";
		
		// calculate HTML encoded size of the log

		htmlLogSize = 0;
		for (int i = 0; i < rawLogSize; i++)
		{
			if (rawLog[i] >= 0 && rawLog[i] <= 0x8
				|| rawLog[i] >= 0xb && rawLog[i] <= 0xc
				|| rawLog[i] >= 0xe && rawLog[i] <= 0x1f
				|| rawLog[i] >= 0x80 && rawLog[i] <= 0x9f)
			{
				// characters disallowed in HTML will be converted to [xAB] notation, thus taking 5 bytes
				htmlLogSize += 5;
			}
			else
			{
				switch (rawLog[i]) 
				{
				default:
					htmlLogSize++; 
					break;
				case '&':
					htmlLogSize += 5; // &amp;
					break;
				case '<':
				case '>':
					htmlLogSize += 4; // &lt; &gt;
					break;
				case '"':
				case '\'':
					htmlLogSize += 6; // &quot; &apos;
					break;
				};
			}
		}

		// calculate total size of HTML and allocate memory

		htmlTotalSize = strlen(templ1) + 20 /* hresult */ + 20 /* status code */ + strlen(reason) + 300 /* log content heading */ + htmlLogSize;
		ErrorIf(NULL == (html = (char*)ctx->AllocateRequestMemory(htmlTotalSize)), ERROR_NOT_ENOUGH_MEMORY);
		RtlZeroMemory(html, htmlTotalSize);

		// construct the HTML

		sprintf(html, templ1, hresult, status, reason);

		if (0 == rawLogSize)
		{
			if (CModuleConfiguration::GetLoggingEnabled(ctx))
			{
				strcat(html, "<p>The node.exe process has not written any information to the stdout or stderr.</p>");
			}
			else
			{
				strcat(html, "<p>You may get additional information about this error condition by logging stdout and stderr of the node.exe process."
					"To enable logging, set the <a href=""https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config"">"
					"system.webServer/iisnode/@loggingEnabled</a> configuration setting to 'true' (current value is 'false').</p>");
			}
		}
		else
		{
			strcat(html, "<p>The last 64k of the output generated by the node.exe process to stdout and stderr is shown below:</p><pre style=\"background-color: eeeeee\">");

			current = html + strlen(html);

			if (htmlLogSize == rawLogSize)
			{
				// no HTML encoding is necessary
				
				memcpy(current, rawLog, rawLogSize);
			}
			else
			{
				// HTML encode the log

				for (int i = 0; i < rawLogSize; i++)
				{
					if (rawLog[i] >= 0 && rawLog[i] <= 0x8
						|| rawLog[i] >= 0xb && rawLog[i] <= 0xc
						|| rawLog[i] >= 0xe && rawLog[i] <= 0x1f
						|| rawLog[i] >= 0x80 && rawLog[i] <= 0x9f)
					{
						// characters disallowed in HTML are converted to [xAB] notation
						*current++ = '[';
						*current++ = 'x';
						*current = rawLog[i] >> 4;
						*current++ += *current > 9 ? 'A' - 10 : '0';
						*current = rawLog[i] & 15;
						*current++ += *current > 9 ? 'A' - 10 : '0';
						*current++ = ']';
					}
					else
					{
						switch (rawLog[i]) 
						{
						default:
							*current++ = rawLog[i];
							break;
						case '&':
							*current++ = '&';
							*current++ = 'a';
							*current++ = 'm';
							*current++ = 'p';
							*current++ = ';';
							break;
						case '<':
							*current++ = '&';
							*current++ = 'l';
							*current++ = 't';
							*current++ = ';';
							break;
						case '>':
							*current++ = '&';
							*current++ = 'g';
							*current++ = 't';
							*current++ = ';';
							break;
						case '"':
							*current++ = '&';
							*current++ = 'q';
							*current++ = 'u';
							*current++ = 'o';
							*current++ = 't';
							*current++ = ';';
							break;
						case '\'':
							*current++ = '&';
							*current++ = 'a';
							*current++ = 'p';
							*current++ = 'o';
							*current++ = 's';
							*current++ = ';';
							break;
						};
					}
				}
			}
Пример #6
0
HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void** result, DWORD* resultSize, DWORD* resultLength)
{
	HRESULT hr;
	PCSTR originalUrl = NULL;
	USHORT originalUrlLength;	

	CheckNull(ctx);
	CheckNull(result);
	CheckNull(resultSize);
	CheckNull(resultLength);

	IHttpContext* context = ctx->GetHttpContext();

	DWORD bufferLength = CModuleConfiguration::GetInitialRequestBufferSize(context);
	DWORD offset = 0;
	IHttpRequest* request = context->GetRequest();
	HTTP_REQUEST* raw = request->GetRawHttpRequest();
	USHORT major, minor;
	char tmp[256];
	PCSTR method = request->GetHttpMethod();
	
	ErrorIf(NULL == (*result = context->AllocateRequestMemory(bufferLength)), ERROR_NOT_ENOUGH_MEMORY);	

	// Determine whether response entity body is to be expected

	if (method && 0 == strcmpi("HEAD", method))
	{
		// HEAD requests do not have response entity body
		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4

		ctx->SetExpectResponseBody(FALSE);
	}
	
	// Request-Line

	CheckError(CHttpProtocol::Append(context, method, 0, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, " ", 1, result, &bufferLength, &offset));
	CheckError(CHttpProtocol::Append(context, ctx->GetTargetUrl(), ctx->GetTargetUrlLength(), result, &bufferLength, &offset));
	request->GetHttpVersion(&major, &minor);
	if (1 == major && 1 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.1\r\n", 11, result, &bufferLength, &offset));
	}
	else if (1 == major && 0 == minor)
	{
		CheckError(CHttpProtocol::Append(context, " HTTP/1.0\r\n", 11, result, &bufferLength, &offset));
	}
	else
	{
		sprintf(tmp, " HTTP/%d.%d\r\n", major, minor);
		CheckError(CHttpProtocol::Append(context, tmp, 0, result, &bufferLength, &offset));
	}

	// Known headers

	for (int i = 0; i < HttpHeaderRequestMaximum; i++)
	{
		if (raw->Headers.KnownHeaders[i].RawValueLength > 0)
		{
			CheckError(CHttpProtocol::Append(context, CHttpProtocol::httpRequestHeaders[i], 0, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, raw->Headers.KnownHeaders[i].pRawValue, raw->Headers.KnownHeaders[i].RawValueLength, result, &bufferLength, &offset));
			CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
		}
	}

	// Unknown headers

	for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++)
	{
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pName, raw->Headers.pUnknownHeaders[i].NameLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pRawValue, raw->Headers.pUnknownHeaders[i].RawValueLength, result, &bufferLength, &offset));
		CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));		
	}

	// CRLF

	CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));

	*resultSize = bufferLength;
	*resultLength = offset;

	return S_OK;
Error:
	
	if (NULL != result)
	{
		*result = NULL;
	}
	if (NULL != resultLength)
	{
		*resultLength = 0;
	}
	if (NULL != resultSize)
	{
		*resultSize = 0;
	}

	return hr;
}