tipi 0.37.2 → 0.38
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 +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
|