h1p 0.6.1 → 1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
- - ">="
|