webrick: prevent response splitting and header injection
Original patch by tenderlove (with minor style adjustments).
* lib/webrick/httpresponse.rb (send_header): call check_header
(check_header): raise on embedded CRLF in header value
* test/webrick/test_httpresponse.rb
(test_prevent_response_splitting_headers): new test
* (test_prevent_response_splitting_cookie_headers): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@63022 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
webrick: use IO.copy_stream for multipart response
Use the new Proc response body feature to generate a multipart
range response dynamically. We use a flat array to minimize
object overhead as much as possible; as many ranges may fit
into an HTTP request header.
* lib/webrick/httpservlet/filehandler.rb (multipart_body): new method
(make_partial_content): use multipart_body
------------------------------------------------------------------------
r62960 | normal | 2018-03-28 17:06:23 +0900 (水, 28 3 2018) | 13 lines
webrick/httprequest: limit request headers size
We use the same 112 KB limit started (AFAIK) by Mongrel, Thin,
and Puma to prevent malicious users from using up all the memory
with a single request. This also limits the damage done by
excessive ranges in multipart Range: requests.
Due to the way we rely on IO#gets and the desire to keep
the code simple, the actual maximum header may be 4093 bytes
larger than 112 KB, but we're splitting hairs at that point.
* lib/webrick/httprequest.rb: define MAX_HEADER_LENGTH
(read_header): raise when headers exceed max length
------------------------------------------------------------------------
r62961 | normal | 2018-03-28 17:06:28 +0900 (水, 28 3 2018) | 9 lines
webrick/httpservlet/cgihandler: reduce memory use
WEBrick::HTTPRequest#body can be passed a block to process the
body in chunks. Use this feature to avoid building a giant
string in memory.
* lib/webrick/httpservlet/cgihandler.rb (do_GET):
avoid reading entire request body into memory
(do_POST is aliased to do_GET, so it handles bodies)
------------------------------------------------------------------------
r62962 | normal | 2018-03-28 17:06:34 +0900 (水, 28 3 2018) | 7 lines
webrick/httprequest: raise correct exception
"BadRequest" alone does not resolve correctly, it is in the
HTTPStatus namespace.
* lib/webrick/httprequest.rb (read_chunked): use correct exception
* test/webrick/test_httpserver.rb (test_eof_in_chunk): new test
------------------------------------------------------------------------
r62963 | normal | 2018-03-28 17:06:39 +0900 (水, 28 3 2018) | 9 lines
webrick/httprequest: use InputBufferSize for chunked requests
While WEBrick::HTTPRequest#body provides a Proc interface
for streaming large request bodies, clients must not force
the server to use an excessively large chunk size.
* lib/webrick/httprequest.rb (read_chunk_size): limit each
read and block.call to :InputBufferSize in config.
* test/webrick/test_httpserver.rb (test_big_chunks): new test
------------------------------------------------------------------------
r62964 | normal | 2018-03-28 17:06:44 +0900 (水, 28 3 2018) | 9 lines
webrick: add test for Digest auth-int
No changes to the actual code, this is a new test for
a feature for which no tests existed. I don't understand
the Digest authentication code well at all, but this is
necessary for the subsequent change.
* test/webrick/test_httpauth.rb (test_digest_auth_int): new test
(credentials_for_request): support bodies with POST
------------------------------------------------------------------------
r62965 | normal | 2018-03-28 17:06:49 +0900 (水, 28 3 2018) | 18 lines
webrick/httpauth/digestauth: stream req.body
WARNING! WARNING! WARNING! LIKELY BROKEN CHANGE
Pass a proc to WEBrick::HTTPRequest#body to avoid reading a
potentially large request body into memory during
authentication.
WARNING! this will break apps completely which want to do
something with the body besides calculating the MD5 digest
of it.
Also, keep in mind that probably nobody uses "auth-int".
Servers such as Apache, lighttpd, nginx don't seem to
support it; nor does curl when using POST/PUT bodies;
and we didn't have tests for it until now...
* lib/webrick/httpauth/digestauth.rb (_authenticate): stream req.body
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@63021 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
webrick: support Proc objects as body responses
* lib/webrick/httpresponse.rb (send_body): call send_body_proc
(send_body_proc): new method
(class ChunkedWrapper): new class
* test/webrick/test_httpresponse.rb (test_send_body_proc): new test
(test_send_body_proc_chunked): ditto
[Feature #855]
webrick: favor .write over << method
This will make the next change to use IO.copy_stream
easier-to-read. When we can drop Ruby 2.4 support in a few
years, this will allow us to use writev(2) with multiple
arguments for headers and chunked responses.
* lib/webrick/cgi.rb (write): new wrapper method
lib/webrick/httpresponse.rb: (send_header): use socket.write
(send_body_io): ditto
(send_body_string): ditto
(send_body_proc): ditto
(_write_data): ditto
(ChunkedWrapper#write): ditto
(_send_file): ditto
------------------------------------------------------------------------
r62954 | normal | 2018-03-28 17:05:52 +0900 (水, 28 3 2018) | 14 lines
webrick/httpresponse: IO.copy_stream for regular files
Remove the redundant _send_file method since its functionality
is unnecessary with IO.copy_stream. IO.copy_stream also allows
the use of sendfile under some OSes to speed up copies to
non-TLS sockets.
Testing with "curl >/dev/null" and "ruby -run -e httpd" to
read a 1G file over Linux loopback reveals a reduction from
around ~0.770 to ~0.490 seconds on the client side.
* lib/webrick/httpresponse.rb (send_body_io): use IO.copy_stream
(_send_file): remove
[Feature #14237]
------------------------------------------------------------------------
r62955 | normal | 2018-03-28 17:05:57 +0900 (水, 28 3 2018) | 10 lines
webrick: use IO.copy_stream for single range response
This is also compatible with range responses generated
by Rack::File (tested with rack 2.0.3).
* lib/webrick/httpresponse.rb (send_body_io): use Content-Range
* lib/webrick/httpservlet/filehandler.rb (make_partial_content):
use File object for the single range case
* test/webrick/test_filehandler.rb (get_res_body): use send_body
to test result
------------------------------------------------------------------------
r62956 | normal | 2018-03-28 17:06:02 +0900 (水, 28 3 2018) | 7 lines
test/webrick/test_filehandler.rb: stricter multipart range test
We need to ensure we generate compatibile output in
the face of future changes
* test/webrick/test_filehandler.rb (test_make_partial_content):
check response body
------------------------------------------------------------------------
r62957 | normal | 2018-03-28 17:06:08 +0900 (水, 28 3 2018) | 8 lines
webrick: quiet warning for multi-part ranges
Content-Length is ignored by WEBrick::HTTPResponse even if we
calculate it, so instead we chunk responses to HTTP/1.1 clients
and terminate HTTP/1.0 connections.
* lib/webrick/httpservlet/filehandler.rb (make_partial_content):
quiet warning
------------------------------------------------------------------------
r62958 | normal | 2018-03-28 17:06:13 +0900 (水, 28 3 2018) | 7 lines
webrick/httpresponse: make ChunkedWrapper copy_stream-compatible
The .write method needs to return the number of bytes written
to avoid confusing IO.copy_stream.
* lib/webrick/httpresponse.rb (ChunkedWrapper#write): return bytes written
(ChunkedWrapper#<<): return self
------------------------------------------------------------------------
r62959 | normal | 2018-03-28 17:06:18 +0900 (水, 28 3 2018) | 9 lines
webrick: use IO.copy_stream for multipart response
Use the new Proc response body feature to generate a multipart
range response dynamically. We use a flat array to minimize
object overhead as much as possible; as many ranges may fit
into an HTTP request header.
* lib/webrick/httpservlet/filehandler.rb (multipart_body): new method
(make_partial_content): use multipart_body
get rid of test error/failure on Windows introduced at r62955
* lib/webrick/httpresponse.rb (send_body_io): use seek if NotImplementedError
is raised in IO.copy_stream with offset.
* lib/webrick/httpservlet/filehandler.rb (multipart_body): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@63020 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
lib/webrick/log.rb: sanitize any type of logs
It had failed to sanitize some type of exception messages. Reported and
patched by Yusuke Endoh (mame) at https://hackerone.com/reports/223363
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@59902 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
notify readability on the read side of the pipe.
write_nonblock() is not usable for pipe on Windows.
(cleanup_shutdown_pipe): Rescue IOError for @shutdown_pipe_w.close.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48354 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
to avoid race condition.
(cleanup_shutdown_pipe): New private method.
(cleanup_listener): Extracted from shutdown method.
Call this method from start method to avoid race condition.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48353 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/webrick/utils.rb (WEBrick::Utils::TimeoutHandler::Thread):
use particular class to mark by the class name.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46651 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
shutdown() or close() for listening socket is not a reliable.
Actually, both doesn't work (doesn't wake up select()) on
DragonFly BSD 3.6.2.
* test/webrick/utils.rb: :ShutdownSocketWithoutClose is not required
now to immediate server shutdown detection.
This fixes fd leaks.
* test/net/http/utils.rb: Ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46253 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/webrick/httpserver.rb (WEBrick::HTTPServer#run): stop
handling requests on shutdown, even if the socket is readable
and IO.select() returns true. [Fixes GH-607]
* lib/webrick/server.rb (WEBrick::GenericServer#start): IO.select()
raises ENOTSOCK on shutdown on Windows.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45872 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/webrick/httpservlet/filehandler.rb (set_dir_list): pass the
given queries to subdirectories.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44919 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* test/ruby/test_parse.rb: Fix typo in a test name.
s/allowd/allowed/
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43917 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
that responds to #readpartial and #read.
[ruby-trunk - Feature #8155]
* NEWS: NEWS for above
* test/webrick/test_httpresponse.rb: Tests for above.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42427 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
unintentional unlink() by the finalizer.
lib/webrick/httpauth/htdigest.rb: Ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
response codes added in RFCs 2817 and 4918. [ruby-core:45547]
[Feature #6569]
* lib/net/http/responses.rb: Rename Net::HTTPMultipleChoice to
Net::HTTPMultipleChoices, leaving the former as alias to the
latter for backward compatibitily. [ruby-core:45547]
[Feature #6569]
* lib/net/http/responses.rb: Add comments about unused,
still-in-draft and private extension response codes.
[ruby-core:45547] [Feature #6569]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e