Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from GallaFrancesco/multiplexing_pull
Stream Multiplexing and Flow Control (updated)
- Loading branch information
Showing
17 changed files
with
1,511 additions
and
435 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name "http2-example" | ||
|
||
dependency "vibe-http" path="../../../vibe-http" | ||
|
||
/*versions "VibeForceALPN"*/ | ||
targetType "executable" | ||
/*buildOptions "profileGC"*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIDUjCCAjoCCQDPHygOhe1ZVjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQGEwJE | ||
RTEbMBkGA1UECBMSU2NobGVzd2lnLUhvbHN0ZWluMRAwDgYDVQQHFAdMw7xiZWNr | ||
MRkwFwYDVQQKExBvdXRlcnByb2R1Y3Qub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3Qw | ||
HhcNMTIwMjE0MjAxNDM0WhcNMTMwMjEzMjAxNDM0WjBrMQswCQYDVQQGEwJERTEb | ||
MBkGA1UECBMSU2NobGVzd2lnLUhvbHN0ZWluMRAwDgYDVQQHFAdMw7xiZWNrMRkw | ||
FwYDVQQKExBvdXRlcnByb2R1Y3Qub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEi | ||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4fLPWRShlq+o6vM5nhUCtR+IN | ||
mlAlQCzM3asWpQ76T/MOX1Ci1brypRgOXCmYI8c5lFGOIMpH1ZAh987t4UdkwVCn | ||
76pXv5yY4U1jJ5i9v7R7IUeKZ7utwlq1jPo3WWhiZwm1o6AxVRHGiUQ5XrcX0Rgt | ||
0bh9/5BWHLks3OJ44myjpgGv2J7n1LcyecRAd+suN4qsBiTITQBYq27WYsDCqrVB | ||
BoyCPhb51xTlaMlcAH2ekrm886FlC95VrwV7o4jb4sRGYdfKqT6HwXK1yTB3n742 | ||
2WavDgRj2vNQaL+XoPiBOrQZ8fj9PeWCyefSEtqz8/dpnJO+pxidKAow8As5AgMB | ||
AAEwDQYJKoZIhvcNAQEFBQADggEBAA8N27Wb9aq9JkAEGZ0Z/CLHbLeV3UQ5qb9V | ||
6KG8vvSoew3oxMlcHa49kq89AKx/gewt4fqCAHk64qpx8aEdbYorTbo9VIbwoLek | ||
9Lyp+AynmqDA6zk5+uOtPkwfN84f30khH04ouSmOvbV+uqD9bVZtR8ULTzbuE2h1 | ||
jbT64JQd+GW/uLQ770EKDVFml52BMJWrRFFgaRQhkm9k8krKqsCvYfMoULk3EQqS | ||
b5a/5q9pirXB7AHmiYAnqDu2xQL8N5e548RTZSWNl7mZD1NvVYc4l8tSKfCC3zG3 | ||
4wKngPl6t68pdnli67lX3YDTdHgOZWL+CsJT9TIRAOojfp5kWGY= | ||
-----END CERTIFICATE----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
-----BEGIN RSA PRIVATE KEY----- | ||
MIIEowIBAAKCAQEAuHyz1kUoZavqOrzOZ4VArUfiDZpQJUAszN2rFqUO+k/zDl9Q | ||
otW68qUYDlwpmCPHOZRRjiDKR9WQIffO7eFHZMFQp++qV7+cmOFNYyeYvb+0eyFH | ||
ime7rcJatYz6N1loYmcJtaOgMVURxolEOV63F9EYLdG4ff+QVhy5LNzieOJso6YB | ||
r9ie59S3MnnEQHfrLjeKrAYkyE0AWKtu1mLAwqq1QQaMgj4W+dcU5WjJXAB9npK5 | ||
vPOhZQveVa8Fe6OI2+LERmHXyqk+h8Fytckwd5++Ntlmrw4EY9rzUGi/l6D4gTq0 | ||
GfH4/T3lgsnn0hLas/P3aZyTvqcYnSgKMPALOQIDAQABAoIBABdkiJEk18h8kgi8 | ||
pBdwSBEwyjMbXAo9JvEbMnR+nXWT6afq4hijrT7TPEel3AhUkRB2BBlXgw60v7/u | ||
4ig7pofaE1YYB6t0unCQMPXfsXht9H6ga6fbG2se982JgLi/94JyukJz6v4WYVih | ||
UytLHUBB3SUCMLiZTT3+CmTr5TOamtcUi9ZNKtbxT2l+8iDbi7WaCUznrODZ8YMn | ||
/5RhE3XopBuCmeT8P7EhJSHe1THEcCcXtlChb7bMU7DMpvWYp9XBM4CQ2PpdHN5x | ||
bvKP8P6IH0TpjdBrdE16yO9P14saJoy1GSOx8y6zUxTMdgyFUnXK4bC+nUi3VRrq | ||
cikR3GECgYEA9MUsGAhVF8CRUsgvbn/q1QM1oFG1Dj1+LYEnXXNbdOugZVj2L8eT | ||
olAFFjprciemADmqhnxNgM0Ev+RVZzSDZFrAhQ+NYKw6JQe/EfIvnGyt5GXnoIJQ | ||
4hsibRH2UDHoGzxWTwcxbOdM3mqnY3WCMA3JWoLDEqApGRDh/hFFYtUCgYEAwPOB | ||
Ryfx5wTg/HM2kaVETgPkML81PvGdJxgKDW6XabEVdqf3Ds1UfELHRCK0LH0RS+8L | ||
5GDBuBeAuhpXtzkmwK30rTMfVqxi7IlddcYpBqCg9bHdyg6iAI2htwm+j9aLSCPw | ||
uNeCSqIYKIvLrcvrFWOlLRYonSxlyj7XLFypkNUCgYAnjkGs9JPDzePuS9mWcueh | ||
Wu5spSesUHW2ptuUt5K9F2MJXdITMJ6EKYhY6kH45b1m5erP5wCjYv50gFLo5cyi | ||
CCR6nGPNjqeq2lCfdtMI5WtIsMs43jZyA86Rb8itdxM6a4rLJK9xGQQMIZJBeXj7 | ||
iQ7UKLObq/RYT6kl5OagrQKBgGLsdRtGH3+RwMetSgzh7mMRG6ziWyoqNagVaxH3 | ||
4SkO4TI0azXrj6Ull4QXRsiIVpXXuQEdmjQH2LeRSedmJbgjd45U53xIZW9f/cqk | ||
DeSX9e4BgvRVDDm8Y2y0Uj7sf/w8cO5Tjzk0Ya5n/cTdB2mv7L9w3OG4IXfPQAI+ | ||
f7EBAoGBAKgvIg/bvF705Lg2bebjR2MVeVySDZP/SjY5my+4cF8VSJOK+8WA1MeJ | ||
dv4sukGjAMrMApegKmaiIngb2izINfanEd0xn4h1nCwVcRaNr9fSkZDBhi+JErol | ||
0janntvmByXPD0BXguza7NVJGmtzCyZk+rOHtC1J+qG7kdXHpPYT | ||
-----END RSA PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* ==== Vibe.d HTTP/2 Webserver Example ==== */ | ||
/* Supports both HTTP and HTTPS transport */ | ||
/* Transparent (WIP: exposing settings) */ | ||
/* ========================================= */ | ||
|
||
import vibe.http.server; | ||
import vibe.stream.tls; | ||
import vibe.http.internal.http2.http2 : http2Callback; // ALPN negotiation | ||
import vibe.core.core : runApplication; | ||
|
||
/* ==== declare two handlers (could use the same one) ==== */ | ||
void handleReq(HTTPServerRequest req, HTTPServerResponse res) | ||
@safe { | ||
if (res.httpVersion == HTTPVersion.HTTP_2) | ||
res.writeBody("Hello, you connected to "~req.path~"! This response is sent through HTTP/2\n"); | ||
else | ||
res.writeBody("Hello, World! You connected through HTTP/1, try using HTTP/2!\n"); | ||
} | ||
|
||
void tlsHandleReq(HTTPServerRequest req, HTTPServerResponse res) | ||
@safe { | ||
if (req.httpVersion == HTTPVersion.HTTP_2) | ||
res.writeBody("Hello, you connected to "~req.path~"! This response is sent through HTTP/2 with TLS\n"); | ||
else | ||
res.writeBody("Hello, World! You connected through HTTP/1 with TLS, try using HTTP/2!\n"); | ||
} | ||
|
||
// sends a very big data frame | ||
void bigHandleReq(size_t DIM)(HTTPServerRequest req, HTTPServerResponse res) | ||
@trusted { | ||
import vibe.utils.array : FixedAppender; | ||
import std.range : iota; | ||
|
||
FixedAppender!(immutable(char)[], DIM) appender; | ||
|
||
if (req.path == "/") { | ||
foreach(i; iota(1,DIM-4)) appender.put('1'); | ||
appender.put(['O','k','!', '\n']); | ||
res.writeBody(appender.data); | ||
} | ||
} | ||
|
||
void main() | ||
{ | ||
//import vibe.core.log; | ||
//setLogLevel(LogLevel.trace); | ||
|
||
/* ==== cleartext HTTP/2 support (h2c) ==== */ | ||
auto settings = HTTPServerSettings(); | ||
settings.port = 8090; | ||
settings.bindAddresses = ["127.0.0.1"]; | ||
listenHTTP!handleReq(settings); | ||
|
||
/* ==== cleartext HTTP/2 support (h2c) with a heavy DATA frame ==== */ | ||
auto bigSettings = HTTPServerSettings(); | ||
settings.port = 8092; | ||
settings.bindAddresses = ["127.0.0.1"]; | ||
listenHTTP!(bigHandleReq!100000)(settings); | ||
|
||
/* ========== HTTPS (h2) support ========== */ | ||
HTTPServerSettings tlsSettings; | ||
tlsSettings.port = 8091; | ||
tlsSettings.bindAddresses = ["127.0.0.1"]; | ||
|
||
/// setup TLS context by using cert and key in example rootdir | ||
tlsSettings.tlsContext = createTLSContext(TLSContextKind.server); | ||
tlsSettings.tlsContext.useCertificateChainFile("server.crt"); | ||
tlsSettings.tlsContext.usePrivateKeyFile("server.key"); | ||
|
||
// set alpn callback to support HTTP/2 protocol negotiation | ||
tlsSettings.tlsContext.alpnCallback(http2Callback); | ||
listenHTTP!tlsHandleReq(tlsSettings); | ||
|
||
/* ========== HTTPS (h2) support with a heavy DATA frame ========== */ | ||
HTTPServerSettings bigTLSSettings; | ||
bigTLSSettings.port = 8093; | ||
bigTLSSettings.bindAddresses = ["127.0.0.1"]; | ||
|
||
/// setup TLS context by using cert and key in example rootdir | ||
bigTLSSettings.tlsContext = createTLSContext(TLSContextKind.server); | ||
bigTLSSettings.tlsContext.useCertificateChainFile("server.crt"); | ||
bigTLSSettings.tlsContext.usePrivateKeyFile("server.key"); | ||
|
||
// set alpn callback to support HTTP/2 protocol negotiation | ||
bigTLSSettings.tlsContext.alpnCallback(http2Callback); | ||
auto l = listenHTTP!(bigHandleReq!100000)(bigTLSSettings); | ||
scope(exit) l.stopListening(); | ||
|
||
/* ========== Run both `listenHTTP` handlers ========== */ | ||
// UNCOMMENT to run | ||
runApplication(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
module vibe.http.internal.http2.error; | ||
|
||
import vibe.http.internal.http2.hpack.exception; | ||
import vibe.http.internal.http2.frame; | ||
|
||
import vibe.core.log; | ||
import vibe.core.net; | ||
import vibe.core.core; | ||
import vibe.core.stream; | ||
import vibe.stream.tls; | ||
import vibe.internal.array; | ||
import vibe.internal.allocator; | ||
import vibe.internal.freelistref; | ||
import vibe.internal.interfaceproxy; | ||
|
||
import std.range; | ||
import std.base64; | ||
import std.traits; | ||
import std.bitmanip; // read from ubyte (decoding) | ||
import std.typecons; | ||
import std.conv : to; | ||
import std.exception; | ||
import std.algorithm : canFind; // alpn callback | ||
import std.algorithm.iteration; | ||
|
||
enum HTTP2Error { | ||
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 | ||
} | ||
|
||
enum GOAWAYFrameLength = 17; | ||
|
||
/// creates a GOAWAY frame as defined in RFC 7540, section 6.8 | ||
void buildGOAWAYFrame(R)(ref R buf, const uint streamId, HTTP2Error error) | ||
@safe @nogc | ||
{ | ||
assert(buf.length == GOAWAYFrameLength, "Unable to create GOAWAY frame"); | ||
|
||
// last stream processed by the server (client-initiated) | ||
uint sid = (streamId > 1) ? streamId - 2 : 0; | ||
|
||
buf.createHTTP2FrameHeader(8, HTTP2FrameType.GOAWAY, 0x0, 0x0); | ||
buf.putBytes!4(sid & 127); // last stream ID | ||
buf.putBytes!4(error); | ||
} | ||
/// ditto | ||
auto buildGOAWAYFrame(uint sid, HTTP2Error code) @safe | ||
{ | ||
BatchBuffer!(ubyte, GOAWAYFrameLength) gbuf; | ||
|
||
gbuf.putN(GOAWAYFrameLength); | ||
gbuf.buildGOAWAYFrame(sid, code); | ||
|
||
return gbuf.peekDst; | ||
} | ||
|
||
|
||
/// exceptions | ||
T enforceHTTP2(T)(T condition, string message = null, HTTP2Error h2e = HTTP2Error.NO_ERROR, string file = __FILE__, typeof(__LINE__) line = __LINE__) @trusted | ||
{ | ||
return enforce(condition, new HTTP2Exception(message, h2e, file, line)); | ||
} | ||
|
||
class HTTP2Exception : Exception | ||
{ | ||
HTTP2Error code; | ||
|
||
this(string msg, HTTP2Error h2e = HTTP2Error.NO_ERROR, string file = __FILE__, size_t line = __LINE__) { | ||
code = h2e; | ||
super(msg, file, line); | ||
} | ||
} |
Oops, something went wrong.