Skip to content

Commit

Permalink
Merge pull request #1739 from hioa-cs/dev
Browse files Browse the repository at this point in the history
Merge dev
  • Loading branch information
alfreb authored Apr 10, 2018
2 parents 4d2dd08 + 50c73b0 commit ec807a2
Show file tree
Hide file tree
Showing 39 changed files with 853 additions and 696 deletions.
2 changes: 1 addition & 1 deletion api/net/buffer_store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ namespace net
size_t bufsize_;
uint8_t* pool_;
std::vector<uint8_t*> available_;
BufferStore* next_;
std::unique_ptr<BufferStore> next_;
int index;
#ifndef INCLUDEOS_SINGLE_THREADED
// has strict alignment reqs, so put at end
Expand Down
256 changes: 256 additions & 0 deletions api/net/http/basic_client.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2016-2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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
#ifndef HTTP_BASIC_CLIENT_HPP
#define HTTP_BASIC_CLIENT_HPP

// http
#include "client_connection.hpp"

#include <net/tcp/tcp.hpp>
#include <vector>
#include <map>

namespace http {

struct Client_error : public std::runtime_error {
using runtime_error::runtime_error;
};

using Response_handler = Client_connection::Response_handler;

class Basic_client {
public:
using TCP = net::TCP;
using Host = net::Socket;

using Response_handler = Client_connection::Response_handler;
struct Options;
using Request_handler = delegate<void(Request&, Options&, const Host)>;

using Connection_set = std::vector<std::unique_ptr<Client_connection>>;
using Connection_mapset = std::map<Host, Connection_set>;

using timeout_duration = Client_connection::timeout_duration;

const static timeout_duration DEFAULT_TIMEOUT; // client.cpp, 5s
constexpr static size_t DEFAULT_BUFSIZE = 2048;

/* Client Options */
// if someone has a better solution, please fix
struct Options {
timeout_duration timeout{DEFAULT_TIMEOUT};
size_t bufsize{DEFAULT_BUFSIZE};

Options(timeout_duration dur, size_t bufsz)
: timeout{dur},
bufsize{bufsz}
{}

Options() : Options(DEFAULT_TIMEOUT, DEFAULT_BUFSIZE) {}

Options(timeout_duration dur) : Options(dur, DEFAULT_BUFSIZE) {}

Options(size_t bufsz) : Options(DEFAULT_TIMEOUT, bufsz) {}

};

private:
using ResolveCallback = delegate<void(net::ip4::Addr, const net::Error&)>;

public:
explicit Basic_client(TCP& tcp, Request_handler on_send = nullptr);

/**
* @brief Creates a request with some predefined attributes
*
* @param[in] method The HTTP method
*
* @return A Request_ptr
*/
Request_ptr create_request(Method method = GET) const;

/**
* @brief Send a request to a specific host with a response handler
*
* @param[in] req The request
* @param[in] host The host
* @param[in] cb Callback to be invoked when a response is received (or error)
*/
void send(Request_ptr req, Host host, Response_handler cb,
const bool secure = false, Options options = {});

/**
* @brief Create a request on the given URL
*
* @param[in] method The HTTP method
* @param[in] url The url
* @param[in] hfields A set of headers
* @param[in] cb Response handler
*/
void request(Method method, URI url, Header_set hfields,
Response_handler cb, Options options = {});

/**
* @brief Same as above
*/
void request(Method method, std::string url, Header_set hfields,
Response_handler cb, Options options = {})
{ request(method, URI{url}, std::move(hfields), std::move(cb), std::move(options)); }

/**
* @brief Create a request to the given host on the given path
*
* @param[in] method The HTTP method
* @param[in] host The host
* @param[in] path The path
* @param[in] hfields A set of headers
* @param[in] cb Response handler
*/
void request(Method method, Host host, std::string path, Header_set hfields,
Response_handler cb, const bool secure = false, Options options = {});

/**
* @brief Create a request on the given URL with payload
*
* @param[in] method The HTTP method
* @param[in] url The url
* @param[in] hfields A set of headers
* @param[in] data The data (payload)
* @param[in] cb Response handler
*/
void request(Method method, URI url, Header_set hfields, std::string data,
Response_handler cb, Options options = {});

/**
* @brief Same as above
*/
void request(Method method, std::string url, Header_set hfields, std::string data,
Response_handler cb, Options options = {})
{ request(method, URI{url}, std::move(hfields), std::move(data), std::move(cb), std::move(options)); }

/**
* @brief Create a request to the given host on the given path with payload
*
* @param[in] method The HTTP method
* @param[in] host The host
* @param[in] path The path
* @param[in] hfields A set of headers
* @param[in] data The data (payload)
* @param[in] cb Response handler
*/
void request(Method method, Host host, std::string path, Header_set hfields,
const std::string& data, Response_handler cb,
const bool secure = false, Options options = {});

/* GET */
inline void get(URI url, Header_set hfields, Response_handler cb, Options options = {});
inline void get(Host host, std::string path, Header_set hfields,
Response_handler cb, const bool secure = false, Options options = {});

/* POST */
inline void post(URI url, Header_set hfields, std::string data,
Response_handler cb, Options options = {});
inline void post(Host host, std::string path, Header_set hfields,
const std::string& data, Response_handler cb,
const bool secure = false, Options options = {});

/**
* @brief Set callback to be invoked right before the request gets sent.
*
* @details Useful for modifying/inspecting auto-generated Requests.
*
* @param[in] cb Request_handler callback
*/
void on_send(Request_handler cb)
{ on_send_ = std::move(cb); }

/**
* @brief Returns the Origin for the Client as a string.
* Currently returns the IP address to the stack.
*
* @return The origin as a string
*/
std::string origin() const
{ return tcp_.stack().ip_addr().to_string(); }

virtual ~Basic_client() = default;

protected:
TCP& tcp_;
Connection_mapset conns_;

explicit Basic_client(TCP& tcp, Request_handler on_send, const bool https_supported);

virtual Client_connection& get_secure_connection(const Host host);

private:
friend class Client_connection;
Request_handler on_send_;
bool keep_alive_ = false;
const bool supports_https;

void resolve(const std::string& host, ResolveCallback);

void set_connection_header(Request& req) const
{
req.header().set_field(header::Connection,
(keep_alive_) ? std::string{"keep-alive"} : std::string{"close"});
}

/** Set uri and Host from URL */
void populate_from_url(Request& req, const URI& url);

/** Add data and content length */
void add_data(Request&, const std::string& data);

Client_connection& get_connection(const Host host);

void close(Client_connection&);

void validate_secure(const bool secure) const
{
if(secure and not this->supports_https)
throw Client_error{"Secured connections not supported with Basic_client (use the HTTPS Client)."};
}

}; // < class Basic_client


/* Inline implementation */
inline void Basic_client::get(URI url, Header_set hfields, Response_handler cb, Options options)
{ request(GET, std::move(url), std::move(hfields), std::move(cb), std::move(options)); }

inline void Basic_client::get(Host host, std::string path, Header_set hfields,
Response_handler cb, const bool secure, Options options)
{ request(GET, std::move(host), std::move(path), std::move(hfields), std::move(cb), secure, std::move(options)); }

/* POST */
inline void Basic_client::post(URI url, Header_set hfields, std::string data,
Response_handler cb, Options options)
{ request(POST, std::move(url), std::move(hfields), std::move(data), std::move(cb), std::move(options)); }

inline void Basic_client::post(Host host, std::string path, Header_set hfields,
const std::string& data, Response_handler cb,
const bool secure, Options options)
{ request(POST, std::move(host), std::move(path), std::move(hfields), std::move(data), std::move(cb), secure, std::move(options)); }


} // < namespace http

#endif // < HTTP_BASIC_CLIENT_HPP
Loading

0 comments on commit ec807a2

Please sign in to comment.