diff options
Diffstat (limited to 'apps/src/http-server/http-server')
19 files changed, 1376 insertions, 0 deletions
diff --git a/apps/src/http-server/http-server/common.h b/apps/src/http-server/http-server/common.h new file mode 100644 index 000000000..81f6757c7 --- /dev/null +++ b/apps/src/http-server/http-server/common.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "config.h" + +#if defined(HICNET) +#include <hicn/transport/http/facade.h> +#include <hicn/transport/utils/hash.h> +#elif defined(ICNET) +#include <icnet/icnet_http_facade.h> +#include <icnet/icnet_utils_hash.h> +#else +#error "No ICN tranport library to which link against." +#endif + +#include <algorithm> +#include <asio.hpp> +#include <functional> +#include <future> +#include <iostream> +#include <memory> +#include <regex> +#include <sstream> +#include <string> +#include <thread> +#include <unordered_map> + +typedef asio::ip::tcp::socket socket_type; +typedef std::function<void(const std::error_code &)> SendCallback; diff --git a/apps/src/http-server/http-server/configuration.cc b/apps/src/http-server/http-server/configuration.cc new file mode 100644 index 000000000..603396b44 --- /dev/null +++ b/apps/src/http-server/http-server/configuration.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "configuration.h" + +namespace icn_httpserver { + +Configuration::Configuration(unsigned short port, size_t num_threads) + : num_threads_(num_threads), port_(port), reuse_address_(true) {} + +size_t Configuration::getNum_threads() const { return num_threads_; } + +void Configuration::setNum_threads(size_t num_threads) { + Configuration::num_threads_ = num_threads; +} + +unsigned short Configuration::getPort() const { return port_; } + +void Configuration::setPort(unsigned short port) { + Configuration::port_ = port; +} + +const std::string &Configuration::getAddress() const { return address_; } + +void Configuration::setAddress(const std::string &address) { + Configuration::address_ = address; +} + +bool Configuration::isReuse_address() const { return reuse_address_; } + +void Configuration::setReuse_address(bool reuse_address) { + Configuration::reuse_address_ = reuse_address; +} + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/configuration.h b/apps/src/http-server/http-server/configuration.h new file mode 100644 index 000000000..b87558f91 --- /dev/null +++ b/apps/src/http-server/http-server/configuration.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" + +namespace icn_httpserver { + +class Configuration { +public: + Configuration(unsigned short port, size_t num_threads); + + size_t getNum_threads() const; + + void setNum_threads(size_t num_threads); + + unsigned short getPort() const; + + void setPort(unsigned short port); + + const std::string &getAddress() const; + + void setAddress(const std::string &address); + + bool isReuse_address() const; + + void setReuse_address(bool reuse_address); + +private: + size_t num_threads_; + unsigned short port_; + std::string address_; + bool reuse_address_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/content.cc b/apps/src/http-server/http-server/content.cc new file mode 100644 index 000000000..8ad16f904 --- /dev/null +++ b/apps/src/http-server/http-server/content.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "content.h" + +namespace icn_httpserver { + +Content::Content(asio::streambuf &streambuf) + : std::istream(&streambuf), streambuf_(streambuf) {} + +std::size_t Content::size() { return streambuf_.size(); } + +std::string Content::string() { + std::stringstream ss; + ss << rdbuf(); + return ss.str(); +} + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/content.h b/apps/src/http-server/http-server/content.h new file mode 100644 index 000000000..ebf2f7f32 --- /dev/null +++ b/apps/src/http-server/http-server/content.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common.h" + +#pragma once + +namespace icn_httpserver { + +class Content : public std::istream { +public: + Content(asio::streambuf &streambuf); + + size_t size(); + + std::string string(); + +private: + asio::streambuf &streambuf_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/http_server.cc b/apps/src/http-server/http-server/http_server.cc new file mode 100644 index 000000000..911656f7a --- /dev/null +++ b/apps/src/http-server/http-server/http_server.cc @@ -0,0 +1,416 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "http_server.h" + +#include <asio.hpp> +#include <fstream> +#include <istream> + +namespace icn_httpserver { + +HttpServer::HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive) + : config_(port, num_threads), + internal_io_service_(std::make_shared<asio::io_service>()), + io_service_(*internal_io_service_), acceptor_(io_service_), + icn_name_(icn_name), timeout_request_(timeout_request), + timeout_content_(timeout_send_or_receive) {} + +HttpServer::HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive, + asio::io_service &ioService) + : config_(port, num_threads), io_service_(ioService), + acceptor_(io_service_), icn_name_(icn_name), + timeout_request_(timeout_request), + timeout_content_(timeout_send_or_receive) {} + +void HttpServer::onIcnRequest( + std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + const uint8_t *buffer, std::size_t size, int request_id) { + std::shared_ptr<Request> request = std::make_shared<IcnRequest>(publisher); + request->getContent().rdbuf()->sputn((char *)buffer, size); + + if (!parse_request(request, request->getContent())) { + return; + } + + std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>> + &icn_publishers = icn_acceptor_->getPublishers(); + + std::unique_lock<std::mutex> lock(thread_list_mtx_); + if (icn_publishers.size() < config_.getNum_threads()) { + std::cout << "Received request for: " << request->getPath() << std::endl; + + publisher->attachPublisher(); + std::cout << "Starting new thread" << std::endl; + io_service_.dispatch([this, request, request_id]() { + std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>> + &icn_publishers = icn_acceptor_->getPublishers(); + find_resource(nullptr, request); + icn_publishers[request_id]->serveClients(); + std::unique_lock<std::mutex> lock(thread_list_mtx_); + icn_publishers.erase(request_id); + }); + } +} + +void HttpServer::setIcnAcceptor() { + icn_acceptor_ = std::make_shared<libl4::http::HTTPServerAcceptor>( + icn_name_, std::bind(&HttpServer::onIcnRequest, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + icn_acceptor_->listen(true); +} + +void HttpServer::spawnThreads() { + if (io_service_.stopped()) { + io_service_.reset(); + } + + asio::ip::tcp::endpoint endpoint; + + if (config_.getAddress().size() > 0) { + endpoint = asio::ip::tcp::endpoint( + asio::ip::address::from_string(config_.getAddress()), + config_.getPort()); + } else { + endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config_.getPort()); + } + + acceptor_.open(endpoint.protocol()); + acceptor_.set_option( + asio::socket_base::reuse_address(config_.isReuse_address())); + acceptor_.bind(endpoint); + acceptor_.listen(); + + accept(); + + // If num_threads>1, start m_io_service.run() in (num_threads-1) threads for + // thread-pooling + socket_threads_.clear(); + for (size_t c = 1; c < config_.getNum_threads(); c++) { + socket_threads_.emplace_back([this]() { io_service_.run(); }); + } +} + +void HttpServer::start() { + // Copy the resources to opt_resource for more efficient request processing + opt_resource_.clear(); + for (auto &res : resource) { + for (auto &res_method : res.second) { + auto it = opt_resource_.end(); + for (auto opt_it = opt_resource_.begin(); opt_it != opt_resource_.end(); + opt_it++) { + if (res_method.first == opt_it->first) { + it = opt_it; + break; + } + } + if (it == opt_resource_.end()) { + opt_resource_.emplace_back(); + it = opt_resource_.begin() + (opt_resource_.size() - 1); + it->first = res_method.first; + } + it->second.emplace_back(std::regex(res.first), res_method.second); + } + } + + spawnThreads(); + + setIcnAcceptor(); + + // Wait for the rest of the threads, if any, to finish as well + for (auto &t : socket_threads_) { + t.join(); + } + // for (auto &t : icn_threads) { + // t.second.get(); + // } +} + +void HttpServer::stop() { + acceptor_.close(); + + io_service_.stop(); + + std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>> + &icn_publishers = icn_acceptor_->getPublishers(); + + for (auto &p : icn_publishers) { + p.second->stop(); + } +} + +void HttpServer::accept() { + // Create new socket for this connection + // Shared_ptr is used to pass temporary objects to the asynchronous functions + std::shared_ptr<socket_type> socket = + std::make_shared<socket_type>(io_service_); + + acceptor_.async_accept(*socket, [this, socket](const std::error_code &ec) { + // Immediately start accepting a new connection + accept(); + + if (!ec) { + asio::ip::tcp::no_delay option(true); + socket->set_option(option); + read_request_and_content(socket); + } + }); +} + +void HttpServer::send(std::shared_ptr<Response> response, + SendCallback callback) const { + response->send(callback); +} + +std::shared_ptr<asio::steady_timer> +HttpServer::set_timeout_on_socket(std::shared_ptr<socket_type> socket, + long seconds) { + std::shared_ptr<asio::steady_timer> timer = + std::make_shared<asio::steady_timer>(io_service_); + timer->expires_from_now(std::chrono::seconds(seconds)); + timer->async_wait([socket](const std::error_code &ec) { + if (!ec) { + std::error_code ec; + socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); + socket->lowest_layer().close(); + } + }); + return timer; +} + +void HttpServer::read_request_and_content(std::shared_ptr<socket_type> socket) { + // Create new streambuf (Request::streambuf) for async_read_until() + // shared_ptr is used to pass temporary objects to the asynchronous functions + std::shared_ptr<Request> request = std::make_shared<SocketRequest>(); + request->read_remote_endpoint_data(*socket); + + // Set timeout on the following asio::async-read or write function + std::shared_ptr<asio::steady_timer> timer; + if (timeout_request_ > 0) { + timer = set_timeout_on_socket(socket, timeout_request_); + } + + asio::async_read_until( + *socket, request->getStreambuf(), "\r\n\r\n", + [this, socket, request, timer](const std::error_code &ec, + size_t bytes_transferred) { + if (timeout_request_ > 0) { + timer->cancel(); + } + if (!ec) { + // request->streambuf.size() is not necessarily the same as + // bytes_transferred, from Asio-docs: "After a successful + //async_read_until operation, the streambuf may contain additional + //data beyond the delimiter" The chosen solution is to extract lines + // from the stream directly when parsing the header. What is left of + // the streambuf (maybe some bytes of the content) is appended to in + // the async_read-function below (for retrieving content). + size_t num_additional_bytes = + request->getStreambuf().in_avail() - bytes_transferred; + + if (!parse_request(request, request->getContent())) { + return; + } + + // If content, read that as well + auto it = request->getHeader().find("Content-Length"); + if (it != request->getHeader().end()) { + // Set timeout on the following asio::async-read or write function + std::shared_ptr<asio::steady_timer> timer; + if (timeout_content_ > 0) { + timer = set_timeout_on_socket(socket, timeout_content_); + } + unsigned long long content_length; + try { + content_length = atol(it->second.c_str()); + } catch (const std::exception &) { + return; + } + if (content_length > num_additional_bytes) { + asio::async_read( + *socket, request->getStreambuf(), + asio::transfer_exactly(content_length - num_additional_bytes), + [this, socket, request, timer](const std::error_code &ec, + size_t /*bytes_transferred*/) { + if (timeout_content_ > 0) { + timer->cancel(); + } + if (!ec) { + find_resource(socket, request); + } + }); + } else { + + if (timeout_content_ > 0) { + timer->cancel(); + } + + find_resource(socket, request); + } + } else { + find_resource(socket, request); + } + } + }); +} + +bool HttpServer::parse_request(std::shared_ptr<Request> request, + std::istream &stream) const { + std::string line; + getline(stream, line); + size_t method_end; + if ((method_end = line.find(' ')) != std::string::npos) { + size_t path_end; + if ((path_end = line.find(' ', method_end + 1)) != std::string::npos) { + request->setMethod(line.substr(0, method_end)); + request->setPath(line.substr(method_end + 1, path_end - method_end - 1)); + + size_t protocol_end; + if ((protocol_end = line.find('/', path_end + 1)) != std::string::npos) { + if (line.substr(path_end + 1, protocol_end - path_end - 1) != "HTTP") { + return false; + } + request->setHttp_version( + line.substr(protocol_end + 1, line.size() - protocol_end - 2)); + } else { + return false; + } + + getline(stream, line); + size_t param_end; + while ((param_end = line.find(':')) != std::string::npos) { + size_t value_start = param_end + 1; + if ((value_start) < line.size()) { + if (line[value_start] == ' ') { + value_start++; + } + if (value_start < line.size()) { + request->getHeader().insert(std::make_pair( + line.substr(0, param_end), + line.substr(value_start, line.size() - value_start - 1))); + } + } + + getline(stream, line); + } + } else { + return false; + } + } else { + return false; + } + return true; +} + +void HttpServer::find_resource(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request) { + // Find path- and method-match, and call write_response + for (auto &res : opt_resource_) { + if (request->getMethod() == res.first) { + for (auto &res_path : res.second) { + std::smatch sm_res; + if (std::regex_match(request->getPath(), sm_res, res_path.first)) { + request->setPath_match(std::move(sm_res)); + write_response(socket, request, res_path.second); + return; + } + } + } + } + auto it_method = default_resource.find(request->getMethod()); + if (it_method != default_resource.end()) { + write_response(socket, request, it_method->second); + return; + } + + std::cout << "resource not found" << std::endl; +} + +void HttpServer::write_response(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request, + ResourceCallback &resource_function) { + // Set timeout on the following asio::async-read or write function + std::shared_ptr<asio::steady_timer> timer; + if (timeout_content_ > 0 && socket) { + timer = set_timeout_on_socket(socket, timeout_content_); + } + + Response *resp; + + if (socket) { + resp = new SocketResponse(socket); + } else { + resp = new IcnResponse( + std::static_pointer_cast<IcnRequest>(request)->getHttpPublisher(), + std::static_pointer_cast<IcnRequest>(request)->getName(), + std::static_pointer_cast<IcnRequest>(request)->getPath()); + } + + auto response = std::shared_ptr<Response>(resp, [this, request, timer, + socket]( + Response *response_ptr) { + auto response = std::shared_ptr<Response>(response_ptr); + response->setIsLast(true); + + send(response, [this, response, request, timer, + socket](const std::error_code &ec) { + if (!ec) { + if (socket && timeout_content_ > 0) { + timer->cancel(); + } + + float http_version; + try { + http_version = atof(request->getHttp_version().c_str()); + } catch (const std::exception &) { + return; + } + + auto range = request->getHeader().equal_range("Connection"); + for (auto it = range.first; it != range.second; it++) { + if (caseInsCompare(it->second, "close")) { + return; + } + } + if (http_version > 1.05 && socket) { + read_request_and_content( + std::static_pointer_cast<SocketResponse>(response)->getSocket()); + } + } + }); + }); + + try { + resource_function(response, request); + } catch (const std::exception &) { + return; + } +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/http_server.h b/apps/src/http-server/http-server/http_server.h new file mode 100644 index 000000000..3468b438a --- /dev/null +++ b/apps/src/http-server/http-server/http_server.h @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include "common.h" +#include "configuration.h" +#include "icn_request.h" +#include "icn_response.h" +#include "socket_request.h" +#include "socket_response.h" + +typedef std::function<void(std::shared_ptr<icn_httpserver::Response>, + std::shared_ptr<icn_httpserver::Request>)> + ResourceCallback; + +#define SERVER_NAME "/webserver" +#define PACKET_SIZE 1500 +#define SEND_BUFFER_SIZE 30000 + +#define GET "GET" +#define POST "POST" +#define PUT "PUT" +#define DELETE "DELETE" +#define PATCH "PATCH" + +namespace icn_httpserver { + +class HttpServer { +public: + explicit HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive); + + explicit HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive, + asio::io_service &ioService); + + void start(); + + void stop(); + + void accept(); + + void send(std::shared_ptr<Response> response, + SendCallback callback = nullptr) const; + + std::unordered_map<std::string, + std::unordered_map<std::string, ResourceCallback>> + resource; + + std::unordered_map<std::string, ResourceCallback> default_resource; + + void + onIcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + const uint8_t *buffer, std::size_t size, int request_id); + +private: + void spawnThreads(); + + void setIcnAcceptor(); + + std::shared_ptr<asio::steady_timer> + set_timeout_on_socket(std::shared_ptr<socket_type> socket, long seconds); + + void read_request_and_content(std::shared_ptr<socket_type> socket); + + bool parse_request(std::shared_ptr<Request> request, + std::istream &stream) const; + + void find_resource(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request); + + void write_response(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request, + ResourceCallback &resource_function); + + Configuration config_; + + std::vector<std::pair<std::string, + std::vector<std::pair<std::regex, ResourceCallback>>>> + opt_resource_; + + std::shared_ptr<asio::io_service> internal_io_service_; + asio::io_service &io_service_; + asio::ip::tcp::acceptor acceptor_; + std::vector<std::thread> socket_threads_; + std::string icn_name_; + std::shared_ptr<libl4::http::HTTPServerAcceptor> icn_acceptor_; + std::mutex thread_list_mtx_; + + long timeout_request_; + long timeout_content_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/icn_request.cc b/apps/src/http-server/http-server/icn_request.cc new file mode 100644 index 000000000..7871d908d --- /dev/null +++ b/apps/src/http-server/http-server/icn_request.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "icn_request.h" + +namespace icn_httpserver { + +IcnRequest::IcnRequest( + std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher) + : publisher_(publisher) { + time_t t; + time(&t); + srand((unsigned int)t); + request_id_ = rand(); +} + +IcnRequest::IcnRequest( + std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + std::string name, std::string path, std::string method, + std::string http_version) + : IcnRequest(publisher) { + this->name_ = name; + this->path_ = path; + this->method_ = method; + this->http_version_ = http_version; +} + +const std::string &IcnRequest::getName() const { return name_; } + +void IcnRequest::setName(const std::string &name) { IcnRequest::name_ = name; } + +int IcnRequest::getRequest_id() const { return request_id_; } + +void IcnRequest::setRequest_id(int request_id) { + IcnRequest::request_id_ = request_id; +} + +const std::shared_ptr<libl4::http::HTTPServerPublisher> & +IcnRequest::getHttpPublisher() const { + return publisher_; +} + +void IcnRequest::setProducer( + const std::shared_ptr<libl4::http::HTTPServerPublisher> &producer) { + IcnRequest::publisher_ = producer; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/icn_request.h b/apps/src/http-server/http-server/icn_request.h new file mode 100644 index 000000000..adf36d129 --- /dev/null +++ b/apps/src/http-server/http-server/icn_request.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" +#include "request.h" + +namespace icn_httpserver { + +class IcnRequest : public Request { +public: + IcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher); + + IcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + std::string name, std::string path, std::string method, + std::string http_version); + + ~IcnRequest() = default; + + const std::string &getName() const; + + void setName(const std::string &name); + + int getRequest_id() const; + + void setRequest_id(int request_id); + + const std::shared_ptr<libl4::http::HTTPServerPublisher> & + getHttpPublisher() const; + + void setProducer( + const std::shared_ptr<libl4::http::HTTPServerPublisher> &producer); + +private: + std::string name_; + int request_id_; + std::shared_ptr<libl4::http::HTTPServerPublisher> publisher_; +}; + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/icn_response.cc b/apps/src/http-server/http-server/icn_response.cc new file mode 100644 index 000000000..11d0faf6b --- /dev/null +++ b/apps/src/http-server/http-server/icn_response.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "icn_response.h" + +namespace icn_httpserver { + +IcnResponse::IcnResponse( + std::shared_ptr<libl4::http::HTTPServerPublisher> publisher, + std::string ndn_name, + std::string ndn_path) //, + // int response_id) + : ndn_name_(ndn_name), ndn_path_(ndn_path), publisher_(publisher) {} + +void IcnResponse::send(const SendCallback &callback) { + + std::size_t buffer_size = this->streambuf_.size(); + this->streambuf_.commit(this->streambuf_.size()); + + this->publisher_->publishContent( + asio::buffer_cast<const uint8_t *>(this->streambuf_.data()), buffer_size, + response_lifetime_, this->is_last_); + + this->streambuf_.consume(buffer_size); + + if (callback) { + callback(std::error_code()); + } +} + +void IcnResponse::setResponseLifetime( + const std::chrono::milliseconds &response_lifetime) { + this->publisher_->setTimeout(response_lifetime, true); + Response::setResponseLifetime(response_lifetime); +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/icn_response.h b/apps/src/http-server/http-server/icn_response.h new file mode 100644 index 000000000..2194a5a7f --- /dev/null +++ b/apps/src/http-server/http-server/icn_response.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "response.h" + +namespace icn_httpserver { + +class IcnResponse : public Response { + +public: + IcnResponse(std::shared_ptr<libl4::http::HTTPServerPublisher> producer, + std::string ndn_name, std::string ndn_path); + + void send(const SendCallback &callback = nullptr) override; + + void setResponseLifetime( + const std::chrono::milliseconds &response_lifetime) override; + +private: + std::string ndn_name_; + std::string ndn_path_; + std::shared_ptr<libl4::http::HTTPServerPublisher> publisher_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/request.cc b/apps/src/http-server/http-server/request.cc new file mode 100644 index 000000000..e754d645b --- /dev/null +++ b/apps/src/http-server/http-server/request.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "request.h" + +using namespace std; + +inline bool caseInsCharCompareN(char a, char b) { + return (toupper(a) == toupper(b)); +} + +inline bool caseInsCharCompareW(wchar_t a, wchar_t b) { + return (towupper(a) == towupper(b)); +} + +bool caseInsCompare(const string &s1, const string &s2) { + return ((s1.size() == s2.size()) && + equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompareN)); +} + +bool caseInsCompare(const wstring &s1, const wstring &s2) { + return ((s1.size() == s2.size()) && + equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompareW)); +} + +namespace icn_httpserver { + +Request::Request() : content_(streambuf_) {} + +const std::string &Request::getMethod() const { return method_; } + +void Request::setMethod(const std::string &method) { + Request::method_ = method; +} + +const std::string &Request::getPath() const { return path_; } + +void Request::setPath(const std::string &path) { Request::path_ = path; } + +const std::string &Request::getHttp_version() const { return http_version_; } + +void Request::setHttp_version(const std::string &http_version) { + Request::http_version_ = http_version; +} + +std::unordered_multimap<std::string, std::string, ihash, iequal_to> & +Request::getHeader() { + return header_; +} + +Content &Request::getContent() { return content_; } + +const std::smatch &Request::getPath_match() const { return path_match_; } + +void Request::setPath_match(const std::smatch &path_match) { + Request::path_match_ = path_match; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/request.h b/apps/src/http-server/http-server/request.h new file mode 100644 index 000000000..f9b2a73df --- /dev/null +++ b/apps/src/http-server/http-server/request.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" +#include "content.h" + +using namespace std; + +inline bool caseInsCharCompareN(char a, char b); + +inline bool caseInsCharCompareW(wchar_t a, wchar_t b); + +bool caseInsCompare(const string &s1, const string &s2); + +bool caseInsCompare(const wstring &s1, const wstring &s2); + +namespace icn_httpserver { + +class iequal_to { +public: + bool operator()(const std::string &key1, const std::string &key2) const { + return caseInsCompare(key1, key2); + } +}; + +class ihash { +public: + size_t operator()(const std::string &key) const { + std::size_t seed = 0; + for (auto &c : key) { + std::hash<char> hasher; + seed ^= hasher(c) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } +}; + +class Request { +public: + Request(); + + virtual void read_remote_endpoint_data(socket_type &socket){}; + + virtual ~Request() = default; + + const std::string &getMethod() const; + + void setMethod(const std::string &method); + + const std::string &getPath() const; + + void setPath(const std::string &path); + + const std::string &getHttp_version() const; + + void setHttp_version(const std::string &http_version); + + std::unordered_multimap<std::string, std::string, ihash, iequal_to> & + getHeader(); + + asio::streambuf &getStreambuf() { return streambuf_; } + + Content &getContent(); + + const std::smatch &getPath_match() const; + + void setPath_match(const std::smatch &path_match); + +protected: + std::string method_, path_, http_version_; + Content content_; + std::unordered_multimap<std::string, std::string, ihash, iequal_to> header_; + std::smatch path_match_; + asio::streambuf streambuf_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/response.cc b/apps/src/http-server/http-server/response.cc new file mode 100644 index 000000000..ccb249e4a --- /dev/null +++ b/apps/src/http-server/http-server/response.cc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "response.h" +#include "common.h" + +#define DEFAULT_LIFETIME 1000 * 1000 + +namespace icn_httpserver { + +Response::Response() + : std::ostream(&streambuf_), is_last_(false), response_length_(0), + response_lifetime_(DEFAULT_LIFETIME) {} + +Response::~Response() {} + +std::size_t Response::size() { return streambuf_.size(); } + +bool Response::isIsLast() const { return is_last_; } + +void Response::setIsLast(bool is_last) { Response::is_last_ = is_last; } + +const std::chrono::milliseconds &Response::getResponseLifetime() const { + return response_lifetime_; +} + +void Response::setResponseLifetime( + const std::chrono::milliseconds &response_lifetime) { + Response::response_lifetime_ = response_lifetime; +} + +void Response::setResponseLength(std::size_t length) { + response_length_ = length; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/response.h b/apps/src/http-server/http-server/response.h new file mode 100644 index 000000000..9cc2e61ab --- /dev/null +++ b/apps/src/http-server/http-server/response.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" + +namespace icn_httpserver { + +class Response : public std::ostream { +public: + Response(); + + virtual ~Response(); + + size_t size(); + + virtual void send(const SendCallback &callback = nullptr){}; + + bool isIsLast() const; + + void setIsLast(bool is_last); + + void setResponseLength(std::size_t length); + + const std::chrono::milliseconds &getResponseLifetime() const; + + virtual void + setResponseLifetime(const std::chrono::milliseconds &response_lifetime); + +protected: + asio::streambuf streambuf_; + bool is_last_; + std::size_t response_length_; + std::chrono::milliseconds response_lifetime_; +}; + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/socket_request.cc b/apps/src/http-server/http-server/socket_request.cc new file mode 100644 index 000000000..321d9c61a --- /dev/null +++ b/apps/src/http-server/http-server/socket_request.cc @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "socket_request.h" + +namespace icn_httpserver { + +void SocketRequest::read_remote_endpoint_data(socket_type &socket) { + try { + remote_endpoint_address_ = + socket.lowest_layer().remote_endpoint().address().to_string(); + remote_endpoint_port_ = socket.lowest_layer().remote_endpoint().port(); + } catch (const std::exception &) { + } +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/socket_request.h b/apps/src/http-server/http-server/socket_request.h new file mode 100644 index 000000000..c6566a207 --- /dev/null +++ b/apps/src/http-server/http-server/socket_request.h @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include "request.h" + +namespace icn_httpserver { + +class SocketRequest : public Request { +public: + void read_remote_endpoint_data(socket_type &socket); + +private: + std::string remote_endpoint_address_; + unsigned short remote_endpoint_port_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/socket_response.cc b/apps/src/http-server/http-server/socket_response.cc new file mode 100644 index 000000000..5095c614f --- /dev/null +++ b/apps/src/http-server/http-server/socket_response.cc @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "socket_response.h" + +namespace icn_httpserver { + +SocketResponse::SocketResponse(std::shared_ptr<asio::ip::tcp::socket> socket) + : socket_(socket) {} + +SocketResponse::~SocketResponse(){}; + +void SocketResponse::send(const SendCallback &callback) { + asio::async_write( + *this->socket_, this->streambuf_, + [callback](const std::error_code &ec, size_t /*bytes_transferred*/) { + if (callback) { + callback(ec); + } + }); +} + +const std::shared_ptr<socket_type> &SocketResponse::getSocket() const { + return socket_; +} + +void SocketResponse::setSocket(const std::shared_ptr<socket_type> &socket) { + SocketResponse::socket_ = socket; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/socket_response.h b/apps/src/http-server/http-server/socket_response.h new file mode 100644 index 000000000..b582809dc --- /dev/null +++ b/apps/src/http-server/http-server/socket_response.h @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include "response.h" + +namespace icn_httpserver { + +class SocketResponse : public Response { +public: + SocketResponse(std::shared_ptr<socket_type> socket); + + ~SocketResponse(); + + void send(const SendCallback &callback = nullptr); + + const std::shared_ptr<socket_type> &getSocket() const; + + void setSocket(const std::shared_ptr<socket_type> &socket); + +private: + std::shared_ptr<socket_type> socket_; +}; + +} // end namespace icn_httpserver |