Improvements for HTTP messages processing 12/10612/1
authorMauro Sardara <[email protected]>
Fri, 16 Feb 2018 16:22:53 +0000 (17:22 +0100)
committerMauro Sardara <[email protected]>
Fri, 16 Feb 2018 16:22:53 +0000 (17:22 +0100)
Change-Id: Iefcbfa1820bd47fd52475780c68c363a2baa2568
Signed-off-by: Mauro Sardara <[email protected]>
35 files changed:
apps/http/icnet_http_echo_server.cc
apps/http/icnet_iget.cc
icnet/CMakeLists.txt
icnet/errors/icnet_errors_malformed_name_exception.cc
icnet/errors/icnet_errors_malformed_name_exception.h
icnet/errors/icnet_errors_malformed_packet_exception.cc
icnet/errors/icnet_errors_malformed_packet_exception.h
icnet/errors/icnet_errors_not_implemented_exception.cc
icnet/errors/icnet_errors_not_implemented_exception.h
icnet/errors/icnet_errors_runtime_exception.cc
icnet/errors/icnet_errors_runtime_exception.h
icnet/errors/icnet_errors_tokenizer_exception.cc
icnet/errors/icnet_errors_tokenizer_exception.h
icnet/http/icnet_http_client_connection.cc
icnet/http/icnet_http_client_connection.h
icnet/http/icnet_http_message.h [new file with mode: 0644]
icnet/http/icnet_http_request.cc
icnet/http/icnet_http_request.h
icnet/http/icnet_http_response.cc [new file with mode: 0644]
icnet/http/icnet_http_response.h [new file with mode: 0644]
icnet/http/icnet_http_server_acceptor.cc
icnet/http/icnet_http_server_acceptor.h
icnet/http/icnet_http_server_publisher.cc
icnet/http/icnet_http_server_publisher.h
icnet/utils/icnet_utils_array.cc
icnet/utils/icnet_utils_array.h
icnet/utils/icnet_utils_daemonizator.cc
icnet/utils/icnet_utils_daemonizator.h
icnet/utils/icnet_utils_hash.cc
icnet/utils/icnet_utils_hash.h
icnet/utils/icnet_utils_sharable_vector.h [new file with mode: 0644]
icnet/utils/icnet_utils_string_tokenizer.cc
icnet/utils/icnet_utils_string_tokenizer.h
icnet/utils/icnet_utils_uri.cc
icnet/utils/icnet_utils_uri.h

index 223646a..961c44f 100644 (file)
@@ -19,7 +19,7 @@ namespace icnet {
 
 namespace http {
 
-void onPayload(std::shared_ptr<HTTPServerPublisher> &publisher, const uint8_t *buffer, std::size_t size) {
+void onPayload(std::shared_ptr<HTTPServerPublisher> &publisher, const uint8_t *buffer, std::size_t size, int request_id) {
 
   char *string = (char *) buffer;
   std::cout << "Received this content:" << std::endl;
index d322cc3..4a50786 100644 (file)
@@ -29,19 +29,21 @@ namespace http {
 
 void processResponse(std::string &name, HTTPResponse &&response) {
 
+  auto &payload = response.getPayload();
+
   std::string filename = name.substr(1 + name.find_last_of("/"));
-  std::cout << "Saving to: " << filename << " " << response.size() / 1024 << "kB" << std::endl;
+  std::cout << "Saving to: " << filename << " " << payload.size() / 1024 << "kB" << std::endl;
   Time t3 = std::chrono::system_clock::now();;
   std::ofstream file(filename.c_str(), std::ofstream::binary);
-  file.write((char *) response.data(), response.size());
+  file.write((char *) payload.data(), payload.size());
   file.close();
   Time t2 = std::chrono::system_clock::now();;
   TimeDuration dt = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
   TimeDuration dt3 = std::chrono::duration_cast<std::chrono::milliseconds>(t3 - t1);
   long msec = dt.count();
   long msec3 = dt3.count();
-  std::cout << "Elapsed Time: " << msec / 1000.0 << " seconds -- " << response.size() * 8 / msec / 1000.0
-            << "[Mbps] -- " << response.size() * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl;
+  std::cout << "Elapsed Time: " << msec / 1000.0 << " seconds -- " << payload.size() * 8 / msec / 1000.0
+            << "[Mbps] -- " << payload.size() * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl;
 
 }
 
index 427a3d9..5d5b3c0 100644 (file)
@@ -89,21 +89,25 @@ set(HTTP_HEADER_FILES
         http/icnet_http_client_connection.h
         http/icnet_http_server_acceptor.h
         http/icnet_http_server_publisher.h
+    http/icnet_http_message.h
         http/icnet_http_request.h
+    http/icnet_http_response.h
         http/icnet_http_facade.h)
 
 set(HTTP_SOURCE_FILES
         http/icnet_http_client_connection.cc
         http/icnet_http_server_acceptor.cc
         http/icnet_http_server_publisher.cc
-        http/icnet_http_request.cc)
+        http/icnet_http_request.cc
+        http/icnet_http_response.cc)
 
 set(UTILS_HEADER_FILES
         utils/icnet_utils_array.h
         utils/icnet_utils_uri.h
         utils/icnet_utils_daemonizator.h
         utils/icnet_utils_hash.h
-        utils/icnet_utils_string_tokenizer.h)
+        utils/icnet_utils_string_tokenizer.h
+        utils/icnet_utils_sharable_vector.h)
 
 set(UTILS_SOURCE_FILES
         utils/icnet_utils_array.cc
index 361c211..b721ebf 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_errors.h"
 
-namespace icnet {
-
 namespace errors {
 
 MalformedNameException::MalformedNameException()
@@ -27,6 +25,4 @@ char const *MalformedNameException::what() const noexcept {
   return "Malformed IP address.";
 }
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index f714d2b..c113ee1 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <stdexcept>
 
-namespace icnet {
-
 namespace errors {
 
 class MalformedNameException : public std::runtime_error {
@@ -27,6 +25,4 @@ class MalformedNameException : public std::runtime_error {
   virtual char const *what() const noexcept override;
 };
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index 962a658..5f63e73 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_errors_malformed_packet_exception.h"
 
-namespace icnet {
-
 namespace errors {
 
 MalformedPacketException::MalformedPacketException()
@@ -27,6 +25,4 @@ char const *MalformedPacketException::what() const noexcept {
   return "Malformed IP packet.";
 }
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index 0420d5c..42fc717 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <stdexcept>
 
-namespace icnet {
-
 namespace errors {
 
 class MalformedPacketException : public std::runtime_error {
@@ -27,6 +25,4 @@ class MalformedPacketException : public std::runtime_error {
   virtual char const *what() const noexcept override;
 };
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index c58039c..8a652c7 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_errors_not_implemented_exception.h"
 
-namespace icnet {
-
 namespace errors {
 
 NotImplementedException::NotImplementedException()
@@ -28,6 +26,4 @@ char const *NotImplementedException::what() const noexcept {
   return "Function not yet implemented.";
 }
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index 980ae99..5711bd1 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <stdexcept>
 
-namespace icnet {
-
 namespace errors {
 
 class NotImplementedException : public std::logic_error {
@@ -27,6 +25,4 @@ class NotImplementedException : public std::logic_error {
   virtual char const *what() const noexcept override;
 };
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index 4853f25..a180224 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_errors_runtime_exception.h"
 
-namespace icnet {
-
 namespace errors {
 
 RuntimeException::RuntimeException()
@@ -27,6 +25,4 @@ RuntimeException::RuntimeException()
 //  return "Function not yet implemented.";
 //}
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index 37c6bcb..7c1e23d 100644 (file)
@@ -18,8 +18,6 @@
 #include <stdexcept>
 #include <string>
 
-namespace icnet {
-
 namespace errors {
 
 class RuntimeException : public std::runtime_error {
@@ -29,6 +27,4 @@ class RuntimeException : public std::runtime_error {
       : runtime_error(what) {};
 };
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index 1b5e843..d7da2b0 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_errors_tokenizer_exception.h"
 
-namespace icnet {
-
 namespace errors {
 
 TokenizerException::TokenizerException()
@@ -28,6 +26,4 @@ char const *TokenizerException::what() const noexcept {
   return "No more tokens available.";
 }
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index bae9d82..e849e0d 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <stdexcept>
 
-namespace icnet {
-
 namespace errors {
 
 class TokenizerException : public std::logic_error {
@@ -27,6 +25,4 @@ class TokenizerException : public std::logic_error {
   virtual char const *what() const noexcept override;
 };
 
-} // end namespace errors
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace errors
\ No newline at end of file
index f07edcc..d3ccd81 100644 (file)
@@ -28,7 +28,8 @@ namespace http {
 using namespace transport;
 
 HTTPClientConnection::HTTPClientConnection()
-    : consumer_(Name("ccnx:"), transport::TransportProtocolAlgorithms::RAAQM) {
+    : consumer_(Name("ccnx:"), transport::TransportProtocolAlgorithms::RAAQM), timer_(nullptr),
+      response_(std::make_shared<HTTPResponse>()) {
 
   consumer_.setSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY,
                             (ConsumerContentObjectVerificationCallback) std::bind(&HTTPClientConnection::verifyData,
@@ -41,9 +42,15 @@ HTTPClientConnection::HTTPClientConnection()
                                                                 this,
                                                                 std::placeholders::_1,
                                                                 std::placeholders::_2));
+
+  std::shared_ptr<ccnx::Portal> portal;
+  consumer_.getSocketOption(GeneralTransportOptions::PORTAL, portal);
+  timer_.reset(new boost::asio::steady_timer(portal->getIoService()));
 }
 
-HTTPClientConnection &HTTPClientConnection::get(std::string &url, HTTPHeaders headers, HTTPPayload payload) {
+HTTPClientConnection &HTTPClientConnection::get(const std::string &url,
+                                                HTTPHeaders headers,
+                                                HTTPPayload payload) {
 
   HTTPRequest request(GET, url, headers, payload);
 
@@ -60,7 +67,7 @@ HTTPClientConnection &HTTPClientConnection::get(std::string &url, HTTPHeaders he
 
   // Send content to producer piggybacking it through first interest (to fix)
 
-  response_.clear();
+  response_->clear();
 
   // Factor icn name
 
@@ -78,12 +85,12 @@ HTTPClientConnection &HTTPClientConnection::get(std::string &url, HTTPHeaders he
 }
 
 HTTPResponse &&HTTPClientConnection::response() {
-  return std::move(response_);
+  return std::move(*response_);
 }
 
 void HTTPClientConnection::processPayload(transport::ConsumerSocket &c,
                                           std::vector<uint8_t> &&payload) {
-  response_ = std::move(payload);
+  *std::static_pointer_cast<std::vector<uint8_t>>(response_) = std::move(payload);
 }
 
 bool HTTPClientConnection::verifyData(transport::ConsumerSocket &c, const ContentObject &contentObject) {
@@ -99,10 +106,10 @@ bool HTTPClientConnection::verifyData(transport::ConsumerSocket &c, const Conten
 void HTTPClientConnection::processLeavingInterest(transport::ConsumerSocket &c,
                                                   const Interest &interest,
                                                   std::string &payload) {
-  if (interest.getName().get(-1).toSegment() == 0) {
+  //  if (interest.getName().get(-1).toSegment() == 0) {
     Interest &int2 = const_cast<Interest &>(interest);
     int2.setPayload((const uint8_t *) payload.data(), payload.size());
-  }
+  //  }
 }
 
 HTTPClientConnection& HTTPClientConnection::stop() {
@@ -116,6 +123,16 @@ transport::ConsumerSocket& HTTPClientConnection::getConsumer() {
   return consumer_;
 }
 
+void HTTPClientConnection::setTimeout(const std::chrono::seconds &timeout) {
+  timer_->cancel();
+  timer_->expires_from_now(timeout);
+  timer_->async_wait([this](boost::system::error_code ec) {
+    if (!ec) {
+      consumer_.stop();
+    }
+  });
+}
+
 }
 
 }
index 41a2a4f..ae52aa3 100644 (file)
 #include "icnet_transport_socket_producer.h"
 #include "icnet_utils_uri.h"
 #include "icnet_http_request.h"
+#include "icnet_http_response.h"
 #include "icnet_http_default_values.h"
 
 #include <vector>
+#include <boost/asio/steady_timer.hpp>
 
 #define HTTP_VERSION "1.0"
 
@@ -33,7 +35,9 @@ class HTTPClientConnection {
  public:
   HTTPClientConnection();
 
-  HTTPClientConnection &get(std::string &url, HTTPHeaders headers = {}, HTTPPayload payload = {});
+  HTTPClientConnection &get(const std::string &url,
+                            HTTPHeaders headers = {},
+                            HTTPPayload payload = {});
 
   HTTPResponse &&response();
 
@@ -41,16 +45,19 @@ class HTTPClientConnection {
 
   transport::ConsumerSocket &getConsumer();
 
+  void setTimeout(const std::chrono::seconds &timeout);
+
  private:
 
-  void processPayload(transport::ConsumerSocket &c, std::vector<uint8_t> &&payload);
+  void processPayload(transport::ConsumerSocket &c, std::vector<uint8_t> &&response);
 
   bool verifyData(transport::ConsumerSocket &c, const transport::ContentObject &contentObject);
 
   void processLeavingInterest(transport::ConsumerSocket &c, const transport::Interest &interest, std::string &payload);
 
-  HTTPResponse response_;
+  std::shared_ptr<HTTPResponse> response_;
   transport::ConsumerSocket consumer_;
+  std::unique_ptr<boost::asio::steady_timer> timer_;
 };
 
 } // end namespace http
diff --git a/icnet/http/icnet_http_message.h b/icnet/http/icnet_http_message.h
new file mode 100644 (file)
index 0000000..3d6f982
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 "icnet_utils_sharable_vector.h"
+
+#include <sstream>
+#include <vector>
+#include <map>
+
+#define HTTP_VERSION "1.0"
+
+namespace icnet {
+
+namespace http {
+
+typedef enum {
+  GET,
+  POST,
+  PUT,
+  PATCH,
+  DELETE
+} HTTPMethod;
+
+static std::map<HTTPMethod, std::string> method_map = {
+    {GET, "GET"}, {POST, "POST"}, {PUT, "PUT"}, {PATCH, "PATCH"}, {DELETE, "DELETE"},
+};
+
+typedef std::map<std::string, std::string> HTTPHeaders;
+typedef std::vector<uint8_t> HTTPPayload;
+
+class HTTPMessage {
+ public:
+
+  virtual ~HTTPMessage() = default;
+
+  virtual HTTPHeaders &getHeaders() = 0;
+
+  virtual HTTPPayload &getPayload() = 0;
+
+  virtual std::string &getHttpVersion() = 0;
+
+ protected:
+  HTTPHeaders headers_;
+  HTTPPayload payload_;
+  std::string http_version_;
+};
+
+} // end namespace http
+
+} // end namespace hicnet
\ No newline at end of file
index f793e89..7710739 100644 (file)
@@ -20,17 +20,10 @@ namespace icnet {
 
 namespace http {
 
-static std::map<HTTPMethod, std::string> method_map = {
-    {GET, "GET"},
-    {POST, "POST"},
-    {PUT, "PUT"},
-    {PATCH, "PATCH"},
-    {DELETE, "DELETE"},
-};
-
-//std::map<HTTPMethod, std::string> method_map
-
-HTTPRequest::HTTPRequest(HTTPMethod method, std::string &url, HTTPHeaders &headers, HTTPPayload &payload) {
+HTTPRequest::HTTPRequest(HTTPMethod method,
+                         const std::string &url,
+                         const HTTPHeaders &headers,
+                         const HTTPPayload &payload) {
   utils::Uri uri;
   uri.parse(url);
 
@@ -39,6 +32,7 @@ HTTPRequest::HTTPRequest(HTTPMethod method, std::string &url, HTTPHeaders &heade
   protocol_ = uri.getProtocol();
   locator_ = uri.getLocator();
   port_ = uri.getPort();
+  http_version_ = HTTP_VERSION;
 
   headers_ = headers;
   payload_ = payload;
@@ -99,6 +93,10 @@ std::string &HTTPRequest::getRequestString() {
   return request_string_;
 }
 
+std::string &HTTPRequest::getHttpVersion() {
+  return http_version_;
+}
+
 }
 
 }
\ No newline at end of file
index 985d762..ec4a3d6 100644 (file)
@@ -15,6 +15,9 @@
 
 #pragma once
 
+#include "icnet_utils_sharable_vector.h"
+#include "icnet_http_message.h"
+
 #include <sstream>
 #include <vector>
 #include <map>
@@ -25,23 +28,11 @@ namespace icnet {
 
 namespace http {
 
-typedef enum {
-  GET,
-  POST,
-  PUT,
-  PATCH,
-  DELETE
-} HTTPMethod;
-
-typedef std::map<std::string, std::string> HTTPHeaders;
-typedef std::vector<uint8_t> HTTPPayload;
-typedef std::vector<uint8_t> HTTPResponse;
-
-class HTTPRequest {
+class HTTPRequest : public HTTPMessage {
  public:
 
   HTTPRequest(HTTPMethod method,
-              std::string &url, HTTPHeaders &headers, HTTPPayload &payload);
+              const std::string &url, const HTTPHeaders &headers, const HTTPPayload &payload);
 
   std::string &getQueryString();
 
@@ -55,9 +46,11 @@ class HTTPRequest {
 
   std::string &getRequestString();
 
-  HTTPHeaders &getHeaders();
+  HTTPHeaders &getHeaders() override;
+
+  HTTPPayload &getPayload() override;
 
-  HTTPPayload &getPayload();
+  std::string &getHttpVersion() override;
 
  private:
   std::string query_string_, path_, protocol_, locator_, port_;
diff --git a/icnet/http/icnet_http_response.cc b/icnet/http/icnet_http_response.cc
new file mode 100644 (file)
index 0000000..c9d3173
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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 "icnet_http_response.h"
+#include "icnet_errors.h"
+
+#include <algorithm>
+
+#include <cstring>
+
+namespace icnet {
+
+namespace http {
+
+HTTPResponse::HTTPResponse() {
+}
+
+HTTPResponse::HTTPResponse(const HTTPHeaders &headers, const HTTPPayload &payload) {
+  headers_ = headers;
+  payload_ = payload;
+}
+
+HTTPHeaders &HTTPResponse::getHeaders() {
+  parse();
+  return headers_;
+}
+
+HTTPPayload &HTTPResponse::getPayload() {
+  parse();
+  return payload_;
+}
+
+bool HTTPResponse::parseHeaders() {
+  const char *crlf2 = "\r\n\r\n";
+  auto it = std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+
+  if (it != end()) {
+    std::stringstream ss;
+    ss.str(std::string(begin(), it));
+
+    std::string line;
+    getline(ss, line);
+    std::istringstream line_s(line);
+    std::string _http_version;
+    std::string http_version;
+
+    line_s >> _http_version;
+    std::size_t separator;
+    if ((separator = _http_version.find('/')) != std::string::npos) {
+      if (_http_version.substr(0, separator) != "HTTP") {
+        return false;
+      }
+      http_version_ = line.substr(separator + 1, _http_version.length() - separator - 1);
+    } else {
+      return false;
+    }
+
+    std::string status_code, status_string;
+
+    line_s >> status_code_;
+    line_s >> status_string;
+
+    auto _it = std::search(line.begin(), line.end(), status_string.begin(), status_string.end());
+
+    status_string_ = std::string(_it, line.end() - 1);
+
+    std::size_t param_end;
+    std::size_t value_start;
+    while (getline(ss, line)) {
+      if ((param_end = line.find(':')) != std::string::npos) {
+        value_start = param_end + 1;
+        if ((value_start) < line.size()) {
+          if (line[value_start] == ' ') {
+            value_start++;
+          }
+          if (value_start < line.size()) {
+            headers_[line.substr(0, param_end)] = line.substr(value_start, line.size() - value_start - 1);
+          }
+        }
+      } else {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+void HTTPResponse::parse() {
+  if (!parseHeaders()) {
+    throw errors::RuntimeException("Malformed HTTP response");
+  }
+
+  if (payload_.empty()) {
+    const char *crlf2 = "\r\n\r\n";
+    auto it = std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+
+    if (it != this->end()) {
+      erase(begin(), it + strlen(crlf2));
+      payload_ = std::move(*dynamic_cast<std::vector<uint8_t> *>(this));
+    }
+  }
+}
+
+std::string &HTTPResponse::getStatusCode() {
+  return status_code_;
+}
+
+std::string &HTTPResponse::getStatusString() {
+  return status_string_;
+}
+
+std::string &HTTPResponse::getHttpVersion() {
+  return http_version_;
+}
+
+}
+
+}
\ No newline at end of file
diff --git a/icnet/http/icnet_http_response.h b/icnet/http/icnet_http_response.h
new file mode 100644 (file)
index 0000000..b925e1e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 "icnet_utils_sharable_vector.h"
+#include "icnet_http_message.h"
+#include "icnet_utils_array.h"
+
+#include <sstream>
+#include <vector>
+#include <map>
+
+namespace icnet {
+
+namespace http {
+
+class HTTPResponse : public HTTPMessage, public utils::SharableVector<uint8_t> {
+ public:
+
+  HTTPResponse(const HTTPHeaders &headers, const HTTPPayload &payload);
+
+  HTTPResponse();
+
+  HTTPHeaders &getHeaders() override;
+
+  HTTPPayload &getPayload() override;
+
+  std::string &getStatusCode();
+
+  std::string &getStatusString();
+
+  std::string &getHttpVersion() override;
+
+  void parse();
+
+ private:
+  bool parseHeaders();
+
+ private:
+  std::string status_code_;
+  std::string status_string_;
+};
+
+} // end namespace http
+
+} // end namespace hicnet
\ No newline at end of file
index 9406955..424d380 100644 (file)
@@ -106,65 +106,29 @@ void HTTPServerAcceptor::processIncomingInterest(transport::ProducerSocket &p, c
 
   if (method == "GET") {
     HTTPRequest request(GET, url, headers, payload);
-    auto publisher = std::make_shared<HTTPServerPublisher>(request_name);
-    callback_(publisher, (uint8_t *) request.getRequestString().data(), request.getRequestString().size());
+
+    int request_id = utils::Hash::hash32(request.getRequestString().data(), request.getRequestString().size());
+
+    if (publishers_.find(request_id) != publishers_.end()) {
+      if (publishers_[request_id]) {
+        publishers_[request_id]->getProducer().onInterest(interest.getName(), interest);
+        return;
+      }
+    } else {
+      std::cout << "Request ID" << request_id << std::endl;
+    }
+
+    publishers_[request_id] = std::make_shared<HTTPServerPublisher>(request_name);
+    callback_(publishers_[request_id],
+              (uint8_t *) request.getRequestString().data(),
+              request.getRequestString().size(),
+              request_id);
   }
 }
 
-//void HTTPServerConnection::sendResponse() {
-//
-//  std::thread t([]() {
-//
-//    // Get the name of the HTTP method to compute
-//    std::string method = request_name.get(1).toString();
-//    std::transform(method.begin(), method.end(), method.begin(), ::toupper);
-//    std::string path;
-//
-//    // This is done for getting rid of useless name components such as ccnx: or ndn:
-//    if (request_name.getSegmentCount() > 2) {
-//      std::string rawPath = request_name.getSubName(2).toString();
-//      std::size_t pos = rawPath.find("/");
-//      path = rawPath.substr(pos);
-//    }
-//
-//    // Create new producer
-//
-//    // Create timer for response availability
-//    std::shared_ptr<core::Portal> portal;
-//    po->getSocketOption(icnet::GeneralTransportOptions::PORTAL, portal);
-//    boost::asio::io_service &ioService = portal->getIoService();
-//
-//    boost::asio::deadline_timer t(ioService, boost::posix_time::seconds(5));
-//
-//    std::function<void(const boost::system::error_code e)>
-//        wait_callback = [&ioService](const boost::system::error_code e) {
-//      if (!e) {
-//        // Be sure to delete the timer before the io_service, otherwise we'll get some strange behavior!
-//        ioService.stop();
-//      }
-//    };
-//
-//    std::function<void(transport::ProducerSocket, const core::Interest &interest)>
-//        interest_enter_callback = [this, &wait_callback, &t]
-//        (transport::ProducerSocket &p, const core::Interest &interest) {
-//      t.cancel();
-//      t.expires_from_now(boost::posix_time::seconds(5));
-//      t.async_wait(wait_callback);
-//    };
-//
-//    p->setSocketOption(transport::ProducerCallbacksOptions::INTEREST_INPUT,
-//                       (transport::ProducerInterestCallback) interest_enter_callback);
-//
-//    t.async_wait(wait_callback);
-//
-//    p->serveForever();
-//
-//    std::unique_lock<std::mutex> lock(thread_list_mtx_);
-//    icn_producers_.erase(request_name);
-//  });
-//
-//  t.detach();
-//}
+std::map<int, std::shared_ptr<HTTPServerPublisher>>& HTTPServerAcceptor::getPublishers() {
+  return publishers_;
+}
 
 }
 
index 2d0b7f2..f5af47e 100644 (file)
@@ -31,7 +31,7 @@ namespace http {
 
 //typedef std::vector<uint8_t> HTTPResponse;
 typedef std::vector<uint8_t> HttpRequest;
-typedef std::function<void(std::shared_ptr<HTTPServerPublisher> &, const uint8_t *, std::size_t)> OnHttpRequest;
+typedef std::function<void(std::shared_ptr<HTTPServerPublisher> &, const uint8_t *, std::size_t, int request_id)> OnHttpRequest;
 
 class HTTPServerAcceptor {
  public:
@@ -42,11 +42,7 @@ class HTTPServerAcceptor {
 
   HttpRequest &&request();
 
-//  void asyncSendResponse();
-
-//  HTTPClientConnection& get(std::string &url, HTTPHeaders headers = {}, HTTPPayload payload = {});
-//
-//  HTTPResponse&& response();
+  std::map<int, std::shared_ptr<HTTPServerPublisher>>& getPublishers();
 
  private:
 
@@ -55,6 +51,8 @@ class HTTPServerAcceptor {
   OnHttpRequest callback_;
   HttpRequest request_;
   std::shared_ptr<transport::ProducerSocket> acceptor_producer_;
+
+  std::map<int, std::shared_ptr<HTTPServerPublisher>> publishers_;
 };
 
 } // end namespace http
index 82c9005..716eaa7 100644 (file)
@@ -36,10 +36,14 @@ HTTPServerPublisher& HTTPServerPublisher::attachPublisher() {
   return *this;
 }
 
-HTTPServerPublisher &HTTPServerPublisher::setTimeout(uint32_t timeout) {
+transport::ProducerSocket& HTTPServerPublisher::getProducer() {
+  return *producer_;
+}
+
+HTTPServerPublisher &HTTPServerPublisher::setTimeout(const std::chrono::milliseconds &timeout, bool timeout_renewal) {
   std::shared_ptr<transport::Portal> portal;
   producer_->getSocketOption(transport::GeneralTransportOptions::PORTAL, portal);
-  timer_ = std::unique_ptr<boost::asio::deadline_timer>(new boost::asio::deadline_timer(portal->getIoService(), boost::posix_time::seconds(timeout)));
+  timer_ = std::unique_ptr<boost::asio::steady_timer>(new boost::asio::steady_timer(portal->getIoService(), timeout));
 
   wait_callback_ = [this](const boost::system::error_code e) {
     if (!e) {
@@ -47,14 +51,16 @@ HTTPServerPublisher &HTTPServerPublisher::setTimeout(uint32_t timeout) {
     }
   };
 
-  interest_enter_callback_ = [this, timeout](transport::ProducerSocket &p, const transport::Interest &interest) {
-    this->timer_->cancel();
-    this->timer_->expires_from_now(boost::posix_time::seconds(timeout));
-    this->timer_->async_wait(wait_callback_);
-  };
+  if (timeout_renewal) {
+    interest_enter_callback_ = [this, timeout](transport::ProducerSocket &p, const transport::Interest &interest) {
+      this->timer_->cancel();
+      this->timer_->expires_from_now(timeout);
+      this->timer_->async_wait(wait_callback_);
+    };
 
-  producer_->setSocketOption(transport::ProducerCallbacksOptions::INTEREST_INPUT,
-                             (transport::ProducerInterestCallback) interest_enter_callback_);
+    producer_->setSocketOption(transport::ProducerCallbacksOptions::INTEREST_INPUT,
+                               (transport::ProducerInterestCallback) interest_enter_callback_);
+  }
 
   timer_->async_wait(wait_callback_);
 
index 7162f4d..7c96ce1 100644 (file)
@@ -20,6 +20,7 @@
 #include "icnet_http_default_values.h"
 
 #include <vector>
+#include <boost/asio/steady_timer.hpp>
 #include <functional>
 
 #ifdef __ANDROID__
@@ -51,16 +52,18 @@ class HTTPServerPublisher {
 
   void stop();
 
-  HTTPServerPublisher &setTimeout(uint32_t timeout);
+  HTTPServerPublisher &setTimeout(const std::chrono::milliseconds &timeout, bool timeout_renewal);
 
   HTTPServerPublisher &attachPublisher();
 
+  transport::ProducerSocket& getProducer();
+
  private:
 
   void processIncomingInterest(transport::ProducerSocket &p, const transport::Interest &interest);
 
   transport::Name content_name_;
-  std::unique_ptr<boost::asio::deadline_timer> timer_;
+  std::unique_ptr<boost::asio::steady_timer> timer_;
   std::unique_ptr<transport::ProducerSocket> producer_;
   transport::ProducerInterestCallback interest_enter_callback_;
   DeadlineTimerCallback wait_callback_;
index 413119c..a395ddd 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_utils_array.h"
 
-namespace icnet {
-
 namespace utils {
 
 Array::Array(const void *array, size_t size) {
@@ -47,6 +45,4 @@ Array &Array::setSize(std::size_t size) {
   return *this;
 }
 
-}
-
 }
\ No newline at end of file
index f13c0b4..c356190 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <cstddef>
 
-namespace icnet {
-
 namespace utils {
 
 class Array {
@@ -41,5 +39,3 @@ class Array {
 };
 
 }
-
-}
index 2bb6dd0..061573d 100644 (file)
@@ -20,8 +20,6 @@
 #include <iostream>
 #include <sys/stat.h>
 
-namespace icnet {
-
 namespace utils {
 
 void Daemonizator::daemonize() {
@@ -70,5 +68,3 @@ void Daemonizator::daemonize() {
 }
 
 }
-
-}
index 20cd80b..6297c83 100644 (file)
@@ -15,8 +15,6 @@
 
 #pragma once
 
-namespace icnet {
-
 namespace utils {
 
 class Daemonizator {
@@ -24,6 +22,4 @@ class Daemonizator {
   static void daemonize();
 };
 
-}
-
 }
\ No newline at end of file
index 39dd022..51a0f63 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "icnet_utils_hash.h"
 
-namespace icnet {
-
 namespace utils {
 
 uint32_t Hash::hash32(const void *data, std::size_t len) {
@@ -59,6 +57,4 @@ uint64_t Hash::cumulativeHash64(const void *data, std::size_t len, uint64_t last
   return hash;
 }
 
-}
-
 }
\ No newline at end of file
index 9ae01f3..26ae9c6 100644 (file)
@@ -18,8 +18,6 @@
 #include <cstdint>
 #include <cstddef>
 
-namespace icnet {
-
 namespace utils {
 
 //const uint32_t FNV1A_PRIME_32 = 0x01000193;
@@ -37,6 +35,4 @@ class Hash {
 
 };
 
-}
-
 }
\ No newline at end of file
diff --git a/icnet/utils/icnet_utils_sharable_vector.h b/icnet/utils/icnet_utils_sharable_vector.h
new file mode 100644 (file)
index 0000000..d78a9a6
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 <vector>
+#include <memory>
+
+namespace utils {
+
+template<class T>
+class SharableVector : public std::vector<T>, public std::enable_shared_from_this<SharableVector<T>> {
+ public:
+  virtual ~SharableVector() {};
+};
+
+}
index ead1052..19d76c3 100644 (file)
@@ -17,8 +17,6 @@
 #include "icnet_utils_string_tokenizer.h"
 #include "icnet_errors.h"
 
-namespace icnet {
-
 namespace utils {
 
 StringTokenizer::StringTokenizer(const std::string &str)
@@ -48,5 +46,4 @@ std::string StringTokenizer::nextToken() {
   return token;
 }
 
-}
 }
\ No newline at end of file
index 7dc6b45..c1111b4 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <string>
 
-namespace icnet {
-
 namespace utils {
 
 class StringTokenizer {
@@ -34,5 +32,3 @@ class StringTokenizer {
 };
 
 }
-
-}
index 8268bdf..53d67b2 100644 (file)
@@ -16,8 +16,6 @@
 #include "icnet_utils_uri.h"
 #include "icnet_errors_runtime_exception.h"
 
-namespace icnet {
-
 namespace utils {
 
 Uri::Uri() {
@@ -132,6 +130,4 @@ std::string Uri::getQueryString() {
   return query_string_;
 }
 
-} // end namespace utils
-
-} // end namespace icnet
\ No newline at end of file
+} // end namespace utils
\ No newline at end of file
index 3817228..4d42276 100644 (file)
@@ -18,8 +18,6 @@
 #include <string>
 #include <algorithm>    // find
 
-namespace icnet {
-
 namespace utils {
 
 class Uri {
@@ -46,6 +44,4 @@ class Uri {
   std::string query_string_, path_, protocol_, locator_, port_;
 };  // uri
 
-}
-
 }
\ No newline at end of file