0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-25 23:14:13 +01:00

ircd::http2: Start an RFC7540 implementation.

This commit is contained in:
Jason Volk 2019-06-21 16:54:22 -07:00
parent c944818f4b
commit d17afdd531
8 changed files with 439 additions and 0 deletions

View file

@ -0,0 +1,85 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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<class... args>
error(const enum code &,
const string_view &fmt,
args&&...);
template<class... args>
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<class... args>
ircd::http2::error::error(const string_view &fmt,
args&&... a)
:error
{
code::INTERNAL_ERROR, fmt, va_rtti{std::forward<args>(a)...}
}
{}
template<class... args>
ircd::http2::error::error(const enum code &code,
const string_view &fmt,
args&&... a)
:error
{
code, fmt, va_rtti{std::forward<args>(a)...}
}
{}

View file

@ -0,0 +1,51 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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,
};

View file

@ -0,0 +1,23 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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"

View file

@ -0,0 +1,66 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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<const struct param> 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<ircd::http2::frame::settings::flag>::type
{
ACK = (1 << 0),
};
struct ircd::http2::settings
:std::array<uint32_t, num_of<frame::settings::code>()>
{
using code = frame::settings::code;
using array_type = std::array<uint32_t, num_of<code>()>;
settings();
};

View file

@ -0,0 +1,43 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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,
};

View file

@ -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"

View file

@ -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

169
ircd/http2.cc Normal file
View file

@ -0,0 +1,169 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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 "??????";
}