h1p 0.6.1 → 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -3
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +5 -5
- data/LICENSE +1 -1
- data/ext/h1p/h1p.c +46 -17
- data/h1p.gemspec +3 -3
- data/lib/h1p/version.rb +1 -1
- data/test/test_h1p.rb +9 -1
- data/test/test_h1p_server.rb +12 -2
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33974d5940b6a9ad9282df7d946486a1ee265ed67e2d5004bbe3e3572c4233db
|
4
|
+
data.tar.gz: a0b175ce9eb77d83457376902ab71cf597eedc41009c6094564e8de20e8532f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8826e6c0039d1721ba0d662fb542a19ed9349bdc0ec6aadc976b172266284955c0d6784da9b1d1b9d8e5ef76181cc8b1299eb2164ab1b56817899e66ae1ec53
|
7
|
+
data.tar.gz: 6d9343d65ffc31dadaa7fd9a01e5221d183a830d7d79fa82d79381832160ad1c342ffa6f1a4892f8aad78f7f1adde161517b79f571fdb5efc098cc4e55c99781
|
data/.github/workflows/test.yml
CHANGED
@@ -8,7 +8,7 @@ jobs:
|
|
8
8
|
fail-fast: false
|
9
9
|
matrix:
|
10
10
|
os: [ubuntu-latest]
|
11
|
-
ruby: [
|
11
|
+
ruby: ['3.0', '3.1', '3.2', 'head']
|
12
12
|
|
13
13
|
name: >-
|
14
14
|
${{matrix.os}}, ${{matrix.ruby}}
|
@@ -24,8 +24,6 @@ jobs:
|
|
24
24
|
run: |
|
25
25
|
gem install bundler
|
26
26
|
bundle install
|
27
|
-
- name: Show Linux kernel version
|
28
|
-
run: uname -r
|
29
27
|
- name: Compile C-extension
|
30
28
|
run: bundle exec rake compile
|
31
29
|
- name: Run tests
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
h1p (
|
4
|
+
h1p (1.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
minitest (5.
|
9
|
+
minitest (5.18.0)
|
10
10
|
rake (13.0.6)
|
11
|
-
rake-compiler (1.2.
|
11
|
+
rake-compiler (1.2.3)
|
12
12
|
rake
|
13
13
|
|
14
14
|
PLATFORMS
|
@@ -16,9 +16,9 @@ PLATFORMS
|
|
16
16
|
|
17
17
|
DEPENDENCIES
|
18
18
|
h1p!
|
19
|
-
minitest (~> 5.
|
19
|
+
minitest (~> 5.18.0)
|
20
20
|
rake (~> 13.0.6)
|
21
|
-
rake-compiler (= 1.2.
|
21
|
+
rake-compiler (= 1.2.3)
|
22
22
|
|
23
23
|
BUNDLED WITH
|
24
24
|
2.2.26
|
data/LICENSE
CHANGED
data/ext/h1p/h1p.c
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#include <stdnoreturn.h>
|
1
2
|
#include "h1p.h"
|
2
3
|
|
3
4
|
// Security-related limits are defined in limits.rb and injected as
|
@@ -22,6 +23,7 @@ ID ID_call;
|
|
22
23
|
ID ID_downcase;
|
23
24
|
ID ID_eof_p;
|
24
25
|
ID ID_eq;
|
26
|
+
ID ID_join;
|
25
27
|
ID ID_read_method;
|
26
28
|
ID ID_read;
|
27
29
|
ID ID_readpartial;
|
@@ -56,6 +58,7 @@ VALUE STR_transfer_encoding_capitalized;
|
|
56
58
|
|
57
59
|
VALUE STR_CRLF;
|
58
60
|
VALUE STR_EMPTY_CHUNK;
|
61
|
+
VALUE STR_COMMA_SPACE;
|
59
62
|
|
60
63
|
VALUE SYM_backend_read;
|
61
64
|
VALUE SYM_backend_recv;
|
@@ -722,20 +725,7 @@ eof:
|
|
722
725
|
return 0;
|
723
726
|
}
|
724
727
|
|
725
|
-
|
726
|
-
*
|
727
|
-
* Parses headers from the associated IO instance, returning a hash mapping
|
728
|
-
* header keys to their respective values. Header keys are downcased and dashes
|
729
|
-
* are converted to underscores. The returned headers will also include the
|
730
|
-
* following pseudo-headers:
|
731
|
-
*
|
732
|
-
* - `':protocol'` - the protocol as specified in the query line / status line
|
733
|
-
* - `':path'` - the query path (for HTTP requests)
|
734
|
-
* - `':method'` - the HTTP method (for HTTP requests)
|
735
|
-
* - `':status'` - the HTTP status (for HTTP responses)
|
736
|
-
* - `':rx'` - the total number of bytes read by the parser
|
737
|
-
*/
|
738
|
-
VALUE Parser_parse_headers(VALUE self) {
|
728
|
+
VALUE Parser_parse_headers_safe(VALUE self) {
|
739
729
|
Parser_t *parser;
|
740
730
|
GetParser(self, parser);
|
741
731
|
parser->headers = rb_hash_new();
|
@@ -773,6 +763,31 @@ done:
|
|
773
763
|
return parser->headers;
|
774
764
|
}
|
775
765
|
|
766
|
+
noreturn VALUE Parser_parse_headers_rescue(VALUE args, VALUE error) {
|
767
|
+
RAISE_BAD_REQUEST("Invalid character sequences in method or header name");
|
768
|
+
}
|
769
|
+
|
770
|
+
/* call-seq: parser.parse_headers -> headers
|
771
|
+
*
|
772
|
+
* Parses headers from the associated IO instance, returning a hash mapping
|
773
|
+
* header keys to their respective values. Header keys are downcased and dashes
|
774
|
+
* are converted to underscores. The returned headers will also include the
|
775
|
+
* following pseudo-headers:
|
776
|
+
*
|
777
|
+
* - `':protocol'` - the protocol as specified in the query line / status line
|
778
|
+
* - `':path'` - the query path (for HTTP requests)
|
779
|
+
* - `':method'` - the HTTP method (for HTTP requests)
|
780
|
+
* - `':status'` - the HTTP status (for HTTP responses)
|
781
|
+
* - `':rx'` - the total number of bytes read by the parser
|
782
|
+
*/
|
783
|
+
VALUE Parser_parse_headers(VALUE self) {
|
784
|
+
return rb_rescue2(
|
785
|
+
Parser_parse_headers_safe, self,
|
786
|
+
Parser_parse_headers_rescue, self,
|
787
|
+
eArgumentError, (VALUE)0
|
788
|
+
);
|
789
|
+
}
|
790
|
+
|
776
791
|
////////////////////////////////////////////////////////////////////////////////
|
777
792
|
|
778
793
|
static inline int str_to_int(VALUE value, const char *error_msg) {
|
@@ -1176,12 +1191,24 @@ void send_response_write_status_line(send_response_ctx *ctx, VALUE protocol, VAL
|
|
1176
1191
|
ctx->buffer_len += partlen + 2;
|
1177
1192
|
}
|
1178
1193
|
|
1194
|
+
inline static VALUE format_comma_separated_header_values(VALUE array) {
|
1195
|
+
return rb_funcall(array, ID_join, 1, STR_COMMA_SPACE);
|
1196
|
+
}
|
1197
|
+
|
1179
1198
|
int send_response_write_header(VALUE key, VALUE val, VALUE arg) {
|
1180
1199
|
if (TYPE(key) != T_STRING) key = rb_funcall(key, ID_to_s, 0);
|
1181
1200
|
char *keyptr = RSTRING_PTR(key);
|
1182
1201
|
if (RSTRING_LEN(key) < 1 || keyptr[0] == ':') return 0;
|
1183
1202
|
|
1184
|
-
|
1203
|
+
switch (TYPE(val)) {
|
1204
|
+
case T_STRING:
|
1205
|
+
break;
|
1206
|
+
case T_ARRAY:
|
1207
|
+
val = format_comma_separated_header_values(val);
|
1208
|
+
break;
|
1209
|
+
default:
|
1210
|
+
val = rb_funcall(val, ID_to_s, 0);
|
1211
|
+
}
|
1185
1212
|
unsigned int keylen = RSTRING_LEN(key);
|
1186
1213
|
char *valptr = RSTRING_PTR(val);
|
1187
1214
|
unsigned int vallen = RSTRING_LEN(val);
|
@@ -1377,6 +1404,7 @@ void Init_H1P(void) {
|
|
1377
1404
|
ID_downcase = rb_intern("downcase");
|
1378
1405
|
ID_eof_p = rb_intern("eof?");
|
1379
1406
|
ID_eq = rb_intern("==");
|
1407
|
+
ID_join = rb_intern("join");
|
1380
1408
|
ID_read_method = rb_intern("__read_method__");
|
1381
1409
|
ID_read = rb_intern("read");
|
1382
1410
|
ID_readpartial = rb_intern("readpartial");
|
@@ -1405,8 +1433,9 @@ void Init_H1P(void) {
|
|
1405
1433
|
GLOBAL_STR(STR_transfer_encoding, "transfer-encoding");
|
1406
1434
|
GLOBAL_STR(STR_transfer_encoding_capitalized, "Transfer-Encoding");
|
1407
1435
|
|
1408
|
-
GLOBAL_STR(STR_CRLF,
|
1409
|
-
GLOBAL_STR(STR_EMPTY_CHUNK,
|
1436
|
+
GLOBAL_STR(STR_CRLF, "\r\n");
|
1437
|
+
GLOBAL_STR(STR_EMPTY_CHUNK, "0\r\n\r\n");
|
1438
|
+
GLOBAL_STR(STR_COMMA_SPACE, ", ");
|
1410
1439
|
|
1411
1440
|
SYM_backend_read = ID2SYM(ID_backend_read);
|
1412
1441
|
SYM_backend_recv = ID2SYM(ID_backend_recv);
|
data/h1p.gemspec
CHANGED
@@ -16,9 +16,9 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.extra_rdoc_files = ["README.md"]
|
17
17
|
s.extensions = ["ext/h1p/extconf.rb"]
|
18
18
|
s.require_paths = ["lib"]
|
19
|
-
s.required_ruby_version = '>=
|
19
|
+
s.required_ruby_version = '>= 3.0'
|
20
20
|
|
21
|
-
s.add_development_dependency 'rake-compiler', '1.2.
|
21
|
+
s.add_development_dependency 'rake-compiler', '1.2.3'
|
22
22
|
s.add_development_dependency 'rake', '~>13.0.6'
|
23
|
-
s.add_development_dependency 'minitest', '~>5.
|
23
|
+
s.add_development_dependency 'minitest', '~>5.18.0'
|
24
24
|
end
|
data/lib/h1p/version.rb
CHANGED
data/test/test_h1p.rb
CHANGED
@@ -35,6 +35,14 @@ class SendResponseTest < MiniTest::Test
|
|
35
35
|
assert_equal "HTTP/1.1 200 OK\r\nFoo: Bar\r\nX-Blah: 123\r\nContent-Length: 0\r\n\r\n", response
|
36
36
|
end
|
37
37
|
|
38
|
+
def test_send_response_multiple_header_values
|
39
|
+
i, o = IO.pipe
|
40
|
+
H1P.send_response(o, { :Foo => ['Bar', 'Baz'], 'X-Blah' => 123 })
|
41
|
+
o.close
|
42
|
+
response = i.read
|
43
|
+
assert_equal "HTTP/1.1 200 OK\r\nFoo: Bar, Baz\r\nX-Blah: 123\r\nContent-Length: 0\r\n\r\n", response
|
44
|
+
end
|
45
|
+
|
38
46
|
def test_send_response_with_body
|
39
47
|
i, o = IO.pipe
|
40
48
|
H1P.send_response(o, {}, "foobar")
|
@@ -97,7 +105,7 @@ class SendBodyChunkTest < MiniTest::Test
|
|
97
105
|
len = H1P.send_body_chunk(o, chunk)
|
98
106
|
o.close
|
99
107
|
end
|
100
|
-
|
108
|
+
|
101
109
|
response = i.read
|
102
110
|
assert_equal "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n", response
|
103
111
|
assert_equal chunk.bytesize + chunk.bytesize.to_s(16).bytesize + 4, len
|
data/test/test_h1p_server.rb
CHANGED
@@ -88,6 +88,11 @@ class H1PServerTest < MiniTest::Test
|
|
88
88
|
assert_raises(Error) { @parser.parse_headers }
|
89
89
|
end
|
90
90
|
|
91
|
+
def test_invalid_method_string
|
92
|
+
@o << "\x02\x78\x83\x2 / HTTP/1.1\r\n\r\n"
|
93
|
+
assert_raises(Error) { @parser.parse_headers }
|
94
|
+
end
|
95
|
+
|
91
96
|
def test_path_characters
|
92
97
|
@o << "GET /äBçDé¤23~{@€ HTTP/1.1\r\n\r\n"
|
93
98
|
headers = @parser.parse_headers
|
@@ -191,6 +196,11 @@ class H1PServerTest < MiniTest::Test
|
|
191
196
|
assert_equal 'ddd', headers['c']
|
192
197
|
end
|
193
198
|
|
199
|
+
def test_invalid_headers
|
200
|
+
@o << "GET / HTTP/1.1\r\n\foo\x02\x78\x83\x02: bar\n\r\n"
|
201
|
+
assert_raises(Error) { @parser.parse_headers }
|
202
|
+
end
|
203
|
+
|
194
204
|
def test_headers_multiple_values
|
195
205
|
@o << "GET / HTTP/1.1\r\nFoo: Bar\r\nfoo: baz\r\n\r\n"
|
196
206
|
headers = @parser.parse_headers
|
@@ -471,7 +481,7 @@ class H1PServerTest < MiniTest::Test
|
|
471
481
|
@o.close
|
472
482
|
end
|
473
483
|
def w.__write_method__; :backend_write; end
|
474
|
-
|
484
|
+
|
475
485
|
headers = @parser.parse_headers
|
476
486
|
@parser.splice_body_to(w)
|
477
487
|
w.close
|
@@ -492,7 +502,7 @@ class H1PServerTest < MiniTest::Test
|
|
492
502
|
@o.close
|
493
503
|
end
|
494
504
|
def w.__write_method__; :backend_write; end
|
495
|
-
|
505
|
+
|
496
506
|
headers = @parser.parse_headers
|
497
507
|
@parser.splice_body_to(w)
|
498
508
|
w.close
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: h1p
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '1.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.2.
|
19
|
+
version: 1.2.3
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.2.
|
26
|
+
version: 1.2.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 5.
|
47
|
+
version: 5.18.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 5.
|
54
|
+
version: 5.18.0
|
55
55
|
description:
|
56
56
|
email: sharon@noteflakes.com
|
57
57
|
executables: []
|
@@ -102,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
102
102
|
requirements:
|
103
103
|
- - ">="
|
104
104
|
- !ruby/object:Gem::Version
|
105
|
-
version: '
|
105
|
+
version: '3.0'
|
106
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - ">="
|