lsqpack 0.1.0
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 +7 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/Rakefile +19 -0
- data/Steepfile +6 -0
- data/ext/lsqpack/extconf.rb +18 -0
- data/ext/lsqpack/lsqpack.c +426 -0
- data/ext/lsqpack/lsqpack.h +6 -0
- data/lib/lsqpack/version.rb +5 -0
- data/lib/lsqpack.rb +30 -0
- data/ls-qpack/.appveyor.yml +14 -0
- data/ls-qpack/.cirrus.yml +6 -0
- data/ls-qpack/.travis.yml +32 -0
- data/ls-qpack/CMakeLists.txt +66 -0
- data/ls-qpack/LICENSE +21 -0
- data/ls-qpack/README.md +65 -0
- data/ls-qpack/bin/CMakeLists.txt +21 -0
- data/ls-qpack/bin/encode-int.c +87 -0
- data/ls-qpack/bin/fuzz-decode.c +247 -0
- data/ls-qpack/bin/interop-decode.c +433 -0
- data/ls-qpack/bin/interop-encode.c +554 -0
- data/ls-qpack/deps/xxhash/xxhash.c +941 -0
- data/ls-qpack/deps/xxhash/xxhash.h +160 -0
- data/ls-qpack/fuzz/decode/a/README +3 -0
- data/ls-qpack/fuzz/decode/a/preamble +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000390,op_havoc,rep_4 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000579,op_flip1,pos_14 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000000,src_000000,op_flip2,pos_12 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000001,sig_11,src_000579,op_havoc,rep_4 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000002,sig_11,src_000481,op_int16,pos_15,val_-1 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000002,src_000000,op_havoc,rep_8 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000006,src_000285,op_flip2,pos_14 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000008,src_000285,op_flip2,pos_20 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000010,src_000306,op_flip2,pos_75 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000011,src_000344,op_havoc,rep_2 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000014,src_000366,op_flip2,pos_28 +0 -0
- data/ls-qpack/fuzz/decode/b/README +1 -0
- data/ls-qpack/fuzz/decode/b/preamble +0 -0
- data/ls-qpack/fuzz/decode/b/test-cases/seed +0 -0
- data/ls-qpack/fuzz/decode/c/setup.sh +3 -0
- data/ls-qpack/fuzz/decode/c/test-cases/fb-req.qif.proxygen.out.256.100.0-chopped +0 -0
- data/ls-qpack/fuzz/decode/d/preamble +0 -0
- data/ls-qpack/fuzz/decode/d/setup.sh +3 -0
- data/ls-qpack/fuzz/decode/d/test-cases/fb-resp.minhq.256.128.0.ack +0 -0
- data/ls-qpack/fuzz/input/256.100.1/fb-req.out.256.100.1 +0 -0
- data/ls-qpack/fuzz/input/256.100.1/fb-resp.out.256.100.1 +0 -0
- data/ls-qpack/fuzz/input/256.100.1/netbsd.out.256.100.1 +0 -0
- data/ls-qpack/huff-tables.h +136247 -0
- data/ls-qpack/lsqpack.c +5547 -0
- data/ls-qpack/lsqpack.h +768 -0
- data/ls-qpack/test/CMakeLists.txt +76 -0
- data/ls-qpack/test/lsqpack-test.h +43 -0
- data/ls-qpack/test/qifs/fb-req.qif +4917 -0
- data/ls-qpack/test/qifs/fb-resp.qif +5982 -0
- data/ls-qpack/test/qifs/long-codes.qif +5984 -0
- data/ls-qpack/test/qifs/netbsd.qif +235 -0
- data/ls-qpack/test/run-qif.pl +97 -0
- data/ls-qpack/test/run-scenario.sh +68 -0
- data/ls-qpack/test/scenarios/0.95-reset.sce +10 -0
- data/ls-qpack/test/scenarios/cancel-stream.sce +22 -0
- data/ls-qpack/test/scenarios/drain-2.sce +37 -0
- data/ls-qpack/test/scenarios/drain.sce +37 -0
- data/ls-qpack/test/scenarios/end-dst-2.sce +14 -0
- data/ls-qpack/test/scenarios/end-dst.sce +14 -0
- data/ls-qpack/test/scenarios/incl-name.sce +13 -0
- data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-1.sce +110 -0
- data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-2.sce +161 -0
- data/ls-qpack/test/scenarios/post-base-1.sce +10 -0
- data/ls-qpack/test/scenarios/post-base-2.sce +13 -0
- data/ls-qpack/test/scenarios/post-base-nr.sce +10 -0
- data/ls-qpack/test/scenarios/set-max-cap.sce +15 -0
- data/ls-qpack/test/test_enc_str.c +139 -0
- data/ls-qpack/test/test_get_stx_id.c +144 -0
- data/ls-qpack/test/test_huff_dec.c +399 -0
- data/ls-qpack/test/test_int.c +220 -0
- data/ls-qpack/test/test_qpack.c +856 -0
- data/ls-qpack/test/test_read_enc_stream.c +256 -0
- data/ls-qpack/tools/har2qif.pl +139 -0
- data/ls-qpack/tools/randomize-cookies.pl +41 -0
- data/ls-qpack/tools/sort-qif.pl +31 -0
- data/ls-qpack/wincompat/getopt.c +758 -0
- data/ls-qpack/wincompat/getopt.h +131 -0
- data/ls-qpack/wincompat/getopt1.c +188 -0
- data/ls-qpack/wincompat/sys/queue.h +859 -0
- data/lsqpack.gemspec +39 -0
- data/sig/lsqpack.rbs +29 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b3817dceb640976607a1f80f70359dff77831721822c80bf9055b90bd3fb51e5
|
4
|
+
data.tar.gz: 057c391779387b76cfec1e07141fab5e75e713af5f26fa6310899a6dc8d046d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2f6bec1a935ce51d1568eb83673cb14556cd82f437b219e7a7c1f23cbcbe948a123507ac5a5cb71b2af2d92395430eca3c37702c889f13e8a2edb1e3acca7206
|
7
|
+
data.tar.gz: 8c6f3f732c047544e8d5e41ec956832028e5f2bab18e044c0ba0620f91bfd9813be10b442493ae1e87dcdf80af968e59f7005430fffdbc311e72777b086afb53
|
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in lsqpack.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem "rake", "~> 13.0"
|
9
|
+
|
10
|
+
gem "rake-compiler"
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem "steep"
|
14
|
+
end
|
15
|
+
|
16
|
+
group :test do
|
17
|
+
gem "minitest"
|
18
|
+
gem "minitest-reporters"
|
19
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
lsqpack (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activesupport (7.0.4.3)
|
10
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
i18n (>= 1.6, < 2)
|
12
|
+
minitest (>= 5.1)
|
13
|
+
tzinfo (~> 2.0)
|
14
|
+
ansi (1.5.0)
|
15
|
+
ast (2.4.2)
|
16
|
+
builder (3.2.4)
|
17
|
+
concurrent-ruby (1.2.2)
|
18
|
+
csv (3.2.6)
|
19
|
+
ffi (1.15.5)
|
20
|
+
fileutils (1.7.0)
|
21
|
+
i18n (1.12.0)
|
22
|
+
concurrent-ruby (~> 1.0)
|
23
|
+
json (2.6.3)
|
24
|
+
language_server-protocol (3.17.0.3)
|
25
|
+
listen (3.8.0)
|
26
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
27
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
28
|
+
logger (1.5.3)
|
29
|
+
minitest (5.18.0)
|
30
|
+
minitest-reporters (1.6.0)
|
31
|
+
ansi
|
32
|
+
builder
|
33
|
+
minitest (>= 5.0)
|
34
|
+
ruby-progressbar
|
35
|
+
parallel (1.22.1)
|
36
|
+
parser (3.2.1.1)
|
37
|
+
ast (~> 2.4.1)
|
38
|
+
rainbow (3.1.1)
|
39
|
+
rake (13.0.6)
|
40
|
+
rake-compiler (1.2.0)
|
41
|
+
rake
|
42
|
+
rb-fsevent (0.11.2)
|
43
|
+
rb-inotify (0.10.1)
|
44
|
+
ffi (~> 1.0)
|
45
|
+
rbs (2.8.4)
|
46
|
+
ruby-progressbar (1.13.0)
|
47
|
+
securerandom (0.2.2)
|
48
|
+
steep (1.3.2)
|
49
|
+
activesupport (>= 5.1)
|
50
|
+
csv (>= 3.0.9)
|
51
|
+
fileutils (>= 1.1.0)
|
52
|
+
json (>= 2.1.0)
|
53
|
+
language_server-protocol (>= 3.15, < 4.0)
|
54
|
+
listen (~> 3.0)
|
55
|
+
logger (>= 1.3.0)
|
56
|
+
parallel (>= 1.0.0)
|
57
|
+
parser (>= 3.1)
|
58
|
+
rainbow (>= 2.2.2, < 4.0)
|
59
|
+
rbs (~> 2.8.0)
|
60
|
+
securerandom (>= 0.1)
|
61
|
+
strscan (>= 1.0.0)
|
62
|
+
terminal-table (>= 2, < 4)
|
63
|
+
strscan (3.0.6)
|
64
|
+
terminal-table (3.0.2)
|
65
|
+
unicode-display_width (>= 1.1.1, < 3)
|
66
|
+
tzinfo (2.0.6)
|
67
|
+
concurrent-ruby (~> 1.0)
|
68
|
+
unicode-display_width (2.4.2)
|
69
|
+
|
70
|
+
PLATFORMS
|
71
|
+
x86_64-linux
|
72
|
+
|
73
|
+
DEPENDENCIES
|
74
|
+
lsqpack!
|
75
|
+
minitest
|
76
|
+
minitest-reporters
|
77
|
+
rake (~> 13.0)
|
78
|
+
rake-compiler
|
79
|
+
steep
|
80
|
+
|
81
|
+
BUNDLED WITH
|
82
|
+
2.3.26
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 Yusuke Nakamura
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Lsqpack
|
2
|
+
|
3
|
+
lsqpack-ruby is a wrapper gem of the [litespeedtech/ls-qpack](https://github.com/litespeedtech/ls-qpack) library. It strongly influenced by [pylsqpack](https://github.com/aiortc/pylsqpack).
|
4
|
+
It strongly influenced by pylsqpack, so it has same api of pylsqpack.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Install the gem and add to the application's Gemfile by executing:
|
9
|
+
|
10
|
+
```sh
|
11
|
+
$ bundle add lsqpack
|
12
|
+
```
|
13
|
+
|
14
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
15
|
+
|
16
|
+
```sh
|
17
|
+
$ gem install lsqpack
|
18
|
+
```
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
See also <https://pylsqpack.readthedocs.io/en/latest/>
|
23
|
+
|
24
|
+
## Development
|
25
|
+
|
26
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
27
|
+
|
28
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/unasuke/lsqpack-ruby.
|
33
|
+
|
34
|
+
## Acknowledgement
|
35
|
+
* <https://github.com/litespeedtech/ls-qpack>
|
36
|
+
* <https://github.com/aiortc/pylsqpack>
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/extensiontask"
|
5
|
+
require "rake/testtask"
|
6
|
+
|
7
|
+
task build: :compile
|
8
|
+
|
9
|
+
Rake::ExtensionTask.new("lsqpack") do |ext|
|
10
|
+
ext.lib_dir = "lib/lsqpack"
|
11
|
+
end
|
12
|
+
|
13
|
+
Rake::TestTask.new(:test) do |t|
|
14
|
+
t.libs << "test"
|
15
|
+
t.libs << "lib"
|
16
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
17
|
+
end
|
18
|
+
|
19
|
+
task default: %i[clobber compile test]
|
data/Steepfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mkmf"
|
4
|
+
|
5
|
+
repo_root = File.join(File.expand_path(__dir__), "../", "../")
|
6
|
+
|
7
|
+
$CPPFLAGS = "-I #{repo_root}"
|
8
|
+
$LDFLAGS = "-lls-qpack -L#{File.join(repo_root, "ls-qpack")}"
|
9
|
+
|
10
|
+
Dir.chdir(repo_root) do
|
11
|
+
Dir.chdir("ls-qpack") do
|
12
|
+
puts(system("git status"))
|
13
|
+
system("cmake .", exception: true)
|
14
|
+
system("make", exception: true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
create_makefile("lsqpack/lsqpack")
|
@@ -0,0 +1,426 @@
|
|
1
|
+
#include "lsqpack.h"
|
2
|
+
#include "ls-qpack/lsqpack.h"
|
3
|
+
#include <stdio.h>
|
4
|
+
|
5
|
+
#define HEADER_BUF_SIZE 4096
|
6
|
+
#define ENCODER_BUF_SIZE 4096
|
7
|
+
#define DECODER_BUF_SIZE 4096
|
8
|
+
#define PREFIX_MAX_SIZE 16
|
9
|
+
|
10
|
+
VALUE rb_mLsqpack;
|
11
|
+
VALUE rb_clsEncoder;
|
12
|
+
VALUE rb_clsDecoder;
|
13
|
+
VALUE rb_eError;
|
14
|
+
VALUE rb_eDecompressionFailed;
|
15
|
+
VALUE rb_eDecoderStreamErr;
|
16
|
+
VALUE rb_eEncoderStreamErr;
|
17
|
+
VALUE rb_eStreamBlocked;
|
18
|
+
|
19
|
+
struct header_block {
|
20
|
+
STAILQ_ENTRY(header_block) entries;
|
21
|
+
int blocked:1;
|
22
|
+
unsigned char* data;
|
23
|
+
size_t data_len;
|
24
|
+
const unsigned char* data_ptr;
|
25
|
+
struct lsqpack_header_list *hlist;
|
26
|
+
uint64_t stream_id;
|
27
|
+
};
|
28
|
+
|
29
|
+
static struct header_block *header_block_new(size_t stream_id, const unsigned char* data, size_t data_len) {
|
30
|
+
struct header_block* hblock = malloc(sizeof(struct header_block));
|
31
|
+
memset(hblock, 0, sizeof(*hblock));
|
32
|
+
hblock->data = malloc(data_len);
|
33
|
+
hblock->data_len = data_len;
|
34
|
+
hblock->data_ptr = hblock->data;
|
35
|
+
memcpy(hblock->data, data, data_len);
|
36
|
+
hblock->stream_id = stream_id;
|
37
|
+
return hblock;
|
38
|
+
}
|
39
|
+
|
40
|
+
static void header_block_free(struct header_block* hblock) {
|
41
|
+
free(hblock->data);
|
42
|
+
hblock->data = 0;
|
43
|
+
hblock->data_ptr = 0;
|
44
|
+
if(hblock->hlist) {
|
45
|
+
lsqpack_dec_destroy_header_list(hblock->hlist);
|
46
|
+
hblock->hlist = 0;
|
47
|
+
}
|
48
|
+
free(hblock);
|
49
|
+
}
|
50
|
+
|
51
|
+
VALUE hlist_to_headers(struct lsqpack_header_list* hlist) {
|
52
|
+
VALUE list, tuple, name, value;
|
53
|
+
struct lsqpack_header* header;
|
54
|
+
|
55
|
+
list = rb_ary_new_capa(hlist->qhl_count);
|
56
|
+
for (size_t i = 0; i < hlist->qhl_count; i++) {
|
57
|
+
header = hlist->qhl_headers[i];
|
58
|
+
name = rb_str_new(header->qh_name, header->qh_name_len);
|
59
|
+
value = rb_str_new(header->qh_value, header->qh_value_len);
|
60
|
+
tuple = rb_ary_new_capa(2);
|
61
|
+
rb_ary_store(tuple, 0, name);
|
62
|
+
rb_ary_store(tuple, 1, value);
|
63
|
+
rb_ary_store(list, i, tuple);
|
64
|
+
}
|
65
|
+
return list;
|
66
|
+
}
|
67
|
+
|
68
|
+
static void header_unblocked(void* opaque) {
|
69
|
+
struct header_block* hblock = opaque;
|
70
|
+
hblock->blocked = 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
typedef struct {
|
74
|
+
struct lsqpack_dec dec;
|
75
|
+
unsigned char decoder_buf[DECODER_BUF_SIZE];
|
76
|
+
STAILQ_HEAD(, header_block) pending_blocks;
|
77
|
+
} DecoderObj;
|
78
|
+
|
79
|
+
size_t lsqpackrb_dec_size(DecoderObj* data) {
|
80
|
+
return sizeof(DecoderObj); // Is it correct?
|
81
|
+
}
|
82
|
+
|
83
|
+
void lsqpackrb_dec_free(DecoderObj* data) {
|
84
|
+
struct header_block* hblock;
|
85
|
+
lsqpack_dec_cleanup(&data->dec);
|
86
|
+
while (!STAILQ_EMPTY(&data->pending_blocks)) {
|
87
|
+
hblock = STAILQ_FIRST(&data->pending_blocks);
|
88
|
+
STAILQ_REMOVE_HEAD(&data->pending_blocks, entries);
|
89
|
+
header_block_free(hblock);
|
90
|
+
}
|
91
|
+
free(data);
|
92
|
+
}
|
93
|
+
|
94
|
+
static const rb_data_type_t decoder_data_type = {
|
95
|
+
.wrap_struct_name = "lsqpack_dec_rb",
|
96
|
+
.function = {
|
97
|
+
.dmark = NULL,
|
98
|
+
.dfree = lsqpackrb_dec_free,
|
99
|
+
.dsize = lsqpackrb_dec_size,
|
100
|
+
},
|
101
|
+
.data = NULL,
|
102
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
103
|
+
};
|
104
|
+
|
105
|
+
VALUE lsqpackrb_dec_alloc(VALUE self) {
|
106
|
+
DecoderObj* data = malloc(sizeof(DecoderObj));
|
107
|
+
return TypedData_Wrap_Struct(self, &decoder_data_type, data);
|
108
|
+
}
|
109
|
+
|
110
|
+
|
111
|
+
VALUE lsqpackrb_dec_init(int argc, VALUE *argv, VALUE self) {
|
112
|
+
DecoderObj* data;
|
113
|
+
TypedData_Get_Struct(self, DecoderObj, &decoder_data_type, data);
|
114
|
+
|
115
|
+
VALUE hash;
|
116
|
+
hash = rb_check_hash_type(argv[argc-1]);
|
117
|
+
unsigned int max_tbl_capa, blked_streams;
|
118
|
+
ID table[2];
|
119
|
+
VALUE values[2];
|
120
|
+
table[0] = rb_intern("max_table_capacity");
|
121
|
+
table[1] = rb_intern("blocked_streams");
|
122
|
+
rb_get_kwargs(hash, table, 0, 2, values);
|
123
|
+
max_tbl_capa = (values[0] != Qundef) ? (FIX2INT(values[0])) : 0;
|
124
|
+
blked_streams = (values[1] != Qundef) ? (FIX2INT(values[1])) : 0;
|
125
|
+
|
126
|
+
lsqpack_dec_init(&data->dec, NULL, max_tbl_capa, blked_streams, header_unblocked);
|
127
|
+
STAILQ_INIT(&data->pending_blocks);
|
128
|
+
return self;
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
VALUE lsqpackrb_dec_feed_encoder(VALUE self, VALUE data) {
|
133
|
+
DecoderObj* dec;
|
134
|
+
TypedData_Get_Struct(self, DecoderObj, &decoder_data_type, dec);
|
135
|
+
struct header_block* hblock;
|
136
|
+
Check_Type(data, T_STRING);
|
137
|
+
unsigned char* feed_data;
|
138
|
+
feed_data = StringValuePtr(data);
|
139
|
+
size_t feed_data_len;
|
140
|
+
feed_data_len = RSTRING_LEN(data);
|
141
|
+
|
142
|
+
if (lsqpack_dec_enc_in(&dec->dec, feed_data, feed_data_len) < 0) {
|
143
|
+
rb_raise(rb_eEncoderStreamErr, "lsqpack_dec_enc_in failed");
|
144
|
+
return NULL;
|
145
|
+
}
|
146
|
+
|
147
|
+
VALUE list = rb_ary_new();
|
148
|
+
STAILQ_FOREACH(hblock, &dec->pending_blocks, entries) {
|
149
|
+
if(!hblock->blocked) {
|
150
|
+
VALUE val = LONG2NUM(hblock->stream_id);
|
151
|
+
rb_ary_push(list, val);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
return list;
|
155
|
+
}
|
156
|
+
|
157
|
+
VALUE lsqpackrb_dec_feed_header(VALUE self, VALUE stream_id, VALUE data) {
|
158
|
+
DecoderObj* dec;
|
159
|
+
TypedData_Get_Struct(self, DecoderObj, &decoder_data_type, dec);
|
160
|
+
uint64_t strm_id;
|
161
|
+
size_t dec_len = DECODER_BUF_SIZE;
|
162
|
+
unsigned char* feed_data;
|
163
|
+
int feed_data_len;
|
164
|
+
enum lsqpack_read_header_status status;
|
165
|
+
struct header_block* hblock;
|
166
|
+
|
167
|
+
strm_id = FIX2LONG(stream_id);
|
168
|
+
Check_Type(data, T_STRING);
|
169
|
+
feed_data = StringValuePtr(data);
|
170
|
+
feed_data_len = RSTRING_LEN(data);
|
171
|
+
|
172
|
+
STAILQ_FOREACH(hblock, &dec->pending_blocks, entries) {
|
173
|
+
if (hblock->stream_id == strm_id) {
|
174
|
+
rb_raise(rb_eError, "a header block for stream %d already exists", strm_id);
|
175
|
+
return NULL;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
hblock = header_block_new(strm_id, feed_data, feed_data_len);
|
179
|
+
status = lsqpack_dec_header_in(
|
180
|
+
&dec->dec,
|
181
|
+
hblock,
|
182
|
+
strm_id,
|
183
|
+
hblock->data_len,
|
184
|
+
&hblock->data_ptr,
|
185
|
+
hblock->data_len,
|
186
|
+
&hblock->hlist,
|
187
|
+
dec->decoder_buf,
|
188
|
+
&dec_len
|
189
|
+
);
|
190
|
+
if (status == LQRHS_BLOCKED || status == LQRHS_NEED) {
|
191
|
+
hblock->blocked = 1;
|
192
|
+
STAILQ_INSERT_TAIL(&dec->pending_blocks, hblock, entries);
|
193
|
+
rb_raise(rb_eStreamBlocked, "stream %d is blocked", strm_id);
|
194
|
+
return NULL;
|
195
|
+
} else if (status != LQRHS_DONE) {
|
196
|
+
rb_raise(rb_eDecompressionFailed, "lsqpack_dec_header_in for stream %d failed", strm_id);
|
197
|
+
header_block_free(hblock);
|
198
|
+
return NULL;
|
199
|
+
}
|
200
|
+
|
201
|
+
VALUE control = rb_str_new(dec->decoder_buf, dec_len);
|
202
|
+
VALUE headers = hlist_to_headers(hblock->hlist);
|
203
|
+
header_block_free(hblock);
|
204
|
+
VALUE tuple = rb_ary_new_capa(2);
|
205
|
+
rb_ary_store(tuple, 0, control);
|
206
|
+
rb_ary_store(tuple, 1, headers);
|
207
|
+
return tuple;
|
208
|
+
}
|
209
|
+
|
210
|
+
VALUE lsqpackrb_dec_resume_header(VALUE self, VALUE stream_id) {
|
211
|
+
DecoderObj* dec;
|
212
|
+
TypedData_Get_Struct(self, DecoderObj, &decoder_data_type, dec);
|
213
|
+
uint64_t strm_id;
|
214
|
+
size_t dec_len = DECODER_BUF_SIZE;
|
215
|
+
enum lsqpack_read_header_status status;
|
216
|
+
struct header_block *hblock;
|
217
|
+
int found = 0;
|
218
|
+
|
219
|
+
Check_Type(stream_id, T_FIXNUM);
|
220
|
+
strm_id = NUM2LONG(stream_id);
|
221
|
+
|
222
|
+
STAILQ_FOREACH(hblock, &dec->pending_blocks, entries) {
|
223
|
+
if(hblock->stream_id == strm_id) {
|
224
|
+
found = 1;
|
225
|
+
break;
|
226
|
+
}
|
227
|
+
}
|
228
|
+
if (!found) {
|
229
|
+
rb_raise(rb_eError, "no pending header block for stream %d", strm_id);
|
230
|
+
return NULL;
|
231
|
+
}
|
232
|
+
if (hblock->blocked) {
|
233
|
+
status = LQRHS_BLOCKED;
|
234
|
+
} else {
|
235
|
+
status = lsqpack_dec_header_read(
|
236
|
+
&dec->dec,
|
237
|
+
hblock,
|
238
|
+
&hblock->data_ptr,
|
239
|
+
hblock->data_len - (hblock->data_ptr - hblock->data),
|
240
|
+
&hblock->hlist,
|
241
|
+
dec->decoder_buf,
|
242
|
+
&dec_len
|
243
|
+
);
|
244
|
+
}
|
245
|
+
|
246
|
+
if (status == LQRHS_BLOCKED || status == LQRHS_NEED) {
|
247
|
+
hblock->blocked = 1;
|
248
|
+
rb_raise(rb_eStreamBlocked, "stream %d is blocked", strm_id);
|
249
|
+
return NULL;
|
250
|
+
} else if (status != LQRHS_DONE) {
|
251
|
+
rb_raise(rb_eDecompressionFailed, "lsqpack_dec_header_in for stream %d failed (%d)", strm_id, status);
|
252
|
+
STAILQ_REMOVE(&dec->pending_blocks, hblock, header_block, entries);
|
253
|
+
header_block_free(hblock);
|
254
|
+
return NULL;
|
255
|
+
}
|
256
|
+
VALUE control = rb_str_new(dec->decoder_buf, dec_len);
|
257
|
+
VALUE headers = hlist_to_headers(hblock->hlist);
|
258
|
+
VALUE tuple = rb_ary_new_capa(2);
|
259
|
+
rb_ary_store(tuple, 0, control);
|
260
|
+
rb_ary_store(tuple, 1, headers);
|
261
|
+
return tuple;
|
262
|
+
}
|
263
|
+
|
264
|
+
|
265
|
+
|
266
|
+
typedef struct {
|
267
|
+
struct lsqpack_enc enc;
|
268
|
+
unsigned char header_buf[HEADER_BUF_SIZE];
|
269
|
+
unsigned char encoder_buf[ENCODER_BUF_SIZE];
|
270
|
+
unsigned char prefix_buf[PREFIX_MAX_SIZE];
|
271
|
+
} EncoderObj;
|
272
|
+
|
273
|
+
size_t lsqpackrb_enc_size(EncoderObj* data) {
|
274
|
+
return sizeof(EncoderObj);
|
275
|
+
}
|
276
|
+
|
277
|
+
void lsqpackrb_enc_free(EncoderObj* data) {
|
278
|
+
lsqpack_enc_cleanup(&data->enc);
|
279
|
+
free(data);
|
280
|
+
}
|
281
|
+
|
282
|
+
static const rb_data_type_t encoder_data_type = {
|
283
|
+
.wrap_struct_name = "lsqpack_enc_rb",
|
284
|
+
.function = {
|
285
|
+
.dmark = NULL,
|
286
|
+
.dfree = lsqpackrb_enc_free,
|
287
|
+
.dsize = lsqpackrb_enc_size,
|
288
|
+
},
|
289
|
+
.data = NULL,
|
290
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
291
|
+
};
|
292
|
+
|
293
|
+
VALUE lsqpackrb_enc_alloc(VALUE self) {
|
294
|
+
EncoderObj* data = malloc(sizeof(EncoderObj));
|
295
|
+
return TypedData_Wrap_Struct(self, &encoder_data_type, data);
|
296
|
+
}
|
297
|
+
|
298
|
+
VALUE lsqpackrb_enc_init(VALUE self) {
|
299
|
+
EncoderObj* data;
|
300
|
+
TypedData_Get_Struct(self, EncoderObj, &encoder_data_type, data);
|
301
|
+
lsqpack_enc_preinit(&data->enc, NULL);
|
302
|
+
return self;
|
303
|
+
}
|
304
|
+
|
305
|
+
VALUE lsqpackrb_enc_apply_settings(VALUE self, VALUE rb_max_table_capacity, VALUE rb_blocked_streams) {
|
306
|
+
EncoderObj* data;
|
307
|
+
TypedData_Get_Struct(self, EncoderObj, &encoder_data_type, data);
|
308
|
+
|
309
|
+
unsigned int max_table_capacity = FIX2INT(rb_max_table_capacity);
|
310
|
+
unsigned int blocked_streams = FIX2INT(rb_blocked_streams);
|
311
|
+
unsigned char stdc_buf[LSQPACK_LONGEST_SDTC];
|
312
|
+
size_t stdc_buf_len = sizeof(stdc_buf);
|
313
|
+
|
314
|
+
if(lsqpack_enc_init(&data->enc, NULL, max_table_capacity, max_table_capacity, blocked_streams, LSQPACK_ENC_OPT_STAGE_2, stdc_buf, &stdc_buf_len) != 0) {
|
315
|
+
rb_raise(rb_eError, "lsqpack_enc_init failed");
|
316
|
+
return NULL;
|
317
|
+
}
|
318
|
+
return rb_str_new(stdc_buf, stdc_buf_len);
|
319
|
+
}
|
320
|
+
|
321
|
+
VALUE lsqpackrb_enc_encode(VALUE self, VALUE stream_id, VALUE headers) {
|
322
|
+
EncoderObj* data;
|
323
|
+
TypedData_Get_Struct(self, EncoderObj, &encoder_data_type, data);
|
324
|
+
|
325
|
+
uint64_t str_id = FIX2LONG(stream_id);
|
326
|
+
unsigned int sequence_number = 0;
|
327
|
+
size_t enc_len, header_len, prefix_len;
|
328
|
+
size_t enc_off = 0, header_off = PREFIX_MAX_SIZE, prefix_off = 0;
|
329
|
+
|
330
|
+
Check_Type(headers, T_ARRAY);
|
331
|
+
if (rb_array_len(headers) == 0) {
|
332
|
+
// no headers present
|
333
|
+
return NULL;
|
334
|
+
}
|
335
|
+
|
336
|
+
if (lsqpack_enc_start_header(&data->enc, str_id, sequence_number) != 0) {
|
337
|
+
rb_raise(rb_eError, "lsqpack_enc_start_header failed");
|
338
|
+
return NULL;
|
339
|
+
}
|
340
|
+
|
341
|
+
for (int i = 0; i < rb_array_len(headers); i++) {
|
342
|
+
VALUE entry = rb_ary_entry(headers, i);
|
343
|
+
if (rb_array_len(entry) != 2) {
|
344
|
+
// no headers present
|
345
|
+
rb_raise(rb_eError, "Each header entry must be include 2 elements");
|
346
|
+
return NULL;
|
347
|
+
}
|
348
|
+
|
349
|
+
VALUE name_ = rb_ary_entry(entry, 0);
|
350
|
+
VALUE value_ = rb_ary_entry(entry, 1);
|
351
|
+
char* name = StringValuePtr(name_);
|
352
|
+
int name_len = RSTRING_LEN(name_);
|
353
|
+
char* value = StringValuePtr(value_);
|
354
|
+
int value_len = RSTRING_LEN(value_);
|
355
|
+
|
356
|
+
enc_len = ENCODER_BUF_SIZE - enc_off;
|
357
|
+
header_len = HEADER_BUF_SIZE - header_off;
|
358
|
+
// printf("==========name %s, len %d\n", name, name_len);
|
359
|
+
// printf("==========value %s, len %d\n", value, value_len);
|
360
|
+
// printf("==========enc_len(init) %d\n", enc_len);
|
361
|
+
if (lsqpack_enc_encode(&data->enc,
|
362
|
+
data->encoder_buf + enc_off, &enc_len,
|
363
|
+
data->header_buf + header_off, &header_len,
|
364
|
+
name, name_len, value, value_len, 0) != LQES_OK) {
|
365
|
+
rb_raise(rb_eError, "lsqpack_enc_encode failed");
|
366
|
+
return NULL;
|
367
|
+
}
|
368
|
+
// printf("==========enc_len %d\n", enc_len);
|
369
|
+
enc_off += enc_len;
|
370
|
+
header_off += header_len;
|
371
|
+
// printf("==========enc_off %d\n", enc_off);
|
372
|
+
}
|
373
|
+
|
374
|
+
prefix_len = lsqpack_enc_end_header(&data->enc, data->prefix_buf, PREFIX_MAX_SIZE, NULL);
|
375
|
+
if (prefix_len <= 0) {
|
376
|
+
rb_raise(rb_eError, "lsqpack_enc_end_header failed");
|
377
|
+
return NULL;
|
378
|
+
}
|
379
|
+
prefix_off = PREFIX_MAX_SIZE - prefix_len;
|
380
|
+
memcpy(data->header_buf + prefix_off, data->prefix_buf, prefix_len);
|
381
|
+
VALUE name = rb_str_new(data->encoder_buf, enc_off);
|
382
|
+
VALUE value = rb_str_new(data->header_buf + prefix_off, (int)(header_off - prefix_off));
|
383
|
+
VALUE tuple = rb_ary_new_from_args(2, name, value);
|
384
|
+
return tuple;
|
385
|
+
}
|
386
|
+
|
387
|
+
void lsqpackrb_enc_feed_decoder(VALUE self, VALUE rb_data) {
|
388
|
+
EncoderObj* data;
|
389
|
+
TypedData_Get_Struct(self, EncoderObj, &encoder_data_type, data);
|
390
|
+
char* feed_data = StringValuePtr(rb_data);
|
391
|
+
int feed_data_len = RSTRING_LEN(rb_data);
|
392
|
+
|
393
|
+
if (lsqpack_enc_decoder_in(&data->enc, feed_data, feed_data_len) < 0) {
|
394
|
+
rb_raise(rb_eDecoderStreamErr, "lsqpack_enc_decoder_in failed");
|
395
|
+
return NULL;
|
396
|
+
}
|
397
|
+
return NULL;
|
398
|
+
}
|
399
|
+
|
400
|
+
|
401
|
+
void
|
402
|
+
Init_lsqpack(void)
|
403
|
+
{
|
404
|
+
rb_mLsqpack = rb_define_module("Lsqpack");
|
405
|
+
rb_eError = rb_define_class_under(rb_mLsqpack, "Error", rb_eStandardError);
|
406
|
+
rb_eDecompressionFailed = rb_define_class_under(rb_mLsqpack, "DecompressionFailed", rb_eError);
|
407
|
+
rb_eDecoderStreamErr = rb_define_class_under(rb_mLsqpack, "DecoderStreamError", rb_eError);
|
408
|
+
rb_eEncoderStreamErr = rb_define_class_under(rb_mLsqpack, "EncoderStreamError", rb_eError);
|
409
|
+
rb_eStreamBlocked = rb_define_class_under(rb_mLsqpack, "StreamBlocked", rb_eError);
|
410
|
+
|
411
|
+
// Encoder
|
412
|
+
rb_clsEncoder = rb_define_class_under(rb_mLsqpack, "Encoder", rb_cObject);
|
413
|
+
rb_define_alloc_func(rb_clsEncoder, lsqpackrb_enc_alloc);
|
414
|
+
rb_define_method(rb_clsEncoder, "initialize", lsqpackrb_enc_init, 0);
|
415
|
+
rb_define_private_method(rb_clsEncoder, "_apply_settings", lsqpackrb_enc_apply_settings, 2);
|
416
|
+
rb_define_method(rb_clsEncoder, "encode", lsqpackrb_enc_encode, 2);
|
417
|
+
rb_define_method(rb_clsEncoder, "feed_decoder", lsqpackrb_enc_feed_decoder, 1);
|
418
|
+
|
419
|
+
// Decoder
|
420
|
+
rb_clsDecoder = rb_define_class_under(rb_mLsqpack, "Decoder", rb_cObject);
|
421
|
+
rb_define_alloc_func(rb_clsDecoder, lsqpackrb_dec_alloc);
|
422
|
+
rb_define_method(rb_clsDecoder, "initialize", lsqpackrb_dec_init, -1);
|
423
|
+
rb_define_method(rb_clsDecoder, "feed_encoder", lsqpackrb_dec_feed_encoder, 1);
|
424
|
+
rb_define_method(rb_clsDecoder, "feed_header", lsqpackrb_dec_feed_header, 2);
|
425
|
+
rb_define_method(rb_clsDecoder, "resume_header", lsqpackrb_dec_resume_header, 1);
|
426
|
+
}
|
data/lib/lsqpack.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lsqpack/version"
|
4
|
+
require_relative "lsqpack/lsqpack"
|
5
|
+
|
6
|
+
module Lsqpack
|
7
|
+
# class Error < StandardError; end
|
8
|
+
# class DecompressonFailed < Error; end
|
9
|
+
# class DecoderStreamError < Error; end
|
10
|
+
# class EncoderStreamError < Error; end
|
11
|
+
# class StreamBlocked < Error; end
|
12
|
+
# Your code goes here...
|
13
|
+
|
14
|
+
class Encoder
|
15
|
+
# def initialize
|
16
|
+
# end
|
17
|
+
|
18
|
+
def apply_settings(max_table_capacity: 0, blocked_streams: 0)
|
19
|
+
_apply_settings(max_table_capacity, blocked_streams)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# class Decoder
|
24
|
+
# def initialize
|
25
|
+
# end
|
26
|
+
|
27
|
+
# def decode
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
end
|