diff --git a/include/ircd/http2/error.h b/include/ircd/http2/error.h new file mode 100644 index 000000000..373a1c046 --- /dev/null +++ b/include/ircd/http2/error.h @@ -0,0 +1,85 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_HTTP2_ERROR_H + +namespace ircd::http2 +{ + struct error; +} + +struct ircd::http2::error +:ircd::error +{ + enum code :uint32_t; + + enum code code; + + error(); + error(const enum code &); + + explicit + error(const enum code &, + const string_view &fmt, + va_rtti &&ap); + + template + error(const enum code &, + const string_view &fmt, + args&&...); + + template + error(const string_view &fmt, + args&&...); +}; + +namespace ircd::http2 +{ + string_view reflect(const enum error::code &); +} + +enum ircd::http2::error::code +:uint32_t +{ + NO_ERROR = 0x0, + PROTOCOL_ERROR = 0x1, + INTERNAL_ERROR = 0x2, + FLOW_CONTROL_ERROR = 0x3, + SETTINGS_TIMEOUT = 0x4, + STREAM_CLOSED = 0x5, + FRAME_SIZE_ERROR = 0x6, + REFUSED_STREAM = 0x7, + CANCEL = 0x8, + COMPRESSION_ERROR = 0x9, + CONNECT_ERROR = 0xa, + ENHANCE_YOUR_CALM = 0xb, + INADEQUATE_SECURITY = 0xc, + HTTP_1_1_REQUIRED = 0xd, +}; + +template +ircd::http2::error::error(const string_view &fmt, + args&&... a) +:error +{ + code::INTERNAL_ERROR, fmt, va_rtti{std::forward(a)...} +} +{} + +template +ircd::http2::error::error(const enum code &code, + const string_view &fmt, + args&&... a) +:error +{ + code, fmt, va_rtti{std::forward(a)...} +} +{} diff --git a/include/ircd/http2/frame.h b/include/ircd/http2/frame.h new file mode 100644 index 000000000..335a75147 --- /dev/null +++ b/include/ircd/http2/frame.h @@ -0,0 +1,51 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_HTTP2_FRAME_H + +namespace ircd::http2 +{ + struct frame; +} + +struct ircd::http2::frame +{ + struct header; + struct settings; + enum type :uint8_t; + + static string_view reflect(const type &); +}; + +struct ircd::http2::frame::header +{ + uint32_t len : 24; + enum type type; + uint8_t flags; + uint32_t : 1; + uint32_t stream_id : 31; +} +__attribute__((packed)); + +enum ircd::http2::frame::type +:uint8_t +{ + DATA = 0x0, + HEADERS = 0x1, + PRIORITY = 0x2, + RST_STREAM = 0x3, + SETTINGS = 0x4, + PUSH_PROMISE = 0x5, + PING = 0x6, + GOAWAY = 0x7, + WINDOW_UPDATE = 0x8, + CONTINUATION = 0x9, +}; diff --git a/include/ircd/http2/http2.h b/include/ircd/http2/http2.h new file mode 100644 index 000000000..457fb7f0f --- /dev/null +++ b/include/ircd/http2/http2.h @@ -0,0 +1,23 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_HTTP2_H + +/// HyperText TransPort / 2.x +namespace ircd::http2 +{ + extern const string_view connection_preface; +} + +#include "error.h" +#include "frame.h" +#include "settings.h" +#include "stream.h" diff --git a/include/ircd/http2/settings.h b/include/ircd/http2/settings.h new file mode 100644 index 000000000..15ef70914 --- /dev/null +++ b/include/ircd/http2/settings.h @@ -0,0 +1,66 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_HTTP2_SETTINGS_H + +namespace ircd::http2 +{ + struct settings; +} + +struct ircd::http2::frame::settings +{ + enum code :uint16_t; + enum flag :decltype(frame::header::flags); + struct param; + + vector_view param; +}; + +struct ircd::http2::frame::settings::param +{ + uint16_t id {0}; + uint32_t value {0}; +} +__attribute__((packed)); + +namespace ircd::http2 +{ + string_view reflect(const frame::settings::code &); +} + +enum ircd::http2::frame::settings::code +:uint16_t +{ + HEADER_TABLE_SIZE = 0x1, + ENABLE_PUSH = 0x2, + MAX_CONCURRENT_STREAMS = 0x3, + INITIAL_WINDOW_SIZE = 0x4, + MAX_FRAME_SIZE = 0x5, + MAX_HEADER_LIST_SIZE = 0x6, + + _NUM_ +}; + +enum ircd::http2::frame::settings::flag +:std::underlying_type::type +{ + ACK = (1 << 0), +}; + +struct ircd::http2::settings +:std::array()> +{ + using code = frame::settings::code; + using array_type = std::array()>; + + settings(); +}; diff --git a/include/ircd/http2/stream.h b/include/ircd/http2/stream.h new file mode 100644 index 000000000..b4fe61a07 --- /dev/null +++ b/include/ircd/http2/stream.h @@ -0,0 +1,43 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_HTTP2_STREAM_H + +namespace ircd::http2 +{ + struct stream; +} + +struct ircd::http2::stream +{ + enum class state :uint8_t; + + enum state state; + + stream(); +}; + +namespace ircd::http2 +{ + string_view reflect(const enum stream::state &); +} + +enum class ircd::http2::stream::state +:uint8_t +{ + IDLE, + RESERVED_LOCAL, + RESERVED_REMOTE, + OPEN, + HALF_CLOSED_LOCAL, + HALF_CLOSED_REMOTE, + CLOSED, +}; diff --git a/include/ircd/ircd.h b/include/ircd/ircd.h index 4fc863aef..29ed6ede8 100644 --- a/include/ircd/ircd.h +++ b/include/ircd/ircd.h @@ -45,6 +45,7 @@ #include "openssl.h" #include "fmt.h" #include "http.h" +#include "http2/http2.h" #include "magics.h" #include "conf.h" #include "stats.h" diff --git a/ircd/Makefile.am b/ircd/Makefile.am index 5631f025c..815c0c3b1 100644 --- a/ircd/Makefile.am +++ b/ircd/Makefile.am @@ -124,6 +124,7 @@ libircd_la_SOURCES += rfc1459.cc libircd_la_SOURCES += rfc3986.cc libircd_la_SOURCES += rfc1035.cc libircd_la_SOURCES += http.cc +libircd_la_SOURCES += http2.cc libircd_la_SOURCES += stats.cc libircd_la_SOURCES += prof.cc libircd_la_SOURCES += fs.cc diff --git a/ircd/http2.cc b/ircd/http2.cc new file mode 100644 index 000000000..ee894bbb0 --- /dev/null +++ b/ircd/http2.cc @@ -0,0 +1,169 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +decltype(ircd::http2::connection_preface) +ircd::http2::connection_preface +{ + "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// stream.h +// + +ircd::http2::stream::stream() +:state +{ + state::IDLE +} +{ +} + +ircd::string_view +ircd::http2::reflect(const enum stream::state &state) +{ + switch(state) + { + case stream::state::IDLE: return "IDLE"; + case stream::state::RESERVED_LOCAL: return "RESERVED_LOCAL"; + case stream::state::RESERVED_REMOTE: return "RESERVED_REMOTE"; + case stream::state::OPEN: return "OPEN"; + case stream::state::HALF_CLOSED_LOCAL: return "HALF_CLOSED_LOCAL"; + case stream::state::HALF_CLOSED_REMOTE: return "HALF_CLOSED_REMOTE"; + case stream::state::CLOSED: return "CLOSED"; + } + + return "??????"; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// settings.h +// + +/// RFC 7540 6.5.2 default settings +/// +ircd::http2::settings::settings() +:array_type +{ + 4096, // HEADER_TABLE_SIZE + 1, // ENABLE_PUSH + 0, // MAX_CONCURRENT_STREAMS (unlimited) + 65535, // INITIAL_WINDOW_SIZE + 16384, // MAX_FRAME_SIZE + 0, // MAX_HEADER_LIST_SIZE (unlimited) +} +{ +} + +ircd::string_view +ircd::http2::reflect(const frame::settings::code &code) +{ + switch(code) + { + case frame::settings::code::HEADER_TABLE_SIZE: return "HEADER_TABLE_SIZE"; + case frame::settings::code::ENABLE_PUSH: return "ENABLE_PUSH"; + case frame::settings::code::MAX_CONCURRENT_STREAMS: return "MAX_CONCURRENT_STREAMS"; + case frame::settings::code::INITIAL_WINDOW_SIZE: return "INITIAL_WINDOW_SIZE"; + case frame::settings::code::MAX_FRAME_SIZE: return "MAX_FRAME_SIZE"; + case frame::settings::code::MAX_HEADER_LIST_SIZE: return "MAX_HEADER_LIST_SIZE"; + case frame::settings::code::_NUM_: assert(0); + } + + return "??????"; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// frame.h +// + +static_assert +( + sizeof(ircd::http2::frame::header) == 9 +); + + +/////////////////////////////////////////////////////////////////////////////// +// +// error.h +// + +namespace ircd::http2 +{ + thread_local char error_fmt_buf[512]; +} + +ircd::http2::error::error() +:error +{ + code::INTERNAL_ERROR +} +{ +} + +ircd::http2::error::error(const enum code &code) +:ircd::error +{ + "(%x) %s", + uint32_t(code), + reflect(code), +} +,code +{ + code +} +{ +} + +ircd::http2::error::error(const enum code &code, + const string_view &fmt, + va_rtti &&ap) +:ircd::error +{ + "(%x) %s :%s", + uint32_t(code), + reflect(code), + string_view{fmt::vsprintf + { + error_fmt_buf, fmt, std::move(ap) + }} +} +,code +{ + code +} +{ +} + +ircd::string_view +ircd::http2::reflect(const enum error::code &code) +{ + switch(code) + { + case error::code::NO_ERROR: return "NO_ERROR"; + case error::code::PROTOCOL_ERROR: return "PROTOCOL_ERROR"; + case error::code::INTERNAL_ERROR: return "INTERNAL_ERROR"; + case error::code::FLOW_CONTROL_ERROR: return "FLOW_CONTROL_ERROR"; + case error::code::SETTINGS_TIMEOUT: return "SETTINGS_TIMEOUT"; + case error::code::STREAM_CLOSED: return "STREAM_CLOSED"; + case error::code::FRAME_SIZE_ERROR: return "FRAME_SIZE_ERROR"; + case error::code::REFUSED_STREAM: return "REFUSED_STREAM"; + case error::code::CANCEL: return "CANCEL"; + case error::code::COMPRESSION_ERROR: return "COMPRESSION_ERROR"; + case error::code::CONNECT_ERROR: return "CONNECT_ERROR"; + case error::code::ENHANCE_YOUR_CALM: return "ENHANCE_YOUR_CALM"; + case error::code::INADEQUATE_SECURITY: return "INADEQUATE_SECURITY"; + case error::code::HTTP_1_1_REQUIRED: return "HTTP_1_1_REQUIRED"; + } + + return "??????"; +}