From 1ad06afe9f952642a26f4d28239cf05eb3283eb7 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Tue, 19 Mar 2019 14:26:52 +0100 Subject: [HICN-6] ATS Working, little refactoring of apps Change-Id: I174815b70bf3a9fbe99ffab7dd2914be04d364b9 Signed-off-by: Mauro Sardara --- CMakeLists.txt | 4 +- apps/CMakeLists.txt | 11 +- apps/README.md | 30 ++ apps/higet/CMakeLists.txt | 35 ++ apps/higet/higet.cc | 164 ++++++++ apps/http-proxy/CMakeLists.txt | 66 ++++ apps/http-proxy/main.cc | 65 ++++ apps/http-proxy/src/ATSConnector.cc | 224 +++++++++++ apps/http-proxy/src/ATSConnector.h | 99 +++++ apps/http-proxy/src/HTTP1.xMessageFastParser.cc | 71 ++++ apps/http-proxy/src/HTTP1.xMessageFastParser.h | 34 ++ apps/http-proxy/src/IcnReceiver.cc | 174 +++++++++ apps/http-proxy/src/IcnReceiver.h | 69 ++++ apps/http-server/CMakeLists.txt | 85 +++++ apps/http-server/http-client/http_client.h | 35 ++ apps/http-server/http-client/http_client_icn.cc | 37 ++ apps/http-server/http-client/http_client_icn.h | 34 ++ apps/http-server/http-client/http_client_tcp.cc | 99 +++++ apps/http-server/http-client/http_client_tcp.h | 36 ++ apps/http-server/http-server.cc | 393 +++++++++++++++++++ apps/http-server/http-server/common.h | 34 ++ apps/http-server/http-server/configuration.cc | 47 +++ apps/http-server/http-server/configuration.h | 49 +++ apps/http-server/http-server/content.cc | 31 ++ apps/http-server/http-server/content.h | 34 ++ apps/http-server/http-server/http_server.cc | 409 ++++++++++++++++++++ apps/http-server/http-server/http_server.h | 109 ++++++ apps/http-server/http-server/icn_request.cc | 60 +++ apps/http-server/http-server/icn_request.h | 53 +++ apps/http-server/http-server/icn_response.cc | 49 +++ apps/http-server/http-server/icn_response.h | 39 ++ apps/http-server/http-server/request.cc | 71 ++++ apps/http-server/http-server/request.h | 91 +++++ apps/http-server/http-server/response.cc | 48 +++ apps/http-server/http-server/response.h | 50 +++ apps/http-server/http-server/socket_request.cc | 29 ++ apps/http-server/http-server/socket_request.h | 31 ++ apps/http-server/http-server/socket_response.cc | 43 +++ apps/http-server/http-server/socket_response.h | 38 ++ apps/src/higet/CMakeLists.txt | 41 -- apps/src/higet/higet.cc | 168 --------- apps/src/http-server/CMakeLists.txt | 79 ---- apps/src/http-server/config.h.in | 19 - apps/src/http-server/http-client/http_client.h | 37 -- .../src/http-server/http-client/http_client_icn.cc | 37 -- apps/src/http-server/http-client/http_client_icn.h | 34 -- .../src/http-server/http-client/http_client_tcp.cc | 99 ----- apps/src/http-server/http-client/http_client_tcp.h | 36 -- apps/src/http-server/http-server.cc | 406 -------------------- apps/src/http-server/http-server/common.h | 43 --- apps/src/http-server/http-server/configuration.cc | 47 --- apps/src/http-server/http-server/configuration.h | 49 --- apps/src/http-server/http-server/content.cc | 31 -- apps/src/http-server/http-server/content.h | 34 -- apps/src/http-server/http-server/http_server.cc | 416 --------------------- apps/src/http-server/http-server/http_server.h | 118 ------ apps/src/http-server/http-server/icn_request.cc | 60 --- apps/src/http-server/http-server/icn_request.h | 53 --- apps/src/http-server/http-server/icn_response.cc | 49 --- apps/src/http-server/http-server/icn_response.h | 39 -- apps/src/http-server/http-server/request.cc | 71 ---- apps/src/http-server/http-server/request.h | 91 ----- apps/src/http-server/http-server/response.cc | 48 --- apps/src/http-server/http-server/response.h | 50 --- apps/src/http-server/http-server/socket_request.cc | 38 -- apps/src/http-server/http-server/socket_request.h | 40 -- .../src/http-server/http-server/socket_response.cc | 52 --- apps/src/http-server/http-server/socket_response.h | 47 --- .../src/hicn/transport/core/forwarder_interface.h | 2 +- libtransport/src/hicn/transport/core/packet.cc | 4 +- libtransport/src/hicn/transport/core/packet.h | 2 +- .../src/hicn/transport/http/client_connection.cc | 8 +- .../transport/interfaces/full_duplex_socket.cc | 16 +- .../hicn/transport/interfaces/full_duplex_socket.h | 7 - .../transport/interfaces/publication_options.h | 19 +- .../src/hicn/transport/utils/content_store.cc | 2 +- .../src/hicn/transport/utils/content_store.h | 4 +- utils/sysrepo-plugin/CMakeLists.txt | 2 +- 78 files changed, 3106 insertions(+), 2372 deletions(-) create mode 100644 apps/higet/CMakeLists.txt create mode 100644 apps/higet/higet.cc create mode 100644 apps/http-proxy/CMakeLists.txt create mode 100644 apps/http-proxy/main.cc create mode 100644 apps/http-proxy/src/ATSConnector.cc create mode 100644 apps/http-proxy/src/ATSConnector.h create mode 100644 apps/http-proxy/src/HTTP1.xMessageFastParser.cc create mode 100644 apps/http-proxy/src/HTTP1.xMessageFastParser.h create mode 100644 apps/http-proxy/src/IcnReceiver.cc create mode 100644 apps/http-proxy/src/IcnReceiver.h create mode 100644 apps/http-server/CMakeLists.txt create mode 100644 apps/http-server/http-client/http_client.h create mode 100644 apps/http-server/http-client/http_client_icn.cc create mode 100644 apps/http-server/http-client/http_client_icn.h create mode 100644 apps/http-server/http-client/http_client_tcp.cc create mode 100644 apps/http-server/http-client/http_client_tcp.h create mode 100644 apps/http-server/http-server.cc create mode 100644 apps/http-server/http-server/common.h create mode 100644 apps/http-server/http-server/configuration.cc create mode 100644 apps/http-server/http-server/configuration.h create mode 100644 apps/http-server/http-server/content.cc create mode 100644 apps/http-server/http-server/content.h create mode 100644 apps/http-server/http-server/http_server.cc create mode 100644 apps/http-server/http-server/http_server.h create mode 100644 apps/http-server/http-server/icn_request.cc create mode 100644 apps/http-server/http-server/icn_request.h create mode 100644 apps/http-server/http-server/icn_response.cc create mode 100644 apps/http-server/http-server/icn_response.h create mode 100644 apps/http-server/http-server/request.cc create mode 100644 apps/http-server/http-server/request.h create mode 100644 apps/http-server/http-server/response.cc create mode 100644 apps/http-server/http-server/response.h create mode 100644 apps/http-server/http-server/socket_request.cc create mode 100644 apps/http-server/http-server/socket_request.h create mode 100644 apps/http-server/http-server/socket_response.cc create mode 100644 apps/http-server/http-server/socket_response.h delete mode 100644 apps/src/higet/CMakeLists.txt delete mode 100644 apps/src/higet/higet.cc delete mode 100644 apps/src/http-server/CMakeLists.txt delete mode 100644 apps/src/http-server/config.h.in delete mode 100644 apps/src/http-server/http-client/http_client.h delete mode 100644 apps/src/http-server/http-client/http_client_icn.cc delete mode 100644 apps/src/http-server/http-client/http_client_icn.h delete mode 100644 apps/src/http-server/http-client/http_client_tcp.cc delete mode 100644 apps/src/http-server/http-client/http_client_tcp.h delete mode 100644 apps/src/http-server/http-server.cc delete mode 100644 apps/src/http-server/http-server/common.h delete mode 100644 apps/src/http-server/http-server/configuration.cc delete mode 100644 apps/src/http-server/http-server/configuration.h delete mode 100644 apps/src/http-server/http-server/content.cc delete mode 100644 apps/src/http-server/http-server/content.h delete mode 100644 apps/src/http-server/http-server/http_server.cc delete mode 100644 apps/src/http-server/http-server/http_server.h delete mode 100644 apps/src/http-server/http-server/icn_request.cc delete mode 100644 apps/src/http-server/http-server/icn_request.h delete mode 100644 apps/src/http-server/http-server/icn_response.cc delete mode 100644 apps/src/http-server/http-server/icn_response.h delete mode 100644 apps/src/http-server/http-server/request.cc delete mode 100644 apps/src/http-server/http-server/request.h delete mode 100644 apps/src/http-server/http-server/response.cc delete mode 100644 apps/src/http-server/http-server/response.h delete mode 100644 apps/src/http-server/http-server/socket_request.cc delete mode 100644 apps/src/http-server/http-server/socket_request.h delete mode 100644 apps/src/http-server/http-server/socket_response.cc delete mode 100644 apps/src/http-server/http-server/socket_response.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a2cd8edd7..9a4136e3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ option(BUILD_LIBHICN "Build the hicn core library" ON) option(BUILD_HICNLIGHT "Build the hicn light forwarder" ON) option(BUILD_LIBTRANSPORT "Build the hicn transport library" ON) option(BUILD_UTILS "Build the hicn utils" ON) -option(BUILD_APPS "Build the hicn apps" ON) +option(BUILD_APPS "Build the hicn apps" OFF) option(BUILD_HICNPLUGIN "Build the hicn vpp plugin" OFF) list(APPEND dir_options @@ -68,7 +68,7 @@ set(LIBTRANSPORT hicntransport) set(HICN_UTILS hicn-utils) set(HICN_APPS hicn-apps) -if (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" ) +if (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") list(APPEND subdirs ${BUILD_HICNPLUGIN_DIR} ) diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 8907dfe5b..766c9c7e5 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -26,7 +26,6 @@ include(BuildMacros) include(WindowsMacros) find_package(Asio REQUIRED) -find_package(CURL REQUIRED) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) find_package(Libtransport REQUIRED) @@ -35,26 +34,24 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) else() set(LIBTRANSPORT_LIBRARIES ${LIBTRANSPORT_SHARED}) list(APPEND DEPENDENCIES - ${LIBHICN} - ${LIBHICN_SHARED} ${LIBTRANSPORT_LIBRARIES} ) endif() list(APPEND LIBRARIES ${LIBTRANSPORT_LIBRARIES} - ${CURL_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ) include(Packaging) -set (COMPILER_DEFINITIONS "") +set(COMPILER_DEFINITIONS "") if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4200 /wd4996") endif () -add_subdirectory(src/http-server) -add_subdirectory(src/higet) \ No newline at end of file +add_subdirectory(http-server) +add_subdirectory(http-proxy) +add_subdirectory(higet) \ No newline at end of file diff --git a/apps/README.md b/apps/README.md index 1311006f6..937d02248 100644 --- a/apps/README.md +++ b/apps/README.md @@ -65,6 +65,36 @@ Options: -z = hicn proxy prefix ``` +### hicn-http-proxy ### + +`hicn-http-proxy` is a reverse proxy which can be used for augmenting the performance of a legacy HTTP/TCP server +by making use of hICN. It performs the following operations: + +- Receives a HTTP request over hICN +- Forwards it to a HTTP server over TCP +- Receives the response from the server and publishes it + +Subsequently, other hICN client asking for the same HTTP message can retrieve it directly +through hICN, by retrieving it either from the forwarder caches or directly from the `hicn-http-proxy`. + +The proxy uses hICN names for performing the multiplexing of http requests, allowing a single +hICN proxy with a single producer socket to serve multiple consumers asking for the same content. Conversely, a normal +TCP proxy still needs to open one TCP connection per client. + +``` +hicn-http-proxy [HTTP_PREFIX] [OPTIONS] + +HTTP_PREFIX: The prefix used for building the hicn names. + +Options: +-a = origin server address +-p = origin server port +-c = cache size of the proxy, in number of hicn data packets + +Example: +./hicn-http-proxy http://webserver -a 127.0.0.1 -p 8080 -c 10000 +``` + ## License ## This software is distributed under the following license: diff --git a/apps/higet/CMakeLists.txt b/apps/higet/CMakeLists.txt new file mode 100644 index 000000000..5dcae66b2 --- /dev/null +++ b/apps/higet/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2017-2019 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +set(CMAKE_CXX_STANDARD 14) + +project(utils) + +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" +) + +list(APPEND APPS_SRC + higet.cc +) + +build_executable(higet + SOURCES ${APPS_SRC} + LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + DEPENDS ${LIBTRANSPORT} + COMPONENT higet + DEFINITIONS ${COMPILER_DEFINITIONS} +) diff --git a/apps/higet/higet.cc b/apps/higet/higet.cc new file mode 100644 index 000000000..7662c1a2b --- /dev/null +++ b/apps/higet/higet.cc @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2019 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 + +#include + +typedef std::chrono::time_point Time; +typedef std::chrono::milliseconds TimeDuration; + +Time t1; + +#define DEFAULT_BETA 0.99 +#define DEFAULT_GAMMA 0.07 + +namespace http { + +typedef struct { + std::string file_name; + bool print_headers; + std::string producer_certificate; +} Configuration; + +void processResponse(Configuration &conf, + transport::http::HTTPResponse &&response) { + auto &payload = response.getPayload(); + + if (conf.file_name != "-") { + std::cerr << "Saving to: " << conf.file_name << " " << payload.size() + << "kB" << std::endl; + } + + Time t3 = std::chrono::system_clock::now(); + + std::streambuf *buf; + std::ofstream of; + + if (conf.file_name != "-") { + of.open(conf.file_name, std::ofstream::binary); + buf = of.rdbuf(); + } else { + buf = std::cout.rdbuf(); + } + + std::ostream out(buf); + + if (conf.print_headers) { + auto &headers = response.getHeaders(); + out << "HTTP/" << response.getHttpVersion() << " " + << response.getStatusCode() << " " << response.getStatusString() + << "\n"; + for (auto &h : headers) { + out << h.first << ": " << h.second << "\n"; + } + out << "\n"; + } + + out.write((char *)payload.data(), payload.size()); + of.close(); + + Time t2 = std::chrono::system_clock::now(); + TimeDuration dt = + std::chrono::duration_cast(t2 - t1); + TimeDuration dt3 = + std::chrono::duration_cast(t3 - t1); + long msec = (long)dt.count(); + long msec3 = (long)dt3.count(); + std::cerr << "Elapsed Time: " << msec / 1000.0 << " seconds -- " + << payload.size() * 8 / msec / 1000.0 << "[Mbps] -- " + << payload.size() * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl; +} + +void usage(char *program_name) { + std::cerr << "usage:" << std::endl; + std::cerr << program_name << " [option]... [url]..." << std::endl; + std::cerr << program_name << "options:" << std::endl; + std::cerr << "-O = write documents to " + << std::endl; + std::cerr << "-S = print server response" + << std::endl; + std::cerr << "example:" << std::endl; + std::cerr << "\t" << program_name << " -O - http://origin/index.html" + << std::endl; + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { +#ifdef _WIN32 + WSADATA wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif + + Configuration conf; + conf.file_name = ""; + conf.print_headers = false; + conf.producer_certificate = ""; + + std::string name("http://webserver/sintel/mpd"); + + int opt; + while ((opt = getopt(argc, argv, "O:Sc:")) != -1) { + switch (opt) { + case 'O': + conf.file_name = optarg; + break; + case 'S': + conf.print_headers = true; + break; + case 'c': + conf.producer_certificate = optarg; + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + if (argv[optind] == 0) { + std::cerr << "Using default name " << name << std::endl; + } else { + name = argv[optind]; + } + + if (conf.file_name.empty()) { + conf.file_name = name.substr(1 + name.find_last_of("/")); + } + + std::map headers = {{"Host", "localhost"}, + {"User-Agent", "higet/1.0"}, + {"Connection", "Keep-Alive"}}; + + transport::http::HTTPClientConnection connection; + if (!conf.producer_certificate.empty()) { + connection.setCertificate(conf.producer_certificate); + } + + t1 = std::chrono::system_clock::now(); + + connection.get(name, headers); + processResponse(conf, connection.response()); + +#ifdef _WIN32 + WSACleanup(); +#endif + + return EXIT_SUCCESS; +} + +} // end namespace http + +int main(int argc, char **argv) { return http::main(argc, argv); } diff --git a/apps/http-proxy/CMakeLists.txt b/apps/http-proxy/CMakeLists.txt new file mode 100644 index 000000000..3d6b9c672 --- /dev/null +++ b/apps/http-proxy/CMakeLists.txt @@ -0,0 +1,66 @@ +# Copyright (c) 2019 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +set(CMAKE_CXX_STANDARD 14) + +if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release") +endif() + +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_SOURCE_DIR}/cmake/Modules/" +) + +find_package(Threads REQUIRED) +include_directories( + SYSTEM + ${CMAKE_BINARY_DIR} + ${LIB${TRANSPORT_LIBRARY}_INCLUDE_DIR} + http-server + http-client +) + +set(LIB_SOURCE_FILES + src/ATSConnector.cc + src/HTTP1.xMessageFastParser.cc + src/IcnReceiver.cc +) + +set(LIB_SERVER_HEADER_FILES + src/IcnReceiver.h + src/ATSConnector.h + src/HTTP1.xMessageFastParser.h +) + +set(APP_SOURCE_FILES + main.cc +) + +build_library(httpproxylib + STATIC + SOURCES ${LIB_SOURCE_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} +) + +build_executable(hicn-http-proxy + SOURCES ${APP_SOURCE_FILES} + LINK_LIBRARIES httpproxylib + DEPENDS httpproxylib + COMPONENT hicn-http-proxy + DEFINITIONS ${COMPILER_DEFINITIONS} +) \ No newline at end of file diff --git a/apps/http-proxy/main.cc b/apps/http-proxy/main.cc new file mode 100644 index 000000000..179da452b --- /dev/null +++ b/apps/http-proxy/main.cc @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 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 "src/IcnReceiver.h" + +using namespace transport; + +int usage(char* program) { + std::cerr << "ICN Plugin not loaded!" << std::endl; + std::cerr << "USAGE: " << program + << "[HTTP_PREFIX] -a [SERVER_IP_ADDRESS] " + "-p [SERVER_PORT] -c [CACHE_SIZE]" + << std::endl; + return -1; +} + +int main(int argc, char** argv) { + std::string prefix("http://hicn-http-proxy"); + std::string ip_address("127.0.0.1"); + std::string port("80"); + std::string cache_size("50000"); + + int opt; + while ((opt = getopt(argc, argv, "a:p:c:")) != -1) { + switch (opt) { + case 'a': + prefix = optarg; + break; + case 'p': + port = optarg; + break; + case 'c': + cache_size = optarg; + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + if (argv[optind] == 0) { + std::cerr << "Using default prefix " << prefix << std::endl; + } else { + prefix = argv[optind]; + } + + transport::AsyncConsumerProducer proxy(prefix, ip_address, port, cache_size); + + proxy.run(); + + return 0; +} \ No newline at end of file diff --git a/apps/http-proxy/src/ATSConnector.cc b/apps/http-proxy/src/ATSConnector.cc new file mode 100644 index 000000000..81f7a776a --- /dev/null +++ b/apps/http-proxy/src/ATSConnector.cc @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2019 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 "ATSConnector.h" +#include "HTTP1.xMessageFastParser.h" + +#include +#include +#include + +namespace transport { + +ATSConnector::ATSConnector(asio::io_service &io_service, + std::string &ip_address, std::string &port, + ContentReceivedCallback receive_callback, + OnReconnect on_reconnect_callback) + : io_service_(io_service), + socket_(io_service_), + resolver_(io_service_), + endpoint_iterator_(resolver_.resolve({ip_address, port})), + timer_(io_service), + is_reconnection_(false), + data_available_(false), + receive_callback_(receive_callback), + on_reconnect_callback_(on_reconnect_callback) { + header_input_buffer_.prepare(2048); + state_ = ConnectorState::CONNECTING; + doConnect(); +} + +ATSConnector::~ATSConnector() {} + +void ATSConnector::send(const uint8_t *packet, std::size_t len, + ContentSentCallback &&content_sent) { + asio::async_write( + socket_, asio::buffer(packet, len), + [content_sent = std::move(content_sent)]( + std::error_code ec, std::size_t /*length*/) { content_sent(); }); +} + +void ATSConnector::send(utils::MemBuf *buffer, + ContentSentCallback &&content_sent) { + io_service_.dispatch([this, buffer, callback = std::move(content_sent)]() { + bool write_in_progress = !write_msgs_.empty(); + write_msgs_.emplace_back(std::unique_ptr(buffer), + std::move(callback)); + if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { + if (!write_in_progress) { + doWrite(); + } + } else { + TRANSPORT_LOGD(" Tell the handle connect it has data to write"); + data_available_ = true; + } + }); +} + +void ATSConnector::close() { + if (state_ != ConnectorState::CLOSED) { + state_ = ConnectorState::CLOSED; + if (socket_.is_open()) { + socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); + socket_.close(); + // on_disconnect_callback_(); + } + } +} + +void ATSConnector::doWrite() { + auto &buffer = write_msgs_.front().first; + + asio::async_write(socket_, asio::buffer(buffer->data(), buffer->length()), + [this](std::error_code ec, std::size_t length) { + if (TRANSPORT_EXPECT_FALSE(!ec)) { + TRANSPORT_LOGD("Content successfully sent!"); + write_msgs_.front().second(); + write_msgs_.pop_front(); + if (!write_msgs_.empty()) { + doWrite(); + } + } else { + TRANSPORT_LOGD("Content NOT sent!"); + } + }); +} // namespace transport + +void ATSConnector::handleRead(std::error_code ec, std::size_t length, + std::size_t size) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + std::size_t bytes_in_buffer = length; + size -= bytes_in_buffer; + receive_callback_(input_buffer_, bytes_in_buffer, !size, false); + + if (!size) { + doReadHeader(); + } else { + auto to_read = size >= buffer_size ? buffer_size : size; + asio::async_read( + socket_, asio::buffer(input_buffer_, to_read), + std::bind(&ATSConnector::handleRead, this, std::placeholders::_1, + std::placeholders::_2, size)); + } + } else if (ec == asio::error::eof) { + tryReconnection(); + } +} + +void ATSConnector::doReadBody(std::size_t size) { + auto to_read = size >= buffer_size ? buffer_size : size; + asio::async_read( + socket_, asio::buffer(input_buffer_, to_read), + std::bind(&ATSConnector::handleRead, this, std::placeholders::_1, + std::placeholders::_2, size)); +} + +void ATSConnector::doReadHeader() { + asio::async_read_until( + socket_, header_input_buffer_, "\r\n\r\n", + [this](std::error_code ec, std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + // TRANSPORT_LOGD("Headers received"); + + const uint8_t *buffer = + asio::buffer_cast(header_input_buffer_.data()); + std::size_t size = HTTPMessageFastParser::hasBody(buffer, length); + + auto additional_bytes = header_input_buffer_.size() - length; + auto bytes_to_read = size - additional_bytes; + receive_callback_(buffer, header_input_buffer_.size(), !bytes_to_read, + true); + header_input_buffer_.consume(header_input_buffer_.size()); + + if (bytes_to_read) { + doReadBody(bytes_to_read); + } else { + doReadHeader(); + } + } else { + header_input_buffer_.consume(header_input_buffer_.size()); + tryReconnection(); + } + }); +} + +void ATSConnector::tryReconnection() { + TRANSPORT_LOGD("Connection lost. Trying to reconnect...\n"); + if (state_ == ConnectorState::CONNECTED) { + state_ = ConnectorState::CONNECTING; + is_reconnection_ = true; + io_service_.post([this]() { + if (socket_.is_open()) { + socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); + socket_.close(); + } + startConnectionTimer(); + doConnect(); + }); + } +} + +void ATSConnector::doConnect() { + asio::async_connect(socket_, endpoint_iterator_, + [this](std::error_code ec, tcp::resolver::iterator) { + if (!ec) { + timer_.cancel(); + state_ = ConnectorState::CONNECTED; + + asio::ip::tcp::no_delay noDelayOption(true); + socket_.set_option(noDelayOption); + + // on_reconnect_callback_(); + + doReadHeader(); + + if (data_available_ && !write_msgs_.empty()) { + data_available_ = false; + doWrite(); + } + + if (is_reconnection_) { + is_reconnection_ = false; + TRANSPORT_LOGD("Connection recovered!"); + } + + } else { + TRANSPORT_LOGE("Impossible to reconnect."); + close(); + } + }); +} + +bool ATSConnector::checkConnected() { + return state_ == ConnectorState::CONNECTED; +} + +void ATSConnector::startConnectionTimer() { + timer_.expires_from_now(std::chrono::seconds(10)); + timer_.async_wait( + std::bind(&ATSConnector::handleDeadline, this, std::placeholders::_1)); +} + +void ATSConnector::handleDeadline(const std::error_code &ec) { + if (!ec) { + io_service_.post([this]() { + socket_.close(); + TRANSPORT_LOGE("Error connecting. Is the server running?\n"); + io_service_.stop(); + }); + } +} + +} // namespace transport diff --git a/apps/http-proxy/src/ATSConnector.h b/apps/http-proxy/src/ATSConnector.h new file mode 100644 index 000000000..be5c2c8d5 --- /dev/null +++ b/apps/http-proxy/src/ATSConnector.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 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 + +#define ASIO_STANDALONE +#include +#include +#include + +namespace transport { + +using asio::ip::tcp; + +typedef std::function + ContentReceivedCallback; +typedef std::function OnReconnect; +typedef std::function ContentSentCallback; +typedef std::deque< + std::pair, ContentSentCallback>> + BufferQueue; + +class ATSConnector { + static constexpr uint32_t buffer_size = 1024 * 64; + + enum class ConnectorState { + CLOSED, + CONNECTING, + CONNECTED, + }; + + public: + ATSConnector(asio::io_service &io_service, std::string &ip_address, + std::string &port, ContentReceivedCallback receive_callback, + OnReconnect on_reconnect_callback); + + ~ATSConnector(); + + void send(const uint8_t *buffer, std::size_t len, + ContentSentCallback &&content_sent = 0); + + void send(utils::MemBuf *buffer, ContentSentCallback &&content_sent); + + void close(); + + private: + void doConnect(); + + void doReadHeader(); + + void doReadBody(std::size_t size); + + void doWrite(); + + bool checkConnected(); + + private: + void handleRead(std::error_code ec, std::size_t length, std::size_t bytes); + void tryReconnection(); + void startConnectionTimer(); + void handleDeadline(const std::error_code &ec); + + asio::io_service &io_service_; + asio::ip::tcp::socket socket_; + asio::ip::tcp::resolver resolver_; + asio::ip::tcp::resolver::iterator endpoint_iterator_; + asio::steady_timer timer_; + + BufferQueue write_msgs_; + + asio::streambuf header_input_buffer_; + uint8_t input_buffer_[buffer_size]; + + bool is_reconnection_; + bool data_available_; + + ContentReceivedCallback receive_callback_; + OnReconnect on_reconnect_callback_; + + // Connector state + ConnectorState state_; +}; + +} // namespace transport diff --git a/apps/http-proxy/src/HTTP1.xMessageFastParser.cc b/apps/http-proxy/src/HTTP1.xMessageFastParser.cc new file mode 100644 index 000000000..a03871649 --- /dev/null +++ b/apps/http-proxy/src/HTTP1.xMessageFastParser.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 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 "HTTP1.xMessageFastParser.h" + +#include +#include +#include + +std::string HTTPMessageFastParser::numbers = "0123456789"; +std::string HTTPMessageFastParser::content_length = "Content-Length"; +std::string HTTPMessageFastParser::cache_control = "Cache-Control"; +std::string HTTPMessageFastParser::mpd = "mpd"; +std::string HTTPMessageFastParser::connection = "Connection"; +std::string HTTPMessageFastParser::separator = "\r\n\r\n"; + +std::size_t HTTPMessageFastParser::hasBody(const uint8_t *headers, + std::size_t length) { + const char *buffer = reinterpret_cast(headers); + const char *begin = buffer; + const char *end = buffer + length; + + using std::experimental::make_boyer_moore_searcher; + auto it = std::experimental::search( + begin, end, + make_boyer_moore_searcher(content_length.begin(), content_length.end())); + + if (it != end) { + // Read header line + auto it2 = std::find_first_of(it, end, numbers.begin(), numbers.end()); + auto it3 = std::find(it2, end, '\n'); + + return std::stoul(std::string(it2, it3)); + } + + return 0; +} + +bool HTTPMessageFastParser::isMpdRequest(const uint8_t *headers, + std::size_t length) { + const char *buffer = reinterpret_cast(headers); + const char *begin = buffer; + const char *end = buffer + length; + + using std::experimental::make_boyer_moore_searcher; + auto it = std::experimental::search( + begin, end, make_boyer_moore_searcher(mpd.begin(), mpd.end())); + + if (it != end) { + return true; + } + + return false; +} + +uint32_t HTTPMessageFastParser::parseCacheControl(const uint8_t *headers, + std::size_t length) { + return 0; +} diff --git a/apps/http-proxy/src/HTTP1.xMessageFastParser.h b/apps/http-proxy/src/HTTP1.xMessageFastParser.h new file mode 100644 index 000000000..10a70c3e9 --- /dev/null +++ b/apps/http-proxy/src/HTTP1.xMessageFastParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 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 +#include + +class HTTPMessageFastParser { + public: + static std::size_t hasBody(const uint8_t* headers, std::size_t length); + static bool isMpdRequest(const uint8_t* headers, std::size_t length); + static uint32_t parseCacheControl(const uint8_t* headers, std::size_t length); + + private: + static std::string numbers; + static std::string content_length; + static std::string cache_control; + static std::string connection; + static std::string mpd; + static std::string separator; +}; diff --git a/apps/http-proxy/src/IcnReceiver.cc b/apps/http-proxy/src/IcnReceiver.cc new file mode 100644 index 000000000..ee8ef0823 --- /dev/null +++ b/apps/http-proxy/src/IcnReceiver.cc @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019 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 "IcnReceiver.h" +#include "HTTP1.xMessageFastParser.h" + +#include +#include + +#include +#include + +namespace transport { + +core::Prefix generatePrefix(const std::string& prefix_url) { + const char* str = prefix_url.c_str(); + uint16_t pos = 0; + + if (strncmp("http://", str, 7) == 0) { + pos = 7; + } else if (strncmp("https://", str, 8) == 0) { + pos = 8; + } + + str += pos; + + uint32_t locator_hash = utils::hash::fnv32_buf(str, strlen(str)); + + std::stringstream stream; + stream << std::hex << http::default_values::ipv6_first_word << ":0"; + + for (uint16_t* word = (uint16_t*)&locator_hash; + std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash)); + word++) { + stream << ":" << std::hex << *word; + } + + stream << "::0"; + + return core::Prefix(stream.str(), 64); +} + +AsyncConsumerProducer::AsyncConsumerProducer(const std::string& prefix, + std::string& ip_address, + std::string& port, + std::string& cache_size) + : prefix_(generatePrefix(prefix)), + producer_socket_(), + ip_address_(ip_address), + port_(port), + cache_size_(std::stoul(cache_size)), + request_counter_(0), + signals_(io_service_, SIGINT, SIGQUIT), + connector_(io_service_, ip_address_, port_, + std::bind(&AsyncConsumerProducer::publishContent, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4), + [this]() { + std::queue empty; + std::swap(response_name_queue_, empty); + }) { + int ret = producer_socket_.setSocketOption( + interface::GeneralTransportOptions::OUTPUT_BUFFER_SIZE, cache_size_); + + if (ret != SOCKET_OPTION_SET) { + TRANSPORT_LOGD("Warning: output buffer size has not been set."); + } + + producer_socket_.registerPrefix(prefix_); + + // Let the main thread to catch SIGINT and SIGQUIT + signals_.async_wait( + [this](const std::error_code& errorCode, int signal_number) { + TRANSPORT_LOGI("Number of requests processed by plugin: %lu", + (unsigned long)request_counter_); + producer_socket_.stop(); + connector_.close(); + }); +} + +void AsyncConsumerProducer::start() { + TRANSPORT_LOGD("Starting listening"); + doReceive(); +} + +void AsyncConsumerProducer::run() { + start(); + io_service_.run(); +} + +void AsyncConsumerProducer::doReceive() { + producer_socket_.setSocketOption( + interface::ProducerCallbacksOptions::CACHE_MISS, + [this](interface::ProducerSocket& producer, + interface::Interest& interest) { + // core::Name n(interest.getWritableName(), true); + io_service_.post(std::bind( + &AsyncConsumerProducer::manageIncomingInterest, this, + interest.getWritableName(), interest.acquireMemBufReference(), + interest.getPayload().release())); + }); + + producer_socket_.connect(); +} + +void AsyncConsumerProducer::manageIncomingInterest( + core::Name& name, core::Packet::MemBufPtr& packet, utils::MemBuf* payload) { + // auto seg = name.getSuffix(); + name.setSuffix(0); + auto _it = chunk_number_map_.find(name); + auto _end = chunk_number_map_.end(); + + if (_it != _end) { + return; + } + + bool is_mpd = + HTTPMessageFastParser::isMpdRequest(payload->data(), payload->length()); + + chunk_number_map_.emplace(name, 0); + response_name_queue_.emplace(std::move(name), is_mpd ? 500 : 10000); + + connector_.send(payload, [packet = std::move(packet)]() {}); +} + +void AsyncConsumerProducer::publishContent(const uint8_t* data, + std::size_t size, bool is_last, + bool headers) { + uint32_t start_suffix = 0; + + if (response_name_queue_.empty()) { + abort(); + } + + interface::PublicationOptions& options = response_name_queue_.front(); + + int ret = producer_socket_.setSocketOption( + interface::GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, + options.getLifetime()); + + if (TRANSPORT_EXPECT_FALSE(ret != SOCKET_OPTION_SET)) { + TRANSPORT_LOGD("Warning: content object lifetime has not been set."); + } + + const interface::Name& name = options.getName(); + + start_suffix = chunk_number_map_[name]; + + if (headers) { + request_counter_++; + } + + chunk_number_map_[name] += + producer_socket_.produce(name, data, size, is_last, start_suffix); + + if (is_last) { + chunk_number_map_.erase(name); + response_name_queue_.pop(); + } +} + +} // namespace transport diff --git a/apps/http-proxy/src/IcnReceiver.h b/apps/http-proxy/src/IcnReceiver.h new file mode 100644 index 000000000..7d5c5e4c8 --- /dev/null +++ b/apps/http-proxy/src/IcnReceiver.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 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 "ATSConnector.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace transport { + +class AsyncConsumerProducer { + public: + explicit AsyncConsumerProducer(const std::string& prefix, + std::string& ip_address, std::string& port, + std::string& cache_size); + + void start(); + + void run(); + + private: + void doSend(); + + void doReceive(); + + void publishContent(const uint8_t* data, std::size_t size, + bool is_last = true, bool headers = false); + + void manageIncomingInterest(core::Name& name, core::Packet::MemBufPtr& packet, + utils::MemBuf* payload); + + core::Prefix prefix_; + asio::io_service io_service_; + interface::ProducerSocket producer_socket_; + + std::string ip_address_; + std::string port_; + uint32_t cache_size_; + + uint64_t request_counter_; + asio::signal_set signals_; + + // std::unordered_map> + // connection_map_; + ATSConnector connector_; + std::unordered_map chunk_number_map_; + std::queue response_name_queue_; +}; + +} // namespace transport diff --git a/apps/http-server/CMakeLists.txt b/apps/http-server/CMakeLists.txt new file mode 100644 index 000000000..94aa9d43a --- /dev/null +++ b/apps/http-server/CMakeLists.txt @@ -0,0 +1,85 @@ +# Copyright (c) 2019 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +set(CMAKE_CXX_STANDARD 14) + +find_package(CURL REQUIRED) +list(APPEND LIBRARIES + ${CURL_LIBRARY} +) + +set(LIB_SOURCE_FILES + http-server/http_server.cc + http-server/response.cc + http-server/socket_response.cc + http-server/icn_response.cc + http-server/content.cc + http-server/request.cc + http-server/icn_request.cc + http-server/socket_request.cc + http-server/configuration.cc + http-client/http_client_tcp.cc + http-client/http_client_icn.cc +) + +set(LIB_SERVER_HEADER_FILES + http-server/http_server.h + http-server/response.h + http-server/common.h + http-server/socket_response.h + http-server/content.h + http-server/request.h + http-server/icn_request.h + http-server/socket_request.h + http-server/configuration.h + http-server/icn_response.h +) + +set(LIB_CLIENT_HEADER_FILES + http-client/http_client_tcp.h + http-client/http_client_icn.h + http-client/http_client.h +) + +set(APP_SOURCE_FILES + http-server.cc +) + +include_directories( + ${CMAKE_BINARY_DIR}/apps/http-server + http-server + http-client +) + +build_library(hicn-httpserver + STATIC + SOURCES ${LIB_SOURCE_FILES} ${LIB_SERVER_HEADER_FILES} ${LIB_CLIENT_HEADER_FILES} + INSTALL_HEADERS ${HEADER_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + COMPONENT lib${LIBTRANSPORT} + INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} + INSTALL_ROOT_DIR hicn/transport + DEFINITIONS ${COMPILER_DEFINITIONS} +) + +build_executable(hicn-http-server + SOURCES ${APP_SOURCE_FILES} + LINK_LIBRARIES hicn-httpserver ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + DEPENDS hicn-httpserver + COMPONENT ${HICN_APPS} + DEFINITIONS ${COMPILER_DEFINITIONS} +) + diff --git a/apps/http-server/http-client/http_client.h b/apps/http-server/http-client/http_client.h new file mode 100644 index 000000000..087a061ab --- /dev/null +++ b/apps/http-server/http-client/http_client.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019 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 + +#if defined(HICNET) +#include +#elif defined(ICNET) +#include +#else +#error "No ICN tranport library to which link against." +#endif + +class HTTPClient { + public: + virtual ~HTTPClient() = default; + + virtual void setTcp() = 0; + + virtual bool download(const std::string &url, std::ostream &out) = 0; +}; diff --git a/apps/http-server/http-client/http_client_icn.cc b/apps/http-server/http-client/http_client_icn.cc new file mode 100644 index 000000000..327d2eed1 --- /dev/null +++ b/apps/http-server/http-client/http_client_icn.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 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 "http_client_icn.h" +#include "response.h" + +#include + +using namespace std; + +HTTPClientIcn::HTTPClientIcn(uint32_t timeout) { + std::chrono::seconds _timeout(timeout); + connection_.setTimeout(_timeout); +} + +void HTTPClientIcn::setTcp() {} + +HTTPClientIcn::~HTTPClientIcn() {} + +bool HTTPClientIcn::download(const std::string &url, std::ostream &out) { + connection_.get(url); + libl4::http::HTTPResponse r = connection_.response(); + out.write(reinterpret_cast(r.data()), r.size()); + return true; +} diff --git a/apps/http-server/http-client/http_client_icn.h b/apps/http-server/http-client/http_client_icn.h new file mode 100644 index 000000000..5586f6d62 --- /dev/null +++ b/apps/http-server/http-client/http_client_icn.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 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 "http_client.h" + +#include + +class HTTPClientIcn : public HTTPClient { +public: + HTTPClientIcn(uint32_t timeout); + + void setTcp(); + + ~HTTPClientIcn(); + + bool download(const std::string &url, std::ostream &out); + +private: + libl4::http::HTTPClientConnection connection_; +}; diff --git a/apps/http-server/http-client/http_client_tcp.cc b/apps/http-server/http-client/http_client_tcp.cc new file mode 100644 index 000000000..530f8ef95 --- /dev/null +++ b/apps/http-server/http-client/http_client_tcp.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 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 "http_client_tcp.h" +#include "response.h" + +#include +#include +#include +#include +#include + +using namespace std; + +struct UserData { + void *out; + void *curl; + bool tcp; + bool first_time; +}; + +typedef struct UserData UserData; + +size_t write_data(void *ptr, size_t size, size_t nmemb, void *user_data) { + + UserData *data = (UserData *)user_data; + + if (data->first_time) { + double cl; + + int res = + curl_easy_getinfo(data->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); + + if (res >= 0) { + *(ostream *)data->out + << "HTTP/1.0 200 OK\r\nContent-Length: " << std::size_t(cl) + << "\r\n\r\n"; + } + + data->first_time = false; + } + + ((icn_httpserver::Response *)data->out) + ->write((const char *)ptr, size * nmemb); + // ((icn_httpserver::Response*) data->out)->send(); + return size * nmemb; +} + +HTTPClientTcp::HTTPClientTcp() { + tcp_ = false; + first_time = true; + curl_ = curl_easy_init(); +} + +void HTTPClientTcp::setTcp() { tcp_ = true; } + +HTTPClientTcp::~HTTPClientTcp() { curl_easy_cleanup(curl_); } + +bool HTTPClientTcp::download(const std::string &url, std::ostream &out) { + curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()); + + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl_, CURLOPT_ACCEPT_ENCODING, "deflate"); + + curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, write_data); + UserData data; + data.out = &out; + data.curl = curl_; + data.tcp = tcp_; + data.first_time = first_time; + + curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &data); + + /* Perform the request, res will get the return code */ + CURLcode res = curl_easy_perform(curl_); + + /* Check for errors */ + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + return false; + } + + return true; +} diff --git a/apps/http-server/http-client/http_client_tcp.h b/apps/http-server/http-client/http_client_tcp.h new file mode 100644 index 000000000..9433e8a36 --- /dev/null +++ b/apps/http-server/http-client/http_client_tcp.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 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 "http_client.h" + +#include + +class HTTPClientTcp : public HTTPClient { +public: + HTTPClientTcp(); + + void setTcp(); + + ~HTTPClientTcp(); + + bool download(const std::string &url, std::ostream &out); + +private: + bool first_time; + bool tcp_; + void *curl_; +}; diff --git a/apps/http-server/http-server.cc b/apps/http-server/http-server.cc new file mode 100644 index 000000000..9d3eac5b8 --- /dev/null +++ b/apps/http-server/http-server.cc @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2019 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 +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include "http-server/http_server.h" +#include "http_client_icn.h" +#include "http_client_tcp.h" + +#ifdef _WIN32 +#include +#endif + +typedef icn_httpserver::HttpServer HttpServer; +typedef icn_httpserver::Response Response; +typedef icn_httpserver::Request Request; + +namespace std { + +int _isDirectory(const char *path) { + struct stat statbuf; + if (stat(path, &statbuf) != 0) return -1; + return S_ISDIR(statbuf.st_mode); +} + +int _isRegularFile(const char *path) { + struct stat statbuf; + if (stat(path, &statbuf) != 0) return 0; + return S_ISREG(statbuf.st_mode); +} + +string _getFileName(const string &strPath) { + size_t iLastSeparator = 0; +#ifdef _WIN32 + return strPath.substr( + (iLastSeparator = strPath.find_last_of("\\")) != std::string::npos + ? iLastSeparator + 1 + : 0, + strPath.size() - strPath.find_last_of(".")); +#else + return strPath.substr( + (iLastSeparator = strPath.find_last_of("/")) != std::string::npos + ? iLastSeparator + 1 + : 0, + strPath.size() - strPath.find_last_of(".")); +#endif +} + +int _mkdir(const char *dir) { + std::cout << dir << std::endl; +#ifdef _WIN32 + char sepChar = '\\'; + char tmp[MAX_PATH]; +#else + char sepChar = '/'; + char tmp[PATH_MAX]; +#endif + char *p = NULL; + size_t len; + + snprintf(tmp, sizeof(tmp), "%s", dir); + len = strlen(tmp); + + if (tmp[len - 1] == sepChar) tmp[len - 1] = 0; + for (p = tmp + 1; *p; p++) { + if (*p == sepChar) { + *p = 0; + if (_isDirectory(tmp) != 1) { +#ifdef _WIN32 + if (!CreateDirectory(tmp, NULL)) { +#else + if (mkdir(tmp, S_IRWXU) == -1) { +#endif + return -1; + } + } + *p = sepChar; + } + } + + if (_isDirectory(tmp) != 1) { +#ifdef _WIN32 + if (!CreateDirectory(tmp, NULL)) { +#else + if (mkdir(tmp, S_IRWXU) == -1) { +#endif + return -1; + } + } + + return 0; +} + +string _getExtension(const string &strPath) { + size_t iLastSeparator = 0; + return strPath.substr( + (iLastSeparator = strPath.find_last_of(".")) != std::string::npos + ? iLastSeparator + 1 + : 0, + strPath.size()); +} + +void default_resource_send(const HttpServer &server, + shared_ptr response, + shared_ptr ifs, + shared_ptr> buffer, + std::size_t bytes_to_read) { + streamsize read_length; + + if ((read_length = ifs->read(&(*buffer)[0], buffer->size()).gcount()) > 0) { + response->write(&(*buffer)[0], read_length); + + if (bytes_to_read <= static_cast(buffer->size())) { + // If this is the last part of the response, send it at the pointer + // deletion! + return; + } + + std::size_t to_read = bytes_to_read - read_length; + server.send(response, [&server, response, ifs, buffer, + to_read](const std::error_code &ec) { + if (!ec) { + default_resource_send(server, response, ifs, buffer, to_read); + } else { + cerr << "Connection interrupted" << endl; + } + }); + } +} + +void afterSignal(HttpServer *webServer, const std::error_code &errorCode) { + cout << "\nGracefully terminating http-server... wait." << endl; + webServer->stop(); +} + +void usage(const char *programName) { + cerr << "usage: " << programName << " [options]" << endl; + cerr << programName << " options:" << endl; + cerr << "-p = path to root folder" << endl; + cerr << "-f = configuration file path" << endl; + cerr << "-o = tcp listener port" << endl; + cerr << "-l = webserver prefix" << endl; + cerr << "-x = tcp proxy prefix" << endl; + cerr << "-z = hicn proxy prefix" << endl; + cerr << endl; + cerr << "Web server able to publish content and generate http responses over " + "TCP/ICN" + << endl; + cerr << endl; + + exit(1); +} + +int main(int argc, char **argv) { + // Parse command line arguments + +#ifndef _WIN32 + string root_folder = "/var/www/html"; +#else + char path[MAX_PATH]; + SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path); + string root_folder(path); + root_folder += "\\www\\html"; +#endif + string webserver_prefix = "http://webserver"; + string tcp_proxy_address; + string icn_proxy_prefix; + int port = 8080; + int opt = 0; + + while ((opt = getopt(argc, argv, "p:l:o:hx:z:")) != -1) { + switch (opt) { + case 'p': + root_folder = optarg; + break; + case 'l': + webserver_prefix = optarg; + break; + case 'x': + tcp_proxy_address = optarg; + break; + case 'o': + port = atoi(optarg); + break; + case 'z': + icn_proxy_prefix = optarg; + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + if (_isDirectory(root_folder.c_str()) != 1) { + if (_mkdir(root_folder.c_str()) == -1) { + std::cerr << "The web root folder " << root_folder + << " does not exist and its creation failed. Exiting.." + << std::endl; + return (EXIT_FAILURE); + } + } + + std::cout << "Using web root folder: [" << root_folder << "]" << std::endl; + std::cout << "Using locator: [" << webserver_prefix << "]" << std::endl; + if (!tcp_proxy_address.empty()) { + std::cout << "Using TCP proxy: [" << tcp_proxy_address << "]" << std::endl; + } + if (!icn_proxy_prefix.empty()) { + std::cout << "Using ICN proxy: [" << icn_proxy_prefix << "]" << std::endl; + } + + asio::io_service io_service; + HttpServer server(port, webserver_prefix, 50, 5, 300, io_service); + + // GET for the path /info + // Responds with some server info + server.resource["^/info$"]["GET"] = [](shared_ptr response, + shared_ptr request) { + stringstream content_stream; + content_stream + << "

This webserver is able to reply to HTTP over TCP/ICN

"; + content_stream << request->getMethod() << " " << request->getPath() + << " HTTP/" << request->getHttp_version() << "
"; + + for (auto &header : request->getHeader()) { + content_stream << header.first << ": " << header.second << "
"; + } + + // find length of content_stream (length received using + // content_stream.tellp()) + content_stream.seekp(0, ios::end); + + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content_stream.tellp() + << "\r\n\r\n" + << content_stream.rdbuf(); + }; + + // Default GET-example. If no other matches, this anonymous function will be + // called. Will respond with content in the web/-directory, and its + // subdirectories. Default file: index.html Can for instance be used to + // retrieve an HTML 5 client that uses REST-resources on this server + server.default_resource["GET"] = + [&server, &root_folder, &tcp_proxy_address, &icn_proxy_prefix]( + shared_ptr response, shared_ptr request) { + const auto web_root_path = root_folder; + std::string path = web_root_path; + + // check if there is "/" + path = path + request->getPath(); + std::cout << "path:" << path << std::endl; + auto socket_request = + dynamic_cast(request.get()); + + std::chrono::milliseconds response_lifetime; + std::string stem = _getFileName(path); + std::string extension = _getExtension(path); + if (extension == "mpd" || stem == "latest") { + std::cout << "1 second" << std::endl; + std::cout << "Setting lifetime to 1 second" << std::endl; + response_lifetime = std::chrono::milliseconds(1000); + } else { + std::cout << "5 second" << std::endl; + std::cout << "Setting lifetime to 5 second" << std::endl; + response_lifetime = std::chrono::milliseconds(5000); + } + + response->setResponseLifetime(response_lifetime); + + if (_isDirectory(path.c_str())) { + // Check if path is within web_root_path + if (distance(web_root_path.begin(), web_root_path.end()) <= + distance(path.begin(), path.end()) && + equal(web_root_path.begin(), web_root_path.end(), path.begin())) { + path += "index.html"; + if (_isRegularFile(path.c_str())) { + auto ifs = make_shared(); + ifs->open(path, ifstream::in | ios::binary); + + if (*ifs) { + // read and send 15 MB at a time + streamsize buffer_size = 15 * 1024 * 1024; + auto buffer = make_shared>(buffer_size); + + ifs->seekg(0, ios::end); + auto length = ifs->tellg(); + ifs->seekg(0, ios::beg); + + response->setResponseLength(length); + *response << "HTTP/1.0 200 OK\r\nContent-Length: " << length + << "\r\n\r\n"; + + default_resource_send(server, response, ifs, buffer, length); + + return; + } + } + } + } + + string proxy; + HTTPClient *client = nullptr; + + if (tcp_proxy_address.empty() && !icn_proxy_prefix.empty()) { + proxy = icn_proxy_prefix; + client = new HTTPClientIcn(20); + } else if (!tcp_proxy_address.empty() && icn_proxy_prefix.empty()) { + proxy = tcp_proxy_address; + client = new HTTPClientTcp; + } else if (!tcp_proxy_address.empty() && !icn_proxy_prefix.empty()) { + if (socket_request) { + proxy = icn_proxy_prefix; + client = new HTTPClientIcn(20); + } else { + proxy = tcp_proxy_address; + client = new HTTPClientTcp; + } + } + + if (!proxy.empty()) { + // Fetch content from remote origin + std::stringstream ss; + + if (strncmp("http://", proxy.c_str(), 7) != 0) { + if (strncmp("https://", proxy.c_str(), 8) != 0) { + ss << "https://"; + } else { + ss << "http://"; + } + } + + ss << proxy; + ss << request->getPath(); + + std::cout << "Forwarding request to " << ss.str() << std::endl; + + client->download(ss.str(), *response); + + delete client; + + if (response->size() == 0) { + *response << "HTTP/1.1 504 Gateway Timeout\r\n\r\n"; + } + + return; + } + + string content = "Could not open path " + request->getPath() + "\n"; + + *response << "HTTP/1.1 404 Not found\r\nContent-Length: " + << content.length() << "\r\n\r\n" + << content; + }; + + // Let the main thread to catch SIGINT + asio::signal_set signals(io_service, SIGINT); + signals.async_wait(bind(afterSignal, &server, placeholders::_1)); + + thread server_thread([&server]() { + // Start server + server.start(); + }); + + if (server_thread.joinable()) { + server_thread.join(); + } + + return 0; +} + +} // end namespace std + +int main(int argc, char **argv) { return std::main(argc, argv); } diff --git a/apps/http-server/http-server/common.h b/apps/http-server/http-server/common.h new file mode 100644 index 000000000..d61ddefe5 --- /dev/null +++ b/apps/http-server/http-server/common.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef asio::ip::tcp::socket socket_type; +typedef std::function SendCallback; diff --git a/apps/http-server/http-server/configuration.cc b/apps/http-server/http-server/configuration.cc new file mode 100644 index 000000000..8aa371432 --- /dev/null +++ b/apps/http-server/http-server/configuration.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 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/http-server/http-server/configuration.h b/apps/http-server/http-server/configuration.h new file mode 100644 index 000000000..8404025a6 --- /dev/null +++ b/apps/http-server/http-server/configuration.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 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/http-server/http-server/content.cc b/apps/http-server/http-server/content.cc new file mode 100644 index 000000000..86b7afc47 --- /dev/null +++ b/apps/http-server/http-server/content.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 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/http-server/http-server/content.h b/apps/http-server/http-server/content.h new file mode 100644 index 000000000..d1e6fecd2 --- /dev/null +++ b/apps/http-server/http-server/content.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 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/http-server/http-server/http_server.cc b/apps/http-server/http-server/http_server.cc new file mode 100644 index 000000000..a2e911e10 --- /dev/null +++ b/apps/http-server/http-server/http_server.cc @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2019 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 "http_server.h" + +#include +#include +#include + +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()), + 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 &publisher, + const uint8_t *buffer, std::size_t size, int request_id) { + std::shared_ptr request = std::make_shared(publisher); + request->getContent().rdbuf()->sputn((char *)buffer, size); + + if (!parse_request(request, request->getContent())) { + return; + } + + std::map> + &icn_publishers = icn_acceptor_->getPublishers(); + + std::unique_lock 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> + &icn_publishers = icn_acceptor_->getPublishers(); + find_resource(nullptr, request); + icn_publishers[request_id]->serveClients(); + std::unique_lock lock(thread_list_mtx_); + icn_publishers.erase(request_id); + }); + } +} + +void HttpServer::setIcnAcceptor() { + icn_acceptor_ = std::make_shared( + 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> + &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 = + std::make_shared(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, + SendCallback callback) const { + response->send(callback); +} + +std::shared_ptr HttpServer::set_timeout_on_socket( + std::shared_ptr socket, long seconds) { + std::shared_ptr timer = + std::make_shared(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) { + // 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 = std::make_shared(); + request->read_remote_endpoint_data(*socket); + + // Set timeout on the following asio::async-read or write function + std::shared_ptr 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 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, + 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, + std::shared_ptr 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, + std::shared_ptr request, + ResourceCallback &resource_function) { + // Set timeout on the following asio::async-read or write function + std::shared_ptr 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(request)->getHttpPublisher(), + std::static_pointer_cast(request)->getName(), + std::static_pointer_cast(request)->getPath()); + } + + auto response = std::shared_ptr(resp, [this, request, timer, + socket]( + Response *response_ptr) { + auto response = std::shared_ptr(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(response)->getSocket()); + } + } + }); + }); + + try { + resource_function(response, request); + } catch (const std::exception &) { + return; + } +} + +} // end namespace icn_httpserver diff --git a/apps/http-server/http-server/http_server.h b/apps/http-server/http-server/http_server.h new file mode 100644 index 000000000..cb963a900 --- /dev/null +++ b/apps/http-server/http-server/http_server.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 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 "configuration.h" +#include "icn_request.h" +#include "icn_response.h" +#include "socket_request.h" +#include "socket_response.h" + +typedef std::function, + std::shared_ptr)> + 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, + SendCallback callback = nullptr) const; + + std::unordered_map> + resource; + + std::unordered_map default_resource; + + void onIcnRequest( + std::shared_ptr &publisher, + const uint8_t *buffer, std::size_t size, int request_id); + + private: + void spawnThreads(); + + void setIcnAcceptor(); + + std::shared_ptr set_timeout_on_socket( + std::shared_ptr socket, long seconds); + + void read_request_and_content(std::shared_ptr socket); + + bool parse_request(std::shared_ptr request, + std::istream &stream) const; + + void find_resource(std::shared_ptr socket, + std::shared_ptr request); + + void write_response(std::shared_ptr socket, + std::shared_ptr request, + ResourceCallback &resource_function); + + Configuration config_; + + std::vector>>> + opt_resource_; + + std::shared_ptr internal_io_service_; + asio::io_service &io_service_; + asio::ip::tcp::acceptor acceptor_; + std::vector socket_threads_; + std::string icn_name_; + std::shared_ptr icn_acceptor_; + std::mutex thread_list_mtx_; + + long timeout_request_; + long timeout_content_; +}; + +} // end namespace icn_httpserver diff --git a/apps/http-server/http-server/icn_request.cc b/apps/http-server/http-server/icn_request.cc new file mode 100644 index 000000000..3f85a927b --- /dev/null +++ b/apps/http-server/http-server/icn_request.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 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 &publisher) + : publisher_(publisher) { + time_t t; + time(&t); + srand((unsigned int)t); + request_id_ = rand(); +} + +IcnRequest::IcnRequest( + std::shared_ptr &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 & +IcnRequest::getHttpPublisher() const { + return publisher_; +} + +void IcnRequest::setProducer( + const std::shared_ptr &producer) { + IcnRequest::publisher_ = producer; +} + +} // end namespace icn_httpserver diff --git a/apps/http-server/http-server/icn_request.h b/apps/http-server/http-server/icn_request.h new file mode 100644 index 000000000..230197d3f --- /dev/null +++ b/apps/http-server/http-server/icn_request.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 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 &publisher); + + IcnRequest(std::shared_ptr &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 & + getHttpPublisher() const; + + void setProducer( + const std::shared_ptr &producer); + +private: + std::string name_; + int request_id_; + std::shared_ptr publisher_; +}; + +} // end namespace icn_httpserver \ No newline at end of file diff --git a/apps/http-server/http-server/icn_response.cc b/apps/http-server/http-server/icn_response.cc new file mode 100644 index 000000000..0fcfa9493 --- /dev/null +++ b/apps/http-server/http-server/icn_response.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 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 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(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/http-server/http-server/icn_response.h b/apps/http-server/http-server/icn_response.h new file mode 100644 index 000000000..90cd33313 --- /dev/null +++ b/apps/http-server/http-server/icn_response.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 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 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 publisher_; +}; + +} // end namespace icn_httpserver diff --git a/apps/http-server/http-server/request.cc b/apps/http-server/http-server/request.cc new file mode 100644 index 000000000..1e3d5b81d --- /dev/null +++ b/apps/http-server/http-server/request.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 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 & +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/http-server/http-server/request.h b/apps/http-server/http-server/request.h new file mode 100644 index 000000000..393556edb --- /dev/null +++ b/apps/http-server/http-server/request.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 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 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 & + 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 header_; + std::smatch path_match_; + asio::streambuf streambuf_; +}; + +} // end namespace icn_httpserver diff --git a/apps/http-server/http-server/response.cc b/apps/http-server/http-server/response.cc new file mode 100644 index 000000000..ce5919934 --- /dev/null +++ b/apps/http-server/http-server/response.cc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 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/http-server/http-server/response.h b/apps/http-server/http-server/response.h new file mode 100644 index 000000000..27be566bf --- /dev/null +++ b/apps/http-server/http-server/response.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 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/http-server/http-server/socket_request.cc b/apps/http-server/http-server/socket_request.cc new file mode 100644 index 000000000..7affe08f3 --- /dev/null +++ b/apps/http-server/http-server/socket_request.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 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 "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/http-server/http-server/socket_request.h b/apps/http-server/http-server/socket_request.h new file mode 100644 index 000000000..020b7f5b4 --- /dev/null +++ b/apps/http-server/http-server/socket_request.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 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 "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/http-server/http-server/socket_response.cc b/apps/http-server/http-server/socket_response.cc new file mode 100644 index 000000000..07ef96045 --- /dev/null +++ b/apps/http-server/http-server/socket_response.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 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 "socket_response.h" + +namespace icn_httpserver { + +SocketResponse::SocketResponse(std::shared_ptr 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 &SocketResponse::getSocket() const { + return socket_; +} + +void SocketResponse::setSocket(const std::shared_ptr &socket) { + SocketResponse::socket_ = socket; +} + +} // end namespace icn_httpserver diff --git a/apps/http-server/http-server/socket_response.h b/apps/http-server/http-server/socket_response.h new file mode 100644 index 000000000..477fb30cb --- /dev/null +++ b/apps/http-server/http-server/socket_response.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 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 SocketResponse : public Response { + public: + SocketResponse(std::shared_ptr socket); + + ~SocketResponse(); + + void send(const SendCallback &callback = nullptr); + + const std::shared_ptr &getSocket() const; + + void setSocket(const std::shared_ptr &socket); + + private: + std::shared_ptr socket_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/higet/CMakeLists.txt b/apps/src/higet/CMakeLists.txt deleted file mode 100644 index a144d4c08..000000000 --- a/apps/src/higet/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2017-2019 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. - -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) -set(CMAKE_CXX_STANDARD 14) - -project(utils) - -set(CMAKE_MODULE_PATH - ${CMAKE_MODULE_PATH} - "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules" - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" -) - -list(APPEND APPS_SRC - higet.cc -) - - -foreach(app ${APPS_SRC}) - get_filename_component(_app_name ${app} NAME) - string(REGEX REPLACE ".cc" "" app_name ${_app_name}) - - build_executable(${app_name} - SOURCES ${app} - LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} - DEPENDS ${LIBTRANSPORT} - COMPONENT ${HICN_APPS} - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endforeach() diff --git a/apps/src/higet/higet.cc b/apps/src/higet/higet.cc deleted file mode 100644 index 1d1379887..000000000 --- a/apps/src/higet/higet.cc +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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 - -#include - -typedef std::chrono::time_point Time; -typedef std::chrono::milliseconds TimeDuration; - -Time t1; - -#define DEFAULT_BETA 0.99 -#define DEFAULT_GAMMA 0.07 - -namespace hicnet { - -namespace http { - -typedef struct { - std::string file_name; - bool print_headers; - std::string producer_certificate; -} Configuration; - -void processResponse(Configuration &conf, - transport::http::HTTPResponse &&response) { - - auto &payload = response.getPayload(); - - if (conf.file_name != "-") { - std::cerr << "Saving to: " << conf.file_name << " " << payload.size() - << "kB" << std::endl; - } - - Time t3 = std::chrono::system_clock::now(); - - std::streambuf *buf; - std::ofstream of; - - if (conf.file_name != "-") { - of.open(conf.file_name, std::ofstream::binary); - buf = of.rdbuf(); - } else { - buf = std::cout.rdbuf(); - } - - std::ostream out(buf); - - if (conf.print_headers) { - auto &headers = response.getHeaders(); - out << "HTTP/" << response.getHttpVersion() << " " - << response.getStatusCode() << " " << response.getStatusString() - << "\n"; - for (auto &h : headers) { - out << h.first << ": " << h.second << "\n"; - } - out << "\n"; - } - - out.write((char *)payload.data(), payload.size()); - of.close(); - - Time t2 = std::chrono::system_clock::now(); - ; - TimeDuration dt = - std::chrono::duration_cast(t2 - t1); - TimeDuration dt3 = - std::chrono::duration_cast(t3 - t1); - long msec = (long)dt.count(); - long msec3 = (long)dt3.count(); - std::cerr << "Elapsed Time: " << msec / 1000.0 << " seconds -- " - << payload.size() * 8 / msec / 1000.0 << "[Mbps] -- " - << payload.size() * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl; -} - -void usage(char *program_name) { - std::cerr << "usage:" << std::endl; - std::cerr << program_name << " [option]... [url]..." << std::endl; - std::cerr << program_name << "options:" << std::endl; - std::cerr << "-O = write documents to " << std::endl; - std::cerr << "-S = print server response" << std::endl; - std::cerr << "example:" << std::endl; - std::cerr << "\t" << program_name << " -O - http://origin/index.html" - << std::endl; - exit(EXIT_FAILURE); -} - -int main(int argc, char **argv) { - -#ifdef _WIN32 - WSADATA wsaData = {0}; - WSAStartup(MAKEWORD(2, 2), &wsaData); -#endif - - Configuration conf; - conf.file_name = ""; - conf.print_headers = false; - conf.producer_certificate = ""; - - std::string name("http://webserver/sintel/mpd"); - - int opt; - while ((opt = getopt(argc, argv, "O:Sc:")) != -1) { - switch (opt) { - case 'O': - conf.file_name = optarg; - break; - case 'S': - conf.print_headers = true; - break; - case 'c': - conf.producer_certificate = optarg; - break; - case 'h': - default: - usage(argv[0]); - break; - } - } - - if (argv[optind] == 0) { - std::cerr << "Using default name " << name << std::endl; - } else { - name = argv[optind]; - } - - if (conf.file_name.empty()) { - conf.file_name = name.substr(1 + name.find_last_of("/")); - } - - std::map headers = {{"Host", "localhost"}, - {"User-Agent", "higet/1.0"}}; - - transport::http::HTTPClientConnection connection; - if (!conf.producer_certificate.empty()) { - connection.setCertificate(conf.producer_certificate); - } - - t1 = std::chrono::system_clock::now(); - - connection.get(name, headers); - processResponse(conf, connection.response()); - -#ifdef _WIN32 - WSACleanup(); -#endif - - return EXIT_SUCCESS; -} - -} // end namespace http - -} // end namespace hicnet - -int main(int argc, char **argv) { return hicnet::http::main(argc, argv); } diff --git a/apps/src/http-server/CMakeLists.txt b/apps/src/http-server/CMakeLists.txt deleted file mode 100644 index a005f1a8f..000000000 --- a/apps/src/http-server/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# 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. - -cmake_minimum_required(VERSION 3.2) - -set(CMAKE_CXX_STANDARD 14) - -option(HICNET "Link against Libhicnet." ON) - -configure_file("${PROJECT_SOURCE_DIR}/src/http-server/config.h.in" - "${CMAKE_BINARY_DIR}/apps/http-server/config.h") - -set(LIB_SOURCE_FILES - http-server/http_server.cc - http-server/response.cc - http-server/socket_response.cc - http-server/icn_response.cc - http-server/content.cc - http-server/request.cc - http-server/icn_request.cc - http-server/socket_request.cc - http-server/configuration.cc - http-client/http_client_tcp.cc - http-client/http_client_icn.cc) - -set(LIB_SERVER_HEADER_FILES - http-server/http_server.h - http-server/response.h - http-server/common.h - http-server/socket_response.h - http-server/content.h - http-server/request.h - http-server/icn_request.h - http-server/socket_request.h - http-server/configuration.h - ${CMAKE_BINARY_DIR}/apps/http-server/config.h - http-server/icn_response.h) - -set(LIB_CLIENT_HEADER_FILES - http-client/http_client_tcp.h - http-client/http_client_icn.h - http-client/http_client.h) - -set(APP_SOURCE_FILES - http-server.cc) - -include_directories(${CMAKE_BINARY_DIR}/apps/http-server http-server http-client) - -build_library(hicn-httpserver - STATIC - SOURCES ${LIB_SOURCE_FILES} ${LIB_SERVER_HEADER_FILES} ${LIB_CLIENT_HEADER_FILES} - INSTALL_HEADERS ${HEADER_FILES} - LINK_LIBRARIES ${LIBRARIES} - DEPENDS ${DEPENDENCIES} - COMPONENT lib${LIBTRANSPORT} - INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} - INSTALL_ROOT_DIR hicn/transport - DEFINITIONS ${COMPILER_DEFINITIONS} -) - - -build_executable(hicn-http-server - SOURCES ${APP_SOURCE_FILES} - LINK_LIBRARIES hicn-httpserver ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} - DEPENDS hicn-httpserver - COMPONENT ${HICN_APPS} - DEFINITIONS ${COMPILER_DEFINITIONS} -) - diff --git a/apps/src/http-server/config.h.in b/apps/src/http-server/config.h.in deleted file mode 100644 index d10e62ee2..000000000 --- a/apps/src/http-server/config.h.in +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 - -#cmakedefine ICNET -#cmakedefine HICNET diff --git a/apps/src/http-server/http-client/http_client.h b/apps/src/http-server/http-client/http_client.h deleted file mode 100644 index b2dbd1ffd..000000000 --- a/apps/src/http-server/http-client/http_client.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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" - -#include - -#if defined(HICNET) -#include -#elif defined(ICNET) -#include -#else -#error "No ICN tranport library to which link against." -#endif - -class HTTPClient { -public: - virtual ~HTTPClient() = default; - - virtual void setTcp() = 0; - - virtual bool download(const std::string &url, std::ostream &out) = 0; -}; diff --git a/apps/src/http-server/http-client/http_client_icn.cc b/apps/src/http-server/http-client/http_client_icn.cc deleted file mode 100644 index 862741bd9..000000000 --- a/apps/src/http-server/http-client/http_client_icn.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 "http_client_icn.h" -#include "response.h" - -#include - -using namespace std; - -HTTPClientIcn::HTTPClientIcn(uint32_t timeout) { - std::chrono::seconds _timeout(timeout); - connection_.setTimeout(_timeout); -} - -void HTTPClientIcn::setTcp() {} - -HTTPClientIcn::~HTTPClientIcn() {} - -bool HTTPClientIcn::download(const std::string &url, std::ostream &out) { - connection_.get(url); - libl4::http::HTTPResponse r = connection_.response(); - out.write(reinterpret_cast(r.data()), r.size()); - return true; -} diff --git a/apps/src/http-server/http-client/http_client_icn.h b/apps/src/http-server/http-client/http_client_icn.h deleted file mode 100644 index 8f5e9ae44..000000000 --- a/apps/src/http-server/http-client/http_client_icn.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 "http_client.h" - -#include - -class HTTPClientIcn : public HTTPClient { -public: - HTTPClientIcn(uint32_t timeout); - - void setTcp(); - - ~HTTPClientIcn(); - - bool download(const std::string &url, std::ostream &out); - -private: - libl4::http::HTTPClientConnection connection_; -}; diff --git a/apps/src/http-server/http-client/http_client_tcp.cc b/apps/src/http-server/http-client/http_client_tcp.cc deleted file mode 100644 index 08474d71c..000000000 --- a/apps/src/http-server/http-client/http_client_tcp.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 "http_client_tcp.h" -#include "response.h" - -#include -#include -#include -#include -#include - -using namespace std; - -struct UserData { - void *out; - void *curl; - bool tcp; - bool first_time; -}; - -typedef struct UserData UserData; - -size_t write_data(void *ptr, size_t size, size_t nmemb, void *user_data) { - - UserData *data = (UserData *)user_data; - - if (data->first_time) { - double cl; - - int res = - curl_easy_getinfo(data->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); - - if (res >= 0) { - *(ostream *)data->out - << "HTTP/1.0 200 OK\r\nContent-Length: " << std::size_t(cl) - << "\r\n\r\n"; - } - - data->first_time = false; - } - - ((icn_httpserver::Response *)data->out) - ->write((const char *)ptr, size * nmemb); - // ((icn_httpserver::Response*) data->out)->send(); - return size * nmemb; -} - -HTTPClientTcp::HTTPClientTcp() { - tcp_ = false; - first_time = true; - curl_ = curl_easy_init(); -} - -void HTTPClientTcp::setTcp() { tcp_ = true; } - -HTTPClientTcp::~HTTPClientTcp() { curl_easy_cleanup(curl_); } - -bool HTTPClientTcp::download(const std::string &url, std::ostream &out) { - curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()); - - /* example.com is redirected, so we tell libcurl to follow redirection */ - curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(curl_, CURLOPT_ACCEPT_ENCODING, "deflate"); - - curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, write_data); - UserData data; - data.out = &out; - data.curl = curl_; - data.tcp = tcp_; - data.first_time = first_time; - - curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &data); - - /* Perform the request, res will get the return code */ - CURLcode res = curl_easy_perform(curl_); - - /* Check for errors */ - if (res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - return false; - } - - return true; -} diff --git a/apps/src/http-server/http-client/http_client_tcp.h b/apps/src/http-server/http-client/http_client_tcp.h deleted file mode 100644 index e1d81ada0..000000000 --- a/apps/src/http-server/http-client/http_client_tcp.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 "http_client.h" - -#include - -class HTTPClientTcp : public HTTPClient { -public: - HTTPClientTcp(); - - void setTcp(); - - ~HTTPClientTcp(); - - bool download(const std::string &url, std::ostream &out); - -private: - bool first_time; - bool tcp_; - void *curl_; -}; diff --git a/apps/src/http-server/http-server.cc b/apps/src/http-server/http-server.cc deleted file mode 100644 index ec6aa19a1..000000000 --- a/apps/src/http-server/http-server.cc +++ /dev/null @@ -1,406 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include "http-server/http_server.h" -#include "http_client_icn.h" -#include "http_client_tcp.h" - -#ifdef _WIN32 -#include -#endif - -typedef icn_httpserver::HttpServer HttpServer; -typedef icn_httpserver::Response Response; -typedef icn_httpserver::Request Request; - -namespace std { - -int _isDirectory(const char *path) { - struct stat statbuf; - if (stat(path, &statbuf) != 0) - return -1; - return S_ISDIR(statbuf.st_mode); -} - -int _isRegularFile(const char *path) { - struct stat statbuf; - if (stat(path, &statbuf) != 0) - return 0; - return S_ISREG(statbuf.st_mode); -} - -string _getFileName(const string &strPath) { - size_t iLastSeparator = 0; -#ifdef _WIN32 - return strPath.substr((iLastSeparator = strPath.find_last_of("\\")) != - std::string::npos - ? iLastSeparator + 1 - : 0, - strPath.size() - strPath.find_last_of(".")); -#else - return strPath.substr((iLastSeparator = strPath.find_last_of("/")) != - std::string::npos - ? iLastSeparator + 1 - : 0, - strPath.size() - strPath.find_last_of(".")); -#endif -} - -int _mkdir(const char *dir) { - std::cout << dir << std::endl; -#ifdef _WIN32 - char sepChar = '\\'; - char tmp[MAX_PATH]; -#else - char sepChar = '/'; - char tmp[PATH_MAX]; -#endif - char *p = NULL; - size_t len; - - snprintf(tmp, sizeof(tmp), "%s", dir); - len = strlen(tmp); - - if (tmp[len - 1] == sepChar) - tmp[len - 1] = 0; - for (p = tmp + 1; *p; p++) { - if (*p == sepChar) { - *p = 0; - if (_isDirectory(tmp) != 1) { -#ifdef _WIN32 - if (!CreateDirectory(tmp, NULL)) { -#else - if (mkdir(tmp, S_IRWXU) == -1) { -#endif - return -1; - } - } - *p = sepChar; - } - } - - if (_isDirectory(tmp) != 1) { -#ifdef _WIN32 - if (!CreateDirectory(tmp, NULL)) { -#else - if (mkdir(tmp, S_IRWXU) == -1) { -#endif - return -1; - } - } - - return 0; -} - -string _getExtension(const string &strPath) { - size_t iLastSeparator = 0; - return strPath.substr((iLastSeparator = strPath.find_last_of(".")) != - std::string::npos - ? iLastSeparator + 1 - : 0, - strPath.size()); -} - -void default_resource_send(const HttpServer &server, - shared_ptr response, - shared_ptr ifs, - shared_ptr> buffer, - std::size_t bytes_to_read) { - streamsize read_length; - - if ((read_length = ifs->read(&(*buffer)[0], buffer->size()).gcount()) > 0) { - response->write(&(*buffer)[0], read_length); - - if (bytes_to_read <= static_cast(buffer->size())) { - // If this is the last part of the response, send it at the pointer - // deletion! - return; - } - - std::size_t to_read = bytes_to_read - read_length; - server.send(response, [&server, response, ifs, buffer, - to_read](const std::error_code &ec) { - if (!ec) { - default_resource_send(server, response, ifs, buffer, to_read); - } else { - cerr << "Connection interrupted" << endl; - } - }); - } -} - -void afterSignal(HttpServer *webServer, const std::error_code &errorCode) { - cout << "\nGracefully terminating http-server... wait." << endl; - webServer->stop(); -} - -void usage(const char *programName) { - cerr << "usage: " << programName << " [options]" << endl; - cerr << programName << " options:" << endl; - cerr << "-p = path to root folder" << endl; - cerr << "-f = configuration file path" << endl; - cerr << "-o = tcp listener port" << endl; - cerr << "-l = webserver prefix" << endl; - cerr << "-x = tcp proxy prefix" << endl; - cerr << "-z = hicn proxy prefix" << endl; - cerr << endl; - cerr << "Web server able to publish content and generate http responses over " - "TCP/ICN" - << endl; - cerr << endl; - - exit(1); -} - -int main(int argc, char **argv) { - // Parse command line arguments - -#ifndef _WIN32 - string root_folder = "/var/www/html"; -#else - char path[MAX_PATH]; - SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path); - string root_folder(path); - root_folder += "\\www\\html"; -#endif - string webserver_prefix = "http://webserver"; - string tcp_proxy_address; - string icn_proxy_prefix; - int port = 8080; - int opt = 0; - - while ((opt = getopt(argc, argv, "p:l:o:hx:z:")) != -1) { - switch (opt) { - case 'p': - root_folder = optarg; - break; - case 'l': - webserver_prefix = optarg; - break; - case 'x': - tcp_proxy_address = optarg; - break; - case 'o': - port = atoi(optarg); - break; - case 'z': - icn_proxy_prefix = optarg; - break; - case 'h': - default: - usage(argv[0]); - break; - } - } - - if (_isDirectory(root_folder.c_str()) != 1) { - if (_mkdir(root_folder.c_str()) == -1) { - std::cerr << "The web root folder " << root_folder - << " does not exist and its creation failed. Exiting.." - << std::endl; - return (EXIT_FAILURE); - } - } - - std::cout << "Using web root folder: [" << root_folder << "]" << std::endl; - std::cout << "Using locator: [" << webserver_prefix << "]" << std::endl; - if (!tcp_proxy_address.empty()) { - std::cout << "Using TCP proxy: [" << tcp_proxy_address << "]" << std::endl; - } - if (!icn_proxy_prefix.empty()) { - std::cout << "Using ICN proxy: [" << icn_proxy_prefix << "]" << std::endl; - } - - asio::io_service io_service; - HttpServer server(port, webserver_prefix, 50, 5, 300, io_service); - - // GET for the path /info - // Responds with some server info - server.resource["^/info$"]["GET"] = [](shared_ptr response, - shared_ptr request) { - stringstream content_stream; - content_stream - << "

This webserver is able to reply to HTTP over TCP/ICN

"; - content_stream << request->getMethod() << " " << request->getPath() - << " HTTP/" << request->getHttp_version() << "
"; - - for (auto &header : request->getHeader()) { - content_stream << header.first << ": " << header.second << "
"; - } - - // find length of content_stream (length received using - // content_stream.tellp()) - content_stream.seekp(0, ios::end); - - *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content_stream.tellp() - << "\r\n\r\n" - << content_stream.rdbuf(); - }; - - // Default GET-example. If no other matches, this anonymous function will be - // called. Will respond with content in the web/-directory, and its - // subdirectories. Default file: index.html Can for instance be used to - // retrieve an HTML 5 client that uses REST-resources on this server - server.default_resource["GET"] = - [&server, &root_folder, &tcp_proxy_address, &icn_proxy_prefix]( - shared_ptr response, shared_ptr request) { - const auto web_root_path = root_folder; - std::string path = web_root_path; - - // check if there is "/" - path = path + request->getPath(); - std::cout << "path:" << path << std::endl; - auto socket_request = - dynamic_cast(request.get()); - - std::chrono::milliseconds response_lifetime; - std::string stem = _getFileName(path); - std::string extension = _getExtension(path); - if (extension == "mpd" || stem == "latest") { - std::cout << "1 second" << std::endl; - std::cout << "Setting lifetime to 1 second" << std::endl; - response_lifetime = std::chrono::milliseconds(1000); - } else { - std::cout << "5 second" << std::endl; - std::cout << "Setting lifetime to 5 second" << std::endl; - response_lifetime = std::chrono::milliseconds(5000); - } - - response->setResponseLifetime(response_lifetime); - - if (_isDirectory(path.c_str())) { - // Check if path is within web_root_path - if (distance(web_root_path.begin(), web_root_path.end()) <= - distance(path.begin(), path.end()) && - equal(web_root_path.begin(), web_root_path.end(), path.begin())) { - path += "index.html"; - if (_isRegularFile(path.c_str())) { - - auto ifs = make_shared(); - ifs->open(path, ifstream::in | ios::binary); - - if (*ifs) { - // read and send 15 MB at a time - streamsize buffer_size = 15 * 1024 * 1024; - auto buffer = make_shared>(buffer_size); - - ifs->seekg(0, ios::end); - auto length = ifs->tellg(); - ifs->seekg(0, ios::beg); - - response->setResponseLength(length); - *response << "HTTP/1.0 200 OK\r\nContent-Length: " << length - << "\r\n\r\n"; - - default_resource_send(server, response, ifs, buffer, length); - - return; - } - } - } - } - - string proxy; - HTTPClient *client = nullptr; - - if (tcp_proxy_address.empty() && !icn_proxy_prefix.empty()) { - proxy = icn_proxy_prefix; - client = new HTTPClientIcn(20); - } else if (!tcp_proxy_address.empty() && icn_proxy_prefix.empty()) { - proxy = tcp_proxy_address; - client = new HTTPClientTcp; - } else if (!tcp_proxy_address.empty() && !icn_proxy_prefix.empty()) { - if (socket_request) { - proxy = icn_proxy_prefix; - client = new HTTPClientIcn(20); - } else { - proxy = tcp_proxy_address; - client = new HTTPClientTcp; - } - } - - if (!proxy.empty()) { - // Fetch content from remote origin - std::stringstream ss; - - if (strncmp("http://", proxy.c_str(), 7) != 0) { - if (strncmp("https://", proxy.c_str(), 8) != 0) { - ss << "https://"; - } else { - ss << "http://"; - } - } - - ss << proxy; - ss << request->getPath(); - - std::cout << "Forwarding request to " << ss.str() << std::endl; - - client->download(ss.str(), *response); - - delete client; - - if (response->size() == 0) { - *response << "HTTP/1.1 504 Gateway Timeout\r\n\r\n"; - } - - return; - } - - string content = "Could not open path " + request->getPath() + "\n"; - - *response << "HTTP/1.1 404 Not found\r\nContent-Length: " - << content.length() << "\r\n\r\n" - << content; - }; - - // Let the main thread to catch SIGINT - asio::signal_set signals(io_service, SIGINT); - signals.async_wait(bind(afterSignal, &server, placeholders::_1)); - - thread server_thread([&server]() { - // Start server - server.start(); - }); - - if (server_thread.joinable()) { - server_thread.join(); - } - - return 0; -} - -} // end namespace std - -int main(int argc, char **argv) { return std::main(argc, argv); } diff --git a/apps/src/http-server/http-server/common.h b/apps/src/http-server/http-server/common.h deleted file mode 100644 index 81f6757c7..000000000 --- a/apps/src/http-server/http-server/common.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 -#include -#elif defined(ICNET) -#include -#include -#else -#error "No ICN tranport library to which link against." -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef asio::ip::tcp::socket socket_type; -typedef std::function SendCallback; diff --git a/apps/src/http-server/http-server/configuration.cc b/apps/src/http-server/http-server/configuration.cc deleted file mode 100644 index 603396b44..000000000 --- a/apps/src/http-server/http-server/configuration.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 deleted file mode 100644 index b87558f91..000000000 --- a/apps/src/http-server/http-server/configuration.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 deleted file mode 100644 index 8ad16f904..000000000 --- a/apps/src/http-server/http-server/content.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 deleted file mode 100644 index ebf2f7f32..000000000 --- a/apps/src/http-server/http-server/content.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 deleted file mode 100644 index 8c8bea60a..000000000 --- a/apps/src/http-server/http-server/http_server.cc +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 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 -#include -#include - -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()), - 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 &publisher, - const uint8_t *buffer, std::size_t size, int request_id) { - std::shared_ptr request = std::make_shared(publisher); - request->getContent().rdbuf()->sputn((char *)buffer, size); - - if (!parse_request(request, request->getContent())) { - return; - } - - std::map> - &icn_publishers = icn_acceptor_->getPublishers(); - - std::unique_lock 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> - &icn_publishers = icn_acceptor_->getPublishers(); - find_resource(nullptr, request); - icn_publishers[request_id]->serveClients(); - std::unique_lock lock(thread_list_mtx_); - icn_publishers.erase(request_id); - }); - } -} - -void HttpServer::setIcnAcceptor() { - icn_acceptor_ = std::make_shared( - 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> - &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 = - std::make_shared(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, - SendCallback callback) const { - response->send(callback); -} - -std::shared_ptr -HttpServer::set_timeout_on_socket(std::shared_ptr socket, - long seconds) { - std::shared_ptr timer = - std::make_shared(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) { - // 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 = std::make_shared(); - request->read_remote_endpoint_data(*socket); - - // Set timeout on the following asio::async-read or write function - std::shared_ptr 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 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, - 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, - std::shared_ptr 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, - std::shared_ptr request, - ResourceCallback &resource_function) { - // Set timeout on the following asio::async-read or write function - std::shared_ptr 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(request)->getHttpPublisher(), - std::static_pointer_cast(request)->getName(), - std::static_pointer_cast(request)->getPath()); - } - - auto response = std::shared_ptr(resp, [this, request, timer, - socket]( - Response *response_ptr) { - auto response = std::shared_ptr(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(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 deleted file mode 100644 index 3468b438a..000000000 --- a/apps/src/http-server/http-server/http_server.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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, - std::shared_ptr)> - 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, - SendCallback callback = nullptr) const; - - std::unordered_map> - resource; - - std::unordered_map default_resource; - - void - onIcnRequest(std::shared_ptr &publisher, - const uint8_t *buffer, std::size_t size, int request_id); - -private: - void spawnThreads(); - - void setIcnAcceptor(); - - std::shared_ptr - set_timeout_on_socket(std::shared_ptr socket, long seconds); - - void read_request_and_content(std::shared_ptr socket); - - bool parse_request(std::shared_ptr request, - std::istream &stream) const; - - void find_resource(std::shared_ptr socket, - std::shared_ptr request); - - void write_response(std::shared_ptr socket, - std::shared_ptr request, - ResourceCallback &resource_function); - - Configuration config_; - - std::vector>>> - opt_resource_; - - std::shared_ptr internal_io_service_; - asio::io_service &io_service_; - asio::ip::tcp::acceptor acceptor_; - std::vector socket_threads_; - std::string icn_name_; - std::shared_ptr 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 deleted file mode 100644 index 7871d908d..000000000 --- a/apps/src/http-server/http-server/icn_request.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 &publisher) - : publisher_(publisher) { - time_t t; - time(&t); - srand((unsigned int)t); - request_id_ = rand(); -} - -IcnRequest::IcnRequest( - std::shared_ptr &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 & -IcnRequest::getHttpPublisher() const { - return publisher_; -} - -void IcnRequest::setProducer( - const std::shared_ptr &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 deleted file mode 100644 index adf36d129..000000000 --- a/apps/src/http-server/http-server/icn_request.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 &publisher); - - IcnRequest(std::shared_ptr &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 & - getHttpPublisher() const; - - void setProducer( - const std::shared_ptr &producer); - -private: - std::string name_; - int request_id_; - std::shared_ptr 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 deleted file mode 100644 index 11d0faf6b..000000000 --- a/apps/src/http-server/http-server/icn_response.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 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(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 deleted file mode 100644 index 2194a5a7f..000000000 --- a/apps/src/http-server/http-server/icn_response.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 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 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 deleted file mode 100644 index e754d645b..000000000 --- a/apps/src/http-server/http-server/request.cc +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 & -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 deleted file mode 100644 index f9b2a73df..000000000 --- a/apps/src/http-server/http-server/request.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 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 & - 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 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 deleted file mode 100644 index ccb249e4a..000000000 --- a/apps/src/http-server/http-server/response.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9cc2e61ab..000000000 --- a/apps/src/http-server/http-server/response.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 deleted file mode 100644 index 321d9c61a..000000000 --- a/apps/src/http-server/http-server/socket_request.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 deleted file mode 100644 index c6566a207..000000000 --- a/apps/src/http-server/http-server/socket_request.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 deleted file mode 100644 index 5095c614f..000000000 --- a/apps/src/http-server/http-server/socket_response.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 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 &SocketResponse::getSocket() const { - return socket_; -} - -void SocketResponse::setSocket(const std::shared_ptr &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 deleted file mode 100644 index b582809dc..000000000 --- a/apps/src/http-server/http-server/socket_response.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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); - - ~SocketResponse(); - - void send(const SendCallback &callback = nullptr); - - const std::shared_ptr &getSocket() const; - - void setSocket(const std::shared_ptr &socket); - -private: - std::shared_ptr socket_; -}; - -} // end namespace icn_httpserver diff --git a/libtransport/src/hicn/transport/core/forwarder_interface.h b/libtransport/src/hicn/transport/core/forwarder_interface.h index 974b1c39a..b4bc26da7 100644 --- a/libtransport/src/hicn/transport/core/forwarder_interface.h +++ b/libtransport/src/hicn/transport/core/forwarder_interface.h @@ -98,7 +98,7 @@ class ForwarderInterface { } packet.setChecksum(); - connector_.send(packet.data()); + connector_.send(packet.acquireMemBufReference()); } template diff --git a/libtransport/src/hicn/transport/core/packet.cc b/libtransport/src/hicn/transport/core/packet.cc index c5c2b9796..de8ede421 100644 --- a/libtransport/src/hicn/transport/core/packet.cc +++ b/libtransport/src/hicn/transport/core/packet.cc @@ -230,7 +230,9 @@ Packet::Format Packet::getFormat() const { return format_; } -const std::shared_ptr Packet::data() { return packet_; } +const std::shared_ptr Packet::acquireMemBufReference() { + return packet_; +} void Packet::dump() const { const_cast(this)->separateHeaderPayload(); diff --git a/libtransport/src/hicn/transport/core/packet.h b/libtransport/src/hicn/transport/core/packet.h index 88d9f9318..6d8bc7e0f 100644 --- a/libtransport/src/hicn/transport/core/packet.h +++ b/libtransport/src/hicn/transport/core/packet.h @@ -99,7 +99,7 @@ class Packet : public std::enable_shared_from_this { std::size_t headerSize() const; - const std::shared_ptr data(); + const std::shared_ptr acquireMemBufReference(); virtual const Name &getName() const = 0; diff --git a/libtransport/src/hicn/transport/http/client_connection.cc b/libtransport/src/hicn/transport/http/client_connection.cc index e2ee6478d..b31d89b6b 100644 --- a/libtransport/src/hicn/transport/http/client_connection.cc +++ b/libtransport/src/hicn/transport/http/client_connection.cc @@ -154,10 +154,10 @@ bool HTTPClientConnection::verifyData( void HTTPClientConnection::processLeavingInterest( ConsumerSocket &c, const core::Interest &interest, std::string &payload) { - // if (interest.getName().getSuffix() == 0) { - Interest &int2 = const_cast(interest); - int2.appendPayload((uint8_t *)payload.data(), payload.size()); - // } + if (interest.payloadSize() == 0) { + Interest &int2 = const_cast(interest); + int2.appendPayload((uint8_t *)payload.data(), payload.size()); + } } ConsumerSocket &HTTPClientConnection::getConsumer() { return consumer_; } diff --git a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc index 2e180cf34..fdd422dee 100644 --- a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc +++ b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc @@ -187,14 +187,14 @@ void AsyncFullDuplexSocket::write(WriteCallback *callback, const void *buf, if (bytes > core::Packet::default_mtu - sizeof(PayloadMessage)) { TRANSPORT_LOGI("Producing content with name %s", - options.name.toString().c_str()); - producer_->asyncProduce(options.name, + options.getName().toString().c_str()); + producer_->asyncProduce(options.getName(), reinterpret_cast(buf), bytes); - signalProductionToSubscribers(options.name); + signalProductionToSubscribers(options.getName()); } else { TRANSPORT_LOGI("Sending payload through interest"); piggybackPayloadToSubscribers( - options.name, reinterpret_cast(buf), bytes); + options.getName(), reinterpret_cast(buf), bytes); } } @@ -212,12 +212,12 @@ void AsyncFullDuplexSocket::write(WriteCallback *callback, if (output_buffer->size() > core::Packet::default_mtu - sizeof(PayloadMessage)) { TRANSPORT_LOGI("Producing content with name %s", - options.name.toString().c_str()); - producer_->asyncProduce(options.name, std::move(output_buffer)); - signalProductionToSubscribers(options.name); + options.getName().toString().c_str()); + producer_->asyncProduce(options.getName(), std::move(output_buffer)); + signalProductionToSubscribers(options.getName()); } else { TRANSPORT_LOGI("Sending payload through interest"); - piggybackPayloadToSubscribers(options.name, &(*output_buffer)[0], + piggybackPayloadToSubscribers(options.getName(), &(*output_buffer)[0], output_buffer->size()); } } diff --git a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h index 1d7ad3cb1..438325fdb 100644 --- a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h +++ b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h @@ -139,13 +139,6 @@ class AsyncFullDuplexSocket : public AsyncSocket, void waitForSubscribers(AcceptCallback *cb) override; - // void writev( - // WriteCallback* callback, - // const iovec* vec, - // size_t count, - // Name &&content_to_publish_name, - // WriteFlags flags = WriteFlags::NONE) override; - void close() override; void closeNow() override; diff --git a/libtransport/src/hicn/transport/interfaces/publication_options.h b/libtransport/src/hicn/transport/interfaces/publication_options.h index ae5366ce7..6910e5371 100644 --- a/libtransport/src/hicn/transport/interfaces/publication_options.h +++ b/libtransport/src/hicn/transport/interfaces/publication_options.h @@ -15,9 +15,7 @@ #pragma once -#include -#include -#include +#include namespace transport { @@ -25,8 +23,19 @@ namespace interface { class PublicationOptions { public: - core::Name name; - uint32_t content_lifetime_milliseconds; + template + PublicationOptions(T&& name, uint32_t lifetime) + : name_(std::forward(name)), + content_lifetime_milliseconds_(lifetime) {} + + TRANSPORT_ALWAYS_INLINE const core::Name& getName() const { return name_; } + TRANSPORT_ALWAYS_INLINE uint32_t getLifetime() const { + return content_lifetime_milliseconds_; + } + + private: + core::Name name_; + uint32_t content_lifetime_milliseconds_; // TODO Signature }; } // namespace interface diff --git a/libtransport/src/hicn/transport/utils/content_store.cc b/libtransport/src/hicn/transport/utils/content_store.cc index d48e16daf..c3864310e 100644 --- a/libtransport/src/hicn/transport/utils/content_store.cc +++ b/libtransport/src/hicn/transport/utils/content_store.cc @@ -62,7 +62,7 @@ void ContentStore::insert( } } -const std::shared_ptr &ContentStore::find( +const std::shared_ptr ContentStore::find( const Interest &interest) { std::unique_lock lock(cs_mutex_); auto it = content_store_hash_table_.find(interest.getName()); diff --git a/libtransport/src/hicn/transport/utils/content_store.h b/libtransport/src/hicn/transport/utils/content_store.h index 39e87fb7d..ba8ee5bd2 100644 --- a/libtransport/src/hicn/transport/utils/content_store.h +++ b/libtransport/src/hicn/transport/utils/content_store.h @@ -46,13 +46,13 @@ typedef std::unordered_map ContentStoreHashTable; class ContentStore { public: - explicit ContentStore(std::size_t max_packets = 65536); + explicit ContentStore(std::size_t max_packets = (1 << 16)); ~ContentStore(); void insert(const std::shared_ptr &content_object); - const std::shared_ptr &find(const Interest &interest); + const std::shared_ptr find(const Interest &interest); void erase(const Name &exact_name); diff --git a/utils/sysrepo-plugin/CMakeLists.txt b/utils/sysrepo-plugin/CMakeLists.txt index c062c010c..6479aa6cd 100644 --- a/utils/sysrepo-plugin/CMakeLists.txt +++ b/utils/sysrepo-plugin/CMakeLists.txt @@ -13,7 +13,7 @@ # limitations under the License. # -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(hicn_sysrepo_plugin) include(GNUInstallDirs) -- cgit 1.2.3-korg