rack 2.0.9 → 2.1.4
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 +77 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +77 -117
- data/Rakefile +25 -18
- data/SPEC +3 -4
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack.rb +63 -60
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +2 -0
- data/lib/rack/body_proxy.rb +3 -6
- data/lib/rack/builder.rb +39 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -8
- data/lib/rack/conditional_get.rb +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +3 -1
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +32 -17
- data/lib/rack/directory.rb +19 -16
- data/lib/rack/etag.rb +3 -1
- data/lib/rack/events.rb +5 -3
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/handler/cgi.rb +3 -1
- data/lib/rack/handler/fastcgi.rb +4 -2
- data/lib/rack/handler/lsws.rb +3 -1
- data/lib/rack/handler/scgi.rb +9 -6
- data/lib/rack/handler/thin.rb +3 -1
- data/lib/rack/handler/webrick.rb +4 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +14 -11
- data/lib/rack/lobster.rb +7 -5
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +4 -2
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +74 -15
- data/lib/rack/multipart.rb +5 -3
- data/lib/rack/multipart/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +51 -45
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +51 -25
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +79 -26
- data/lib/rack/response.rb +71 -31
- data/lib/rack/rewindable_input.rb +4 -2
- data/lib/rack/runtime.rb +4 -2
- data/lib/rack/sendfile.rb +15 -8
- data/lib/rack/server.rb +88 -18
- data/lib/rack/session/abstract/id.rb +30 -20
- data/lib/rack/session/cookie.rb +10 -9
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +4 -2
- data/lib/rack/show_exceptions.rb +15 -9
- data/lib/rack/show_status.rb +4 -2
- data/lib/rack/static.rb +15 -10
- data/lib/rack/tempfile_reaper.rb +2 -0
- data/lib/rack/urlmap.rb +11 -2
- data/lib/rack/utils.rb +59 -72
- data/rack.gemspec +17 -7
- metadata +33 -175
- data/HISTORY.md +0 -505
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -95
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -722
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1407
- data/test/spec_response.rb +0 -528
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/session/pool.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
|
|
2
4
|
# THANKS:
|
|
3
5
|
# apeiros, for session id generation, expiry setup, and threadiness
|
|
@@ -26,9 +28,9 @@ module Rack
|
|
|
26
28
|
|
|
27
29
|
class Pool < Abstract::PersistedSecure
|
|
28
30
|
attr_reader :mutex, :pool
|
|
29
|
-
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :
|
|
31
|
+
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge drop: false
|
|
30
32
|
|
|
31
|
-
def initialize(app, options={})
|
|
33
|
+
def initialize(app, options = {})
|
|
32
34
|
super
|
|
33
35
|
@pool = Hash.new
|
|
34
36
|
@mutex = Mutex.new
|
data/lib/rack/show_exceptions.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'ostruct'
|
|
2
4
|
require 'erb'
|
|
3
5
|
require 'rack/request'
|
|
@@ -55,7 +57,7 @@ module Rack
|
|
|
55
57
|
private :accepts_html?
|
|
56
58
|
|
|
57
59
|
def dump_exception(exception)
|
|
58
|
-
string = "#{exception.class}: #{exception.message}\n"
|
|
60
|
+
string = "#{exception.class}: #{exception.message}\n".dup
|
|
59
61
|
string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
|
|
60
62
|
string
|
|
61
63
|
end
|
|
@@ -77,13 +79,13 @@ module Rack
|
|
|
77
79
|
frame.function = $4
|
|
78
80
|
|
|
79
81
|
begin
|
|
80
|
-
lineno = frame.lineno-1
|
|
82
|
+
lineno = frame.lineno - 1
|
|
81
83
|
lines = ::File.readlines(frame.filename)
|
|
82
|
-
frame.pre_context_lineno = [lineno-CONTEXT, 0].max
|
|
84
|
+
frame.pre_context_lineno = [lineno - CONTEXT, 0].max
|
|
83
85
|
frame.pre_context = lines[frame.pre_context_lineno...lineno]
|
|
84
86
|
frame.context_line = lines[lineno].chomp
|
|
85
|
-
frame.post_context_lineno = [lineno+CONTEXT, lines.size].min
|
|
86
|
-
frame.post_context = lines[lineno+1..frame.post_context_lineno]
|
|
87
|
+
frame.post_context_lineno = [lineno + CONTEXT, lines.size].min
|
|
88
|
+
frame.post_context = lines[lineno + 1..frame.post_context_lineno]
|
|
87
89
|
rescue
|
|
88
90
|
end
|
|
89
91
|
|
|
@@ -93,7 +95,11 @@ module Rack
|
|
|
93
95
|
end
|
|
94
96
|
}.compact
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
template.result(binding)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def template
|
|
102
|
+
TEMPLATE
|
|
97
103
|
end
|
|
98
104
|
|
|
99
105
|
def h(obj) # :nodoc:
|
|
@@ -107,8 +113,8 @@ module Rack
|
|
|
107
113
|
|
|
108
114
|
# :stopdoc:
|
|
109
115
|
|
|
110
|
-
# adapted from Django <djangoproject.com>
|
|
111
|
-
# Copyright (c)
|
|
116
|
+
# adapted from Django <www.djangoproject.com>
|
|
117
|
+
# Copyright (c) Django Software Foundation and individual contributors.
|
|
112
118
|
# Used under the modified BSD license:
|
|
113
119
|
# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
|
|
114
120
|
TEMPLATE = ERB.new(<<-'HTML'.gsub(/^ /, ''))
|
|
@@ -363,7 +369,7 @@ module Rack
|
|
|
363
369
|
<% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
|
|
364
370
|
<tr>
|
|
365
371
|
<td><%=h key %></td>
|
|
366
|
-
<td class="code"><div><%=h val %></div></td>
|
|
372
|
+
<td class="code"><div><%=h val.inspect %></div></td>
|
|
367
373
|
</tr>
|
|
368
374
|
<% } %>
|
|
369
375
|
</tbody>
|
data/lib/rack/show_status.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'erb'
|
|
2
4
|
require 'rack/request'
|
|
3
5
|
require 'rack/utils'
|
|
@@ -52,8 +54,8 @@ module Rack
|
|
|
52
54
|
|
|
53
55
|
# :stopdoc:
|
|
54
56
|
|
|
55
|
-
# adapted from Django <djangoproject.com>
|
|
56
|
-
# Copyright (c)
|
|
57
|
+
# adapted from Django <www.djangoproject.com>
|
|
58
|
+
# Copyright (c) Django Software Foundation and individual contributors.
|
|
57
59
|
# Used under the modified BSD license:
|
|
58
60
|
# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
|
|
59
61
|
TEMPLATE = <<'HTML'
|
data/lib/rack/static.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rack/files"
|
|
2
4
|
require "rack/utils"
|
|
3
5
|
|
|
6
|
+
require_relative 'core_ext/regexp'
|
|
7
|
+
|
|
4
8
|
module Rack
|
|
5
9
|
|
|
6
10
|
# The Rack::Static middleware intercepts requests for static files
|
|
7
11
|
# (javascript files, images, stylesheets, etc) based on the url prefixes or
|
|
8
|
-
# route mappings passed in the options, and serves them using a Rack::
|
|
12
|
+
# route mappings passed in the options, and serves them using a Rack::Files
|
|
9
13
|
# object. This allows a Rack stack to serve both static and dynamic content.
|
|
10
14
|
#
|
|
11
15
|
# Examples:
|
|
@@ -82,8 +86,9 @@ module Rack
|
|
|
82
86
|
# ]
|
|
83
87
|
#
|
|
84
88
|
class Static
|
|
89
|
+
using ::Rack::RegexpExtensions
|
|
85
90
|
|
|
86
|
-
def initialize(app, options={})
|
|
91
|
+
def initialize(app, options = {})
|
|
87
92
|
@app = app
|
|
88
93
|
@urls = options[:urls] || ["/favicon.ico"]
|
|
89
94
|
@index = options[:index]
|
|
@@ -93,13 +98,13 @@ module Rack
|
|
|
93
98
|
# HTTP Headers
|
|
94
99
|
@header_rules = options[:header_rules] || []
|
|
95
100
|
# Allow for legacy :cache_control option while prioritizing global header_rules setting
|
|
96
|
-
@header_rules.unshift([:all, {CACHE_CONTROL => options[:cache_control]}]) if options[:cache_control]
|
|
101
|
+
@header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control]
|
|
97
102
|
|
|
98
|
-
@file_server = Rack::
|
|
103
|
+
@file_server = Rack::Files.new(root)
|
|
99
104
|
end
|
|
100
105
|
|
|
101
106
|
def add_index_root?(path)
|
|
102
|
-
@index && path
|
|
107
|
+
@index && route_file(path) && path.end_with?('/')
|
|
103
108
|
end
|
|
104
109
|
|
|
105
110
|
def overwrite_file_path(path)
|
|
@@ -120,7 +125,7 @@ module Rack
|
|
|
120
125
|
if can_serve(path)
|
|
121
126
|
if overwrite_file_path(path)
|
|
122
127
|
env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path])
|
|
123
|
-
elsif @gzip && env['HTTP_ACCEPT_ENCODING']
|
|
128
|
+
elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING'])
|
|
124
129
|
path = env[PATH_INFO]
|
|
125
130
|
env[PATH_INFO] += '.gz'
|
|
126
131
|
response = @file_server.call(env)
|
|
@@ -157,14 +162,14 @@ module Rack
|
|
|
157
162
|
when :all
|
|
158
163
|
true
|
|
159
164
|
when :fonts
|
|
160
|
-
|
|
165
|
+
/\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
|
|
161
166
|
when String
|
|
162
167
|
path = ::Rack::Utils.unescape(path)
|
|
163
168
|
path.start_with?(rule) || path.start_with?('/' + rule)
|
|
164
169
|
when Array
|
|
165
|
-
|
|
170
|
+
/\.(#{rule.join('|')})\z/.match?(path)
|
|
166
171
|
when Regexp
|
|
167
|
-
path
|
|
172
|
+
rule.match?(path)
|
|
168
173
|
else
|
|
169
174
|
false
|
|
170
175
|
end
|
data/lib/rack/tempfile_reaper.rb
CHANGED
data/lib/rack/urlmap.rb
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
1
5
|
module Rack
|
|
2
6
|
# Rack::URLMap takes a hash mapping urls or paths to apps, and
|
|
3
7
|
# dispatches accordingly. Support for HTTP/1.1 host names exists if
|
|
@@ -20,9 +24,11 @@ module Rack
|
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
def remap(map)
|
|
27
|
+
@known_hosts = Set[]
|
|
23
28
|
@mapping = map.map { |location, app|
|
|
24
29
|
if location =~ %r{\Ahttps?://(.*?)(/.*)}
|
|
25
30
|
host, location = $1, $2
|
|
31
|
+
@known_hosts << host
|
|
26
32
|
else
|
|
27
33
|
host = nil
|
|
28
34
|
end
|
|
@@ -50,10 +56,13 @@ module Rack
|
|
|
50
56
|
is_same_server = casecmp?(http_host, server_name) ||
|
|
51
57
|
casecmp?(http_host, "#{server_name}:#{server_port}")
|
|
52
58
|
|
|
59
|
+
is_host_known = @known_hosts.include? http_host
|
|
60
|
+
|
|
53
61
|
@mapping.each do |host, location, match, app|
|
|
54
62
|
unless casecmp?(http_host, host) \
|
|
55
63
|
|| casecmp?(server_name, host) \
|
|
56
|
-
|| (!host && is_same_server)
|
|
64
|
+
|| (!host && is_same_server) \
|
|
65
|
+
|| (!host && !is_host_known) # If we don't have a matching host, default to the first without a specified host
|
|
57
66
|
next
|
|
58
67
|
end
|
|
59
68
|
|
|
@@ -68,7 +77,7 @@ module Rack
|
|
|
68
77
|
return app.call(env)
|
|
69
78
|
end
|
|
70
79
|
|
|
71
|
-
[404, {CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
|
|
80
|
+
[404, { CONTENT_TYPE => "text/plain", "X-Cascade" => "pass" }, ["Not Found: #{path}"]]
|
|
72
81
|
|
|
73
82
|
ensure
|
|
74
83
|
env[PATH_INFO] = path
|
data/lib/rack/utils.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# -*- encoding: binary -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
2
4
|
require 'uri'
|
|
3
5
|
require 'fileutils'
|
|
4
6
|
require 'set'
|
|
@@ -6,11 +8,15 @@ require 'tempfile'
|
|
|
6
8
|
require 'rack/query_parser'
|
|
7
9
|
require 'time'
|
|
8
10
|
|
|
11
|
+
require_relative 'core_ext/regexp'
|
|
12
|
+
|
|
9
13
|
module Rack
|
|
10
14
|
# Rack::Utils contains a grab-bag of useful methods for writing web
|
|
11
15
|
# applications adopted from all kinds of Ruby libraries.
|
|
12
16
|
|
|
13
17
|
module Utils
|
|
18
|
+
using ::Rack::RegexpExtensions
|
|
19
|
+
|
|
14
20
|
ParameterTypeError = QueryParser::ParameterTypeError
|
|
15
21
|
InvalidParameterError = QueryParser::InvalidParameterError
|
|
16
22
|
DEFAULT_SEP = QueryParser::DEFAULT_SEP
|
|
@@ -118,7 +124,7 @@ module Rack
|
|
|
118
124
|
when Hash
|
|
119
125
|
value.map { |k, v|
|
|
120
126
|
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
|
121
|
-
}.
|
|
127
|
+
}.delete_if(&:empty?).join('&')
|
|
122
128
|
when nil
|
|
123
129
|
prefix
|
|
124
130
|
else
|
|
@@ -132,7 +138,7 @@ module Rack
|
|
|
132
138
|
q_value_header.to_s.split(/\s*,\s*/).map do |part|
|
|
133
139
|
value, parameters = part.split(/\s*;\s*/, 2)
|
|
134
140
|
quality = 1.0
|
|
135
|
-
if md = /\Aq=([\d.]+)/.match(parameters)
|
|
141
|
+
if parameters && (md = /\Aq=([\d.]+)/.match(parameters))
|
|
136
142
|
quality = md[1].to_f
|
|
137
143
|
end
|
|
138
144
|
[value, quality]
|
|
@@ -175,27 +181,26 @@ module Rack
|
|
|
175
181
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
|
176
182
|
|
|
177
183
|
expanded_accept_encoding =
|
|
178
|
-
accept_encoding.
|
|
184
|
+
accept_encoding.each_with_object([]) do |(m, q), list|
|
|
179
185
|
if m == "*"
|
|
180
|
-
(available_encodings - accept_encoding.map
|
|
186
|
+
(available_encodings - accept_encoding.map(&:first))
|
|
187
|
+
.each { |m2| list << [m2, q] }
|
|
181
188
|
else
|
|
182
|
-
[
|
|
189
|
+
list << [m, q]
|
|
183
190
|
end
|
|
184
|
-
|
|
185
|
-
mem + list
|
|
186
|
-
}
|
|
191
|
+
end
|
|
187
192
|
|
|
188
|
-
encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map
|
|
193
|
+
encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map!(&:first)
|
|
189
194
|
|
|
190
195
|
unless encoding_candidates.include?("identity")
|
|
191
196
|
encoding_candidates.push("identity")
|
|
192
197
|
end
|
|
193
198
|
|
|
194
|
-
expanded_accept_encoding.each
|
|
199
|
+
expanded_accept_encoding.each do |m, q|
|
|
195
200
|
encoding_candidates.delete(m) if q == 0.0
|
|
196
|
-
|
|
201
|
+
end
|
|
197
202
|
|
|
198
|
-
|
|
203
|
+
(encoding_candidates & available_encodings)[0]
|
|
199
204
|
end
|
|
200
205
|
module_function :select_best_encoding
|
|
201
206
|
|
|
@@ -210,8 +215,12 @@ module Rack
|
|
|
210
215
|
# the Cookie header such that those with more specific Path attributes
|
|
211
216
|
# precede those with less specific. Ordering with respect to other
|
|
212
217
|
# attributes (e.g., Domain) is unspecified.
|
|
213
|
-
|
|
214
|
-
|
|
218
|
+
return {} unless header
|
|
219
|
+
header.split(/[;,] */n).each_with_object({}) do |cookie, cookies|
|
|
220
|
+
next if cookie.empty?
|
|
221
|
+
key, value = cookie.split('=', 2)
|
|
222
|
+
cookies[key] = (unescape(value) rescue value) unless cookies.key?(key)
|
|
223
|
+
end
|
|
215
224
|
end
|
|
216
225
|
module_function :parse_cookies_header
|
|
217
226
|
|
|
@@ -221,31 +230,7 @@ module Rack
|
|
|
221
230
|
domain = "; domain=#{value[:domain]}" if value[:domain]
|
|
222
231
|
path = "; path=#{value[:path]}" if value[:path]
|
|
223
232
|
max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
|
|
224
|
-
|
|
225
|
-
# only are there contradicting RFCs and examples within RFC text, but
|
|
226
|
-
# there are also numerous conflicting names of fields and partially
|
|
227
|
-
# cross-applicable specifications.
|
|
228
|
-
#
|
|
229
|
-
# These are best described in RFC 2616 3.3.1. This RFC text also
|
|
230
|
-
# specifies that RFC 822 as updated by RFC 1123 is preferred. That is a
|
|
231
|
-
# fixed length format with space-date delimited fields.
|
|
232
|
-
#
|
|
233
|
-
# See also RFC 1123 section 5.2.14.
|
|
234
|
-
#
|
|
235
|
-
# RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined
|
|
236
|
-
# in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote
|
|
237
|
-
# the space delimited format. These formats are compliant with RFC 2822.
|
|
238
|
-
#
|
|
239
|
-
# For reference, all involved RFCs are:
|
|
240
|
-
# RFC 822
|
|
241
|
-
# RFC 1123
|
|
242
|
-
# RFC 2109
|
|
243
|
-
# RFC 2616
|
|
244
|
-
# RFC 2822
|
|
245
|
-
# RFC 2965
|
|
246
|
-
# RFC 6265
|
|
247
|
-
expires = "; expires=" +
|
|
248
|
-
rfc2822(value[:expires].clone.gmtime) if value[:expires]
|
|
233
|
+
expires = "; expires=#{value[:expires].httpdate}" if value[:expires]
|
|
249
234
|
secure = "; secure" if value[:secure]
|
|
250
235
|
httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only])
|
|
251
236
|
same_site =
|
|
@@ -253,11 +238,11 @@ module Rack
|
|
|
253
238
|
when false, nil
|
|
254
239
|
nil
|
|
255
240
|
when :none, 'None', :None
|
|
256
|
-
'; SameSite=None'
|
|
241
|
+
'; SameSite=None'
|
|
257
242
|
when :lax, 'Lax', :Lax
|
|
258
|
-
'; SameSite=Lax'
|
|
243
|
+
'; SameSite=Lax'
|
|
259
244
|
when true, :strict, 'Strict', :Strict
|
|
260
|
-
'; SameSite=Strict'
|
|
245
|
+
'; SameSite=Strict'
|
|
261
246
|
else
|
|
262
247
|
raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
|
|
263
248
|
end
|
|
@@ -297,15 +282,15 @@ module Rack
|
|
|
297
282
|
cookies = header
|
|
298
283
|
end
|
|
299
284
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
285
|
+
regexp = if value[:domain]
|
|
286
|
+
/\A#{escape(key)}=.*domain=#{value[:domain]}/
|
|
287
|
+
elsif value[:path]
|
|
288
|
+
/\A#{escape(key)}=.*path=#{value[:path]}/
|
|
289
|
+
else
|
|
290
|
+
/\A#{escape(key)}=/
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
cookies.reject! { |cookie| regexp.match? cookie }
|
|
309
294
|
|
|
310
295
|
cookies.join("\n")
|
|
311
296
|
end
|
|
@@ -323,9 +308,9 @@ module Rack
|
|
|
323
308
|
new_header = make_delete_cookie_header(header, key, value)
|
|
324
309
|
|
|
325
310
|
add_cookie_to_header(new_header, key,
|
|
326
|
-
{:
|
|
327
|
-
:
|
|
328
|
-
:
|
|
311
|
+
{ value: '', path: nil, domain: nil,
|
|
312
|
+
max_age: '0',
|
|
313
|
+
expires: Time.at(0) }.merge(value))
|
|
329
314
|
|
|
330
315
|
end
|
|
331
316
|
module_function :add_remove_cookie_to_header
|
|
@@ -366,7 +351,7 @@ module Rack
|
|
|
366
351
|
ranges = []
|
|
367
352
|
$1.split(/,\s*/).each do |range_spec|
|
|
368
353
|
return nil unless range_spec =~ /(\d*)-(\d*)/
|
|
369
|
-
r0,r1 = $1, $2
|
|
354
|
+
r0, r1 = $1, $2
|
|
370
355
|
if r0.empty?
|
|
371
356
|
return nil if r1.empty?
|
|
372
357
|
# suffix-byte-range-spec, represents trailing suffix of file
|
|
@@ -380,7 +365,7 @@ module Rack
|
|
|
380
365
|
else
|
|
381
366
|
r1 = r1.to_i
|
|
382
367
|
return nil if r1 < r0 # backwards range is syntactically invalid
|
|
383
|
-
r1 = size-1 if r1 >= size
|
|
368
|
+
r1 = size - 1 if r1 >= size
|
|
384
369
|
end
|
|
385
370
|
end
|
|
386
371
|
ranges << (r0..r1) if r0 <= r1
|
|
@@ -401,7 +386,7 @@ module Rack
|
|
|
401
386
|
l = a.unpack("C*")
|
|
402
387
|
|
|
403
388
|
r, i = 0, -1
|
|
404
|
-
b.each_byte { |v| r |= v ^ l[i+=1] }
|
|
389
|
+
b.each_byte { |v| r |= v ^ l[i += 1] }
|
|
405
390
|
r == 0
|
|
406
391
|
end
|
|
407
392
|
module_function :secure_compare
|
|
@@ -427,19 +412,17 @@ module Rack
|
|
|
427
412
|
self.class.new(@for, app)
|
|
428
413
|
end
|
|
429
414
|
|
|
430
|
-
def context(env, app
|
|
415
|
+
def context(env, app = @app)
|
|
431
416
|
recontext(app).call(env)
|
|
432
417
|
end
|
|
433
418
|
end
|
|
434
419
|
|
|
435
420
|
# A case-insensitive Hash that preserves the original case of a
|
|
436
421
|
# header when set.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
def initialize(hash={})
|
|
422
|
+
#
|
|
423
|
+
# @api private
|
|
424
|
+
class HeaderHash < Hash # :nodoc:
|
|
425
|
+
def initialize(hash = {})
|
|
443
426
|
super()
|
|
444
427
|
@names = {}
|
|
445
428
|
hash.each { |k, v| self[k] = v }
|
|
@@ -459,7 +442,7 @@ module Rack
|
|
|
459
442
|
|
|
460
443
|
def to_hash
|
|
461
444
|
hash = {}
|
|
462
|
-
each { |k,v| hash[k] = v }
|
|
445
|
+
each { |k, v| hash[k] = v }
|
|
463
446
|
hash
|
|
464
447
|
end
|
|
465
448
|
|
|
@@ -512,13 +495,14 @@ module Rack
|
|
|
512
495
|
|
|
513
496
|
# Every standard HTTP code mapped to the appropriate message.
|
|
514
497
|
# Generated with:
|
|
515
|
-
#
|
|
516
|
-
#
|
|
517
|
-
#
|
|
498
|
+
# curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
|
|
499
|
+
# ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
|
|
500
|
+
# puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
|
|
518
501
|
HTTP_STATUS_CODES = {
|
|
519
502
|
100 => 'Continue',
|
|
520
503
|
101 => 'Switching Protocols',
|
|
521
504
|
102 => 'Processing',
|
|
505
|
+
103 => 'Early Hints',
|
|
522
506
|
200 => 'OK',
|
|
523
507
|
201 => 'Created',
|
|
524
508
|
202 => 'Accepted',
|
|
@@ -535,6 +519,7 @@ module Rack
|
|
|
535
519
|
303 => 'See Other',
|
|
536
520
|
304 => 'Not Modified',
|
|
537
521
|
305 => 'Use Proxy',
|
|
522
|
+
306 => '(Unused)',
|
|
538
523
|
307 => 'Temporary Redirect',
|
|
539
524
|
308 => 'Permanent Redirect',
|
|
540
525
|
400 => 'Bad Request',
|
|
@@ -559,6 +544,7 @@ module Rack
|
|
|
559
544
|
422 => 'Unprocessable Entity',
|
|
560
545
|
423 => 'Locked',
|
|
561
546
|
424 => 'Failed Dependency',
|
|
547
|
+
425 => 'Too Early',
|
|
562
548
|
426 => 'Upgrade Required',
|
|
563
549
|
428 => 'Precondition Required',
|
|
564
550
|
429 => 'Too Many Requests',
|
|
@@ -573,12 +559,13 @@ module Rack
|
|
|
573
559
|
506 => 'Variant Also Negotiates',
|
|
574
560
|
507 => 'Insufficient Storage',
|
|
575
561
|
508 => 'Loop Detected',
|
|
562
|
+
509 => 'Bandwidth Limit Exceeded',
|
|
576
563
|
510 => 'Not Extended',
|
|
577
564
|
511 => 'Network Authentication Required'
|
|
578
565
|
}
|
|
579
566
|
|
|
580
567
|
# Responses with HTTP status codes that should not have an entity body
|
|
581
|
-
STATUS_WITH_NO_ENTITY_BODY =
|
|
568
|
+
STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
|
|
582
569
|
|
|
583
570
|
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
|
|
584
571
|
[message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
|
|
@@ -586,7 +573,7 @@ module Rack
|
|
|
586
573
|
|
|
587
574
|
def status_code(status)
|
|
588
575
|
if status.is_a?(Symbol)
|
|
589
|
-
SYMBOL_TO_STATUS_CODE
|
|
576
|
+
SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
|
|
590
577
|
else
|
|
591
578
|
status.to_i
|
|
592
579
|
end
|
|
@@ -607,11 +594,11 @@ module Rack
|
|
|
607
594
|
|
|
608
595
|
clean.unshift '/' if parts.empty? || parts.first.empty?
|
|
609
596
|
|
|
610
|
-
::File.join
|
|
597
|
+
::File.join clean
|
|
611
598
|
end
|
|
612
599
|
module_function :clean_path_info
|
|
613
600
|
|
|
614
|
-
NULL_BYTE = "\0"
|
|
601
|
+
NULL_BYTE = "\0"
|
|
615
602
|
|
|
616
603
|
def valid_path?(path)
|
|
617
604
|
path.valid_encoding? && !path.include?(NULL_BYTE)
|