diff --git a/src/iisnode/cfilewatcher.cpp b/src/iisnode/cfilewatcher.cpp index befc222..0cda805 100644 --- a/src/iisnode/cfilewatcher.cpp +++ b/src/iisnode/cfilewatcher.cpp @@ -26,7 +26,11 @@ CFileWatcher::~CFileWatcher() while (NULL != this->directories) { WatchedDirectory* currentDirectory = this->directories; - CloseHandle(currentDirectory->watchHandle); + if(currentDirectory->watchHandle != NULL) + { + CloseHandle(currentDirectory->watchHandle); + currentDirectory->watchHandle = NULL; + } delete [] currentDirectory->directoryName; while (NULL != currentDirectory->files) { @@ -385,6 +389,7 @@ Error: if (NULL != newDirectory->watchHandle) { CloseHandle(newDirectory->watchHandle); + newDirectory->watchHandle = NULL; } delete newDirectory; @@ -437,7 +442,11 @@ HRESULT CFileWatcher::RemoveWatch(CNodeApplication* application) if (!directory->files) { delete [] directory->directoryName; - CloseHandle(directory->watchHandle); + if(directory->watchHandle != NULL) + { + CloseHandle(directory->watchHandle); + directory->watchHandle = NULL; + } if (previousDirectory) { @@ -507,7 +516,7 @@ unsigned int CFileWatcher::Worker(void* arg) while (current && current != directory) current = current->next; - if (current) + if (current && current->watchHandle != NULL) { watcher->ScanDirectory(current, FALSE); @@ -541,8 +550,46 @@ unsigned int CFileWatcher::Worker(void* arg) WatchedDirectory* current = watcher->directories; while (current) { - if (watcher->ScanDirectory(current, TRUE)) - break; + // + // watched directory exists, check if handle is valid, if not, create one. + // watchHandle will be NULL if the watched directory was deleted before. + // + if(watcher->DirectoryExists(current->directoryName)) + { + if(current->watchHandle == NULL) + { + current->watchHandle = CreateFileW( + current->directoryName, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + NULL); + } + + // + // scan the directory for file changes + // + if (watcher->ScanDirectory(current, TRUE)) + { + // + // found a change that will recycle the application. + // + break; + } + } + else + { + // + // directory being watched was deleted, close the handle. + // + if(current->watchHandle != NULL) + { + CloseHandle(current->watchHandle); + current->watchHandle = NULL; + } + } current = current->next; } @@ -553,6 +600,16 @@ unsigned int CFileWatcher::Worker(void* arg) return 0; } +BOOL CFileWatcher::DirectoryExists(LPCWSTR directoryPath) +{ + DWORD dwFileAttributes; + + dwFileAttributes = GetFileAttributesW(directoryPath); + + return ((dwFileAttributes != INVALID_FILE_ATTRIBUTES) && + (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); +} + BOOL CFileWatcher::ScanDirectory(WatchedDirectory* directory, BOOL unc) { WatchedFile* file = directory->files; diff --git a/src/iisnode/cfilewatcher.h b/src/iisnode/cfilewatcher.h index 92801c8..cdf9659 100644 --- a/src/iisnode/cfilewatcher.h +++ b/src/iisnode/cfilewatcher.h @@ -42,6 +42,7 @@ private: static unsigned int WINAPI Worker(void* arg); BOOL ScanDirectory(WatchedDirectory* directory, BOOL unc); HRESULT WatchFile(PCWSTR directoryName, DWORD directoryNameLength, BOOL unc, PCWSTR startSubdirectoryName, PCWSTR startFileName, PCWSTR endFileName, BOOL wildcard); + BOOL DirectoryExists(LPCWSTR directoryPath); static HRESULT GetWatchedFileTimestamp(WatchedFile* file, FILETIME* timestamp); public: diff --git a/src/iisnode/cmoduleconfiguration.cpp b/src/iisnode/cmoduleconfiguration.cpp index 43fb091..31f9bf4 100644 --- a/src/iisnode/cmoduleconfiguration.cpp +++ b/src/iisnode/cmoduleconfiguration.cpp @@ -629,10 +629,11 @@ HRESULT CModuleConfiguration::GetBOOL(char* str, BOOL* value) return S_OK; } -HRESULT CModuleConfiguration::GetString(char* str, LPWSTR* value) +HRESULT CModuleConfiguration::GetString(char* str, LPWSTR* value, BOOL expandEnvironmentStrings) { HRESULT hr; int wcharSize, bytesConverted; + LPWSTR pszStr = NULL; if (*value) { @@ -645,12 +646,31 @@ HRESULT CModuleConfiguration::GetString(char* str, LPWSTR* value) str = ""; } - ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); - ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, *value, wcharSize), GetLastError()); + if(expandEnvironmentStrings == FALSE) + { + ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); + ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, *value, wcharSize), GetLastError()); + } + else + { + ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); + ErrorIf(NULL == (pszStr = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, pszStr, wcharSize), GetLastError()); + ErrorIf(0 == (wcharSize = ExpandEnvironmentStringsW(pszStr, NULL, 0)), GetLastError()); + ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(wcharSize != ExpandEnvironmentStringsW(pszStr, *value, wcharSize), GetLastError()); + } + + hr = S_OK; // fall through to clean up section. - return S_OK; Error: + + if(pszStr != NULL) + { + delete[] pszStr; + } + return hr; } @@ -774,7 +794,7 @@ HRESULT CModuleConfiguration::ApplyConfigOverrideKeyValue(IHttpContext* context, } else if (0 == strcmpi(keyStart, "nodeProcessCommandLine")) { - CheckError(GetString(valueStart, &config->nodeProcessCommandLine)); + CheckError(GetString(valueStart, &config->nodeProcessCommandLine, TRUE)); } else if (0 == strcmpi(keyStart, "interceptor")) { diff --git a/src/iisnode/cmoduleconfiguration.h b/src/iisnode/cmoduleconfiguration.h index af62e02..3774250 100644 --- a/src/iisnode/cmoduleconfiguration.h +++ b/src/iisnode/cmoduleconfiguration.h @@ -52,7 +52,7 @@ private: static HRESULT GetBOOL(IAppHostElement* section, LPCWSTR propertyName, BOOL* value, BOOL defaultValue); static HRESULT GetDWORD(char* str, DWORD* value); static HRESULT GetBOOL(char* str, BOOL* value); - static HRESULT GetString(char* str, LPWSTR* value); + static HRESULT GetString(char* str, LPWSTR* value, BOOL expandEnvironmentStrings = FALSE); static HRESULT GetDWORD(IAppHostElement* section, LPCWSTR propertyName, DWORD* value); static HRESULT ApplyConfigOverrideKeyValue(IHttpContext* context, CModuleConfiguration* config, char* keyStart, char* keyEnd, char* valueStart, char* valueEnd); static HRESULT ApplyYamlConfigOverrides(IHttpContext* context, CModuleConfiguration* config); diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index efb59bb..6c9b9a4 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -491,7 +491,17 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) if (NULL == (url = request->GetHeader("X-Original-URL", &urlLength))) { HTTP_REQUEST* raw = request->GetRawHttpRequest(); - context->SetTargetUrl(raw->pRawUrl, raw->RawUrlLength); + + // Fix for https://github.com/tjanczuk/iisnode/issues/296 + PSTR path = NULL; + int pathSizeA = 0; + int cchAbsPathLength = (raw->CookedUrl.AbsPathLength + raw->CookedUrl.QueryStringLength) >> 1; + ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, cchAbsPathLength, NULL, 0, NULL, NULL)), E_FAIL); + ErrorIf(NULL == (path = (TCHAR*)context->GetHttpContext()->AllocateRequestMemory(pathSizeA + 1)), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, cchAbsPathLength, path, pathSizeA, NULL, NULL), E_FAIL); + path[pathSizeA] = 0; + + context->SetTargetUrl(path, pathSizeA); } else { diff --git a/test/functional/www/103_urlrewrite/web.config b/test/functional/www/103_urlrewrite/web.config index 59ce739..148ac55 100644 --- a/test/functional/www/103_urlrewrite/web.config +++ b/test/functional/www/103_urlrewrite/web.config @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + +