예제 #1
0
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(&ltime);
			strftime(szCurTime, sizeof(szCurTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&ltime));

			char szFileTime[ 100 ];
			FileTimeToUnixTime(&stFileTime, &ltime);
			strftime(szFileTime, sizeof(szFileTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&ltime));
			
			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;
}
예제 #2
0
파일: main.cpp 프로젝트: martok/miranda-ng
static INT_PTR nAddChangeRemoveShare(WPARAM wParam, LPARAM lParam) {
	if (!lParam)
		return 1001;

	STFileShareInfo * pclNew = (STFileShareInfo*)lParam;

	// make the server path lowercase
	char* pszPos = pclNew->pszSrvPath;
	while (*pszPos) {
		*pszPos = (char)tolower(*pszPos);
		pszPos++;
	}

	if (pclNew->lStructSize != sizeof(STFileShareInfo))
		return 1002;

	CLFileShareListAccess clCritSection;
	bool bIsDirectory = (pclNew->pszSrvPath[strlen(pclNew->pszSrvPath)-1] == '/');

	CLFileShareNode **pclPrev = &pclFirstNode;
	CLFileShareNode * pclCur = pclFirstNode;

	// insert files after directories
	if (!bIsDirectory) {
		while (pclCur && pclCur->bIsDirectory()) {
			pclPrev = &pclCur->pclNext;
			pclCur = pclCur->pclNext;
		}
	}

	while (pclCur) {
		if (_stricmp(pclCur->st.pszSrvPath, pclNew->pszSrvPath) == 0) {
			if (pclCur->bAnyUsers()) {
				// Some downloads are in progress we will try an terminate them !!
				// we try for 5 sec.
				pclCur->CloseAllTransfers();
				int nTryCount = 0;
				do {
					nTryCount++;
					if (nTryCount >= 100)
						return 1004;
					clCritSection.Unlock();
					Sleep(50);
					clCritSection.Lock();
				} while (pclCur->bAnyUsers());
			}

			if (!pclNew->pszRealPath || pclNew->pszRealPath[0] == 0) {
				// remove this one
				*pclPrev = pclCur->pclNext;
				delete pclCur;
			} else {
				// update info !!
				if (! pclCur->bSetInfo(pclNew))
					return 1003;
			}
			return !bWriteConfigurationFile();
		}
		pclPrev = &pclCur->pclNext;
		pclCur = pclCur->pclNext;
	}

	// Node was not found we will add a new one.
	CLFileShareNode* pclNewNode = new CLFileShareNode(pclNew);
	pclNewNode->pclNext = *pclPrev;
	*pclPrev = pclNewNode;

	/* Add by Sérgio Vieira Rolanski */
	if (pclNew->dwOptions & OPT_SEND_LINK)
		SendLinkToUser(wParam, pclNew->pszSrvPath);

	return !bWriteConfigurationFile();
}