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, §ion, 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; }
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, §ion)); 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; }