http-protocol 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
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 HTTP
25
+ module Protocol
26
+ module HTTP2
27
+ # Certain frames can have padding:
28
+ # https://http2.github.io/http2-spec/#padding
29
+ #
30
+ # +---------------+
31
+ # |Pad Length? (8)|
32
+ # +---------------+-----------------------------------------------+
33
+ # | Data (*) ...
34
+ # +---------------------------------------------------------------+
35
+ # | Padding (*) ...
36
+ # +---------------------------------------------------------------+
37
+ #
38
+ module Padded
39
+ def padded?
40
+ flag_set?(PADDED)
41
+ end
42
+
43
+ # We will round up frames to the given length:
44
+ MODULUS = 0x0F
45
+
46
+ def pack(data, modulus: MODULUS, padding_size: nil, maximum_size: nil)
47
+ padding_size ||= (MODULUS - data.bytesize) % MODULUS
48
+
49
+ if maximum_size
50
+ maximum_padding_size = maximum_size - data.bytesize
51
+
52
+ if padding_size > maximum_padding_size
53
+ padding_size = maximum_padding_size
54
+ end
55
+ end
56
+
57
+ if padding_size > 0
58
+ set_flags(PADDED)
59
+
60
+ buffer = String.new.b
61
+
62
+ buffer << padding_size.chr
63
+ buffer << data
64
+ buffer << "\0" * padding_size
65
+
66
+ super buffer
67
+ else
68
+ clear_flags(PADDED)
69
+
70
+ super data
71
+ end
72
+ end
73
+
74
+ def unpack
75
+ if padded?
76
+ padding_size = @payload[0].ord
77
+ data_size = @payload.bytesize - 1 - padding_size
78
+
79
+ if data_size < 0
80
+ raise ProtocolError, "Invalid padding length: #{padding_size}"
81
+ end
82
+
83
+ return @payload.byteslice(1, data_size)
84
+ else
85
+ return @payload
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,82 @@
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 HTTP
24
+ module Protocol
25
+ module HTTP2
26
+ ACKNOWLEDGEMENT = 0x1
27
+
28
+ module Acknowledgement
29
+ def acknowledgement?
30
+ flag_set?(ACKNOWLEDGEMENT)
31
+ end
32
+
33
+ def acknowledge
34
+ frame = self.class.new
35
+
36
+ frame.length = 0
37
+ frame.set_flags(ACKNOWLEDGEMENT)
38
+
39
+ return frame
40
+ end
41
+ end
42
+
43
+ # 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.
44
+ #
45
+ # +---------------------------------------------------------------+
46
+ # | |
47
+ # | Opaque Data (64) |
48
+ # | |
49
+ # +---------------------------------------------------------------+
50
+ #
51
+ class PingFrame < Frame
52
+ TYPE = 0x6
53
+
54
+ include Acknowledgement
55
+
56
+ def connection?
57
+ true
58
+ end
59
+
60
+ def apply(connection)
61
+ connection.receive_ping(self)
62
+ end
63
+
64
+ def acknowledge
65
+ frame = super
66
+
67
+ frame.pack self.unpack
68
+
69
+ return frame
70
+ end
71
+
72
+ def read_payload(io)
73
+ super
74
+
75
+ if @length > 8
76
+ raise FrameSizeError, "Invalid frame length"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,82 @@
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 HTTP
24
+ module Protocol
25
+ module HTTP2
26
+ Priority = Struct.new(:exclusive, :stream_dependency, :weight) do
27
+ FORMAT = "NC".freeze
28
+ EXCLUSIVE = 1 << 31
29
+
30
+ def self.unpack(data)
31
+ stream_dependency, weight = data.unpack(FORMAT)
32
+
33
+ return self.new(stream_dependency & EXCLUSIVE != 0, stream_dependency & ~EXCLUSIVE, weight)
34
+ end
35
+
36
+ def pack
37
+ if exclusive
38
+ stream_dependency = self.stream_dependency | EXCLUSIVE
39
+ end
40
+
41
+ return [stream_dependency, self.weight].pack(FORMAT)
42
+ end
43
+ end
44
+
45
+ # The PRIORITY frame specifies the sender-advised priority of a stream. It can be sent in any stream state, including idle or closed streams.
46
+ #
47
+ # +-+-------------------------------------------------------------+
48
+ # |E| Stream Dependency (31) |
49
+ # +-+-------------+-----------------------------------------------+
50
+ # | Weight (8) |
51
+ # +-+-------------+
52
+ #
53
+ class PriorityFrame < Frame
54
+ TYPE = 0x2
55
+
56
+ def priority
57
+ Priority.unpack(@payload)
58
+ end
59
+
60
+ def pack priority
61
+ super priority.pack
62
+ end
63
+
64
+ def unpack
65
+ Priority.unpack(super)
66
+ end
67
+
68
+ def apply(connection)
69
+ connection.receive_priority(self)
70
+ end
71
+
72
+ def read_payload(io)
73
+ super
74
+
75
+ if @length != 5
76
+ raise FrameSizeError, "Invalid frame length"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,67 @@
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
+
24
+ module HTTP
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 end_headers?
46
+ flag_set?(END_HEADERS)
47
+ end
48
+
49
+ def unpack
50
+ data = super
51
+
52
+ stream_id = data.unpack(FORMAT).first
53
+
54
+ return stream_id, data.byteslice(4, data.bytesize - 4)
55
+ end
56
+
57
+ def pack(stream_id, data, *args)
58
+ super([stream_id].pack(FORMAT) + data, *args)
59
+ end
60
+
61
+ def apply(connection)
62
+ connection.receive_push_promise(self)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,74 @@
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 HTTP
24
+ module Protocol
25
+ module HTTP2
26
+ NO_ERROR = 0
27
+ PROTOCOL_ERROR = 1
28
+ INTERNAL_ERROR = 2
29
+ FLOW_CONTROL_ERROR = 3
30
+ TIMEOUT = 4
31
+ STREAM_CLOSED = 5
32
+ FRAME_SIZE_ERROR = 6
33
+ REFUSED_STREAM = 7
34
+ CANCEL = 8
35
+ COMPRESSION_ERROR = 9
36
+ CONNECT_ERROR = 10
37
+ ENHANCE_YOUR_CALM = 11
38
+ INADEQUATE_SECURITY = 12
39
+ HTTP_1_1_REQUIRED = 13
40
+
41
+ # 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.
42
+ #
43
+ # +---------------------------------------------------------------+
44
+ # | Error Code (32) |
45
+ # +---------------------------------------------------------------+
46
+ #
47
+ class ResetStreamFrame < Frame
48
+ TYPE = 0x3
49
+ FORMAT = "N".freeze
50
+
51
+ def unpack
52
+ @payload.unpack(FORMAT).first
53
+ end
54
+
55
+ def pack(error_code = NO_ERROR)
56
+ @payload = [error_code].pack(FORMAT)
57
+ @length = @payload.bytesize
58
+ end
59
+
60
+ def apply(connection)
61
+ connection.receive_reset_stream(self)
62
+ end
63
+
64
+ def read_payload(io)
65
+ super
66
+
67
+ if @length != 4
68
+ raise FrameSizeError, "Invalid frame length"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,47 @@
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 HTTP
24
+ module Protocol
25
+ module HTTP2
26
+ class Server < Connection
27
+ def initialize(framer, *args)
28
+ super(framer, 2, *args)
29
+ end
30
+
31
+ def read_connection_preface(settings)
32
+ if @state == :new
33
+ @framer.read_connection_preface
34
+
35
+ send_settings(settings)
36
+
37
+ read_frame do |frame|
38
+ raise ProtocolError, "First frame must be SettingsFrame, but got #{frame.class}" unless frame.is_a? SettingsFrame
39
+ end
40
+ else
41
+ raise ProtocolError, "Cannot send connection preface in state #{@state}"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end