/* 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 . */ /** @file HttpServer.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com * @date 2015 * Ethereum IDE client. */ #include #include #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 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(); }