Updated documentation in preparation for Rack 3.0.0 release. (#1943)

This commit is contained in:
Samuel Williams 2022-08-06 10:45:22 +12:00 committed by GitHub
parent 1e4c18d895
commit db43fc24ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 600 additions and 341 deletions

8
.editorconfig Normal file
View File

@ -0,0 +1,8 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true

View File

@ -2,7 +2,7 @@
All notable changes to this project will be documented in this file. For info on how to format all future additions to this file please reference [Keep A Changelog](https://keepachangelog.com/en/1.0.0/).
## [3.0.0] - Unreleased
## [3.0.0.beta1] - 2022-08-05
### Security

View File

@ -1,21 +1,25 @@
Contributing to Rack
=====================
# Contributing to Rack
Rack is work of [hundreds of contributors](https://github.com/rack/rack/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/rack/rack/pulls), [propose features and discuss issues](https://github.com/rack/rack/issues). When in doubt, post to the [rack-devel](http://groups.google.com/group/rack-devel) mailing list.
Rack is work of [hundreds of
contributors](https://github.com/rack/rack/graphs/contributors). You're
encouraged to submit [pull requests](https://github.com/rack/rack/pulls) and
[propose features and discuss issues](https://github.com/rack/rack/issues).
#### Fork the Project
## Fork the Project
Fork the [project on GitHub](https://github.com/rack/rack) and check out your copy.
Fork the [project on GitHub](https://github.com/rack/rack) and check out your
copy.
```
git clone https://github.com/contributor/rack.git
git clone https://github.com/(your-github-username)/rack.git
cd rack
git remote add upstream https://github.com/rack/rack.git
```
#### Create a Topic Branch
## Create a Topic Branch
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
Make sure your fork is up-to-date and create a topic branch for your feature or
bug fix.
```
git checkout main
@ -23,7 +27,7 @@ git pull upstream main
git checkout -b my-feature-branch
```
#### Bundle Install and Quick Test
## Bundle Install and Quick Test
Ensure that you can build the project and run quick tests.
@ -32,7 +36,7 @@ bundle install --without extra
bundle exec rake test
```
#### Running All Tests
## Running All Tests
Install all dependencies.
@ -46,25 +50,15 @@ Run all tests.
rake test
```
The test suite has no dependencies outside of the core Ruby installation and bacon.
## Write Tests
Some tests will be skipped if a dependency is not found.
Try to write a test that reproduces the problem you're trying to fix or
describes a feature that you want to build.
To run the test suite completely, you need:
We definitely appreciate pull requests that highlight or reproduce a problem,
even without a fix.
* fcgi
* dalli
* thin
To test Memcache sessions, you need memcached (will be run on port 11211) and dalli installed.
#### Write Tests
Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build.
We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
#### Write Code
## Write Code
Implement your feature or bug fix.
@ -74,15 +68,15 @@ Make sure that all tests pass:
bundle exec rake test
```
#### Write Documentation
## Write Documentation
Document any external behavior in the [README](README.rdoc).
Document any external behavior in the [README](README.md).
#### Update Changelog
## Update Changelog
Add a line to [CHANGELOG](CHANGELOG.md).
#### Commit Changes
## Commit Changes
Make sure git knows your name and email address:
@ -91,24 +85,27 @@ git config --global user.name "Your Name"
git config --global user.email "contributor@example.com"
```
Writing good commit logs is important. A commit log should describe what changed and why.
Writing good commit logs is important. A commit log should describe what changed
and why.
```
git add ...
git commit
```
#### Push
## Push
```
git push origin my-feature-branch
```
#### Make a Pull Request
## Make a Pull Request
Go to https://github.com/contributor/rack and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
Go to your fork of rack on GitHub and select your feature branch. Click the
'Pull Request' button and fill out the form. Pull requests are usually
reviewed within a few days.
#### Rebase
## Rebase
If you've been working on a change for a while, rebase with upstream/main.
@ -118,7 +115,7 @@ git rebase upstream/main
git push origin my-feature-branch -f
```
#### Make Required Changes
## Make Required Changes
Amend your previous commit and force push the changes.
@ -127,14 +124,19 @@ git commit --amend
git push origin my-feature-branch -f
```
#### Check on Your Pull Request
## Check on Your Pull Request
Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
Go back to your pull request after a few minutes and see whether it passed
tests with GitHub Actions. Everything should look green, otherwise fix issues and
amend your commit as described above.
#### Be Patient
## Be Patient
It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there!
It's likely that your change will not be merged and that the nitpicky
maintainers will ask you to do more, or fix seemingly benign problems. Hang in
there!
#### Thank You
## Thank You
Please do know that we really appreciate and value your time and work. We love you, really.
Please do know that we really appreciate and value your time and work. We love
you, really.

287
README.md Normal file
View File

@ -0,0 +1,287 @@
# ![Rack](contrib/logo.webp)
> **_NOTE:_** Rack v3.0.0beta1 was recently released. Please check the [Upgrade
> Guide](UPGRADE-GUIDE.md) for more details about migrating your existing
> servers, middlewares and applications. For detailed information on specific
> changes, check the [Change Log](CHANGELOG.md).
Rack provides a minimal, modular, and adaptable interface for developing web
applications in Ruby. By wrapping HTTP requests and responses in the simplest
way possible, it unifies and distills the bridge between web servers, web
frameworks, and web application into a single method call.
The exact details of this are described in the [Rack Specification], which all
Rack applications should conform to.
## Installation
Add the rack gem to your application bundle, or follow the instructions provided
by a [supported web framework](#supported-web-frameworks):
```bash
# Install it generally:
$ gem install rack
# or, add it to your current application gemfile:
$ bundle add rack
```
## Usage
Create a file called `config.ru` with the following contents:
```ruby
run do |env|
[200, {}, ["Hello World"]]
end
```
Run this using the rackup gem or another [supported web
server](#supported-web-servers).
```bash
$ gem install rackup
$ rackup
$ curl http://localhost:9292
Hello World
```
## Supported web servers
Rack is supported by a wide range of servers, including:
* [Agoo](https://github.com/ohler55/agoo)
* [Falcon](https://github.com/socketry/falcon) **(Rack 3 Compatible)**
* [Iodine](https://github.com/boazsegev/iodine)
* [NGINX Unit](https://unit.nginx.org/)
* [Phusion Passenger](https://www.phusionpassenger.com/) (which is mod_rack for
Apache and for nginx)
* [Puma](https://puma.io/)
* [Thin](https://github.com/macournoyer/thin)
* [Unicorn](https://yhbt.net/unicorn/)
* [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/)
* [Lamby](https://lamby.custominktech.com) (for AWS Lambda)
You will need to consult the server documentation to find out what features and
limitations they may have. In general, any valid Rack app will run the same on
all these servers, without changing anything.
### Rackup
Rack provides a separate gem, [rackup](https://github.com/rack/rackup) which is
a generic interface for running a Rack application on supported servers, which
include `WEBRick`, `Puma`, `Falcon` and others.
## Supported web frameworks
These frameworks and many others support the [Rack Specification]:
* [Camping](https://github.com/camping/camping)
* [Hanami](https://hanamirb.org/)
* [Padrino](https://padrinorb.com/)
* [Roda](https://github.com/jeremyevans/roda) **(Rack 3 Compatible)**
* [Ruby on Rails](https://rubyonrails.org/)
* [Sinatra](https://sinatrarb.com/)
* [Utopia](https://github.com/socketry/utopia) **(Rack 3 Compatible)**
* [WABuR](https://github.com/ohler55/wabur)
### Older (possibly unsupported) web frameworks
* [Ramaze](http://ramaze.net/)
* [Rum](https://github.com/leahneukirchen/rum)
## Available middleware shipped with Rack
Between the server and the framework, Rack can be customized to your
applications needs using middleware. Rack itself ships with the following
middleware:
* `Rack::CommonLogger` for creating Apache-style logfiles.
* `Rack::ConditionalGet` for returning [Not
Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304)
responses when the response has not changed.
* `Rack::Config` for modifying the environment before processing the request.
* `Rack::ContentLength` for setting a `content-length` header based on body
size.
* `Rack::ContentType` for setting a default `content-type` header for responses.
* `Rack::Deflater` for compressing responses with gzip.
* `Rack::ETag` for setting `etag` header on bodies that can be buffered.
* `Rack::Events` for providing easy hooks when a request is received and when
the response is sent.
* `Rack::Files` for serving static files.
* `Rack::Head` for returning an empty body for HEAD requests.
* `Rack::Lint` for checking conformance to the [Rack Specification].
* `Rack::Lock` for serializing requests using a mutex.
* `Rack::Logger` for setting a logger to handle logging errors.
* `Rack::MethodOverride` for modifying the request method based on a submitted
parameter.
* `Rack::Recursive` for including data from other paths in the application, and
for performing internal redirects.
* `Rack::Reloader` for reloading files if they have been modified.
* `Rack::Runtime` for including a response header with the time taken to process
the request.
* `Rack::Sendfile` for working with web servers that can use optimized file
serving for file system paths.
* `Rack::ShowException` for catching unhandled exceptions and presenting them in
a nice and helpful way with clickable backtrace.
* `Rack::ShowStatus` for using nice error pages for empty client error
responses.
* `Rack::Static` for more configurable serving of static files.
* `Rack::TempfileReaper` for removing temporary files creating during a request.
All these components use the same interface, which is described in detail in the
[Rack Specification]. These optional components can be used in any way you wish.
### Convenience interfaces
If you want to develop outside of existing frameworks, implement your own ones,
or develop middleware, Rack provides many helpers to create Rack applications
quickly and without doing the same web stuff all over:
* `Rack::Request` which also provides query string parsing and multipart
handling.
* `Rack::Response` for convenient generation of HTTP replies and cookie
handling.
* `Rack::MockRequest` and `Rack::MockResponse` for efficient and quick testing
of Rack application without real HTTP round-trips.
* `Rack::Cascade` for trying additional Rack applications if an application
returns a not found or method not supported response.
* `Rack::Directory` for serving files under a given directory, with directory
indexes.
* `Rack::MediaType` for parsing content-type headers.
* `Rack::Mime` for determining content-type based on file extension.
* `Rack::RewindableInput` for making any IO object rewindable, using a temporary
file buffer.
* `Rack::URLMap` to route to multiple applications inside the same process.
## Configuration
Rack exposes several configuration parameters to control various features of the
implementation.
### `param_depth_limit`
```ruby
Rack::Utils.param_depth_limit = 32 # default
```
The maximum amount of nesting allowed in parameters. For example, if set to 3,
this query string would be allowed:
```
?a[b][c]=d
```
but this query string would not be allowed:
```
?a[b][c][d]=e
```
Limiting the depth prevents a possible stack overflow when parsing parameters.
### `multipart_part_limit`
```ruby
Rack::Utils.multipart_part_limit = 128 # default
```
The maximum number of parts a request can contain. Accepting too many parts can
lead to the server running out of file handles.
The default is 128, which means that a single request can't upload more than 128
files at once. Set to 0 for no limit.
Can also be set via the `RACK_MULTIPART_PART_LIMIT` environment variable.
## Changelog
See [CHANGELOG.md](CHANGELOG.md).
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for specific details about how to make a
contribution to Rack.
Please post bugs, suggestions and patches to [GitHub
Issues](https://github.com/rack/rack/issues).
Please check our [Security Policy](https://github.com/rack/rack/security/policy)
for responsible disclosure and security bug reporting process. Due to wide usage
of the library, it is strongly preferred that we manage timing in order to
provide viable patches at the time of disclosure. Your assistance in this matter
is greatly appreciated.
## See Also
### `rack-contrib`
The plethora of useful middleware created the need for a project that collects
fresh Rack middleware. `rack-contrib` includes a variety of add-on components
for Rack and it is easy to contribute new modules.
* https://github.com/rack/rack-contrib
### `rack-session`
Provides convenient session management for Rack.
* https://github.com/rack/rack-session
## Thanks
The Rack Core Team, consisting of
* Aaron Patterson [tenderlove](https://github.com/tenderlove)
* Samuel Williams [ioquatix](https://github.com/ioquatix)
* Jeremy Evans [jeremyevans](https://github.com/jeremyevans)
* Eileen Uchitelle [eileencodes](https://github.com/eileencodes)
* Matthew Draper [matthewd](https://github.com/matthewd)
* Rafael França [rafaelfranca](https://github.com/rafaelfranca)
and the Rack Alumni
* Ryan Tomayko [rtomayko](https://github.com/rtomayko)
* Scytrin dai Kinthra [scytrin](https://github.com/scytrin)
* Leah Neukirchen [leahneukirchen](https://github.com/leahneukirchen)
* James Tucker [raggi](https://github.com/raggi)
* Josh Peek [josh](https://github.com/josh)
* José Valim [josevalim](https://github.com/josevalim)
* Michael Fellinger [manveru](https://github.com/manveru)
* Santiago Pastorino [spastorino](https://github.com/spastorino)
* Konstantin Haase [rkh](https://github.com/rkh)
would like to thank:
* Adrian Madrid, for the LiteSpeed handler.
* Christoffer Sawicki, for the first Rails adapter and `Rack::Deflater`.
* Tim Fletcher, for the HTTP authentication code.
* Luc Heinrich for the Cookie sessions, the static file handler and bugfixes.
* Armin Ronacher, for the logo and racktools.
* Alex Beregszaszi, Alexander Kahn, Anil Wadghule, Aredridel, Ben Alpert, Dan
Kubb, Daniel Roethlisberger, Matt Todd, Tom Robinson, Phil Hagelberg, S. Brent
Faulkner, Bosko Milekic, Daniel Rodríguez Troitiño, Genki Takiuchi, Geoffrey
Grosenbach, Julien Sanchez, Kamal Fariz Mahyuddin, Masayoshi Takahashi,
Patrick Aljordm, Mig, Kazuhiro Nishiyama, Jon Bardin, Konstantin Haase, Larry
Siden, Matias Korhonen, Sam Ruby, Simon Chiang, Tim Connor, Timur Batyrshin,
and Zach Brock for bug fixing and other improvements.
* Eric Wong, Hongli Lai, Jeremy Kemper for their continuous support and API
improvements.
* Yehuda Katz and Carl Lerche for refactoring rackup.
* Brian Candler, for `Rack::ContentType`.
* Graham Batty, for improved handler loading.
* Stephen Bannasch, for bug reports and documentation.
* Gary Wright, for proposing a better `Rack::Response` interface.
* Jonathan Buch, for improvements regarding `Rack::Response`.
* Armin Röhrl, for tracking down bugs in the Cookie generator.
* Alexander Kellett for testing the Gem and reviewing the announcement.
* Marcus Rückert, for help with configuring and debugging lighttpd.
* The WSGI team for the well-done and documented work they've done and Rack
builds up on.
* All bug reporters and patch contributors not mentioned above.
## License
Rack is released under the [MIT License](MIT-LICENSE).
[Rack Specification]: SPEC.rdoc

View File

@ -1,298 +0,0 @@
= rdoc-image:contrib/logo.webp
{<img src="https://github.com/rack/rack/workflows/Development/badge.svg" alt="GitHub Actions status" />}[https://github.com/rack/rack/actions?query=workflow%3ADevelopment]
{<img src="https://badge.fury.io/rb/rack.svg" alt="Gem Version" />}[http://badge.fury.io/rb/rack]
{<img src="http://inch-ci.org/github/rack/rack.svg?branch=main" alt="Inline docs" />}[http://inch-ci.org/github/rack/rack]
\Rack provides a minimal, modular, and adaptable interface for developing
web applications in Ruby. By wrapping HTTP requests and responses in
the simplest way possible, it unifies and distills the API for web
servers, web frameworks, and software in between (the so-called
middleware) into a single method call.
The exact details of this are described in the {\Rack specification}[link:SPEC.rdoc],
which all \Rack applications should conform to.
== Supported web servers
The included *handlers* can connect these web servers to \Rack:
* WEBrick[https://github.com/ruby/webrick]
* CGI
These web servers include \Rack handlers in their distributions:
* Agoo[https://github.com/ohler55/agoo]
* Falcon[https://github.com/socketry/falcon]
* Iodine[https://github.com/boazsegev/iodine]
* {NGINX Unit}[https://unit.nginx.org/]
* {Phusion Passenger}[https://www.phusionpassenger.com/] (which is mod_rack for Apache and for nginx)
* Puma[https://puma.io/]
* Thin[https://rubygems.org/gems/thin]
* Unicorn[https://yhbt.net/unicorn/]
* uWSGI[https://uwsgi-docs.readthedocs.io/en/latest/]
* Lamby[https://lamby.custominktech.com] (for AWS Lambda)
Any valid \Rack app will run the same on all these handlers, without
changing anything.
== Supported web frameworks
These frameworks and many others support the \Rack API:
* Camping[http://www.ruby-camping.com/]
* Coset[http://leahneukirchen.org/repos/coset/]
* Hanami[https://hanamirb.org/]
* Padrino[http://padrinorb.com/]
* Ramaze[http://ramaze.net/]
* Roda[https://github.com/jeremyevans/roda]
* {Ruby on Rails}[https://rubyonrails.org/]
* Rum[https://github.com/leahneukirchen/rum]
* Sinatra[http://sinatrarb.com/]
* Utopia[https://github.com/socketry/utopia]
* WABuR[https://github.com/ohler55/wabur]
== Available middleware shipped with \Rack
Between the server and the framework, \Rack can be customized to your
applications needs using middleware. \Rack itself ships with the following
middleware:
* Rack::Chunked, for streaming responses using chunked encoding.
* Rack::CommonLogger, for creating Apache-style logfiles.
* Rack::ConditionalGet, for returning not modified responses when the response
has not changed.
* Rack::Config, for modifying the environment before processing the request.
* Rack::ContentLength, for setting content-length header based on body size.
* Rack::ContentType, for setting default content-type header for responses.
* Rack::Deflater, for compressing responses with gzip.
* Rack::ETag, for setting ETag header on string bodies.
* Rack::Events, for providing easy hooks when a request is received
and when the response is sent.
* Rack::Files, for serving static files.
* Rack::Head, for returning an empty body for HEAD requests.
* Rack::Lint, for checking conformance to the \Rack API.
* Rack::Lock, for serializing requests using a mutex.
* Rack::Logger, for setting a logger to handle logging errors.
* Rack::MethodOverride, for modifying the request method based on a submitted
parameter.
* Rack::Recursive, for including data from other paths in the application,
and for performing internal redirects.
* Rack::Reloader, for reloading files if they have been modified.
* Rack::Runtime, for including a response header with the time taken to
process the request.
* Rack::Sendfile, for working with web servers that can use optimized
file serving for file system paths.
* Rack::ShowException, for catching unhandled exceptions and
presenting them in a nice and helpful way with clickable backtrace.
* Rack::ShowStatus, for using nice error pages for empty client error
responses.
* Rack::Static, for more configurable serving of static files.
* Rack::TempfileReaper, for removing temporary files creating during a
request.
All these components use the same interface, which is described in
detail in the \Rack specification. These optional components can be
used in any way you wish.
== Convenience
If you want to develop outside of existing frameworks, implement your
own ones, or develop middleware, \Rack provides many helpers to create
\Rack applications quickly and without doing the same web stuff all
over:
* Rack::Request, which also provides query string parsing and
multipart handling.
* Rack::Response, for convenient generation of HTTP replies and
cookie handling.
* Rack::MockRequest and Rack::MockResponse for efficient and quick
testing of \Rack application without real HTTP round-trips.
* Rack::Cascade, for trying additional \Rack applications if an
application returns a not found or method not supported response.
* Rack::Directory, for serving files under a given directory, with
directory indexes.
* Rack::MediaType, for parsing content-type headers.
* Rack::Mime, for determining content-type based on file extension.
* Rack::RewindableInput, for making any IO object rewindable, using
a temporary file buffer.
* Rack::URLMap, to route to multiple applications inside the same process.
== rack-contrib
The plethora of useful middleware created the need for a project that
collects fresh \Rack middleware. rack-contrib includes a variety of
add-on components for \Rack and it is easy to contribute new modules.
* https://github.com/rack/rack-contrib
== rackup
rackup is a useful tool for running \Rack applications, which uses the
Rack::Builder DSL to configure middleware and build up applications
easily.
rackup automatically figures out the environment it is run in, and
runs your application as FastCGI, CGI, or WEBrick---all from the
same configuration.
== Quick start
Try the lobster!
Either with the embedded WEBrick starter:
ruby -Ilib lib/rack/lobster.rb
Or with rackup:
bin/rackup -Ilib example/lobster.ru
By default, the lobster is found at http://localhost:9292.
== Installing with RubyGems
A Gem of \Rack is available at {rubygems.org}[https://rubygems.org/gems/rack]. You can install it with:
gem install rack
== Usage
You should require the library:
require 'rack'
\Rack uses autoload to automatically load other files \Rack ships with on demand,
so you should not need require paths under +rack+. If you require paths under
+rack+ without requiring +rack+ itself, things may not work correctly.
== Configuration
Several parameters can be modified on Rack::Utils to configure \Rack behaviour.
e.g:
Rack::Utils.param_depth_limit = 3
=== param_depth_limit
The maximum amount of nesting allowed in parameters.
For example, if set to 3, this query string would be allowed:
?a[b][c]=d
but this query string would not be allowed:
?a[b][c][d]=e
Limiting the depth prevents a possible stack overflow when parsing parameters.
Defaults to 32.
=== multipart_part_limit
The maximum number of parts a request can contain.
Accepting too many part can lead to the server running out of file handles.
The default is 128, which means that a single request can't upload more than 128 files at once.
Set to 0 for no limit.
Can also be set via the +RACK_MULTIPART_PART_LIMIT+ environment variable.
=== key_space_limit
No longer has an effect, deprecated.
== Changelog
See {CHANGELOG.md}[link:CHANGELOG.md].
== Contributing
See {CONTRIBUTING.md}[link:CONTRIBUTING.md].
== Contact
Please post bugs, suggestions and patches to
the bug tracker at {issues}[https://github.com/rack/rack/issues].
Please post security related bugs and suggestions to the core team at
<https://groups.google.com/forum/#!forum/rack-core> or rack-core@googlegroups.com. This
list is not public. Due to wide usage of the library, it is strongly preferred
that we manage timing in order to provide viable patches at the time of
disclosure. Your assistance in this matter is greatly appreciated.
Mailing list archives are available at
<https://groups.google.com/forum/#!forum/rack-devel>.
Git repository (send Git patches to the mailing list):
* https://github.com/rack/rack
You are also welcome to join the #rack channel on irc.freenode.net.
== Thanks
The \Rack Core Team, consisting of
* Aaron Patterson (tenderlove[https://github.com/tenderlove])
* Samuel Williams (ioquatix[https://github.com/ioquatix])
* Jeremy Evans (jeremyevans[https://github.com/jeremyevans])
* Eileen Uchitelle (eileencodes[https://github.com/eileencodes])
* Matthew Draper (matthewd[https://github.com/matthewd])
* Rafael França (rafaelfranca[https://github.com/rafaelfranca])
and the \Rack Alumni
* Ryan Tomayko (rtomayko[https://github.com/rtomayko])
* Scytrin dai Kinthra (scytrin[https://github.com/scytrin])
* Leah Neukirchen (leahneukirchen[https://github.com/leahneukirchen])
* James Tucker (raggi[https://github.com/raggi])
* Josh Peek (josh[https://github.com/josh])
* José Valim (josevalim[https://github.com/josevalim])
* Michael Fellinger (manveru[https://github.com/manveru])
* Santiago Pastorino (spastorino[https://github.com/spastorino])
* Konstantin Haase (rkh[https://github.com/rkh])
would like to thank:
* Adrian Madrid, for the LiteSpeed handler.
* Christoffer Sawicki, for the first Rails adapter and Rack::Deflater.
* Tim Fletcher, for the HTTP authentication code.
* Luc Heinrich for the Cookie sessions, the static file handler and bugfixes.
* Armin Ronacher, for the logo and racktools.
* Alex Beregszaszi, Alexander Kahn, Anil Wadghule, Aredridel, Ben
Alpert, Dan Kubb, Daniel Roethlisberger, Matt Todd, Tom Robinson,
Phil Hagelberg, S. Brent Faulkner, Bosko Milekic, Daniel Rodríguez
Troitiño, Genki Takiuchi, Geoffrey Grosenbach, Julien Sanchez, Kamal
Fariz Mahyuddin, Masayoshi Takahashi, Patrick Aljordm, Mig, Kazuhiro
Nishiyama, Jon Bardin, Konstantin Haase, Larry Siden, Matias
Korhonen, Sam Ruby, Simon Chiang, Tim Connor, Timur Batyrshin, and
Zach Brock for bug fixing and other improvements.
* Eric Wong, Hongli Lai, Jeremy Kemper for their continuous support
and API improvements.
* Yehuda Katz and Carl Lerche for refactoring rackup.
* Brian Candler, for Rack::ContentType.
* Graham Batty, for improved handler loading.
* Stephen Bannasch, for bug reports and documentation.
* Gary Wright, for proposing a better Rack::Response interface.
* Jonathan Buch, for improvements regarding Rack::Response.
* Armin Röhrl, for tracking down bugs in the Cookie generator.
* Alexander Kellett for testing the Gem and reviewing the announcement.
* Marcus Rückert, for help with configuring and debugging lighttpd.
* The WSGI team for the well-done and documented work they've done and
\Rack builds up on.
* All bug reporters and patch contributors not mentioned above.
== Links
\Rack:: <https://rack.github.io/>
Official \Rack repositories:: <https://github.com/rack>
\Rack Bug Tracking:: <https://github.com/rack/rack/issues>
rack-devel mailing list:: <https://groups.google.com/forum/#!forum/rack-devel>
== License
\Rack is released under the {MIT License}[https://opensource.org/licenses/MIT].

260
UPGRADE-GUIDE.md Normal file
View File

@ -0,0 +1,260 @@
# Rack 3 Upgrade Guide
This document is a work in progress, but outlines some of the key changes in
Rack 3 which you should be aware of in order to update your server, middleware
and/or applications.
## Interface Changes
### `config.ru` `Rack::Builder#run` now accepts block
Previously, `Rack::Builder#run` method would only accept a callable argument:
```ruby
run lambda{|env| [200, {}, ["Hello World"]]}
```
This can be rewritten more simply:
```ruby
run do |env|
[200, {}, ["Hello World"]]
end
```
### Response bodies can be used for bi-directional streaming
Previously, the `rack.hijack` response header could be used for implementing
bi-directional streaming (e.g. WebSockets).
```ruby
def call(env)
stream_callback = proc do |stream|
stream.read(...)
stream.write(...)
ensure
stream.close(...)
end
return [200, {'rack.hijack' => stream_callback}, []]
end
```
This feature was optional and tricky to use correctly. You can now achieve the
same thing by giving `stream_callback` as the response body:
```ruby
def call(env)
stream_callback = proc do |stream|
stream.read(...)
stream.write(...)
ensure
stream.close(...)
end
return [200, {}, stream_callback]
end
```
### `Rack::Session` is now moved to an external gem
Previously, `Rack::Session` was part of the `rack` gem. Not every application
needs it, and it increases the security surface area of the `rack`, so it was
decided to extract it into its own gem `rack-session` which can be updated
independently.
Applications that make use of `rack-session` will need to add that gem as a
dependency:
```ruby
gem 'rack-session'
```
## Request Changes
### `rack.version` is no longer required
Previously, the "rack protocol version" was available in `rack.version` but it
was not practically useful, so it has been removed as a requirement.
### `rack.multithread`/`rack.multiprocess`/`rack.run_once` are no longer required
Previously, servers tried to provide these keys to reflect the execution
environment. These come too late to be useful, so they have been removed as a
requirement.
### `rack.hijack?` now only applies to partial hijack
Previously, both full and partial hijiack were controlled by the presence and
value of `rack.hijack?`. Now, it only applies to partial hijack (which itself
has been effectively replaced by streaming bodies).
### `rack.hijack` alone indicates that you can execute a full hijack
Previously, `rack.hijack?` had to be truthy, as well as having `rack.hijack`
present in the request environment. Now, the presence of the `rack.hijack`
callback is enough.
### `rack.hijack_io` is removed
Previously, the server would try to set `rack.hijack_io` into the request
environment when `rack.hijack` was invoked for a full hijack. This was often
impossible if a middleware had called `env.dup`, so this requirement has been
dropped entirely.
### `rack.input` is no longer required to be rewindable
Previosuly, `rack.input` was required to be rewindable, i.e. `io.seek(0)` but
this was only generally possible with a file based backing, which prevented
efficient streaming of request bodies. Now, `rack.input` is not required to be
rewindable.
## Response Changes
### Response must be mutable
Rack 3 requires the response Array `[status, headers, body]` to be mutable.
Existing code that uses a frozen response will need to be changed:
```ruby
NOT_FOUND = [404, {}, ["Not Found"]].freeze
def call(env)
...
return NOT_FOUND
end
```
should be rewritten as:
```ruby
def not_found
[404, {}, ["Not Found"]]
end
def call(env)
...
return not_found
end
```
Note there is a subtle bug in the former version: the headers hash is mutable
and can be modified, and these modifications can leak into subsequent requests.
### Response headers must be a mutable hash
Rack 3 requires response headers to be a mutable hash. Previously it could be
any object that would respond to `#each` and yield `key`/`value` pairs.
Previously, the following was acceptable:
```ruby
def call(env)
return [200, [['content-type', 'text/plain']], ["Hello World]]
end
```
Now you must use a hash instance:
```ruby
def call(env)
return [200, {'content-type' => 'text/plain'}, ["Hello World]]
end
```
This ensures middleware can predictably update headers as needed.
### Response Headers must be lower case
Rack 3 requires all response headers to be lower case. This is to simplify
fetching and updating response headers. Previously you had to use something like
`Rack::HeadersHash`
```ruby
def call(env)
response = @app.call(env)
# HeaderHash must allocate internal objects and compute lower case keys:
headers = Rack::Utils::HeaderHash[response[1]]
cache_response(headers['ETag'], response)
...
end
```
but now you must just use the normal form for HTTP header:
```ruby
def call(env)
response = @app.call(env)
# A plain hash with lower case keys:
headers = response[1]
cache_response(headers['etag'], response)
...
end
```
### Multiple response header values are encoded using an `Array`
Response header values can be an Array to handle multiple values (and no longer
supports `\n` encoded headers). If you use `Rack::Response`, you don't need to
do anything, but if manually append values to response headers, you will need to
promote them to an Array, e.g.
```ruby
def set_cookie_header!(headers, key, value)
if header = headers[SET_COOKIE]
if header.is_a?(Array)
header << set_cookie_header(key, value)
else
headers[SET_COOKIE] = [header, set_cookie_header(key, value)]
end
else
headers[SET_COOKIE] = set_cookie_header(key, value)
end
end
```
### Response body might not respond to `#each`
Rack 3 has more strict requirements on response bodies. Previously, response
body would only need to respond to `#each` and optionally `#close`. In addition,
there was no way to determine whether it was safe to call `#each` and buffer the
response.
### Response bodies can be buffered if they expose `#to_ary`
If your body responds to `#to_ary` then it must return an `Array` whose contents
are identical to that produced by calling `#each`. If the body responds to both
`#to_ary` and `#close` then its implementation of `#to_ary` must also call
`#close`.
Previously, it was not possible to determine whether a response body was
immediately available (could be buffered) or was streaming chunks. This case is
now unambiguously exposed by `#to_ary`:
```ruby
def call(env)
status, headers, body = @app.call(env)
# Check if we can buffer the body into an Array, so we can compute a digest:
if body.respond_to?(:to_ary)
body = body.to_ary
digest = digest_body(body)
headers[ETAG_STRING] = %(W/"#{digest}") if digest
end
return [status, headers, body]
end
```
### Middleware should not directly modify the response body
Be aware that the response body might not respond to `#each` and you must now
check if the body responds to `#each` or not to determine if it is an enumerable
or streaming body.
You must not call `#each` directly on the body and instead you should return a
new body that calls `#each` on the original body.