yWeb 2.8.a.4

- updated nhttpd
- Code clean up
- changes to nhttpd.conf
- some changes for logo display

git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@416 e54a6e83-5905-42d5-8d5c-058d10e6a962
This commit is contained in:
yjogol
2010-02-25 20:00:09 +00:00
parent eabc0f1644
commit bad0521f6c
30 changed files with 1711 additions and 1905 deletions

View File

@@ -4,9 +4,9 @@
//=============================================================================
// c
#include <cstdio> // printf prototype.
#include <cstdlib> // calloc and free prototypes.
#include <cstring> // str* and memset prototypes.
#include <cstdio> // printf prototype.
#include <cstdlib> // calloc and free prototypes.
#include <cstring> // str* and memset prototypes.
#include <cstdarg>
// yhttpd
@@ -21,10 +21,11 @@
//-------------------------------------------------------------------------
// Check and set integer inside boundaries (min, max)
//-------------------------------------------------------------------------
int minmax(int value,int min, int max)
{
if(value < min) return min;
if(value > max) return max;
int minmax(int value, int min, int max) {
if (value < min)
return min;
if (value > max)
return max;
return value;
}
//=============================================================================
@@ -33,15 +34,14 @@ int minmax(int value,int min, int max)
//-------------------------------------------------------------------------
// Check and set Date/Time (tm*) inside boundaries
//-------------------------------------------------------------------------
void correctTime(struct tm *zt)
{
void correctTime(struct tm *zt) {
zt->tm_year = minmax(zt->tm_year,0,129);
zt->tm_mon = minmax(zt->tm_mon,0,11);
zt->tm_mday = minmax(zt->tm_mday,1,31); //-> eine etwas laxe pruefung, aber mktime biegt das wieder grade
zt->tm_hour = minmax(zt->tm_hour,0,23);
zt->tm_min = minmax(zt->tm_min,0,59);
zt->tm_sec = minmax(zt->tm_sec,0,59);
zt->tm_year = minmax(zt->tm_year, 0, 129);
zt->tm_mon = minmax(zt->tm_mon, 0, 11);
zt->tm_mday = minmax(zt->tm_mday, 1, 31); //-> eine etwas laxe pruefung, aber mktime biegt das wieder grade
zt->tm_hour = minmax(zt->tm_hour, 0, 23);
zt->tm_min = minmax(zt->tm_min, 0, 59);
zt->tm_sec = minmax(zt->tm_sec, 0, 59);
}
//=============================================================================
// Strings
@@ -49,23 +49,20 @@ void correctTime(struct tm *zt)
//-------------------------------------------------------------------------
// Integer to Hexadecimal-String
//-------------------------------------------------------------------------
std::string itoh(unsigned int conv)
{
return string_printf("0x%06x",conv);
std::string itoh(unsigned int conv) {
return string_printf("0x%06x", conv);
}
//-------------------------------------------------------------------------
// Integer to String
//-------------------------------------------------------------------------
std::string itoa(unsigned int conv)
{
return string_printf("%u",conv);
std::string itoa(unsigned int conv) {
return string_printf("%u", conv);
}
//-------------------------------------------------------------------------
// convert timer_t to "<hour>:<minutes>" String
//-------------------------------------------------------------------------
std::string timeString(time_t time)
{
char tmp[7]={'\0'};
std::string timeString(time_t time) {
char tmp[7] = { '\0' };
struct tm *tm = localtime(&time);
if (strftime(tmp, 6, "%H:%M", tm))
return std::string(tmp);
@@ -77,13 +74,11 @@ std::string timeString(time_t time)
// max length up to bufferlen -> then snip
//-------------------------------------------------------------------------
#define bufferlen 4*1024
std::string string_printf(const char *fmt, ...)
{
std::string string_printf(const char *fmt, ...) {
char buffer[bufferlen];
va_list arglist;
va_start( arglist, fmt );
if(arglist)
vsnprintf( buffer, bufferlen, fmt, arglist );
va_start(arglist, fmt);
vsnprintf(buffer, bufferlen, fmt, arglist);
va_end(arglist);
return std::string(buffer);
}
@@ -91,16 +86,13 @@ std::string string_printf(const char *fmt, ...)
// ySplitString: spit string "str" in two strings "left" and "right" at
// one of the chars in "delimiter" returns true if delimiter found
//-------------------------------------------------------------------------
bool ySplitString(std::string str, std::string delimiter, std::string& left, std::string& right)
{
bool ySplitString(std::string str, std::string delimiter, std::string& left,
std::string& right) {
std::string::size_type pos;
if ((pos = str.find_first_of(delimiter)) != std::string::npos)
{
if ((pos = str.find_first_of(delimiter)) != std::string::npos) {
left = str.substr(0, pos);
right = str.substr(pos + 1, str.length() - (pos + 1 ));
}
else
{
right = str.substr(pos + 1, str.length() - (pos + 1));
} else {
left = str; //default if not found
right = "";
}
@@ -110,16 +102,14 @@ bool ySplitString(std::string str, std::string delimiter, std::string& left, std
// ySplitString: spit string "str" in two strings "left" and "right" at
// one of the chars in "delimiter" returns true if delimiter found
//-------------------------------------------------------------------------
bool ySplitStringExact(std::string str, std::string delimiter, std::string& left, std::string& right)
{
bool ySplitStringExact(std::string str, std::string delimiter,
std::string& left, std::string& right) {
std::string::size_type pos;
if ((pos = str.find(delimiter)) != std::string::npos)
{
if ((pos = str.find(delimiter)) != std::string::npos) {
left = str.substr(0, pos);
right = str.substr(pos + delimiter.length(), str.length() - (pos + delimiter.length() ));
}
else
{
right = str.substr(pos + delimiter.length(), str.length() - (pos
+ delimiter.length()));
} else {
left = str; //default if not found
right = "";
}
@@ -129,16 +119,13 @@ bool ySplitStringExact(std::string str, std::string delimiter, std::string& left
// ySplitStringRight: spit string "str" in two strings "left" and "right" at
// one of the chars in "delimiter" returns true if delimiter found
//-------------------------------------------------------------------------
bool ySplitStringLast(std::string str, std::string delimiter, std::string& left, std::string& right)
{
bool ySplitStringLast(std::string str, std::string delimiter,
std::string& left, std::string& right) {
std::string::size_type pos;
if ((pos = str.find_last_of(delimiter)) != std::string::npos)
{
if ((pos = str.find_last_of(delimiter)) != std::string::npos) {
left = str.substr(0, pos);
right = str.substr(pos + 1, str.length() - (pos + 1 ));
}
else
{
right = str.substr(pos + 1, str.length() - (pos + 1));
} else {
left = str; //default if not found
right = "";
}
@@ -147,33 +134,29 @@ bool ySplitStringLast(std::string str, std::string delimiter, std::string& left,
//-------------------------------------------------------------------------
// ySplitStringVector: spit string "str" and build vector of strings
//-------------------------------------------------------------------------
CStringArray ySplitStringVector(std::string str, std::string delimiter)
{
CStringArray ySplitStringVector(std::string str, std::string delimiter) {
std::string left, right, rest;
bool found;
CStringArray split;
rest = str;
do
{
do {
found = ySplitString(rest, delimiter, left, right);
split.push_back(left);
rest = right;
}
while(found);
} while (found);
return split;
}
//-------------------------------------------------------------------------
// trim whitespaces
//-------------------------------------------------------------------------
std::string trim(std::string const& source, char const* delims)
{
std::string trim(std::string const& source, char const* delims) {
std::string result(source);
std::string::size_type index = result.find_last_not_of(delims);
if(index != std::string::npos)
if (index != std::string::npos)
result.erase(++index);
index = result.find_first_not_of(delims);
if(index != std::string::npos)
if (index != std::string::npos)
result.erase(0, index);
else
result.erase();
@@ -182,53 +165,45 @@ std::string trim(std::string const& source, char const* delims)
//-------------------------------------------------------------------------
// replace all occurrences find_what
//-------------------------------------------------------------------------
void replace(std::string &str, const std::string &find_what, const std::string &replace_with)
{
std::string::size_type pos=0;
while((pos=str.find(find_what, pos))!=std::string::npos)
{
void replace(std::string &str, const std::string &find_what,
const std::string &replace_with) {
std::string::size_type pos = 0;
while ((pos = str.find(find_what, pos)) != std::string::npos) {
str.erase(pos, find_what.length());
str.insert(pos, replace_with);
pos+=replace_with.length();
pos += replace_with.length();
}
}
//-------------------------------------------------------------------------
// equal-function for case insensitive compare
//-------------------------------------------------------------------------
bool nocase_compare (char c1, char c2)
{
bool nocase_compare(char c1, char c2) {
return toupper(c1) == toupper(c2);
}
//-----------------------------------------------------------------------------
// Decode URLEncoded std::string
//-----------------------------------------------------------------------------
std::string decodeString(std::string encodedString)
{
std::string decodeString(std::string encodedString) {
const char *string = encodedString.c_str();
unsigned int count=0;
char hex[3]={'\0'};
unsigned int count = 0;
char hex[3] = { '\0' };
unsigned long iStr;
std::string result = "";
count = 0;
while(count<encodedString.length()) /* use the null character as a loop terminator */
while (count < encodedString.length()) /* use the null character as a loop terminator */
{
if(string[count] == '%' && count+2 <encodedString.length())
{
hex[0]=string[count+1];
hex[1]=string[count+2];
hex[2]='\0';
iStr = strtoul(hex,NULL,16); /* convert to Hex char */
result += (char)iStr;
if (string[count] == '%' && count + 2 < encodedString.length()) {
hex[0] = string[count + 1];
hex[1] = string[count + 2];
hex[2] = '\0';
iStr = strtoul(hex, NULL, 16); /* convert to Hex char */
result += (char) iStr;
count += 3;
}
else if(string[count] == '+')
{
} else if (string[count] == '+') {
result += ' ';
count++;
}
else
{
} else {
result += string[count];
count++;
}
@@ -238,29 +213,27 @@ std::string decodeString(std::string encodedString)
//-----------------------------------------------------------------------------
// Encode URLEncoded std::string
//-----------------------------------------------------------------------------
std::string encodeString(std::string decodedString)
{
unsigned int len = sizeof(char) * decodedString.length()*5 + 1;
std::string result( len, '\0' );
char *newString = (char *)result.c_str();
char *dstring = (char *)decodedString.c_str();
std::string encodeString(std::string decodedString) {
unsigned int len = sizeof(char) * decodedString.length() * 5 + 1;
std::string result(len, '\0');
char *newString = (char *) result.c_str();
char *dstring = (char *) decodedString.c_str();
char one_char;
if(len == result.length()) // got memory needed
if (len == result.length()) // got memory needed
{
while((one_char = *dstring++)) /* use the null character as a loop terminator */
while ((one_char = *dstring++)) /* use the null character as a loop terminator */
{
if(isalnum(one_char))
if (isalnum(one_char))
*newString++ = one_char;
else
newString += sprintf(newString, "&#%d;", (unsigned char) one_char);
newString += sprintf(newString, "&#%d;",
(unsigned char) one_char);
}
*newString='\0'; /* when done copying the string,need to terminate w/ null char */
result.resize((unsigned int)(newString - result.c_str()), '\0');
*newString = '\0'; /* when done copying the string,need to terminate w/ null char */
result.resize((unsigned int) (newString - result.c_str()), '\0');
return result;
}
else
{
} else {
return "";
}
}
@@ -268,9 +241,8 @@ std::string encodeString(std::string decodedString)
//-----------------------------------------------------------------------------
// returns string in lower case
//-----------------------------------------------------------------------------
std::string string_tolower(std::string str)
{
for(unsigned int i = 0; i < str.length(); i++)
std::string string_tolower(std::string str) {
for (unsigned int i = 0; i < str.length(); i++)
str[i] = tolower(str[i]);
return str;
}
@@ -278,16 +250,14 @@ std::string string_tolower(std::string str)
//-----------------------------------------------------------------------------
// write string to a file
//-----------------------------------------------------------------------------
bool write_to_file(std::string filename, std::string content)
{
bool write_to_file(std::string filename, std::string content) {
FILE *fd = NULL;
if((fd = fopen(filename.c_str(),"w")) != NULL) // open file
if ((fd = fopen(filename.c_str(), "w")) != NULL) // open file
{
fwrite(content.c_str(), content.length(), 1, fd);
fflush(fd); // flush and close file
fflush(fd); // flush and close file
fclose(fd);
return true;
}
else
} else
return false;
}

View File

@@ -21,46 +21,43 @@ long CWebserverConnection::GConnectionNumber = 0;
//=============================================================================
// Constructor & Destructor & Initialization
//=============================================================================
CWebserverConnection::CWebserverConnection(CWebserver *pWebserver)
{
Webserver = pWebserver;
Request.Webserver = pWebserver;
Request.Connection = this;
Response.Webserver = pWebserver;
Response.Connection = this;
Method = M_UNKNOWN;
HttpStatus = 0;
RequestCanceled = false;
CWebserverConnection::CWebserverConnection(CWebserver *pWebserver) {
Webserver = pWebserver;
Request.Webserver = pWebserver;
Request.Connection = this;
Response.Webserver = pWebserver;
Response.Connection = this;
Method = M_UNKNOWN;
HttpStatus = 0;
RequestCanceled = false;
#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE
keep_alive = true;
keep_alive = true;
#else
keep_alive = false;
keep_alive = false;
#endif
}
//-------------------------------------------------------------------------
CWebserverConnection::CWebserverConnection()
{
// aprintf("test CWebserverConnection::CWebserverConnection()\n");
CWebserverConnection::CWebserverConnection() {
// aprintf("test CWebserverConnection::CWebserverConnection()\n");
ConnectionNumber = ++GConnectionNumber;
}
//-------------------------------------------------------------------------
CWebserverConnection::~CWebserverConnection(void)
{
CWebserverConnection::~CWebserverConnection(void) {
}
//-------------------------------------------------------------------------
// End The Connection. Request and Response allready handled.
// do "after done" work, like create a www-Log entry.
// Use "Hooks_EndConnection()" Handler to write own Hooks.
//-------------------------------------------------------------------------
void CWebserverConnection::EndConnection()
{
HookHandler.HookVarList["enlapsed_request"] = itoa(enlapsed_request/1000);
HookHandler.HookVarList["enlapsed_response"] = itoa(enlapsed_response/1000);
HookHandler.Hooks_EndConnection(); // Handle Hooks
if(RequestCanceled) // Canceled
void CWebserverConnection::EndConnection() {
HookHandler.HookVarList["enlapsed_request"] = itoa(enlapsed_request / 1000);
HookHandler.HookVarList["enlapsed_response"] = itoa(enlapsed_response
/ 1000);
HookHandler.Hooks_EndConnection(); // Handle Hooks
if (RequestCanceled) // Canceled
keep_alive = false;
RequestCanceled = true;
// sock->Flush();
// sock->Flush();
#ifndef Y_CONFIG_FEATURE_KEEP_ALIVE
sock->close();
#endif
@@ -69,24 +66,25 @@ void CWebserverConnection::EndConnection()
// Main
// Handle the Request, Handle (Send) Response), End the Connection
//-------------------------------------------------------------------------
void CWebserverConnection::HandleConnection()
{
void CWebserverConnection::HandleConnection() {
gettimeofday(&tv_connection_start, &tz_connection_start);
// get the request
if (Request.HandleRequest())
{
if (Request.HandleRequest()) {
// determine time from Connection creation until now
gettimeofday(&tv_connection_Response_start, &tz_connection_Response_start);
enlapsed_request = ((tv_connection_Response_start.tv_sec - tv_connection_start.tv_sec) * 1000000
+ (tv_connection_Response_start.tv_usec - tv_connection_start.tv_usec));
gettimeofday(&tv_connection_Response_start,
&tz_connection_Response_start);
enlapsed_request = ((tv_connection_Response_start.tv_sec
- tv_connection_start.tv_sec) * 1000000
+ (tv_connection_Response_start.tv_usec
- tv_connection_start.tv_usec));
// Keep-Alive checking
#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE
if(string_tolower(Request.HeaderList["Connection"]) == "close"
|| (httprotocol != "HTTP/1.1" && string_tolower(Request.HeaderList["Connection"]) != "keep-alive")
|| !Webserver->CheckKeepAliveAllowedByIP(sock->get_client_ip()))
keep_alive = false;
if(string_tolower(Request.HeaderList["Connection"]) == "close"
|| (httprotocol != "HTTP/1.1" && string_tolower(Request.HeaderList["Connection"]) != "keep-alive")
|| !Webserver->CheckKeepAliveAllowedByIP(sock->get_client_ip()))
keep_alive = false;
#else
keep_alive = false;
#endif
@@ -95,40 +93,39 @@ void CWebserverConnection::HandleConnection()
// determine time for SendResponse
gettimeofday(&tv_connection_Response_end, &tz_connection_Response_end);
enlapsed_response = ((tv_connection_Response_end.tv_sec - tv_connection_Response_start.tv_sec) * 1000000
+ (tv_connection_Response_end.tv_usec - tv_connection_Response_start.tv_usec));
enlapsed_response = ((tv_connection_Response_end.tv_sec
- tv_connection_Response_start.tv_sec) * 1000000
+ (tv_connection_Response_end.tv_usec
- tv_connection_Response_start.tv_usec));
// print production times
log_level_printf(1,"enlapsed time request:%ld response:%ld url:%s\n",
enlapsed_request, enlapsed_response, (Request.UrlData["fullurl"]).c_str());
log_level_printf(1, "enlapsed time request:%ld response:%ld url:%s\n",
enlapsed_request, enlapsed_response,
(Request.UrlData["fullurl"]).c_str());
}
else
{
} else {
RequestCanceled = true;
keep_alive = false; // close this connection socket
// dperror("Error while parsing request\n");
log_level_printf(1,"request canceled: %s\n", strerror(errno));
keep_alive = false; // close this connection socket
// dperror("Error while parsing request\n");
log_level_printf(1, "request canceled: %s\n", strerror(errno));
}
EndConnection();
}
//-------------------------------------------------------------------------
void CWebserverConnection::ShowEnlapsedRequest(char *text)
{
void CWebserverConnection::ShowEnlapsedRequest(char *text) {
long enlapsed = GetEnlapsedRequestTime() / 1000;
log_level_printf(1,"enlapsed-f-start (%s) t:%ld url:%s\n",
text, enlapsed, (Request.UrlData["fullurl"]).c_str());
long enlapsed = GetEnlapsedRequestTime() / 1000;
log_level_printf(1, "enlapsed-f-start (%s) t:%ld url:%s\n", text, enlapsed,
(Request.UrlData["fullurl"]).c_str());
}
//-------------------------------------------------------------------------
// Time from creation of socket until now in microseconds!
//-------------------------------------------------------------------------
long CWebserverConnection::GetEnlapsedRequestTime()
{
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
long CWebserverConnection::GetEnlapsedRequestTime() {
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
return ((tv_now.tv_sec - tv_connection_start.tv_sec) * 1000000
+ (tv_now.tv_usec - tv_connection_start.tv_usec));
}
@@ -136,11 +133,10 @@ long CWebserverConnection::GetEnlapsedRequestTime()
//-------------------------------------------------------------------------
// Time from beginning of response until now in microseconds!
//-------------------------------------------------------------------------
long CWebserverConnection::GetEnlapsedResponseTime()
{
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
long CWebserverConnection::GetEnlapsedResponseTime() {
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
return ((tv_now.tv_sec - tv_connection_Response_start.tv_sec) * 1000000
+ (tv_now.tv_usec - tv_connection_Response_start.tv_usec));
}

View File

@@ -25,22 +25,22 @@ THookList CyhookHandler::HookList;
// Hook Dispatcher for Session Hooks
// Execute every Hook in HookList until State change != HANDLED_NONE
//-----------------------------------------------------------------------------
THandleStatus CyhookHandler::Hooks_SendResponse()
{
log_level_printf(4,"Response Hook-List Start\n");
THandleStatus CyhookHandler::Hooks_SendResponse() {
log_level_printf(4, "Response Hook-List Start\n");
THandleStatus _status = HANDLED_NONE;
THookList::iterator i = HookList.begin();
for ( ; i!= HookList.end(); i++ )
{
log_level_printf(4,"Response Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
for (; i != HookList.end(); i++) {
log_level_printf(4, "Response Hook-List (%s) Start\n",
((*i)->getHookName()).c_str());
// response Hook
_status = (*i)->Hook_SendResponse(this);
log_level_printf(4,"Response Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), status);
if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
log_level_printf(4, "Response Hook-List (%s) End. Status (%d)\n",
((*i)->getHookName()).c_str(), status);
if ((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
break;
}
log_level_printf(4,"Response Hook-List End\n");
log_level_printf(8,"Response Hook-List Result:\n%s\n", yresult.c_str());
log_level_printf(4, "Response Hook-List End\n");
log_level_printf(8, "Response Hook-List Result:\n%s\n", yresult.c_str());
status = _status;
return _status;
}
@@ -48,22 +48,25 @@ THandleStatus CyhookHandler::Hooks_SendResponse()
// Hook Dispatcher for Session Hooks
// Execute every Hook in HookList until State change != HANDLED_NONE
//-----------------------------------------------------------------------------
THandleStatus CyhookHandler::Hooks_PrepareResponse()
{
log_level_printf(4,"PrepareResponse Hook-List Start\n");
THandleStatus CyhookHandler::Hooks_PrepareResponse() {
log_level_printf(4, "PrepareResponse Hook-List Start\n");
THandleStatus _status = HANDLED_NONE;
THookList::iterator i = HookList.begin();
for ( ; i!= HookList.end(); i++ )
{
log_level_printf(4,"PrepareResponse Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
for (; i != HookList.end(); i++) {
log_level_printf(4, "PrepareResponse Hook-List (%s) Start\n",
((*i)->getHookName()).c_str());
// response Hook
_status = (*i)->Hook_PrepareResponse(this);
log_level_printf(4,"PrepareResponse Hook-List (%s) End. Status (%d) HTTP Status (%d)\n", ((*i)->getHookName()).c_str(), status, httpStatus);
if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
log_level_printf(
4,
"PrepareResponse Hook-List (%s) End. Status (%d) HTTP Status (%d)\n",
((*i)->getHookName()).c_str(), status, httpStatus);
if ((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
break;
}
log_level_printf(4,"PrepareResponse Hook-List End\n");
log_level_printf(8,"PrepareResponse Hook-List Result:\n%s\n", yresult.c_str());
log_level_printf(4, "PrepareResponse Hook-List End\n");
log_level_printf(8, "PrepareResponse Hook-List Result:\n%s\n",
yresult.c_str());
status = _status;
return _status;
}
@@ -73,83 +76,86 @@ THandleStatus CyhookHandler::Hooks_PrepareResponse()
// Execute every Hook in HookList until State change != HANDLED_NONE and
// != HANDLED_CONTINUE
//-----------------------------------------------------------------------------
THandleStatus CyhookHandler::Hooks_ReadConfig(CConfigFile *Config, CStringList &ConfigList)
{
log_level_printf(4,"ReadConfig Hook-List Start\n");
THandleStatus CyhookHandler::Hooks_ReadConfig(CConfigFile *Config,
CStringList &ConfigList) {
log_level_printf(4, "ReadConfig Hook-List Start\n");
THandleStatus _status = HANDLED_NONE;
THookList::iterator i = HookList.begin();
for ( ; i!= HookList.end(); i++ )
{
// log_level_printf(4,"ReadConfig Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
for (; i != HookList.end(); i++) {
// log_level_printf(4,"ReadConfig Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
// response Hook
_status = (*i)->Hook_ReadConfig(Config, ConfigList);
log_level_printf(4,"ReadConfig Hook-List (%s) Status (%d)\n", ((*i)->getHookName()).c_str(), _status);
if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
log_level_printf(4, "ReadConfig Hook-List (%s) Status (%d)\n",
((*i)->getHookName()).c_str(), _status);
if ((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
break;
}
log_level_printf(4,"ReadConfig Hook-List End\n");
log_level_printf(4, "ReadConfig Hook-List End\n");
return _status;
}
//-----------------------------------------------------------------------------
// Hook Dispatcher for EndConnection
//-----------------------------------------------------------------------------
THandleStatus CyhookHandler::Hooks_EndConnection()
{
log_level_printf(4,"EndConnection Hook-List Start\n");
THandleStatus CyhookHandler::Hooks_EndConnection() {
log_level_printf(4, "EndConnection Hook-List Start\n");
THandleStatus _status = HANDLED_NONE;
THookList::iterator i = HookList.begin();
for ( ; i!= HookList.end(); i++ )
{
log_level_printf(4,"EndConnection Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
for (; i != HookList.end(); i++) {
log_level_printf(4, "EndConnection Hook-List (%s) Start\n",
((*i)->getHookName()).c_str());
// response Hook
_status = (*i)->Hook_EndConnection(this);
log_level_printf(4,"EndConnection Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), _status);
if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
log_level_printf(4, "EndConnection Hook-List (%s) End. Status (%d)\n",
((*i)->getHookName()).c_str(), _status);
if ((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
break;
}
log_level_printf(4,"EndConnection Hook-List End\n");
log_level_printf(4, "EndConnection Hook-List End\n");
status = _status;
return _status;
}
//-----------------------------------------------------------------------------
// Hook Dispatcher for UploadSetFilename
//-----------------------------------------------------------------------------
THandleStatus CyhookHandler::Hooks_UploadSetFilename(std::string &Filename)
{
log_level_printf(4,"UploadSetFilename Hook-List Start. Filename:(%s)\n", Filename.c_str());
THandleStatus CyhookHandler::Hooks_UploadSetFilename(std::string &Filename) {
log_level_printf(4, "UploadSetFilename Hook-List Start. Filename:(%s)\n",
Filename.c_str());
THandleStatus _status = HANDLED_NONE;
THookList::iterator i = HookList.begin();
for ( ; i!= HookList.end(); i++ )
{
log_level_printf(4,"UploadSetFilename Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
for (; i != HookList.end(); i++) {
log_level_printf(4, "UploadSetFilename Hook-List (%s) Start\n",
((*i)->getHookName()).c_str());
// response Hook
_status = (*i)->Hook_UploadSetFilename(this, Filename);
log_level_printf(4,"UploadSetFilename Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), _status);
if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
log_level_printf(4,
"UploadSetFilename Hook-List (%s) End. Status (%d)\n",
((*i)->getHookName()).c_str(), _status);
if ((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
break;
}
log_level_printf(4,"UploadSetFilename Hook-List End\n");
log_level_printf(4, "UploadSetFilename Hook-List End\n");
status = _status;
return _status;
}
//-----------------------------------------------------------------------------
// Hook Dispatcher for UploadSetFilename
//-----------------------------------------------------------------------------
THandleStatus CyhookHandler::Hooks_UploadReady(const std::string& Filename)
{
log_level_printf(4,"UploadReady Hook-List Start. Filename:(%s)\n", Filename.c_str());
THandleStatus CyhookHandler::Hooks_UploadReady(const std::string& Filename) {
log_level_printf(4, "UploadReady Hook-List Start. Filename:(%s)\n",
Filename.c_str());
THandleStatus _status = HANDLED_NONE;
THookList::iterator i = HookList.begin();
for ( ; i!= HookList.end(); i++ )
{
log_level_printf(4,"UploadReady Hook-List (%s) Start\n", ((*i)->getHookName()).c_str());
for (; i != HookList.end(); i++) {
log_level_printf(4, "UploadReady Hook-List (%s) Start\n",
((*i)->getHookName()).c_str());
// response Hook
_status = (*i)->Hook_UploadReady(this, Filename);
log_level_printf(4,"UploadReady Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), _status);
if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
log_level_printf(4, "UploadReady Hook-List (%s) End. Status (%d)\n",
((*i)->getHookName()).c_str(), _status);
if ((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE))
break;
}
log_level_printf(4,"UploadReady Hook-List End\n");
log_level_printf(4, "UploadReady Hook-List End\n");
status = _status;
return _status;
}
@@ -157,19 +163,19 @@ THandleStatus CyhookHandler::Hooks_UploadReady(const std::string& Filename)
//=============================================================================
// Output helpers
//=============================================================================
void CyhookHandler::session_init(CStringList _ParamList, CStringList _UrlData, CStringList _HeaderList,
CStringList& _ConfigList, THttp_Method _Method, bool _keep_alive)
{
ParamList = _ParamList;
UrlData = _UrlData;
HeaderList = _HeaderList;
WebserverConfigList = _ConfigList;
Method = _Method;
status = HANDLED_NONE;
httpStatus = HTTP_OK;
ContentLength = 0;
LastModified = (time_t)-1;
keep_alive = _keep_alive;
void CyhookHandler::session_init(CStringList _ParamList, CStringList _UrlData,
CStringList _HeaderList, CStringList& _ConfigList,
THttp_Method _Method, bool _keep_alive) {
ParamList = _ParamList;
UrlData = _UrlData;
HeaderList = _HeaderList;
WebserverConfigList = _ConfigList;
Method = _Method;
status = HANDLED_NONE;
httpStatus = HTTP_OK;
ContentLength = 0;
LastModified = (time_t) - 1;
keep_alive = _keep_alive;
HookVarList.clear();
}
@@ -202,113 +208,111 @@ void CyhookHandler::session_init(CStringList _ParamList, CStringList _UrlData, C
// | Via ; not implemented
// | Warning ; not implemented
//
// response-header = Accept-Ranges ; not implemented
// | Age ; not implemented
// | ETag ; not implemented
// | Location ; implemented (redirection / Object moved)
// | Proxy-Authenticate ; not implemented
// | Retry-After ; not implemented
// | Server ; implemented
// | Vary ; not implemented
// | WWW-Authenticate ; implemented (by mod_auth and SendHeader)
// response-header = Accept-Ranges ; not implemented
// | Age ; not implemented
// | ETag ; not implemented
// | Location ; implemented (redirection / Object moved)
// | Proxy-Authenticate ; not implemented
// | Retry-After ; not implemented
// | Server ; implemented
// | Vary ; not implemented
// | WWW-Authenticate ; implemented (by mod_auth and SendHeader)
//
// entity-header = Allow ; not implemented
// | Content-Encoding ; not implemented
// | Content-Language ; not implemented
// | Content-Length ; implemented
// | Content-Location ; not implemented
// | Content-MD5 ; not implemented
// | Content-Range ; not implemented
// | Content-Type ; implemented
// | Expires ; not implemented
// | Last-Modified ; implemented for static files
// | extension-header
// entity-header = Allow ; not implemented
// | Content-Encoding ; not implemented
// | Content-Language ; not implemented
// | Content-Length ; implemented
// | Content-Location ; not implemented
// | Content-MD5 ; not implemented
// | Content-Range ; not implemented
// | Content-Type ; implemented
// | Expires ; not implemented
// | Last-Modified ; implemented for static files
// | extension-header
//
// extension-header = message-header
// extension-header = message-header
//=============================================================================
std::string CyhookHandler::BuildHeader(bool cache)
{
std::string result="";
std::string CyhookHandler::BuildHeader(bool cache) {
std::string result = "";
const char *responseString = "";
const char *infoString = 0;
// get Info Index
for (unsigned int i = 0;i < (sizeof(httpResponseNames)/sizeof(httpResponseNames[0])); i++)
if (httpResponseNames[i].type == httpStatus)
{
for (unsigned int i = 0; i < (sizeof(httpResponseNames)
/ sizeof(httpResponseNames[0])); i++)
if (httpResponseNames[i].type == httpStatus) {
responseString = httpResponseNames[i].name;
infoString = httpResponseNames[i].info;
break;
}
// print Status-line
result = string_printf(HTTP_PROTOCOL " %d %s\r\nContent-Type: %s\r\n",httpStatus, responseString, ResponseMimeType.c_str());
log_level_printf(2,"Respose: HTTP/1.1 %d %s\r\nContent-Type: %s\r\n",httpStatus, responseString, ResponseMimeType.c_str());
log_level_printf(2, "Respose: HTTP/1.1 %d %s\r\nContent-Type: %s\r\n",
httpStatus, responseString, ResponseMimeType.c_str());
switch (httpStatus)
{
case HTTP_UNAUTHORIZED:
result += "WWW-Authenticate: Basic realm=\"";
result += AUTH_NAME_MSG "\r\n";
break;
switch (httpStatus) {
case HTTP_UNAUTHORIZED:
result += "WWW-Authenticate: Basic realm=\"";
result += AUTH_NAME_MSG "\r\n";
break;
case HTTP_MOVED_TEMPORARILY:
case HTTP_MOVED_PERMANENTLY:
// Status HTTP_*_TEMPORARILY (redirection)
result += string_printf("Location: %s\r\n",NewURL.c_str());
// NO break HERE !!!
case HTTP_MOVED_TEMPORARILY:
case HTTP_MOVED_PERMANENTLY:
// Status HTTP_*_TEMPORARILY (redirection)
result += string_printf("Location: %s\r\n", NewURL.c_str());
// NO break HERE !!!
default:
time_t timer = time(0);
char timeStr[80];
// cache
if(!cache && (HookVarList["CacheCategory"]).empty() )
result += "Cache-Control: no-cache\r\n";
else
{
time_t x_time = time(NULL);
struct tm *ptm = gmtime(&x_time);
ptm->tm_mday+=1;
x_time = mktime(ptm);
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&x_time));
result += string_printf("Expires: %s\r\n", timeStr);
}
result += "Server: " WEBSERVERNAME "\r\n";
// actual date
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer));
result += string_printf("Date: %s\r\n", timeStr);
// connection type
default:
time_t timer = time(0);
char timeStr[80];
// cache
if (!cache && (HookVarList["CacheCategory"]).empty())
result += "Cache-Control: no-cache\r\n";
else {
time_t x_time = time(NULL);
struct tm *ptm = gmtime(&x_time);
ptm->tm_mday += 1;
x_time = mktime(ptm);
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&x_time));
result += string_printf("Expires: %s\r\n", timeStr);
}
result += "Server: " WEBSERVERNAME "\r\n";
// actual date
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer));
result += string_printf("Date: %s\r\n", timeStr);
// connection type
#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE
if(keep_alive)
result += "Connection: keep-alive\r\n";
else
result += "Connection: close\r\n";
if(keep_alive)
result += "Connection: keep-alive\r\n";
else
result += "Connection: close\r\n";
#else
result += "Connection: close\r\n";
result += "Connection: close\r\n";
#endif
// gzipped ?
if(UrlData["fileext"] == "gz")
result += "Content-Encoding: gzip\r\n";
// content-len, last-modified
if(httpStatus == HTTP_NOT_MODIFIED ||httpStatus == HTTP_NOT_FOUND)
result += "Content-Length: 0\r\n";
else if(GetContentLength() >0)
{
time_t mod_time = time(NULL);
if(LastModified != (time_t)-1)
mod_time = LastModified;
// gzipped ?
if (UrlData["fileext"] == "gz")
result += "Content-Encoding: gzip\r\n";
// content-len, last-modified
if (httpStatus == HTTP_NOT_MODIFIED || httpStatus == HTTP_NOT_FOUND)
result += "Content-Length: 0\r\n";
else if (GetContentLength() > 0) {
time_t mod_time = time(NULL);
if (LastModified != (time_t) - 1)
mod_time = LastModified;
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&mod_time));
result += string_printf("Last-Modified: %s\r\nContent-Length: %ld\r\n", timeStr, GetContentLength());
}
result += "\r\n"; // End of Header
break;
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&mod_time));
result += string_printf(
"Last-Modified: %s\r\nContent-Length: %ld\r\n", timeStr,
GetContentLength());
}
result += "\r\n"; // End of Header
break;
}
// Body
if (Method != M_HEAD)
switch (httpStatus)
{
switch (httpStatus) {
case HTTP_OK:
case HTTP_NOT_MODIFIED:
case HTTP_CONTINUE:
@@ -321,13 +325,16 @@ std::string CyhookHandler::BuildHeader(bool cache)
case HTTP_MOVED_TEMPORARILY:
case HTTP_MOVED_PERMANENTLY:
result += "<html><head><title>Object moved</title></head><body>";
result += string_printf("302 : Object moved.<br/>If you dont get redirected click <a href=\"%s\">here</a></body></html>\n",NewURL.c_str());
result
+= string_printf(
"302 : Object moved.<br/>If you dont get redirected click <a href=\"%s\">here</a></body></html>\n",
NewURL.c_str());
break;
default:
// Error pages
break;
}
}
return result;
}
@@ -335,27 +342,24 @@ std::string CyhookHandler::BuildHeader(bool cache)
// Output helpers
//=============================================================================
//-----------------------------------------------------------------------------
void CyhookHandler::SendHTMLHeader(const std::string& Titel)
{
void CyhookHandler::SendHTMLHeader(const std::string& Titel) {
WriteLn("<html>\n<head><title>" + Titel + "</title>\n");
WriteLn("<meta http-equiv=\"cache-control\" content=\"no-cache\" />");
WriteLn("<meta http-equiv=\"expires\" content=\"0\" />\n</head>\n<body>\n");
}
//-----------------------------------------------------------------------------
void CyhookHandler::SendHTMLFooter(void)
{
void CyhookHandler::SendHTMLFooter(void) {
WriteLn("</body>\n</html>\n\n");
}
//-----------------------------------------------------------------------------
#define OUTBUFSIZE 4096
void CyhookHandler::printf ( const char *fmt, ... )
{
void CyhookHandler::printf(const char *fmt, ...) {
char outbuf[OUTBUFSIZE];
bzero(outbuf,OUTBUFSIZE);
bzero(outbuf, OUTBUFSIZE);
va_list arglist;
va_start( arglist, fmt );
vsnprintf( outbuf,OUTBUFSIZE, fmt, arglist );
va_start(arglist, fmt);
vsnprintf(outbuf, OUTBUFSIZE, fmt, arglist);
va_end(arglist);
Write(outbuf);
}

View File

@@ -83,10 +83,10 @@ std::string CLanguage::getTranslation(std::string id){
std::string CLanguage::getLanguageDir(void){
std::string tmpfilename = "/"+Cyhttpd::ConfigList["Language.directory"],dir="";
if( access(std::string(Cyhttpd::ConfigList["PublicDocumentRoot"] + tmpfilename).c_str(),4) == 0)
dir = Cyhttpd::ConfigList["PublicDocumentRoot"] + tmpfilename;
else if(access(std::string(Cyhttpd::ConfigList["PrivatDocumentRoot"] + tmpfilename).c_str(),4) == 0)
dir = Cyhttpd::ConfigList["PrivatDocumentRoot"] + tmpfilename;
if( access(std::string(Cyhttpd::ConfigList["WebsiteMain.override_directory"] + tmpfilename).c_str(),4) == 0)
dir = Cyhttpd::ConfigList["WebsiteMain.override_directory"] + tmpfilename;
else if(access(std::string(Cyhttpd::ConfigList["WebsiteMain.directory"] + tmpfilename).c_str(),4) == 0)
dir = Cyhttpd::ConfigList["WebsiteMain.directory"] + tmpfilename;
return dir;
}

View File

@@ -24,16 +24,14 @@ CLogging *CLogging::instance = NULL;
//-----------------------------------------------------------------------------
// There is only one Instance
//-----------------------------------------------------------------------------
CLogging *CLogging::getInstance(void)
{
CLogging *CLogging::getInstance(void) {
if (!instance)
instance = new CLogging();
return instance;
}
//-----------------------------------------------------------------------------
void CLogging::deleteInstance(void)
{
void CLogging::deleteInstance(void) {
if (instance)
delete instance;
instance = NULL;
@@ -42,30 +40,26 @@ void CLogging::deleteInstance(void)
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CLogging::CLogging(void)
{
Debug = false;
LogToFile = false; //not implemented
LogLevel = 0;
Logfile = NULL;
CLogging::CLogging(void) {
Debug = false;
LogToFile = false; //not implemented
LogLevel = 0;
Logfile = NULL;
pthread_mutex_init(&Log_mutex, NULL);
}
//-----------------------------------------------------------------------------
CLogging::~CLogging(void)
{
CLogging::~CLogging(void) {
}
//=============================================================================
//-----------------------------------------------------------------------------
void CLogging::setDebug(bool _debug)
{
Debug = _debug;
void CLogging::setDebug(bool _debug) {
Debug = _debug;
}
//-----------------------------------------------------------------------------
bool CLogging::getDebug(void)
{
return Debug;
bool CLogging::getDebug(void) {
return Debug;
}
//=============================================================================
// Logging Calls
@@ -74,22 +68,19 @@ bool CLogging::getDebug(void)
//=============================================================================
#define bufferlen 1024*8
//-----------------------------------------------------------------------------
void CLogging::printf ( const char *fmt, ... )
{
void CLogging::printf(const char *fmt, ...) {
char buffer[bufferlen];
va_list arglist;
va_start( arglist, fmt );
if(arglist)
vsnprintf( buffer, bufferlen, fmt, arglist );
va_start(arglist, fmt);
vsnprintf(buffer, bufferlen, fmt, arglist);
va_end(arglist);
pthread_mutex_lock( &Log_mutex );
pthread_mutex_lock(&Log_mutex);
::printf(buffer);
if(LogToFile) {
; //FIXME Logging to File
if (LogToFile) {
; //FIXME Logging to File
}
pthread_mutex_unlock( &Log_mutex );
pthread_mutex_unlock(&Log_mutex);
}

View File

@@ -33,8 +33,7 @@
//=============================================================================
// Constructor & Destructor
//=============================================================================
CWebserverRequest::CWebserverRequest(CWebserver *pWebserver)
{
CWebserverRequest::CWebserverRequest(CWebserver *pWebserver) {
Webserver = pWebserver;
CWebserverRequest();
}
@@ -51,61 +50,53 @@ CWebserverRequest::CWebserverRequest(CWebserver *pWebserver)
// [ message-body ]
// start-line = Request-Line | Status-Line
//-----------------------------------------------------------------------------
bool CWebserverRequest::HandleRequest(void)
{
bool CWebserverRequest::HandleRequest(void) {
std::string start_line = "";
// read first line
do
{
do {
start_line = Connection->sock->ReceiveLine();
if(!Connection->sock->isValid)
if (!Connection->sock->isValid)
return false;
if(start_line == "") // Socket empty
if (start_line == "") // Socket empty
{
log_level_printf(1,"HandleRequest: End of line not found\n");
log_level_printf(1, "HandleRequest: End of line not found\n");
Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR);
Connection->RequestCanceled = true;
return false;
}
}
while(start_line == "\r\n"); // ignore empty lines at begin on start-line
} while (start_line == "\r\n"); // ignore empty lines at begin on start-line
start_line = trim(start_line);
log_level_printf(1,"Request: %s\n", start_line.c_str() );
log_level_printf(1, "Request: %s\n", start_line.c_str());
UrlData["startline"] = start_line;
if(!ParseStartLine(start_line))
if (!ParseStartLine(start_line))
return false;
if(Connection->Method == M_GET || Connection->Method == M_HEAD)
{
if (Connection->Method == M_GET || Connection->Method == M_HEAD) {
std::string tmp_line;
//read header (speed up: read rest of request in blockmode)
tmp_line = Connection->sock->ReceiveBlock();
if(!Connection->sock->isValid)
{
if (!Connection->sock->isValid) {
Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR);
return false;
}
if(tmp_line == "")
{
if (tmp_line == "") {
Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR);
return false;
}
ParseHeader(tmp_line);
}
// Other Methods
if(Connection->Method == M_DELETE || Connection->Method == M_PUT || Connection->Method == M_TRACE)
{
if (Connection->Method == M_DELETE || Connection->Method == M_PUT
|| Connection->Method == M_TRACE) {
//todo: implement
aprintf("HTTP Method not implemented :%d\n",Connection->Method);
aprintf("HTTP Method not implemented :%d\n", Connection->Method);
Connection->Response.SendError(HTTP_NOT_IMPLEMENTED);
return false;
}
// handle POST (read header & body)
if(Connection->Method == M_POST)
{
if (Connection->Method == M_POST) {
Connection->Response.Write("HTTP/1.1 100 Continue\r\n\r\n"); // POST Requests requires CONTINUE in HTTP/1.1
return HandlePost();
}
@@ -122,33 +113,29 @@ bool CWebserverRequest::HandleRequest(void)
// Determine Reqest-Method, URL, HTTP-Version and Split Parameters
// Split URL into path, filename, fileext .. UrlData[]
//-----------------------------------------------------------------------------
bool CWebserverRequest::ParseStartLine(std::string start_line)
{
std::string method,url,http,tmp;
bool CWebserverRequest::ParseStartLine(std::string start_line) {
std::string method, url, http, tmp;
log_level_printf(8,"<ParseStartLine>: line: %s\n", start_line.c_str() );
if(ySplitString(start_line," ",method,tmp))
{
if(ySplitStringLast(tmp," ",url,Connection->httprotocol))
{
log_level_printf(8, "<ParseStartLine>: line: %s\n", start_line.c_str());
if (ySplitString(start_line, " ", method, tmp)) {
if (ySplitStringLast(tmp, " ", url, Connection->httprotocol)) {
analyzeURL(url);
UrlData["httprotocol"] = Connection->httprotocol;
// determine http Method
if(method.compare("POST") == 0) Connection->Method = M_POST;
else if(method.compare("GET") == 0) Connection->Method = M_GET;
else if(method.compare("PUT") == 0) Connection->Method = M_PUT;
else if(method.compare("HEAD") == 0) Connection->Method = M_HEAD;
else if(method.compare("PUT") == 0) Connection->Method = M_PUT;
else if(method.compare("DELETE") == 0) Connection->Method = M_DELETE;
else if(method.compare("TRACE") == 0) Connection->Method = M_TRACE;
else
{
log_level_printf(1,"Unknown Method or invalid request\n");
if (method.compare("POST") == 0) Connection->Method = M_POST;
else if (method.compare("GET") == 0) Connection->Method = M_GET;
else if (method.compare("PUT") == 0) Connection->Method = M_PUT;
else if (method.compare("HEAD") == 0) Connection->Method = M_HEAD;
else if (method.compare("PUT") == 0) Connection->Method = M_PUT;
else if (method.compare("DELETE") == 0) Connection->Method = M_DELETE;
else if (method.compare("TRACE") == 0) Connection->Method = M_TRACE;
else {
log_level_printf(1, "Unknown Method or invalid request\n");
Connection->Response.SendError(HTTP_NOT_IMPLEMENTED);
log_level_printf(3,"Request: '%s'\n",rawbuffer.c_str());
log_level_printf(3, "Request: '%s'\n", rawbuffer.c_str());
return false;
}
log_level_printf(3,"Request: FullURL: %s\n",UrlData["fullurl"].c_str());
log_level_printf(3, "Request: FullURL: %s\n", UrlData["fullurl"].c_str());
return true;
}
}
@@ -164,28 +151,24 @@ bool CWebserverRequest::ParseStartLine(std::string start_line)
// If parameter attribute is multiple times given, the values are stored like this:
// <attribute>=<value1>,<value2>,..,<value n>
//-----------------------------------------------------------------------------
bool CWebserverRequest::ParseParams(std::string param_string)
{
bool CWebserverRequest::ParseParams(std::string param_string) {
bool ende = false;
std::string param, name="", value, number;
std::string param, name = "", value, number;
while(!ende)
{
if(!ySplitStringExact(param_string,"&",param,param_string))
while (!ende) {
if (!ySplitStringExact(param_string, "&", param, param_string))
ende = true;
if(ySplitStringExact(param,"=",name,value))
{
if (ySplitStringExact(param, "=", name, value)) {
value = trim(decodeString(value));
if(ParameterList[name].empty())
if (ParameterList[name].empty())
ParameterList[name] = value;
else
{
else {
ParameterList[name] += ",";
ParameterList[name] += value;
}
}
number = string_printf("%d", ParameterList.size()+1);
log_level_printf(7,"ParseParams: name: %s value: %s\n",name.c_str(), value.c_str());
number = string_printf("%d", ParameterList.size() + 1);
log_level_printf(7, "ParseParams: name: %s value: %s\n", name.c_str(), value.c_str());
ParameterList[number] = name;
}
return true;
@@ -201,19 +184,17 @@ bool CWebserverRequest::ParseParams(std::string param_string)
// and consisting of either *TEXT or combinations
// of token, separators, and quoted-string>
//-----------------------------------------------------------------------------
bool CWebserverRequest::ParseHeader(std::string header)
{
bool CWebserverRequest::ParseHeader(std::string header) {
bool ende = false;
std::string sheader, name, value;
HeaderList.clear();
while(!ende)
{
if(!ySplitStringExact(header,"\r\n",sheader,header))
while (!ende) {
if (!ySplitStringExact(header, "\r\n", sheader, header))
ende = true;
if(ySplitStringExact(sheader,":",name,value))
if (ySplitStringExact(sheader, ":", name, value))
HeaderList[name] = trim(value);
log_level_printf(8,"ParseHeader: name: %s value: %s\n",name.c_str(), value.c_str());
log_level_printf(8, "ParseHeader: name: %s value: %s\n", name.c_str(), value.c_str());
}
return true;
}
@@ -225,66 +206,65 @@ bool CWebserverRequest::ParseHeader(std::string header)
// http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
// query data is splitted and stored in ParameterList
//-----------------------------------------------------------------------------
void CWebserverRequest::analyzeURL(std::string url)
{
void CWebserverRequest::analyzeURL(std::string url) {
ParameterList.clear();
// URI decode
url = decodeString(url);
url = trim(url, "\r\n"); // non-HTTP-Standard: allow \r or \n in URL. Delete it.
UrlData["fullurl"] = url;
// split Params
if(ySplitString(url,"?",UrlData["url"],UrlData["paramstring"])) // split pure URL and all Params
ParseParams(UrlData["paramstring"]); // split params to ParameterList
else // No Params
if (ySplitString(url, "?", UrlData["url"], UrlData["paramstring"])) // split pure URL and all Params
ParseParams( UrlData["paramstring"]); // split params to ParameterList
else
// No Params
UrlData["url"] = url;
if(!ySplitStringLast(UrlData["url"],"/",UrlData["path"],UrlData["filename"]))
{
UrlData["path"] = "/"; // Set "/" if not contained
}
else
if (!ySplitStringLast(UrlData["url"], "/", UrlData["path"],
UrlData["filename"])) {
UrlData["path"] = "/"; // Set "/" if not contained
} else
UrlData["path"] += "/";
if(( UrlData["url"].length() == 1) || (UrlData["url"][UrlData["url"].length()-1] == '/' ))
{ // if "/" at end use index.html
if ((UrlData["url"].length() == 1)
|| (UrlData["url"][UrlData["url"].length() - 1] == '/')) { // if "/" at end use index.html
UrlData["path"] = UrlData["url"];
UrlData["filename"] = "index.html";
}
ySplitStringLast(UrlData["filename"],".",UrlData["filenamepure"],UrlData["fileext"]);
ySplitStringLast(UrlData["filename"], ".", UrlData["filenamepure"],
UrlData["fileext"]);
}
//-----------------------------------------------------------------------------
// Handle Post (Form and ONE file upload)
//-----------------------------------------------------------------------------
bool CWebserverRequest::HandlePost()
{
bool CWebserverRequest::HandlePost() {
//read header: line by line
std::string raw_header, tmp_line;
do
{
do {
tmp_line = Connection->sock->ReceiveLine();
if(tmp_line == "") // Socket empty
if (tmp_line == "") // Socket empty
{
log_level_printf(1,"HandleRequest: (Header) End of line not found: %s\n", strerror(errno));
log_level_printf(1,
"HandleRequest: (Header) End of line not found: %s\n",
strerror(errno));
Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR);
return false;
}
raw_header.append(tmp_line);
}
while(tmp_line != "\r\n"); // header ends with first empty line
} while (tmp_line != "\r\n"); // header ends with first empty line
ParseHeader(raw_header);
// read meesage body
unsigned int content_len = 0;
if(HeaderList["Content-Length"] != "")
content_len = atoi( HeaderList["Content-Length"].c_str() );
if (HeaderList["Content-Length"] != "")
content_len = atoi(HeaderList["Content-Length"].c_str());
// Get Rest of Request from Socket
log_level_printf(2,"Connection->Method Post !\n");
log_level_printf(9,"Conntent Type:%s\n",(HeaderList["Content-Type"]).c_str());
log_level_printf(8,"Post Content-Length:%d as string:(%s)\n", content_len, HeaderList["Content-Length"].c_str());
log_level_printf(2, "Connection->Method Post !\n");
log_level_printf(9, "Conntent Type:%s\n", (HeaderList["Content-Type"]).c_str());
log_level_printf(8, "Post Content-Length:%d as string:(%s)\n", content_len, HeaderList["Content-Length"].c_str());
static const std::string t = "multipart/form-data; boundary=";
if(HeaderList["Content-Type"].compare(0,t.length(),t) == 0) // this a a multpart POST, normallly: file upload
if (HeaderList["Content-Type"].compare(0, t.length(), t) == 0) // this a a multpart POST, normallly: file upload
{
#ifdef Y_CONFIG_FEATURE_UPLOAD
std::string boundary = "--" + HeaderList["Content-Type"].substr(t.length(),HeaderList["Content-Type"].length() - t.length());
@@ -298,21 +278,20 @@ bool CWebserverRequest::HandlePost()
Connection->Response.SendError(HTTP_NOT_IMPLEMENTED);
return false;
#endif
}
else if(HeaderList["Content-Type"].compare("application/x-www-form-urlencoded") == 0) //this is a normal POST with form-data (no upload)
} else if (HeaderList["Content-Type"].compare(
"application/x-www-form-urlencoded") == 0) //this is a normal POST with form-data (no upload)
{
// handle normal form POST
log_level_printf(6,"Handle POST application/x-www-form-urlencoded\n");
log_level_printf(6, "Handle POST application/x-www-form-urlencoded\n");
std::string post_header;
// get message-body
post_header = Connection->sock->ReceiveBlock();
while(post_header.length() < content_len)
{
while (post_header.length() < content_len) {
post_header += Connection->sock->ReceiveBlock();
/* aprintf("POST form less data then expected\n");
Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR);
return false;
*/
/* aprintf("POST form less data then expected\n");
Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR);
return false;
*/
}
// parse the params in post_header (message-body) an add them to ParameterList
ParseParams(post_header);
@@ -401,35 +380,31 @@ bool CWebserverRequest::HandlePost()
// where the original filename is known. This is useful or necessary in
// many applications.
//-----------------------------------------------------------------------------
unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigned int content_len)
{
unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary,
unsigned int content_len) {
std::string tmp_line;
// read boundary
tmp_line = Connection->sock->ReceiveLine();
content_len -= tmp_line.length();
log_level_printf(2,"<POST Boundary> Start\n");
if(tmp_line.find(boundary) != std::string::npos)
{
log_level_printf(2, "<POST Boundary> Start\n");
if (tmp_line.find(boundary) != std::string::npos) {
// is it the boudary end?
if(tmp_line.find(boundary+"--") != std::string::npos)
{
log_level_printf(7,"<POST Boundary> Boundary END found\n");
if (tmp_line.find(boundary + "--") != std::string::npos) {
log_level_printf(7, "<POST Boundary> Boundary END found\n");
return 0;
}
log_level_printf(7,"<POST Boundary> Boundary START found\n");
log_level_printf(7, "<POST Boundary> Boundary START found\n");
// read content-disposition: ...
tmp_line = Connection->sock->ReceiveLine();
content_len -= tmp_line.length();
if(tmp_line.find("Content-Disposition:") == std::string::npos)
{
log_level_printf(7,"<POST Boundary> no content-disposition found. line:(%s)\n", tmp_line.c_str());
if (tmp_line.find("Content-Disposition:") == std::string::npos) {
log_level_printf(7, "<POST Boundary> no content-disposition found. line:(%s)\n", tmp_line.c_str());
return 0;
}
if(tmp_line.find("filename") != std::string::npos)
{
if (tmp_line.find("filename") != std::string::npos) {
#ifdef Y_CONFIG_FEATURE_UPLOAD
// this part is a file
log_level_printf(2,"<POST Boundary> disposition !!this is a file!! found. line:(%s)\n", tmp_line.c_str());
@@ -473,7 +448,6 @@ unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigne
ParameterList[var_name+"_mime"] = var_value;
log_level_printf(7,"<POST Boundary> Content-Type found. name:(%s_mime) value:(%s)\n", var_name.c_str(), var_value.c_str());
//read empty line as separator
tmp_line = Connection->sock->ReceiveLine();
content_len -= tmp_line.length();
@@ -505,7 +479,7 @@ unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigne
// It only works, if no multipart/mixed is used (e.g. in file attachments). Not nessesary in embedded systems.
// To speed up uploading, read content_len - SEARCH_BOUNDARY_LEN bytes in blockmode.
// To save memory, write them direct into the file.
#define SEARCH_BOUNDARY_LEN 2*RECEIVE_BLOCK_LEN // >= RECEIVE_BLOCK_LEN in ySocket
#define SEARCH_BOUNDARY_LEN 2*RECEIVE_BLOCK_LEN // >= RECEIVE_BLOCK_LEN in ySocket
unsigned int _readbytes = 0;
if((int)content_len - SEARCH_BOUNDARY_LEN >0)
{
@@ -529,17 +503,17 @@ unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigne
if(tmp_line.find(boundary) != std::string::npos)
{
if(tmp_line.find(boundary+"--") != std::string::npos)
found_end_boundary = true; // it is the end! of POST request!
break; // boundary found. end of file.
found_end_boundary = true; // it is the end! of POST request!
break; // boundary found. end of file.
}
else // no Boundary: write CRFL if found in last line
{
if(is_CRLF)
if ((unsigned int)write(fd, "\r\n", 2) != 2)
{
perror("write file failed\n");
return 0;
}
if ((unsigned int)write(fd, "\r\n", 2) != 2)
{
perror("write file failed\n");
return 0;
}
}
// normal line: write it to file
// CRLF at end? Maybe CRLF before boundary. Can not decide yet
@@ -563,29 +537,25 @@ unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigne
return 0;
}
#endif // Y_CONFIG_FEATURE_UPLOAD
}
else
} else
// this part is a POST variable/parameter
{
// get var_name from 'content-disposition: form-data; name="var_name"'
std::string left, right, var_name, var_value;
if(!ySplitStringExact(tmp_line, "name=\"", left, right))
{
log_level_printf(7,"<POST Boundary> no var_name START found. line:(%s)\n", tmp_line.c_str());
if (!ySplitStringExact(tmp_line, "name=\"", left, right)) {
log_level_printf(7, "<POST Boundary> no var_name START found. line:(%s)\n", tmp_line.c_str());
return 0;
}
if(!ySplitStringExact(right, "\"", var_name, right))
{
log_level_printf(7,"<POST Boundary> no var_name END found. line:(%s)\n", tmp_line.c_str());
if (!ySplitStringExact(right, "\"", var_name, right)) {
log_level_printf(7, "<POST Boundary> no var_name END found. line:(%s)\n", tmp_line.c_str());
return 0;
}
//read empty line as separator
tmp_line = Connection->sock->ReceiveLine();
content_len -= tmp_line.length();
if(tmp_line != "\r\n")
{
log_level_printf(7,"<POST Boundary> no empty line found. line:(%s)\n", tmp_line.c_str());
if (tmp_line != "\r\n") {
log_level_printf(7, "<POST Boundary> no empty line found. line:(%s)\n", tmp_line.c_str());
return 0;
}
@@ -596,7 +566,7 @@ unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigne
content_len -= tmp_line.length();
var_value = trim(decodeString(var_value));
ParameterList[var_name] = var_value;
log_level_printf(7,"<POST Boundary> Parameter found. name:(%s) value:(%s)\n", var_name.c_str(), var_value.c_str());
log_level_printf(7, "<POST Boundary> Parameter found. name:(%s) value:(%s)\n", var_name.c_str(), var_value.c_str());
}
}
return content_len;

View File

@@ -29,14 +29,12 @@
//=============================================================================
// Constructor & Destructor
//=============================================================================
CWebserverResponse::CWebserverResponse(CWebserver *pWebserver)
{
CWebserverResponse::CWebserverResponse(CWebserver *pWebserver) {
Webserver = pWebserver;
CWebserverResponse();
}
//-----------------------------------------------------------------------------
CWebserverResponse::CWebserverResponse()
{
CWebserverResponse::CWebserverResponse() {
}
//=============================================================================
@@ -54,198 +52,177 @@ CWebserverResponse::CWebserverResponse()
// CRLF ; generated by SendHeader
// [ message-body ] ; by HOOK Handling Loop or Sendfile
//=============================================================================
bool CWebserverResponse::SendResponse()
{
bool CWebserverResponse::SendResponse() {
// Init Hookhandler
Connection->HookHandler.session_init(Connection->Request.ParameterList, Connection->Request.UrlData,
(Connection->Request.HeaderList), (Cyhttpd::ConfigList), Connection->Method, Connection->keep_alive);
Connection->HookHandler.session_init(Connection->Request.ParameterList,
Connection->Request.UrlData, (Connection->Request.HeaderList),
(Cyhttpd::ConfigList), Connection->Method, Connection->keep_alive);
//--------------------------------------------------------------
// HOOK Handling Loop [ PREPARE response hook ]
// Checking and Preperation: Auth, static, cache, ...
//--------------------------------------------------------------
// move to mod_sendfile ???
// move to mod_sendfile ???
#ifdef Y_CONFIG_USE_HOSTEDWEB
// for hosted webs: rewrite URL
std::string _hosted="/hosted/";
if((Connection->Request.UrlData["path"]).compare(0,_hosted.length(),"/hosted/") == 0) // hosted Web ?
Connection->Request.UrlData["path"]=Cyhttpd::ConfigList["HostedDocumentRoot"]
+(Connection->Request.UrlData["path"]).substr(_hosted.length()-1);
if((Connection->Request.UrlData["path"]).compare(0,_hosted.length(),"/hosted/") == 0) // hosted Web ?
Connection->Request.UrlData["path"]=Cyhttpd::ConfigList["WebsiteMain.hosted_directory"]
+(Connection->Request.UrlData["path"]).substr(_hosted.length()-1);
#endif //Y_CONFIG_USE_HOSTEDWEB
do
{
if(Connection->RequestCanceled)
do {
if (Connection->RequestCanceled)
return false;
Connection->HookHandler.Hooks_PrepareResponse();
if(Connection->HookHandler.status == HANDLED_ERROR || Connection->HookHandler.status == HANDLED_ABORT)
{
log_level_printf(2,"Response Prepare Hook found but Error\n");
if (Connection->HookHandler.status == HANDLED_ERROR
|| Connection->HookHandler.status == HANDLED_ABORT) {
log_level_printf(2, "Response Prepare Hook found but Error\n");
Write(Connection->HookHandler.BuildHeader());
Write(Connection->HookHandler.yresult);
return false;
}
// URL has new value. Analyze new URL for SendFile
else if(Connection->HookHandler.status == HANDLED_SENDFILE ||
Connection->HookHandler.status == HANDLED_REWRITE)
{
else if (Connection->HookHandler.status == HANDLED_SENDFILE
|| Connection->HookHandler.status == HANDLED_REWRITE) {
Connection->Request.analyzeURL(Connection->HookHandler.NewURL);
Connection->HookHandler.UrlData = Connection->Request.UrlData;
}
if(Connection->HookHandler.status == HANDLED_REDIRECTION)
{
if (Connection->HookHandler.status == HANDLED_REDIRECTION) {
Write(Connection->HookHandler.BuildHeader());
return false;
}
}
while(Connection->HookHandler.status == HANDLED_REWRITE);
} while (Connection->HookHandler.status == HANDLED_REWRITE);
// Prepare = NOT_MODIFIED ?
if(Connection->HookHandler.httpStatus == HTTP_NOT_MODIFIED)
{
if (Connection->HookHandler.httpStatus == HTTP_NOT_MODIFIED) {
Write(Connection->HookHandler.BuildHeader());
return true;
}
//--------------------------------------------------------------
// HOOK Handling Loop [ response hook ]
// Production
//--------------------------------------------------------------
if(Connection->HookHandler.status != HANDLED_SENDFILE)
do
{
if(Connection->RequestCanceled)
return false;
if (Connection->HookHandler.status != HANDLED_SENDFILE)
do {
if (Connection->RequestCanceled)
return false;
Connection->HookHandler.Hooks_SendResponse();
if((Connection->HookHandler.status == HANDLED_READY)||(Connection->HookHandler.status == HANDLED_CONTINUE))
{
log_level_printf(2,"Response Hook Output. Status:%d\n", Connection->HookHandler.status);
Write(Connection->HookHandler.BuildHeader());
if(Connection->Method != M_HEAD)
Write(Connection->HookHandler.yresult);
if(Connection->HookHandler.status != HANDLED_CONTINUE)
return true;
}
else if(Connection->HookHandler.status == HANDLED_ERROR)
{
log_level_printf(2,"Response Hook found but Error\n");
Write(Connection->HookHandler.BuildHeader());
if(Connection->Method != M_HEAD)
Write(Connection->HookHandler.yresult);
return false;
}
else if(Connection->HookHandler.status == HANDLED_ABORT)
return false;
// URL has new value. Analyze new URL for SendFile
else if(Connection->HookHandler.status == HANDLED_SENDFILE ||
Connection->HookHandler.status == HANDLED_REWRITE)
{
Connection->Request.analyzeURL(Connection->HookHandler.NewURL);
Connection->HookHandler.UrlData = Connection->Request.UrlData;
}
if(Connection->HookHandler.status == HANDLED_REDIRECTION)
{
Write(Connection->HookHandler.BuildHeader());
return false;
}
}
while(Connection->HookHandler.status == HANDLED_REWRITE);
Connection->HookHandler.Hooks_SendResponse();
if ((Connection->HookHandler.status == HANDLED_READY)
|| (Connection->HookHandler.status == HANDLED_CONTINUE)) {
log_level_printf(2, "Response Hook Output. Status:%d\n", Connection->HookHandler.status);
Write(Connection->HookHandler.BuildHeader());
if (Connection->Method != M_HEAD)
Write(Connection->HookHandler.yresult);
if (Connection->HookHandler.status != HANDLED_CONTINUE)
return true;
} else if (Connection->HookHandler.status == HANDLED_ERROR) {
log_level_printf(2, "Response Hook found but Error\n");
Write(Connection->HookHandler.BuildHeader());
if (Connection->Method != M_HEAD)
Write(Connection->HookHandler.yresult);
return false;
} else if (Connection->HookHandler.status == HANDLED_ABORT)
return false;
// URL has new value. Analyze new URL for SendFile
else if (Connection->HookHandler.status == HANDLED_SENDFILE
|| Connection->HookHandler.status == HANDLED_REWRITE) {
Connection->Request.analyzeURL(Connection->HookHandler.NewURL);
Connection->HookHandler.UrlData = Connection->Request.UrlData;
}
if (Connection->HookHandler.status == HANDLED_REDIRECTION) {
Write(Connection->HookHandler.BuildHeader());
return false;
}
} while (Connection->HookHandler.status == HANDLED_REWRITE);
// Send static file
if(Connection->HookHandler.status == HANDLED_SENDFILE && !Connection->RequestCanceled)
{
if (Connection->HookHandler.status == HANDLED_SENDFILE
&& !Connection->RequestCanceled) {
bool cache = true;
// if(Connection->HookHandler.UrlData["path"] == "/tmp/")//TODO: un-cachable dirs
// cache = false;
// if(Connection->HookHandler.UrlData["path"] == "/tmp/")//TODO: un-cachable dirs
// cache = false;
Write(Connection->HookHandler.BuildHeader(cache));
if(Connection->Method != M_HEAD)
if (Connection->Method != M_HEAD)
Sendfile(Connection->Request.UrlData["url"]);
return true;
}
}
// arrived here? = error!
SendError(HTTP_NOT_FOUND);
SendError( HTTP_NOT_FOUND);
return false;
}
//=============================================================================
// Output
//=============================================================================
void CWebserverResponse::SendHeader(HttpResponseType responseType, bool cache, std::string ContentType)
{
Connection->HookHandler.SetHeader(responseType, ContentType);
void CWebserverResponse::SendHeader(HttpResponseType responseType, bool cache,
std::string ContentType) {
Connection->HookHandler.SetHeader(responseType, ContentType);
Write(Connection->HookHandler.BuildHeader(cache));
}
//-----------------------------------------------------------------------------
// BASIC Send over Socket for Strings (char*)
//-----------------------------------------------------------------------------
bool CWebserverResponse::WriteData(char const * data, long length)
{
if(Connection->RequestCanceled)
bool CWebserverResponse::WriteData(char const * data, long length) {
if (Connection->RequestCanceled)
return false;
if(Connection->sock->Send(data, length) == -1)
{
log_level_printf(1,"response canceled: %s\n", strerror(errno));
if (Connection->sock->Send(data, length) == -1) {
log_level_printf(1, "response canceled: %s\n", strerror(errno));
Connection->RequestCanceled = true;
return false;
}
else
} else
return true;
}
//-----------------------------------------------------------------------------
#define bufferlen 4*1024
void CWebserverResponse::printf ( const char *fmt, ... )
{
void CWebserverResponse::printf(const char *fmt, ...) {
char buffer[bufferlen];
va_list arglist;
va_start( arglist, fmt );
vsnprintf( buffer, bufferlen, fmt, arglist );
va_start(arglist, fmt);
vsnprintf(buffer, bufferlen, fmt, arglist);
va_end(arglist);
Write(buffer);
}
//-----------------------------------------------------------------------------
bool CWebserverResponse::Write(char const *text)
{
bool CWebserverResponse::Write(char const *text) {
return WriteData(text, strlen(text));
}
//-----------------------------------------------------------------------------
bool CWebserverResponse::WriteLn(char const *text)
{
if(!WriteData(text, strlen(text)))
bool CWebserverResponse::WriteLn(char const *text) {
if (!WriteData(text, strlen(text)))
return false;
return WriteData("\r\n",2);
return WriteData("\r\n", 2);
}
//-----------------------------------------------------------------------------
bool CWebserverResponse::Sendfile(std::string filename)
{
if(Connection->RequestCanceled)
bool CWebserverResponse::Sendfile(std::string filename) {
if (Connection->RequestCanceled)
return false;
int filed = open( filename.c_str(), O_RDONLY );
if(filed != -1 ) //can access file?
int filed = open(filename.c_str(), O_RDONLY);
if (filed != -1) //can access file?
{
if(!Connection->sock->SendFile(filed))
if (!Connection->sock->SendFile(filed))
Connection->RequestCanceled = true;
close(filed);
}
return (filed != -1 );
return (filed != -1);
}
//-----------------------------------------------------------------------------
// Send File: Determine MIME-Type fro File-Extention
//-----------------------------------------------------------------------------
std::string CWebserverResponse::GetContentType(std::string ext)
{
std::string CWebserverResponse::GetContentType(std::string ext) {
std::string ctype = "text/plain";
ext = string_tolower(ext);
for (unsigned int i = 0;i < (sizeof(MimeFileExtensions)/sizeof(MimeFileExtensions[0])); i++)
if (MimeFileExtensions[i].fileext == ext)
{
for (unsigned int i = 0; i < (sizeof(MimeFileExtensions)
/ sizeof(MimeFileExtensions[0])); i++)
if (MimeFileExtensions[i].fileext == ext) {
ctype = MimeFileExtensions[i].mime;
break;
}
}
return ctype;
}

View File

@@ -32,46 +32,43 @@
// Initialization of static variables
//=============================================================================
#ifdef Y_CONFIG_USE_OPEN_SSL
SSL_CTX *CySocket::SSL_ctx;
std::string CySocket::SSL_pemfile;
std::string CySocket::SSL_CA_file;
SSL_CTX *CySocket::SSL_ctx;
std::string CySocket::SSL_pemfile;
std::string CySocket::SSL_CA_file;
#endif
//=============================================================================
// Constructor & Destructor & Initialization
//=============================================================================
CySocket::CySocket()
: sock(0)
{
CySocket::CySocket() :
sock(0) {
#ifdef Y_CONFIG_USE_OPEN_SSL
ssl = NULL;
#endif
tv_start_waiting.tv_sec = 0;
tv_start_waiting.tv_usec = 0;
BytesSend =0;
sock = socket(AF_INET,SOCK_STREAM,0);
BytesSend = 0;
sock = socket(AF_INET, SOCK_STREAM, 0);
init();
}
//-----------------------------------------------------------------------------
CySocket::~CySocket()
{
CySocket::~CySocket() {
#ifdef Y_CONFIG_USE_OPEN_SSL
if(isSSLSocket && ssl != NULL)
SSL_free(ssl);
SSL_free(ssl);
#endif
}
//-----------------------------------------------------------------------------
// initialize
//-----------------------------------------------------------------------------
void CySocket::init(void)
{
handling = false;
isOpened = false;
isValid = true;
addr_len = sizeof(addr);
void CySocket::init(void) {
handling = false;
isOpened = false;
isValid = true;
addr_len = sizeof(addr);
memset(&addr, 0, addr_len);
#ifdef Y_CONFIG_USE_OPEN_SSL
isSSLSocket = false;
isSSLSocket = false;
#endif
}
//-----------------------------------------------------------------------------
@@ -82,13 +79,13 @@ void CySocket::init(void)
bool CySocket::initAsSSL(void)
{
isSSLSocket = true;
if (NULL == (ssl = SSL_new(CySocket::SSL_ctx))) // create SSL-socket
if (NULL == (ssl = SSL_new(CySocket::SSL_ctx))) // create SSL-socket
{
aprintf("ySocket:SSL Error: Create SSL_new : %s\n", ERR_error_string(ERR_get_error(), NULL) );
return false;
}
SSL_set_accept_state(ssl); // accept connection
if(1 != (SSL_set_fd(ssl, sock))) // associate socket descriptor
SSL_set_accept_state(ssl); // accept connection
if(1 != (SSL_set_fd(ssl, sock))) // associate socket descriptor
if (NULL == (ssl = SSL_new(CySocket::SSL_ctx)))
{
aprintf("ySocket:SSL Error: Create SSL_new : %s\n", ERR_error_string(ERR_get_error(), NULL) );
@@ -102,9 +99,9 @@ bool CySocket::initAsSSL(void)
//-----------------------------------------------------------------------------
bool CySocket::initSSL(void)
{
SSL_load_error_strings(); // Load SSL Error Strings
SSL_library_init(); // Load SSL Library
if (0 == RAND_status()) // set Random
SSL_load_error_strings(); // Load SSL Error Strings
SSL_library_init(); // Load SSL Library
if (0 == RAND_status()) // set Random
{
aprintf("ySocket:SSL got no rand\n");
return false;
@@ -119,12 +116,12 @@ bool CySocket::initSSL(void)
aprintf("ySocket:SSL Error: no pemfile given\n");
return false;
}
if(SSL_CA_file != "") // have a CA?
if(1 != SSL_CTX_load_verify_locations(SSL_ctx, SSL_CA_file.c_str(), NULL))
{
aprintf("ySocket:SSL Error: %s CA-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_CA_file.c_str());
return false;
}
if(SSL_CA_file != "") // have a CA?
if(1 != SSL_CTX_load_verify_locations(SSL_ctx, SSL_CA_file.c_str(), NULL))
{
aprintf("ySocket:SSL Error: %s CA-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_CA_file.c_str());
return false;
}
if(SSL_CTX_use_certificate_file(SSL_ctx, SSL_pemfile.c_str(), SSL_FILETYPE_PEM) < 0)
{
aprintf("ySocket:SSL Error: %s PEM-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_pemfile.c_str());
@@ -147,54 +144,48 @@ bool CySocket::initSSL(void)
//=============================================================================
// Socket handling
//=============================================================================
void CySocket::close(void)
{
if(sock != 0 && sock != INVALID_SOCKET)
::close(sock);
void CySocket::close(void) {
if (sock != 0 && sock != INVALID_SOCKET)
::close( sock);
#ifndef Y_CONFIG_FEATURE_KEEP_ALIVE
sock = 0;
#endif
isOpened = false;
}
//-----------------------------------------------------------------------------
void CySocket::shutdown(void)
{
if(sock != 0 && sock != INVALID_SOCKET)
::shutdown(sock,SHUT_RDWR);
void CySocket::shutdown(void) {
if (sock != 0 && sock != INVALID_SOCKET)
::shutdown(sock, SHUT_RDWR);
}
//-----------------------------------------------------------------------------
bool CySocket::listen(int port, int max_connections)
{
if(sock == INVALID_SOCKET)
bool CySocket::listen(int port, int max_connections) {
if (sock == INVALID_SOCKET)
return false;
// set sockaddr for listening
sockaddr_in sai;
memset(&sai, 0, sizeof(sai));
sai.sin_family = AF_INET; // Protocol
sai.sin_addr.s_addr = htonl(INADDR_ANY); // No Filter
sai.sin_port = htons(port); // Listening Port
memset(&sai, 0, sizeof(sai));
sai.sin_family = AF_INET; // Protocol
sai.sin_addr.s_addr = htonl(INADDR_ANY); // No Filter
sai.sin_port = htons(port); // Listening Port
set_reuse_port(); // Re-Use Port
set_reuse_addr(); // Re-Use IP
if(bind(sock, (sockaddr *)&sai, sizeof(sockaddr_in)) != SOCKET_ERROR)
if(::listen(sock, max_connections) == 0)
set_reuse_port(); // Re-Use Port
set_reuse_addr(); // Re-Use IP
if (bind(sock, (sockaddr *) &sai, sizeof(sockaddr_in)) != SOCKET_ERROR)
if (::listen(sock, max_connections) == 0)
return true;
return false;
}
//-----------------------------------------------------------------------------
CySocket* CySocket::accept()
{
CySocket* CySocket::accept() {
init();
SOCKET newSock = ::accept(sock, (sockaddr *) &addr, &addr_len);
if(newSock == INVALID_SOCKET)
{
if (newSock == INVALID_SOCKET) {
dperror("accept: invalid socket\n");
return NULL;
}
CySocket *new_ySocket = new CySocket(newSock);
if(new_ySocket != NULL)
{
if (new_ySocket != NULL) {
new_ySocket->setAddr(addr);
#ifdef TCP_CORK
new_ySocket->set_option(IPPROTO_TCP, TCP_CORK);
@@ -203,75 +194,67 @@ CySocket* CySocket::accept()
#endif
}
new_ySocket->isOpened = true;
// handling = true;
// handling = true;
return new_ySocket;
}
//-----------------------------------------------------------------------------
std::string CySocket::get_client_ip(void)
{
std::string CySocket::get_client_ip(void) {
return inet_ntoa(addr.sin_addr);
}
//-----------------------------------------------------------------------------
int CySocket::get_accept_port(void)
{
return (int)ntohs(addr.sin_port);
int CySocket::get_accept_port(void) {
return (int) ntohs(addr.sin_port);
}
//-----------------------------------------------------------------------------
void CySocket::setAddr(sockaddr_in _addr)
{
void CySocket::setAddr(sockaddr_in _addr) {
addr = _addr;
}
//-----------------------------------------------------------------------------
// Set Socket Option (return = false = error)
//-----------------------------------------------------------------------------
bool CySocket::set_option(int typ, int option)
{
bool CySocket::set_option(int typ, int option) {
int on = 1;
return (setsockopt(sock, typ, option, (char *)&on, sizeof(on)) >= 0);
return (setsockopt(sock, typ, option, (char *) &on, sizeof(on)) >= 0);
}
//-----------------------------------------------------------------------------
// Set Re-Use Option for Port.
//-----------------------------------------------------------------------------
void CySocket::set_reuse_port()
{
void CySocket::set_reuse_port() {
#ifdef SO_REUSEPORT
if(!set_option(SOL_SOCKET, SO_REUSEPORT))
dperror("setsockopt(SO_REUSEPORT)\n");
dperror("setsockopt(SO_REUSEPORT)\n");
#endif
}
//-----------------------------------------------------------------------------
// Set Re-Use Option for Address.
//-----------------------------------------------------------------------------
void CySocket::set_reuse_addr()
{
void CySocket::set_reuse_addr() {
#ifdef SO_REUSEADDR
if(!set_option(SOL_SOCKET, SO_REUSEADDR))
dperror("setsockopt(SO_REUSEADDR)\n");
dperror("setsockopt(SO_REUSEADDR)\n");
#endif
}
//-----------------------------------------------------------------------------
// Set Keep-Alive Option for Socket.
//-----------------------------------------------------------------------------
void CySocket::set_keep_alive()
{
void CySocket::set_keep_alive() {
#ifdef SO_KEEPALIVE
if(!set_option(SOL_SOCKET, SO_KEEPALIVE))
dperror("setsockopt(SO_KEEPALIVE)\n");
dperror("setsockopt(SO_KEEPALIVE)\n");
#endif
}
//-----------------------------------------------------------------------------
// Set Keep-Alive Option for Socket.
//-----------------------------------------------------------------------------
void CySocket::set_tcp_nodelay()
{
void CySocket::set_tcp_nodelay() {
#ifdef TCP_NODELAY
if(!set_option(IPPROTO_TCP, TCP_NODELAY))
dperror("setsockopt(SO_KEEPALIVE)\n");
dperror("setsockopt(SO_KEEPALIVE)\n");
#endif
}
//=============================================================================
@@ -280,37 +263,34 @@ void CySocket::set_tcp_nodelay()
//-----------------------------------------------------------------------------
// Read a buffer (normal or SSL)
//-----------------------------------------------------------------------------
int CySocket::Read(char *buffer, unsigned int length)
{
int CySocket::Read(char *buffer, unsigned int length) {
#ifdef Y_CONFIG_USE_OPEN_SSL
if(isSSLSocket)
return SSL_read(ssl, buffer, length);
return SSL_read(ssl, buffer, length);
else
#endif
return ::read(sock, buffer, length);
return ::read(sock, buffer, length);
}
//-----------------------------------------------------------------------------
// Send a buffer (normal or SSL)
//-----------------------------------------------------------------------------
int CySocket::Send(char const *buffer, unsigned int length)
{
int CySocket::Send(char const *buffer, unsigned int length) {
unsigned int len = 0;
#ifdef Y_CONFIG_USE_OPEN_SSL
if(isSSLSocket)
len = SSL_write(ssl, buffer, length);
len = SSL_write(ssl, buffer, length);
else
#endif
len = ::send(sock, buffer, length, MSG_NOSIGNAL);
if(len > 0)
len = ::send(sock, buffer, length, MSG_NOSIGNAL);
if (len > 0)
BytesSend += len;
return len;
}
//-----------------------------------------------------------------------------
// Check if Socket was closed by client
//-----------------------------------------------------------------------------
bool CySocket::CheckSocketOpen()
{
char buffer[32]={0};
bool CySocket::CheckSocketOpen() {
char buffer[32] = { 0 };
#ifdef CONFIG_SYSTEM_CYGWIN
return !(recv(sock, buffer, sizeof(buffer), MSG_PEEK | MSG_NOSIGNAL) == 0);
@@ -327,9 +307,8 @@ bool CySocket::CheckSocketOpen()
// BASIC Send File over Socket for FILE*
// fd is an opened FILE-Descriptor
//-----------------------------------------------------------------------------
int CySocket::SendFile(int filed)
{
if(!isValid)
int CySocket::SendFile(int filed) {
if (!isValid)
return false;
#ifdef Y_CONFIG_HAVE_SENDFILE
// does not work with SSL !!!
@@ -339,23 +318,21 @@ int CySocket::SendFile(int filed)
if((written = ::sendfile(sock,filed,&start,end)) == -1)
{
perror("sendfile failed\n");
return false;
return false;
}
else
BytesSend += written;
BytesSend += written;
#else
char sbuf[1024];
unsigned int r=0;
while ((r=read(filed, sbuf, 1024)) > 0)
{
if (Send(sbuf, r) < 0)
{
unsigned int r = 0;
while ((r = read(filed, sbuf, 1024)) > 0) {
if (Send(sbuf, r) < 0) {
perror("sendfile failed\n");
return false;
}
}
return false;
}
}
#endif // Y_CONFIG_HAVE_SENDFILE
log_level_printf(9,"<Sock:SendFile>: Bytes:%ld\n", BytesSend);
log_level_printf(9, "<Sock:SendFile>: Bytes:%ld\n", BytesSend);
return true;
}
//-----------------------------------------------------------------------------
@@ -365,107 +342,100 @@ int CySocket::SendFile(int filed)
// fd is an opened FILE-Descriptor
//-----------------------------------------------------------------------------
//TODO: Write upload Progress Informations into a file
unsigned int CySocket::ReceiveFileGivenLength(int filed, unsigned int _length)
{
unsigned int CySocket::ReceiveFileGivenLength(int filed, unsigned int _length) {
unsigned int _readbytes = 0;
char buffer[RECEIVE_BLOCK_LEN];
int retries=0;
int retries = 0;
do
{
do {
// check bytes in Socket buffer
u_long readarg = 0;
#ifdef Y_CONFIG_USE_OPEN_SSL
if(isSSLSocket)
readarg = RECEIVE_BLOCK_LEN;
readarg = RECEIVE_BLOCK_LEN;
else
#endif
{
if(ioctl(sock, FIONREAD, &readarg) != 0)// How many bytes avaiable on socket?
break;
if(readarg > RECEIVE_BLOCK_LEN) // enough bytes to read
readarg = RECEIVE_BLOCK_LEN; // read only given length
if (ioctl(sock, FIONREAD, &readarg) != 0)// How many bytes avaiable on socket?
break;
if (readarg > RECEIVE_BLOCK_LEN) // enough bytes to read
readarg = RECEIVE_BLOCK_LEN; // read only given length
}
if(readarg == 0) // nothing to read: sleep
{
retries++;
if(retries >NON_BLOCKING_MAX_RETRIES)
break;
sleep(1);
}
else
{
if (readarg == 0) // nothing to read: sleep
{
retries++;
if (retries > NON_BLOCKING_MAX_RETRIES)
break;
sleep(1);
} else {
int bytes_gotten = Read(buffer, readarg);
if(bytes_gotten == -1 && errno == EINTR)// non-blocking
continue;
if(bytes_gotten <= 0) // ERROR Code gotten or Conection closed by peer
if (bytes_gotten == -1 && errno == EINTR)// non-blocking
continue;
if (bytes_gotten <= 0) // ERROR Code gotten or Conection closed by peer
{
isValid = false;
break;
}
_readbytes += bytes_gotten;
if (write(filed, buffer, bytes_gotten) != bytes_gotten)
{
if (write(filed, buffer, bytes_gotten) != bytes_gotten) {
perror("write file failed\n");
return 0;
}
retries = 0;
if(bytes_gotten < NON_BLOCKING_TRY_BYTES) // to few bytes gotten: sleep
sleep(1);
}
log_level_printf(8,"Receive Block length:%d all:%d\n",_readbytes, _length);
}
while(_readbytes + RECEIVE_BLOCK_LEN < _length);
return 0;
}
retries = 0;
if (bytes_gotten < NON_BLOCKING_TRY_BYTES) // to few bytes gotten: sleep
sleep(1);
}
log_level_printf(8, "Receive Block length:%d all:%d\n", _readbytes,
_length);
} while (_readbytes + RECEIVE_BLOCK_LEN < _length);
return _readbytes;
}
//-----------------------------------------------------------------------------
// read all data avaiable on Socket
//-----------------------------------------------------------------------------
std::string CySocket::ReceiveBlock()
{
std::string CySocket::ReceiveBlock() {
std::string result = "";
char buffer[RECEIVE_BLOCK_LEN];
if(!isValid || !isOpened)
if (!isValid || !isOpened)
return "";
// signal(SIGALRM, ytimeout);
// signal(SIGALRM, ytimeout);
alarm(1);
while(true)
{
while (true) {
// check bytes in Socket buffer
u_long readarg = 0;
#ifdef Y_CONFIG_USE_OPEN_SSL
if(isSSLSocket)
readarg = RECEIVE_BLOCK_LEN;
readarg = RECEIVE_BLOCK_LEN;
else
#endif
// determine bytes that can be read
{
if(ioctl(sock, FIONREAD, &readarg) != 0)
break;
if(readarg == 0) // nothing to read
break;
if(readarg > RECEIVE_BLOCK_LEN) // need more loops
readarg = RECEIVE_BLOCK_LEN;
if (ioctl(sock, FIONREAD, &readarg) != 0)
break;
if (readarg == 0) // nothing to read
break;
if (readarg > RECEIVE_BLOCK_LEN) // need more loops
readarg = RECEIVE_BLOCK_LEN;
}
// Read data
int bytes_gotten = Read(buffer, readarg);
if(bytes_gotten == -1 && errno == EINTR)// non-blocking
continue;
if(bytes_gotten <= 0) // ERROR Code gotten or Conection closed by peer
if (bytes_gotten == -1 && errno == EINTR)// non-blocking
continue;
if (bytes_gotten <= 0) // ERROR Code gotten or Conection closed by peer
{
isValid = false;
break;
}
result.append(buffer, bytes_gotten);
if((u_long)bytes_gotten < readarg) // no more bytes
if ((u_long) bytes_gotten < readarg) // no more bytes
break;
}
alarm(0);
signal(SIGALRM,SIG_IGN);
signal(SIGALRM, SIG_IGN);
return result;
}
@@ -473,28 +443,23 @@ std::string CySocket::ReceiveBlock()
// Read on line (Ends with LF) or maximum MAX_LINE_BUFFER chars
// Result Contains [CR]LF!
//-----------------------------------------------------------------------------
std::string CySocket::ReceiveLine()
{
std::string CySocket::ReceiveLine() {
char buffer[MAX_LINE_BUFFER];
int bytes_gotten = 0;
std::string result="";
std::string result = "";
while(true)
{
while (true) {
// read one char
if(Read(buffer+bytes_gotten, 1) == 1)
{
if(buffer[bytes_gotten] == '\n')
if (Read(buffer + bytes_gotten, 1) == 1) {
if (buffer[bytes_gotten] == '\n')
break;
}
else
{
} else {
isValid = false;
break;
}
if(bytes_gotten < MAX_LINE_BUFFER-1)
bytes_gotten ++;
if (bytes_gotten < MAX_LINE_BUFFER - 1)
bytes_gotten++;
else
break;
}

View File

@@ -30,21 +30,20 @@
//=============================================================================
// Initialization of static variables
//=============================================================================
bool CWebserver::is_threading = true;
pthread_mutex_t CWebserver::mutex = PTHREAD_MUTEX_INITIALIZER;;
bool CWebserver::is_threading = true;
pthread_mutex_t CWebserver::mutex = PTHREAD_MUTEX_INITIALIZER;
;
//=============================================================================
// Constructor & Destructor & Initialization
//=============================================================================
CWebserver::CWebserver()
{
CWebserver::CWebserver() {
terminate = false;
for(int i=0;i<HTTPD_MAX_CONNECTIONS;i++)
{
Connection_Thread_List[i] = (pthread_t)NULL;
for (int i = 0; i < HTTPD_MAX_CONNECTIONS; i++) {
Connection_Thread_List[i] = (pthread_t) NULL;
SocketList[i] = NULL;
}
FD_ZERO(&master); // initialize FD_SETs
FD_ZERO(&master); // initialize FD_SETs
FD_ZERO(&read_fds);
fdmax = 0;
open_connections = 0;
@@ -52,13 +51,11 @@ CWebserver::CWebserver()
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#endif
port=80;
port = 80;
}
//-----------------------------------------------------------------------------
CWebserver::~CWebserver()
{
CWebserver::~CWebserver() {
listenSocket.close();
}
//=============================================================================
@@ -118,10 +115,8 @@ CWebserver::~CWebserver()
//=============================================================================
#define MAX_TIMEOUTS_TO_CLOSE 10
#define MAX_TIMEOUTS_TO_TEST 100
bool CWebserver::run(void)
{
if(!listenSocket.listen(port, HTTPD_MAX_CONNECTIONS))
{
bool CWebserver::run(void) {
if (!listenSocket.listen(port, HTTPD_MAX_CONNECTIONS)) {
dperror("Socket cannot bind and listen. Abort.\n");
return false;
}
@@ -129,31 +124,31 @@ bool CWebserver::run(void)
// initialize values for select
int listener = listenSocket.get_socket();// Open Listener
struct timeval tv; // timeout struct
FD_SET(listener, &master); // add the listener to the master set
fdmax = listener; // init max fd
fcntl(listener, F_SETFD , O_NONBLOCK); // listener master socket non-blocking
int timeout_counter = 0; // Counter for Connection Timeout checking
int test_counter = 0; // Counter for Testing long running Connections
struct timeval tv; // timeout struct
FD_SET(listener, &master); // add the listener to the master set
fdmax = listener; // init max fd
fcntl(listener, F_SETFD , O_NONBLOCK); // listener master socket non-blocking
int timeout_counter = 0; // Counter for Connection Timeout checking
int test_counter = 0; // Counter for Testing long running Connections
// main Webserver Loop
while(!terminate)
{
// select : init vars
read_fds = master; // copy it
tv.tv_usec = 10000; // microsec: Timeout for select ! for re-use / keep-alive socket
tv.tv_sec = 0; // seconds
int fd = -1;
read_fds = master; // copy it
tv.tv_usec = 10000; // microsec: Timeout for select ! for re-use / keep-alive socket
tv.tv_sec = 0; // seconds
int fd = -1;
// select : wait for socket activity
if(open_connections <= 0) // No open Connection. Wait in select.
fd = select(fdmax+1,&read_fds, NULL, NULL, NULL);// wait for socket activity
if(open_connections <= 0) // No open Connection. Wait in select.
fd = select(fdmax+1,&read_fds, NULL, NULL, NULL);// wait for socket activity
else
fd = select(fdmax+1,&read_fds, NULL, NULL, &tv);// wait for socket activity or timeout
fd = select(fdmax+1,&read_fds, NULL, NULL, &tv);// wait for socket activity or timeout
// too much to do : sleep
if(open_connections >= HTTPD_MAX_CONNECTIONS-1)
sleep(1);
sleep(1);
// Socket Error?
if(fd == -1 && errno != EINTR)
@@ -169,9 +164,9 @@ bool CWebserver::run(void)
if(++test_counter >= MAX_TIMEOUTS_TO_TEST)
{
for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++)
if(SocketList[j] != NULL) // here is a socket
log_level_printf(2,"FD-TEST sock:%d handle:%d open:%d\n",SocketList[j]->get_socket(),
SocketList[j]->handling,SocketList[j]->isOpened);
if(SocketList[j] != NULL) // here is a socket
log_level_printf(2,"FD-TEST sock:%d handle:%d open:%d\n",SocketList[j]->get_socket(),
SocketList[j]->handling,SocketList[j]->isOpened);
test_counter=0;
}
// some connection closing previous missed?
@@ -180,7 +175,7 @@ bool CWebserver::run(void)
CloseConnectionSocketsByTimeout();
timeout_counter=0;
}
continue; // main loop again
continue; // main loop again
}
//----------------------------------------------------------------------------------------
// Check all observed descriptors & check new or re-use Connections
@@ -188,48 +183,48 @@ bool CWebserver::run(void)
for(int i = listener; i <= fdmax; i++)
{
int slot = -1;
if(FD_ISSET(i, &read_fds)) // Socket observed?
if(FD_ISSET(i, &read_fds)) // Socket observed?
{ // we got one!!
if (i == listener) // handle new connections
slot = AcceptNewConnectionSocket();
else // Connection on an existing open Socket = reuse (keep-alive)
if (i == listener) // handle new connections
slot = AcceptNewConnectionSocket();
else // Connection on an existing open Socket = reuse (keep-alive)
{
slot = SL_GetExistingSocket(i);
if(slot>=0)
log_level_printf(2,"FD: reuse con fd:%d\n",SocketList[slot]->get_socket());
log_level_printf(2,"FD: reuse con fd:%d\n",SocketList[slot]->get_socket());
}
// prepare Connection handling
if(slot>=0)
if(SocketList[slot] != NULL && !SocketList[slot]->handling && SocketList[slot]->isValid)
{
log_level_printf(2,"FD: START CON HANDLING con fd:%d\n",SocketList[slot]->get_socket());
FD_CLR(SocketList[slot]->get_socket(), &master); // remove from master set
SocketList[slot]->handling = true; // prepares for thread-handling
if(!handle_connection(SocketList[slot]))// handle this activity
{ // Can not handle more threads
char httpstr[]=HTTP_PROTOCOL " 503 Service Unavailable\r\n\r\n";
SocketList[slot]->Send(httpstr, strlen(httpstr));
SL_CloseSocketBySlot(slot);
}
if(SocketList[slot] != NULL && !SocketList[slot]->handling && SocketList[slot]->isValid)
{
log_level_printf(2,"FD: START CON HANDLING con fd:%d\n",SocketList[slot]->get_socket());
FD_CLR(SocketList[slot]->get_socket(), &master); // remove from master set
SocketList[slot]->handling = true; // prepares for thread-handling
if(!handle_connection(SocketList[slot]))// handle this activity
{ // Can not handle more threads
char httpstr[]=HTTP_PROTOCOL " 503 Service Unavailable\r\n\r\n";
SocketList[slot]->Send(httpstr, strlen(httpstr));
SL_CloseSocketBySlot(slot);
}
}
}
}// for
CloseConnectionSocketsByTimeout(); // Check connections to close
CloseConnectionSocketsByTimeout(); // Check connections to close
}//while
#else
while(!terminate)
{
while (!terminate) {
CySocket *newConnectionSock;
if(!(newConnectionSock = listenSocket.accept() )) //Now: Blocking wait
if (!(newConnectionSock = listenSocket.accept())) //Now: Blocking wait
{
dperror("Socket accept error. Continue.\n");
continue;
}
log_level_printf(3,"Socket connect from %s\n", (listenSocket.get_client_ip()).c_str() );
log_level_printf(3, "Socket connect from %s\n",
(listenSocket.get_client_ip()).c_str());
#ifdef Y_CONFIG_USE_OPEN_SSL
if(Cyhttpd::ConfigList["SSL"]=="true")
newConnectionSock->initAsSSL(); // make it a SSL-socket
if(Cyhttpd::ConfigList["SSL"]=="true")
newConnectionSock->initAsSSL(); // make it a SSL-socket
#endif
handle_connection(newConnectionSock);
}
@@ -242,13 +237,12 @@ bool CWebserver::run(void)
//-----------------------------------------------------------------------------
// Accept new Connection
//-----------------------------------------------------------------------------
int CWebserver::AcceptNewConnectionSocket()
{
int CWebserver::AcceptNewConnectionSocket() {
int slot = -1;
CySocket *connectionSock = NULL;
int newfd;
if(!(connectionSock = listenSocket.accept() )) // Blocking wait
if (!(connectionSock = listenSocket.accept())) // Blocking wait
{
dperror("Socket accept error. Continue.\n");
delete connectionSock;
@@ -256,24 +250,22 @@ int CWebserver::AcceptNewConnectionSocket()
}
#ifdef Y_CONFIG_USE_OPEN_SSL
if(Cyhttpd::ConfigList["SSL"]=="true")
connectionSock->initAsSSL(); // make it a SSL-socket
connectionSock->initAsSSL(); // make it a SSL-socket
#endif
log_level_printf(2,"FD: new con fd:%d on port:%d\n",connectionSock->get_socket(), connectionSock->get_accept_port());
log_level_printf(2, "FD: new con fd:%d on port:%d\n",
connectionSock->get_socket(), connectionSock->get_accept_port());
// Add Socket to List
slot = SL_GetFreeSlot();
if(slot < 0)
{
if (slot < 0) {
connectionSock->close();
aprintf("No free Slot in SocketList found. Open:%d\n",open_connections);
}
else
{
SocketList[slot] = connectionSock; // put it to list
fcntl(connectionSock->get_socket() , F_SETFD , O_NONBLOCK); // set non-blocking
open_connections++; // count open connectins
aprintf("No free Slot in SocketList found. Open:%d\n", open_connections);
} else {
SocketList[slot] = connectionSock; // put it to list
fcntl(connectionSock->get_socket(), F_SETFD, O_NONBLOCK); // set non-blocking
open_connections++; // count open connectins
newfd = connectionSock->get_socket();
if (newfd > fdmax) // keep track of the maximum fd
if (newfd > fdmax) // keep track of the maximum fd
fdmax = newfd;
}
return slot;
@@ -282,12 +274,11 @@ int CWebserver::AcceptNewConnectionSocket()
//-----------------------------------------------------------------------------
// Get Index for Socket from SocketList
//-----------------------------------------------------------------------------
int CWebserver::SL_GetExistingSocket(SOCKET sock)
{
int CWebserver::SL_GetExistingSocket(SOCKET sock) {
int slot = -1;
for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++)
if(SocketList[j] != NULL // here is a socket
&& SocketList[j]->get_socket() == sock) // we know that socket
for (int j = 0; j < HTTPD_MAX_CONNECTIONS; j++)
if (SocketList[j] != NULL // here is a socket
&& SocketList[j]->get_socket() == sock) // we know that socket
{
slot = j;
break;
@@ -297,11 +288,10 @@ int CWebserver::SL_GetExistingSocket(SOCKET sock)
//-----------------------------------------------------------------------------
// Get Index for free Slot in SocketList
//-----------------------------------------------------------------------------
int CWebserver::SL_GetFreeSlot()
{
int CWebserver::SL_GetFreeSlot() {
int slot = -1;
for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++)
if(SocketList[j] == NULL) // here is a free slot
for (int j = 0; j < HTTPD_MAX_CONNECTIONS; j++)
if (SocketList[j] == NULL) // here is a free slot
{
slot = j;
break;
@@ -312,67 +302,65 @@ int CWebserver::SL_GetFreeSlot()
//-----------------------------------------------------------------------------
// Look for Sockets to close
//-----------------------------------------------------------------------------
void CWebserver::CloseConnectionSocketsByTimeout()
{
void CWebserver::CloseConnectionSocketsByTimeout() {
CySocket *connectionSock = NULL;
for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++)
if(SocketList[j] != NULL // here is a socket
&& !SocketList[j]->handling) // it is not handled
{
connectionSock = SocketList[j];
SOCKET thisSocket = connectionSock->get_socket();
bool shouldClose = true;
if(!connectionSock->isValid) // If not valid -> close
; // close
else if(connectionSock->tv_start_waiting.tv_sec != 0 || SocketList[j]->tv_start_waiting.tv_usec != 0)
{ // calculate keep-alive timeout
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
int64_t tdiff = ((tv_now.tv_sec - connectionSock->tv_start_waiting.tv_sec) * 1000000
+ (tv_now.tv_usec - connectionSock->tv_start_waiting.tv_usec));
if(tdiff < HTTPD_KEEPALIVE_TIMEOUT || tdiff <0)
shouldClose = false;
}
if(shouldClose)
for (int j = 0; j < HTTPD_MAX_CONNECTIONS; j++)
if (SocketList[j] != NULL // here is a socket
&& !SocketList[j]->handling) // it is not handled
{
log_level_printf(2,"FD: close con Timeout fd:%d\n",thisSocket);
SL_CloseSocketBySlot(j);
connectionSock = SocketList[j];
SOCKET thisSocket = connectionSock->get_socket();
bool shouldClose = true;
if (!connectionSock->isValid) // If not valid -> close
; // close
else if (connectionSock->tv_start_waiting.tv_sec != 0
|| SocketList[j]->tv_start_waiting.tv_usec != 0) { // calculate keep-alive timeout
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
int64_t tdiff = ((tv_now.tv_sec
- connectionSock->tv_start_waiting.tv_sec) * 1000000
+ (tv_now.tv_usec
- connectionSock->tv_start_waiting.tv_usec));
if (tdiff < HTTPD_KEEPALIVE_TIMEOUT || tdiff < 0)
shouldClose = false;
}
if (shouldClose) {
log_level_printf(2, "FD: close con Timeout fd:%d\n", thisSocket);
SL_CloseSocketBySlot(j);
}
}
}
}
//-----------------------------------------------------------------------------
// Add Socket fd to FD_SET again (for select-handling)
// Add start-time for waiting for connection re-use / keep-alive
//-----------------------------------------------------------------------------
void CWebserver::addSocketToMasterSet(SOCKET fd)
{
int slot = SL_GetExistingSocket(fd); // get slot/index for fd
if(slot<0)
void CWebserver::addSocketToMasterSet(SOCKET fd) {
int slot = SL_GetExistingSocket(fd); // get slot/index for fd
if (slot < 0)
return;
log_level_printf(2,"FD: add to master fd:%d\n",fd);
struct timeval tv_now;
struct timezone tz_now;
log_level_printf(2, "FD: add to master fd:%d\n", fd);
struct timeval tv_now;
struct timezone tz_now;
gettimeofday(&tv_now, &tz_now);
SocketList[slot]->tv_start_waiting = tv_now; // add keep-alive wait time
FD_SET(fd, &master); // add fd to select-master-set
SocketList[slot]->tv_start_waiting = tv_now; // add keep-alive wait time
FD_SET(fd, &master); // add fd to select-master-set
}
//-----------------------------------------------------------------------------
// Close (FD_SET handled) Socket
// Clear it from SocketList
//-----------------------------------------------------------------------------
void CWebserver::SL_CloseSocketBySlot(int slot)
{
open_connections--; // count open connections
if(SocketList[slot] == NULL)
void CWebserver::SL_CloseSocketBySlot(int slot) {
open_connections--; // count open connections
if (SocketList[slot] == NULL)
return;
SocketList[slot]->handling = false; // no handling anymore
SocketList[slot]->handling = false; // no handling anymore
FD_CLR(SocketList[slot]->get_socket(), &master);// remove from master set
SocketList[slot]->close(); // close the socket
delete SocketList[slot]; // destroy ySocket
SocketList[slot] = NULL; // free in list
SocketList[slot]->close(); // close the socket
delete SocketList[slot]; // destroy ySocket
SocketList[slot] = NULL; // free in list
}
//=============================================================================
@@ -381,38 +369,34 @@ void CWebserver::SL_CloseSocketBySlot(int slot)
//-----------------------------------------------------------------------------
// Check if IP is allowed for keep-alive
//-----------------------------------------------------------------------------
bool CWebserver::CheckKeepAliveAllowedByIP(std::string client_ip)
{
pthread_mutex_lock( &mutex );
bool CWebserver::CheckKeepAliveAllowedByIP(std::string client_ip) {
pthread_mutex_lock(&mutex);
bool do_keep_alive = true;
CStringVector::const_iterator it = conf_no_keep_alive_ips.begin();
while(it != conf_no_keep_alive_ips.end())
{
if(trim(*it) == client_ip)
while (it != conf_no_keep_alive_ips.end()) {
if (trim(*it) == client_ip)
do_keep_alive = false;
it++;
}
pthread_mutex_unlock( &mutex );
pthread_mutex_unlock(&mutex);
return do_keep_alive;
}
//-----------------------------------------------------------------------------
// Set Entry(number)to NULL in Threadlist
//-----------------------------------------------------------------------------
void CWebserver::clear_Thread_List_Number(int number)
{
pthread_mutex_lock( &mutex );
if(number <HTTPD_MAX_CONNECTIONS)
Connection_Thread_List[number] = (pthread_t)NULL;
void CWebserver::clear_Thread_List_Number(int number) {
pthread_mutex_lock(&mutex);
if (number < HTTPD_MAX_CONNECTIONS)
Connection_Thread_List[number] = (pthread_t) NULL;
CloseConnectionSocketsByTimeout();
pthread_mutex_unlock( &mutex );
pthread_mutex_unlock(&mutex);
}
//-----------------------------------------------------------------------------
// A new Connection is established to newSock. Create a (threaded) Connection
// and handle the Request.
//-----------------------------------------------------------------------------
bool CWebserver::handle_connection(CySocket *newSock)
{
bool CWebserver::handle_connection(CySocket *newSock) {
void *WebThread(void *args); //forward declaration
// create arguments
@@ -432,56 +416,56 @@ bool CWebserver::handle_connection(CySocket *newSock)
pthread_mutex_lock( &mutex );
// look for free Thread slot
for(int i=0;i<HTTPD_MAX_CONNECTIONS;i++)
if(Connection_Thread_List[i] == (pthread_t)NULL)
{
index = i;
break;
}
if(Connection_Thread_List[i] == (pthread_t)NULL)
{
index = i;
break;
}
if(index == -1)
{
dperror("Maximum Connection-Threads reached\n");
pthread_mutex_unlock( &mutex );
return false;
}
newConn->thread_number = index; //remember Index of Thread slot (for clean up)
newConn->thread_number = index; //remember Index of Thread slot (for clean up)
// Create an orphan Thread. It is not joinable anymore
pthread_mutex_unlock( &mutex );
// start connection Thread
if(pthread_create(&Connection_Thread_List[index], &attr, WebThread, (void *)newConn) != 0)
dperror("Could not create Connection-Thread\n");
dperror("Could not create Connection-Thread\n");
}
else // non threaded
else // non threaded
#endif
WebThread((void *)newConn);
WebThread((void *) newConn);
return ((index != -1) || !is_threading);
}
//-------------------------------------------------------------------------
// Webserver-Thread for each connection
//-------------------------------------------------------------------------
void *WebThread(void *args)
{
void *WebThread(void *args) {
CWebserverConnection *con;
CWebserver *ws;
TWebserverConnectionArgs *newConn = (TWebserverConnectionArgs *) args;
ws = newConn->WebserverBackref;
bool is_threaded = newConn->is_treaded;
if(is_threaded)
log_level_printf(1,"++ Thread 0x06%X gestartet\n", (int) pthread_self());
if (is_threaded)
log_level_printf(1, "++ Thread 0x06%X gestartet\n",
(int) pthread_self());
if (!newConn) {
dperror("WebThread called without arguments!\n");
if(newConn->is_treaded)
pthread_exit(NULL);
if (newConn->is_treaded)
pthread_exit( NULL);
}
// (1) create & init Connection
con = new CWebserverConnection(ws);
con->Request.UrlData["clientaddr"] = newConn->ySock->get_client_ip(); // TODO:here?
con->sock = newConn->ySock; // give socket reference
newConn->ySock->handling = true; // dont handle this socket now be webserver main loop
con->sock = newConn->ySock; // give socket reference
newConn->ySock->handling = true; // dont handle this socket now be webserver main loop
// (2) handle the connection
con->HandleConnection();
@@ -489,25 +473,24 @@ void *WebThread(void *args)
// (3) end connection handling
#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE
if(!con->keep_alive)
log_level_printf(2,"FD SHOULD CLOSE sock:%d!!!\n",con->sock->get_socket());
log_level_printf(2,"FD SHOULD CLOSE sock:%d!!!\n",con->sock->get_socket());
else
ws->addSocketToMasterSet(con->sock->get_socket()); // add to master set
ws->addSocketToMasterSet(con->sock->get_socket()); // add to master set
#else
delete newConn->ySock;
#endif
if(!con->keep_alive)
if (!con->keep_alive)
con->sock->isValid = false;
con->sock->handling = false; // socket can be handled by webserver main loop (select) again
con->sock->handling = false; // socket can be handled by webserver main loop (select) again
// (4) end thread
delete con;
int thread_number = newConn->thread_number;
delete newConn;
if(is_threaded)
{
log_level_printf(1,"-- Thread 0x06%X beendet\n",(int)pthread_self());
if (is_threaded) {
log_level_printf(1, "-- Thread 0x06%X beendet\n", (int) pthread_self());
ws->clear_Thread_List_Number(thread_number);
pthread_exit(NULL);
pthread_exit( NULL);
}
return NULL;
}