version 1.1.2.3, 2013/09/18 06:29:19
|
version 1.2.2.2, 2014/03/12 22:35:06
|
|
|
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
#include <time.h> |
#include <Pegasus/Common/AutoPtr.h> | #include <Pegasus/Common/AutoPtr.h> |
#include <Pegasus/Common/HTTPConnection.h> | #include <Pegasus/Common/HTTPConnection.h> |
#include <Pegasus/Common/Logger.h> | #include <Pegasus/Common/Logger.h> |
|
|
| |
#include <Pegasus/WebServer/WebProcessor.h> | #include <Pegasus/WebServer/WebProcessor.h> |
#include <Pegasus/WebServer/WebServer.h> | #include <Pegasus/WebServer/WebServer.h> |
#include <Pegasus/WebServer/WebRequest.h> |
|
#include <Pegasus/WebServer/WebConfig.h> |
|
| |
| |
PEGASUS_USING_STD; | PEGASUS_USING_STD; |
|
|
const String WebProcessor::DEFLATE = "deflate"; | const String WebProcessor::DEFLATE = "deflate"; |
| |
| |
|
|
|
|
WebProcessor::WebProcessor(WebServer* const webServer) | WebProcessor::WebProcessor(WebServer* const webServer) |
: _webConfig(), |
: _webConfig(), _webServer(webServer) |
_webServer(webServer) |
|
{ | { |
} | } |
| |
|
|
{ | { |
} | } |
| |
|
|
void WebProcessor::handleWebRequest(WebRequest* request) | void WebProcessor::handleWebRequest(WebRequest* request) |
{ | { |
PEG_METHOD_ENTER(TRC_WEBSERVER, |
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::handleWebRequest()"); |
"WebProcessor::handleWebRequest(WebRequest* request)"); |
|
| |
if (!request) | if (!request) |
{ | { |
|
|
} | } |
| |
Uint32 queueId = request->getQueueId(); | Uint32 queueId = request->getQueueId(); |
|
|
|
|
// check protocol version | // check protocol version |
if (String::equal(request->httpVersion, "") |
if( String::equal(request->httpVersion, "") || |
|| PEG_NOT_FOUND == request->httpVersion.find("HTTP/")) |
PEG_NOT_FOUND == request->httpVersion.find("HTTP/")) |
{// bad request | {// bad request |
_sendError( |
_sendError( HTTP_STATUSCODE_BADREQUEST, queueId, |
HTTP_STATUSCODE_BADREQUEST, |
"Malformed Http, http version string not found!"); |
queueId, |
|
"The request has a bad syntax, http version string not found!"); |
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
return; | return; |
} | } |
|
|
"(WebRequest* webRequest) - httpVersion='%s'", | "(WebRequest* webRequest) - httpVersion='%s'", |
(const char*)request->httpVersion.getCString())); | (const char*)request->httpVersion.getCString())); |
| |
String* method; |
const char* method = NULL; |
// check HTTPmethod | // check HTTPmethod |
if (request->httpMethod == HTTP_METHOD_GET) | if (request->httpMethod == HTTP_METHOD_GET) |
{ | { |
method = new String("GET"); |
method = "GET"; |
} | } |
else if (request->httpMethod == HTTP_METHOD_HEAD) | else if (request->httpMethod == HTTP_METHOD_HEAD) |
{ | { |
method = new String("HEAD"); |
method = "HEAD"; |
} | } |
else | else |
{// handle bad request (method not allowed) | {// handle bad request (method not allowed) |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
return; | return; |
} | } |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest" |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"Requested httpMethod= %s",method)); |
"(WebRequest* webRequest) - httpMethod='%s'", |
|
(const char*)method->getCString())); |
|
| |
// get absolute filename from URI | // get absolute filename from URI |
String fileName; | String fileName; |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
return; | return; |
} | } |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest" |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"URI maps to valid/allowed " |
"(WebRequest* webRequest) - URI maps to valid/allowed " |
|
"fileName='%s'", | "fileName='%s'", |
(const char*)fileName.getCString())); | (const char*)fileName.getCString())); |
| |
// get and check contentType for requested file | // get and check contentType for requested file |
String contentType; |
|
/* RFC 2616, section 10.4.7 '406 Not Acceptable' | /* RFC 2616, section 10.4.7 '406 Not Acceptable' |
* | * |
* Note: HTTP/1.1 servers are allowed to return responses which are | * Note: HTTP/1.1 servers are allowed to return responses which are |
|
|
* the delivered file with a header line in the response including a | * the delivered file with a header line in the response including a |
* mime-type definition it does not know. | * mime-type definition it does not know. |
*/ | */ |
|
String contentType; |
if (!_getContentType(fileName, contentType)) | if (!_getContentType(fileName, contentType)) |
{ | { |
// no contentType known for requested file(-extension) | // no contentType known for requested file(-extension) |
_sendError( | _sendError( |
HTTP_STATUSCODE_FORBIDDEN, |
HTTP_STATUSCODE_FORBIDDEN, queueId, |
queueId, |
|
"The requested file '" + fileName | "The requested file '" + fileName |
+ "' has an undefined content type. It will not be served!"); | + "' has an undefined content type. It will not be served!"); |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
return; | return; |
} | } |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest" |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4, |
"(WebRequest* webRequest) - response contentType='%s'", |
" Requested response contentType='%s'", |
(const char*)contentType.getCString())); | (const char*)contentType.getCString())); |
| |
/* is it a text based mime-type ? | /* is it a text based mime-type ? |
|
|
* There are text based mime-types which do not start with 'text/'. | * There are text based mime-types which do not start with 'text/'. |
*/ | */ |
Boolean isBinFile = String::compare(contentType.subString(0, 4), "text"); | Boolean isBinFile = String::compare(contentType.subString(0, 4), "text"); |
|
|
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest" | PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest" |
"(WebRequest* webRequest) - contentType is binary='%s'", | "(WebRequest* webRequest) - contentType is binary='%s'", |
((isBinFile)?"true":"false"))); |
(isBinFile ? "true" : "false" ))); |
| |
/* | /* |
* check requested encodings | * check requested encodings |
|
|
request->encodings, | request->encodings, |
const_cast<String&>(GZIP), | const_cast<String&>(GZIP), |
enc); | enc); |
|
|
if (statusCode != HTTP_STATUSCODE_OK) | if (statusCode != HTTP_STATUSCODE_OK) |
{ | { |
statusCode = _getRequestHeaderValue( |
statusCode = _getRequestHeaderValue( request->encodings, |
request->encodings, |
|
const_cast<String&>(DEFLATE), | const_cast<String&>(DEFLATE), |
enc); | enc); |
|
|
if (statusCode == HTTP_STATUSCODE_BADREQUEST) | if (statusCode == HTTP_STATUSCODE_BADREQUEST) |
{ | { |
_sendError( | _sendError( |
statusCode, | statusCode, |
queueId, | queueId, |
"Bad Syntax in header-parameter 'Accept-Encoding' !"); | "Bad Syntax in header-parameter 'Accept-Encoding' !"); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
return; | return; |
} | } |
|
|
//compress files bigger than 10KB, only | //compress files bigger than 10KB, only |
Boolean compressionFlag = String::equal(GZIP, enc) | Boolean compressionFlag = String::equal(GZIP, enc) |
|| String::equal(DEFLATE, enc); | || String::equal(DEFLATE, enc); |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest" |
|
|
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest" |
"(WebRequest* webRequest) - response encoding='%s', " | "(WebRequest* webRequest) - response encoding='%s', " |
"compressionFlag='%s'", | "compressionFlag='%s'", |
(const char*)enc.getCString(), | (const char*)enc.getCString(), |
(compressionFlag)?"true":"false")); | (compressionFlag)?"true":"false")); |
| |
PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL2,"WebServer::handleWebRequest" |
PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest" |
"(WebRequest* webRequest) - All Headers have been parsed and " | "(WebRequest* webRequest) - All Headers have been parsed and " |
"successfully validated."); | "successfully validated."); |
| |
|
|
HTTP_STATUSCODE_FORBIDDEN, | HTTP_STATUSCODE_FORBIDDEN, |
queueId, | queueId, |
"The requested file '" + fileName + "' is not accessible!"); | "The requested file '" + fileName + "' is not accessible!"); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
return; | return; |
} | } |
|
|
// end of headers | // end of headers |
_message << "\r\n"; | _message << "\r\n"; |
| |
PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL2,"WebServer::handleWebRequest" |
PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest" |
"(WebRequest* webRequest) - All response headers have been " |
"(WebRequest* webRequest) - All response headers have been written."); |
"written."); |
|
| |
/* | /* |
* Write Body | * Write Body |
|
|
| |
// create response message | // create response message |
HTTPMessage* response = new HTTPMessage(_message, queueId); | HTTPMessage* response = new HTTPMessage(_message, queueId); |
|
|
// set close connection flag | // set close connection flag |
response->setCloseConnect(true); | response->setCloseConnect(true); |
| |
|
|
String debugMsg, | String debugMsg, |
String additionalHeaderFields) | String additionalHeaderFields) |
{ | { |
Uint32 statusC = Uint32(statusCode); |
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_sendError()"); |
|
|
PEG_METHOD_ENTER(TRC_WEBSERVER, |
|
"WebProcessor::_sendError(Uint32 statusCode," |
|
" Uint32 queueId, String debugMsg)"); |
|
| |
|
Uint32 statusC = Uint32(statusCode); |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,"WebServer::_sendError" | PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,"WebServer::_sendError" |
"(Uint32 statusCode, Uint32 queueId, String debugMsg) - " | "(Uint32 statusCode, Uint32 queueId, String debugMsg) - " |
"statusCode: %d, QueueId: %d, debugMsg: %s", | "statusCode: %d, QueueId: %d, debugMsg: %s", |
|
|
| |
void WebProcessor::_sendRepsonse(HTTPMessage* response) | void WebProcessor::_sendRepsonse(HTTPMessage* response) |
{ | { |
PEG_METHOD_ENTER(TRC_WEBSERVER, |
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_sendRepsonse()"); |
"WebProcessor::_sendRepsonse(HTTPMessage* response)"); |
|
_webServer->handleResponse(response); | _webServer->handleResponse(response); |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
| |
String WebProcessor::getErrorPage(Uint32& statusCode, String& debugMsg) | String WebProcessor::getErrorPage(Uint32& statusCode, String& debugMsg) |
{ | { |
|
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::getErrorPage()"); |
String page = String("<html><head><title>"); | String page = String("<html><head><title>"); |
page.reserveCapacity(debugMsg.size() + 512);// 512 for the html-strings | page.reserveCapacity(debugMsg.size() + 512);// 512 for the html-strings |
page.append("Error"); | page.append("Error"); |
|
|
page.append(debugMsg); | page.append(debugMsg); |
#endif /* PEGASUS_DEBUG */ | #endif /* PEGASUS_DEBUG */ |
page.append("</body></html>\r\n"); | page.append("</body></html>\r\n"); |
|
|
|
PEG_METHOD_EXIT(); |
return page; | return page; |
} | } |
| |
| |
Uint32 WebProcessor::_getFileNameForURI(String& requestURI, String& absPath) | Uint32 WebProcessor::_getFileNameForURI(String& requestURI, String& absPath) |
{ | { |
PEG_METHOD_ENTER(TRC_WEBSERVER, |
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_getFileNameForURI()"); |
"WebProcessor::_getFileNameForURI(String& requestURI, " |
|
"String& absPath)"); |
|
| |
if (requestURI.size() == Uint32(0)) | if (requestURI.size() == Uint32(0)) |
{ | { |
|
|
| |
void WebProcessor::_writeTextBody(Buffer& _message, String& fileName) | void WebProcessor::_writeTextBody(Buffer& _message, String& fileName) |
{ | { |
|
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_writeTextBody()"); |
String line; | String line; |
ifstream infile(fileName.getCString()); | ifstream infile(fileName.getCString()); |
| |
|
|
_message << (const char*)line.getCString() << "\r\n"; | _message << (const char*)line.getCString() << "\r\n"; |
} | } |
infile.close(); | infile.close(); |
|
PEG_METHOD_EXIT(); |
} | } |
| |
| |
Boolean WebProcessor::_getContentType(String& fileName, String& contentType) | Boolean WebProcessor::_getContentType(String& fileName, String& contentType) |
{ | { |
PEG_METHOD_ENTER(TRC_WEBSERVER, |
PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_getContentType()"); |
"WebProcessor::_getContentType(String& fileName, " |
|
"String& contentType)"); |
|
| |
//find last dot in filename | //find last dot in filename |
int found = fileName.reverseFind('.'); | int found = fileName.reverseFind('.'); |
|
|
} | } |
String fileExtension = String(fileName.subString(found+1)); | String fileExtension = String(fileName.subString(found+1)); |
contentType.clear(); | contentType.clear(); |
Boolean result = _webConfig.getMimeTypes().lookup(fileExtension, |
Boolean rslt = _webConfig.getMimeTypes().lookup(fileExtension, contentType); |
contentType); |
|
| |
PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4, | PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4, |
"File extension is %s, contentType is %s", | "File extension is %s, contentType is %s", |
(const char*)fileExtension.getCString(), | (const char*)fileExtension.getCString(), |
(const char*)contentType.getCString())); | (const char*)contentType.getCString())); |
PEG_METHOD_EXIT(); |
|
| |
return result; |
PEG_METHOD_EXIT(); |
|
return rslt; |
} | } |
| |
| |