tipi 0.37.2 → 0.38
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -30
- data/Gemfile.lock +1 -1
- data/examples/http_server.rb +11 -3
- data/examples/https_server.rb +11 -1
- data/lib/tipi/digital_fabric/agent_proxy.rb +8 -3
- data/lib/tipi/http1_adapter.rb +23 -25
- data/lib/tipi/version.rb +1 -1
- data/test/test_http_server.rb +20 -36
- data/test/test_request.rb +4 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a8c075ce0b769f014a20587dd061f17e32361f211aad5741f655dafe6687e37
|
4
|
+
data.tar.gz: d14c0fe026a7db1aa46edded54e5ee6f1a0f8598f626dd1aff342ad07b5cec39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e306783fc83d9d7ebd0678c4d68a13f6f9bd77e4b9d83fc84d745e5cc3f53eb27b69286fb1ba9f1ca54fe57358009a4c11dc9374c8a8d9046dc4330e359dc988
|
7
|
+
data.tar.gz: 789c3b4e1374cc57e04e3bce4aa8d12022cfd7e31c9cba4f5777302f57943da0a967f17f8cb2f91551357deac1bbd07fe514c2cb2e002331f525d341c6b7f0e9
|
data/CHANGELOG.md
CHANGED
@@ -1,76 +1,80 @@
|
|
1
|
+
## 0.38 2021-03-09
|
2
|
+
|
3
|
+
- Don't use chunked transfer encoding for non-streaming responses
|
4
|
+
|
1
5
|
## 0.37.2 2021-03-08
|
2
6
|
|
3
|
-
|
7
|
+
- Fix header formatting when header value is an array
|
4
8
|
|
5
9
|
## 0.37 2021-02-15
|
6
10
|
|
7
|
-
|
11
|
+
- Update upgrade mechanism to work with updated Qeweney API
|
8
12
|
|
9
13
|
## 0.36 2021-02-12
|
10
14
|
|
11
|
-
|
15
|
+
- Use `Qeweney::Status` constants
|
12
16
|
|
13
17
|
## 0.35 2021-02-10
|
14
18
|
|
15
|
-
|
19
|
+
- Extract Request class into separate [qeweney](https://github.com/digital-fabric/qeweney) gem
|
16
20
|
|
17
21
|
## 0.34 2021-02-07
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
- Implement digital fabric service and agents
|
24
|
+
- Add multipart and urlencoded form data parsing
|
25
|
+
- Improve request body reading behaviour
|
26
|
+
- Add more `Request` information methods
|
27
|
+
- Add access to connection for HTTP2 requests
|
28
|
+
- Allow calling `Request#send_chunk` with empty chunk
|
29
|
+
- Add support for handling protocol upgrades from within request handler
|
26
30
|
|
27
31
|
## 0.33 2020-11-20
|
28
32
|
|
29
|
-
|
30
|
-
|
33
|
+
- Update code for Polyphony 0.47.5
|
34
|
+
- Add support for Rack::File body to Tipi::RackAdapter
|
31
35
|
|
32
36
|
## 0.32 2020-08-14
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
- Respond with array of strings instead of concatenating for HTTP 1
|
39
|
+
- Use read_loop instead of readpartial
|
40
|
+
- Fix http upgrade test
|
37
41
|
|
38
42
|
## 0.31 2020-07-28
|
39
43
|
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
- Fix websocket server code
|
45
|
+
- Implement configuration layer (WIP)
|
46
|
+
- Improve performance of rack adapter
|
43
47
|
|
44
48
|
## 0.30 2020-07-15
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
+
- Rename project to Tipi
|
51
|
+
- Rearrange source code
|
52
|
+
- Remove HTTP client code (to be developed eventually into a separate gem)
|
53
|
+
- Fix header rendering in rack adapter (#2)
|
50
54
|
|
51
55
|
## 0.29 2020-07-06
|
52
56
|
|
53
|
-
|
57
|
+
- Use IO#read_loop
|
54
58
|
|
55
59
|
## 0.28 2020-07-03
|
56
60
|
|
57
|
-
|
61
|
+
- Update with API changes from Polyphony >= 0.41
|
58
62
|
|
59
63
|
## 0.27 2020-04-14
|
60
64
|
|
61
|
-
|
65
|
+
- Remove modulation dependency
|
62
66
|
|
63
67
|
## 0.26 2020-03-03
|
64
68
|
|
65
|
-
|
69
|
+
- Fix `Server#listen`
|
66
70
|
|
67
71
|
## 0.25 2020-02-19
|
68
72
|
|
69
|
-
|
70
|
-
|
73
|
+
- Ensure server socket is closed upon stopping loop
|
74
|
+
- Fix `Request#format_header_lines`
|
71
75
|
|
72
76
|
## 0.24 2020-01-08
|
73
77
|
|
74
|
-
|
78
|
+
- Move HTTP to separate polyphony-http gem
|
75
79
|
|
76
80
|
For earlier changes look at the Polyphony changelog.
|
data/Gemfile.lock
CHANGED
data/examples/http_server.rb
CHANGED
@@ -13,9 +13,17 @@ puts 'Listening on port 4411...'
|
|
13
13
|
|
14
14
|
spin do
|
15
15
|
Tipi.serve('0.0.0.0', 4411, opts) do |req|
|
16
|
-
req.
|
17
|
-
|
18
|
-
|
16
|
+
p path: req.path
|
17
|
+
if req.path == '/stream'
|
18
|
+
req.send_headers('Foo' => 'Bar')
|
19
|
+
sleep 1
|
20
|
+
req.send_chunk("foo\n")
|
21
|
+
sleep 1
|
22
|
+
req.send_chunk("bar\n")
|
23
|
+
req.finish
|
24
|
+
else
|
25
|
+
req.respond("Hello world!\n")
|
26
|
+
end
|
19
27
|
end
|
20
28
|
p 'done...'
|
21
29
|
end.await
|
data/examples/https_server.rb
CHANGED
@@ -16,7 +16,17 @@ opts = {
|
|
16
16
|
puts "pid: #{Process.pid}"
|
17
17
|
puts 'Listening on port 1234...'
|
18
18
|
Tipi.serve('0.0.0.0', 1234, opts) do |req|
|
19
|
-
req.
|
19
|
+
p path: req.path
|
20
|
+
if req.path == '/stream'
|
21
|
+
req.send_headers('Foo' => 'Bar')
|
22
|
+
sleep 1
|
23
|
+
req.send_chunk("foo\n")
|
24
|
+
sleep 1
|
25
|
+
req.send_chunk("bar\n")
|
26
|
+
req.finish
|
27
|
+
else
|
28
|
+
req.respond("Hello world!\n")
|
29
|
+
end
|
20
30
|
# req.send_headers
|
21
31
|
# req.send_chunk("Method: #{req.method}\n")
|
22
32
|
# req.send_chunk("Path: #{req.path}\n")
|
@@ -150,9 +150,14 @@ module DigitalFabric
|
|
150
150
|
headers = message['headers']
|
151
151
|
body = message['body']
|
152
152
|
done = message['complete']
|
153
|
-
|
154
|
-
|
155
|
-
|
153
|
+
if !req.headers_sent? && done
|
154
|
+
req.respond(body, headers|| {})
|
155
|
+
true
|
156
|
+
else
|
157
|
+
req.send_headers(headers) if headers && !req.headers_sent?
|
158
|
+
req.send_chunk(body, done: done) if body or done
|
159
|
+
done
|
160
|
+
end
|
156
161
|
else
|
157
162
|
# invalid message
|
158
163
|
true
|
data/lib/tipi/http1_adapter.rb
CHANGED
@@ -204,31 +204,28 @@ module Tipi
|
|
204
204
|
# @param headers
|
205
205
|
def respond(body, headers)
|
206
206
|
consume_request if @parsing
|
207
|
-
data = [format_headers(headers, body)]
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
end
|
207
|
+
data = [format_headers(headers, body, false), body]
|
208
|
+
|
209
|
+
# if body
|
210
|
+
# if @parser.http_minor == 0
|
211
|
+
# data << body
|
212
|
+
# else
|
213
|
+
# # data << body.bytesize.to_s(16) << CRLF << body << CRLF_ZERO_CRLF_CRLF
|
214
|
+
# data << "#{body.bytesize.to_s(16)}\r\n#{body}\r\n0\r\n\r\n"
|
215
|
+
# end
|
216
|
+
# end
|
216
217
|
# Polyphony.backend_sendv(@conn, data, 0)
|
217
218
|
@conn.write(*data)
|
218
219
|
end
|
219
220
|
|
220
|
-
DEFAULT_HEADERS_OPTS = {
|
221
|
-
empty_response: false,
|
222
|
-
consume_request: true
|
223
|
-
}.freeze
|
224
|
-
|
225
221
|
# Sends response headers. If empty_response is truthy, the response status
|
226
222
|
# code will default to 204, otherwise to 200.
|
227
223
|
# @param headers [Hash] response headers
|
228
224
|
# @param empty_response [boolean] whether a response body will be sent
|
225
|
+
# @param chunked [boolean] whether to use chunked transfer encoding
|
229
226
|
# @return [void]
|
230
|
-
def send_headers(headers,
|
231
|
-
data = format_headers(headers,
|
227
|
+
def send_headers(headers, empty_response: false, chunked: true)
|
228
|
+
data = format_headers(headers, !empty_response, @parser.http_minor == 1 && chunked)
|
232
229
|
@conn.write(data)
|
233
230
|
end
|
234
231
|
|
@@ -261,12 +258,13 @@ module Tipi
|
|
261
258
|
# Formats response headers into an array. If empty_response is true(thy),
|
262
259
|
# the response status code will default to 204, otherwise to 200.
|
263
260
|
# @param headers [Hash] response headers
|
264
|
-
# @param
|
261
|
+
# @param body [boolean] whether a response body will be sent
|
262
|
+
# @param chunked [boolean] whether to use chunked transfer encoding
|
265
263
|
# @return [String] formatted response headers
|
266
|
-
def format_headers(headers, body)
|
264
|
+
def format_headers(headers, body, chunked)
|
267
265
|
status = headers[':status']
|
268
266
|
status ||= (body ? Qeweney::Status::OK : Qeweney::Status::NO_CONTENT)
|
269
|
-
lines = format_status_line(body, status)
|
267
|
+
lines = format_status_line(body, status, chunked)
|
270
268
|
headers.each do |k, v|
|
271
269
|
next if k =~ /^:/
|
272
270
|
|
@@ -276,11 +274,11 @@ module Tipi
|
|
276
274
|
lines
|
277
275
|
end
|
278
276
|
|
279
|
-
def format_status_line(body, status)
|
277
|
+
def format_status_line(body, status, chunked)
|
280
278
|
if !body
|
281
279
|
empty_status_line(status)
|
282
280
|
else
|
283
|
-
with_body_status_line(status, body)
|
281
|
+
with_body_status_line(status, body, chunked)
|
284
282
|
end
|
285
283
|
end
|
286
284
|
|
@@ -292,11 +290,11 @@ module Tipi
|
|
292
290
|
end
|
293
291
|
end
|
294
292
|
|
295
|
-
def with_body_status_line(status, body)
|
296
|
-
if
|
297
|
-
+"HTTP/1.0 #{status}\r\nContent-Length: #{body.bytesize}\r\n"
|
298
|
-
else
|
293
|
+
def with_body_status_line(status, body, chunked)
|
294
|
+
if chunked
|
299
295
|
+"HTTP/1.1 #{status}\r\nTransfer-Encoding: chunked\r\n"
|
296
|
+
else
|
297
|
+
+"HTTP/1.1 #{status}\r\nContent-Length: #{body.bytesize}\r\n"
|
300
298
|
end
|
301
299
|
end
|
302
300
|
|
data/lib/tipi/version.rb
CHANGED
data/test/test_http_server.rb
CHANGED
@@ -60,8 +60,8 @@ class HTTP1ServerTest < MiniTest::Test
|
|
60
60
|
connection << "GET / HTTP/1.0\r\n\r\n"
|
61
61
|
|
62
62
|
response = connection.readpartial(8192)
|
63
|
-
expected = <<~HTTP.chomp.http_lines
|
64
|
-
HTTP/1.
|
63
|
+
expected = <<~HTTP.chomp.http_lines.chomp
|
64
|
+
HTTP/1.1 200
|
65
65
|
Content-Length: 13
|
66
66
|
|
67
67
|
Hello, world!
|
@@ -78,14 +78,11 @@ class HTTP1ServerTest < MiniTest::Test
|
|
78
78
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
79
79
|
|
80
80
|
response = connection.readpartial(8192)
|
81
|
-
expected = <<~HTTP.http_lines
|
81
|
+
expected = <<~HTTP.http_lines.chomp
|
82
82
|
HTTP/1.1 200
|
83
|
-
|
83
|
+
Content-Length: 13
|
84
84
|
|
85
|
-
d
|
86
85
|
Hello, world!
|
87
|
-
0
|
88
|
-
|
89
86
|
HTTP
|
90
87
|
assert_equal(expected, response)
|
91
88
|
end
|
@@ -98,26 +95,23 @@ class HTTP1ServerTest < MiniTest::Test
|
|
98
95
|
connection << "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"
|
99
96
|
response = connection.readpartial(8192)
|
100
97
|
assert !connection.eof?
|
101
|
-
assert_equal("HTTP/1.
|
98
|
+
assert_equal("HTTP/1.1 200\r\nContent-Length: 2\r\n\r\nHi", response)
|
102
99
|
|
103
100
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
104
101
|
response = connection.readpartial(8192)
|
105
102
|
assert !connection.eof?
|
106
|
-
expected = <<~HTTP.http_lines
|
103
|
+
expected = <<~HTTP.http_lines.chomp
|
107
104
|
HTTP/1.1 200
|
108
|
-
|
105
|
+
Content-Length: 2
|
109
106
|
|
110
|
-
2
|
111
107
|
Hi
|
112
|
-
0
|
113
|
-
|
114
108
|
HTTP
|
115
109
|
assert_equal(expected, response)
|
116
110
|
|
117
111
|
connection << "GET / HTTP/1.0\r\n\r\n"
|
118
112
|
response = connection.readpartial(8192)
|
119
113
|
assert connection.eof?
|
120
|
-
assert_equal("HTTP/1.
|
114
|
+
assert_equal("HTTP/1.1 200\r\nContent-Length: 2\r\n\r\nHi", response)
|
121
115
|
end
|
122
116
|
|
123
117
|
def test_pipelining_client
|
@@ -130,24 +124,17 @@ class HTTP1ServerTest < MiniTest::Test
|
|
130
124
|
end
|
131
125
|
|
132
126
|
connection << "GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\nFoo: bar\r\n\r\n"
|
133
|
-
|
127
|
+
sleep 0.01
|
134
128
|
response = connection.readpartial(8192)
|
135
129
|
|
136
|
-
expected = <<~HTTP.http_lines
|
130
|
+
expected = <<~HTTP.http_lines.chomp
|
137
131
|
HTTP/1.1 200
|
138
|
-
|
139
|
-
|
140
|
-
d
|
141
|
-
Hello, world!
|
142
|
-
0
|
132
|
+
Content-Length: 13
|
143
133
|
|
144
|
-
HTTP/1.1 200
|
145
|
-
|
134
|
+
Hello, world!HTTP/1.1 200
|
135
|
+
Content-Length: 14
|
146
136
|
|
147
|
-
e
|
148
137
|
Hello, foobar!
|
149
|
-
0
|
150
|
-
|
151
138
|
HTTP
|
152
139
|
assert_equal(expected, response)
|
153
140
|
end
|
@@ -172,22 +159,22 @@ class HTTP1ServerTest < MiniTest::Test
|
|
172
159
|
6
|
173
160
|
foobar
|
174
161
|
HTTP
|
175
|
-
|
162
|
+
sleep 0.01
|
176
163
|
assert request
|
177
164
|
assert_equal %w[foobar], chunks
|
178
165
|
assert !request.complete?
|
179
166
|
|
180
167
|
connection << "6\r\nbazbud\r\n"
|
181
|
-
|
168
|
+
sleep 0.01
|
182
169
|
assert_equal %w[foobar bazbud], chunks
|
183
170
|
assert !request.complete?
|
184
171
|
|
185
172
|
connection << "0\r\n\r\n"
|
186
|
-
|
173
|
+
sleep 0.01
|
187
174
|
assert_equal %w[foobar bazbud], chunks
|
188
175
|
assert request.complete?
|
189
176
|
|
190
|
-
|
177
|
+
sleep 0.01
|
191
178
|
|
192
179
|
response = connection.readpartial(8192)
|
193
180
|
|
@@ -232,14 +219,11 @@ class HTTP1ServerTest < MiniTest::Test
|
|
232
219
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
233
220
|
response = connection.readpartial(8192)
|
234
221
|
assert !connection.eof?
|
235
|
-
expected = <<~HTTP.http_lines
|
222
|
+
expected = <<~HTTP.http_lines.chomp
|
236
223
|
HTTP/1.1 200
|
237
|
-
|
224
|
+
Content-Length: 2
|
238
225
|
|
239
|
-
2
|
240
226
|
Hi
|
241
|
-
0
|
242
|
-
|
243
227
|
HTTP
|
244
228
|
assert_equal(expected, response)
|
245
229
|
|
@@ -272,7 +256,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
272
256
|
connection.close
|
273
257
|
assert !done
|
274
258
|
|
275
|
-
|
259
|
+
sleep 0.01
|
276
260
|
assert done
|
277
261
|
end
|
278
262
|
|
data/test/test_request.rb
CHANGED
@@ -60,7 +60,7 @@ class RequestHeadersTest < MiniTest::Test
|
|
60
60
|
|
61
61
|
connection << "GET /titi HTTP/1.1\r\nHost: blah.com\r\nFoo: bar\r\nhi: 1\r\nHi: 2\r\nhi: 3\r\n\r\n"
|
62
62
|
|
63
|
-
|
63
|
+
sleep 0.01
|
64
64
|
|
65
65
|
assert_kind_of Qeweney::Request, req
|
66
66
|
assert_equal 'blah.com', req.headers['host']
|
@@ -78,7 +78,7 @@ class RequestHeadersTest < MiniTest::Test
|
|
78
78
|
end
|
79
79
|
|
80
80
|
connection << "GET /titi HTTP/1.1\nHost: blah.com\nFoo: bar\nhi: 1\nHi: 2\nhi: 3\n\n"
|
81
|
-
|
81
|
+
sleep 0.01
|
82
82
|
assert_equal 'blah.com', req.host
|
83
83
|
end
|
84
84
|
|
@@ -90,7 +90,7 @@ class RequestHeadersTest < MiniTest::Test
|
|
90
90
|
end
|
91
91
|
|
92
92
|
connection << "GET /titi HTTP/1.1\nConnection: keep-alive\nFoo: bar\nhi: 1\nHi: 2\nhi: 3\n\n"
|
93
|
-
|
93
|
+
sleep 0.01
|
94
94
|
assert_equal 'keep-alive', req.connection
|
95
95
|
end
|
96
96
|
|
@@ -102,7 +102,7 @@ class RequestHeadersTest < MiniTest::Test
|
|
102
102
|
end
|
103
103
|
|
104
104
|
connection << "GET /titi HTTP/1.1\nConnection: upgrade\nUpgrade: foobar\n\n"
|
105
|
-
|
105
|
+
sleep 0.01
|
106
106
|
assert_equal 'foobar', req.upgrade_protocol
|
107
107
|
end
|
108
108
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tipi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.38'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: polyphony
|