protocol-http2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'frame'
22
+ require_relative 'padded'
23
+ require_relative 'continuation_frame'
24
+ require_relative 'priority_frame'
25
+
26
+ module Protocol
27
+ module HTTP2
28
+ # The HEADERS frame is used to open a stream, and additionally carries a header block fragment. HEADERS frames can be sent on a stream in the "idle", "reserved (local)", "open", or "half-closed (remote)" state.
29
+ #
30
+ # +---------------+
31
+ # |Pad Length? (8)|
32
+ # +-+-------------+-----------------------------------------------+
33
+ # |E| Stream Dependency? (31) |
34
+ # +-+-------------+-----------------------------------------------+
35
+ # | Weight? (8) |
36
+ # +-+-------------+-----------------------------------------------+
37
+ # | Header Block Fragment (*) ...
38
+ # +---------------------------------------------------------------+
39
+ # | Padding (*) ...
40
+ # +---------------------------------------------------------------+
41
+ #
42
+ class HeadersFrame < Frame
43
+ include Continued, Padded
44
+
45
+ TYPE = 0x1
46
+
47
+ def priority?
48
+ flag_set?(PRIORITY)
49
+ end
50
+
51
+ def end_stream?
52
+ flag_set?(END_STREAM)
53
+ end
54
+
55
+ def unpack
56
+ data = super
57
+
58
+ if priority?
59
+ priority = Priority.unpack(data)
60
+ data = data.byteslice(5, data.bytesize - 5)
61
+ end
62
+
63
+ return priority, data
64
+ end
65
+
66
+ def pack(priority, data, *args)
67
+ buffer = String.new.b
68
+
69
+ if priority
70
+ buffer << priority.pack
71
+ end
72
+
73
+ buffer << data
74
+
75
+ super(buffer, *args)
76
+ end
77
+
78
+ def apply(connection)
79
+ connection.receive_headers(self)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,79 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ # Copyright, 2013, by Ilya Grigorik.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require_relative 'frame'
23
+
24
+ module Protocol
25
+ module HTTP2
26
+ # Certain frames can have padding:
27
+ # https://http2.github.io/http2-spec/#padding
28
+ #
29
+ # +---------------+
30
+ # |Pad Length? (8)|
31
+ # +---------------+-----------------------------------------------+
32
+ # | Data (*) ...
33
+ # +---------------------------------------------------------------+
34
+ # | Padding (*) ...
35
+ # +---------------------------------------------------------------+
36
+ #
37
+ module Padded
38
+ def padded?
39
+ flag_set?(PADDED)
40
+ end
41
+
42
+ def pack(data, padding_size: nil, maximum_size: nil)
43
+ if padding_size
44
+ set_flags(PADDED)
45
+
46
+ buffer = String.new.b
47
+
48
+ buffer << padding_size.chr
49
+ buffer << data
50
+
51
+ if padding_size > 1
52
+ buffer << "\0" * (padding_size - 1)
53
+ end
54
+
55
+ super buffer
56
+ else
57
+ clear_flags(PADDED)
58
+
59
+ super data
60
+ end
61
+ end
62
+
63
+ def unpack
64
+ if padded?
65
+ padding_size = @payload[0].ord
66
+ data_size = (@payload.bytesize - 1) - padding_size
67
+
68
+ if data_size < 0
69
+ raise ProtocolError, "Invalid padding length: #{padding_size}"
70
+ end
71
+
72
+ return @payload.byteslice(1, data_size)
73
+ else
74
+ return @payload
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,80 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'frame'
22
+
23
+ module Protocol
24
+ module HTTP2
25
+ ACKNOWLEDGEMENT = 0x1
26
+
27
+ module Acknowledgement
28
+ def acknowledgement?
29
+ flag_set?(ACKNOWLEDGEMENT)
30
+ end
31
+
32
+ def acknowledge
33
+ frame = self.class.new
34
+
35
+ frame.length = 0
36
+ frame.set_flags(ACKNOWLEDGEMENT)
37
+
38
+ return frame
39
+ end
40
+ end
41
+
42
+ # The PING frame is a mechanism for measuring a minimal round-trip time from the sender, as well as determining whether an idle connection is still functional. PING frames can be sent from any endpoint.
43
+ #
44
+ # +---------------------------------------------------------------+
45
+ # | |
46
+ # | Opaque Data (64) |
47
+ # | |
48
+ # +---------------------------------------------------------------+
49
+ #
50
+ class PingFrame < Frame
51
+ TYPE = 0x6
52
+
53
+ include Acknowledgement
54
+
55
+ def connection?
56
+ true
57
+ end
58
+
59
+ def apply(connection)
60
+ connection.receive_ping(self)
61
+ end
62
+
63
+ def acknowledge
64
+ frame = super
65
+
66
+ frame.pack self.unpack
67
+
68
+ return frame
69
+ end
70
+
71
+ def read_payload(stream)
72
+ super
73
+
74
+ if @length > 8
75
+ raise FrameSizeError, "Invalid frame length"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,80 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'frame'
22
+
23
+ module Protocol
24
+ module HTTP2
25
+ Priority = Struct.new(:exclusive, :stream_dependency, :weight) do
26
+ FORMAT = "NC".freeze
27
+ EXCLUSIVE = 1 << 31
28
+
29
+ def self.unpack(data)
30
+ stream_dependency, weight = data.unpack(FORMAT)
31
+
32
+ return self.new(stream_dependency & EXCLUSIVE != 0, stream_dependency & ~EXCLUSIVE, weight)
33
+ end
34
+
35
+ def pack
36
+ if exclusive
37
+ stream_dependency = self.stream_dependency | EXCLUSIVE
38
+ end
39
+
40
+ return [stream_dependency, self.weight].pack(FORMAT)
41
+ end
42
+ end
43
+
44
+ # The PRIORITY frame specifies the sender-advised priority of a stream. It can be sent in any stream state, including idle or closed streams.
45
+ #
46
+ # +-+-------------------------------------------------------------+
47
+ # |E| Stream Dependency (31) |
48
+ # +-+-------------+-----------------------------------------------+
49
+ # | Weight (8) |
50
+ # +-+-------------+
51
+ #
52
+ class PriorityFrame < Frame
53
+ TYPE = 0x2
54
+
55
+ def priority
56
+ Priority.unpack(@payload)
57
+ end
58
+
59
+ def pack priority
60
+ super priority.pack
61
+ end
62
+
63
+ def unpack
64
+ Priority.unpack(super)
65
+ end
66
+
67
+ def apply(connection)
68
+ connection.receive_priority(self)
69
+ end
70
+
71
+ def read_payload(stream)
72
+ super
73
+
74
+ if @length != 5
75
+ raise FrameSizeError, "Invalid frame length"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'frame'
22
+ require_relative 'padded'
23
+ require_relative 'continuation_frame'
24
+
25
+ module Protocol
26
+ module HTTP2
27
+ # The PUSH_PROMISE frame is used to notify the peer endpoint in advance of streams the sender intends to initiate. The PUSH_PROMISE frame includes the unsigned 31-bit identifier of the stream the endpoint plans to create along with a set of headers that provide additional context for the stream.
28
+ #
29
+ # +---------------+
30
+ # |Pad Length? (8)|
31
+ # +-+-------------+-----------------------------------------------+
32
+ # |R| Promised Stream ID (31) |
33
+ # +-+-----------------------------+-------------------------------+
34
+ # | Header Block Fragment (*) ...
35
+ # +---------------------------------------------------------------+
36
+ # | Padding (*) ...
37
+ # +---------------------------------------------------------------+
38
+ #
39
+ class PushPromiseFrame < Frame
40
+ include Continued, Padded
41
+
42
+ TYPE = 0x5
43
+ FORMAT = "N".freeze
44
+
45
+ def unpack
46
+ data = super
47
+
48
+ stream_id = data.unpack(FORMAT).first
49
+
50
+ return stream_id, data.byteslice(4, data.bytesize - 4)
51
+ end
52
+
53
+ def pack(stream_id, data, *args)
54
+ super([stream_id].pack(FORMAT) + data, *args)
55
+ end
56
+
57
+ def apply(connection)
58
+ connection.receive_push_promise(self)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,72 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'frame'
22
+
23
+ module Protocol
24
+ module HTTP2
25
+ NO_ERROR = 0
26
+ PROTOCOL_ERROR = 1
27
+ INTERNAL_ERROR = 2
28
+ FLOW_CONTROL_ERROR = 3
29
+ TIMEOUT = 4
30
+ STREAM_CLOSED = 5
31
+ FRAME_SIZE_ERROR = 6
32
+ REFUSED_STREAM = 7
33
+ CANCEL = 8
34
+ COMPRESSION_ERROR = 9
35
+ CONNECT_ERROR = 10
36
+ ENHANCE_YOUR_CALM = 11
37
+ INADEQUATE_SECURITY = 12
38
+ HTTP_1_1_REQUIRED = 13
39
+
40
+ # The RST_STREAM frame allows for immediate termination of a stream. RST_STREAM is sent to request cancellation of a stream or to indicate that an error condition has occurred.
41
+ #
42
+ # +---------------------------------------------------------------+
43
+ # | Error Code (32) |
44
+ # +---------------------------------------------------------------+
45
+ #
46
+ class ResetStreamFrame < Frame
47
+ TYPE = 0x3
48
+ FORMAT = "N".freeze
49
+
50
+ def unpack
51
+ @payload.unpack(FORMAT).first
52
+ end
53
+
54
+ def pack(error_code = NO_ERROR)
55
+ @payload = [error_code].pack(FORMAT)
56
+ @length = @payload.bytesize
57
+ end
58
+
59
+ def apply(connection)
60
+ connection.receive_reset_stream(self)
61
+ end
62
+
63
+ def read_payload(stream)
64
+ super
65
+
66
+ if @length != 4
67
+ raise FrameSizeError, "Invalid frame length"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,53 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'connection'
22
+
23
+ module Protocol
24
+ module HTTP2
25
+ class Server < Connection
26
+ def initialize(framer)
27
+ super(framer, 2)
28
+ end
29
+
30
+ def read_connection_preface(settings = [])
31
+ if @state == :new
32
+ @framer.read_connection_preface
33
+
34
+ send_settings(settings)
35
+
36
+ read_frame do |frame|
37
+ raise ProtocolError, "First frame must be SettingsFrame, but got #{frame.class}" unless frame.is_a? SettingsFrame
38
+ end
39
+ else
40
+ raise ProtocolError, "Cannot send connection preface in state #{@state}"
41
+ end
42
+ end
43
+
44
+ def enable_push?
45
+ @remote_settings.enable_push?
46
+ end
47
+
48
+ def receive_push_promise
49
+ raise ProtocolError, "Server cannot receive push promises."
50
+ end
51
+ end
52
+ end
53
+ end