qeweney 0.13 → 0.16

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: 742be1b1238ea117928a544134e57702776b707caf0cccdf68b74225ff3990d7
4
- data.tar.gz: 357beb13e5f99b3f776de0a9e30447a034a647af208c1d69adedc118cabe8be1
3
+ metadata.gz: e47873e013c1c06c36014fdc550160b271e22328a906ee95b86fe9d16aaffb81
4
+ data.tar.gz: 0e6628b1948c1aff876e08822712e22e46083861dcf1c7467d540ba15cd6d3c8
5
5
  SHA512:
6
- metadata.gz: 2b0249f07ce24a2acb3d9d20a9a43927de50217b9b27d23b911819c50ad6ca6312c395c966ebd57fda8db69908de392667ed3294ced76d4143b1ecbc37820cef
7
- data.tar.gz: c80e535de1921e6b655a019c74a1a35fc808a9a7088ef368b84a485b42582d37d03ac9eb53250fd73277fe077cdd6c28ae6a4f60b814931fd6150f22ab929a42
6
+ metadata.gz: dfdf28acfa73a50c7f3a42808a406a0b23b332e04e039fe22d67883f9b31f3cc93e54eba273251cca6f38b90a737e0d3e143814cb1907428d9e9606da0a412b0
7
+ data.tar.gz: cb61de0b69e783ddd1f817fe606d4ce32a007efeea0d3afb5e259ed9a51f3351ed5f55ffa8316dc6fa0ccded957036f6c163d89644046beae913f0919e49a9d5
@@ -0,0 +1 @@
1
+ github: ciconia
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.16 2022-01-22
2
+
3
+ - Use frozen empty hash as default headers in response methods
4
+ - Add `text` key in registered MIME types
5
+
6
+ ## 0.15 2022-01-08
7
+
8
+ - Add `TestAdapter` class for testing requests and responses
9
+ - Add `RoutingMethods#reject` method
10
+
11
+ ## 0.14 2021-08-10
12
+
13
+ - Fix Request#on with paths containing slashes
14
+
15
+ ## 0.13.1 2021-08-03
16
+
17
+ - Fix `Request#read`
18
+
1
19
  ## 0.13 2021-08-02
2
20
 
3
21
  - Restore `Request#complete?` method
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- qeweney (0.13)
4
+ qeweney (0.16)
5
5
  escape_utils (~> 1.2.1)
6
6
 
7
7
  GEM
@@ -21,7 +21,7 @@ GEM
21
21
  ruby-progressbar (1.11.0)
22
22
 
23
23
  PLATFORMS
24
- ruby
24
+ x86_64-linux
25
25
 
26
26
  DEPENDENCIES
27
27
  benchmark-ips (~> 2.8.3)
@@ -31,4 +31,4 @@ DEPENDENCIES
31
31
  rake (~> 12.3.3)
32
32
 
33
33
  BUNDLED WITH
34
- 2.1.4
34
+ 2.3.3
@@ -104,7 +104,7 @@ OptimizedRubyApp = ->(r) do
104
104
  else
105
105
  return r.respond('Hello')
106
106
  end
107
- elsif method == 'post'
107
+ elsif method == 'post'
108
108
  # puts 'Someone said Hello'
109
109
  return r.redirect('/')
110
110
  end
@@ -8,6 +8,7 @@ module Qeweney
8
8
  'css' => 'text/css',
9
9
  'js' => 'application/javascript',
10
10
  'txt' => 'text/plain',
11
+ 'text' => 'text/plain',
11
12
 
12
13
  'gif' => 'image/gif',
13
14
  'jpg' => 'image/jpeg',
data/lib/qeweney/rack.rb CHANGED
@@ -74,15 +74,15 @@ module Qeweney
74
74
  def initialize(request)
75
75
  @request = request
76
76
  end
77
-
77
+
78
78
  def gets; end
79
-
79
+
80
80
  def read(length = nil, outbuf = nil); end
81
-
81
+
82
82
  def each(&block)
83
83
  @request.each_chunk(&block)
84
84
  end
85
-
85
+
86
86
  def rewind; end
87
87
  end
88
88
 
@@ -110,7 +110,7 @@ module Qeweney
110
110
  'rack.multipart.buffer_size' => nil,
111
111
  'rack.multipar.tempfile_factory' => nil
112
112
  }
113
-
113
+
114
114
  HTTP_HEADER_RE = /^HTTP_(.+)$/.freeze
115
115
 
116
116
  def self.rack_env_value_from_request(request, key)
@@ -15,13 +15,12 @@ module Qeweney
15
15
  extend RequestInfoClassMethods
16
16
 
17
17
  attr_reader :headers, :adapter
18
- attr_accessor :__next__
19
-
18
+
20
19
  def initialize(headers, adapter)
21
20
  @headers = headers
22
21
  @adapter = adapter
23
22
  end
24
-
23
+
25
24
  def buffer_body_chunk(chunk)
26
25
  @buffered_body_chunks ||= []
27
26
  @buffered_body_chunks << chunk
@@ -38,7 +37,7 @@ module Qeweney
38
37
 
39
38
  @adapter.get_body_chunk(self, buffered_only)
40
39
  end
41
-
40
+
42
41
  def each_chunk
43
42
  if @buffered_body_chunks
44
43
  while (chunk = @buffered_body_chunks.shift)
@@ -52,6 +51,15 @@ module Qeweney
52
51
  end
53
52
 
54
53
  def read
54
+ if @buffered_body_chunks
55
+ body = @buffered_body_chunks.join
56
+ if !complete?
57
+ rest = @adapter.get_body(self)
58
+ body << rest if rest
59
+ end
60
+ @buffered_body_chunks = nil
61
+ return body
62
+ end
55
63
  @adapter.get_body(self)
56
64
  end
57
65
  alias_method :body, :read
@@ -59,29 +67,31 @@ module Qeweney
59
67
  def complete?
60
68
  @adapter.complete?(self)
61
69
  end
62
-
63
- def respond(body, headers = {})
70
+
71
+ EMPTY_HEADERS = {}.freeze
72
+
73
+ def respond(body, headers = EMPTY_HEADERS)
64
74
  @adapter.respond(self, body, headers)
65
75
  @headers_sent = true
66
76
  end
67
-
68
- def send_headers(headers = {}, empty_response = false)
77
+
78
+ def send_headers(headers = EMPTY_HEADERS, empty_response = false)
69
79
  return if @headers_sent
70
-
80
+
71
81
  @headers_sent = true
72
82
  @adapter.send_headers(self, headers, empty_response: empty_response)
73
83
  end
74
-
84
+
75
85
  def send_chunk(body, done: false)
76
86
  send_headers({}) unless @headers_sent
77
-
87
+
78
88
  @adapter.send_chunk(self, body, done: done)
79
89
  end
80
90
  alias_method :<<, :send_chunk
81
-
91
+
82
92
  def finish
83
93
  send_headers({}) unless @headers_sent
84
-
94
+
85
95
  @adapter.finish(self)
86
96
  end
87
97
 
@@ -25,43 +25,42 @@ module Qeweney
25
25
  def protocol
26
26
  @protocol ||= @adapter.protocol
27
27
  end
28
-
28
+
29
29
  def method
30
30
  @method ||= @headers[':method'].downcase
31
31
  end
32
-
32
+
33
33
  def scheme
34
34
  @scheme ||= @headers[':scheme']
35
35
  end
36
-
36
+
37
37
  def uri
38
38
  @uri ||= URI.parse(@headers[':path'] || '')
39
39
  end
40
-
40
+
41
41
  def full_uri
42
42
  @full_uri = "#{scheme}://#{host}#{uri}"
43
43
  end
44
-
44
+
45
45
  def path
46
46
  @path ||= uri.path
47
47
  end
48
-
48
+
49
49
  def query_string
50
50
  @query_string ||= uri.query
51
51
  end
52
-
52
+
53
53
  def query
54
54
  return @query if @query
55
-
55
+
56
56
  @query = (q = uri.query) ? parse_query(q) : {}
57
57
  end
58
-
58
+
59
59
  QUERY_KV_REGEXP = /([^=]+)(?:=(.*))?/
60
-
60
+
61
61
  def parse_query(query)
62
62
  query.split('&').each_with_object({}) do |kv, h|
63
63
  k, v = kv.match(QUERY_KV_REGEXP)[1..2]
64
- # k, v = kv.split('=')
65
64
  h[k.to_sym] = v ? URI.decode_www_form_component(v) : true
66
65
  end
67
66
  end
@@ -89,13 +88,13 @@ module Qeweney
89
88
 
90
89
  COOKIE_RE = /^([^=]+)=(.*)$/.freeze
91
90
  SEMICOLON = ';'
92
-
91
+
93
92
  def parse_cookies(cookies)
94
93
  return {} unless cookies
95
94
 
96
95
  cookies.split(SEMICOLON).each_with_object({}) do |c, h|
97
96
  raise BadRequestError, 'Invalid cookie format' unless c.strip =~ COOKIE_RE
98
-
97
+
99
98
  key, value = Regexp.last_match[1..2]
100
99
  h[key] = EscapeUtils.unescape_uri(value)
101
100
  end
@@ -151,7 +150,7 @@ module Qeweney
151
150
  break if header.empty?
152
151
 
153
152
  next unless header =~ /^([^\:]+)\:\s?(.+)$/
154
-
153
+
155
154
  headers[Regexp.last_match(1).downcase] = Regexp.last_match(2)
156
155
  end
157
156
  # remove trailing \r\n
@@ -164,16 +163,18 @@ module Qeweney
164
163
  MAX_PARAMETER_VALUE_SIZE = 2**20 # 1MB
165
164
 
166
165
  def parse_urlencoded_form_data(body)
166
+ return {} unless body
167
+
167
168
  body.force_encoding(Encoding::UTF_8) unless body.encoding == Encoding::UTF_8
168
169
  body.split('&').each_with_object({}) do |i, m|
169
170
  raise 'Invalid parameter format' unless i =~ PARAMETER_RE
170
-
171
+
171
172
  k = Regexp.last_match(1)
172
173
  raise 'Invalid parameter size' if k.size > MAX_PARAMETER_NAME_SIZE
173
-
174
+
174
175
  v = Regexp.last_match(2)
175
176
  raise 'Invalid parameter size' if v.size > MAX_PARAMETER_VALUE_SIZE
176
-
177
+
177
178
  m[EscapeUtils.unescape_uri(k)] = EscapeUtils.unescape_uri(v)
178
179
  end
179
180
  end
@@ -14,7 +14,7 @@ module Qeweney
14
14
  def file_stat_to_etag(stat)
15
15
  "#{stat.mtime.to_i.to_s(36)}#{stat.size.to_s(36)}"
16
16
  end
17
-
17
+
18
18
  def file_stat_to_last_modified(stat)
19
19
  stat.mtime.httpdate
20
20
  end
@@ -114,7 +114,7 @@ module Qeweney
114
114
  if (modified_since = headers['if-modified-since'])
115
115
  return true if modified_since == last_modified
116
116
  end
117
-
117
+
118
118
  false
119
119
  end
120
120
 
@@ -7,10 +7,11 @@ module Qeweney
7
7
 
8
8
  module RoutingMethods
9
9
  def route(&block)
10
- (@path_parts ||= path.split('/'))[@path_parts_idx ||= 1]
10
+ @path_parts ||= path.split('/')
11
+ @path_parts_idx ||= 1
11
12
  res = catch(:stop) { yield self }
12
13
  return if res == :found
13
-
14
+
14
15
  respond(nil, ':status' => 404)
15
16
  end
16
17
 
@@ -29,22 +30,24 @@ module Qeweney
29
30
  @path_parts.empty? ? '/' : "/#{@path_parts[@path_parts_idx..-1].join('/')}"
30
31
  end
31
32
 
32
- def enter_route
33
- @path_parts_idx += 1
33
+ def enter_route(depth = 1)
34
+ @path_parts_idx += depth
34
35
  end
35
36
 
36
- def leave_route
37
- @path_parts_idx -= 1
37
+ def leave_route(depth = 1)
38
+ @path_parts_idx -= depth
38
39
  end
39
40
 
40
- def on(route = nil, &block)
41
- if route
42
- return unless @path_parts[@path_parts_idx] == route
43
- end
44
-
45
- enter_route
41
+ def on(route, &block)
42
+ return route_found(&block) unless route
43
+
44
+ route_parts = route.split('/')
45
+ route_length = route_parts.size
46
+ return unless @path_parts[@path_parts_idx, route_length] == route_parts
47
+
48
+ enter_route(route_length)
46
49
  route_found(&block)
47
- leave_route
50
+ leave_route(route_length)
48
51
  end
49
52
 
50
53
  def is(route = '/', &block)
@@ -70,22 +73,22 @@ module Qeweney
70
73
 
71
74
  route_found(&block)
72
75
  end
73
-
76
+
74
77
  def on_get(route = nil, &block)
75
78
  return unless method == 'get'
76
-
79
+
77
80
  on(route, &block)
78
81
  end
79
-
82
+
80
83
  def on_post(route = nil, &block)
81
84
  return unless method == 'post'
82
-
85
+
83
86
  on(route, &block)
84
87
  end
85
88
 
86
89
  def on_options(route = nil, &block)
87
90
  return unless method == 'options'
88
-
91
+
89
92
  on(route, &block)
90
93
  end
91
94
 
@@ -122,6 +125,11 @@ module Qeweney
122
125
  on_upgrade('websocket', &block)
123
126
  end
124
127
 
128
+ def reject(body, status)
129
+ respond(body, ':status' => status)
130
+ throw :stop, :found
131
+ end
132
+
125
133
  def stop_routing
126
134
  throw :stop, :found
127
135
  end
@@ -5,7 +5,7 @@ module Qeweney
5
5
  module Status
6
6
  # translated from https://golang.org/pkg/net/http/#pkg-constants
7
7
  # https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
8
-
8
+
9
9
  CONTINUE = 100 # RFC 7231, 6.2.1
10
10
  SWITCHING_PROTOCOLS = 101 # RFC 7231, 6.2.2
11
11
  PROCESSING = 102 # RFC 2518, 10.1
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qeweney
4
+ class TestAdapter
5
+ attr_reader :body, :headers
6
+
7
+ def get_body_chunk
8
+ nil
9
+ end
10
+
11
+ def respond(req, body, headers)
12
+ @body = body
13
+ @headers = headers
14
+ end
15
+
16
+ def status
17
+ headers[':status']
18
+ end
19
+
20
+ def self.mock(headers = {})
21
+ headers[':method'] ||= ''
22
+ headers[':path'] ||= ''
23
+ Request.new(headers, new)
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Qeweney
4
- VERSION = '0.13'
4
+ VERSION = '0.16'
5
5
  end
data/lib/qeweney.rb CHANGED
@@ -5,4 +5,3 @@ end
5
5
 
6
6
  require_relative 'qeweney/request.rb'
7
7
  require_relative 'qeweney/status.rb'
8
-
data/test/helper.rb CHANGED
@@ -8,7 +8,6 @@ require 'fileutils'
8
8
  require_relative './coverage' if ENV['COVERAGE']
9
9
 
10
10
  require 'minitest/autorun'
11
- require 'minitest/reporters'
12
11
 
13
12
  module Qeweney
14
13
  class MockAdapter
@@ -35,7 +34,3 @@ module Qeweney
35
34
  end
36
35
  end
37
36
  end
38
-
39
- Minitest::Reporters.use! [
40
- Minitest::Reporters::SpecReporter.new
41
- ]
@@ -73,7 +73,7 @@ class StaticFileResponeTest < MiniTest::Test
73
73
 
74
74
  deflate = Zlib::Deflate.new
75
75
  deflated_content = deflate.deflate(@content, Zlib::FINISH)
76
-
76
+
77
77
  assert_equal [
78
78
  [:respond, r, deflated_content, {
79
79
  'etag' => @etag,
@@ -94,7 +94,7 @@ class StaticFileResponeTest < MiniTest::Test
94
94
  z.flush
95
95
  z.close
96
96
  gzipped_content = buf.string
97
-
97
+
98
98
  assert_equal [
99
99
  [:respond, r, gzipped_content, {
100
100
  'etag' => @etag,
@@ -127,7 +127,7 @@ class UpgradeTest < MiniTest::Test
127
127
  }]
128
128
  ], r.response_calls
129
129
 
130
-
130
+
131
131
  r = Qeweney.mock
132
132
  r.upgrade('df', { 'foo' => 'bar' })
133
133
 
@@ -148,7 +148,7 @@ class UpgradeTest < MiniTest::Test
148
148
  'sec-websocket-version' => '23',
149
149
  'sec-websocket-key' => 'abcdefghij'
150
150
  )
151
-
151
+
152
152
  assert_equal 'websocket', r.upgrade_protocol
153
153
 
154
154
  r.upgrade_to_websocket('foo' => 'baz')
data/test/test_routing.rb CHANGED
@@ -81,7 +81,7 @@ class RoutingTest < MiniTest::Test
81
81
  default_relative_path = r.route_relative_path
82
82
  r.on_root { r.respond(File.join('ROOT', r.route_relative_path)) }
83
83
  r.on('foo') { r.respond(File.join('FOO', r.route_relative_path)) }
84
- r.on('bar') {
84
+ r.on('bar') {
85
85
  r.on('baz') { r.respond(File.join('BAR/BAZ', r.route_relative_path)) }
86
86
  r.default { r.respond(File.join('BAR', r.route_relative_path)) }
87
87
  }
@@ -114,4 +114,16 @@ class RoutingTest < MiniTest::Test
114
114
  assert_equal '/baz/d/e/f', default_relative_path
115
115
  assert_equal [[:respond, r, '/d/e/f', {}]], r.response_calls
116
116
  end
117
+
118
+ def test_well_known
119
+ app = Qeweney.route do |r|
120
+ r.on('.well-known/acme-challenge') { r.respond(r.route_relative_path) }
121
+ r.default { r.respond('not found') }
122
+ end
123
+
124
+ r = Qeweney.mock(':path' => '/.well-known/acme-challenge/foo')
125
+ app.(r)
126
+ assert_equal [[:respond, r, '/foo', {}]], r.response_calls
127
+ end
117
128
  end
129
+
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'qeweney/test_adapter'
5
+
6
+ class TestAdapterTest < MiniTest::Test
7
+ def test_test_adapter
8
+ adapter = Qeweney::TestAdapter.new
9
+ req = Qeweney::Request.new({ ':path' => '/foo' }, adapter)
10
+ req.respond('bar', 'Content-Type' => 'baz')
11
+
12
+ assert_equal 'bar', adapter.body
13
+ assert_equal({'Content-Type' => 'baz'}, adapter.headers)
14
+ end
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qeweney
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.13'
4
+ version: '0.16'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-02 00:00:00.000000000 Z
11
+ date: 2022-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils
@@ -80,13 +80,14 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 2.8.3
83
- description:
83
+ description:
84
84
  email: sharon@noteflakes.com
85
85
  executables: []
86
86
  extensions: []
87
87
  extra_rdoc_files:
88
88
  - README.md
89
89
  files:
90
+ - ".github/FUNDING.yml"
90
91
  - ".github/workflows/test.yml"
91
92
  - ".gitignore"
92
93
  - CHANGELOG.md
@@ -105,6 +106,7 @@ files:
105
106
  - lib/qeweney/response.rb
106
107
  - lib/qeweney/routing.rb
107
108
  - lib/qeweney/status.rb
109
+ - lib/qeweney/test_adapter.rb
108
110
  - lib/qeweney/version.rb
109
111
  - qeweney.gemspec
110
112
  - test/helper.rb
@@ -112,12 +114,13 @@ files:
112
114
  - test/test_request_info.rb
113
115
  - test/test_response.rb
114
116
  - test/test_routing.rb
117
+ - test/test_test_adapter.rb
115
118
  homepage: http://github.com/digital-fabric/qeweney
116
119
  licenses:
117
120
  - MIT
118
121
  metadata:
119
122
  source_code_uri: https://github.com/digital-fabric/qeweney
120
- post_install_message:
123
+ post_install_message:
121
124
  rdoc_options:
122
125
  - "--title"
123
126
  - Qeweney
@@ -136,8 +139,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
139
  - !ruby/object:Gem::Version
137
140
  version: '0'
138
141
  requirements: []
139
- rubygems_version: 3.1.6
140
- signing_key:
142
+ rubygems_version: 3.3.3
143
+ signing_key:
141
144
  specification_version: 4
142
145
  summary: Qeweney - cross library HTTP request / response API
143
146
  test_files: []