You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
7.0 KiB
238 lines
7.0 KiB
/***************************************************************************
|
|
* Copyright (C) 2005 by Joris Guisson *
|
|
* joris.guisson@gmail.com *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
***************************************************************************/
|
|
#include <qsocket.h>
|
|
#include <qhttp.h>
|
|
#include <util/log.h>
|
|
#include <util/mmapfile.h>
|
|
#include "httpserver.h"
|
|
#include "httpclienthandler.h"
|
|
#include "httpresponseheader.h"
|
|
#include "php_handler.h"
|
|
|
|
using namespace bt;
|
|
|
|
namespace kt
|
|
{
|
|
|
|
HttpClientHandler::HttpClientHandler(HttpServer* srv,QSocket* sock) : srv(srv),client(sock),php_response_hdr(200)
|
|
{
|
|
state = WAITING_FOR_REQUEST;
|
|
bytes_read = 0;
|
|
php = 0;
|
|
}
|
|
|
|
|
|
HttpClientHandler::~HttpClientHandler()
|
|
{
|
|
delete client;
|
|
delete php;
|
|
}
|
|
|
|
void HttpClientHandler::readyToRead()
|
|
{
|
|
if (state == WAITING_FOR_REQUEST)
|
|
{
|
|
while (client->canReadLine())
|
|
{
|
|
QString line = client->readLine();
|
|
header_data += line;
|
|
if (header_data.endsWith("\r\n\r\n"))
|
|
{
|
|
// We have got the header, so lets parse it
|
|
handleRequest();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (state == WAITING_FOR_CONTENT)
|
|
{
|
|
Uint32 ba = client->bytesAvailable();
|
|
if (ba + bytes_read < header.contentLength())
|
|
{
|
|
client->readBlock((char*)request_data.data() + bytes_read,ba);
|
|
bytes_read += ba;
|
|
}
|
|
else
|
|
{
|
|
Uint32 left = header.contentLength() - bytes_read;
|
|
client->readBlock((char*)request_data.data() + bytes_read,left);
|
|
bytes_read += left;
|
|
srv->handlePost(this,header,request_data);
|
|
|
|
header_data = "";
|
|
request_data.resize(0);
|
|
state = WAITING_FOR_REQUEST;
|
|
if (client->bytesAvailable() > 0)
|
|
readyToRead();
|
|
}
|
|
}
|
|
}
|
|
|
|
void HttpClientHandler::handleRequest()
|
|
{
|
|
header = QHttpRequestHeader(header_data);
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Parsing request : " << header.toString() << endl;
|
|
if (header.method() == "POST")
|
|
{
|
|
if (header.hasContentLength())
|
|
{
|
|
request_data.resize(header.contentLength());
|
|
state = WAITING_FOR_CONTENT;
|
|
bytes_read = 0;
|
|
if (client->bytesAvailable() > 0)
|
|
readyToRead();
|
|
}
|
|
}
|
|
else if (header.method() == "GET")
|
|
{
|
|
srv->handleGet(this,header);
|
|
header_data = "";
|
|
request_data.resize(0);
|
|
}
|
|
else
|
|
{
|
|
srv->handleUnsupportedMethod(this);
|
|
}
|
|
}
|
|
|
|
bool HttpClientHandler::sendFile(HttpResponseHeader & hdr,const QString & full_path)
|
|
{
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Sending file " << full_path << endl;
|
|
// first look in cache
|
|
MMapFile* c = srv->cacheLookup(full_path);
|
|
|
|
if (!c)
|
|
{
|
|
// not in cache so load it
|
|
c = new MMapFile();
|
|
if (!c->open(full_path,MMapFile::READ))
|
|
{
|
|
delete c;
|
|
Out(SYS_WEB|LOG_DEBUG) << "Failed to open file " << full_path << endl;
|
|
return false;
|
|
}
|
|
srv->insertIntoCache(full_path,c);
|
|
}
|
|
|
|
hdr.setValue("Content-Length",QString::number(c->getSize()));
|
|
|
|
// Out(SYS_WEB|LOG_DEBUG) << "HTTP header : " << endl;
|
|
// Out(SYS_WEB|LOG_DEBUG) << hdr.toString() << endl;
|
|
|
|
QCString d = hdr.toString().utf8();
|
|
client->writeBlock(d.data(),d.length());
|
|
|
|
Uint32 written = 0;
|
|
Uint32 total = c->getSize();
|
|
const char* data = (const char*)c->getDataPointer();
|
|
while (written < total)
|
|
{
|
|
Uint32 w = client->writeBlock(data + written,total - written);
|
|
written += w;
|
|
}
|
|
client->flush();
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Finished sending " << full_path << " (" << written << " bytes)" << endl;
|
|
return true;
|
|
}
|
|
|
|
#define HTTP_404_ERROR "<html><head><title>404 Not Found</title></head><body>The requested file was not found !</body></html>"
|
|
#define HTTP_500_ERROR "<html><head><title>HTTP/1.1 500 Internal Server Error</title></head><body>HTTP/1.1 Internal Server Error<br>%1</body></html>"
|
|
|
|
|
|
void HttpClientHandler::send404(HttpResponseHeader & hdr,const QString & path)
|
|
{
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Sending 404 " << path << endl;
|
|
QString data = HTTP_404_ERROR;
|
|
hdr.setValue("Content-Length",QString::number(data.length()));
|
|
|
|
QTextStream os(client);
|
|
os.setEncoding( QTextStream::UnicodeUTF8 );
|
|
os << hdr.toString();
|
|
os << data;
|
|
}
|
|
|
|
void HttpClientHandler::send500(HttpResponseHeader & hdr)
|
|
{
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Sending 500 " << endl;
|
|
QString data = QString(HTTP_500_ERROR).arg("An internal server error occured !");
|
|
hdr.setValue("Content-Length",QString::number(data.length()));
|
|
|
|
QTextStream os(client);
|
|
os.setEncoding( QTextStream::UnicodeUTF8 );
|
|
os << hdr.toString();
|
|
os << data;
|
|
}
|
|
|
|
void HttpClientHandler::sendResponse(const HttpResponseHeader & hdr)
|
|
{
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Sending response " << hdr.toString() << endl;
|
|
QTextStream os(client);
|
|
os.setEncoding( QTextStream::UnicodeUTF8 );
|
|
os << hdr.toString();
|
|
}
|
|
|
|
void HttpClientHandler::executePHPScript(
|
|
PhpInterface* php_iface,
|
|
HttpResponseHeader & hdr,
|
|
const QString & php_exe,
|
|
const QString & php_file,
|
|
const QMap<QString,QString> & args)
|
|
{
|
|
// Out(SYS_WEB|LOG_DEBUG) << "Launching PHP script " << php_file << endl;
|
|
php = new PhpHandler(php_exe,php_iface);
|
|
if (!php->executeScript(php_file,args))
|
|
{
|
|
QString data = QString(HTTP_500_ERROR).arg("Failed to launch PHP executable !");
|
|
hdr.setResponseCode(500);
|
|
hdr.setValue("Content-Length",QString::number(data.utf8().length()));
|
|
|
|
QTextStream os(client);
|
|
os.setEncoding( QTextStream::UnicodeUTF8 );
|
|
os << hdr.toString();
|
|
os << data;
|
|
state = WAITING_FOR_REQUEST;
|
|
}
|
|
else
|
|
{
|
|
php_response_hdr = hdr;
|
|
connect(php,SIGNAL(finished()),this,SLOT(onPHPFinished()));
|
|
state = PROCESSING_PHP;
|
|
}
|
|
}
|
|
|
|
void HttpClientHandler::onPHPFinished()
|
|
{
|
|
const QByteArray & output = php->getOutput();
|
|
php_response_hdr.setValue("Content-Length",QString::number(output.size()));
|
|
|
|
QTextStream os(client);
|
|
os.setEncoding( QTextStream::UnicodeUTF8 );
|
|
os << php_response_hdr.toString();
|
|
os.writeRawBytes(output.data(),output.size());
|
|
|
|
php->deleteLater();
|
|
php = 0;
|
|
state = WAITING_FOR_REQUEST;
|
|
}
|
|
}
|
|
|
|
#include "httpclienthandler.moc"
|
|
|