aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAngelo Mantellini <angelo.mantellini@cisco.com>2020-02-18 17:27:27 +0000
committerGerrit Code Review <gerrit@fd.io>2020-02-18 17:27:27 +0000
commit0710f1ff754ebf01ae5befabb055349fe472b0c2 (patch)
tree648f6b622437353da87af9fcd3019de5fd5b24a3
parente43298508d6e8afe67cebb53f97499dd06f4d822 (diff)
parent46c924b9d2edd84bc6ecb5367ba52fcff82804fa (diff)
Merge "[HICN-528] Add progress bar to higet."
-rw-r--r--apps/higet/higet.cc212
-rw-r--r--libtransport/src/hicn/transport/http/client_connection.cc82
-rw-r--r--libtransport/src/hicn/transport/http/client_connection.h26
-rw-r--r--libtransport/src/hicn/transport/http/message.h20
-rw-r--r--libtransport/src/hicn/transport/http/request.cc39
-rw-r--r--libtransport/src/hicn/transport/http/request.h26
-rw-r--r--libtransport/src/hicn/transport/http/response.cc60
-rw-r--r--libtransport/src/hicn/transport/http/response.h17
-rw-r--r--libtransport/src/hicn/transport/utils/membuf.h9
9 files changed, 276 insertions, 215 deletions
diff --git a/apps/higet/higet.cc b/apps/higet/higet.cc
index fa19528f8..df34d5c14 100644
--- a/apps/higet/higet.cc
+++ b/apps/higet/higet.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Copyright (c) 2020 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:
@@ -8,14 +8,19 @@
*
* 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.
+ * 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 <hicn/transport/http/client_connection.h>
-
#include <fstream>
+#include <map>
+
+#ifndef ASIO_STANDALONE
+#define ASIO_STANDALONE
+#include <asio.hpp>
+#endif
typedef std::chrono::time_point<std::chrono::system_clock> Time;
typedef std::chrono::milliseconds TimeDuration;
@@ -34,61 +39,160 @@ typedef struct {
std::string ipv6_first_word;
} Configuration;
-void processResponse(Configuration &conf,
- transport::http::HTTPResponse &&response) {
- auto &payload = response.getPayload();
+class ReadBytesCallbackImplementation
+ : public transport::http::HTTPClientConnection::ReadBytesCallback {
+ public:
+ ReadBytesCallbackImplementation(std::string file_name, long yet_downloaded)
+ : file_name_(file_name),
+ temp_file_name_(file_name_ + ".temp"),
+ yet_downloaded_(yet_downloaded),
+ byte_downloaded_(yet_downloaded),
+ work_(std::make_unique<asio::io_service::work>(io_service_)),
+ thread_(
+ std::make_unique<std::thread>([this]() { io_service_.run(); })) {
+ std::streambuf *buf;
+ if (file_name_ != "-") {
+ of_.open(temp_file_name_, std::ofstream::binary | std::ofstream::app);
+ buf = of_.rdbuf();
+ } else {
+ buf = std::cout.rdbuf();
+ }
- if (conf.file_name != "-") {
- std::cerr << "Saving to: " << conf.file_name << " " << payload.size()
- << "kB" << std::endl;
+ out_ = new std::ostream(buf);
}
- Time t3 = std::chrono::system_clock::now();
+ ~ReadBytesCallbackImplementation() {
+ if (thread_->joinable()) {
+ thread_->join();
+ }
+ }
- std::streambuf *buf;
- std::ofstream of;
+ void onBytesReceived(std::unique_ptr<utils::MemBuf> &&buffer) {
+ auto buffer_ptr = buffer.release();
+ io_service_.post([this, buffer_ptr]() {
+ auto buffer = std::unique_ptr<utils::MemBuf>(buffer_ptr);
+ if (!first_chunk_read_) {
+ transport::http::HTTPResponse http_response(std::move(buffer));
+ auto payload = http_response.getPayload();
+ auto header = http_response.getHeaders();
+ std::map<std::string, std::string>::iterator it =
+ header.find("Content-Length");
+ if (it != header.end()) {
+ content_size_ = yet_downloaded_ + std::stol(it->second);
+ }
+ out_->write((char *)payload->data(), payload->length());
+ first_chunk_read_ = true;
+ byte_downloaded_ += payload->length();
+ } else {
+ out_->write((char *)buffer->data(), buffer->length());
+ byte_downloaded_ += buffer->length();
+ }
+
+ if (file_name_ != "-") {
+ print_bar(byte_downloaded_, content_size_, false);
+ }
+ });
+ }
- if (conf.file_name != "-") {
- of.open(conf.file_name, std::ofstream::binary);
- buf = of.rdbuf();
- } else {
- buf = std::cout.rdbuf();
+ void onSuccess(std::size_t bytes) {
+ io_service_.post([this, bytes]() {
+ if (file_name_ != "-") {
+ of_.close();
+ delete out_;
+ std::size_t found = file_name_.find_last_of(".");
+ std::string name = file_name_.substr(0, found);
+ std::string extension = file_name_.substr(found + 1);
+ if (!exists_file(file_name_)) {
+ std::rename(temp_file_name_.c_str(), file_name_.c_str());
+ } else {
+ int i = 1;
+ std::ostringstream sstream;
+ sstream << name << "(" << i << ")." << extension;
+ std::string final_name = sstream.str();
+ while (exists_file(final_name)) {
+ i++;
+ sstream.str("");
+ sstream << name << "(" << i << ")." << extension;
+ final_name = sstream.str();
+ }
+ std::rename(temp_file_name_.c_str(), final_name.c_str());
+ }
+
+ print_bar(100, 100, true);
+ std::cout << "\nDownloaded " << bytes << " bytes" << std::endl;
+ }
+ work_.reset();
+ });
}
- std::ostream out(buf);
+ void onError(const std::error_code ec) {
+ io_service_.post([this]() {
+ of_.close();
+ delete out_;
+ work_.reset();
+ });
+ }
+
+ private:
+ bool exists_file(const std::string &name) {
+ std::ifstream f(name.c_str());
+ return f.good();
+ }
- 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";
+ void print_bar(long value, long max_value, bool last) {
+ float progress = (float)value / max_value;
+ struct winsize size;
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
+ int barWidth = size.ws_col - 8;
+
+ std::cout << "[";
+ int pos = barWidth * progress;
+ for (int i = 0; i < barWidth; ++i) {
+ if (i < pos) {
+ std::cout << "=";
+ } else if (i == pos) {
+ std::cout << ">";
+ } else {
+ std::cout << " ";
+ }
+ }
+ if (last) {
+ std::cout << "] " << int(progress * 100.0) << " %" << std::endl
+ << std::endl;
+ } else {
+ std::cout << "] " << int(progress * 100.0) << " %\r";
+ std::cout.flush();
}
- out << "\n";
}
- out.write((char *)payload.data(), payload.size());
- of.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 = (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;
+ private:
+ std::string file_name_;
+ std::string temp_file_name_;
+ std::ostream *out_;
+ std::ofstream of_;
+ long yet_downloaded_;
+ long content_size_;
+ bool first_chunk_read_ = false;
+ long byte_downloaded_ = 0;
+ asio::io_service io_service_;
+ std::unique_ptr<asio::io_service::work> work_;
+ std::unique_ptr<std::thread> thread_;
+};
+
+long checkFileStatus(std::string file_name) {
+ struct stat stat_buf;
+ std::string temp_file_name_ = file_name + ".temp";
+ int rc = stat(temp_file_name_.c_str(), &stat_buf);
+ return rc == 0 ? stat_buf.st_size : -1;
}
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 <output_path> = write documents to <output_file>"
- << std::endl;
+ std::cerr
+ << "-O <out_put_path> = write documents to <out_put_file>"
+ << std::endl;
std::cerr << "-S = print server response"
<< std::endl;
std::cerr << "-P = first word of the ipv6 name of "
@@ -145,10 +249,23 @@ int main(int argc, char **argv) {
conf.file_name = name.substr(1 + name.find_last_of("/"));
}
- std::map<std::string, std::string> headers = {{"Host", "localhost"},
- {"User-Agent", "higet/1.0"},
- {"Connection", "Keep-Alive"}};
+ long yetDownloaded = checkFileStatus(conf.file_name);
+ std::map<std::string, std::string> headers;
+ if (yetDownloaded == -1) {
+ headers = {{"Host", "localhost"},
+ {"User-Agent", "higet/1.0"},
+ {"Connection", "Keep-Alive"}};
+ } else {
+ std::string range;
+ range.append("bytes=");
+ range.append(std::to_string(yetDownloaded));
+ range.append("-");
+ headers = {{"Host", "localhost"},
+ {"User-Agent", "higet/1.0"},
+ {"Connection", "Keep-Alive"},
+ {"Range", range}};
+ }
transport::http::HTTPClientConnection connection;
if (!conf.producer_certificate.empty()) {
connection.setCertificate(conf.producer_certificate);
@@ -156,8 +273,11 @@ int main(int argc, char **argv) {
t1 = std::chrono::system_clock::now();
- connection.get(name, headers, {}, nullptr, nullptr, conf.ipv6_first_word);
- processResponse(conf, connection.response());
+ http::ReadBytesCallbackImplementation readBytesCallback(conf.file_name,
+ yetDownloaded);
+
+ connection.get(name, headers, {}, nullptr, &readBytesCallback,
+ conf.ipv6_first_word);
#ifdef _WIN32
WSACleanup();
diff --git a/libtransport/src/hicn/transport/http/client_connection.cc b/libtransport/src/hicn/transport/http/client_connection.cc
index aa9cb0463..bd21bc448 100644
--- a/libtransport/src/hicn/transport/http/client_connection.cc
+++ b/libtransport/src/hicn/transport/http/client_connection.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -16,8 +16,6 @@
#include <hicn/transport/http/client_connection.h>
#include <hicn/transport/utils/hash.h>
-#include <fstream>
-
#define DEFAULT_BETA 0.99
#define DEFAULT_GAMMA 0.07
@@ -40,12 +38,6 @@ HTTPClientConnection::HTTPClientConnection()
std::placeholders::_2));
consumer_.setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, this);
- consumer_.setSocketOption(
- ConsumerCallbacksOptions::VERIFICATION_FAILED,
- (ConsumerContentObjectVerificationFailedCallback)std::bind(
- &HTTPClientConnection::onSignatureVerificationFailed, this,
- std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- consumer_.setSocketOption(GeneralTransportOptions::VERIFY_SIGNATURE, false);
consumer_.connect();
std::shared_ptr<typename ConsumerSocket::Portal> portal;
@@ -54,31 +46,30 @@ HTTPClientConnection::HTTPClientConnection()
}
HTTPClientConnection::RC HTTPClientConnection::get(
- const std::string &url, HTTPHeaders headers, HTTPPayload payload,
+ const std::string &url, HTTPHeaders headers, HTTPPayload &&payload,
std::shared_ptr<HTTPResponse> response, ReadBytesCallback *callback,
std::string ipv6_first_word) {
- return sendRequest(url, HTTPMethod::GET, headers, payload, response, callback,
- ipv6_first_word);
+ return sendRequest(url, HTTPMethod::GET, headers, std::move(payload),
+ response, callback, ipv6_first_word);
}
HTTPClientConnection::RC HTTPClientConnection::sendRequest(
const std::string &url, HTTPMethod method, HTTPHeaders headers,
- HTTPPayload payload, std::shared_ptr<HTTPResponse> response,
+ HTTPPayload &&payload, std::shared_ptr<HTTPResponse> response,
ReadBytesCallback *callback, std::string ipv6_first_word) {
current_url_ = url;
read_bytes_callback_ = callback;
if (!response) {
- response = response_;
+ response_ = std::make_shared<HTTPResponse>();
+ } else {
+ response_ = response;
}
auto start = std::chrono::steady_clock::now();
- HTTPRequest request(method, url, headers, payload);
- response->clear();
+ request_.init(method, url, headers, std::move(payload));
success_callback_ = [this, method = std::move(method), url = std::move(url),
- start = std::move(start),
- response = std::move(response)](
- std::size_t size) -> std::shared_ptr<HTTPResponse> {
+ start = std::move(start)](std::size_t size) -> void {
auto end = std::chrono::steady_clock::now();
TRANSPORT_LOGI(
"%s %s [%s] duration: %llu [usec] %zu [bytes]\n",
@@ -87,23 +78,15 @@ HTTPClientConnection::RC HTTPClientConnection::sendRequest(
std::chrono::duration_cast<std::chrono::microseconds>(end - start)
.count(),
size);
-
- return response;
};
- sendRequestGetReply(request, response, ipv6_first_word);
+ sendRequestGetReply(ipv6_first_word);
return return_code_;
}
-void HTTPClientConnection::verifyPacketSignature(bool verify) {
- consumer_.setSocketOption(GeneralTransportOptions::VERIFY_SIGNATURE, verify);
-}
-
-void HTTPClientConnection::sendRequestGetReply(
- const HTTPRequest &request, std::shared_ptr<HTTPResponse> &response,
- std::string &ipv6_first_word) {
- const std::string &request_string = request.getRequestString();
- const std::string &locator = request.getLocator();
+void HTTPClientConnection::sendRequestGetReply(std::string &ipv6_first_word) {
+ const std::string &request_string = request_.getRequestString();
+ const std::string &locator = request_.getLocator();
// Hash it
@@ -116,7 +99,7 @@ void HTTPClientConnection::sendRequestGetReply(
ConsumerCallbacksOptions::INTEREST_OUTPUT,
(ConsumerInterestCallback)std::bind(
&HTTPClientConnection::processLeavingInterest, this,
- std::placeholders::_1, std::placeholders::_2, request_string));
+ std::placeholders::_1, std::placeholders::_2));
// Factor hicn name using hash
name_.str("");
@@ -142,9 +125,9 @@ void HTTPClientConnection::sendRequestGetReply(
consumer_.stop();
}
-HTTPResponse HTTPClientConnection::response() {
- // response_->parse();
- return std::move(*response_);
+std::shared_ptr<HTTPResponse> HTTPClientConnection::response() {
+ response_->coalescePayloadBuffer();
+ return response_;
}
bool HTTPClientConnection::verifyData(
@@ -159,10 +142,14 @@ bool HTTPClientConnection::verifyData(
}
void HTTPClientConnection::processLeavingInterest(
- ConsumerSocket &c, const core::Interest &interest, std::string &payload) {
+ ConsumerSocket &c, const core::Interest &interest) {
if (interest.payloadSize() == 0) {
Interest &int2 = const_cast<Interest &>(interest);
+ auto payload = request_.getRequestString();
+ auto payload2 = request_.getPayload();
int2.appendPayload((uint8_t *)payload.data(), payload.size());
+ if (payload2)
+ int2.appendPayload((uint8_t *)payload2->data(), payload2->length());
}
}
@@ -198,21 +185,11 @@ HTTPClientConnection &HTTPClientConnection::setCertificate(
return *this;
}
-VerificationPolicy HTTPClientConnection::onSignatureVerificationFailed(
- ConsumerSocket &consumer, const core::ContentObject &content_object,
- std::error_code reason) {
- return VerificationPolicy::ACCEPT_PACKET;
-}
-
// Read buffer management
void HTTPClientConnection::readBufferAvailable(
std::unique_ptr<utils::MemBuf> &&buffer) noexcept {
if (!read_bytes_callback_) {
- if (!read_buffer_) {
- read_buffer_ = std::move(buffer);
- } else {
- read_buffer_->prependChain(std::move(buffer));
- }
+ response_->appendResponseChunk(std::move(buffer));
} else {
read_bytes_callback_->onBytesReceived(std::move(buffer));
}
@@ -230,18 +207,9 @@ void HTTPClientConnection::readError(const std::error_code ec) noexcept {
}
void HTTPClientConnection::readSuccess(std::size_t total_size) noexcept {
- auto response = success_callback_(total_size);
+ success_callback_(total_size);
if (read_bytes_callback_) {
read_bytes_callback_->onSuccess(total_size);
- } else {
- response->reserve(total_size);
- const utils::MemBuf *head = read_buffer_.get(), *current = head;
- do {
- response->insert(response->end(), current->data(), current->tail());
- current = current->next();
- } while (current != head);
-
- read_buffer_.reset();
}
return_code_ = HTTPClientConnection::RC::DOWNLOAD_SUCCESS;
diff --git a/libtransport/src/hicn/transport/http/client_connection.h b/libtransport/src/hicn/transport/http/client_connection.h
index e001653ab..e93a37111 100644
--- a/libtransport/src/hicn/transport/http/client_connection.h
+++ b/libtransport/src/hicn/transport/http/client_connection.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -20,7 +20,6 @@
#include <hicn/transport/http/response.h>
#include <hicn/transport/interfaces/socket_consumer.h>
#include <hicn/transport/interfaces/socket_producer.h>
-#include <hicn/transport/interfaces/verification_policy.h>
#include <hicn/transport/utils/uri.h>
#include <vector>
@@ -48,18 +47,18 @@ class HTTPClientConnection : public ConsumerSocket::ReadCallback {
HTTPClientConnection();
RC get(const std::string &url, HTTPHeaders headers = {},
- HTTPPayload payload = {},
+ HTTPPayload &&payload = nullptr,
std::shared_ptr<HTTPResponse> response = nullptr,
ReadBytesCallback *callback = nullptr,
std::string ipv6_first_word = "b001");
RC sendRequest(const std::string &url, HTTPMethod method,
- HTTPHeaders headers = {}, HTTPPayload payload = {},
+ HTTPHeaders headers = {}, HTTPPayload &&payload = nullptr,
std::shared_ptr<HTTPResponse> response = nullptr,
ReadBytesCallback *callback = nullptr,
std::string ipv6_first_word = "b001");
- HTTPResponse response();
+ std::shared_ptr<HTTPResponse> response();
HTTPClientConnection &stop();
@@ -69,23 +68,14 @@ class HTTPClientConnection : public ConsumerSocket::ReadCallback {
HTTPClientConnection &setCertificate(const std::string &cert_path);
- void verifyPacketSignature(bool verify);
-
private:
- void sendRequestGetReply(const HTTPRequest &request,
- std::shared_ptr<HTTPResponse> &response,
- std::string &ipv6_first_word);
+ void sendRequestGetReply(std::string &ipv6_first_word);
bool verifyData(interface::ConsumerSocket &c,
const core::ContentObject &contentObject);
void processLeavingInterest(interface::ConsumerSocket &c,
- const core::Interest &interest,
- std::string &payload);
-
- VerificationPolicy onSignatureVerificationFailed(
- ConsumerSocket &consumer, const core::ContentObject &content_object,
- std::error_code reason);
+ const core::Interest &interest);
// Read callback
bool isBufferMovable() noexcept override { return true; }
@@ -106,7 +96,7 @@ class HTTPClientConnection : public ConsumerSocket::ReadCallback {
// The current hICN name used for downloading
std::stringstream name_;
// Function to be called when the read is successful
- std::function<std::shared_ptr<HTTPResponse>(std::size_t)> success_callback_;
+ std::function<void(std::size_t)> success_callback_;
// Return code for current download
RC return_code_;
@@ -115,6 +105,8 @@ class HTTPClientConnection : public ConsumerSocket::ReadCallback {
// any byte internally.
ReadBytesCallback *read_bytes_callback_;
+ HTTPRequest request_;
+
// Internal read buffer and HTTP response, to be used if the application does
// not provide any read_bytes_callback
std::unique_ptr<utils::MemBuf> read_buffer_;
diff --git a/libtransport/src/hicn/transport/http/message.h b/libtransport/src/hicn/transport/http/message.h
index 270dd3f0e..b8756224f 100644
--- a/libtransport/src/hicn/transport/http/message.h
+++ b/libtransport/src/hicn/transport/http/message.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -19,6 +19,8 @@
#include <hicn/transport/portability/win_portability.h>
#endif
+#include <hicn/transport/utils/membuf.h>
+
#include <map>
#include <sstream>
#include <vector>
@@ -37,17 +39,25 @@ static std::map<HTTPMethod, std::string> method_map = {
};
typedef std::map<std::string, std::string> HTTPHeaders;
-typedef std::vector<uint8_t> HTTPPayload;
+typedef std::unique_ptr<utils::MemBuf> HTTPPayload;
class HTTPMessage {
public:
virtual ~HTTPMessage() = default;
- virtual const HTTPHeaders &getHeaders() = 0;
+ const HTTPHeaders getHeaders() { return headers_; };
+
+ void coalescePayloadBuffer() {
+ auto it = headers_.find("Content-Length");
+ if (it != headers_.end()) {
+ auto content_length = std::stoul(it->second);
+ payload_->gather(content_length);
+ }
+ }
- virtual const HTTPPayload &getPayload() = 0;
+ HTTPPayload &&getPayload() { return std::move(payload_); }
- virtual const std::string &getHttpVersion() const = 0;
+ std::string getHttpVersion() const { return http_version_; };
protected:
HTTPHeaders headers_;
diff --git a/libtransport/src/hicn/transport/http/request.cc b/libtransport/src/hicn/transport/http/request.cc
index 7a63b4f75..09f709642 100644
--- a/libtransport/src/hicn/transport/http/request.cc
+++ b/libtransport/src/hicn/transport/http/request.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -20,11 +20,15 @@ namespace transport {
namespace http {
-// std::map<HTTPMethod, std::string> method_map
+HTTPRequest::HTTPRequest() {}
HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url,
- const HTTPHeaders &headers,
- const HTTPPayload &payload) {
+ const HTTPHeaders &headers, HTTPPayload &&payload) {
+ init(method, url, headers, std::move(payload));
+}
+
+void HTTPRequest::init(HTTPMethod method, const std::string &url,
+ const HTTPHeaders &headers, HTTPPayload &&payload) {
utils::Uri uri;
uri.parse(url);
@@ -36,7 +40,7 @@ HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url,
http_version_ = HTTP_VERSION;
headers_ = headers;
- payload_ = payload;
+ payload_ = std::move(payload);
std::transform(locator_.begin(), locator_.end(), locator_.begin(), ::tolower);
@@ -50,33 +54,20 @@ HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url,
stream << item.first << ": " << item.second << "\r\n";
}
stream << "\r\n";
-
- if (payload.size() > 0) {
- stream << payload.data();
- }
-
request_string_ = stream.str();
}
-const std::string &HTTPRequest::getPort() const { return port_; }
+std::string HTTPRequest::getPort() const { return port_; }
-const std::string &HTTPRequest::getLocator() const { return locator_; }
+std::string HTTPRequest::getLocator() const { return locator_; }
-const std::string &HTTPRequest::getProtocol() const { return protocol_; }
+std::string HTTPRequest::getProtocol() const { return protocol_; }
-const std::string &HTTPRequest::getPath() const { return path_; }
+std::string HTTPRequest::getPath() const { return path_; }
-const std::string &HTTPRequest::getQueryString() const { return query_string_; }
-
-const HTTPHeaders &HTTPRequest::getHeaders() { return headers_; }
-
-const HTTPPayload &HTTPRequest::getPayload() { return payload_; }
-
-const std::string &HTTPRequest::getRequestString() const {
- return request_string_;
-}
+std::string HTTPRequest::getQueryString() const { return query_string_; }
-const std::string &HTTPRequest::getHttpVersion() const { return http_version_; }
+std::string HTTPRequest::getRequestString() const { return request_string_; }
} // namespace http
diff --git a/libtransport/src/hicn/transport/http/request.h b/libtransport/src/hicn/transport/http/request.h
index 1202144c0..54904d696 100644
--- a/libtransport/src/hicn/transport/http/request.h
+++ b/libtransport/src/hicn/transport/http/request.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -27,32 +27,28 @@ namespace http {
class HTTPRequest : public HTTPMessage {
public:
+ HTTPRequest();
HTTPRequest(HTTPMethod method, const std::string &url,
- const HTTPHeaders &headers, const HTTPPayload &payload);
+ const HTTPHeaders &headers, HTTPPayload &&payload);
- const std::string &getQueryString() const;
+ void init(HTTPMethod method, const std::string &url,
+ const HTTPHeaders &headers, HTTPPayload &&payload);
- const std::string &getPath() const;
+ std::string getQueryString() const;
- const std::string &getProtocol() const;
+ std::string getPath() const;
- const std::string &getLocator() const;
+ std::string getProtocol() const;
- const std::string &getPort() const;
+ std::string getLocator() const;
- const std::string &getRequestString() const;
+ std::string getPort() const;
- const HTTPHeaders &getHeaders() override;
-
- const HTTPPayload &getPayload() override;
-
- const std::string &getHttpVersion() const override;
+ std::string getRequestString() const;
private:
std::string query_string_, path_, protocol_, locator_, port_;
std::string request_string_;
- HTTPHeaders headers_;
- HTTPPayload payload_;
};
} // end namespace http
diff --git a/libtransport/src/hicn/transport/http/response.cc b/libtransport/src/hicn/transport/http/response.cc
index db7306cca..a2bc47e6b 100644
--- a/libtransport/src/hicn/transport/http/response.cc
+++ b/libtransport/src/hicn/transport/http/response.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -16,7 +16,8 @@
#include <hicn/transport/errors/errors.h>
#include <hicn/transport/http/response.h>
-#include <algorithm>
+#include <experimental/algorithm>
+#include <experimental/functional>
#include <cstring>
@@ -26,30 +27,32 @@ namespace http {
HTTPResponse::HTTPResponse() {}
-HTTPResponse::HTTPResponse(const HTTPHeaders &headers,
- const HTTPPayload &payload) {
- headers_ = headers;
- payload_ = payload;
+HTTPResponse::HTTPResponse(std::unique_ptr<utils::MemBuf> &&response) {
+ parse(std::move(response));
}
-const HTTPHeaders &HTTPResponse::getHeaders() {
- parse();
- return headers_;
-}
-
-const HTTPPayload &HTTPResponse::getPayload() {
- parse();
- return payload_;
+void HTTPResponse::appendResponseChunk(
+ std::unique_ptr<utils::MemBuf> &&response_chunk) {
+ if (headers_.empty()) {
+ parse(std::move(response_chunk));
+ } else {
+ payload_->prependChain(std::move(response_chunk));
+ }
}
-bool HTTPResponse::parseHeaders() {
+bool HTTPResponse::parseHeaders(std::unique_ptr<utils::MemBuf> &&buffer) {
const char *crlf2 = "\r\n\r\n";
+ const char *begin = (const char *)buffer->data();
+ const char *end = begin + buffer->length();
auto it =
- std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+ std::experimental::search(begin, end,
+ std::experimental::make_boyer_moore_searcher(
+ crlf2, crlf2 + strlen(crlf2)));
- if (it != end()) {
+ if (it != end) {
+ buffer->trimStart(it + strlen(crlf2) - begin);
std::stringstream ss;
- ss.str(std::string(begin(), it + 1));
+ ss.str(std::string(begin, it));
std::string line;
getline(ss, line);
@@ -99,24 +102,15 @@ bool HTTPResponse::parseHeaders() {
}
}
+ payload_ = std::move(buffer);
+
return true;
}
-void HTTPResponse::parse() {
- if (!parseHeaders()) {
+void HTTPResponse::parse(std::unique_ptr<utils::MemBuf> &&response) {
+ if (!parseHeaders(std::move(response))) {
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));
- }
- }
}
const std::string &HTTPResponse::getStatusCode() const { return status_code_; }
@@ -125,10 +119,6 @@ const std::string &HTTPResponse::getStatusString() const {
return status_string_;
}
-const std::string &HTTPResponse::getHttpVersion() const {
- return http_version_;
-}
-
} // namespace http
} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/response.h b/libtransport/src/hicn/transport/http/response.h
index b261a128a..7ef655059 100644
--- a/libtransport/src/hicn/transport/http/response.h
+++ b/libtransport/src/hicn/transport/http/response.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 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:
@@ -26,26 +26,21 @@ namespace transport {
namespace http {
-class HTTPResponse : public HTTPMessage, public std::vector<uint8_t> {
+class HTTPResponse : public HTTPMessage {
public:
- HTTPResponse(const HTTPHeaders &headers, const HTTPPayload &payload);
-
HTTPResponse();
- const HTTPHeaders &getHeaders() override;
+ HTTPResponse(std::unique_ptr<utils::MemBuf> &&response);
- const HTTPPayload &getPayload() override;
+ void appendResponseChunk(std::unique_ptr<utils::MemBuf> &&response_chunk);
const std::string &getStatusCode() const;
const std::string &getStatusString() const;
- const std::string &getHttpVersion() const override;
-
- void parse();
+ void parse(std::unique_ptr<utils::MemBuf> &&response);
- private:
- bool parseHeaders();
+ bool parseHeaders(std::unique_ptr<utils::MemBuf> &&buffer);
private:
std::string status_code_;
diff --git a/libtransport/src/hicn/transport/utils/membuf.h b/libtransport/src/hicn/transport/utils/membuf.h
index 66e9d7afa..9fc37dd25 100644
--- a/libtransport/src/hicn/transport/utils/membuf.h
+++ b/libtransport/src/hicn/transport/utils/membuf.h
@@ -526,12 +526,11 @@ class MemBuf {
// *
// * Returns ByteRange that points to the data MemBuf stores.
// */
- // ByteRange coalesceWithHeadroomTailroom(
- // std::size_t newHeadroom,
- // std::size_t newTailroom) {
+ // ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom,
+ // std::size_t newTailroom) {
// if (isChained()) {
- // coalesceAndReallocate(
- // newHeadroom, computeChainDataLength(), this, newTailroom);
+ // coalesceAndReallocate(newHeadroom, computeChainDataLength(), this,
+ // newTailroom);
// }
// return ByteRange(data_, length_);
// }