Last active
June 29, 2020 11:35
-
-
Save headius/cb184868d6d8b709b8a3f62cd0c275eb to your computer and use it in GitHub Desktop.
Diffs from WEBrick 1.4.2 in the ruby/webrick repository versus CRuby's ruby_2_6 branch lib/webrick
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/../ruby/lib/webrick/.document b/../ruby/lib/webrick/.document | |
new file mode 100644 | |
index 0000000..c62f890 | |
--- /dev/null | |
+++ b/../ruby/lib/webrick/.document | |
@@ -0,0 +1,6 @@ | |
+# Add files to this as they become documented | |
+ | |
+*.rb | |
+ | |
+httpauth | |
+httpservlet | |
diff --git a/lib/webrick/cgi.rb b/../ruby/lib/webrick/cgi.rb | |
index 94f385f..bb0ae2f 100644 | |
--- a/lib/webrick/cgi.rb | |
+++ b/../ruby/lib/webrick/cgi.rb | |
@@ -8,9 +8,9 @@ | |
# | |
# $Id$ | |
-require "webrick/httprequest" | |
-require "webrick/httpresponse" | |
-require "webrick/config" | |
+require_relative "httprequest" | |
+require_relative "httpresponse" | |
+require_relative "config" | |
require "stringio" | |
module WEBrick | |
@@ -265,6 +265,10 @@ def <<(data) | |
@out_port << data | |
end | |
+ def write(data) | |
+ @out_port.write(data) | |
+ end | |
+ | |
def cert | |
return nil unless defined?(OpenSSL) | |
if pem = @env["SSL_SERVER_CERT"] | |
diff --git a/lib/webrick/config.rb b/../ruby/lib/webrick/config.rb | |
index af4b561..9f2ab44 100644 | |
--- a/lib/webrick/config.rb | |
+++ b/../ruby/lib/webrick/config.rb | |
@@ -9,11 +9,11 @@ | |
# | |
# $IPR: config.rb,v 1.52 2003/07/22 19:20:42 gotoyuzo Exp $ | |
-require 'webrick/version' | |
-require 'webrick/httpversion' | |
-require 'webrick/httputils' | |
-require 'webrick/utils' | |
-require 'webrick/log' | |
+require_relative 'version' | |
+require_relative 'httpversion' | |
+require_relative 'httputils' | |
+require_relative 'utils' | |
+require_relative 'log' | |
module WEBrick | |
module Config | |
diff --git a/lib/webrick/cookie.rb b/../ruby/lib/webrick/cookie.rb | |
index 24bf92e..5fd3bfb 100644 | |
--- a/lib/webrick/cookie.rb | |
+++ b/../ruby/lib/webrick/cookie.rb | |
@@ -10,7 +10,7 @@ | |
# $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $ | |
require 'time' | |
-require 'webrick/httputils' | |
+require_relative 'httputils' | |
module WEBrick | |
diff --git a/lib/webrick/httpauth/basicauth.rb b/../ruby/lib/webrick/httpauth/basicauth.rb | |
index e23420f..7d0a9cf 100644 | |
--- a/lib/webrick/httpauth/basicauth.rb | |
+++ b/../ruby/lib/webrick/httpauth/basicauth.rb | |
@@ -8,9 +8,9 @@ | |
# | |
# $IPR: basicauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $ | |
-require 'webrick/config' | |
-require 'webrick/httpstatus' | |
-require 'webrick/httpauth/authenticator' | |
+require_relative '../config' | |
+require_relative '../httpstatus' | |
+require_relative 'authenticator' | |
module WEBrick | |
module HTTPAuth | |
@@ -24,7 +24,7 @@ module HTTPAuth | |
# | |
# config = { :Realm => 'BasicAuth example realm' } | |
# | |
- # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file' | |
+ # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file', password_hash: :bcrypt | |
# htpasswd.set_passwd config[:Realm], 'username', 'password' | |
# htpasswd.flush | |
# | |
@@ -81,7 +81,15 @@ def authenticate(req, res) | |
error("%s: the user is not allowed.", userid) | |
challenge(req, res) | |
end | |
- if password.crypt(encpass) != encpass | |
+ | |
+ case encpass | |
+ when /\A\$2[aby]\$/ | |
+ password_matches = BCrypt::Password.new(encpass.sub(/\A\$2[aby]\$/, '$2a$')) == password | |
+ else | |
+ password_matches = password.crypt(encpass) == encpass | |
+ end | |
+ | |
+ unless password_matches | |
error("%s: password unmatch.", userid) | |
challenge(req, res) | |
end | |
diff --git a/lib/webrick/httpauth/digestauth.rb b/../ruby/lib/webrick/httpauth/digestauth.rb | |
index 375ec20..3cf1289 100644 | |
--- a/lib/webrick/httpauth/digestauth.rb | |
+++ b/../ruby/lib/webrick/httpauth/digestauth.rb | |
@@ -12,9 +12,9 @@ | |
# | |
# $IPR: digestauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $ | |
-require 'webrick/config' | |
-require 'webrick/httpstatus' | |
-require 'webrick/httpauth/authenticator' | |
+require_relative '../config' | |
+require_relative '../httpstatus' | |
+require_relative 'authenticator' | |
require 'digest/md5' | |
require 'digest/sha1' | |
@@ -235,9 +235,11 @@ def _authenticate(req, res) | |
ha2 = hexdigest(req.request_method, auth_req['uri']) | |
ha2_res = hexdigest("", auth_req['uri']) | |
elsif auth_req['qop'] == "auth-int" | |
- ha2 = hexdigest(req.request_method, auth_req['uri'], | |
- hexdigest(req.body)) | |
- ha2_res = hexdigest("", auth_req['uri'], hexdigest(res.body)) | |
+ body_digest = @h.new | |
+ req.body { |chunk| body_digest.update(chunk) } | |
+ body_digest = body_digest.hexdigest | |
+ ha2 = hexdigest(req.request_method, auth_req['uri'], body_digest) | |
+ ha2_res = hexdigest("", auth_req['uri'], body_digest) | |
end | |
if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int" | |
@@ -288,23 +290,8 @@ def _authenticate(req, res) | |
def split_param_value(string) | |
ret = {} | |
- while string.bytesize != 0 | |
- case string | |
- when /^\s*([\w\-\.\*\%\!]+)=\s*\"((\\.|[^\"])*)\"\s*,?/ | |
- key = $1 | |
- matched = $2 | |
- string = $' | |
- ret[key] = matched.gsub(/\\(.)/, "\\1") | |
- when /^\s*([\w\-\.\*\%\!]+)=\s*([^,\"]*),?/ | |
- key = $1 | |
- matched = $2 | |
- string = $' | |
- ret[key] = matched.clone | |
- when /^s*^,/ | |
- string = $' | |
- else | |
- break | |
- end | |
+ string.scan(/\G\s*([\w\-.*%!]+)=\s*(?:\"((?>\\.|[^\"])*)\"|([^,\"]*))\s*,?/) do | |
+ ret[$1] = $3 || $2.gsub(/\\(.)/, "\\1") | |
end | |
ret | |
end | |
diff --git a/lib/webrick/httpauth/htdigest.rb b/../ruby/lib/webrick/httpauth/htdigest.rb | |
index c35b384..93b18e2 100644 | |
--- a/lib/webrick/httpauth/htdigest.rb | |
+++ b/../ruby/lib/webrick/httpauth/htdigest.rb | |
@@ -8,8 +8,8 @@ | |
# | |
# $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $ | |
-require 'webrick/httpauth/userdb' | |
-require 'webrick/httpauth/digestauth' | |
+require_relative 'userdb' | |
+require_relative 'digestauth' | |
require 'tempfile' | |
module WEBrick | |
diff --git a/lib/webrick/httpauth/htgroup.rb b/../ruby/lib/webrick/httpauth/htgroup.rb | |
index 399a62c..e06c441 100644 | |
--- a/lib/webrick/httpauth/htgroup.rb | |
+++ b/../ruby/lib/webrick/httpauth/htgroup.rb | |
@@ -63,15 +63,18 @@ def reload | |
def flush(output=nil) | |
output ||= @path | |
- tmp = Tempfile.new("htgroup", File::dirname(output)) | |
+ tmp = Tempfile.create("htgroup", File::dirname(output)) | |
begin | |
@group.keys.sort.each{|group| | |
tmp.puts(format("%s: %s", group, self.members(group).join(" "))) | |
} | |
+ ensure | |
tmp.close | |
- File::rename(tmp.path, output) | |
- rescue | |
- tmp.close(true) | |
+ if $! | |
+ File.unlink(tmp.path) | |
+ else | |
+ return File.rename(tmp.path, output) | |
+ end | |
end | |
end | |
diff --git a/lib/webrick/httpauth/htpasswd.rb b/../ruby/lib/webrick/httpauth/htpasswd.rb | |
index 976eeeb..abca305 100644 | |
--- a/lib/webrick/httpauth/htpasswd.rb | |
+++ b/../ruby/lib/webrick/httpauth/htpasswd.rb | |
@@ -8,8 +8,8 @@ | |
# | |
# $IPR: htpasswd.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $ | |
-require 'webrick/httpauth/userdb' | |
-require 'webrick/httpauth/basicauth' | |
+require_relative 'userdb' | |
+require_relative 'basicauth' | |
require 'tempfile' | |
module WEBrick | |
@@ -35,11 +35,29 @@ class Htpasswd | |
## | |
# Open a password database at +path+ | |
- def initialize(path) | |
+ def initialize(path, password_hash: nil) | |
@path = path | |
@mtime = Time.at(0) | |
@passwd = Hash.new | |
@auth_type = BasicAuth | |
+ @password_hash = password_hash | |
+ | |
+ case @password_hash | |
+ when nil | |
+ # begin | |
+ # require "string/crypt" | |
+ # rescue LoadError | |
+ # warn("Unable to load string/crypt, proceeding with deprecated use of String#crypt, consider using password_hash: :bcrypt") | |
+ # end | |
+ @password_hash = :crypt | |
+ when :crypt | |
+ # require "string/crypt" | |
+ when :bcrypt | |
+ require "bcrypt" | |
+ else | |
+ raise ArgumentError, "only :crypt and :bcrypt are supported for password_hash keyword argument" | |
+ end | |
+ | |
File.open(@path,"a").close unless File.exist?(@path) | |
reload | |
end | |
@@ -56,6 +74,14 @@ def reload | |
line.chomp! | |
case line | |
when %r!\A[^:]+:[a-zA-Z0-9./]{13}\z! | |
+ if @password_hash == :bcrypt | |
+ raise StandardError, ".htpasswd file contains crypt password, only bcrypt passwords supported" | |
+ end | |
+ user, pass = line.split(":") | |
+ when %r!\A[^:]+:\$2[aby]\$\d{2}\$.{53}\z! | |
+ if @password_hash == :crypt | |
+ raise StandardError, ".htpasswd file contains bcrypt password, only crypt passwords supported" | |
+ end | |
user, pass = line.split(":") | |
when /:\$/, /:{SHA}/ | |
raise NotImplementedError, | |
@@ -102,7 +128,14 @@ def get_passwd(realm, user, reload_db) | |
# Sets a password in the database for +user+ in +realm+ to +pass+. | |
def set_passwd(realm, user, pass) | |
- @passwd[user] = make_passwd(realm, user, pass) | |
+ if @password_hash == :bcrypt | |
+ # Cost of 5 to match Apache default, and because the | |
+ # bcrypt default of 10 will introduce significant delays | |
+ # for every request. | |
+ @passwd[user] = BCrypt::Password.create(pass, :cost=>5) | |
+ else | |
+ @passwd[user] = make_passwd(realm, user, pass) | |
+ end | |
end | |
## | |
diff --git a/lib/webrick/httpauth.rb b/../ruby/lib/webrick/httpauth.rb | |
index bbb6776..f8bf09a 100644 | |
--- a/lib/webrick/httpauth.rb | |
+++ b/../ruby/lib/webrick/httpauth.rb | |
@@ -9,11 +9,11 @@ | |
# | |
# $IPR: httpauth.rb,v 1.14 2003/07/22 19:20:42 gotoyuzo Exp $ | |
-require 'webrick/httpauth/basicauth' | |
-require 'webrick/httpauth/digestauth' | |
-require 'webrick/httpauth/htpasswd' | |
-require 'webrick/httpauth/htdigest' | |
-require 'webrick/httpauth/htgroup' | |
+require_relative 'httpauth/basicauth' | |
+require_relative 'httpauth/digestauth' | |
+require_relative 'httpauth/htpasswd' | |
+require_relative 'httpauth/htdigest' | |
+require_relative 'httpauth/htgroup' | |
module WEBrick | |
diff --git a/lib/webrick/httpproxy.rb b/../ruby/lib/webrick/httpproxy.rb | |
index be5531f..d05d595 100644 | |
--- a/lib/webrick/httpproxy.rb | |
+++ b/../ruby/lib/webrick/httpproxy.rb | |
@@ -10,7 +10,7 @@ | |
# $IPR: httpproxy.rb,v 1.18 2003/03/08 18:58:10 gotoyuzo Exp $ | |
# $kNotwork: straw.rb,v 1.3 2002/02/12 15:13:07 gotoken Exp $ | |
-require "webrick/httpserver" | |
+require_relative "httpserver" | |
require "net/http" | |
module WEBrick | |
@@ -211,21 +211,15 @@ def do_CONNECT(req, res) | |
end | |
def do_GET(req, res) | |
- perform_proxy_request(req, res) do |http, path, header| | |
- http.get(path, header) | |
- end | |
+ perform_proxy_request(req, res, Net::HTTP::Get) | |
end | |
def do_HEAD(req, res) | |
- perform_proxy_request(req, res) do |http, path, header| | |
- http.head(path, header) | |
- end | |
+ perform_proxy_request(req, res, Net::HTTP::Head) | |
end | |
def do_POST(req, res) | |
- perform_proxy_request(req, res) do |http, path, header| | |
- http.post(path, req.body || "", header) | |
- end | |
+ perform_proxy_request(req, res, Net::HTTP::Post, req.body_reader) | |
end | |
def do_OPTIONS(req, res) | |
@@ -301,38 +295,56 @@ def setup_upstream_proxy_authentication(req, res, header) | |
return FakeProxyURI | |
end | |
- def perform_proxy_request(req, res) | |
+ def perform_proxy_request(req, res, req_class, body_stream = nil) | |
uri = req.request_uri | |
path = uri.path.dup | |
path << "?" << uri.query if uri.query | |
header = setup_proxy_header(req, res) | |
upstream = setup_upstream_proxy_authentication(req, res, header) | |
- response = nil | |
+ body_tmp = [] | |
http = Net::HTTP.new(uri.host, uri.port, upstream.host, upstream.port) | |
- http.start do | |
- if @config[:ProxyTimeout] | |
- ################################## these issues are | |
- http.open_timeout = 30 # secs # necessary (maybe because | |
- http.read_timeout = 60 # secs # Ruby's bug, but why?) | |
- ################################## | |
+ req_fib = Fiber.new do | |
+ http.start do | |
+ if @config[:ProxyTimeout] | |
+ ################################## these issues are | |
+ http.open_timeout = 30 # secs # necessary (maybe because | |
+ http.read_timeout = 60 # secs # Ruby's bug, but why?) | |
+ ################################## | |
+ end | |
+ if body_stream && req['transfer-encoding'] =~ /\bchunked\b/i | |
+ header['Transfer-Encoding'] = 'chunked' | |
+ end | |
+ http_req = req_class.new(path, header) | |
+ http_req.body_stream = body_stream if body_stream | |
+ http.request(http_req) do |response| | |
+ # Persistent connection requirements are mysterious for me. | |
+ # So I will close the connection in every response. | |
+ res['proxy-connection'] = "close" | |
+ res['connection'] = "close" | |
+ | |
+ # stream Net::HTTP::HTTPResponse to WEBrick::HTTPResponse | |
+ res.status = response.code.to_i | |
+ res.chunked = response.chunked? | |
+ choose_header(response, res) | |
+ set_cookie(response, res) | |
+ set_via(res) | |
+ response.read_body do |buf| | |
+ body_tmp << buf | |
+ Fiber.yield # wait for res.body Proc#call | |
+ end | |
+ end # http.request | |
+ end | |
+ end | |
+ req_fib.resume # read HTTP response headers and first chunk of the body | |
+ res.body = ->(socket) do | |
+ while buf = body_tmp.shift | |
+ socket.write(buf) | |
+ buf.clear | |
+ req_fib.resume # continue response.read_body | |
end | |
- response = yield(http, path, header) | |
end | |
- | |
- # Persistent connection requirements are mysterious for me. | |
- # So I will close the connection in every response. | |
- res['proxy-connection'] = "close" | |
- res['connection'] = "close" | |
- | |
- # Convert Net::HTTP::HTTPResponse to WEBrick::HTTPResponse | |
- res.status = response.code.to_i | |
- choose_header(response, res) | |
- set_cookie(response, res) | |
- set_via(res) | |
- res.body = response.body | |
end | |
- | |
# :stopdoc: | |
end | |
end | |
diff --git a/lib/webrick/httprequest.rb b/../ruby/lib/webrick/httprequest.rb | |
index 10cf72d..e402099 100644 | |
--- a/lib/webrick/httprequest.rb | |
+++ b/../ruby/lib/webrick/httprequest.rb | |
@@ -10,10 +10,10 @@ | |
# $IPR: httprequest.rb,v 1.64 2003/07/13 17:18:22 gotoyuzo Exp $ | |
require 'uri' | |
-require 'webrick/httpversion' | |
-require 'webrick/httpstatus' | |
-require 'webrick/httputils' | |
-require 'webrick/cookie' | |
+require_relative 'httpversion' | |
+require_relative 'httpstatus' | |
+require_relative 'httputils' | |
+require_relative 'cookie' | |
module WEBrick | |
@@ -257,6 +257,32 @@ def body(&block) # :yields: body_chunk | |
@body.empty? ? nil : @body | |
end | |
+ ## | |
+ # Prepares the HTTPRequest object for use as the | |
+ # source for IO.copy_stream | |
+ | |
+ def body_reader | |
+ @body_tmp = [] | |
+ @body_rd = Fiber.new do | |
+ body do |buf| | |
+ @body_tmp << buf | |
+ Fiber.yield | |
+ end | |
+ end | |
+ @body_rd.resume # grab the first chunk and yield | |
+ self | |
+ end | |
+ | |
+ # for IO.copy_stream. Note: we may return a larger string than +size+ | |
+ # here; but IO.copy_stream does not care. | |
+ def readpartial(size, buf = ''.b) # :nodoc | |
+ res = @body_tmp.shift or raise EOFError, 'end of file reached' | |
+ buf.replace(res) | |
+ res.clear | |
+ @body_rd.resume # get more chunks | |
+ buf | |
+ end | |
+ | |
## | |
# Request query as a Hash | |
@@ -414,13 +440,19 @@ def meta_vars | |
MAX_URI_LENGTH = 2083 # :nodoc: | |
+ # same as Mongrel, Thin and Puma | |
+ MAX_HEADER_LENGTH = (112 * 1024) # :nodoc: | |
+ | |
def read_request_line(socket) | |
@request_line = read_line(socket, MAX_URI_LENGTH) if socket | |
- if @request_line.bytesize >= MAX_URI_LENGTH and @request_line[-1, 1] != LF | |
+ raise HTTPStatus::EOFError unless @request_line | |
+ | |
+ @request_bytes = @request_line.bytesize | |
+ if @request_bytes >= MAX_URI_LENGTH and @request_line[-1, 1] != LF | |
raise HTTPStatus::RequestURITooLarge | |
end | |
+ | |
@request_time = Time.now | |
- raise HTTPStatus::EOFError unless @request_line | |
if /^(\S+)\s+(\S++)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line | |
@request_method = $1 | |
@unparsed_uri = $2 | |
@@ -435,6 +467,9 @@ def read_header(socket) | |
if socket | |
while line = read_line(socket) | |
break if /\A(#{CRLF}|#{LF})\z/om =~ line | |
+ if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH | |
+ raise HTTPStatus::RequestEntityTooLarge, 'headers too large' | |
+ end | |
@raw_header << line | |
end | |
end | |
@@ -502,12 +537,16 @@ def read_chunk_size(socket) | |
def read_chunked(socket, block) | |
chunk_size, = read_chunk_size(socket) | |
while chunk_size > 0 | |
- data = read_data(socket, chunk_size) # read chunk-data | |
- if data.nil? || data.bytesize != chunk_size | |
- raise BadRequest, "bad chunk data size." | |
- end | |
+ begin | |
+ sz = [ chunk_size, @buffer_size ].min | |
+ data = read_data(socket, sz) # read chunk-data | |
+ if data.nil? || data.bytesize != sz | |
+ raise HTTPStatus::BadRequest, "bad chunk data size." | |
+ end | |
+ block.call(data) | |
+ end while (chunk_size -= sz) > 0 | |
+ | |
read_line(socket) # skip CRLF | |
- block.call(data) | |
chunk_size, = read_chunk_size(socket) | |
end | |
read_header(socket) # trailer + CRLF | |
diff --git a/lib/webrick/httpresponse.rb b/../ruby/lib/webrick/httpresponse.rb | |
index d76310f..08f7797 100644 | |
--- a/lib/webrick/httpresponse.rb | |
+++ b/../ruby/lib/webrick/httpresponse.rb | |
@@ -10,10 +10,11 @@ | |
# $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $ | |
require 'time' | |
-require 'webrick/httpversion' | |
-require 'webrick/htmlutils' | |
-require 'webrick/httputils' | |
-require 'webrick/httpstatus' | |
+require 'uri' | |
+require_relative 'httpversion' | |
+require_relative 'htmlutils' | |
+require_relative 'httputils' | |
+require_relative 'httpstatus' | |
module WEBrick | |
## | |
@@ -21,6 +22,8 @@ module WEBrick | |
# WEBrick HTTP Servlet. | |
class HTTPResponse | |
+ class InvalidHeader < StandardError | |
+ end | |
## | |
# HTTP Response version | |
@@ -251,7 +254,7 @@ def setup_header() # :nodoc: | |
@header.delete('content-length') | |
elsif @header['content-length'].nil? | |
unless @body.is_a?(IO) | |
- @header['content-length'] = @body ? @body.bytesize : 0 | |
+ @header['content-length'] = (@body ? @body.bytesize : 0).to_s | |
end | |
end | |
@@ -274,7 +277,7 @@ def setup_header() # :nodoc: | |
# Location is a single absoluteURI. | |
if location = @header['location'] | |
if @request_uri | |
- @header['location'] = @request_uri.merge(location) | |
+ @header['location'] = @request_uri.merge(location).to_s | |
end | |
end | |
end | |
@@ -287,14 +290,19 @@ def send_header(socket) # :nodoc: | |
data = status_line() | |
@header.each{|key, value| | |
tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase } | |
- data << "#{tmp}: #{value}" << CRLF | |
+ data << "#{tmp}: #{check_header(value)}" << CRLF | |
} | |
@cookies.each{|cookie| | |
- data << "Set-Cookie: " << cookie.to_s << CRLF | |
+ data << "Set-Cookie: " << check_header(cookie.to_s) << CRLF | |
} | |
data << CRLF | |
- _write_data(socket, data) | |
+ socket.write(data) | |
end | |
+ rescue InvalidHeader => e | |
+ @header.clear | |
+ @cookies.clear | |
+ set_error e | |
+ retry | |
end | |
## | |
@@ -324,8 +332,9 @@ def to_s # :nodoc: | |
# res.set_redirect WEBrick::HTTPStatus::TemporaryRedirect | |
def set_redirect(status, url) | |
+ url = URI(url).to_s | |
@body = "<HTML><A HREF=\"#{url}\">#{url}</A>.</HTML>\n" | |
- @header['location'] = url.to_s | |
+ @header['location'] = url | |
raise status | |
end | |
@@ -359,6 +368,15 @@ def set_error(ex, backtrace=false) | |
private | |
+ def check_header(header_value) | |
+ header_value = header_value.to_s | |
+ if /[\r\n]/ =~ header_value | |
+ raise InvalidHeader | |
+ else | |
+ header_value | |
+ end | |
+ end | |
+ | |
# :stopdoc: | |
def error_body(backtrace, ex, host, port) | |
@@ -401,18 +419,29 @@ def send_body_io(socket) | |
@body.readpartial(@buffer_size, buf) | |
size = buf.bytesize | |
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}" | |
- _write_data(socket, data) | |
+ socket.write(data) | |
data.clear | |
@sent_size += size | |
rescue EOFError | |
break | |
end while true | |
buf.clear | |
- _write_data(socket, "0#{CRLF}#{CRLF}") | |
+ socket.write("0#{CRLF}#{CRLF}") | |
else | |
- size = @header['content-length'].to_i | |
- _send_file(socket, @body, 0, size) | |
- @sent_size = size | |
+ if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ @header['content-range'] | |
+ offset = $1.to_i | |
+ size = $2.to_i - offset + 1 | |
+ else | |
+ offset = nil | |
+ size = @header['content-length'] | |
+ size = size.to_i if size | |
+ end | |
+ begin | |
+ @sent_size = IO.copy_stream(@body, socket, size, offset) | |
+ rescue NotImplementedError | |
+ @body.seek(offset, IO::SEEK_SET) | |
+ @sent_size = IO.copy_stream(@body, socket, size) | |
+ end | |
end | |
ensure | |
@body.close | |
@@ -429,13 +458,13 @@ def send_body_string(socket) | |
size = buf.bytesize | |
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}" | |
buf.clear | |
- _write_data(socket, data) | |
+ socket.write(data) | |
@sent_size += size | |
end | |
- _write_data(socket, "0#{CRLF}#{CRLF}") | |
+ socket.write("0#{CRLF}#{CRLF}") | |
else | |
if @body && @body.bytesize > 0 | |
- _write_data(socket, @body) | |
+ socket.write(@body) | |
@sent_size = @body.bytesize | |
end | |
end | |
@@ -446,7 +475,7 @@ def send_body_proc(socket) | |
# do nothing | |
elsif chunked? | |
@body.call(ChunkedWrapper.new(socket, self)) | |
- _write_data(socket, "0#{CRLF}#{CRLF}") | |
+ socket.write("0#{CRLF}#{CRLF}") | |
else | |
size = @header['content-length'].to_i | |
@body.call(socket) | |
@@ -461,40 +490,25 @@ def initialize(socket, resp) | |
end | |
def write(buf) | |
- return if buf.empty? | |
+ return 0 if buf.empty? | |
socket = @socket | |
@resp.instance_eval { | |
size = buf.bytesize | |
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}" | |
- _write_data(socket, data) | |
+ socket.write(data) | |
data.clear | |
@sent_size += size | |
+ size | |
} | |
end | |
- alias :<< :write | |
- end | |
- | |
- def _send_file(output, input, offset, size) | |
- while offset > 0 | |
- sz = @buffer_size < size ? @buffer_size : size | |
- buf = input.read(sz) | |
- offset -= buf.bytesize | |
- end | |
- if size == 0 | |
- while buf = input.read(@buffer_size) | |
- _write_data(output, buf) | |
- end | |
- else | |
- while size > 0 | |
- sz = @buffer_size < size ? @buffer_size : size | |
- buf = input.read(sz) | |
- _write_data(output, buf) | |
- size -= buf.bytesize | |
- end | |
+ def <<(*buf) | |
+ write(buf) | |
+ self | |
end | |
end | |
+ # preserved for compatibility with some 3rd-party handlers | |
def _write_data(socket, data) | |
socket << data | |
end | |
diff --git a/lib/webrick/https.rb b/../ruby/lib/webrick/https.rb | |
index 4826654..b0a49bc 100644 | |
--- a/lib/webrick/https.rb | |
+++ b/../ruby/lib/webrick/https.rb | |
@@ -9,8 +9,8 @@ | |
# | |
# $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $ | |
-require 'webrick/ssl' | |
-require 'webrick/httpserver' | |
+require_relative 'ssl' | |
+require_relative 'httpserver' | |
module WEBrick | |
module Config | |
diff --git a/lib/webrick/httpserver.rb b/../ruby/lib/webrick/httpserver.rb | |
index e46b3bd..e85d059 100644 | |
--- a/lib/webrick/httpserver.rb | |
+++ b/../ruby/lib/webrick/httpserver.rb | |
@@ -10,13 +10,13 @@ | |
# $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $ | |
require 'io/wait' | |
-require 'webrick/server' | |
-require 'webrick/httputils' | |
-require 'webrick/httpstatus' | |
-require 'webrick/httprequest' | |
-require 'webrick/httpresponse' | |
-require 'webrick/httpservlet' | |
-require 'webrick/accesslog' | |
+require_relative 'server' | |
+require_relative 'httputils' | |
+require_relative 'httpstatus' | |
+require_relative 'httprequest' | |
+require_relative 'httpresponse' | |
+require_relative 'httpservlet' | |
+require_relative 'accesslog' | |
module WEBrick | |
class HTTPServerError < ServerError; end | |
@@ -68,8 +68,8 @@ def initialize(config={}, default=Config::HTTP) | |
def run(sock) | |
while true | |
- res = HTTPResponse.new(@config) | |
- req = HTTPRequest.new(@config) | |
+ req = create_request(@config) | |
+ res = create_response(@config) | |
server = self | |
begin | |
timeout = @config[:RequestTimeout] | |
@@ -224,6 +224,20 @@ def access_log(config, req, res) | |
} | |
end | |
+ ## | |
+ # Creates the HTTPRequest used when handling the HTTP | |
+ # request. Can be overridden by subclasses. | |
+ def create_request(with_webrick_config) | |
+ HTTPRequest.new(with_webrick_config) | |
+ end | |
+ | |
+ ## | |
+ # Creates the HTTPResponse used when handling the HTTP | |
+ # request. Can be overridden by subclasses. | |
+ def create_response(with_webrick_config) | |
+ HTTPResponse.new(with_webrick_config) | |
+ end | |
+ | |
## | |
# Mount table for the path a servlet is mounted on in the directory space | |
# of the server. Users of WEBrick can only access this indirectly via | |
diff --git a/lib/webrick/httpservlet/abstract.rb b/../ruby/lib/webrick/httpservlet/abstract.rb | |
index fc4cd22..bccb091 100644 | |
--- a/lib/webrick/httpservlet/abstract.rb | |
+++ b/../ruby/lib/webrick/httpservlet/abstract.rb | |
@@ -9,9 +9,9 @@ | |
# | |
# $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $ | |
-require 'webrick/htmlutils' | |
-require 'webrick/httputils' | |
-require 'webrick/httpstatus' | |
+require_relative '../htmlutils' | |
+require_relative '../httputils' | |
+require_relative '../httpstatus' | |
module WEBrick | |
module HTTPServlet | |
diff --git a/lib/webrick/httpservlet/cgihandler.rb b/../ruby/lib/webrick/httpservlet/cgihandler.rb | |
index ba6b0b6..981f649 100644 | |
--- a/lib/webrick/httpservlet/cgihandler.rb | |
+++ b/../ruby/lib/webrick/httpservlet/cgihandler.rb | |
@@ -11,8 +11,8 @@ | |
require 'rbconfig' | |
require 'tempfile' | |
-require 'webrick/config' | |
-require 'webrick/httpservlet/abstract' | |
+require_relative '../config' | |
+require_relative 'abstract' | |
module WEBrick | |
module HTTPServlet | |
@@ -65,9 +65,7 @@ def do_GET(req, res) | |
cgi_in.write("%8d" % dump.bytesize) | |
cgi_in.write(dump) | |
- if req.body and req.body.bytesize > 0 | |
- cgi_in.write(req.body) | |
- end | |
+ req.body { |chunk| cgi_in.write(chunk) } | |
ensure | |
cgi_in.close | |
status = $?.exitstatus | |
diff --git a/lib/webrick/httpservlet/erbhandler.rb b/../ruby/lib/webrick/httpservlet/erbhandler.rb | |
index aa02ce8..cd09e5f 100644 | |
--- a/lib/webrick/httpservlet/erbhandler.rb | |
+++ b/../ruby/lib/webrick/httpservlet/erbhandler.rb | |
@@ -9,7 +9,7 @@ | |
# | |
# $IPR: erbhandler.rb,v 1.25 2003/02/24 19:25:31 gotoyuzo Exp $ | |
-require 'webrick/httpservlet/abstract.rb' | |
+require_relative 'abstract' | |
require 'erb' | |
diff --git a/lib/webrick/httpservlet/filehandler.rb b/../ruby/lib/webrick/httpservlet/filehandler.rb | |
index 2c02d0f..601882e 100644 | |
--- a/lib/webrick/httpservlet/filehandler.rb | |
+++ b/../ruby/lib/webrick/httpservlet/filehandler.rb | |
@@ -11,9 +11,9 @@ | |
require 'time' | |
-require 'webrick/htmlutils' | |
-require 'webrick/httputils' | |
-require 'webrick/httpstatus' | |
+require_relative '../htmlutils' | |
+require_relative '../httputils' | |
+require_relative '../httpstatus' | |
module WEBrick | |
module HTTPServlet | |
@@ -55,7 +55,7 @@ def do_GET(req, res) | |
else | |
mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes]) | |
res['content-type'] = mtype | |
- res['content-length'] = st.size | |
+ res['content-length'] = st.size.to_s | |
res['last-modified'] = mtime.httpdate | |
res.body = File.open(@local_path, "rb") | |
end | |
@@ -86,6 +86,35 @@ def not_modified?(req, res, mtime, etag) | |
return false | |
end | |
+ # returns a lambda for webrick/httpresponse.rb send_body_proc | |
+ def multipart_body(body, parts, boundary, mtype, filesize) | |
+ lambda do |socket| | |
+ begin | |
+ begin | |
+ first = parts.shift | |
+ last = parts.shift | |
+ socket.write( | |
+ "--#{boundary}#{CRLF}" \ | |
+ "Content-Type: #{mtype}#{CRLF}" \ | |
+ "Content-Range: bytes #{first}-#{last}/#{filesize}#{CRLF}" \ | |
+ "#{CRLF}" | |
+ ) | |
+ | |
+ begin | |
+ IO.copy_stream(body, socket, last - first + 1, first) | |
+ rescue NotImplementedError | |
+ body.seek(first, IO::SEEK_SET) | |
+ IO.copy_stream(body, socket, last - first + 1) | |
+ end | |
+ socket.write(CRLF) | |
+ end while parts[0] | |
+ socket.write("--#{boundary}--#{CRLF}") | |
+ ensure | |
+ body.close | |
+ end | |
+ end | |
+ end | |
+ | |
def make_partial_content(req, res, filename, filesize) | |
mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes]) | |
unless ranges = HTTPUtils::parse_range_header(req['range']) | |
@@ -96,37 +125,27 @@ def make_partial_content(req, res, filename, filesize) | |
if ranges.size > 1 | |
time = Time.now | |
boundary = "#{time.sec}_#{time.usec}_#{Process::pid}" | |
- body = '' | |
- ranges.each{|range| | |
- first, last = prepare_range(range, filesize) | |
- next if first < 0 | |
- io.pos = first | |
- content = io.read(last-first+1) | |
- body << "--" << boundary << CRLF | |
- body << "Content-Type: #{mtype}" << CRLF | |
- body << "Content-Range: bytes #{first}-#{last}/#{filesize}" << CRLF | |
- body << CRLF | |
- body << content | |
- body << CRLF | |
+ parts = [] | |
+ ranges.each {|range| | |
+ prange = prepare_range(range, filesize) | |
+ next if prange[0] < 0 | |
+ parts.concat(prange) | |
} | |
- raise HTTPStatus::RequestRangeNotSatisfiable if body.empty? | |
- body << "--" << boundary << "--" << CRLF | |
+ raise HTTPStatus::RequestRangeNotSatisfiable if parts.empty? | |
res["content-type"] = "multipart/byteranges; boundary=#{boundary}" | |
- res.body = body | |
+ if req.http_version < '1.1' | |
+ res['connection'] = 'close' | |
+ else | |
+ res.chunked = true | |
+ end | |
+ res.body = multipart_body(io.dup, parts, boundary, mtype, filesize) | |
elsif range = ranges[0] | |
first, last = prepare_range(range, filesize) | |
raise HTTPStatus::RequestRangeNotSatisfiable if first < 0 | |
- if last == filesize - 1 | |
- content = io.dup | |
- content.pos = first | |
- else | |
- io.pos = first | |
- content = io.read(last-first+1) | |
- end | |
res['content-type'] = mtype | |
res['content-range'] = "bytes #{first}-#{last}/#{filesize}" | |
- res['content-length'] = last - first + 1 | |
- res.body = content | |
+ res['content-length'] = (last - first + 1).to_s | |
+ res.body = io.dup | |
else | |
raise HTTPStatus::BadRequest | |
end | |
diff --git a/lib/webrick/httpservlet/prochandler.rb b/../ruby/lib/webrick/httpservlet/prochandler.rb | |
index c1f454e..599ffc4 100644 | |
--- a/lib/webrick/httpservlet/prochandler.rb | |
+++ b/../ruby/lib/webrick/httpservlet/prochandler.rb | |
@@ -9,7 +9,7 @@ | |
# | |
# $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $ | |
-require 'webrick/httpservlet/abstract.rb' | |
+require_relative 'abstract' | |
module WEBrick | |
module HTTPServlet | |
diff --git a/lib/webrick/httpservlet.rb b/../ruby/lib/webrick/httpservlet.rb | |
index 1ee04ec..da49a14 100644 | |
--- a/lib/webrick/httpservlet.rb | |
+++ b/../ruby/lib/webrick/httpservlet.rb | |
@@ -9,11 +9,11 @@ | |
# | |
# $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $ | |
-require 'webrick/httpservlet/abstract' | |
-require 'webrick/httpservlet/filehandler' | |
-require 'webrick/httpservlet/cgihandler' | |
-require 'webrick/httpservlet/erbhandler' | |
-require 'webrick/httpservlet/prochandler' | |
+require_relative 'httpservlet/abstract' | |
+require_relative 'httpservlet/filehandler' | |
+require_relative 'httpservlet/cgihandler' | |
+require_relative 'httpservlet/erbhandler' | |
+require_relative 'httpservlet/prochandler' | |
module WEBrick | |
module HTTPServlet | |
diff --git a/lib/webrick/httpstatus.rb b/../ruby/lib/webrick/httpstatus.rb | |
index 0630219..c811f21 100644 | |
--- a/lib/webrick/httpstatus.rb | |
+++ b/../ruby/lib/webrick/httpstatus.rb | |
@@ -9,7 +9,7 @@ | |
# | |
# $IPR: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $ | |
-require 'webrick/accesslog' | |
+require_relative 'accesslog' | |
module WEBrick | |
diff --git a/lib/webrick/server.rb b/../ruby/lib/webrick/server.rb | |
index 88e160d..4a6e74c 100644 | |
--- a/lib/webrick/server.rb | |
+++ b/../ruby/lib/webrick/server.rb | |
@@ -10,8 +10,8 @@ | |
# $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $ | |
require 'socket' | |
-require 'webrick/config' | |
-require 'webrick/log' | |
+require_relative 'config' | |
+require_relative 'log' | |
module WEBrick | |
diff --git a/lib/webrick/ssl.rb b/../ruby/lib/webrick/ssl.rb | |
index 8a334ea..d125083 100644 | |
--- a/lib/webrick/ssl.rb | |
+++ b/../ruby/lib/webrick/ssl.rb | |
@@ -130,7 +130,7 @@ def create_self_signed_cert(bits, cn, comment) | |
aki = ef.create_extension("authorityKeyIdentifier", | |
"keyid:always,issuer:always") | |
cert.add_extension(aki) | |
- cert.sign(rsa, OpenSSL::Digest::SHA1.new) | |
+ cert.sign(rsa, OpenSSL::Digest::SHA256.new) | |
return [ cert, rsa ] | |
end | |
@@ -181,7 +181,7 @@ def setup_ssl_context(config) # :nodoc: | |
unless config[:SSLCertificate] | |
cn = config[:SSLCertName] | |
comment = config[:SSLCertComment] | |
- cert, key = Utils::create_self_signed_cert(1024, cn, comment) | |
+ cert, key = Utils::create_self_signed_cert(2048, cn, comment) | |
config[:SSLCertificate] = cert | |
config[:SSLPrivateKey] = key | |
end | |
diff --git a/../ruby/lib/webrick/webrick.gemspec b/../ruby/lib/webrick/webrick.gemspec | |
new file mode 100644 | |
index 0000000..611ec13 | |
--- /dev/null | |
+++ b/../ruby/lib/webrick/webrick.gemspec | |
@@ -0,0 +1,33 @@ | |
+# frozen_string_literal: true | |
+begin | |
+ require_relative 'lib/webrick/version' | |
+rescue LoadError | |
+ # for Ruby core repository | |
+ require_relative 'version' | |
+end | |
+ | |
+Gem::Specification.new do |s| | |
+ s.name = "webrick" | |
+ s.version = WEBrick::VERSION | |
+ s.summary = "HTTP server toolkit" | |
+ s.description = "WEBrick is an HTTP server toolkit that can be configured as an HTTPS server, a proxy server, and a virtual-host server." | |
+ | |
+ s.require_path = %w{lib} | |
+ s.files = ["lib/webrick.rb", "lib/webrick/accesslog.rb", "lib/webrick/cgi.rb", "lib/webrick/compat.rb", "lib/webrick/config.rb", "lib/webrick/cookie.rb", "lib/webrick/htmlutils.rb", "lib/webrick/httpauth.rb", "lib/webrick/httpauth/authenticator.rb", "lib/webrick/httpauth/basicauth.rb", "lib/webrick/httpauth/digestauth.rb", "lib/webrick/httpauth/htdigest.rb", "lib/webrick/httpauth/htgroup.rb", "lib/webrick/httpauth/htpasswd.rb", "lib/webrick/httpauth/userdb.rb", "lib/webrick/httpauth.rb", "lib/webrick/httpproxy.rb", "lib/webrick/httprequest.rb", "lib/webrick/httpresponse.rb", "lib/webrick/https.rb", "lib/webrick/httpserver.rb", "lib/webrick/httpservlet.rb", "lib/webrick/httpservlet/abstract.rb", "lib/webrick/httpservlet/cgi_runner.rb", "lib/webrick/httpservlet/cgihandler.rb", "lib/webrick/httpservlet/erbhandler.rb", "lib/webrick/httpservlet/filehandler.rb", "lib/webrick/httpservlet/prochandler.rb", "lib/webrick/httpservlet.rb", "lib/webrick/httpstatus.rb", "lib/webrick/httputils.rb", "lib/webrick/httpversion.rb", "lib/webrick/log.rb", "lib/webrick/server.rb", "lib/webrick/ssl.rb", "lib/webrick/utils.rb", "lib/webrick/version.rb"] | |
+ s.required_ruby_version = ">= 2.3.0" | |
+ | |
+ s.authors = ["TAKAHASHI Masayoshi", "GOTOU YUUZOU", "Eric Wong"] | |
+ s.email = [nil, nil, 'normal@ruby-lang.org'] | |
+ s.homepage = "https://www.ruby-lang.org" | |
+ s.license = "BSD-2-Clause" | |
+ | |
+ if s.respond_to?(:metadata=) | |
+ s.metadata = { | |
+ "bug_tracker_uri" => "https://bugs.ruby-lang.org/projects/ruby-trunk/issues", | |
+ "homepage_uri" => "https://www.ruby-lang.org", | |
+ "source_code_uri" => "https://svn.ruby-lang.org/repos/ruby" | |
+ } | |
+ end | |
+ | |
+ s.add_development_dependency "rake" | |
+end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment