Memoize header hash#1549
Conversation
84b1227 to
c9b2ce3
Compare
c9b2ce3 to
c693180
Compare
c693180 to
4a930f2
Compare
|
cc @schneems |
jeremyevans
left a comment
There was a problem hiding this comment.
OK with the idea and implementation.
This benchmarks are nice and an abbreviated version could go in the commit message, but I don't think we need them in the repository. Could you remove them and squash?
Also, please update CHANGELOG when merging, referencing both the performance improvement and the change in Response behavior (headers are now be mutated if passed as a HeaderHash). CHANGELOG should now be updated for all significant changes, so that it is always in a releasable state modulo the version at the top.
I agree with this, but can you put the benchmarks and results in this PR? We can refer back to the PR to see the results, and the PR will be linked to from the merge commit (another reason I like backporting merge commits rather than individual cherry picking). |
|
I am happy to remove the benchmarks directory. However:
Putting the benchmark data into the GitHub PR ties it to GitHub. I often work offline and if I don't have all the data it's a pain. So, unless there is a strong practical reason not to include the benchmarks in the repo, I'd prefer to leave it. However, I welcome further discussion. I'm easy either way. |
|
It does cost something. Everything added to the repository costs something and requires time/bandwidth to clone and store. Even in 10 years where the data is no longer needed, it'll still be in the .git directory taking up space. If you do want to keep the benchmark, keep just the benchmark and not the results/gemfiles. That way people can use and learn from the benchmark without taking up much space, and it still allows rechecking assumptions later. I would especially remove the gemfiles as we would want to test with with not just Falcon, but also Puma and Unicorn to judge the real world impact. Also, I think the benchmark should be made more realistic. You could consider worst case to be every middleware that Rack ships with that uses |
|
It would be pretty cool if we had a benchmark suite and could keep track of the speeds over time. |
Understood. We could create a separate repo for benchmarks. But that is very cumbersome when they are tied to PRs. I hesitate to say that "even in 10 years when the data is no longer needed". I wish the original benchmarks made by @schneems were committed or in a PR, so that I could actually validate the improvements against his original data. That original issue is ~6 years old.
It sounds like you are bothered to include Falcon in a benchmark. I just used it because it's practical for the purpose of the benchmark. This benchmark is not affected by the server so much. We could use webrick or something else by default. But it didn't occur to me that someone would be unhappy about that, that I didn't use some other server or multiple servers. Making benchmarks reproducible is a good idea IMHO.
I wish I could reproduce the original rails benchmark done by @schneems but that is lost to the sands of time because it was not committed or in any PR that I'm aware of. That's kind of the crux of the issue here and why I decided to include it. I believe any time we have a performance related PR, we should have a corresponding test or benchmark which is (reasonably) reproducible. This is pretty typical, e.g. CRuby. |
|
Just a few examples: Async benchmarks to check assumptions, all fairly reproducible: Useful for comparing assumptions across releases of Ruby, different implementations of Ruby. Specs which include benchmarks: https://github.com/socketry/async/blob/master/spec/async/performance_spec.rb https://github.com/socketry/async/runs/420813752?check_suite_focus=true#step:5:66 There are others, but this is just one example which helps me catch regressions or identify performance issues over time. It's also possible to do the specific regression testing on memory allocations in specs: https://github.com/socketry/rspec-memory honestly, something like the last one might be better than a benchmark, but these all work together to prevent and identify performance issues. |
|
I’m on mobile, but it looks like this used to be the behavior of HeaderHash.new, or at least it was when I made this PR https://github.com/rack/rack/pull/1204/files#diff-7c1a24d5b2fe58a6f925c7cacc6c55e7 I’m not able to see when or why it changed right now. FWIW I extracted my benchmark code to derailed https://github.com/schneems/derailed_benchmarks#i-made-a-patch-to-to-rails-how-can-i-tell-if-it-made-my-rails-app-faster-and-test-for-statistical-significance you can also set the library to rack just like you can for Rails. It won’t show the change over time but will give an a/b perf comparison with some statistical analysis. |
Looks like that logic was reverted by @jodosha in #1325 |
|
Here's how I will test with Derailed and https://www.codetriage.com app (https://github.com/codetriage/codetriage) The gist of how you perf test a library with derailed:
Derailed will then boot the app in memory and hit it with 200 requests using rack-mock, this is done headlessly. It then toggles the git ref and hits that with 200 requests. It repeats this process 200 times. It will print out intermediate results along with statistical significance information as it runs. Ideally, I want histograms too, but that's not implemented yet zombocom/derailed_benchmarks#169 (and will require significant work). I'm going to let this run a few times overnight and let you all know how it turns out. |
|
Thanks that sounds awesome looking forward to the results! |
|
Big caveat - I'm going to give the results of my tests, they are not THE results. They are one picture of results based off of how this patch behaves with CodeTriage. I've spent a lot of time trying to measure perf differences between code changes in my Rails patches. However, I do not have all the answers. Basically, use this data not as an answer, but rather as the basis for more questions. My results I ran derailed against code triage 6 times last night and got statistically insignificant results for all six runs with a 95% confidence interval (derailed will report up to 99% significant if available). Some runs were faster some were slower. But we cannot say, with confidence, that the result was due to the change as opposed random chance on CodeTriage. Here's the results: Again none of these results were significant, so they don't strictly mean anything conclusive. I tried again this morning but so far over two runs, still no significant results. You cannot use these results to say "it is faster!" or "it is slower!" you cannot average or manipulate these results to mean anything, other than we cannot say with 95% confidence that the results are not the result of random chance. That could mean that there is a change, but it's smaller than we are capable of measuring, or it could mean that there's effectively no measurable difference between the two branches (for this test). The app we're testing on for sure will make a difference. A "hello world" rack app would likely better be able to highlight a perf difference, but i'm not able to see one in CodeTriage. I've attached the raw results in a zip file. If you want to chat more about the data, or derailed feel free to ping me. I'm in Nate's performance slack and the Rails basecamp. My email is visible on GitHub if you don't have access to either of those and want more synchronous communication. |
|
Nice work! |
…ethod def in the future Ref rack#1549 (comment). If we'd not prefer the no paren method def style and avoid the style by code review, we have a way to avoid that style by using RuboCop.
…ethod def in the future Ref #1549 (comment). If we'd not prefer the no paren method def style and avoid the style by code review, we have a way to avoid that style by using RuboCop.
|
I was reviewing the HeaderHash code, and realised that it's merging together headers using newlines. Which I subsequently have to revert in Falcon because no actual protocol supports this format: For Rack 3.0, we could consider allowing headers to be an array of values and drop the newline format. The practical benefits of this implementation seem limited, at least according to the data point provided by @schneems which I fully respect the statistical analysis he did, compared to the supplied micro benchmark. That being said, in theory this does avoid memory allocations when there are lots of headers, so generally I think there are going to be use cases which benefit from this memoization. Therefore, I'm going to tidy up this PR with some specs, remove the benchmarks, and merge. Then, with Rack 3.0 push, I will reintroduce benchmarks as part of the tests, and hopefully we can do so in other areas too. |
Co-Authored-By: Rafael França <rafael@franca.dev>
11f7324 to
1736973
Compare
1736973 to
6b1f13b
Compare
6b1f13b to
e94dc31
Compare
| assert_same response[1], headers | ||
| end | ||
|
|
||
| it "duplicates header hash" do |
Update ruby-rack to 2.2.2. ## [2.2.2] - 2020-02-11 ### Fixed - Fix incorrect `Rack::Request#host` value. ([#1591](rack/rack#1591), [@ioquatix](https://github.com/ioquatix)) - Revert `Rack::Handler::Thin` implementation. ([#1583](rack/rack#1583), [@jeremyevans](https://github.com/jeremyevans)) - Double assignment is still needed to prevent an "unused variable" warning. ([#1589](rack/rack#1589), [@kamipo](https://github.com/kamipo)) - Fix to handle same_site option for session pool. ([#1587](rack/rack#1587), [@kamipo](https://github.com/kamipo)) ## [2.2.1] - 2020-02-09 ### Fixed - Rework `Rack::Request#ip` to handle empty `forwarded_for`. ([#1577](rack/rack#1577), [@ioquatix](https://github.com/ioquatix)) ## [2.2.0] - 2020-02-08 ### SPEC Changes - `rack.session` request environment entry must respond to `to_hash` and return unfrozen Hash. ([@jeremyevans](https://github.com/jeremyevans)) - Request environment cannot be frozen. ([@jeremyevans](https://github.com/jeremyevans)) - CGI values in the request environment with non-ASCII characters must use ASCII-8BIT encoding. ([@jeremyevans](https://github.com/jeremyevans)) - Improve SPEC/lint relating to SERVER_NAME, SERVER_PORT and HTTP_HOST. ([#1561](rack/rack#1561), [@ioquatix](https://github.com/ioquatix)) ### Added - `rackup` supports multiple `-r` options and will require all arguments. ([@jeremyevans](https://github.com/jeremyevans)) - `Server` supports an array of paths to require for the `:require` option. ([@khotta](https://github.com/khotta)) - `Files` supports multipart range requests. ([@fatkodima](https://github.com/fatkodima)) - `Multipart::UploadedFile` supports an IO-like object instead of using the filesystem, using `:filename` and `:io` options. ([@jeremyevans](https://github.com/jeremyevans)) - `Multipart::UploadedFile` supports keyword arguments `:path`, `:content_type`, and `:binary` in addition to positional arguments. ([@jeremyevans](https://github.com/jeremyevans)) - `Static` supports a `:cascade` option for calling the app if there is no matching file. ([@jeremyevans](https://github.com/jeremyevans)) - `Session::Abstract::SessionHash#dig`. ([@jeremyevans](https://github.com/jeremyevans)) - `Response.[]` and `MockResponse.[]` for creating instances using status, headers, and body. ([@ioquatix](https://github.com/ioquatix)) - Convenient cache and content type methods for `Rack::Response`. ([#1555](rack/rack#1555), [@ioquatix](https://github.com/ioquatix)) ### Changed - `Request#params` no longer rescues EOFError. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` uses a streaming approach, significantly improving time to first byte for large directories. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` no longer includes a Parent directory link in the root directory index. ([@jeremyevans](https://github.com/jeremyevans)) - `QueryParser#parse_nested_query` uses original backtrace when reraising exception with new class. ([@jeremyevans](https://github.com/jeremyevans)) - `ConditionalGet` follows RFC 7232 precedence if both If-None-Match and If-Modified-Since headers are provided. ([@jeremyevans](https://github.com/jeremyevans)) - `.ru` files supports the `frozen-string-literal` magic comment. ([@eregon](https://github.com/eregon)) - Rely on autoload to load constants instead of requiring internal files, make sure to require 'rack' and not just 'rack/...'. ([@jeremyevans](https://github.com/jeremyevans)) - `Etag` will continue sending ETag even if the response should not be cached. ([@henm](https://github.com/henm)) - `Request#host_with_port` no longer includes a colon for a missing or empty port. ([@AlexWayfer](https://github.com/AlexWayfer)) - All handlers uses keywords arguments instead of an options hash argument. ([@ioquatix](https://github.com/ioquatix)) - `Files` handling of range requests no longer return a body that supports `to_path`, to ensure range requests are handled correctly. ([@jeremyevans](https://github.com/jeremyevans)) - `Multipart::Generator` only includes `Content-Length` for files with paths, and `Content-Disposition` `filename` if the `UploadedFile` instance has one. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#ssl?` is true for the `wss` scheme (secure websockets). ([@jeremyevans](https://github.com/jeremyevans)) - `Rack::HeaderHash` is memoized by default. ([#1549](rack/rack#1549), [@ioquatix](https://github.com/ioquatix)) - `Rack::Directory` allow directory traversal inside root directory. ([#1417](rack/rack#1417), [@ThomasSevestre](https://github.com/ThomasSevestre)) - Sort encodings by server preference. ([#1184](rack/rack#1184), [@ioquatix](https://github.com/ioquatix), [@wjordan](https://github.com/wjordan)) - Rework host/hostname/authority implementation in `Rack::Request`. `#host` and `#host_with_port` have been changed to correctly return IPv6 addresses formatted with square brackets, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-3.2.2). ([#1561](rack/rack#1561), [@ioquatix](https://github.com/ioquatix)) - `Rack::Builder` parsing options on first `#\` line is deprecated. ([#1574](rack/rack#1574), [@ioquatix](https://github.com/ioquatix)) ### Removed - `Directory#path` as it was not used and always returned nil. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy#each` as it was only needed to work around a bug in Ruby <1.9.3. ([@jeremyevans](https://github.com/jeremyevans)) - `URLMap::INFINITY` and `URLMap::NEGATIVE_INFINITY`, in favor of `Float::INFINITY`. ([@ch1c0t](https://github.com/ch1c0t)) - Deprecation of `Rack::File`. It will be deprecated again in rack 2.2 or 3.0. ([@rafaelfranca](https://github.com/rafaelfranca)) - Support for Ruby 2.2 as it is well past EOL. ([@ioquatix](https://github.com/ioquatix)) - Remove `Rack::Files#response_body` as the implementation was broken. ([#1153](rack/rack#1153), [@ioquatix](https://github.com/ioquatix)) - Remove `SERVER_ADDR` which was never part of the original SPEC. ([#1573](rack/rack#1573), [@ioquatix](https://github.com/ioquatix)) ### Fixed - `Directory` correctly handles root paths containing glob metacharacters. ([@jeremyevans](https://github.com/jeremyevans)) - `Cascade` uses a new response object for each call if initialized with no apps. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy` correctly delegates keyword arguments to the body object on Ruby 2.7+. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy#method` correctly handles methods delegated to the body object. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#host` and `Request#host_with_port` handle IPv6 addresses correctly. ([@AlexWayfer](https://github.com/AlexWayfer)) - `Lint` checks when response hijacking that `rack.hijack` is called with a valid object. ([@jeremyevans](https://github.com/jeremyevans)) - `Response#write` correctly updates `Content-Length` if initialized with a body. ([@jeremyevans](https://github.com/jeremyevans)) - `CommonLogger` includes `SCRIPT_NAME` when logging. ([@Erol](https://github.com/Erol)) - `Utils.parse_nested_query` correctly handles empty queries, using an empty instance of the params class instead of a hash. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` correctly escapes paths in links. ([@yous](https://github.com/yous)) - `Request#delete_cookie` and related `Utils` methods handle `:domain` and `:path` options in same call. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#delete_cookie` and related `Utils` methods do an exact match on `:domain` and `:path` options. ([@jeremyevans](https://github.com/jeremyevans)) - `Static` no longer adds headers when a gzipped file request has a 304 response. ([@chooh](https://github.com/chooh)) - `ContentLength` sets `Content-Length` response header even for bodies not responding to `to_ary`. ([@jeremyevans](https://github.com/jeremyevans)) - Thin handler supports options passed directly to `Thin::Controllers::Controller`. ([@jeremyevans](https://github.com/jeremyevans)) - WEBrick handler no longer ignores `:BindAddress` option. ([@jeremyevans](https://github.com/jeremyevans)) - `ShowExceptions` handles invalid POST data. ([@jeremyevans](https://github.com/jeremyevans)) - Basic authentication requires a password, even if the password is empty. ([@jeremyevans](https://github.com/jeremyevans)) - `Lint` checks response is array with 3 elements, per SPEC. ([@jeremyevans](https://github.com/jeremyevans)) - Support for using `:SSLEnable` option when using WEBrick handler. (Gregor Melhorn) - Close response body after buffering it when buffering. ([@ioquatix](https://github.com/ioquatix)) - Only accept `;` as delimiter when parsing cookies. ([@mrageh](https://github.com/mrageh)) - `Utils::HeaderHash#clear` clears the name mapping as well. ([@raxoft](https://github.com/raxoft)) - Support for passing `nil` `Rack::Files.new`, which notably fixes Rails' current `ActiveStorage::FileServer` implementation. ([@ioquatix](https://github.com/ioquatix)) ### Documentation - CHANGELOG updates. ([@Aupajo](https://github.com/aupajo)) - Added [CONTRIBUTING](CONTRIBUTING.md). ([@dblock](https://github.com/dblock)) ## [2.1.2] - 2020-01-27 - Fix multipart parser for some files to prevent denial of service ([@aiomaster](https://github.com/aiomaster)) - Fix `Rack::Builder#use` with keyword arguments ([@kamipo](https://github.com/kamipo)) - Skip deflating in Rack::Deflater if Content-Length is 0 ([@jeremyevans](https://github.com/jeremyevans)) - Remove `SessionHash#transform_keys`, no longer needed ([@pavel](https://github.com/pavel)) - Add to_hash to wrap Hash and Session classes ([@oleh-demyanyuk](https://github.com/oleh-demyanyuk)) - Handle case where session id key is requested but missing ([@jeremyevans](https://github.com/jeremyevans)) ## [2.1.1] - 2020-01-12 - Remove `Rack::Chunked` from `Rack::Server` default middleware. ([#1475](rack/rack#1475), [@ioquatix](https://github.com/ioquatix)) ## 2.1.0 _Note: There are many unreleased changes in Rack (`master` is around 300 commits ahead of `2-0-stable`), and below is not an exhaustive list. If you would like to help out and document some of the unreleased changes, PRs are welcome._ ### Added - Add support for `SameSite=None` cookie value. ([@hennikul](https://github.com/hennikul)) - Add trailer headers. ([@eileencodes](https://github.com/eileencodes)) - Add MIME Types for video streaming. ([@styd](https://github.com/styd)) - Add MIME Type for WASM. ([@buildrtech](https://github.com/buildrtech)) - Add `Early Hints(103)` to status codes. ([@egtra](https://github.com/egtra)) - Add `Too Early(425)` to status codes. ([@y-yagi]((https://github.com/y-yagi))) - Add `Bandwidth Limit Exceeded(509)` to status codes. ([@CJKinni](https://github.com/CJKinni)) - Add method for custom `ip_filter`. ([@svcastaneda](https://github.com/svcastaneda)) - Add boot-time profiling capabilities to `rackup`. ([@tenderlove](https://github.com/tenderlove)) - Add multi mapping support for `X-Accel-Mappings` header. ([@yoshuki](https://github.com/yoshuki)) - Add `sync: false` option to `Rack::Deflater`. (Eric Wong) - Add `Builder#freeze_app` to freeze application and all middleware instances. ([@jeremyevans](https://github.com/jeremyevans)) - Add API to extract cookies from `Rack::MockResponse`. ([@petercline](https://github.com/petercline)) ### Changed - Don't propagate nil values from middleware. ([@ioquatix](https://github.com/ioquatix)) - Lazily initialize the response body and only buffer it if required. ([@ioquatix](https://github.com/ioquatix)) - Fix deflater zlib buffer errors on empty body part. ([@felixbuenemann](https://github.com/felixbuenemann)) - Set `X-Accel-Redirect` to percent-encoded path. ([@diskkid](https://github.com/diskkid)) - Remove unnecessary buffer growing when parsing multipart. ([@tainoe](https://github.com/tainoe)) - Expand the root path in `Rack::Static` upon initialization. ([@rosenfeld](https://github.com/rosenfeld)) - Make `ShowExceptions` work with binary data. ([@axyjo](https://github.com/axyjo)) - Use buffer string when parsing multipart requests. ([@janko-m](https://github.com/janko-m)) - Support optional UTF-8 Byte Order Mark (BOM) in config.ru. ([@mikegee](https://github.com/mikegee)) - Handle `X-Forwarded-For` with optional port. ([@dpritchett](https://github.com/dpritchett)) - Use `Time#httpdate` format for Expires, as proposed by RFC 7231. ([@nanaya](https://github.com/nanaya)) - Make `Utils.status_code` raise an error when the status symbol is invalid instead of `500`. ([@adambutler](https://github.com/adambutler)) - Rename `Request::SCHEME_WHITELIST` to `Request::ALLOWED_SCHEMES`. - Make `Multipart::Parser.get_filename` accept files with `+` in their name. ([@lucaskanashiro](https://github.com/lucaskanashiro)) - Add Falcon to the default handler fallbacks. ([@ioquatix](https://github.com/ioquatix)) - Update codebase to avoid string mutations in preparation for `frozen_string_literals`. ([@pat](https://github.com/pat)) - Change `MockRequest#env_for` to rely on the input optionally responding to `#size` instead of `#length`. ([@janko](https://github.com/janko)) - Rename `Rack::File` -> `Rack::Files` and add deprecation notice. ([@postmodern](https://github.com/postmodern)). ### Removed - Remove `to_ary` from Response ([@tenderlove](https://github.com/tenderlove)) - Deprecate `Rack::Session::Memcache` in favor of `Rack::Session::Dalli` from dalli gem ([@fatkodima](https://github.com/fatkodima)) ### Documentation - Update broken example in `Session::Abstract::ID` documentation. ([tonytonyjan](https://github.com/tonytonyjan)) - Add Padrino to the list of frameworks implmenting Rack. ([@wikimatze](https://github.com/wikimatze)) - Remove Mongrel from the suggested server options in the help output. ([@tricknotes](https://github.com/tricknotes)) - Replace `HISTORY.md` and `NEWS.md` with `CHANGELOG.md`. ([@twitnithegirl](https://github.com/twitnithegirl)) - Backfill `CHANGELOG.md` from 2.0.1 to 2.0.7 releases. ([@drenmi](https://github.com/Drenmi)) ## [2.0.8] - 2019-12-08 - [[CVE-2019-16782](https://nvd.nist.gov/vuln/detail/CVE-2019-16782)] Prevent timing attacks targeted at session ID lookup. BREAKING CHANGE: Session ID is now a SessionId instance instead of a String. ([@tenderlove](https://github.com/tenderlove), [@rafaelfranca](https://github.com/rafaelfranca))
Update ruby-rack to 2.2.2. ## [2.2.2] - 2020-02-11 ### Fixed - Fix incorrect `Rack::Request#host` value. ([#1591](rack/rack#1591), [@ioquatix](https://github.com/ioquatix)) - Revert `Rack::Handler::Thin` implementation. ([#1583](rack/rack#1583), [@jeremyevans](https://github.com/jeremyevans)) - Double assignment is still needed to prevent an "unused variable" warning. ([#1589](rack/rack#1589), [@kamipo](https://github.com/kamipo)) - Fix to handle same_site option for session pool. ([#1587](rack/rack#1587), [@kamipo](https://github.com/kamipo)) ## [2.2.1] - 2020-02-09 ### Fixed - Rework `Rack::Request#ip` to handle empty `forwarded_for`. ([#1577](rack/rack#1577), [@ioquatix](https://github.com/ioquatix)) ## [2.2.0] - 2020-02-08 ### SPEC Changes - `rack.session` request environment entry must respond to `to_hash` and return unfrozen Hash. ([@jeremyevans](https://github.com/jeremyevans)) - Request environment cannot be frozen. ([@jeremyevans](https://github.com/jeremyevans)) - CGI values in the request environment with non-ASCII characters must use ASCII-8BIT encoding. ([@jeremyevans](https://github.com/jeremyevans)) - Improve SPEC/lint relating to SERVER_NAME, SERVER_PORT and HTTP_HOST. ([#1561](rack/rack#1561), [@ioquatix](https://github.com/ioquatix)) ### Added - `rackup` supports multiple `-r` options and will require all arguments. ([@jeremyevans](https://github.com/jeremyevans)) - `Server` supports an array of paths to require for the `:require` option. ([@khotta](https://github.com/khotta)) - `Files` supports multipart range requests. ([@fatkodima](https://github.com/fatkodima)) - `Multipart::UploadedFile` supports an IO-like object instead of using the filesystem, using `:filename` and `:io` options. ([@jeremyevans](https://github.com/jeremyevans)) - `Multipart::UploadedFile` supports keyword arguments `:path`, `:content_type`, and `:binary` in addition to positional arguments. ([@jeremyevans](https://github.com/jeremyevans)) - `Static` supports a `:cascade` option for calling the app if there is no matching file. ([@jeremyevans](https://github.com/jeremyevans)) - `Session::Abstract::SessionHash#dig`. ([@jeremyevans](https://github.com/jeremyevans)) - `Response.[]` and `MockResponse.[]` for creating instances using status, headers, and body. ([@ioquatix](https://github.com/ioquatix)) - Convenient cache and content type methods for `Rack::Response`. ([#1555](rack/rack#1555), [@ioquatix](https://github.com/ioquatix)) ### Changed - `Request#params` no longer rescues EOFError. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` uses a streaming approach, significantly improving time to first byte for large directories. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` no longer includes a Parent directory link in the root directory index. ([@jeremyevans](https://github.com/jeremyevans)) - `QueryParser#parse_nested_query` uses original backtrace when reraising exception with new class. ([@jeremyevans](https://github.com/jeremyevans)) - `ConditionalGet` follows RFC 7232 precedence if both If-None-Match and If-Modified-Since headers are provided. ([@jeremyevans](https://github.com/jeremyevans)) - `.ru` files supports the `frozen-string-literal` magic comment. ([@eregon](https://github.com/eregon)) - Rely on autoload to load constants instead of requiring internal files, make sure to require 'rack' and not just 'rack/...'. ([@jeremyevans](https://github.com/jeremyevans)) - `Etag` will continue sending ETag even if the response should not be cached. ([@henm](https://github.com/henm)) - `Request#host_with_port` no longer includes a colon for a missing or empty port. ([@AlexWayfer](https://github.com/AlexWayfer)) - All handlers uses keywords arguments instead of an options hash argument. ([@ioquatix](https://github.com/ioquatix)) - `Files` handling of range requests no longer return a body that supports `to_path`, to ensure range requests are handled correctly. ([@jeremyevans](https://github.com/jeremyevans)) - `Multipart::Generator` only includes `Content-Length` for files with paths, and `Content-Disposition` `filename` if the `UploadedFile` instance has one. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#ssl?` is true for the `wss` scheme (secure websockets). ([@jeremyevans](https://github.com/jeremyevans)) - `Rack::HeaderHash` is memoized by default. ([#1549](rack/rack#1549), [@ioquatix](https://github.com/ioquatix)) - `Rack::Directory` allow directory traversal inside root directory. ([#1417](rack/rack#1417), [@ThomasSevestre](https://github.com/ThomasSevestre)) - Sort encodings by server preference. ([#1184](rack/rack#1184), [@ioquatix](https://github.com/ioquatix), [@wjordan](https://github.com/wjordan)) - Rework host/hostname/authority implementation in `Rack::Request`. `#host` and `#host_with_port` have been changed to correctly return IPv6 addresses formatted with square brackets, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-3.2.2). ([#1561](rack/rack#1561), [@ioquatix](https://github.com/ioquatix)) - `Rack::Builder` parsing options on first `#\` line is deprecated. ([#1574](rack/rack#1574), [@ioquatix](https://github.com/ioquatix)) ### Removed - `Directory#path` as it was not used and always returned nil. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy#each` as it was only needed to work around a bug in Ruby <1.9.3. ([@jeremyevans](https://github.com/jeremyevans)) - `URLMap::INFINITY` and `URLMap::NEGATIVE_INFINITY`, in favor of `Float::INFINITY`. ([@ch1c0t](https://github.com/ch1c0t)) - Deprecation of `Rack::File`. It will be deprecated again in rack 2.2 or 3.0. ([@rafaelfranca](https://github.com/rafaelfranca)) - Support for Ruby 2.2 as it is well past EOL. ([@ioquatix](https://github.com/ioquatix)) - Remove `Rack::Files#response_body` as the implementation was broken. ([#1153](rack/rack#1153), [@ioquatix](https://github.com/ioquatix)) - Remove `SERVER_ADDR` which was never part of the original SPEC. ([#1573](rack/rack#1573), [@ioquatix](https://github.com/ioquatix)) ### Fixed - `Directory` correctly handles root paths containing glob metacharacters. ([@jeremyevans](https://github.com/jeremyevans)) - `Cascade` uses a new response object for each call if initialized with no apps. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy` correctly delegates keyword arguments to the body object on Ruby 2.7+. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy#method` correctly handles methods delegated to the body object. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#host` and `Request#host_with_port` handle IPv6 addresses correctly. ([@AlexWayfer](https://github.com/AlexWayfer)) - `Lint` checks when response hijacking that `rack.hijack` is called with a valid object. ([@jeremyevans](https://github.com/jeremyevans)) - `Response#write` correctly updates `Content-Length` if initialized with a body. ([@jeremyevans](https://github.com/jeremyevans)) - `CommonLogger` includes `SCRIPT_NAME` when logging. ([@Erol](https://github.com/Erol)) - `Utils.parse_nested_query` correctly handles empty queries, using an empty instance of the params class instead of a hash. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` correctly escapes paths in links. ([@yous](https://github.com/yous)) - `Request#delete_cookie` and related `Utils` methods handle `:domain` and `:path` options in same call. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#delete_cookie` and related `Utils` methods do an exact match on `:domain` and `:path` options. ([@jeremyevans](https://github.com/jeremyevans)) - `Static` no longer adds headers when a gzipped file request has a 304 response. ([@chooh](https://github.com/chooh)) - `ContentLength` sets `Content-Length` response header even for bodies not responding to `to_ary`. ([@jeremyevans](https://github.com/jeremyevans)) - Thin handler supports options passed directly to `Thin::Controllers::Controller`. ([@jeremyevans](https://github.com/jeremyevans)) - WEBrick handler no longer ignores `:BindAddress` option. ([@jeremyevans](https://github.com/jeremyevans)) - `ShowExceptions` handles invalid POST data. ([@jeremyevans](https://github.com/jeremyevans)) - Basic authentication requires a password, even if the password is empty. ([@jeremyevans](https://github.com/jeremyevans)) - `Lint` checks response is array with 3 elements, per SPEC. ([@jeremyevans](https://github.com/jeremyevans)) - Support for using `:SSLEnable` option when using WEBrick handler. (Gregor Melhorn) - Close response body after buffering it when buffering. ([@ioquatix](https://github.com/ioquatix)) - Only accept `;` as delimiter when parsing cookies. ([@mrageh](https://github.com/mrageh)) - `Utils::HeaderHash#clear` clears the name mapping as well. ([@raxoft](https://github.com/raxoft)) - Support for passing `nil` `Rack::Files.new`, which notably fixes Rails' current `ActiveStorage::FileServer` implementation. ([@ioquatix](https://github.com/ioquatix)) ### Documentation - CHANGELOG updates. ([@Aupajo](https://github.com/aupajo)) - Added [CONTRIBUTING](CONTRIBUTING.md). ([@dblock](https://github.com/dblock)) ## [2.1.2] - 2020-01-27 - Fix multipart parser for some files to prevent denial of service ([@aiomaster](https://github.com/aiomaster)) - Fix `Rack::Builder#use` with keyword arguments ([@kamipo](https://github.com/kamipo)) - Skip deflating in Rack::Deflater if Content-Length is 0 ([@jeremyevans](https://github.com/jeremyevans)) - Remove `SessionHash#transform_keys`, no longer needed ([@pavel](https://github.com/pavel)) - Add to_hash to wrap Hash and Session classes ([@oleh-demyanyuk](https://github.com/oleh-demyanyuk)) - Handle case where session id key is requested but missing ([@jeremyevans](https://github.com/jeremyevans)) ## [2.1.1] - 2020-01-12 - Remove `Rack::Chunked` from `Rack::Server` default middleware. ([#1475](rack/rack#1475), [@ioquatix](https://github.com/ioquatix)) ## 2.1.0 _Note: There are many unreleased changes in Rack (`master` is around 300 commits ahead of `2-0-stable`), and below is not an exhaustive list. If you would like to help out and document some of the unreleased changes, PRs are welcome._ ### Added - Add support for `SameSite=None` cookie value. ([@hennikul](https://github.com/hennikul)) - Add trailer headers. ([@eileencodes](https://github.com/eileencodes)) - Add MIME Types for video streaming. ([@styd](https://github.com/styd)) - Add MIME Type for WASM. ([@buildrtech](https://github.com/buildrtech)) - Add `Early Hints(103)` to status codes. ([@egtra](https://github.com/egtra)) - Add `Too Early(425)` to status codes. ([@y-yagi]((https://github.com/y-yagi))) - Add `Bandwidth Limit Exceeded(509)` to status codes. ([@CJKinni](https://github.com/CJKinni)) - Add method for custom `ip_filter`. ([@svcastaneda](https://github.com/svcastaneda)) - Add boot-time profiling capabilities to `rackup`. ([@tenderlove](https://github.com/tenderlove)) - Add multi mapping support for `X-Accel-Mappings` header. ([@yoshuki](https://github.com/yoshuki)) - Add `sync: false` option to `Rack::Deflater`. (Eric Wong) - Add `Builder#freeze_app` to freeze application and all middleware instances. ([@jeremyevans](https://github.com/jeremyevans)) - Add API to extract cookies from `Rack::MockResponse`. ([@petercline](https://github.com/petercline)) ### Changed - Don't propagate nil values from middleware. ([@ioquatix](https://github.com/ioquatix)) - Lazily initialize the response body and only buffer it if required. ([@ioquatix](https://github.com/ioquatix)) - Fix deflater zlib buffer errors on empty body part. ([@felixbuenemann](https://github.com/felixbuenemann)) - Set `X-Accel-Redirect` to percent-encoded path. ([@diskkid](https://github.com/diskkid)) - Remove unnecessary buffer growing when parsing multipart. ([@tainoe](https://github.com/tainoe)) - Expand the root path in `Rack::Static` upon initialization. ([@rosenfeld](https://github.com/rosenfeld)) - Make `ShowExceptions` work with binary data. ([@axyjo](https://github.com/axyjo)) - Use buffer string when parsing multipart requests. ([@janko-m](https://github.com/janko-m)) - Support optional UTF-8 Byte Order Mark (BOM) in config.ru. ([@mikegee](https://github.com/mikegee)) - Handle `X-Forwarded-For` with optional port. ([@dpritchett](https://github.com/dpritchett)) - Use `Time#httpdate` format for Expires, as proposed by RFC 7231. ([@nanaya](https://github.com/nanaya)) - Make `Utils.status_code` raise an error when the status symbol is invalid instead of `500`. ([@adambutler](https://github.com/adambutler)) - Rename `Request::SCHEME_WHITELIST` to `Request::ALLOWED_SCHEMES`. - Make `Multipart::Parser.get_filename` accept files with `+` in their name. ([@lucaskanashiro](https://github.com/lucaskanashiro)) - Add Falcon to the default handler fallbacks. ([@ioquatix](https://github.com/ioquatix)) - Update codebase to avoid string mutations in preparation for `frozen_string_literals`. ([@pat](https://github.com/pat)) - Change `MockRequest#env_for` to rely on the input optionally responding to `#size` instead of `#length`. ([@janko](https://github.com/janko)) - Rename `Rack::File` -> `Rack::Files` and add deprecation notice. ([@postmodern](https://github.com/postmodern)). ### Removed - Remove `to_ary` from Response ([@tenderlove](https://github.com/tenderlove)) - Deprecate `Rack::Session::Memcache` in favor of `Rack::Session::Dalli` from dalli gem ([@fatkodima](https://github.com/fatkodima)) ### Documentation - Update broken example in `Session::Abstract::ID` documentation. ([tonytonyjan](https://github.com/tonytonyjan)) - Add Padrino to the list of frameworks implmenting Rack. ([@wikimatze](https://github.com/wikimatze)) - Remove Mongrel from the suggested server options in the help output. ([@tricknotes](https://github.com/tricknotes)) - Replace `HISTORY.md` and `NEWS.md` with `CHANGELOG.md`. ([@twitnithegirl](https://github.com/twitnithegirl)) - Backfill `CHANGELOG.md` from 2.0.1 to 2.0.7 releases. ([@drenmi](https://github.com/Drenmi)) ## [2.0.8] - 2019-12-08 - [[CVE-2019-16782](https://nvd.nist.gov/vuln/detail/CVE-2019-16782)] Prevent timing attacks targeted at session ID lookup. BREAKING CHANGE: Session ID is now a SessionId instance instead of a String. ([@tenderlove](https://github.com/tenderlove), [@rafaelfranca](https://github.com/rafaelfranca))
Update ruby-rack to 2.2.2. ## [2.2.2] - 2020-02-11 ### Fixed - Fix incorrect `Rack::Request#host` value. ([#1591](rack/rack#1591), [@ioquatix](https://github.com/ioquatix)) - Revert `Rack::Handler::Thin` implementation. ([#1583](rack/rack#1583), [@jeremyevans](https://github.com/jeremyevans)) - Double assignment is still needed to prevent an "unused variable" warning. ([#1589](rack/rack#1589), [@kamipo](https://github.com/kamipo)) - Fix to handle same_site option for session pool. ([#1587](rack/rack#1587), [@kamipo](https://github.com/kamipo)) ## [2.2.1] - 2020-02-09 ### Fixed - Rework `Rack::Request#ip` to handle empty `forwarded_for`. ([#1577](rack/rack#1577), [@ioquatix](https://github.com/ioquatix)) ## [2.2.0] - 2020-02-08 ### SPEC Changes - `rack.session` request environment entry must respond to `to_hash` and return unfrozen Hash. ([@jeremyevans](https://github.com/jeremyevans)) - Request environment cannot be frozen. ([@jeremyevans](https://github.com/jeremyevans)) - CGI values in the request environment with non-ASCII characters must use ASCII-8BIT encoding. ([@jeremyevans](https://github.com/jeremyevans)) - Improve SPEC/lint relating to SERVER_NAME, SERVER_PORT and HTTP_HOST. ([#1561](rack/rack#1561), [@ioquatix](https://github.com/ioquatix)) ### Added - `rackup` supports multiple `-r` options and will require all arguments. ([@jeremyevans](https://github.com/jeremyevans)) - `Server` supports an array of paths to require for the `:require` option. ([@khotta](https://github.com/khotta)) - `Files` supports multipart range requests. ([@fatkodima](https://github.com/fatkodima)) - `Multipart::UploadedFile` supports an IO-like object instead of using the filesystem, using `:filename` and `:io` options. ([@jeremyevans](https://github.com/jeremyevans)) - `Multipart::UploadedFile` supports keyword arguments `:path`, `:content_type`, and `:binary` in addition to positional arguments. ([@jeremyevans](https://github.com/jeremyevans)) - `Static` supports a `:cascade` option for calling the app if there is no matching file. ([@jeremyevans](https://github.com/jeremyevans)) - `Session::Abstract::SessionHash#dig`. ([@jeremyevans](https://github.com/jeremyevans)) - `Response.[]` and `MockResponse.[]` for creating instances using status, headers, and body. ([@ioquatix](https://github.com/ioquatix)) - Convenient cache and content type methods for `Rack::Response`. ([#1555](rack/rack#1555), [@ioquatix](https://github.com/ioquatix)) ### Changed - `Request#params` no longer rescues EOFError. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` uses a streaming approach, significantly improving time to first byte for large directories. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` no longer includes a Parent directory link in the root directory index. ([@jeremyevans](https://github.com/jeremyevans)) - `QueryParser#parse_nested_query` uses original backtrace when reraising exception with new class. ([@jeremyevans](https://github.com/jeremyevans)) - `ConditionalGet` follows RFC 7232 precedence if both If-None-Match and If-Modified-Since headers are provided. ([@jeremyevans](https://github.com/jeremyevans)) - `.ru` files supports the `frozen-string-literal` magic comment. ([@eregon](https://github.com/eregon)) - Rely on autoload to load constants instead of requiring internal files, make sure to require 'rack' and not just 'rack/...'. ([@jeremyevans](https://github.com/jeremyevans)) - `Etag` will continue sending ETag even if the response should not be cached. ([@henm](https://github.com/henm)) - `Request#host_with_port` no longer includes a colon for a missing or empty port. ([@AlexWayfer](https://github.com/AlexWayfer)) - All handlers uses keywords arguments instead of an options hash argument. ([@ioquatix](https://github.com/ioquatix)) - `Files` handling of range requests no longer return a body that supports `to_path`, to ensure range requests are handled correctly. ([@jeremyevans](https://github.com/jeremyevans)) - `Multipart::Generator` only includes `Content-Length` for files with paths, and `Content-Disposition` `filename` if the `UploadedFile` instance has one. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#ssl?` is true for the `wss` scheme (secure websockets). ([@jeremyevans](https://github.com/jeremyevans)) - `Rack::HeaderHash` is memoized by default. ([#1549](rack/rack#1549), [@ioquatix](https://github.com/ioquatix)) - `Rack::Directory` allow directory traversal inside root directory. ([#1417](rack/rack#1417), [@ThomasSevestre](https://github.com/ThomasSevestre)) - Sort encodings by server preference. ([#1184](rack/rack#1184), [@ioquatix](https://github.com/ioquatix), [@wjordan](https://github.com/wjordan)) - Rework host/hostname/authority implementation in `Rack::Request`. `#host` and `#host_with_port` have been changed to correctly return IPv6 addresses formatted with square brackets, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-3.2.2). ([#1561](rack/rack#1561), [@ioquatix](https://github.com/ioquatix)) - `Rack::Builder` parsing options on first `#\` line is deprecated. ([#1574](rack/rack#1574), [@ioquatix](https://github.com/ioquatix)) ### Removed - `Directory#path` as it was not used and always returned nil. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy#each` as it was only needed to work around a bug in Ruby <1.9.3. ([@jeremyevans](https://github.com/jeremyevans)) - `URLMap::INFINITY` and `URLMap::NEGATIVE_INFINITY`, in favor of `Float::INFINITY`. ([@ch1c0t](https://github.com/ch1c0t)) - Deprecation of `Rack::File`. It will be deprecated again in rack 2.2 or 3.0. ([@rafaelfranca](https://github.com/rafaelfranca)) - Support for Ruby 2.2 as it is well past EOL. ([@ioquatix](https://github.com/ioquatix)) - Remove `Rack::Files#response_body` as the implementation was broken. ([#1153](rack/rack#1153), [@ioquatix](https://github.com/ioquatix)) - Remove `SERVER_ADDR` which was never part of the original SPEC. ([#1573](rack/rack#1573), [@ioquatix](https://github.com/ioquatix)) ### Fixed - `Directory` correctly handles root paths containing glob metacharacters. ([@jeremyevans](https://github.com/jeremyevans)) - `Cascade` uses a new response object for each call if initialized with no apps. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy` correctly delegates keyword arguments to the body object on Ruby 2.7+. ([@jeremyevans](https://github.com/jeremyevans)) - `BodyProxy#method` correctly handles methods delegated to the body object. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#host` and `Request#host_with_port` handle IPv6 addresses correctly. ([@AlexWayfer](https://github.com/AlexWayfer)) - `Lint` checks when response hijacking that `rack.hijack` is called with a valid object. ([@jeremyevans](https://github.com/jeremyevans)) - `Response#write` correctly updates `Content-Length` if initialized with a body. ([@jeremyevans](https://github.com/jeremyevans)) - `CommonLogger` includes `SCRIPT_NAME` when logging. ([@Erol](https://github.com/Erol)) - `Utils.parse_nested_query` correctly handles empty queries, using an empty instance of the params class instead of a hash. ([@jeremyevans](https://github.com/jeremyevans)) - `Directory` correctly escapes paths in links. ([@yous](https://github.com/yous)) - `Request#delete_cookie` and related `Utils` methods handle `:domain` and `:path` options in same call. ([@jeremyevans](https://github.com/jeremyevans)) - `Request#delete_cookie` and related `Utils` methods do an exact match on `:domain` and `:path` options. ([@jeremyevans](https://github.com/jeremyevans)) - `Static` no longer adds headers when a gzipped file request has a 304 response. ([@chooh](https://github.com/chooh)) - `ContentLength` sets `Content-Length` response header even for bodies not responding to `to_ary`. ([@jeremyevans](https://github.com/jeremyevans)) - Thin handler supports options passed directly to `Thin::Controllers::Controller`. ([@jeremyevans](https://github.com/jeremyevans)) - WEBrick handler no longer ignores `:BindAddress` option. ([@jeremyevans](https://github.com/jeremyevans)) - `ShowExceptions` handles invalid POST data. ([@jeremyevans](https://github.com/jeremyevans)) - Basic authentication requires a password, even if the password is empty. ([@jeremyevans](https://github.com/jeremyevans)) - `Lint` checks response is array with 3 elements, per SPEC. ([@jeremyevans](https://github.com/jeremyevans)) - Support for using `:SSLEnable` option when using WEBrick handler. (Gregor Melhorn) - Close response body after buffering it when buffering. ([@ioquatix](https://github.com/ioquatix)) - Only accept `;` as delimiter when parsing cookies. ([@mrageh](https://github.com/mrageh)) - `Utils::HeaderHash#clear` clears the name mapping as well. ([@raxoft](https://github.com/raxoft)) - Support for passing `nil` `Rack::Files.new`, which notably fixes Rails' current `ActiveStorage::FileServer` implementation. ([@ioquatix](https://github.com/ioquatix)) ### Documentation - CHANGELOG updates. ([@Aupajo](https://github.com/aupajo)) - Added [CONTRIBUTING](CONTRIBUTING.md). ([@dblock](https://github.com/dblock)) ## [2.1.2] - 2020-01-27 - Fix multipart parser for some files to prevent denial of service ([@aiomaster](https://github.com/aiomaster)) - Fix `Rack::Builder#use` with keyword arguments ([@kamipo](https://github.com/kamipo)) - Skip deflating in Rack::Deflater if Content-Length is 0 ([@jeremyevans](https://github.com/jeremyevans)) - Remove `SessionHash#transform_keys`, no longer needed ([@pavel](https://github.com/pavel)) - Add to_hash to wrap Hash and Session classes ([@oleh-demyanyuk](https://github.com/oleh-demyanyuk)) - Handle case where session id key is requested but missing ([@jeremyevans](https://github.com/jeremyevans)) ## [2.1.1] - 2020-01-12 - Remove `Rack::Chunked` from `Rack::Server` default middleware. ([#1475](rack/rack#1475), [@ioquatix](https://github.com/ioquatix)) ## 2.1.0 _Note: There are many unreleased changes in Rack (`master` is around 300 commits ahead of `2-0-stable`), and below is not an exhaustive list. If you would like to help out and document some of the unreleased changes, PRs are welcome._ ### Added - Add support for `SameSite=None` cookie value. ([@hennikul](https://github.com/hennikul)) - Add trailer headers. ([@eileencodes](https://github.com/eileencodes)) - Add MIME Types for video streaming. ([@styd](https://github.com/styd)) - Add MIME Type for WASM. ([@buildrtech](https://github.com/buildrtech)) - Add `Early Hints(103)` to status codes. ([@egtra](https://github.com/egtra)) - Add `Too Early(425)` to status codes. ([@y-yagi]((https://github.com/y-yagi))) - Add `Bandwidth Limit Exceeded(509)` to status codes. ([@CJKinni](https://github.com/CJKinni)) - Add method for custom `ip_filter`. ([@svcastaneda](https://github.com/svcastaneda)) - Add boot-time profiling capabilities to `rackup`. ([@tenderlove](https://github.com/tenderlove)) - Add multi mapping support for `X-Accel-Mappings` header. ([@yoshuki](https://github.com/yoshuki)) - Add `sync: false` option to `Rack::Deflater`. (Eric Wong) - Add `Builder#freeze_app` to freeze application and all middleware instances. ([@jeremyevans](https://github.com/jeremyevans)) - Add API to extract cookies from `Rack::MockResponse`. ([@petercline](https://github.com/petercline)) ### Changed - Don't propagate nil values from middleware. ([@ioquatix](https://github.com/ioquatix)) - Lazily initialize the response body and only buffer it if required. ([@ioquatix](https://github.com/ioquatix)) - Fix deflater zlib buffer errors on empty body part. ([@felixbuenemann](https://github.com/felixbuenemann)) - Set `X-Accel-Redirect` to percent-encoded path. ([@diskkid](https://github.com/diskkid)) - Remove unnecessary buffer growing when parsing multipart. ([@tainoe](https://github.com/tainoe)) - Expand the root path in `Rack::Static` upon initialization. ([@rosenfeld](https://github.com/rosenfeld)) - Make `ShowExceptions` work with binary data. ([@axyjo](https://github.com/axyjo)) - Use buffer string when parsing multipart requests. ([@janko-m](https://github.com/janko-m)) - Support optional UTF-8 Byte Order Mark (BOM) in config.ru. ([@mikegee](https://github.com/mikegee)) - Handle `X-Forwarded-For` with optional port. ([@dpritchett](https://github.com/dpritchett)) - Use `Time#httpdate` format for Expires, as proposed by RFC 7231. ([@nanaya](https://github.com/nanaya)) - Make `Utils.status_code` raise an error when the status symbol is invalid instead of `500`. ([@adambutler](https://github.com/adambutler)) - Rename `Request::SCHEME_WHITELIST` to `Request::ALLOWED_SCHEMES`. - Make `Multipart::Parser.get_filename` accept files with `+` in their name. ([@lucaskanashiro](https://github.com/lucaskanashiro)) - Add Falcon to the default handler fallbacks. ([@ioquatix](https://github.com/ioquatix)) - Update codebase to avoid string mutations in preparation for `frozen_string_literals`. ([@pat](https://github.com/pat)) - Change `MockRequest#env_for` to rely on the input optionally responding to `#size` instead of `#length`. ([@janko](https://github.com/janko)) - Rename `Rack::File` -> `Rack::Files` and add deprecation notice. ([@postmodern](https://github.com/postmodern)). ### Removed - Remove `to_ary` from Response ([@tenderlove](https://github.com/tenderlove)) - Deprecate `Rack::Session::Memcache` in favor of `Rack::Session::Dalli` from dalli gem ([@fatkodima](https://github.com/fatkodima)) ### Documentation - Update broken example in `Session::Abstract::ID` documentation. ([tonytonyjan](https://github.com/tonytonyjan)) - Add Padrino to the list of frameworks implmenting Rack. ([@wikimatze](https://github.com/wikimatze)) - Remove Mongrel from the suggested server options in the help output. ([@tricknotes](https://github.com/tricknotes)) - Replace `HISTORY.md` and `NEWS.md` with `CHANGELOG.md`. ([@twitnithegirl](https://github.com/twitnithegirl)) - Backfill `CHANGELOG.md` from 2.0.1 to 2.0.7 releases. ([@drenmi](https://github.com/Drenmi)) ## [2.0.8] - 2019-12-08 - [[CVE-2019-16782](https://nvd.nist.gov/vuln/detail/CVE-2019-16782)] Prevent timing attacks targeted at session ID lookup. BREAKING CHANGE: Session ID is now a SessionId instance instead of a String. ([@tenderlove](https://github.com/tenderlove), [@rafaelfranca](https://github.com/rafaelfranca))
The motivation/measurements/benchmarks are in
benchmark/header-hash/README.md.Fixes the main performance issues outlined by #738