Gav Wood
10 years ago
22 changed files with 613 additions and 200 deletions
@ -0,0 +1,170 @@ |
|||||
|
/*
|
||||
|
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 this->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 || QTcpServer::listen(QHostAddress::LocalHost, m_port)) |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
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()); |
||||
|
if (hdr.startsWith("POST")) |
||||
|
{ |
||||
|
QString l; |
||||
|
do |
||||
|
l = socket->readLine(); |
||||
|
while (!(l.isEmpty() || l == "\r" || l == "\r\n")); |
||||
|
|
||||
|
QString content = socket->readAll(); |
||||
|
QUrl url; |
||||
|
std::unique_ptr<HttpRequest> request(new HttpRequest(this, url, content)); |
||||
|
clientConnected(request.get()); |
||||
|
QTextStream os(socket); |
||||
|
os.setAutoDetectUnicode(true); |
||||
|
///@todo: allow setting response content-type, charset, etc
|
||||
|
os << "HTTP/1.0 200 Ok\r\n" |
||||
|
"Content-Type: text/plain; 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(); |
||||
|
} |
@ -0,0 +1,123 @@ |
|||||
|
/*
|
||||
|
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.h
|
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <QObject> |
||||
|
#include <QTcpServer> |
||||
|
#include <QUrl> |
||||
|
#include <QQmlParserStatus> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace mix |
||||
|
{ |
||||
|
|
||||
|
/// Simple http server for serving jsonrpc requests
|
||||
|
class HttpRequest : public QObject |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
/// Request url
|
||||
|
Q_PROPERTY(QUrl url MEMBER m_url CONSTANT) |
||||
|
/// Request body contents
|
||||
|
Q_PROPERTY(QString content MEMBER m_content CONSTANT) |
||||
|
|
||||
|
private: |
||||
|
HttpRequest(QObject* _parent, QUrl const& _url, QString const& _content): |
||||
|
QObject(_parent), m_url(_url), m_content(_content) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
/// Set response for a request
|
||||
|
/// @param _response Response body. If no response is set, server returns status 200 with empty body
|
||||
|
Q_INVOKABLE void setResponse(QString const& _response) { m_response = _response; } |
||||
|
|
||||
|
private: |
||||
|
QUrl m_url; |
||||
|
QString m_content; |
||||
|
QString m_response; |
||||
|
friend class HttpServer; |
||||
|
}; |
||||
|
|
||||
|
class HttpServer : public QTcpServer, public QQmlParserStatus |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
Q_DISABLE_COPY(HttpServer) |
||||
|
Q_INTERFACES(QQmlParserStatus) |
||||
|
|
||||
|
/// Server url
|
||||
|
Q_PROPERTY(QUrl url READ url NOTIFY urlChanged) |
||||
|
/// Server port
|
||||
|
Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged) |
||||
|
/// Listen for connections
|
||||
|
Q_PROPERTY(bool listen READ listen WRITE setListen NOTIFY listenChanged) |
||||
|
/// Accept new connections
|
||||
|
Q_PROPERTY(bool accept READ accept WRITE setAccept NOTIFY acceptChanged) |
||||
|
/// Error string if any
|
||||
|
Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged) |
||||
|
|
||||
|
public: |
||||
|
explicit HttpServer(); |
||||
|
virtual ~HttpServer(); |
||||
|
|
||||
|
QUrl url() const; |
||||
|
int port() const { return m_port; } |
||||
|
void setPort(int _port); |
||||
|
bool listen() const { return m_listen; } |
||||
|
void setListen(bool _listen); |
||||
|
bool accept() const { return m_accept; } |
||||
|
void setAccept(bool _accept); |
||||
|
QString errorString() const; |
||||
|
|
||||
|
protected: |
||||
|
virtual void classBegin() override; |
||||
|
virtual void componentComplete() override; |
||||
|
virtual void incomingConnection(qintptr _socket) override; |
||||
|
|
||||
|
signals: |
||||
|
void clientConnected(HttpRequest* _request); |
||||
|
void errorStringChanged(QString const& _errorString); |
||||
|
void urlChanged(QUrl const& _url); |
||||
|
void portChanged(int _port); |
||||
|
void listenChanged(bool _listen); |
||||
|
void acceptChanged(bool _accept); |
||||
|
|
||||
|
private: |
||||
|
void init(); |
||||
|
void updateListening(); |
||||
|
void newConnection(); |
||||
|
void serverError(); |
||||
|
|
||||
|
private slots: |
||||
|
void readClient(); |
||||
|
void discardClient(); |
||||
|
|
||||
|
private: |
||||
|
int m_port; |
||||
|
bool m_listen; |
||||
|
bool m_accept; |
||||
|
bool m_componentCompleted; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
Loading…
Reference in new issue