Commit 769a716e authored by Felix Morgner's avatar Felix Morgner
Browse files

week10: add solution for task 1

parent a3f3ec3f
......@@ -21,8 +21,6 @@
namespace http {
struct message_headers {
message_headers();
template<header HeaderField, typename ... ValueTypes>
auto set(ValueTypes ... value) -> message_headers & = delete;
......@@ -83,32 +81,47 @@ namespace http {
auto body(std::string &&body) noexcept(std::is_nothrow_move_assignable_v<std::string>) -> DerivedType &
{
m_body = std::move(body);
(void)set<http::header::content_length>(body.size());
(void) set<http::header::content_length>(body.size());
return static_cast<DerivedType&>(*this);
}
auto body(std::string const &body) -> DerivedType &
{
m_body = body;
(void)set<http::header::content_length>(body.size());
(void) set<http::header::content_length>(body.size());
return static_cast<DerivedType&>(*this);
}
auto body(std::vector<std::byte> const &body) -> DerivedType &
{
m_body.resize(body.size());
(void)set<http::header::content_length>(body.size());
(void) set<http::header::content_length>(body.size());
transform(cbegin(body), cend(body), begin(m_body), [](auto part) {
return static_cast<char>(part);
});
return static_cast<DerivedType&>(*this);
}
auto body(std::istream &input) -> DerivedType &
{
m_body.clear();
copy(std::istreambuf_iterator<char>{input}, std::istreambuf_iterator<char>{}, back_inserter(m_body));
return static_cast<DerivedType&>(*this);
}
auto body() const -> std::string
{
return m_body;
}
auto complete() const -> bool {
return !has(header::content_length) || get<header::content_length>() == m_body.size();
}
template<typename Derived>
friend auto operator<<(std::ostream &out, message<Derived> const &message) -> std::ostream &;
protected:
auto read_headers(std::istream &input) -> void {
auto line = std::string{};
while (getline(input, line)) {
......@@ -143,9 +156,6 @@ namespace http {
}
}
template<typename Derived>
friend auto operator<<(std::ostream &out, message<Derived> const &message) -> std::ostream &;
private:
std::string m_body{};
};
......
......@@ -14,6 +14,7 @@ namespace http {
struct request : message<request> {
explicit request(method method = http::method::get) noexcept;
explicit request(std::istream & input);
auto path(std::string path) -> request &;
auto path() const -> std::string;
......@@ -37,8 +38,6 @@ namespace http {
auto friend operator<<(std::ostream & out, request const & request) -> std::ostream &;
auto read_headers(std::istream & input) -> void;
private:
http::method m_method{};
std::string m_path{};
......
......@@ -10,6 +10,7 @@ namespace http {
struct response : message<response> {
explicit response(status_code code) noexcept;
explicit response(std::istream & stream);
auto friend operator<<(std::ostream & out, response const & request) -> std::ostream &;
......
......@@ -89,4 +89,6 @@ auto to_string(http::status_code const &object) -> std::string;
template<>
auto from_string(std::string const &stringified) -> http::status_code;
auto to_status_code(int code) -> http::status_code;
#endif /* SIMPLE_HTTP_STATUS_CODE_H_ */
......@@ -7,10 +7,6 @@
namespace http
{
message_headers::message_headers() {
set<header::content_length>(static_cast<std::size_t>(0));
}
auto message_headers::has(header field) const noexcept -> bool {
return m_headers.count(field);
}
......
......@@ -50,6 +50,31 @@ namespace http {
: m_method{method} {
}
request::request(std::istream & input) {
auto line = std::string{};
while (std::isspace(input.peek())) {
input.ignore();
}
if (!getline(input, line)) {
throw std::invalid_argument{"missing method"};
}
std::string method{}, path{}, version{};
auto method_stream = std::istringstream{line};
if (!(method_stream >> method >> path >> version) || version != "HTTP/1.1") {
throw std::invalid_argument{"failed to parse method line"};
}
m_method = from_string<http::method>(method);
m_path = extract_path(path);
m_parameters = extract_parameters(path);
read_headers(input);
}
auto request::path(std::string path) -> request &
{
m_path = std::move(path);
......@@ -88,31 +113,6 @@ namespace http {
return m_method;
}
auto request::read_headers(std::istream &input) -> void {
auto line = std::string{};
while (std::isspace(input.peek())) {
input.ignore();
}
if (!getline(input, line)) {
throw std::invalid_argument{"missing method"};
}
std::string method{}, path{}, version{};
auto method_stream = std::istringstream{line};
if (!(method_stream >> method >> path >> version) || version != "HTTP/1.1") {
throw std::invalid_argument{"failed to parse method line"};
}
m_method = from_string<http::method>(method);
m_path = extract_path(path);
m_parameters = extract_parameters(path);
message<request>::read_headers(input);
}
auto operator<<(std::ostream &out, request const &request) -> std::ostream &
{
out << to_string(request.m_method) << ' ' << (request.m_path.empty() ? "/" : request.m_path);
......
#include "simple_http/response.h"
#include <type_traits>
#include <cctype>
#include <cstddef>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
namespace http {
response::response(status_code code) noexcept
: m_code{code} {
(void)set<header::content_length>(static_cast<std::size_t>(0));
}
response::response(std::istream &input) : m_code{static_cast<status_code>(-1)} {
auto line = std::string{};
while (std::isspace(input.peek())) {
input.ignore();
}
if (!getline(input, line)) {
throw std::invalid_argument{"missing http version"};
}
std::string version{}, code{}, code_message{};
auto method_stream = std::istringstream{line};
if (!(method_stream >> version >> code >> code_message) || version != "HTTP/1.1") {
throw std::invalid_argument{"failed to parse method line"};
}
m_code = to_status_code(std::stoi(code));
read_headers(input);
}
auto operator<<(std::ostream &out, response const &request) -> std::ostream &
......@@ -16,6 +43,4 @@ namespace http {
return out << "HTTP/1.1 " << to_string(request.m_code) << "\r\n"
<< static_cast<message<std::remove_cv_t<std::remove_reference_t<decltype(request)>>> const&>(request);
//@formatter:on
}
}
} }
......@@ -4,6 +4,8 @@
#include <stdexcept>
#include <string>
#include <utility>
#include <algorithm>
#include <iterator>
using namespace http;
......@@ -80,7 +82,7 @@ auto to_string(status_code const &object) -> std::string {
return std::to_string(static_cast<int>(object)) + " " + *found;
}
throw std::invalid_argument{"invalid mime type: " + std::to_string(static_cast<int>(object))};
throw std::invalid_argument{"invalid status code: " + std::to_string(static_cast<int>(object))};
}
template<>
......@@ -90,5 +92,16 @@ auto from_string(std::string const &stringified) -> status_code {
return *found;
}
throw std::invalid_argument{"invalid mime type: " + stringified};
throw std::invalid_argument{"invalid status code: " + stringified};
}
auto to_status_code(int code) -> http::status_code {
auto found = std::find_if(cbegin(string_map), cend(string_map), [&](auto entry){
return static_cast<int>(entry.first) == code;
});
if(found != cend(string_map)) {
return found->first;
}
throw std::invalid_argument("unknown status code: " + std::to_string(code));
}
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>w10_solution_01_SyncJuliaClient</name>
<comment></comment>
<projects>
<project>simple_http</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>
#include "simple_http.h"
#include "asio.hpp"
#include <algorithm>
#include <fstream>
#include <istream>
#include <iterator>
#include <sstream>
int main()
{
auto context = asio::io_context{};
auto resolver = asio::ip::tcp::resolver{context};
auto resolved = resolver.resolve("127.0.0.1", "8080");
auto socket = asio::ip::tcp::socket{context};
asio::connect(socket, resolved);
auto request = std::ostringstream{};
request << http::request{http::method::get};
auto request_data = request.str();
asio::write(socket, asio::buffer(request_data));
auto response_buffer = asio::streambuf{};
auto response_stream = std::istream{&response_buffer};
asio::read_until(socket, response_buffer, "\r\n\r\n");
auto response = http::response{response_stream};
if(!response.complete()) {
auto content_length = response.get<http::header::content_length>();
auto buffered = response_buffer.size();
asio::read(socket, response_buffer, asio::transfer_exactly(content_length - buffered));
response.body(response_stream);
}
auto file = std::ofstream{"julia.bmp", std::ios::trunc | std::ios::binary};
auto image_data = response.body();
copy(cbegin(image_data), cend(image_data), std::ostream_iterator<char>{file, ""});
}
//
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_HPP
#define ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "../../../third_party/asio/include/asio/associated_allocator.hpp"
#include "../../../third_party/asio/include/asio/associated_executor.hpp"
#include "../../../third_party/asio/include/asio/async_result.hpp"
#include "../../../third_party/asio/include/asio/awaitable.hpp"
#include "../../../third_party/asio/include/asio/basic_datagram_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_deadline_timer.hpp"
#include "../../../third_party/asio/include/asio/basic_io_object.hpp"
#include "../../../third_party/asio/include/asio/basic_raw_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_seq_packet_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_serial_port.hpp"
#include "../../../third_party/asio/include/asio/basic_signal_set.hpp"
#include "../../../third_party/asio/include/asio/basic_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_socket_acceptor.hpp"
#include "../../../third_party/asio/include/asio/basic_socket_iostream.hpp"
#include "../../../third_party/asio/include/asio/basic_socket_streambuf.hpp"
#include "../../../third_party/asio/include/asio/basic_stream_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_streambuf.hpp"
#include "../../../third_party/asio/include/asio/basic_waitable_timer.hpp"
#include "../../../third_party/asio/include/asio/bind_executor.hpp"
#include "../../../third_party/asio/include/asio/buffer.hpp"
#include "../../../third_party/asio/include/asio/buffered_read_stream_fwd.hpp"
#include "../../../third_party/asio/include/asio/buffered_read_stream.hpp"
#include "../../../third_party/asio/include/asio/buffered_stream_fwd.hpp"
#include "../../../third_party/asio/include/asio/buffered_stream.hpp"
#include "../../../third_party/asio/include/asio/buffered_write_stream_fwd.hpp"
#include "../../../third_party/asio/include/asio/buffered_write_stream.hpp"
#include "../../../third_party/asio/include/asio/buffers_iterator.hpp"
#include "../../../third_party/asio/include/asio/co_spawn.hpp"
#include "../../../third_party/asio/include/asio/completion_condition.hpp"
#include "../../../third_party/asio/include/asio/compose.hpp"
#include "../../../third_party/asio/include/asio/connect.hpp"
#include "../../../third_party/asio/include/asio/coroutine.hpp"
#include "../../../third_party/asio/include/asio/deadline_timer.hpp"
#include "../../../third_party/asio/include/asio/defer.hpp"
#include "../../../third_party/asio/include/asio/detached.hpp"
#include "../../../third_party/asio/include/asio/dispatch.hpp"
#include "../../../third_party/asio/include/asio/error.hpp"
#include "../../../third_party/asio/include/asio/error_code.hpp"
#include "../../../third_party/asio/include/asio/execution_context.hpp"
#include "../../../third_party/asio/include/asio/executor.hpp"
#include "../../../third_party/asio/include/asio/executor_work_guard.hpp"
#include "../../../third_party/asio/include/asio/generic/basic_endpoint.hpp"
#include "../../../third_party/asio/include/asio/generic/datagram_protocol.hpp"
#include "../../../third_party/asio/include/asio/generic/raw_protocol.hpp"
#include "../../../third_party/asio/include/asio/generic/seq_packet_protocol.hpp"
#include "../../../third_party/asio/include/asio/generic/stream_protocol.hpp"
#include "../../../third_party/asio/include/asio/handler_alloc_hook.hpp"
#include "../../../third_party/asio/include/asio/handler_continuation_hook.hpp"
#include "../../../third_party/asio/include/asio/handler_invoke_hook.hpp"
#include "../../../third_party/asio/include/asio/high_resolution_timer.hpp"
#include "../../../third_party/asio/include/asio/io_context.hpp"
#include "../../../third_party/asio/include/asio/io_context_strand.hpp"
#include "../../../third_party/asio/include/asio/io_service.hpp"
#include "../../../third_party/asio/include/asio/io_service_strand.hpp"
#include "../../../third_party/asio/include/asio/ip/address.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v4.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v4_iterator.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v4_range.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v6.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v6_iterator.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v6_range.hpp"
#include "../../../third_party/asio/include/asio/ip/network_v4.hpp"
#include "../../../third_party/asio/include/asio/ip/network_v6.hpp"
#include "../../../third_party/asio/include/asio/ip/bad_address_cast.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_endpoint.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver_entry.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver_iterator.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver_query.hpp"
#include "../../../third_party/asio/include/asio/ip/host_name.hpp"
#include "../../../third_party/asio/include/asio/ip/icmp.hpp"
#include "../../../third_party/asio/include/asio/ip/multicast.hpp"
#include "../../../third_party/asio/include/asio/ip/resolver_base.hpp"
#include "../../../third_party/asio/include/asio/ip/resolver_query_base.hpp"
#include "../../../third_party/asio/include/asio/ip/tcp.hpp"
#include "../../../third_party/asio/include/asio/ip/udp.hpp"
#include "../../../third_party/asio/include/asio/ip/unicast.hpp"
#include "../../../third_party/asio/include/asio/ip/v6_only.hpp"
#include "../../../third_party/asio/include/asio/is_executor.hpp"
#include "../../../third_party/asio/include/asio/is_read_buffered.hpp"
#include "../../../third_party/asio/include/asio/is_write_buffered.hpp"
#include "../../../third_party/asio/include/asio/local/basic_endpoint.hpp"
#include "../../../third_party/asio/include/asio/local/connect_pair.hpp"
#include "../../../third_party/asio/include/asio/local/datagram_protocol.hpp"
#include "../../../third_party/asio/include/asio/local/stream_protocol.hpp"
#include "../../../third_party/asio/include/asio/packaged_task.hpp"
#include "../../../third_party/asio/include/asio/placeholders.hpp"
#include "../../../third_party/asio/include/asio/posix/basic_descriptor.hpp"
#include "../../../third_party/asio/include/asio/posix/basic_stream_descriptor.hpp"
#include "../../../third_party/asio/include/asio/posix/descriptor.hpp"
#include "../../../third_party/asio/include/asio/posix/descriptor_base.hpp"
#include "../../../third_party/asio/include/asio/posix/stream_descriptor.hpp"
#include "../../../third_party/asio/include/asio/post.hpp"
#include "../../../third_party/asio/include/asio/read.hpp"
#include "../../../third_party/asio/include/asio/read_at.hpp"
#include "../../../third_party/asio/include/asio/read_until.hpp"
#include "../../../third_party/asio/include/asio/redirect_error.hpp"
#include "../../../third_party/asio/include/asio/serial_port.hpp"
#include "../../../third_party/asio/include/asio/serial_port_base.hpp"
#include "../../../third_party/asio/include/asio/signal_set.hpp"
#include "../../../third_party/asio/include/asio/socket_base.hpp"
#include "../../../third_party/asio/include/asio/steady_timer.hpp"
#include "../../../third_party/asio/include/asio/strand.hpp"
#include "../../../third_party/asio/include/asio/streambuf.hpp"
#include "../../../third_party/asio/include/asio/system_context.hpp"
#include "../../../third_party/asio/include/asio/system_error.hpp"
#include "../../../third_party/asio/include/asio/system_executor.hpp"
#include "../../../third_party/asio/include/asio/system_timer.hpp"
#include "../../../third_party/asio/include/asio/this_coro.hpp"
#include "../../../third_party/asio/include/asio/thread.hpp"
#include "../../../third_party/asio/include/asio/thread_pool.hpp"
#include "../../../third_party/asio/include/asio/time_traits.hpp"
#include "../../../third_party/asio/include/asio/use_awaitable.hpp"
#include "../../../third_party/asio/include/asio/use_future.hpp"
#include "../../../third_party/asio/include/asio/uses_executor.hpp"
#include "../../../third_party/asio/include/asio/version.hpp"
#include "../../../third_party/asio/include/asio/wait_traits.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_object_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_overlapped_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_random_access_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_stream_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/object_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/overlapped_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/overlapped_ptr.hpp"
#include "../../../third_party/asio/include/asio/windows/random_access_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/stream_handle.hpp"
#include "../../../third_party/asio/include/asio/write.hpp"
#include "../../../third_party/asio/include/asio/write_at.hpp"
#endif // ASIO_HPP
//
// associated_allocator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATED_ALLOCATOR_HPP
#define ASIO_ASSOCIATED_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "../../../../third_party/asio/include/asio/detail/config.hpp"
#include <memory>
#include "../../../../third_party/asio/include/asio/detail/type_traits.hpp"
#include "../../../../third_party/asio/include/asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename>
struct associated_allocator_check
{
typedef void type;
};
template <typename T, typename E, typename = void>
struct associated_allocator_impl
{
typedef E type;
static type get(const T&, const E& e) ASIO_NOEXCEPT
{
return e;
}
};
template <typename T, typename E>
struct associated_allocator_impl<T, E,
typename associated_allocator_check<typename T::allocator_type>::type>
{
typedef typename T::allocator_type type;
static type get(const T& t, const E&) ASIO_NOEXCEPT
{
return t.get_allocator();
}
};
} // namespace detail
/// Traits type used to obtain the allocator associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Allocator shall be a type meeting the Allocator requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c a is an object of type @c
* Allocator.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Allocator requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,a) and with return type @c type.
*/
template <typename T, typename Allocator = std::allocator<void> >
struct associated_allocator
{
/// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
/// Otherwise @c Allocator.
#if defined(GENERATING_DOCUMENTATION)
typedef see_below type;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::associated_allocator_impl<T, Allocator>::type type;
#endif // defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c allocator_type, returns
/// <tt>t.get_allocator()</tt>. Otherwise returns @c a.