aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAxel Ulrich <ulrich.axel@gmail.com>2020-05-19 13:20:51 -0400
committerRasmus Thomsen <oss@cogitri.dev>2020-05-26 20:34:43 +0000
commit33c2125e094c1367bad0c4bd9760c2db12269267 (patch)
tree6e5d4e466264c6b756cb43bbf0568b8f7cf610e9
parent479a259baa0f66bfeb5d11a0d0d4ce4fa3da9260 (diff)
downloadalpine_aports-33c2125e094c1367bad0c4bd9760c2db12269267.tar.bz2
alpine_aports-33c2125e094c1367bad0c4bd9760c2db12269267.tar.xz
alpine_aports-33c2125e094c1367bad0c4bd9760c2db12269267.zip
community/h2o: adding check()
-rw-r--r--community/h2o/APKBUILD28
-rw-r--r--community/h2o/backslashinterpreationintests.patch14
-rw-r--r--community/h2o/cannotlocatetutilpm.patch39
-rw-r--r--community/h2o/disabletls13intls12tests.patch25
-rw-r--r--community/h2o/increasewaitforserverstartintests.patch14
-rw-r--r--community/h2o/largeheadertest.patch19
-rw-r--r--community/h2o/missingsubmodules.patch503
-rw-r--r--community/h2o/proxysessionresumption.patch134
-rw-r--r--community/h2o/sessiontickettest.patch140
-rw-r--r--community/perl-http-entity-parser/APKBUILD (renamed from testing/perl-http-entity-parser/APKBUILD)0
-rw-r--r--community/perl-http-multipartparser/APKBUILD (renamed from testing/perl-http-multipartparser/APKBUILD)0
-rw-r--r--community/perl-protocol-http2/APKBUILD (renamed from testing/perl-protocol-http2/APKBUILD)0
-rw-r--r--community/perl-www-form-urlencoded/APKBUILD (renamed from testing/perl-www-form-urlencoded/APKBUILD)0
13 files changed, 912 insertions, 4 deletions
diff --git a/community/h2o/APKBUILD b/community/h2o/APKBUILD
index 9be25491d4..c46efaf3c0 100644
--- a/community/h2o/APKBUILD
+++ b/community/h2o/APKBUILD
@@ -1,21 +1,30 @@
1# Contributor: Bennett Goble <nivardus@gmail.com> 1# Contributor: Bennett Goble <nivardus@gmail.com>
2# Contributor: Axel Ulrich <ulrich.axel@gmail.com>
2# Maintainer: Bennett Goble <nivardus@gmail.com> 3# Maintainer: Bennett Goble <nivardus@gmail.com>
3pkgname=h2o 4pkgname=h2o
4pkgver=2.2.6 5pkgver=2.2.6
5pkgrel=4 6pkgrel=5
6pkgdesc="An optimized HTTP/1, HTTP/2 server written in C" 7pkgdesc="An optimized HTTP/1, HTTP/2 server written in C"
7url="https://h2o.examp1e.net" 8url="https://h2o.examp1e.net"
8arch="all !s390x" 9arch="all !s390x"
9depends="perl openssl" 10depends="perl openssl"
10license="MIT" 11license="MIT"
11makedepends="cmake ruby-dev bison zlib-dev wslay-dev openssl-dev libuv-dev yaml-dev" 12makedepends="cmake ruby-dev bison zlib-dev wslay-dev openssl-dev libuv-dev yaml-dev"
12options="!check" 13checkdepends="perl-test-harness-utils perl-test-tcp perl-test-simple perl-json perl-path-tiny perl-scope-guard perl-test-exception perl-protocol-http2 perl-test-requires perl-hash-multivalue perl-plack perl-lwp-protocol-https perl-http-headers-fast perl-cookie-baker perl-http-entity-parser perl-starlet perl-fcgi-procmanager perl-cgi perl-fcgi nodejs wget"
13install="$pkgname.pre-install" 14install="$pkgname.pre-install"
14subpackages="$pkgname-dev $pkgname-doc $pkgname-openrc" 15subpackages="$pkgname-dev $pkgname-doc $pkgname-openrc"
15source="$pkgname-$pkgver.tar.gz::https://github.com/h2o/h2o/archive/v$pkgver.tar.gz 16source="$pkgname-$pkgver.tar.gz::https://github.com/h2o/h2o/archive/v$pkgver.tar.gz
16 h2o.conf 17 h2o.conf
17 h2o.initd 18 h2o.initd
18 h2o.logrotate 19 h2o.logrotate
20 missingsubmodules.patch
21 backslashinterpreationintests.patch
22 disabletls13intls12tests.patch
23 largeheadertest.patch
24 proxysessionresumption.patch
25 sessiontickettest.patch
26 cannotlocatetutilpm.patch
27 increasewaitforserverstartintests.patch
19 " 28 "
20 29
21# secfixes: 30# secfixes:
@@ -32,7 +41,10 @@ build() {
32 -DCMAKE_INSTALL_PREFIX=/usr \ 41 -DCMAKE_INSTALL_PREFIX=/usr \
33 -DWITH_MRUBY=ON 42 -DWITH_MRUBY=ON
34 make -C build 43 make -C build
35 make -C build libh2o 44}
45
46check() {
47 make -C build check
36} 48}
37 49
38package() { 50package() {
@@ -56,4 +68,12 @@ package() {
56sha512sums="f2f28905c01782a0432c9dfdb2f21054e0a4741ac4c5f26802d4b439d0172840aa215aba5dc7c9af62275dcc24de105674a3819384dc38246e43ce3e8263eb20 h2o-2.2.6.tar.gz 68sha512sums="f2f28905c01782a0432c9dfdb2f21054e0a4741ac4c5f26802d4b439d0172840aa215aba5dc7c9af62275dcc24de105674a3819384dc38246e43ce3e8263eb20 h2o-2.2.6.tar.gz
57444f55c3eaae1f349223036086e45c983ea8be89e793068537ec25488c4065174bc509d0987ddc65a0357cb8acfec272e90d13ea7cdadf9cf112953d857aa574 h2o.conf 69444f55c3eaae1f349223036086e45c983ea8be89e793068537ec25488c4065174bc509d0987ddc65a0357cb8acfec272e90d13ea7cdadf9cf112953d857aa574 h2o.conf
58e93e66a6b00b1bff94e37489c5fdf99d9d657adc63975ec54be30f8da23dafe7d7389f02a6452ed819efc9d8398aa716782a7fd6d8509621a975ed954b73bef9 h2o.initd 70e93e66a6b00b1bff94e37489c5fdf99d9d657adc63975ec54be30f8da23dafe7d7389f02a6452ed819efc9d8398aa716782a7fd6d8509621a975ed954b73bef9 h2o.initd
593d2c9e36c48cbb974d0691e4af8e9eb8f13e3bebb98a30417cdc87e76a4b5cddc4e4f665ebea26b95174287b95d002fdc3363f30ffcf15247fcd0530fe1abfcc h2o.logrotate" 713d2c9e36c48cbb974d0691e4af8e9eb8f13e3bebb98a30417cdc87e76a4b5cddc4e4f665ebea26b95174287b95d002fdc3363f30ffcf15247fcd0530fe1abfcc h2o.logrotate
72c03ceeea23a545b948815aeb48872dbac388665f0c79c643e7fa17695580c71260b2227058fe60702d052536e8bdb4d8104d430557ec0c3c4515ed132db7a4a8 missingsubmodules.patch
73cd62b93041f2f9407d3aa82c924aa13a3f38330a3557c230c47f30eb3d8bbb90db95cdd2ff1e8248eadcae711c90d0e33caa221ede46015df92c3fe4148a6f21 backslashinterpreationintests.patch
7428c5a3a8f64391f317c90f826a488e513b25ad3e7c5febffc0f3a0323b361e4b2900d9dd5e542754b0083c30f68f270eb3b17a8b23ad3f43e4b28feb260ad9eb disabletls13intls12tests.patch
75a8b2edff9da782319682ecbf62b93090eedc5503236a7106d0313429b157ec091ddbeb9b8f9f91567ae712a4f2c082b9ba8f84d890b72b54c161c0c4e1cab0ef largeheadertest.patch
76a5df628f200475f5db6eb9d1714e955cd33c2de3081ee5f770929833a4cb9e5030fe338c23bcfb516235c2036c6e6452bb52447da0c3d69e3ea8de8bfa00f420 proxysessionresumption.patch
779304ea3ebb74eb66f3d8c8facfc8a08366cb35ac8f5ee8090f59202abd13842d4a4565b5cbfcfff3110473a03bb9ff00b0f74311b450113675f0cb6d6b759d90 sessiontickettest.patch
78848b9d20221c2d55b034bd3b9943100fd82f3e32a6032e126868471f9e18f60a9d94bc9024890e4af7ee8ffd6308cc1beb001e3052cb938b14280d331493307b cannotlocatetutilpm.patch
7926c4f34bdcb82cdca00b81e8c3223a1c517f912f433e99ae4a9aa16481db2cd23fc77f65773932f8c6e30cb5e34d5d37e0e7a022518a6a13db75d8e16fee2ab4 increasewaitforserverstartintests.patch"
diff --git a/community/h2o/backslashinterpreationintests.patch b/community/h2o/backslashinterpreationintests.patch
new file mode 100644
index 0000000000..c8cb4663c8
--- /dev/null
+++ b/community/h2o/backslashinterpreationintests.patch
@@ -0,0 +1,14 @@
1Upstream: Yes
2Reason: Without this patch tests fail on shells backslash escapes disabled
3Url: https://github.com/h2o/h2o/pull/2331
4--- a/t/50mruby.t
5+++ b/t/50mruby.t
6@@ -498,7 +498,7 @@
7 EOT
8 my $nc = sub {
9 my $path = shift;
10- my $cmd = "echo 'GET $path HTTP/1.1\\r\\nHost: 127.0.0.1\\r\\n\\r' | nc 127.0.0.1 $server->{port}";
11+ my $cmd = "echo 'GET $path HTTP/1.1\r\nHost: 127.0.0.1\r\n\r' | nc 127.0.0.1 $server->{port}";
12 (undef, my $r) = run_prog($cmd);
13 split(/\r\n\r\n/, $r, 2);
14 };
diff --git a/community/h2o/cannotlocatetutilpm.patch b/community/h2o/cannotlocatetutilpm.patch
new file mode 100644
index 0000000000..2897fcdc08
--- /dev/null
+++ b/community/h2o/cannotlocatetutilpm.patch
@@ -0,0 +1,39 @@
1Upstream: Yes
2Reason: Without this patch make check fails
3Url: https://github.com/h2o/h2o/issues/2167
4--- a/CMakeLists.txt
5+++ b/CMakeLists.txt
6@@ -386,13 +386,13 @@
7 OUTPUT_NAME h2o
8 VERSION ${LIBRARY_VERSION}
9 SOVERSION ${LIBRARY_SOVERSION})
10-TARGET_LINK_LIBRARIES(libh2o ${LIBUV_LIBRARIES} ${EXTRA_LIBS})
11+TARGET_LINK_LIBRARIES(libh2o ${WSLAY_LIBRARIES} ${LIBUV_LIBRARIES} ${EXTRA_LIBS})
12 SET_TARGET_PROPERTIES(libh2o-evloop PROPERTIES
13 OUTPUT_NAME h2o-evloop
14 COMPILE_FLAGS "-DH2O_USE_LIBUV=0"
15 VERSION ${LIBRARY_VERSION}
16 SOVERSION ${LIBRARY_SOVERSION})
17-TARGET_LINK_LIBRARIES(libh2o-evloop ${EXTRA_LIBS})
18+TARGET_LINK_LIBRARIES(libh2o-evloop ${WSLAY_LIBRARIES} ${EXTRA_LIBS})
19
20 IF (OPENSSL_FOUND)
21 TARGET_INCLUDE_DIRECTORIES(libh2o PUBLIC ${OPENSSL_INCLUDE_DIR})
22@@ -553,7 +553,7 @@
23 ENDIF (OPENSSL_FOUND)
24 ENDIF (WITH_BUNDLED_SSL)
25
26-ADD_CUSTOM_TARGET(check env H2O_ROOT=. BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} prove -v t/*.t
27+ADD_CUSTOM_TARGET(check env H2O_ROOT=. BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} prove -I. -v t/*.t
28 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
29 DEPENDS h2o t-00unit-evloop.t)
30 IF (LIBUV_FOUND)
31@@ -563,7 +563,7 @@
32 ENDIF ()
33 ENDIF ()
34
35-ADD_CUSTOM_TARGET(check-as-root env H2O_ROOT=. BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} prove -v t/90root-*.t
36+ADD_CUSTOM_TARGET(check-as-root env H2O_ROOT=. BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} prove -I. -v t/90root-*.t
37 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
38
39 IF (BUILD_FUZZER)
diff --git a/community/h2o/disabletls13intls12tests.patch b/community/h2o/disabletls13intls12tests.patch
new file mode 100644
index 0000000000..714e9fa4bd
--- /dev/null
+++ b/community/h2o/disabletls13intls12tests.patch
@@ -0,0 +1,25 @@
1Upstream: Yes
2Reason: Without this patch certain TLS1.2 bahavior tests fail as TLS1.3 is chosen by default
3Url: https://github.com/h2o/h2o/commit/442908871b935311c903d2d234708b3de9b40fd5
4--- a/t/40ssl-cipher-suite.t
5+++ b/t/40ssl-cipher-suite.t
6@@ -32,7 +32,7 @@
7 );
8
9 # connect to the server with AES256-SHA as the first choice, and check that AES128-SHA was selected
10-my $log = `openssl s_client -cipher AES256-SHA:AES128-SHA -host 127.0.0.1 -port $port < /dev/null 2>&1`;
11+my $log = `openssl s_client -cipher AES256-SHA:AES128-SHA -host 127.0.0.1 -port $port -tls1_2 < /dev/null 2>&1`;
12 like $log, qr/^\s*Cipher\s*:\s*AES128-SHA\s*$/m;
13
14 done_testing;
15--- a/t/50access-log.t
16+++ b/t/50access-log.t
17@@ -168,7 +168,7 @@
18 sub {
19 my $server = shift;
20 system("curl --silent http://127.0.0.1:$server->{port}/ > /dev/null");
21- system("curl --silent --insecure @{[curl_supports_http2() ? ' --http1.1' : '']} https://127.0.0.1:$server->{tls_port}/ > /dev/null");
22+ system("curl --silent --insecure @{[curl_supports_http2() ? ' --http1.1' : '']} https://127.0.0.1:$server->{tls_port}/ --tls-max 1.2 > /dev/null");
23 if (prog_exists("nghttp")) {
24 system("nghttp -n https://127.0.0.1:$server->{tls_port}/");
25 system("nghttp -n --weight=22 https://127.0.0.1:$server->{tls_port}/");
diff --git a/community/h2o/increasewaitforserverstartintests.patch b/community/h2o/increasewaitforserverstartintests.patch
new file mode 100644
index 0000000000..057341c026
--- /dev/null
+++ b/community/h2o/increasewaitforserverstartintests.patch
@@ -0,0 +1,14 @@
1Upstream: No
2Reason: Without this patch some tests fail as the server is not fully started,
3issue only present on Alpine running in docker
4--- a/t/Util.pm
5+++ b/t/Util.pm
6@@ -125,7 +125,7 @@
7 if (waitpid($pid, WNOHANG) == $pid) {
8 die "server failed to start (got $?)\n";
9 }
10- sleep 0.1;
11+ sleep 3;
12 }
13 }
14 my $guard = scope_guard(sub {
diff --git a/community/h2o/largeheadertest.patch b/community/h2o/largeheadertest.patch
new file mode 100644
index 0000000000..3c3770b522
--- /dev/null
+++ b/community/h2o/largeheadertest.patch
@@ -0,0 +1,19 @@
1Upstream: No
2Reason: Without this patch tests using curl for large http headers fail, issue not present with curl on other distro's
3Url: https://lists.alpinelinux.org/~alpine/users/%3CCAG5E%3DNdf%3Dc1+Hwt2rY%3DK-kJTtWuMHLnitDoCLrCKkp7n5ksD6w%40mail.gmail.com%3E
4--- a/t/50fastcgi.t
5+++ b/t/50fastcgi.t
6@@ -66,7 +66,12 @@
7 my ($proto, $port, $curl) = @_;
8 plan skip_all => "skip due to curl bug #659"
9 if $curl =~ /--http2/;
10- my $content = `$curl --silent --show-error -H foo:@{["0123456789"x7000]} $proto://127.0.0.1:$port/echo-headers`;
11+ my $content;
12+ if ($curl =~ /--http1.1/) {
13+ $content = `wget --no-check-certificate -O - --header="foo:@{["0123456789"x7000]}" https://127.0.0.1:$port/echo-headers`;
14+ } else {
15+ $content = `$curl --silent --show-error -H foo:@{["0123456789"x7000]} $proto://127.0.0.1:$port/echo-headers`;
16+ }
17 like $content, qr/^foo: (0123456789){7000,7000}$/mi;
18 if ($proto eq 'https') {
19 like $content, qr/^https: on$/m;
diff --git a/community/h2o/missingsubmodules.patch b/community/h2o/missingsubmodules.patch
new file mode 100644
index 0000000000..85063bbcc9
--- /dev/null
+++ b/community/h2o/missingsubmodules.patch
@@ -0,0 +1,503 @@
1Upstream: Yes
2Reason: Without this patch certain tests are failing as these files are dependencies for tests
3Url: https://github.com/h2o/h2o/issues/2329
4--- /dev/null
5+++ b/misc/cache-digest/cache-digest.js
6@@ -0,0 +1,247 @@
7+/*
8+ * Copyright (c) 2015,2016 Jxck, DeNA Co., Ltd., Kazuho Oku
9+ *
10+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11+ * of this software and associated documentation files (the "Software"), to
12+ * deal in the Software without restriction, including without limitation the
13+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14+ * sell copies of the Software, and to permit persons to whom the Software is
15+ * furnished to do so, subject to the following conditions:
16+ *
17+ * The above copyright notice and this permission notice shall be included in
18+ * all copies or substantial portions of the Software.
19+ *
20+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26+ * IN THE SOFTWARE.
27+ *
28+ *
29+ * Includes a minified SHA256 implementation taken from https://gist.github.com/kazuho/bb8aab1a2946bbf42127d8a6197ad18c,
30+ * licensed under the following copyright:
31+ *
32+ * Copyright (c) 2015,2016 Chen Yi-Cyuan, Kazuho Oku
33+ *
34+ * MIT License
35+ *
36+ * Permission is hereby granted, free of charge, to any person obtaining a copy
37+ * of this software and associated documentation files (the "Software"), to
38+ * deal in the Software without restriction, including without limitation the
39+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
40+ * sell copies of the Software, and to permit persons to whom the Software is
41+ * furnished to do so, subject to the following conditions:
42+ *
43+ * The above copyright notice and this permission notice shall be included in
44+ * all copies or substantial portions of the Software.
45+ *
46+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
51+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
52+ * IN THE SOFTWARE.
53+ */
54+"use strict";
55+
56+if (typeof self !== "undefined" && "ServiceWorkerGlobalScope" in self &&
57+ self instanceof ServiceWorkerGlobalScope) {
58+
59+ /* ServiceWorker */
60+ self.addEventListener('fetch', function(evt) {
61+ var req = evt.request.clone();
62+ if (req.method != "GET" || req.url.match(/\/cache-digests?\.js(?:\?|$)/)) {
63+ logInfo(req, "skip");
64+ return;
65+ }
66+ evt.respondWith(caches.open("v1").then(function (cache) {
67+ return cache.match(req).then(function (res) {
68+ if (res && isFresh(res.headers.entries(), Date.now())) {
69+ logInfo(req, "hit");
70+ return res;
71+ }
72+ var requestWithDigests = function (digests) {
73+ if (digests != null) {
74+ var err = null;
75+ try {
76+ req = new Request(req);
77+ req.headers.append("cache-digest", digests);
78+ if (req.headers.get("cache-digest") == null)
79+ err = "append failed";
80+ } catch (e) {
81+ err = e;
82+ }
83+ if (err)
84+ logError(req, e);
85+ }
86+ return fetch(req).then(function (res) {
87+ var cached = false;
88+ if (res.status == 200 && isFresh(res.headers.entries(), Date.now())) {
89+ cache.put(req, res.clone());
90+ cached = true;
91+ }
92+ logInfo(req, "fetched" + (cached ? " & cached" : "") + " with cache-digest:\"" + digests + "\"");
93+ return res;
94+ });
95+ };
96+ if (req.mode == "navigate") {
97+ return generateCacheDigests(cache).then(requestWithDigests);
98+ } else {
99+ return requestWithDigests(null);
100+ }
101+ });
102+ }));
103+ });
104+
105+} else if (typeof navigator !== "undefined") {
106+
107+ /* bootstrap, loaded via <script src=...> */
108+ navigator.serviceWorker.register("/cache-digest.js", {scope: "./"}).then(function(reg) {
109+ console.log("registered cache-digest.js service worker");
110+ }).catch(function(e) {
111+ console.log("failed to register cache-digest.js service worker:" + e);
112+ });
113+
114+}
115+
116+// returns a promise that returns the cache digest value
117+function generateCacheDigests(cache) {
118+ var urls = [];
119+ return cache.keys().then(function (reqs) {
120+ // collect 31-bit hashes of fresh responses
121+ return Promise.all(reqs.map(function (req) {
122+ var now = Date.now();
123+ return cache.match(req).then(function (resp) {
124+ if (resp && isFresh(resp.headers.entries(), now))
125+ urls.push(req.url);
126+ });
127+ })).then(function () {
128+ var dv = calcDigestValue(urls, 7);
129+ return dv != null ? base64Encode(dv) + "; complete" : null;
130+ });
131+ });
132+}
133+
134+function calcDigestValue(urls, pbits) {
135+ var nbits = Math.round(Math.log(Math.max(urls.length, 1)) * 1.4426950408889634); // round log2(urls.length)
136+ if (nbits + pbits > 31)
137+ return null;
138+ var hashes = [];
139+ for (var i = 0; i != urls.length; ++i)
140+ hashes.push(sha256Truncated(urls[i], nbits + pbits));
141+ return (new BitCoder).addBits(nbits, 5).addBits(pbits, 5).gcsEncode(hashes, pbits).value;
142+}
143+
144+function isFresh(headers, now) {
145+ var date = 0, maxAge = null;
146+ var o;
147+ while (!(o = headers.next()).done) {
148+ var name = o.value[0], value = o.value[1];
149+ if (name.match(/^expires$/i) != null) {
150+ var parsed = Date.parse(value);
151+ if (parsed && parsed > now)
152+ return true;
153+ } else if (name.match(/^cache-control$/i) != null) {
154+ var directives = value.split(/\s*,\s*/);
155+ for (var i = 0; i != directives.length; ++i) {
156+ var d = directives[i];
157+ if (d.match(/^\s*no-(?:cache|store)\s*$/) != null) {
158+ return false;
159+ } else if (d.match(/^\s*max-age\s*=\s*([0-9]+)/) != null) {
160+ maxAge = Math.min(RegExp.$1, maxAge || Infinity);
161+ }
162+ }
163+ } else if (name.match(/^date$/i) != null) {
164+ date = Date.parse(value);
165+ }
166+ }
167+
168+ if (maxAge != null) {
169+ if (date + maxAge * 1000 > now)
170+ return true;
171+ }
172+
173+ return false;
174+}
175+
176+function BitCoder() {
177+ this.value = [];
178+ this.leftBits = 0;
179+}
180+
181+BitCoder.prototype.addBit = function (b) {
182+ if (this.leftBits == 0) {
183+ this.value.push(0);
184+ this.leftBits = 8;
185+ }
186+ --this.leftBits;
187+ if (b)
188+ this.value[this.value.length - 1] |= 1 << this.leftBits;
189+ return this;
190+};
191+
192+BitCoder.prototype.addBits = function (v, nbits) {
193+ if (nbits != 0) {
194+ do {
195+ --nbits;
196+ this.addBit(v & (1 << nbits));
197+ } while (nbits != 0);
198+ }
199+ return this;
200+};
201+
202+BitCoder.prototype.gcsEncode = function (values, bits_fixed) {
203+ values = values.sort(function (a, b) { return a - b; });
204+ var prev = -1;
205+ for (var i = 0; i != values.length; ++i) {
206+ if (prev == values[i])
207+ continue;
208+ var v = values[i] - prev - 1;
209+ for (var q = v >> bits_fixed; q != 0; --q)
210+ this.addBit(0);
211+ this.addBit(1);
212+ this.addBits(v, bits_fixed);
213+ prev = values[i];
214+ }
215+ return this;
216+};
217+
218+var base64Encode = function (buf) {
219+ var TOKENS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
220+ return function base64Encode(buf) {
221+ var str = '';
222+ for (var pos = 0; pos < buf.length; pos += 3) {
223+ var quad = buf[pos] << 16 | buf[pos + 1] << 8 | buf[pos + 2];
224+ str += TOKENS[(quad >> 18)] + TOKENS[(quad >> 12) & 63] + TOKENS[(quad >> 6) & 63] + TOKENS[quad & 63];
225+ }
226+ str = str.substring(0, str.length - pos + buf.length);
227+ return str;
228+ };
229+}();
230+
231+function sha256Truncated(src, bits) {
232+ // only supports bits <= 31
233+ return ((sha256(src)[0] >> 1) & 0x7fffffff) >> (31 - bits);
234+}
235+
236+var sha256=function(){var r=[-2147483648,8388608,32768,128],o=[24,16,8,0],a=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];return function(n){var t,e,f,h,c,u,v,d,i,l,A,C,g,s=[],w=!0,b=!1,j=0,k=0,m=0,p=n.length,q=1779033703,x=3144134277,y=1013904242,z=2773480762,B=1359893119,D=2600822924,E=528734635,F=1541459225,G=0;do{for(s[0]=G,s[16]=s[1]=s[2]=s[3]=s[4]=s[5]=s[6]=s[7]=s[8]=s[9]=s[10]=s[11]=s[12]=s[13]=s[14]=s[15]=0,e=k;p>j&&64>e;++j)t=n.charCodeAt(j),128>t?s[e>>2]|=t<<o[3&e++]:2048>t?(s[e>>2]|=(192|t>>6)<<o[3&e++],s[e>>2]|=(128|63&t)<<o[3&e++]):55296>t||t>=57344?(s[e>>2]|=(224|t>>12)<<o[3&e++],s[e>>2]|=(128|t>>6&63)<<o[3&e++],s[e>>2]|=(128|63&t)<<o[3&e++]):(t=65536+((1023&t)<<10|1023&n.charCodeAt(++j)),s[e>>2]|=(240|t>>18)<<o[3&e++],s[e>>2]|=(128|t>>12&63)<<o[3&e++],s[e>>2]|=(128|t>>6&63)<<o[3&e++],s[e>>2]|=(128|63&t)<<o[3&e++]);m+=e-k,k=e-64,j==p&&(s[e>>2]|=r[3&e],++j),G=s[16],j>p&&56>e&&(s[15]=m<<3,b=!0);var H=q,I=x,J=y,K=z,L=B,M=D,N=E,O=F;for(f=16;64>f;++f)v=s[f-15],h=(v>>>7|v<<25)^(v>>>18|v<<14)^v>>>3,v=s[f-2],c=(v>>>17|v<<15)^(v>>>19|v<<13)^v>>>10,s[f]=s[f-16]+h+s[f-7]+c<<0;for(g=I&J,f=0;64>f;f+=4)w?(l=704751109,v=s[0]-210244248,O=v-1521486534<<0,K=v+143694565<<0,w=!1):(h=(H>>>2|H<<30)^(H>>>13|H<<19)^(H>>>22|H<<10),c=(L>>>6|L<<26)^(L>>>11|L<<21)^(L>>>25|L<<7),l=H&I,u=l^H&J^g,i=L&M^~L&N,v=O+c+i+a[f]+s[f],d=h+u,O=K+v<<0,K=v+d<<0),h=(K>>>2|K<<30)^(K>>>13|K<<19)^(K>>>22|K<<10),c=(O>>>6|O<<26)^(O>>>11|O<<21)^(O>>>25|O<<7),A=K&H,u=A^K&I^l,i=O&L^~O&M,v=N+c+i+a[f+1]+s[f+1],d=h+u,N=J+v<<0,J=v+d<<0,h=(J>>>2|J<<30)^(J>>>13|J<<19)^(J>>>22|J<<10),c=(N>>>6|N<<26)^(N>>>11|N<<21)^(N>>>25|N<<7),C=J&K,u=C^J&H^A,i=N&O^~N&L,v=M+c+i+a[f+2]+s[f+2],d=h+u,M=I+v<<0,I=v+d<<0,h=(I>>>2|I<<30)^(I>>>13|I<<19)^(I>>>22|I<<10),c=(M>>>6|M<<26)^(M>>>11|M<<21)^(M>>>25|M<<7),g=I&J,u=g^I&K^C,i=M&N^~M&O,v=L+c+i+a[f+3]+s[f+3],d=h+u,L=H+v<<0,H=v+d<<0;q=q+H<<0,x=x+I<<0,y=y+J<<0,z=z+K<<0,B=B+L<<0,D=D+M<<0,E=E+N<<0,F=F+O<<0}while(!b);return[q,x,y,z,B,D,E,F]}}();
237+
238+function logRequest(req) {
239+ var s = req.method + " " + req.url + "\n";
240+ var o;
241+ for (var iter = req.headers.entries(); !(o = iter.next()).done;)
242+ s += o.value[0] + ": " + o.value[1] + "\n";
243+ console.log(s);
244+}
245+function logError(req, msg) {
246+ console.log(req.url + ":error:" + msg);
247+}
248+function logInfo(req, msg) {
249+ console.log(req.url + ":info:" + msg);
250+}
251+function logDebug(req, msg) {
252+ console.log(req.url + ":debug:" + msg);
253+}
254--- /dev/null
255+++ b/misc/cache-digest/cli.js
256@@ -0,0 +1,247 @@
257+/*
258+ * Copyright (c) 2015,2016 Jxck, DeNA Co., Ltd., Kazuho Oku
259+ *
260+ * Permission is hereby granted, free of charge, to any person obtaining a copy
261+ * of this software and associated documentation files (the "Software"), to
262+ * deal in the Software without restriction, including without limitation the
263+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
264+ * sell copies of the Software, and to permit persons to whom the Software is
265+ * furnished to do so, subject to the following conditions:
266+ *
267+ * The above copyright notice and this permission notice shall be included in
268+ * all copies or substantial portions of the Software.
269+ *
270+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
271+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
272+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
273+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
274+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
275+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
276+ * IN THE SOFTWARE.
277+ *
278+ *
279+ * Includes a minified SHA256 implementation taken from https://gist.github.com/kazuho/bb8aab1a2946bbf42127d8a6197ad18c,
280+ * licensed under the following copyright:
281+ *
282+ * Copyright (c) 2015,2016 Chen Yi-Cyuan, Kazuho Oku
283+ *
284+ * MIT License
285+ *
286+ * Permission is hereby granted, free of charge, to any person obtaining a copy
287+ * of this software and associated documentation files (the "Software"), to
288+ * deal in the Software without restriction, including without limitation the
289+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
290+ * sell copies of the Software, and to permit persons to whom the Software is
291+ * furnished to do so, subject to the following conditions:
292+ *
293+ * The above copyright notice and this permission notice shall be included in
294+ * all copies or substantial portions of the Software.
295+ *
296+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
297+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
298+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
299+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
300+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
301+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
302+ * IN THE SOFTWARE.
303+ */
304+"use strict";
305+
306+if (typeof self !== "undefined" && "ServiceWorkerGlobalScope" in self &&
307+ self instanceof ServiceWorkerGlobalScope) {
308+
309+ /* ServiceWorker */
310+ self.addEventListener('fetch', function(evt) {
311+ var req = evt.request.clone();
312+ if (req.method != "GET" || req.url.match(/\/cache-digests?\.js(?:\?|$)/)) {
313+ logInfo(req, "skip");
314+ return;
315+ }
316+ evt.respondWith(caches.open("v1").then(function (cache) {
317+ return cache.match(req).then(function (res) {
318+ if (res && isFresh(res.headers.entries(), Date.now())) {
319+ logInfo(req, "hit");
320+ return res;
321+ }
322+ var requestWithDigests = function (digests) {
323+ if (digests != null) {
324+ var err = null;
325+ try {
326+ req = new Request(req);
327+ req.headers.append("cache-digest", digests);
328+ if (req.headers.get("cache-digest") == null)
329+ err = "append failed";
330+ } catch (e) {
331+ err = e;
332+ }
333+ if (err)
334+ logError(req, e);
335+ }
336+ return fetch(req).then(function (res) {
337+ var cached = false;
338+ if (res.status == 200 && isFresh(res.headers.entries(), Date.now())) {
339+ cache.put(req, res.clone());
340+ cached = true;
341+ }
342+ logInfo(req, "fetched" + (cached ? " & cached" : "") + " with cache-digest:\"" + digests + "\"");
343+ return res;
344+ });
345+ };
346+ if (req.mode == "navigate") {
347+ return generateCacheDigests(cache).then(requestWithDigests);
348+ } else {
349+ return requestWithDigests(null);
350+ }
351+ });
352+ }));
353+ });
354+
355+} else if (typeof navigator !== "undefined") {
356+
357+ /* bootstrap, loaded via <script src=...> */
358+ navigator.serviceWorker.register("/cache-digest.js", {scope: "./"}).then(function(reg) {
359+ console.log("registered cache-digest.js service worker");
360+ }).catch(function(e) {
361+ console.log("failed to register cache-digest.js service worker:" + e);
362+ });
363+
364+}
365+
366+// returns a promise that returns the cache digest value
367+function generateCacheDigests(cache) {
368+ var urls = [];
369+ return cache.keys().then(function (reqs) {
370+ // collect 31-bit hashes of fresh responses
371+ return Promise.all(reqs.map(function (req) {
372+ var now = Date.now();
373+ return cache.match(req).then(function (resp) {
374+ if (resp && isFresh(resp.headers.entries(), now))
375+ urls.push(req.url);
376+ });
377+ })).then(function () {
378+ var dv = calcDigestValue(urls, 7);
379+ return dv != null ? base64Encode(dv) + "; complete" : null;
380+ });
381+ });
382+}
383+
384+function calcDigestValue(urls, pbits) {
385+ var nbits = Math.round(Math.log(Math.max(urls.length, 1)) * 1.4426950408889634); // round log2(urls.length)
386+ if (nbits + pbits > 31)
387+ return null;
388+ var hashes = [];
389+ for (var i = 0; i != urls.length; ++i)
390+ hashes.push(sha256Truncated(urls[i], nbits + pbits));
391+ return (new BitCoder).addBits(nbits, 5).addBits(pbits, 5).gcsEncode(hashes, pbits).value;
392+}
393+
394+function isFresh(headers, now) {
395+ var date = 0, maxAge = null;
396+ var o;
397+ while (!(o = headers.next()).done) {
398+ var name = o.value[0], value = o.value[1];
399+ if (name.match(/^expires$/i) != null) {
400+ var parsed = Date.parse(value);
401+ if (parsed && parsed > now)
402+ return true;
403+ } else if (name.match(/^cache-control$/i) != null) {
404+ var directives = value.split(/\s*,\s*/);
405+ for (var i = 0; i != directives.length; ++i) {
406+ var d = directives[i];
407+ if (d.match(/^\s*no-(?:cache|store)\s*$/) != null) {
408+ return false;
409+ } else if (d.match(/^\s*max-age\s*=\s*([0-9]+)/) != null) {
410+ maxAge = Math.min(RegExp.$1, maxAge || Infinity);
411+ }
412+ }
413+ } else if (name.match(/^date$/i) != null) {
414+ date = Date.parse(value);
415+ }
416+ }
417+
418+ if (maxAge != null) {
419+ if (date + maxAge * 1000 > now)
420+ return true;
421+ }
422+
423+ return false;
424+}
425+
426+function BitCoder() {
427+ this.value = [];
428+ this.leftBits = 0;
429+}
430+
431+BitCoder.prototype.addBit = function (b) {
432+ if (this.leftBits == 0) {
433+ this.value.push(0);
434+ this.leftBits = 8;
435+ }
436+ --this.leftBits;
437+ if (b)
438+ this.value[this.value.length - 1] |= 1 << this.leftBits;
439+ return this;
440+};
441+
442+BitCoder.prototype.addBits = function (v, nbits) {
443+ if (nbits != 0) {
444+ do {
445+ --nbits;
446+ this.addBit(v & (1 << nbits));
447+ } while (nbits != 0);
448+ }
449+ return this;
450+};
451+
452+BitCoder.prototype.gcsEncode = function (values, bits_fixed) {
453+ values = values.sort(function (a, b) { return a - b; });
454+ var prev = -1;
455+ for (var i = 0; i != values.length; ++i) {
456+ if (prev == values[i])
457+ continue;
458+ var v = values[i] - prev - 1;
459+ for (var q = v >> bits_fixed; q != 0; --q)
460+ this.addBit(0);
461+ this.addBit(1);
462+ this.addBits(v, bits_fixed);
463+ prev = values[i];
464+ }
465+ return this;
466+};
467+
468+var base64Encode = function (buf) {
469+ var TOKENS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
470+ return function base64Encode(buf) {
471+ var str = '';
472+ for (var pos = 0; pos < buf.length; pos += 3) {
473+ var quad = buf[pos] << 16 | buf[pos + 1] << 8 | buf[pos + 2];
474+ str += TOKENS[(quad >> 18)] + TOKENS[(quad >> 12) & 63] + TOKENS[(quad >> 6) & 63] + TOKENS[quad & 63];
475+ }
476+ str = str.substring(0, str.length - pos + buf.length);
477+ return str;
478+ };
479+}();
480+
481+function sha256Truncated(src, bits) {
482+ // only supports bits <= 31
483+ return ((sha256(src)[0] >> 1) & 0x7fffffff) >> (31 - bits);
484+}
485+
486+var sha256=function(){var r=[-2147483648,8388608,32768,128],o=[24,16,8,0],a=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];return function(n){var t,e,f,h,c,u,v,d,i,l,A,C,g,s=[],w=!0,b=!1,j=0,k=0,m=0,p=n.length,q=1779033703,x=3144134277,y=1013904242,z=2773480762,B=1359893119,D=2600822924,E=528734635,F=1541459225,G=0;do{for(s[0]=G,s[16]=s[1]=s[2]=s[3]=s[4]=s[5]=s[6]=s[7]=s[8]=s[9]=s[10]=s[11]=s[12]=s[13]=s[14]=s[15]=0,e=k;p>j&&64>e;++j)t=n.charCodeAt(j),128>t?s[e>>2]|=t<<o[3&e++]:2048>t?(s[e>>2]|=(192|t>>6)<<o[3&e++],s[e>>2]|=(128|63&t)<<o[3&e++]):55296>t||t>=57344?(s[e>>2]|=(224|t>>12)<<o[3&e++],s[e>>2]|=(128|t>>6&63)<<o[3&e++],s[e>>2]|=(128|63&t)<<o[3&e++]):(t=65536+((1023&t)<<10|1023&n.charCodeAt(++j)),s[e>>2]|=(240|t>>18)<<o[3&e++],s[e>>2]|=(128|t>>12&63)<<o[3&e++],s[e>>2]|=(128|t>>6&63)<<o[3&e++],s[e>>2]|=(128|63&t)<<o[3&e++]);m+=e-k,k=e-64,j==p&&(s[e>>2]|=r[3&e],++j),G=s[16],j>p&&56>e&&(s[15]=m<<3,b=!0);var H=q,I=x,J=y,K=z,L=B,M=D,N=E,O=F;for(f=16;64>f;++f)v=s[f-15],h=(v>>>7|v<<25)^(v>>>18|v<<14)^v>>>3,v=s[f-2],c=(v>>>17|v<<15)^(v>>>19|v<<13)^v>>>10,s[f]=s[f-16]+h+s[f-7]+c<<0;for(g=I&J,f=0;64>f;f+=4)w?(l=704751109,v=s[0]-210244248,O=v-1521486534<<0,K=v+143694565<<0,w=!1):(h=(H>>>2|H<<30)^(H>>>13|H<<19)^(H>>>22|H<<10),c=(L>>>6|L<<26)^(L>>>11|L<<21)^(L>>>25|L<<7),l=H&I,u=l^H&J^g,i=L&M^~L&N,v=O+c+i+a[f]+s[f],d=h+u,O=K+v<<0,K=v+d<<0),h=(K>>>2|K<<30)^(K>>>13|K<<19)^(K>>>22|K<<10),c=(O>>>6|O<<26)^(O>>>11|O<<21)^(O>>>25|O<<7),A=K&H,u=A^K&I^l,i=O&L^~O&M,v=N+c+i+a[f+1]+s[f+1],d=h+u,N=J+v<<0,J=v+d<<0,h=(J>>>2|J<<30)^(J>>>13|J<<19)^(J>>>22|J<<10),c=(N>>>6|N<<26)^(N>>>11|N<<21)^(N>>>25|N<<7),C=J&K,u=C^J&H^A,i=N&O^~N&L,v=M+c+i+a[f+2]+s[f+2],d=h+u,M=I+v<<0,I=v+d<<0,h=(I>>>2|I<<30)^(I>>>13|I<<19)^(I>>>22|I<<10),c=(M>>>6|M<<26)^(M>>>11|M<<21)^(M>>>25|M<<7),g=I&J,u=g^I&K^C,i=M&N^~M&O,v=L+c+i+a[f+3]+s[f+3],d=h+u,L=H+v<<0,H=v+d<<0;q=q+H<<0,x=x+I<<0,y=y+J<<0,z=z+K<<0,B=B+L<<0,D=D+M<<0,E=E+N<<0,F=F+O<<0}while(!b);return[q,x,y,z,B,D,E,F]}}();
487+
488+function logRequest(req) {
489+ var s = req.method + " " + req.url + "\n";
490+ var o;
491+ for (var iter = req.headers.entries(); !(o = iter.next()).done;)
492+ s += o.value[0] + ": " + o.value[1] + "\n";
493+ console.log(s);
494+}
495+function logError(req, msg) {
496+ console.log(req.url + ":error:" + msg);
497+}
498+function logInfo(req, msg) {
499+ console.log(req.url + ":info:" + msg);
500+}
501+function logDebug(req, msg) {
502+ console.log(req.url + ":debug:" + msg);
503+}
diff --git a/community/h2o/proxysessionresumption.patch b/community/h2o/proxysessionresumption.patch
new file mode 100644
index 0000000000..c7d45336a7
--- /dev/null
+++ b/community/h2o/proxysessionresumption.patch
@@ -0,0 +1,134 @@
1Upstream: Yes
2Reason: Without this patch proxy ssl session resumptions fails
3Url: https://github.com/h2o/h2o/pull/2088
4--- a/include/h2o/socket.h
5+++ b/include/h2o/socket.h
6@@ -71,6 +71,9 @@
7
8 #define H2O_SOCKET_INITIAL_INPUT_BUFFER_SIZE 4096
9
10+#define H2O_SESSID_CTX ((const uint8_t*)"h2o")
11+#define H2O_SESSID_CTX_LEN (sizeof("h2o") - 1)
12+
13 typedef struct st_h2o_socket_t h2o_socket_t;
14
15 typedef void (*h2o_socket_cb)(h2o_socket_t *sock, const char *err);
16@@ -266,6 +269,7 @@
17 static h2o_iovec_t h2o_socket_log_ssl_cipher(h2o_socket_t *sock, h2o_mem_pool_t *pool);
18 h2o_iovec_t h2o_socket_log_ssl_cipher_bits(h2o_socket_t *sock, h2o_mem_pool_t *pool);
19 h2o_iovec_t h2o_socket_log_ssl_session_id(h2o_socket_t *sock, h2o_mem_pool_t *pool);
20+int h2o_socket_ssl_new_session_cb(SSL *s, SSL_SESSION *sess);
21
22 /**
23 * compares socket addresses
24--- a/lib/common/socket.c
25+++ b/lib/common/socket.c
26@@ -916,6 +916,8 @@
27 static void create_ossl(h2o_socket_t *sock)
28 {
29 sock->ssl->ossl = SSL_new(sock->ssl->ssl_ctx);
30+ /* set app data to be used in h2o_socket_ssl_new_session_cb */
31+ SSL_set_app_data(sock->ssl->ossl, sock);
32 setup_bio(sock);
33 }
34
35@@ -942,6 +944,26 @@
36 }
37 }
38
39+int h2o_socket_ssl_new_session_cb(SSL *s, SSL_SESSION *sess)
40+{
41+ h2o_socket_t *sock = (h2o_socket_t *)SSL_get_app_data(s);
42+ assert(sock != NULL);
43+ assert(sock->ssl != NULL);
44+
45+ if (!SSL_is_server(s) && sock->ssl->handshake.client.session_cache != NULL
46+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1010100fL
47+ && SSL_SESSION_is_resumable(sess)
48+#endif
49+ ) {
50+ h2o_cache_set(sock->ssl->handshake.client.session_cache, h2o_now(h2o_socket_get_loop(sock)),
51+ sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash,
52+ h2o_iovec_init(sess, 1));
53+ return 1; /* retain ref count */
54+ }
55+
56+ return 0; /* drop ref count */
57+}
58+
59 static int on_async_resumption_new(SSL *ssl, SSL_SESSION *session)
60 {
61 h2o_iovec_t data;
62@@ -992,16 +1014,6 @@
63 sock->ssl->record_overhead = 32; /* sufficiently large number that can hold most payloads */
64 break;
65 }
66- }
67- }
68-
69- /* set ssl session into the cache */
70- if (sock->ssl->ossl != NULL && !SSL_is_server(sock->ssl->ossl) && sock->ssl->handshake.client.session_cache != NULL) {
71- if (err == NULL || err == h2o_socket_error_ssl_cert_name_mismatch) {
72- SSL_SESSION *session = SSL_get1_session(sock->ssl->ossl);
73- h2o_cache_set(sock->ssl->handshake.client.session_cache, h2o_now(h2o_socket_get_loop(sock)),
74- sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash,
75- h2o_iovec_init(session, 1));
76 }
77 }
78
79--- a/lib/handler/configurator/proxy.c
80+++ b/lib/handler/configurator/proxy.c
81@@ -27,6 +27,7 @@
82 #include <openssl/ssl.h>
83 #include "h2o.h"
84 #include "h2o/configurator.h"
85+#include "h2o/socket.h"
86
87 struct proxy_configurator_t {
88 h2o_configurator_t super;
89@@ -86,6 +87,9 @@
90 {
91 SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
92 SSL_CTX_set_options(ctx, SSL_CTX_get_options(ctx) | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
93+ SSL_CTX_set_session_id_context(ctx, H2O_SESSID_CTX, H2O_SESSID_CTX_LEN);
94+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);
95+ SSL_CTX_sess_set_new_cb(ctx, h2o_socket_ssl_new_session_cb);
96 return ctx;
97 }
98
99@@ -119,6 +123,7 @@
100
101 /* create new ctx */
102 *ctx = create_ssl_ctx();
103+ SSL_CTX_set_session_id_context(*ctx, H2O_SESSID_CTX, H2O_SESSID_CTX_LEN);
104 SSL_CTX_set_cert_store(*ctx, cert_store);
105 SSL_CTX_set_verify(*ctx, verify_mode, NULL);
106 if (new_session_cache != NULL)
107--- a/src/main.c
108+++ b/src/main.c
109@@ -674,9 +674,15 @@
110 ssl_options |= SSL_OP_NO_COMPRESSION;
111 #endif
112
113+#ifdef SSL_OP_NO_RENEGOTIATION
114+ ssl_options |= SSL_OP_NO_RENEGOTIATION;
115+#endif
116+
117 /* setup */
118 ssl_ctx = SSL_CTX_new(SSLv23_server_method());
119 SSL_CTX_set_options(ssl_ctx, ssl_options);
120+
121+ SSL_CTX_set_session_id_context(ssl_ctx, H2O_SESSID_CTX, H2O_SESSID_CTX_LEN);
122
123 setup_ecc_key(ssl_ctx);
124 if (SSL_CTX_use_certificate_chain_file(ssl_ctx, certificate_file->data.scalar) != 1) {
125--- a/src/ssl.c
126+++ b/src/ssl.c
127@@ -116,6 +116,7 @@
128 size_t i;
129 for (i = 0; i != num_contexts; ++i) {
130 SSL_CTX_set_session_cache_mode(contexts[i], SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR);
131+ SSL_CTX_set_session_id_context(contexts[i], H2O_SESSID_CTX, H2O_SESSID_CTX_LEN);
132 SSL_CTX_set_timeout(contexts[i], conf.lifetime);
133 }
134 spawn_cache_cleanup_thread(contexts, num_contexts);
diff --git a/community/h2o/sessiontickettest.patch b/community/h2o/sessiontickettest.patch
new file mode 100644
index 0000000000..86ea5ba4ca
--- /dev/null
+++ b/community/h2o/sessiontickettest.patch
@@ -0,0 +1,140 @@
1Upstream: Yes
2Reason: Without this patch the session ticket test fails
3Url: https://github.com/h2o/h2o/pull/2334
4--- a/t/40session-ticket.t
5+++ b/t/40session-ticket.t
6@@ -3,6 +3,7 @@
7 use File::Temp qw(tempdir);
8 use Net::EmptyPort qw(check_port empty_port);
9 use Test::More;
10+use Time::HiRes qw(sleep);
11 use t::Util;
12
13 plan skip_all => "could not find openssl"
14@@ -17,16 +18,16 @@
15 mode: ticket
16 EOT
17 sub {
18- is test(), "New";
19- test(); # openssl 0.9.8 seems to return "New" (maybe because in the first run we did not specify -sess_in)
20- is test(), "Reused";
21- is test(), "Reused";
22+ sleep 5;
23+ is test("new"), "New";
24+ is test("reuse"), "Reused";
25+ is test("reuse"), "Reused";
26 });
27 spawn_with(<< "EOT",
28 mode: ticket
29 EOT
30 sub {
31- is test(), "New";
32+ is test("reuse"), "New";
33 });
34 };
35
36@@ -36,11 +37,13 @@
37 mode: ticket
38 ticket-store: file
39 ticket-file: $tickets_file
40+num-threads: 1
41 EOT
42 sub {
43- is test(), "New";
44- is test(), "Reused";
45- is test(), "Reused";
46+ sleep 5; # wait for tickets file to be loaded
47+ is test("new"), "New";
48+ is test("reuse"), "Reused";
49+ is test("reuse"), "Reused";
50 });
51 spawn_with(<< "EOT",
52 mode: ticket
53@@ -48,8 +51,8 @@
54 ticket-file: $tickets_file
55 EOT
56 sub {
57- sleep 1;
58- is test(), "Reused";
59+ sleep 5; # wait for tickets file to be loaded
60+ is test("reuse"), "Reused";
61 });
62 };
63
64@@ -59,11 +62,13 @@
65 mode: ticket
66 ticket-store: file
67 ticket-file: $tickets_file
68+num-threads: 1
69 EOT
70 sub {
71- is test(), "New";
72- is test(), "New";
73- is test(), "New";
74+ sleep 5; # wait for tickets file to be loaded
75+ is test("new"), "New";
76+ is test("reuse"), "New";
77+ is test("reuse"), "New";
78 });
79 };
80
81@@ -86,15 +91,17 @@
82 host: 127.0.0.1
83 port: $memc_port
84 protocol: $memc_proto
85+num-threads: 1
86 EOT
87 spawn_with($conf, sub {
88- is test(), "New";
89- is test(), "Reused";
90- is test(), "Reused";
91+ sleep 5;
92+ is test("new"), "New";
93+ is test("reuse"), "Reused";
94+ is test("reuse"), "Reused";
95 });
96 spawn_with($conf, sub {
97- sleep 1;
98- is test(), "Reused";
99+ sleep 5;
100+ is test("reuse"), "Reused";
101 });
102 };
103 $doit->("binary");
104@@ -120,14 +127,33 @@
105 }
106
107 sub test {
108+ my $sess_mode = shift @_; # reuse or new
109+
110+ # 'openssl -sess_out' writes a session file ONLY if
111+ # a session was handed out by the server!
112+
113+ my $cmd_opts;
114+ if ( $sess_mode eq 'new' ) {
115+ unlink "$tempdir/session";
116+ $cmd_opts = "-sess_out $tempdir/session";
117+ } else {
118+ return "no session to reuse $tempdir/session does no exist" unless ( -e "$tempdir/session" );
119+ $cmd_opts = "-sess_in $tempdir/session";
120+ }
121+
122 my $lines = do {
123- my $cmd_opts = (-e "$tempdir/session" ? "-sess_in $tempdir/session" : "") . " -sess_out $tempdir/session";
124- open my $fh, "-|", "openssl s_client $cmd_opts -connect 127.0.0.1:$server->{tls_port} 2>&1 < /dev/null"
125+ open my $fh, "-|", "openssl s_client $cmd_opts -prexit -servername 127.0.0.1 -connect 127.0.0.1:$server->{tls_port} -tls1_2 2>&1"
126 or die "failed to open pipe:$!";
127 local $/;
128 <$fh>;
129 };
130+ print $lines;
131 $lines =~ m{---\n(New|Reused),}s
132 or die "failed to parse the output of s_client:{{{$lines}}}";
133- $1;
134+
135+ if ( $sess_mode eq 'new' ) {
136+ -e "$tempdir/session" ? $1 : "no session created $tempdir/session does no exist";
137+ } else {
138+ $1;
139+ }
140 }
diff --git a/testing/perl-http-entity-parser/APKBUILD b/community/perl-http-entity-parser/APKBUILD
index f5541a00ab..f5541a00ab 100644
--- a/testing/perl-http-entity-parser/APKBUILD
+++ b/community/perl-http-entity-parser/APKBUILD
diff --git a/testing/perl-http-multipartparser/APKBUILD b/community/perl-http-multipartparser/APKBUILD
index 262cd14b43..262cd14b43 100644
--- a/testing/perl-http-multipartparser/APKBUILD
+++ b/community/perl-http-multipartparser/APKBUILD
diff --git a/testing/perl-protocol-http2/APKBUILD b/community/perl-protocol-http2/APKBUILD
index 11bd53dd6c..11bd53dd6c 100644
--- a/testing/perl-protocol-http2/APKBUILD
+++ b/community/perl-protocol-http2/APKBUILD
diff --git a/testing/perl-www-form-urlencoded/APKBUILD b/community/perl-www-form-urlencoded/APKBUILD
index 57ab9bb2d3..57ab9bb2d3 100644
--- a/testing/perl-www-form-urlencoded/APKBUILD
+++ b/community/perl-www-form-urlencoded/APKBUILD