Beispiel #1
0
HRESULT CHttpProtocol::ParseChunkHeader(CNodeHttpStoredContext* context)
{
	HRESULT hr;

	char* data = (char*)context->GetBuffer() + context->GetParsingOffset();
	char* current;
	char* chunkHeaderStart;
	DWORD dataSize = context->GetDataSize() - context->GetParsingOffset();
	ULONG chunkLength = 0;
	ULONG totalChunkLength = 0;

	// attempt to parse as many response body chunks as there are buffered in memory

	current = data;
	do
	{
		// parse chunk length
		
		chunkHeaderStart = current;
		chunkLength = 0;
		while (true)
		{
			ErrorIf((current - data) >= dataSize, ERROR_MORE_DATA);
			if (*current >= 'A' && *current <= 'F')
			{
				chunkLength <<= 4;
				chunkLength += *current - 'A' + 10;
			}
			else if (*current >= 'a' && *current <= 'f')
			{
				chunkLength <<= 4;
				chunkLength += *current - 'a' + 10;
			}
			else if (*current >= '0' && *current <= '9')
			{
				chunkLength <<= 4;
				chunkLength += *current - '0';
			}
			else 
			{
				ErrorIf(current == chunkHeaderStart, ERROR_BAD_FORMAT); // no hex digits found
				break;
			}

			current++;
		}

		// skip optional extensions

		while (true)
		{
			ErrorIf((current - data) >= dataSize, ERROR_MORE_DATA);
			if (*current == 0x0D)
			{
				break;
			}

			current++;
		}

		// LF

		current++;
		ErrorIf((current - data) >= dataSize, ERROR_MORE_DATA);
		ErrorIf(*current != 0x0A, ERROR_BAD_FORMAT);
		current++;

		// remember total length of all parsed chunks before attempting to parse subsequent chunk header

		// set total chunk length to include current chunk content length, previously parsed chunks (with headers), 
		// plus the CRLF following the current chunk content
		totalChunkLength = chunkLength + (ULONG)(current - data) + 2; 
		current += chunkLength + 2; // chunk content length + CRLF

	} while (chunkLength != 0); // exit when last chunk has been detected	

	// if we are here, current buffer contains the header of the last chunk of the response

	context->SetChunkLength(totalChunkLength);
	context->SetIsLastChunk(TRUE);
	context->SetChunkTransmitted(0);

	return S_OK;

Error:

	if (ERROR_MORE_DATA != hr)
	{
		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
			L"iisnode failed to parse response body chunk header", WINEVENT_LEVEL_ERROR, context->GetActivityId());

		return hr;
	}
	else if (0 < totalChunkLength)
	{
		// at least one response chunk has been successfuly parsed, but more chunks remain

		context->SetChunkLength(totalChunkLength);
		context->SetIsLastChunk(FALSE);
		context->SetChunkTransmitted(0);

		return S_OK;
	}

	return hr;
}
HRESULT CModuleConfiguration::CreateNodeEnvironment(IHttpContext* ctx, PCH namedPipe, PCH* env)
{
	HRESULT hr;
	LPCH currentEnvironment = NULL;
	LPCH tmpStart, tmpIndex = NULL;
	DWORD tmpSize;
	DWORD environmentSize;
	IAppHostElement* section = NULL;
	IAppHostElementCollection* appSettings = NULL;
	IAppHostElement* entry = NULL;
	IAppHostPropertyCollection* properties = NULL;
	IAppHostProperty* prop = NULL;
	BSTR keyPropertyName = NULL;
	BSTR valuePropertyName = NULL;
	VARIANT vKeyPropertyName;
	VARIANT vValuePropertyName;
	DWORD count;
	BSTR propertyValue;
	int propertySize;

	CheckNull(env);
	*env = NULL;

	// this is a zero terminated list of zero terminated strings of the form <var>=<value>

	// calculate size of current environment

	ErrorIf(NULL == (currentEnvironment = GetEnvironmentStrings()), GetLastError());
	environmentSize = 0;
	do {
		while (*(currentEnvironment + environmentSize++) != 0);
	} while (*(currentEnvironment + environmentSize++) != 0);

	// allocate memory for new environment variables

	tmpSize = 32767 - environmentSize;
	ErrorIf(NULL == (tmpIndex = tmpStart = new char[tmpSize]), ERROR_NOT_ENOUGH_MEMORY);
	RtlZeroMemory(tmpIndex, tmpSize);

	// set PORT and IISNODE_VERSION variables

	ErrorIf(tmpSize < (strlen(namedPipe) + strlen(IISNODE_VERSION) + 6 + 17), ERROR_NOT_ENOUGH_MEMORY);
	sprintf(tmpIndex, "PORT=%s", namedPipe);
	tmpIndex += strlen(namedPipe) + 6;
	sprintf(tmpIndex, "IISNODE_VERSION=%s", IISNODE_VERSION);
	tmpIndex += strlen(IISNODE_VERSION) + 17;

	// add environment variables from the appSettings section of config

	ErrorIf(NULL == (keyPropertyName = SysAllocString(L"key")), ERROR_NOT_ENOUGH_MEMORY);
	vKeyPropertyName.vt = VT_BSTR;
	vKeyPropertyName.bstrVal = keyPropertyName;
	ErrorIf(NULL == (valuePropertyName = SysAllocString(L"value")), ERROR_NOT_ENOUGH_MEMORY);
	vValuePropertyName.vt = VT_BSTR;
	vValuePropertyName.bstrVal = valuePropertyName;
	CheckError(GetConfigSection(ctx, &section, L"appSettings"));
	CheckError(section->get_Collection(&appSettings));
	CheckError(appSettings->get_Count(&count));

	for (USHORT i = 0; i < count; i++)
	{
		VARIANT index;
		index.vt = VT_I2;
		index.iVal = i;		

		CheckError(appSettings->get_Item(index, &entry));
		CheckError(entry->get_Properties(&properties));
		
		CheckError(properties->get_Item(vKeyPropertyName, &prop));
		CheckError(prop->get_StringValue(&propertyValue));
		ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL);
		ErrorIf((propertySize + 2) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY);
		ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL);
		tmpIndex[propertySize] = '=';
		tmpIndex += propertySize + 1;
		SysFreeString(propertyValue);
		propertyValue = NULL;
		prop->Release();
		prop = NULL;

		CheckError(properties->get_Item(vValuePropertyName, &prop));
		CheckError(prop->get_StringValue(&propertyValue));
		ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL);
		ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY);
		ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL);
		tmpIndex += propertySize + 1;
		SysFreeString(propertyValue);
		propertyValue = NULL;
		prop->Release();
		prop = NULL;

		properties->Release();
		properties = NULL;
		entry->Release();
		entry = NULL;
	}

	// concatenate new environment variables with the current environment block

	ErrorIf(NULL == (*env = (LPCH)new char[environmentSize + (tmpIndex - tmpStart)]), ERROR_NOT_ENOUGH_MEMORY);	
	memcpy(*env, tmpStart, (tmpIndex - tmpStart));
	memcpy(*env + (tmpIndex - tmpStart), currentEnvironment, environmentSize);

	// cleanup

	FreeEnvironmentStrings(currentEnvironment);
	section->Release();
	appSettings->Release();
	SysFreeString(keyPropertyName);
	SysFreeString(valuePropertyName);
	delete [] tmpStart;

	return S_OK;
Error:

	if (currentEnvironment)
	{
		FreeEnvironmentStrings(currentEnvironment);
		currentEnvironment = NULL;
	}

	if (section)
	{
		section->Release();
		section = NULL;
	}

	if (appSettings)
	{
		appSettings->Release();
		appSettings = NULL;
	}

	if (keyPropertyName)
	{
		SysFreeString(keyPropertyName);
		keyPropertyName = NULL;
	}

	if (valuePropertyName)
	{
		SysFreeString(valuePropertyName);
		valuePropertyName = NULL;
	}

	if (entry)
	{
		entry->Release();
		entry = NULL;
	}

	if (properties)
	{
		properties->Release();
		properties = NULL;
	}

	if (prop)
	{
		prop->Release();
		prop = NULL;
	}

	if (propertyValue)
	{
		SysFreeString(propertyValue);
		propertyValue = NULL;
	}

	if (tmpStart)
	{
		delete [] tmpStart;
		tmpStart = NULL;
	}

	return hr;
}
Beispiel #3
0
HRESULT CHttpProtocol::ParseResponseStatusLine(CNodeHttpStoredContext* context)
{
	HRESULT hr;

	char* data = (char*)context->GetBuffer() + context->GetParsingOffset();
	DWORD dataSize = context->GetDataSize() - context->GetParsingOffset();
	DWORD offset = 0;	
	USHORT major, minor;
	DWORD count, newOffset;
	char tmp[256];
	char* tmp1;
	USHORT statusCode, subStatusCode = 0;

	// HTTP-Version SP

	context->GetHttpContext()->GetRequest()->GetHttpVersion(&major, &minor);
	if (1 == major && 1 == minor)
	{
		tmp1 = "HTTP/1.1 ";
		count = 9;
	}
	else if (1 == major && 0 == minor)
	{
		tmp1 = "HTTP/1.0 ";
		count = 9;
	}
	else
	{
		sprintf(tmp, "HTTP/%d.%d ", major, minor);
		count = strlen(tmp);
		tmp1 = tmp;
	}

	ErrorIf(count >= dataSize, ERROR_MORE_DATA);
	ErrorIf(0 != memcmp(tmp1, data, count), ERROR_BAD_FORMAT);
	offset += count;

	// Status-Code[.Sub-Status-Code] SP

	statusCode = 0;
	while (offset < dataSize && data[offset] >= '0' && data[offset] <= '9')
	{
		statusCode = statusCode * 10 + data[offset++] - '0';
	}
	ErrorIf(offset == dataSize, ERROR_MORE_DATA);

	if ('.' == data[offset])
	{
		// Sub-Status-Code

		offset++;		

		while (offset < dataSize && data[offset] >= '0' && data[offset] <= '9')
		{
			subStatusCode = subStatusCode * 10 + data[offset++] - '0';
		}
		ErrorIf(offset == dataSize, ERROR_MORE_DATA);
	}

	ErrorIf(' ' != data[offset], ERROR_BAD_FORMAT);
	offset++;

	// Determine whether to expect response entity body
	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4

	if (statusCode >= 100 && statusCode < 200
		|| statusCode == 204
		|| statusCode == 304)
	{
		context->SetExpectResponseBody(FALSE);
	}

	// Reason-Phrase CRLF

	newOffset = offset;
	while (newOffset < (dataSize - 1) && data[newOffset] != 0x0D)
	{
		newOffset++;
	}
	ErrorIf(newOffset == dataSize - 1, ERROR_MORE_DATA);
	ErrorIf(0x0A != data[newOffset + 1], ERROR_BAD_FORMAT);
	
	// set HTTP response status line

	data[newOffset] = 0; // zero-terminate the reason phrase to reuse it without copying

	IHttpResponse* response = context->GetHttpContext()->GetResponse();
	response->Clear();
	response->SetStatus(statusCode, data + offset, subStatusCode);
	
	// adjust buffers

	context->SetParsingOffset(context->GetParsingOffset() + newOffset + 2);

	return S_OK;
Error:

	if (ERROR_MORE_DATA != hr)
	{
		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
			L"iisnode failed to parse response status line", WINEVENT_LEVEL_ERROR, context->GetActivityId());
	}

	return hr;
}
HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfiguration** config)
{
	HRESULT hr;
	CModuleConfiguration* c = NULL;
	IAppHostElement* section = NULL;
	LPWSTR commandLine = NULL;
	size_t i;

	CheckNull(config);

	*config = (CModuleConfiguration*)context->GetMetadata()->GetModuleContextContainer()->GetModuleContext(moduleId);

	if (NULL == *config)
	{
		ErrorIf(NULL == (c = new CModuleConfiguration()), ERROR_NOT_ENOUGH_MEMORY);
		
		CheckError(GetConfigSection(context, &section));		
		CheckError(GetDWORD(section, L"maxPendingRequestsPerApplication", &c->maxPendingRequestsPerApplication));
		CheckError(GetDWORD(section, L"asyncCompletionThreadCount", &c->asyncCompletionThreadCount));
		CheckError(GetDWORD(section, L"maxProcessCountPerApplication", &c->maxProcessCountPerApplication));
		CheckError(GetDWORD(section, L"maxConcurrentRequestsPerProcess", &c->maxConcurrentRequestsPerProcess));
		CheckError(GetDWORD(section, L"maxNamedPipeConnectionRetry", &c->maxNamedPipeConnectionRetry));
		CheckError(GetDWORD(section, L"namedPipeConnectionRetryDelay", &c->namedPipeConnectionRetryDelay));
		CheckError(GetDWORD(section, L"initialRequestBufferSize", &c->initialRequestBufferSize));
		CheckError(GetDWORD(section, L"maxRequestBufferSize", &c->maxRequestBufferSize));
		CheckError(GetDWORD(section, L"uncFileChangesPollingInterval", &c->uncFileChangesPollingInterval));
		CheckError(GetDWORD(section, L"gracefulShutdownTimeout", &c->gracefulShutdownTimeout));
		CheckError(GetDWORD(section, L"logFileFlushInterval", &c->logFileFlushInterval));
		CheckError(GetDWORD(section, L"maxLogFileSizeInKB", &c->maxLogFileSizeInKB));
		CheckError(GetBOOL(section, L"loggingEnabled", &c->loggingEnabled));
		CheckError(GetBOOL(section, L"appendToExistingLog", &c->appendToExistingLog));
		CheckError(GetString(section, L"logDirectoryNameSuffix", &c->logDirectoryNameSuffix));
		CheckError(GetString(section, L"nodeProcessCommandLine", &commandLine));
		ErrorIf(NULL == (c->nodeProcessCommandLine = new char[MAX_PATH]), ERROR_NOT_ENOUGH_MEMORY);
		ErrorIf(0 != wcstombs_s(&i, c->nodeProcessCommandLine, (size_t)MAX_PATH, commandLine, _TRUNCATE), ERROR_INVALID_PARAMETER);
		delete [] commandLine;
		commandLine = NULL;
		
		section->Release();
		section = NULL;
		
		// CR: check for ERROR_ALREADY_ASSIGNED to detect a race in creation of this section 
		// CR: refcounting may be needed if synchronous code paths proove too long (race with config changes)
		context->GetMetadata()->GetModuleContextContainer()->SetModuleContext(c, moduleId);
		*config = c;
		c = NULL;
	}

	return S_OK;
Error:

	if (NULL != section)
	{
		section->Release();
		section = NULL;
	}

	if (NULL != commandLine)
	{
		delete [] commandLine;
		commandLine = NULL;
	}

	if (NULL != c)
	{
		delete c;
		c = NULL;
	}

	return hr;
}