bool CLHttpUser::bProcessGetRequest(char * pszRequest, bool bIsGetCommand) { //LogEvent("Request", pszRequest); int nUriLength = nUnescapedURI(pszRequest); if (nUriLength <= 0) return false; CLFileShareListAccess clCritSection; if (bShutdownInProgress) return false; static char szTempfile[MAX_PATH+1]; szTempfile[0] = '\0'; if (!bReadGetParameters(pszRequest)) { SendError(400, "Bad Request"); return false; } DWORD dwRemoteIP = ntohl(stAddr.S_un.S_addr); for (CLFileShareNode * pclCur = pclFirstNode; pclCur ; pclCur = pclCur->pclNext) { if ((pclCur->st.dwAllowedIP ^ dwRemoteIP) & pclCur->st.dwAllowedMask) continue; // Not an allowed IP address if (!pclCur->bIsDirectory() && pclCur->nGetSrvPathLen() != nUriLength) continue; // not the right length, quickly move on to the next. if (pclCur->bIsDirectory() ? (strncmp(pclCur->st.pszSrvPath, pszRequest, pclCur->nGetSrvPathLen() - 1) == 0) : (strncmp(pclCur->st.pszSrvPath, pszRequest, pclCur->nGetSrvPathLen()) == 0)) { /*OutputDebugString( "Request for file OK : "); OutputDebugString( pclCur->st.pszSrvPath ); OutputDebugString( "\n" );*/ static char szSrvPath[MAX_PATH+1]; static char szRealPath[MAX_PATH+1]; char* pszSrvPath = pclCur->st.pszSrvPath; char* pszRealPath = pclCur->st.pszRealPath; if (pclCur->bIsDirectory()) { strcpy(szRealPath, pclCur->st.pszRealPath); strcpy(szSrvPath, pclCur->st.pszSrvPath); pszRealPath = szRealPath; pszSrvPath = szSrvPath; if (nUriLength > MAX_PATH) nUriLength = MAX_PATH; pszRequest[nUriLength] = '\0'; if (pclCur->nGetSrvPathLen() - nUriLength == 1) { SendRedir(302, "Found", "The document has moved", pszRequest); return false; } else { strmcat(pszRealPath, &pszRequest[pclCur->nGetSrvPathLen()], MAX_PATH); strmcat(pszSrvPath, &pszRequest[pclCur->nGetSrvPathLen()], MAX_PATH); } pszRequest[nUriLength] = ' '; // hacker protection - should be removed by the browser if (strstr(pszRealPath, "..")) { SendError(404, "Not Found", "The requested URL was not found on this server."); return false; } char* pszTmp = pszRealPath; while (pszTmp = strchr(pszTmp, '/')) * pszTmp = '\\'; hFile = CreateFile(pszRealPath, GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { if (pszSrvPath[strlen(pszSrvPath)-1] != '/') { strmcat(pszRealPath, "\\", MAX_PATH); strmcat(pszSrvPath, "/", MAX_PATH); } // a directory with index.htm strmcat(szRealPath, "index.htm", MAX_PATH); hFile = CreateFile(pszRealPath, GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL); if (hFile == INVALID_HANDLE_VALUE) { // a directory with index.html strmcat(szRealPath, "l", MAX_PATH); hFile = CreateFile(pszRealPath, GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL); if (hFile == INVALID_HANDLE_VALUE) { // generate directory index in temporary file if (*szTempfile == '\0') { GetTempPath(MAX_PATH, szTempfile); strmcat(szTempfile, "\\HttpServerTemp", MAX_PATH); strmcat(szTempfile, pszSrvPath, MAX_PATH); char* pszTmp = szTempfile; while (pszTmp = strchr(pszTmp, '/')) * pszTmp = '~'; } pszRealPath[strlen(pszRealPath) - 10] = '\0'; // detecting browser function removed // every browser should support it by now bool BrowserSupportsXML = true; //(apszParam[eUserAgent] != NULL) && // (strstr(apszParam[eUserAgent], "Firefox") || // (strstr(apszParam[eUserAgent], "MSIE") && !strstr(apszParam[eUserAgent], "Opera"))); if ((indexCreationMode == INDEX_CREATION_XML || (indexCreationMode == INDEX_CREATION_DETECT && BrowserSupportsXML)) && bCreateIndexXML(pszRealPath, szTempfile, pszSrvPath, dwRemoteIP)) { hFile = CreateFile(szTempfile, GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); strcpy(szRealPath, "a.xml"); // restore .xml for mime type } else if ((indexCreationMode == INDEX_CREATION_HTML || indexCreationMode == INDEX_CREATION_DETECT) && bCreateIndexHTML(pszRealPath, szTempfile, pszSrvPath, dwRemoteIP)) { hFile = CreateFile(szTempfile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); strcpy(szRealPath, "a.html"); // restore .html for mime type } else { continue; } } else { strmcat(pszSrvPath, "index.html", MAX_PATH); szTempfile[0] = '\0'; } } else { strmcat(pszSrvPath, "index.htm", MAX_PATH); szTempfile[0] = '\0'; } } else { szTempfile[0] = '\0'; } } else { hFile = CreateFile(pszRealPath, GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { SendError(404, "Not Found", "HTTP server failed to open local file"); return false; } } strcpy(this->szCurrentDLSrvPath, pszSrvPath); DWORD nDataSize = GetFileSize(hFile, NULL); dwTotalSize = nDataSize; FILETIME stFileTime; GetFileTime(hFile, NULL, NULL, &stFileTime); char szCurTime[ 100 ]; time_t ltime; time(<ime); strftime(szCurTime, sizeof(szCurTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(<ime)); char szFileTime[ 100 ]; FileTimeToUnixTime(&stFileTime, <ime); strftime(szFileTime, sizeof(szFileTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(<ime)); if (apszParam[eIfModifiedSince] && strcmp(apszParam[eIfModifiedSince], szFileTime) == 0) { SendError(304, "Not Modified" ); return true; } // we found match send file !! if (bIsGetCommand) { if (! pclCur->bAddUser(this)) { SendError(403, "Forbidden", "Access has been denied because there are too many connections"); return false; } } if (*(ULONG*)(&stAddr) != 0x0100007F && // do not show popup of 127.0.0.1 strstr(pszRealPath, "\\@") == NULL) { // and of shares which start with an @ ShowPopupWindow(inet_ntoa(stAddr), pszSrvPath); } clCritSection.Unlock(); DWORD dwFileStart = 0; DWORD dwDataToSend = nDataSize; char szETag[ 50 ]; { int nETagLen = mir_snprintf(szETag, SIZEOF(szETag), "\"%x-%x-%x\"", nDataSize, stFileTime.dwHighDateTime, stFileTime.dwLowDateTime); if (!apszParam[eIfRange] || (strncmp(szETag, apszParam[eIfRange], nETagLen) == 0)) { char * pszRange = apszParam[eRange]; if (pszRange) { if (strncmp(pszRange, "bytes=", 6) == 0) { pszRange += 6; // Do resume !!! char *pszEnd; if (pszRange[0] == '-') { // its a suffix-byte-range-spec DWORD dwLen = strtol(pszRange + 1, &pszEnd, 10); if (dwLen < nDataSize) dwFileStart = nDataSize - dwLen; } else { DWORD dwLen = strtol(pszRange, &pszEnd, 10); if (*pszEnd == '-' && dwLen < nDataSize) { dwFileStart = dwLen; pszRange = pszEnd + 1; if (*pszRange != 0) { dwLen = strtol(pszEnd + 1, &pszEnd, 10); if (dwLen > dwFileStart) dwDataToSend = (dwLen + 1) - dwFileStart; else dwFileStart = 0; } } else { SendError(400, "Bad Request"); return false; } } } } } } if (dwFileStart >= nDataSize) dwFileStart = 0; if (dwFileStart + dwDataToSend >= nDataSize) dwDataToSend = nDataSize - dwFileStart; DWORD dwBytesToWrite = 0; // To optimize send speed it it ideal to always send larges size packages // But this size depended on network media but on Ethernet it is 1518 bytes. // Ethernet, IP and TCP headers use some of this space and leaves 1460 bytes // for data transfer. // We will use a multiply of this to always send optimal sized packages. char szBuf[1460 * 4]; if (dwFileStart > 0 || dwDataToSend != nDataSize) { if (SetFilePointer(hFile, dwFileStart, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { SendError(416, "Requested Range Not Satisfiable"); return true; } const char szHttpPartial[] = "HTTP/1.1 206 Partial Content\r\n" "Connection: Keep-Alive\r\n" "Date: %s\r\n" "Server: MirandaWeb/%s\r\n" "Accept-Ranges: bytes\r\n" "ETag: %s\r\n" "Content-Length: %d\r\n" "Content-Type: %s\r\n" "Content-Range: bytes %d-%d/%d\r\n" "Last-Modified: %s\r\n" "\r\n"; dwBytesToWrite = mir_snprintf(szBuf, SIZEOF(szBuf), szHttpPartial, szCurTime, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), szETag, dwDataToSend, pszGetMimeType(pszRealPath), dwFileStart, (dwFileStart + dwDataToSend - 1), nDataSize, szFileTime); } else { const char szHttpOk[] = "HTTP/1.1 200 OK\r\n" "Connection: Keep-Alive\r\n" "Date: %s\r\n" "Server: MirandaWeb/%s\r\n" "Accept-Ranges: bytes\r\n" "ETag: %s\r\n" "Content-Length: %d\r\n" "Content-Type: %s\r\n" "Last-Modified: %s\r\n" "\r\n"; dwBytesToWrite = mir_snprintf(szBuf, SIZEOF(szBuf), szHttpOk, szCurTime, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), szETag, nDataSize, pszGetMimeType(pszRealPath), szFileTime); } Netlib_Send(hConnection, szBuf, dwBytesToWrite, 0); if (bIsGetCommand) { static int nThreadCount = 0; nThreadCount++; DWORD dwLastUpdate = GetTickCount(); DWORD dwLastCurrentDL = 0; /* dwLastDLSTickCount = dwCurTick; dwCurrentDL;*/ //DWORD dwMaxSpeed = 8192;// Byte pr Sek //DWORD dwMaxSpeed = 20000;// Byte pr Sek //DWORD dwMaxSpeed = 163840;// Byte pr Sek //DWORD dwMaxSpeed = 4096;// Byte pr Sek DWORD dwLastResetTime = GetTickCount(); int nMaxBytesToSend = nMaxUploadSpeed / nThreadCount; for (;;) { { DWORD dwCurTick = GetTickCount(); if (dwCurTick - dwLastUpdate >= 1000) { dwSpeed = ((dwCurrentDL - dwLastCurrentDL) * 1000) / (dwCurTick - dwLastUpdate); dwLastUpdate = dwCurTick; dwLastCurrentDL = dwCurrentDL; } } if (nMaxUploadSpeed == 0) { Sleep(1000); continue; } bool bSpeedLimit = (nMaxUploadSpeed >= 0) && (bIsOnline || !bLimitOnlyWhenOnline); DWORD dwCurOpr = sizeof(szBuf); if (bSpeedLimit) dwCurOpr = min(nMaxBytesToSend, sizeof(szBuf)); if (!ReadFile(hFile, szBuf, dwCurOpr, &dwBytesToWrite, NULL)) break; if (dwBytesToWrite <= 0) break; if (dwCurrentDL + dwBytesToWrite > dwDataToSend) dwBytesToWrite = dwDataToSend - dwCurrentDL; if (bSpeedLimit) nMaxBytesToSend -= dwBytesToWrite; DWORD dwSend = Netlib_Send(hConnection, szBuf, dwBytesToWrite, MSG_NODUMP); if (dwSend == SOCKET_ERROR) break; dwCurrentDL += dwSend; if (dwSend != dwBytesToWrite) break; if (dwCurrentDL >= dwDataToSend) break; if (bSpeedLimit && nMaxBytesToSend <= 0) { // we have reached the limmit DWORD dwTimeUsed = GetTickCount() - dwLastResetTime; if (dwTimeUsed < 1000) Sleep(1000 - dwTimeUsed); dwLastResetTime = GetTickCount(); nMaxBytesToSend = nMaxUploadSpeed / nThreadCount; } } // file is always closed in destructor if (szTempfile[0] != '\0') { // and here - since it is a temporary index which as to be deleted CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; DeleteFile(szTempfile); } clCritSection.Lock(); nThreadCount--; bool bNeedToWriteConfig = false; if (dwCurrentDL == nDataSize) { if (pclCur->st.nMaxDownloads > 0) { pclCur->st.nMaxDownloads--; bNeedToWriteConfig = true; } } pclCur->bRemoveUser(this); // nMaxDownloads can have been decreesed by another thread. // Therefore we test it even if we did'en decreese it if (pclCur->st.nMaxDownloads == 0 && !pclCur->bAnyUsers()) { CLFileShareNode **pclPrev = &pclFirstNode; for (CLFileShareNode * pcl = pclFirstNode ; pcl ; pcl = pcl->pclNext) { if (pcl == pclCur) { *pclPrev = pclCur->pclNext; ShowPopupWindow(Translate("Share removed"), pclCur->st.pszSrvPath, RGB(255, 189, 189)); delete pclCur; bNeedToWriteConfig = true; break; } pclPrev = &pcl->pclNext; } } if (bNeedToWriteConfig) { bWriteConfigurationFile(); } } return true; } } #ifdef _DEBUG OutputDebugString("########### Request Failed ###########\n"); OutputDebugString(pszRequest); #endif pszRequest[nUriLength] = 0; if ((nUriLength != 12 || strncmp(pszRequest, "/favicon.ico", nUriLength)) && // do not show popup of favicon.ico *(ULONG*)(&stAddr) != 0x0100007F) { // do not show popup of 127.0.0.1 ShowPopupWindow(inet_ntoa(stAddr), pszRequest, RGB(255, 189, 189)); } SendError(404, "Not Found", "The requested URL was not found on this server."); return false; }
bool bCreateIndexXML(const char * pszRealPath, const char * pszIndexPath, const char * pszSrvPath, DWORD dwRemoteIP) { char szMask[MAX_PATH+1]; mir_snprintf(szMask, _countof(szMask), "%s*", pszRealPath); WIN32_FIND_DATAA fdFindFileData; HANDLE hFind = FindFirstFile(szMask, &fdFindFileData); if (hFind == INVALID_HANDLE_VALUE) return FALSE; HANDLE hFile = CreateFile(pszIndexPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); if (hFile == INVALID_HANDLE_VALUE) { FindClose(hFind); return FALSE; } const int BUFFER_SIZE = 1000; char szBuffer[BUFFER_SIZE+1]; char* pszBuffer = szBuffer; char szFileName[MAX_PATH+1] = ""; char* pszExt; DWORD dwBytesWritten = 0; // Generate Dirname strncpy(szBuffer, pszSrvPath, BUFFER_SIZE); char* pszTemp = strrchr(szBuffer, '/'); if (pszTemp) *pszTemp = '\0'; pszTemp = strrchr(szBuffer, '/'); if (pszTemp) strncpy(szFileName, pszTemp + 1, MAX_PATH); // Write Header WriteFile(hFile, szXmlHeader1, sizeof(szXmlHeader1) - 1, &dwBytesWritten, NULL); // check if a index.xsl exists in the same directory otherwise use the global mir_snprintf(szMask, _countof(szMask), "%s%s", pszRealPath, "index.xsl"); HANDLE hFileExists = CreateFile(szMask, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFileExists == INVALID_HANDLE_VALUE) { strncpy(szBuffer, "/index.xsl", BUFFER_SIZE); } else { CloseHandle(hFileExists); strncpy(szBuffer, "index.xsl", BUFFER_SIZE); } WriteFile(hFile, szBuffer, (DWORD)mir_strlen(szBuffer), &dwBytesWritten, NULL); WriteFile(hFile, szXmlHeader2, sizeof(szXmlHeader2) - 1, &dwBytesWritten, NULL); // Write dirname ReplaceSign(szFileName, MAX_PATH, '&', "&"); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), " <dirname>%s</dirname>\r\n", szFileName); WriteFile(hFile, szBuffer, pszBuffer - szBuffer, &dwBytesWritten, NULL); // Find files and directories do { if (mir_strcmp(fdFindFileData.cFileName, ".") && strncmp(fdFindFileData.cFileName, "@", 1) && (mir_strcmp(fdFindFileData.cFileName, "..") || mir_strcmp(pszSrvPath, "/"))) { // hide .. in root pszBuffer = szBuffer; mir_strcpy(szFileName, fdFindFileData.cFileName); ReplaceSign(szFileName, MAX_PATH, '&', "&"); if (fdFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), " <item name=\"%s\" isdir=\"true\"/>\r\n", szFileName); } else { pszExt = strrchr(szFileName, '.'); if (pszExt != NULL) { *pszExt = '\0'; pszExt++; } pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), " <item name=\"%s\" ext=\"%s\" size=\"%i\" ", szFileName, (pszExt == NULL) ? "" : pszExt, fdFindFileData.nFileSizeLow); SYSTEMTIME systemTime; FileTimeToSystemTime(&fdFindFileData.ftCreationTime, &systemTime); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), "created=\"%i/%02i/%02i %i:%02i:%02i\" ", systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond); FileTimeToSystemTime(&fdFindFileData.ftLastWriteTime, &systemTime); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), "modified=\"%i/%02i/%02i %i:%02i:%02i\" ", systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), "/>\r\n"); } if (!WriteFile(hFile, szBuffer, pszBuffer - szBuffer, &dwBytesWritten, NULL)) break; } } while (FindNextFile(hFind, &fdFindFileData)); if (hFind != 0) FindClose(hFind); // Add other shared files & directories for (CLFileShareNode * pclCur = pclFirstNode; pclCur ; pclCur = pclCur->pclNext) { if (!((pclCur->st.dwAllowedIP ^ dwRemoteIP) & pclCur->st.dwAllowedMask) && // hide inaccessible shares (size_t)(pclCur->nGetSrvPathLen()) > mir_strlen(pszSrvPath) && !strstr(pclCur->st.pszRealPath, "\\@") && !strncmp(pclCur->st.pszSrvPath, pszSrvPath, mir_strlen(pszSrvPath))) { pszBuffer = szBuffer; mir_strcpy(szFileName, &pclCur->st.pszSrvPath[mir_strlen(pszSrvPath)]); ReplaceSign(szFileName, MAX_PATH, '&', "&"); if (pclCur->bIsDirectory()) { szFileName[mir_strlen(szFileName)-1] = '\0'; if (!strchr(szFileName, '/')) { // only one level deeper pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), " <item name=\"%s\" isdir=\"true\"/>\r\n", szFileName); if (!WriteFile(hFile, szBuffer, pszBuffer - szBuffer, &dwBytesWritten, NULL)) break; } } else { if (!strchr(szFileName, '/') && // only one level deeper strncmp(pszRealPath, pclCur->st.pszRealPath, mir_strlen(pszRealPath))) { // no duplicates pszExt = strrchr(szFileName, '.'); if (pszExt != NULL) { *pszExt = '\0'; pszExt++; } DWORD dwFileSize = 0; FILETIME ftFileCreateTime; FILETIME ftFileAccessTime; FILETIME ftFileModifyTime; HANDLE hFileS = CreateFile(pclCur->st.pszRealPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFileS != INVALID_HANDLE_VALUE) { dwFileSize = GetFileSize(hFileS, NULL); GetFileTime(hFileS, &ftFileCreateTime, &ftFileAccessTime, &ftFileModifyTime); CloseHandle(hFileS); } pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), " <item name=\"%s\" ext=\"%s\" size=\"%i\" ", szFileName, (pszExt == NULL) ? "" : pszExt, dwFileSize); SYSTEMTIME systemTime; FileTimeToSystemTime(&ftFileCreateTime, &systemTime); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), "created=\"%i/%02i/%02i %i:%02i:%02i\" ", systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond); FileTimeToSystemTime(&ftFileModifyTime, &systemTime); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), "modified=\"%i/%02i/%02i %i:%02i:%02i\" ", systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond); pszBuffer += mir_snprintf(pszBuffer, BUFFER_SIZE - (pszBuffer - szBuffer), "/>\r\n"); if (!WriteFile(hFile, szBuffer, pszBuffer - szBuffer, &dwBytesWritten, NULL)) break; } } } } WriteFile(hFile, szXmlTail, sizeof(szXmlTail) - 1, &dwBytesWritten, NULL); SetEndOfFile(hFile); CloseHandle(hFile); return TRUE; }