//This file is part of HTTPServer a Miranda IM plugin
//Copyright (C)2002 Kennet Nielsen
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "Glob.h"
/////////////////////////////////////////////////////////////////////
// Member Function : FileTimeToUnixTime
// Type : Global
// Parameters : pft - ?
// t - ?
// Returns : void
// Description :
//
// References : -
// Remarks : -
// Created : 030826, 26 august 2003
// Developer : KN
/////////////////////////////////////////////////////////////////////
void FileTimeToUnixTime(LPFILETIME pft, time_t* t) {
LONGLONG ll = ((LONGLONG)pft->dwHighDateTime) << 32;
ll = ll + pft->dwLowDateTime - 116444736000000000;
*t = (time_t)(ll / 10000000);
}
/////////////////////////////////////////////////////////////////////
// Function : nUnescapedURI
// Type : Local
// Parameters : pszURI - URI to convert buffer is modifyed !!
// Returns : length of the Unescaped URI
// Description :
//
// References : -
// Remarks : -
// Created : 030911, 11 september 2003
// Developer : KN
/////////////////////////////////////////////////////////////////////
static int nUnescapedURI(char * pszURI) {
if (! pszURI)
return 0;
char * pszOrigURI = pszURI;
int sumb;
int more = -1;
char* pszCurInsert = pszURI;
for (; *pszURI && pszURI[0] != ' ' ; pszURI++) {
int nNewChar;
if (pszURI[0] == '%') {
// we need to unescape the char
if (pszURI[1] == NULL || pszURI[2] == NULL || pszURI[1] == ' ' || pszURI[2] == ' ')
break; // handles error like "%2 " or "%a"
if (sscanf(&pszURI[1], "%2X", &nNewChar) != 1) {
// can't convert to number
pszURI += 2;
continue; // we skip it !!!
}
pszURI += 2;
}
/*else if( pszURI[0] == '+' )
{
nNewChar = ' ';
}*/
else
nNewChar = (int)tolower(pszURI[0]); // also make the request lowercase
if (nNewChar == '\\')
nNewChar = '/';
if ((nNewChar & 0x80) == 0x00) { // 0xxxxxxx (yields 7 bits)
more = -1; // this is to avoid sequence like %C3k%A6 will end up beeing "kę" insted it will be "k"
*pszCurInsert = (char)nNewChar;
pszCurInsert++;
continue;
}
if ((nNewChar & 0xc0) == 0x80) { // 10xxxxxx (continuation byte)
sumb = (sumb << 6) | (nNewChar & 0x3f) ; // Add 6 bits to sumb
more--;
if (more == 0) {
*pszCurInsert = (char)sumb; // here we just throw away all the fine UTF-8 encoding
pszCurInsert++;
}
} else if ((nNewChar & 0xe0) == 0xc0) { // 110xxxxx (yields 5 bits)
sumb = nNewChar & 0x1f;
more = 1; // Expect 1 more byte
} else if ((nNewChar & 0xf0) == 0xe0) { // 1110xxxx (yields 4 bits)
sumb = nNewChar & 0x0f;
more = 2; // Expect 2 more bytes
} else if ((nNewChar & 0xf8) == 0xf0) { // 11110xxx (yields 3 bits)
sumb = nNewChar & 0x07;
more = 3; // Expect 3 more bytes
} else if ((nNewChar & 0xfc) == 0xf8) { // 111110xx (yields 2 bits)
sumb = nNewChar & 0x03;
more = 4; // Expect 4 more bytes
} else /*if ((nNewChar & 0xfe) == 0xfc)*/
{ // 1111110x (yields 1 bit)
sumb = nNewChar & 0x01;
more = 5; // Expect 5 more bytes
}
}
return (pszCurInsert - pszOrigURI);
}
/////////////////////////////////////////////////////////////////////
// Member Function : CLHttpUser
// Type : Private / Public / Protected
// Parameters : hCon - ?
// stAdd - ?
// pcl - ?
// Returns :
// Description :
//
// References : -
// Remarks : -
// Created : 030918, 18 september 2003
// Developer : KN
/////////////////////////////////////////////////////////////////////
CLHttpUser::CLHttpUser(HANDLE hCon, in_addr stAdd) : CLShareUser(hCon, stAdd) {
memset(apszParam, 0, sizeof(apszParam));
hFile = INVALID_HANDLE_VALUE;
}
/////////////////////////////////////////////////////////////////////
// Member Function : CLHttpUser
// Type : Private / Public / Protected
// Parameters : None
// Returns :
// Description :
//
// References : -
// Remarks : -
// Created : 031124, 24 november 2003
// Developer : KN
/////////////////////////////////////////////////////////////////////
CLHttpUser::~CLHttpUser() {
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
/////////////////////////////////////////////////////////////////////
// Member Function : bReadGetParameters
// Type : Private / Public / Protected
// Parameters : pszRequest - ?
// Returns : Returns true if
// Description :
//
// References : -
// Remarks : -
// Created : 030928, 28 september 2003
// Developer : KN
/////////////////////////////////////////////////////////////////////
bool CLHttpUser::bReadGetParameters(char * pszRequest) {
bool bRet = true;
for (; *pszRequest ; pszRequest++) {
if (pszRequest[0] != '\n') {
if (pszRequest[0] == '\r')
pszRequest[0] = 0;
continue;
}
pszRequest[0] = 0;
pszRequest++;
for (int nCur = 0; nCur < eLastParam ; nCur++) {
int nLen = (int)mir_strlen(szParmStr[nCur]);
if (strncmp(pszRequest, szParmStr[nCur], nLen) == 0) {
if (apszParam[nCur]) {
bRet = false;
// already set !!
} else {
pszRequest += nLen;
apszParam[nCur] = pszRequest;
pszRequest += strcspn(pszRequest, "\r\n") - 1;
char * psz = pszRequest;
while (*psz == ' ') {
psz[0] = 0;// owerwrite ' ' or '\r' or '\n'
psz--;
}
}
break;
}
}
}
return bRet;
}
/////////////////////////////////////////////////////////////////////
// Member Function : SendError
// Type : Private / Public / Protected
// Parameters : iErrorCode - ?
// pszError - ?
// pszDescription - ?
// Returns : void
// Description :
//
// References : -
// Remarks : -
// Created : 031124, 24 november 2003
// Developer : KN, Houdini
// Changed : 21 January 2006 by Vampik
/////////////////////////////////////////////////////////////////////
void CLHttpUser::SendError(int iErrorCode, const char * pszError, const char * pszDescription) {
char szCurTime[ 100 ];
time_t ltime;
time(<ime);
strftime(szCurTime, sizeof(szCurTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(<ime));
if (!pszDescription)
pszDescription = pszError;
char szBuf[1000];
DWORD dwBytesToWrite = mir_snprintf(szBuf,
"HTTP/1.1 %i %s\r\n"
"Date: %s\r\n"
"Server: MirandaWeb/%s\r\n"
"Transfer-Encoding: chunked\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n"
"\r\n"
"10f\r\n"
"\n"
"
\n"
"%i %s\n"
"\n"
"%s
\n"
"%s\n"
"
\n"
"MirandaWeb/%s\n"
"\n"
"\r\n"
"\r\n",
iErrorCode, pszError, szCurTime, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), iErrorCode, pszError, pszError, pszDescription, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM));
Netlib_Send(hConnection, szBuf, dwBytesToWrite, 0);
}
/////////////////////////////////////////////////////////////////////
// Member Function : SendRedir
// Type : Private / Public / Protected
// Parameters : iErrorCode - ?
// pszError - ?
// pszDescription - ?
// pszRedirect - ?
// Returns : void
// Description :
//
// References : -
// Remarks : -
// Created : 21 january 2006
// Developer : KN, Houdini, Vampik
/////////////////////////////////////////////////////////////////////
void CLHttpUser::SendRedir(int iErrorCode, const char * pszError, const char * pszDescription, const char * pszRedirect) {
char szCurrTime[ 100 ];
time_t ltime;
time(<ime);
strftime(szCurrTime, sizeof(szCurrTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(<ime));
if (!pszDescription)
pszDescription = pszError;
char szBuff[1000];
DWORD dwBytesToWrite = mir_snprintf(szBuff,
"HTTP/1.1 %i %s\r\n"
"Date: %s\r\n"
"Server: MirandaWeb/%s\r\n"
"Location: %s/\r\n"
"Transfer-Encoding: chunked\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n"
"\r\n"
"10f\r\n"
"\n"
"\n"
"%i %s\n"
"\n"
"%s
\n"
"%s\n"
"
\n"
"MirandaWeb/%s\n"
"\n"
"\r\n"
"\r\n",
iErrorCode, pszError, szCurrTime, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), pszRedirect, iErrorCode, pszError, pszError, pszDescription, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM));
Netlib_Send(hConnection, szBuff, dwBytesToWrite, 0);
}
/////////////////////////////////////////////////////////////////////
// Function : strmcat
// Type : Local
// Parameters : pszDest - ?
// pszSrc - ?
// MaxLength - ?
// Returns :
// Description : Fills pszDest until it is MaxLength long or
// pszSrc is finished - always appends a \0
// References : -
// Remarks : -
// Created :
// Developer : Houdini
/////////////////////////////////////////////////////////////////////
static void strmcat(char* pszDest, const char* pszSrc, int iMaxLength) {
int iLength = 0;
while (*pszDest != '\0') {
pszDest++;
iLength++;
}
while (iLength < iMaxLength - 1 && *pszSrc != '\0') {
*pszDest = *pszSrc;
pszDest++;
pszSrc++;
iLength++;
}
*pszDest = '\0';
}
/////////////////////////////////////////////////////////////////////
// Member Function : bProcessGetRequest
// Type : Global
// Parameters : hNewConnection - ?
// dwRemoteIP - ?
// pszRequest - ?
// Returns : Returns true if a file was send
// Description :
//
// References : -
// Remarks : -
// Created : 030813, 13 august 2003
// Developer : KN, Houdini
// Changed : 27 January 2005 by Vampik
// Changed : 21 January 2006 by Vampik
/////////////////////////////////////////////////////////////////////
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()) {
strncpy(szRealPath, pclCur->st.pszRealPath, MAX_PATH);
strncpy(szSrvPath, pclCur->st.pszSrvPath, MAX_PATH);
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[mir_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[mir_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);
mir_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);
mir_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;
}
}
mir_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] && mir_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, "\"%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, 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, 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;
}
void CLHttpUser::HandleNewConnection() {
/*
{
SOCKET s = CallService(MS_NETLIB_GETSOCKET, (WPARAM) hConnection, 0);
sockaddr_in MyAddr;
int nSize = sizeof( MyAddr );
getsockname( s, (sockaddr*)&MyAddr, &nSize );
ShowPopupWindow( "My IP address", inet_ntoa( MyAddr.sin_addr ) );
//OutputDebugString( );
}*/
/*
{
LINGER li;
int nLenght = sizeof( li );
int ret = getsockopt( s, IPPROTO_TCP, SO_LINGER, (char *)&li, &nLenght );
if( ret )
{
DWORD error = WSAGetLastError();
if( error
WSANOTINITIALISED
WSAENETDOWN The network subsystem has failed.
WSAEFAULT One of the optval or the optlen parameters is not a valid part of the user address space, or the optlen parameter is too small.
WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSAEINVAL The level parameter is unknown or invalid.
WSAENOPROTOOPT The option is unknown or unsupported by the indicated protocol family.
WSAENOTSOCK
}
nLenght = sizeof( li );
li.l_onoff = 1;
li.l_linger = 0;// time is default
ret = setsockopt( s, IPPROTO_TCP, SO_LINGER, (const char *)&li, nLenght );
if( ret )
{
// error
}
int nLenght = sizeof( li );
int ret = getsockopt( s, IPPROTO_TCP, SO_LINGER, (char *)&li, &nLenght );
}
*/
char szBuf[1000];
int nCurPos = 0;
while (sizeof(szBuf) - nCurPos > 10 && !bShutdownInProgress) {
int nBytesRead = Netlib_Recv(hConnection, &szBuf[nCurPos], sizeof(szBuf) - nCurPos, 0);
if (! nBytesRead) {
// socket closed gracefully
break;
}
if (nBytesRead == SOCKET_ERROR) {
// socket closed with error
// WSAGetLastError();
break;
}
int nOldCurPos = nCurPos;
nCurPos += nBytesRead;
if (nCurPos <= 5)
continue;
bool bIsGetCommand = memcmp(szBuf, "GET ", 4) == 0;
if (!bIsGetCommand && memcmp(szBuf, "HEAD ", 5) != 0) {
SendError(501, "Not Implemented");
break; // We only support GET and HEAD commands !!
}
if (nOldCurPos < 4)
nOldCurPos = 4; // scan forward from end of "GET " to locate the next space ' '
bool bBreakWhile = false;
for (; nOldCurPos < nCurPos; nOldCurPos++) {
if (szBuf[nOldCurPos-2] == '\n' && szBuf[nOldCurPos-1] == '\r' && szBuf[nOldCurPos] == '\n') {
// we have a walid request !!! scan to see if we have this file
szBuf[nOldCurPos] = NULL;
bProcessGetRequest(&szBuf[bIsGetCommand?4:5], bIsGetCommand);
bBreakWhile = true;
break;
}
}
if (bBreakWhile)
break;
}
}