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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 945640dfdad7948a782f37168282335b8183a2109da5b28070f152a8d57090ab
4
- data.tar.gz: 4b3ae61bddd8d51fa429f747f493a93ef16a8ae4e466210878b48827f3280fe6
3
+ metadata.gz: 6a8c075ce0b769f014a20587dd061f17e32361f211aad5741f655dafe6687e37
4
+ data.tar.gz: d14c0fe026a7db1aa46edded54e5ee6f1a0f8598f626dd1aff342ad07b5cec39
5
5
  SHA512:
6
- metadata.gz: a67714ea433353c56a2c68dbfee36a654511e99a910f11868bb1844dbccd024ac2d2cb2779d588be1238fdb90e49f1341093cf3cdb1e2518f6c3fabfbce1de70
7
- data.tar.gz: 356b55c653ec4949c651784b6acc032c41db5cb6262f8b80f488586541c9a9dc789215a1306dd4257599f1fe4a618cd5ed678ddffa4379b52b21b655b2eb4eba
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
- * Fix header formatting when header value is an array
7
+ - Fix header formatting when header value is an array
4
8
 
5
9
  ## 0.37 2021-02-15
6
10
 
7
- * Update upgrade mechanism to work with updated Qeweney API
11
+ - Update upgrade mechanism to work with updated Qeweney API
8
12
 
9
13
  ## 0.36 2021-02-12
10
14
 
11
- * Use `Qeweney::Status` constants
15
+ - Use `Qeweney::Status` constants
12
16
 
13
17
  ## 0.35 2021-02-10
14
18
 
15
- * Extract Request class into separate [qeweney](https://github.com/digital-fabric/qeweney) gem
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
- * Implement digital fabric service and agents
20
- * Add multipart and urlencoded form data parsing
21
- * Improve request body reading behaviour
22
- * Add more `Request` information methods
23
- * Add access to connection for HTTP2 requests
24
- * Allow calling `Request#send_chunk` with empty chunk
25
- * Add support for handling protocol upgrades from within request handler
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
- * Update code for Polyphony 0.47.5
30
- * Add support for Rack::File body to Tipi::RackAdapter
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
- * Respond with array of strings instead of concatenating for HTTP 1
35
- * Use read_loop instead of readpartial
36
- * Fix http upgrade test
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
- * Fix websocket server code
41
- * Implement configuration layer (WIP)
42
- * Improve performance of rack adapter
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
- * Rename project to Tipi
47
- * Rearrange source code
48
- * Remove HTTP client code (to be developed eventually into a separate gem)
49
- * Fix header rendering in rack adapter (#2)
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
- * Use IO#read_loop
57
+ - Use IO#read_loop
54
58
 
55
59
  ## 0.28 2020-07-03
56
60
 
57
- * Update with API changes from Polyphony >= 0.41
61
+ - Update with API changes from Polyphony >= 0.41
58
62
 
59
63
  ## 0.27 2020-04-14
60
64
 
61
- * Remove modulation dependency
65
+ - Remove modulation dependency
62
66
 
63
67
  ## 0.26 2020-03-03
64
68
 
65
- * Fix `Server#listen`
69
+ - Fix `Server#listen`
66
70
 
67
71
  ## 0.25 2020-02-19
68
72
 
69
- * Ensure server socket is closed upon stopping loop
70
- * Fix `Request#format_header_lines`
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
- * Move HTTP to separate polyphony-http gem
78
+ - Move HTTP to separate polyphony-http gem
75
79
 
76
80
  For earlier changes look at the Polyphony changelog.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tipi (0.37.2)
4
+ tipi (0.38)
5
5
  http-2 (~> 0.10.0)
6
6
  http_parser.rb (~> 0.6.0)
7
7
  msgpack (~> 1.4.2)
@@ -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.respond("Hello world!\n")
17
- rescue Exception => e
18
- p e
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
@@ -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.respond("Hello world!\n")
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
- req.send_headers(headers) if headers && !req.headers_sent?
154
- req.send_chunk(body, done: done) if body or done
155
- done
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
@@ -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
- if body
209
- if @parser.http_minor == 0
210
- data << body
211
- else
212
- # data << body.bytesize.to_s(16) << CRLF << body << CRLF_ZERO_CRLF_CRLF
213
- data << "#{body.bytesize.to_s(16)}\r\n#{body}\r\n0\r\n\r\n"
214
- end
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, opts = DEFAULT_HEADERS_OPTS)
231
- data = format_headers(headers, true)
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 empty_response [boolean] whether a response body will be sent
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 @parser.http_minor == 0
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tipi
4
- VERSION = '0.37.2'
4
+ VERSION = '0.38'
5
5
  end
@@ -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.0 200
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
- Transfer-Encoding: chunked
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.0 200\r\nContent-Length: 2\r\n\r\nHi", response)
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
- Transfer-Encoding: chunked
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.0 200\r\nContent-Length: 2\r\n\r\nHi", response)
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
- 2.times { snooze }
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
- Transfer-Encoding: chunked
139
-
140
- d
141
- Hello, world!
142
- 0
132
+ Content-Length: 13
143
133
 
144
- HTTP/1.1 200
145
- Transfer-Encoding: chunked
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
- 20.times { snooze }
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
- 20.times { snooze }
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
- 20.times { snooze }
173
+ sleep 0.01
187
174
  assert_equal %w[foobar bazbud], chunks
188
175
  assert request.complete?
189
176
 
190
- 2.times { snooze }
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
- Transfer-Encoding: chunked
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
- 12.times { snooze }
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
- snooze
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
- snooze
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
- snooze
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
- snooze
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.37.2
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-08 00:00:00.000000000 Z
11
+ date: 2021-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: polyphony