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.
192 lines
3.9 KiB
192 lines
3.9 KiB
/*
|
|
This file is part of cpp-ethereum.
|
|
|
|
cpp-ethereum 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/** @file HttpServer.cpp
|
|
* @author Arkadiy Paronyan arkadiy@ethdev.com
|
|
* @date 2015
|
|
* Ethereum IDE client.
|
|
*/
|
|
|
|
#include <memory>
|
|
#include <QTcpSocket>
|
|
#include "HttpServer.h"
|
|
|
|
|
|
using namespace dev::mix;
|
|
|
|
HttpServer::HttpServer()
|
|
: m_port(0) , m_listen(false) , m_accept(true) , m_componentCompleted(true)
|
|
{
|
|
}
|
|
|
|
HttpServer::~HttpServer()
|
|
{
|
|
setListen(false);
|
|
}
|
|
|
|
void HttpServer::classBegin()
|
|
{
|
|
m_componentCompleted = false;
|
|
}
|
|
|
|
void HttpServer::componentComplete()
|
|
{
|
|
init();
|
|
m_componentCompleted = true;
|
|
}
|
|
|
|
QUrl HttpServer::url() const
|
|
{
|
|
QUrl url;
|
|
url.setPort(m_port);
|
|
url.setHost("localhost");
|
|
url.setScheme("http");
|
|
return url;
|
|
}
|
|
|
|
void HttpServer::setPort(int _port)
|
|
{
|
|
if (_port == m_port)
|
|
return;
|
|
|
|
m_port = _port;
|
|
emit portChanged(_port);
|
|
emit urlChanged(url());
|
|
|
|
if (m_componentCompleted && this->isListening())
|
|
updateListening();
|
|
}
|
|
|
|
QString HttpServer::errorString() const
|
|
{
|
|
return QTcpServer::errorString();
|
|
}
|
|
|
|
void HttpServer::setListen(bool _listen)
|
|
{
|
|
if (_listen == m_listen)
|
|
return;
|
|
|
|
m_listen = _listen;
|
|
emit listenChanged(_listen);
|
|
|
|
if (m_componentCompleted)
|
|
updateListening();
|
|
}
|
|
|
|
void HttpServer::setAccept(bool _accept)
|
|
{
|
|
if (_accept == m_accept)
|
|
return;
|
|
|
|
m_accept = _accept;
|
|
emit acceptChanged(_accept);
|
|
}
|
|
|
|
void HttpServer::init()
|
|
{
|
|
updateListening();
|
|
}
|
|
|
|
void HttpServer::updateListening()
|
|
{
|
|
if (this->isListening())
|
|
this->close();
|
|
|
|
if (!m_listen)
|
|
return;
|
|
|
|
if (!QTcpServer::listen(QHostAddress::LocalHost, m_port))
|
|
{
|
|
errorStringChanged();
|
|
return;
|
|
}
|
|
|
|
if (m_port != QTcpServer::serverPort())
|
|
{
|
|
m_port = QTcpServer::serverPort();
|
|
emit portChanged(m_port);
|
|
emit urlChanged(url());
|
|
}
|
|
}
|
|
|
|
void HttpServer::incomingConnection(qintptr _socket)
|
|
{
|
|
if (!m_accept)
|
|
return;
|
|
|
|
QTcpSocket* s = new QTcpSocket(this);
|
|
connect(s, SIGNAL(readyRead()), this, SLOT(readClient()));
|
|
connect(s, SIGNAL(disconnected()), this, SLOT(discardClient()));
|
|
s->setSocketDescriptor(_socket);
|
|
}
|
|
|
|
void HttpServer::readClient()
|
|
{
|
|
if (!m_accept)
|
|
return;
|
|
|
|
QTcpSocket* socket = (QTcpSocket*)sender();
|
|
try
|
|
{
|
|
if (socket->canReadLine())
|
|
{
|
|
QString hdr = QString(socket->readLine());
|
|
QVariantMap headers;
|
|
if (hdr.startsWith("POST") || hdr.startsWith("GET"))
|
|
{
|
|
QUrl url(hdr.split(' ')[1]);
|
|
QString l;
|
|
do
|
|
{
|
|
l = socket->readLine();
|
|
//collect headers
|
|
int colon = l.indexOf(':');
|
|
if (colon > 0)
|
|
headers[l.left(colon).trimmed().toLower()] = l.right(l.length() - colon - 1).trimmed();
|
|
}
|
|
while (!(l.isEmpty() || l == "\r" || l == "\r\n"));
|
|
|
|
QString content = socket->readAll();
|
|
std::unique_ptr<HttpRequest> request(new HttpRequest(this, std::move(url), std::move(content), std::move(headers)));
|
|
clientConnected(request.get());
|
|
QTextStream os(socket);
|
|
os.setAutoDetectUnicode(true);
|
|
QString q;
|
|
///@todo: allow setting response content-type, charset, etc
|
|
os << "HTTP/1.0 200 Ok\r\n";
|
|
if (!request->m_responseContentType.isEmpty())
|
|
os << "Content-Type: " << request->m_responseContentType << "; ";
|
|
os << "charset=\"utf-8\"\r\n\r\n";
|
|
os << request->m_response;
|
|
}
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
delete socket;
|
|
throw;
|
|
}
|
|
socket->close();
|
|
if (socket->state() == QTcpSocket::UnconnectedState)
|
|
delete socket;
|
|
}
|
|
|
|
void HttpServer::discardClient()
|
|
{
|
|
QTcpSocket* socket = (QTcpSocket*)sender();
|
|
socket->deleteLater();
|
|
}
|
|
|