summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2
diff options
context:
space:
mode:
authorBen Sanders <ben@sanders.life>2026-08-02 09:49:25 -0400
committerBen Sanders <ben@sanders.life>2026-08-02 09:49:25 -0400
commitb41479c91e6685511c1f8ba8586106b322073b62 (patch)
treec9f1345999d754ae0a533849966427e792d9e68d /vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2
parentcfaceeb9a6d1295f5754be211858155cd309acc2 (diff)
added statscounter code
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Gemfile10
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/LICENSE.txt22
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/README.md63
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Rakefile10
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick.rb232
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/accesslog.rb157
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cgi.rb313
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/compat.rb36
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/config.rb158
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cookie.rb172
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/htmlutils.rb30
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth.rb96
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/authenticator.rb117
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/basicauth.rb116
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/digestauth.rb395
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htdigest.rb132
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htgroup.rb97
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htpasswd.rb158
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/userdb.rb53
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpproxy.rb354
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httprequest.rb668
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpresponse.rb588
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/https.rb152
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpserver.rb294
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet.rb23
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/abstract.rb152
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgi_runner.rb47
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgihandler.rb126
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/erbhandler.rb88
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/filehandler.rb552
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/prochandler.rb48
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpstatus.rb194
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httputils.rb543
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpversion.rb76
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/log.rb156
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/server.rb380
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/ssl.rb219
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/utils.rb265
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/version.rb18
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/accesslog.rbs24
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cgi.rbs92
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/compat.rbs18
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/config.rbs17
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cookie.rbs37
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/htmlutils.rbs5
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth.rbs13
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/authenticator.rbs55
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/basicauth.rbs29
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/digestauth.rbs85
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htdigest.rbs31
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htgroup.rbs21
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htpasswd.rbs31
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/userdb.rbs13
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpproxy.rbs61
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httprequest.rbs167
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpresponse.rbs117
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/https.rbs49
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpserver.rbs71
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet.rbs4
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/abstract.rbs36
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgi_runner.rbs3
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgihandler.rbs23
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/erbhandler.rbs17
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/filehandler.rbs76
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/prochandler.rbs21
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpstatus.rbs255
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httputils.rbs116
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpversion.rbs17
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/log.rbs93
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/manifest.yaml8
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/server.rbs57
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/ssl.rbs19
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/utils.rbs122
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/version.rbs3
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/webrick.gemspec105
75 files changed, 9221 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Gemfile b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Gemfile
new file mode 100644
index 0000000..d069402
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Gemfile
@@ -0,0 +1,10 @@
+source 'https://rubygems.org'
+
+gemspec
+
+gem "rake"
+gem "test-unit"
+gem "test-unit-ruby-core"
+
+# rbs requires ruby 3.0+
+gem "rbs", require: false if !RUBY_VERSION.start_with?('2.')
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/LICENSE.txt b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/LICENSE.txt
new file mode 100644
index 0000000..a009cae
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/README.md b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/README.md
new file mode 100644
index 0000000..685dc84
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/README.md
@@ -0,0 +1,63 @@
+# Webrick
+
+WEBrick is an HTTP server toolkit that can be configured as an HTTPS server, a proxy server, and a virtual-host server.
+
+WEBrick features complete logging of both server operations and HTTP access.
+
+WEBrick supports both basic and digest authentication in addition to algorithms not in RFC 2617.
+
+A WEBrick server can be composed of multiple WEBrick servers or servlets to provide differing behavior on a per-host or per-path basis. WEBrick includes servlets for handling CGI scripts, ERB pages, Ruby blocks and directory listings.
+
+WEBrick also includes tools for daemonizing a process and starting a process at a higher privilege level and dropping permissions.
+
+WEBrick is suitable for use in testing and for development. However, while the developers of WEBrick will attempt to fix security issues, they do not encourage the use of WEBrick to serve production web applications that may be subject to hostile input.
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+```ruby
+gem 'webrick'
+```
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install webrick
+
+## Usage
+
+To create a new WEBrick::HTTPServer that will listen to connections on port 8000 and serve documents from the current user's public_html folder:
+
+```ruby
+require 'webrick'
+
+root = File.expand_path '~/public_html'
+server = WEBrick::HTTPServer.new :Port => 8000, :DocumentRoot => root
+```
+
+To run the server you will need to provide a suitable shutdown hook as
+starting the server blocks the current thread:
+
+```ruby
+trap 'INT' do server.shutdown end
+
+server.start
+```
+
+## Development
+
+After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
+
+To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
+
+## Contributing
+
+Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/webrick.
+
+## License
+
+The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Rakefile b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Rakefile
new file mode 100644
index 0000000..5d512c8
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Rakefile
@@ -0,0 +1,10 @@
+require "bundler/gem_tasks"
+require "rake/testtask"
+
+Rake::TestTask.new(:test) do |t|
+ t.libs << "test/lib"
+ t.ruby_opts << "-rhelper"
+ t.test_files = FileList["test/**/test_*.rb"]
+end
+
+task :default => :test
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick.rb
new file mode 100644
index 0000000..b854b68
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick.rb
@@ -0,0 +1,232 @@
+# frozen_string_literal: false
+##
+# = WEB server toolkit.
+#
+# WEBrick is an HTTP server toolkit that can be configured as an HTTPS server,
+# a proxy server, and a virtual-host server. WEBrick features complete
+# logging of both server operations and HTTP access. WEBrick supports both
+# basic and digest authentication in addition to algorithms not in RFC 2617.
+#
+# A WEBrick server can be composed of multiple WEBrick servers or servlets to
+# provide differing behavior on a per-host or per-path basis. WEBrick
+# includes servlets for handling CGI scripts, ERB pages, Ruby blocks and
+# directory listings.
+#
+# WEBrick also includes tools for daemonizing a process and starting a process
+# at a higher privilege level and dropping permissions.
+#
+# == Security
+#
+# *Warning:* WEBrick is not recommended for production. It only implements
+# basic security checks.
+#
+# == Starting an HTTP server
+#
+# To create a new WEBrick::HTTPServer that will listen to connections on port
+# 8000 and serve documents from the current user's public_html folder:
+#
+# require 'webrick'
+#
+# root = File.expand_path '~/public_html'
+# server = WEBrick::HTTPServer.new :Port => 8000, :DocumentRoot => root
+#
+# To run the server you will need to provide a suitable shutdown hook as
+# starting the server blocks the current thread:
+#
+# trap 'INT' do server.shutdown end
+#
+# server.start
+#
+# == Custom Behavior
+#
+# The easiest way to have a server perform custom operations is through
+# WEBrick::HTTPServer#mount_proc. The block given will be called with a
+# WEBrick::HTTPRequest with request info and a WEBrick::HTTPResponse which
+# must be filled in appropriately:
+#
+# server.mount_proc '/' do |req, res|
+# res.body = 'Hello, world!'
+# end
+#
+# Remember that +server.mount_proc+ must precede +server.start+.
+#
+# == Servlets
+#
+# Advanced custom behavior can be obtained through mounting a subclass of
+# WEBrick::HTTPServlet::AbstractServlet. Servlets provide more modularity
+# when writing an HTTP server than mount_proc allows. Here is a simple
+# servlet:
+#
+# class Simple < WEBrick::HTTPServlet::AbstractServlet
+# def do_GET request, response
+# status, content_type, body = do_stuff_with request
+#
+# response.status = 200
+# response['Content-Type'] = 'text/plain'
+# response.body = 'Hello, World!'
+# end
+# end
+#
+# To initialize the servlet you mount it on the server:
+#
+# server.mount '/simple', Simple
+#
+# See WEBrick::HTTPServlet::AbstractServlet for more details.
+#
+# == Virtual Hosts
+#
+# A server can act as a virtual host for multiple host names. After creating
+# the listening host, additional hosts that do not listen can be created and
+# attached as virtual hosts:
+#
+# server = WEBrick::HTTPServer.new # ...
+#
+# vhost = WEBrick::HTTPServer.new :ServerName => 'vhost.example',
+# :DoNotListen => true, # ...
+# vhost.mount '/', ...
+#
+# server.virtual_host vhost
+#
+# If no +:DocumentRoot+ is provided and no servlets or procs are mounted on the
+# main server it will return 404 for all URLs.
+#
+# == HTTPS
+#
+# To create an HTTPS server you only need to enable SSL and provide an SSL
+# certificate name:
+#
+# require 'webrick'
+# require 'webrick/https'
+#
+# cert_name = [
+# %w[CN localhost],
+# ]
+#
+# server = WEBrick::HTTPServer.new(:Port => 8000,
+# :SSLEnable => true,
+# :SSLCertName => cert_name)
+#
+# This will start the server with a self-generated self-signed certificate.
+# The certificate will be changed every time the server is restarted.
+#
+# To create a server with a pre-determined key and certificate you can provide
+# them:
+#
+# require 'webrick'
+# require 'webrick/https'
+# require 'openssl'
+#
+# cert = OpenSSL::X509::Certificate.new File.read '/path/to/cert.pem'
+# pkey = OpenSSL::PKey::RSA.new File.read '/path/to/pkey.pem'
+#
+# server = WEBrick::HTTPServer.new(:Port => 8000,
+# :SSLEnable => true,
+# :SSLCertificate => cert,
+# :SSLPrivateKey => pkey)
+#
+# == Proxy Server
+#
+# WEBrick can act as a proxy server:
+#
+# require 'webrick'
+# require 'webrick/httpproxy'
+#
+# proxy = WEBrick::HTTPProxyServer.new :Port => 8000
+#
+# trap 'INT' do proxy.shutdown end
+#
+# See WEBrick::HTTPProxy for further details including modifying proxied
+# responses.
+#
+# == Basic and Digest authentication
+#
+# WEBrick provides both Basic and Digest authentication for regular and proxy
+# servers. See WEBrick::HTTPAuth, WEBrick::HTTPAuth::BasicAuth and
+# WEBrick::HTTPAuth::DigestAuth.
+#
+# == WEBrick as a daemonized Web Server
+#
+# WEBrick can be run as a daemonized server for small loads.
+#
+# === Daemonizing
+#
+# To start a WEBrick server as a daemon simple run WEBrick::Daemon.start
+# before starting the server.
+#
+# === Dropping Permissions
+#
+# WEBrick can be started as one user to gain permission to bind to port 80 or
+# 443 for serving HTTP or HTTPS traffic then can drop these permissions for
+# regular operation. To listen on all interfaces for HTTP traffic:
+#
+# sockets = WEBrick::Utils.create_listeners nil, 80
+#
+# Then drop privileges:
+#
+# WEBrick::Utils.su 'www'
+#
+# Then create a server that does not listen by default:
+#
+# server = WEBrick::HTTPServer.new :DoNotListen => true, # ...
+#
+# Then overwrite the listening sockets with the port 80 sockets:
+#
+# server.listeners.replace sockets
+#
+# === Logging
+#
+# WEBrick can separately log server operations and end-user access. For
+# server operations:
+#
+# log_file = File.open '/var/log/webrick.log', 'a+'
+# log = WEBrick::Log.new log_file
+#
+# For user access logging:
+#
+# access_log = [
+# [log_file, WEBrick::AccessLog::COMBINED_LOG_FORMAT],
+# ]
+#
+# server = WEBrick::HTTPServer.new :Logger => log, :AccessLog => access_log
+#
+# See WEBrick::AccessLog for further log formats.
+#
+# === Log Rotation
+#
+# To rotate logs in WEBrick on a HUP signal (like syslogd can send), open the
+# log file in 'a+' mode (as above) and trap 'HUP' to reopen the log file:
+#
+# trap 'HUP' do log_file.reopen '/path/to/webrick.log', 'a+'
+#
+# == Copyright
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+#
+# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#--
+# $IPR: webrick.rb,v 1.12 2002/10/01 17:16:31 gotoyuzo Exp $
+
+module WEBrick
+end
+
+require 'webrick/compat.rb'
+
+require 'webrick/version.rb'
+require 'webrick/config.rb'
+require 'webrick/log.rb'
+require 'webrick/server.rb'
+require_relative 'webrick/utils.rb'
+require 'webrick/accesslog'
+
+require 'webrick/htmlutils.rb'
+require 'webrick/httputils.rb'
+require 'webrick/cookie.rb'
+require 'webrick/httpversion.rb'
+require 'webrick/httpstatus.rb'
+require 'webrick/httprequest.rb'
+require 'webrick/httpresponse.rb'
+require 'webrick/httpserver.rb'
+require 'webrick/httpservlet.rb'
+require 'webrick/httpauth.rb'
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/accesslog.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/accesslog.rb
new file mode 100644
index 0000000..fccfd65
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/accesslog.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+#--
+# accesslog.rb -- Access log handling utilities
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2002 keita yamaguchi
+# Copyright (c) 2002 Internet Programming with Ruby writers
+#
+# $IPR: accesslog.rb,v 1.1 2002/10/01 17:16:32 gotoyuzo Exp $
+
+module WEBrick
+
+ ##
+ # AccessLog provides logging to various files in various formats.
+ #
+ # Multiple logs may be written to at the same time:
+ #
+ # access_log = [
+ # [$stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT],
+ # [$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT],
+ # ]
+ #
+ # server = WEBrick::HTTPServer.new :AccessLog => access_log
+ #
+ # Custom log formats may be defined. WEBrick::AccessLog provides a subset
+ # of the formatting from Apache's mod_log_config
+ # http://httpd.apache.org/docs/mod/mod_log_config.html#formats. See
+ # AccessLog::setup_params for a list of supported options
+
+ module AccessLog
+
+ ##
+ # Raised if a parameter such as %e, %i, %o or %n is used without fetching
+ # a specific field.
+
+ class AccessLogError < StandardError; end
+
+ ##
+ # The Common Log Format's time format
+
+ CLF_TIME_FORMAT = "[%d/%b/%Y:%H:%M:%S %Z]"
+
+ ##
+ # Common Log Format
+
+ COMMON_LOG_FORMAT = "%h %l %u %t \"%r\" %s %b"
+
+ ##
+ # Short alias for Common Log Format
+
+ CLF = COMMON_LOG_FORMAT
+
+ ##
+ # Referer Log Format
+
+ REFERER_LOG_FORMAT = "%{Referer}i -> %U"
+
+ ##
+ # User-Agent Log Format
+
+ AGENT_LOG_FORMAT = "%{User-Agent}i"
+
+ ##
+ # Combined Log Format
+
+ COMBINED_LOG_FORMAT = "#{CLF} \"%{Referer}i\" \"%{User-agent}i\""
+
+ module_function
+
+ # This format specification is a subset of mod_log_config of Apache:
+ #
+ # %a:: Remote IP address
+ # %b:: Total response size
+ # %e{variable}:: Given variable in ENV
+ # %f:: Response filename
+ # %h:: Remote host name
+ # %{header}i:: Given request header
+ # %l:: Remote logname, always "-"
+ # %m:: Request method
+ # %{attr}n:: Given request attribute from <tt>req.attributes</tt>
+ # %{header}o:: Given response header
+ # %p:: Server's request port
+ # %{format}p:: The canonical port of the server serving the request or the
+ # actual port or the client's actual port. Valid formats are
+ # canonical, local or remote.
+ # %q:: Request query string
+ # %r:: First line of the request
+ # %s:: Request status
+ # %t:: Time the request was received
+ # %T:: Time taken to process the request
+ # %u:: Remote user from auth
+ # %U:: Unparsed URI
+ # %%:: Literal %
+
+ def setup_params(config, req, res)
+ params = Hash.new("")
+ params["a"] = req.peeraddr[3]
+ params["b"] = res.sent_size
+ params["e"] = ENV
+ params["f"] = res.filename || ""
+ params["h"] = req.peeraddr[2]
+ params["i"] = req
+ params["l"] = "-"
+ params["m"] = req.request_method
+ params["n"] = req.attributes
+ params["o"] = res
+ params["p"] = req.port
+ params["q"] = req.query_string
+ params["r"] = req.request_line.sub(/\x0d?\x0a\z/o, '')
+ params["s"] = res.status # won't support "%>s"
+ params["t"] = req.request_time
+ params["T"] = Time.now - req.request_time
+ params["u"] = req.user || "-"
+ params["U"] = req.unparsed_uri
+ params["v"] = config[:ServerName]
+ params
+ end
+
+ ##
+ # Formats +params+ according to +format_string+ which is described in
+ # setup_params.
+
+ def format(format_string, params)
+ format_string.gsub(/\%(?:\{(.*?)\})?>?([a-zA-Z%])/){
+ param, spec = $1, $2
+ case spec[0]
+ when ?e, ?i, ?n, ?o
+ raise AccessLogError,
+ "parameter is required for \"#{spec}\"" unless param
+ (param = params[spec][param]) ? escape(param) : "-"
+ when ?t
+ params[spec].strftime(param || CLF_TIME_FORMAT)
+ when ?p
+ case param
+ when 'remote'
+ escape(params["i"].peeraddr[1].to_s)
+ else
+ escape(params["p"].to_s)
+ end
+ when ?%
+ "%"
+ else
+ escape(params[spec].to_s)
+ end
+ }
+ end
+
+ ##
+ # Escapes control characters in +data+
+
+ def escape(data)
+ data = data.gsub(/[[:cntrl:]\\]+/) {$&.dump[1...-1]}
+ data.untaint if RUBY_VERSION < '2.7'
+ data
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cgi.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cgi.rb
new file mode 100644
index 0000000..c86d36c
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cgi.rb
@@ -0,0 +1,313 @@
+# frozen_string_literal: true
+#
+# cgi.rb -- Yet another CGI library
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $Id$
+
+require_relative "httprequest"
+require_relative "httpresponse"
+require_relative "config"
+require "stringio"
+
+module WEBrick
+
+ # A CGI library using WEBrick requests and responses.
+ #
+ # Example:
+ #
+ # class MyCGI < WEBrick::CGI
+ # def do_GET req, res
+ # res.body = 'it worked!'
+ # res.status = 200
+ # end
+ # end
+ #
+ # MyCGI.new.start
+
+ class CGI
+
+ # The CGI error exception class
+
+ CGIError = Class.new(StandardError)
+
+ ##
+ # The CGI configuration. This is based on WEBrick::Config::HTTP
+
+ attr_reader :config
+
+ ##
+ # The CGI logger
+
+ attr_reader :logger
+
+ ##
+ # Creates a new CGI interface.
+ #
+ # The first argument in +args+ is a configuration hash which would update
+ # WEBrick::Config::HTTP.
+ #
+ # Any remaining arguments are stored in the <code>@options</code> instance
+ # variable for use by a subclass.
+
+ def initialize(*args)
+ if defined?(MOD_RUBY)
+ unless ENV.has_key?("GATEWAY_INTERFACE")
+ Apache.request.setup_cgi_env
+ end
+ end
+ if %r{HTTP/(\d+\.\d+)} =~ ENV["SERVER_PROTOCOL"]
+ httpv = $1
+ end
+ @config = WEBrick::Config::HTTP.dup.update(
+ :ServerSoftware => ENV["SERVER_SOFTWARE"] || "null",
+ :HTTPVersion => HTTPVersion.new(httpv || "1.0"),
+ :RunOnCGI => true, # to detect if it runs on CGI.
+ :NPH => false # set true to run as NPH script.
+ )
+ if config = args.shift
+ @config.update(config)
+ end
+ @config[:Logger] ||= WEBrick::BasicLog.new($stderr)
+ @logger = @config[:Logger]
+ @options = args
+ end
+
+ ##
+ # Reads +key+ from the configuration
+
+ def [](key)
+ @config[key]
+ end
+
+ ##
+ # Starts the CGI process with the given environment +env+ and standard
+ # input and output +stdin+ and +stdout+.
+
+ def start(env=ENV, stdin=$stdin, stdout=$stdout)
+ sock = WEBrick::CGI::Socket.new(@config, env, stdin, stdout)
+ req = HTTPRequest.new(@config)
+ res = HTTPResponse.new(@config)
+ unless @config[:NPH] or defined?(MOD_RUBY)
+ def res.setup_header
+ unless @header["status"]
+ phrase = HTTPStatus::reason_phrase(@status)
+ @header["status"] = "#{@status} #{phrase}"
+ end
+ super
+ end
+ def res.status_line
+ ""
+ end
+ end
+
+ begin
+ req.parse(sock)
+ req.script_name = (env["SCRIPT_NAME"] || File.expand_path($0)).dup
+ req.path_info = (env["PATH_INFO"] || "").dup
+ req.query_string = env["QUERY_STRING"]
+ req.user = env["REMOTE_USER"]
+ res.request_method = req.request_method
+ res.request_uri = req.request_uri
+ res.request_http_version = req.http_version
+ res.keep_alive = req.keep_alive?
+ self.service(req, res)
+ rescue HTTPStatus::Error => ex
+ res.set_error(ex)
+ rescue HTTPStatus::Status => ex
+ res.status = ex.code
+ rescue Exception => ex
+ @logger.error(ex)
+ res.set_error(ex, true)
+ ensure
+ req.fixup
+ if defined?(MOD_RUBY)
+ res.setup_header
+ Apache.request.status_line = "#{res.status} #{res.reason_phrase}"
+ Apache.request.status = res.status
+ table = Apache.request.headers_out
+ res.header.each{|key, val|
+ case key
+ when /^content-encoding$/i
+ Apache::request.content_encoding = val
+ when /^content-type$/i
+ Apache::request.content_type = val
+ else
+ table[key] = val.to_s
+ end
+ }
+ res.cookies.each{|cookie|
+ table.add("Set-Cookie", cookie.to_s)
+ }
+ Apache.request.send_http_header
+ res.send_body(sock)
+ else
+ res.send_response(sock)
+ end
+ end
+ end
+
+ ##
+ # Services the request +req+ which will fill in the response +res+. See
+ # WEBrick::HTTPServlet::AbstractServlet#service for details.
+
+ def service(req, res)
+ method_name = "do_" + req.request_method.gsub(/-/, "_")
+ if respond_to?(method_name)
+ __send__(method_name, req, res)
+ else
+ raise HTTPStatus::MethodNotAllowed,
+ "unsupported method '#{req.request_method}'."
+ end
+ end
+
+ ##
+ # Provides HTTP socket emulation from the CGI environment
+
+ class Socket # :nodoc:
+ include Enumerable
+
+ private
+
+ def initialize(config, env, stdin, stdout)
+ @config = config
+ @env = env
+ @header_part = StringIO.new
+ @body_part = stdin
+ @out_port = stdout
+ @out_port.binmode
+
+ @server_addr = @env["SERVER_ADDR"] || "0.0.0.0"
+ @server_name = @env["SERVER_NAME"]
+ @server_port = @env["SERVER_PORT"]
+ @remote_addr = @env["REMOTE_ADDR"]
+ @remote_host = @env["REMOTE_HOST"] || @remote_addr
+ @remote_port = @env["REMOTE_PORT"] || 0
+
+ begin
+ @header_part << request_line << CRLF
+ setup_header
+ @header_part << CRLF
+ @header_part.rewind
+ rescue Exception
+ raise CGIError, "invalid CGI environment"
+ end
+ end
+
+ def request_line
+ meth = @env["REQUEST_METHOD"] || "GET"
+ unless url = @env["REQUEST_URI"]
+ url = (@env["SCRIPT_NAME"] || File.expand_path($0)).dup
+ url << @env["PATH_INFO"].to_s
+ url = WEBrick::HTTPUtils.escape_path(url)
+ if query_string = @env["QUERY_STRING"]
+ unless query_string.empty?
+ url << "?" << query_string
+ end
+ end
+ end
+ # we cannot get real HTTP version of client ;)
+ httpv = @config[:HTTPVersion]
+ return "#{meth} #{url} HTTP/#{httpv}"
+ end
+
+ def setup_header
+ @env.each{|key, value|
+ case key
+ when "CONTENT_TYPE", "CONTENT_LENGTH"
+ add_header(key.gsub(/_/, "-"), value)
+ when /^HTTP_(.*)/
+ add_header($1.gsub(/_/, "-"), value)
+ end
+ }
+ end
+
+ def add_header(hdrname, value)
+ unless value.empty?
+ @header_part << hdrname << ": " << value << CRLF
+ end
+ end
+
+ def input
+ @header_part.eof? ? @body_part : @header_part
+ end
+
+ public
+
+ def peeraddr
+ [nil, @remote_port, @remote_host, @remote_addr]
+ end
+
+ def addr
+ [nil, @server_port, @server_name, @server_addr]
+ end
+
+ def gets(eol=LF, size=nil)
+ input.gets(eol, size)
+ end
+
+ def read(size=nil)
+ input.read(size)
+ end
+
+ def each
+ input.each{|line| yield(line) }
+ end
+
+ def eof?
+ input.eof?
+ end
+
+ 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"]
+ OpenSSL::X509::Certificate.new(pem) unless pem.empty?
+ end
+ end
+
+ def peer_cert
+ return nil unless defined?(OpenSSL)
+ if pem = @env["SSL_CLIENT_CERT"]
+ OpenSSL::X509::Certificate.new(pem) unless pem.empty?
+ end
+ end
+
+ def peer_cert_chain
+ return nil unless defined?(OpenSSL)
+ if @env["SSL_CLIENT_CERT_CHAIN_0"]
+ keys = @env.keys
+ certs = keys.sort.collect{|k|
+ if /^SSL_CLIENT_CERT_CHAIN_\d+$/ =~ k
+ if pem = @env[k]
+ OpenSSL::X509::Certificate.new(pem) unless pem.empty?
+ end
+ end
+ }
+ certs.compact
+ end
+ end
+
+ def cipher
+ return nil unless defined?(OpenSSL)
+ if cipher = @env["SSL_CIPHER"]
+ ret = [ cipher ]
+ ret << @env["SSL_PROTOCOL"]
+ ret << @env["SSL_CIPHER_USEKEYSIZE"]
+ ret << @env["SSL_CIPHER_ALGKEYSIZE"]
+ ret
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/compat.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/compat.rb
new file mode 100644
index 0000000..842da1e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/compat.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+#
+# compat.rb -- cross platform compatibility
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2002 GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: compat.rb,v 1.6 2002/10/01 17:16:32 gotoyuzo Exp $
+
+##
+# System call error module used by webrick for cross platform compatibility.
+#
+# EPROTO:: protocol error
+# ECONNRESET:: remote host reset the connection request
+# ECONNABORTED:: Client sent TCP reset (RST) before server has accepted the
+# connection requested by client.
+#
+module Errno
+ ##
+ # Protocol error.
+
+ class EPROTO < SystemCallError; end
+
+ ##
+ # Remote host reset the connection request.
+
+ class ECONNRESET < SystemCallError; end
+
+ ##
+ # Client sent TCP reset (RST) before server has accepted the connection
+ # requested by client.
+
+ class ECONNABORTED < SystemCallError; end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/config.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/config.rb
new file mode 100644
index 0000000..d67375c
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/config.rb
@@ -0,0 +1,158 @@
+# frozen_string_literal: true
+#
+# config.rb -- Default configurations.
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: config.rb,v 1.52 2003/07/22 19:20:42 gotoyuzo Exp $
+
+require_relative 'version'
+require_relative 'httpversion'
+require_relative 'httputils'
+require_relative 'utils'
+require_relative 'log'
+
+module WEBrick
+ module Config
+ LIBDIR = File::dirname(__FILE__) # :nodoc:
+
+ # for GenericServer
+ General = Hash.new { |hash, key|
+ case key
+ when :ServerName
+ hash[key] = Utils.getservername
+ else
+ nil
+ end
+ }.update(
+ :BindAddress => nil, # "0.0.0.0" or "::" or nil
+ :Port => nil, # users MUST specify this!!
+ :MaxClients => 100, # maximum number of the concurrent connections
+ :ServerType => nil, # default: WEBrick::SimpleServer
+ :Logger => nil, # default: WEBrick::Log.new
+ :ServerSoftware => "WEBrick/#{WEBrick::VERSION} " +
+ "(Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})",
+ :TempDir => ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp',
+ :DoNotListen => false,
+ :StartCallback => nil,
+ :StopCallback => nil,
+ :AcceptCallback => nil,
+ :DoNotReverseLookup => true,
+ :ShutdownSocketWithoutClose => false,
+ )
+
+ # for HTTPServer, HTTPRequest, HTTPResponse ...
+ HTTP = General.dup.update(
+ :Port => 80,
+ :RequestTimeout => 30,
+ :HTTPVersion => HTTPVersion.new("1.1"),
+ :AccessLog => nil,
+ :MimeTypes => HTTPUtils::DefaultMimeTypes,
+ :DirectoryIndex => ["index.html","index.htm","index.cgi","index.rhtml"],
+ :DocumentRoot => nil,
+ :DocumentRootOptions => { :FancyIndexing => true },
+ :RequestCallback => nil,
+ :ServerAlias => nil,
+ :InputBufferSize => 65536, # input buffer size in reading request body
+ :OutputBufferSize => 65536, # output buffer size in sending File or IO
+
+ # for HTTPProxyServer
+ :ProxyAuthProc => nil,
+ :ProxyContentHandler => nil,
+ :ProxyVia => true,
+ :ProxyTimeout => true,
+ :ProxyURI => nil,
+
+ :CGIInterpreter => nil,
+ :CGIPathEnv => nil,
+
+ # workaround: if Request-URIs contain 8bit chars,
+ # they should be escaped before calling of URI::parse().
+ :Escape8bitURI => false
+ )
+
+ ##
+ # Default configuration for WEBrick::HTTPServlet::FileHandler
+ #
+ # :AcceptableLanguages::
+ # Array of languages allowed for accept-language. There is no default
+ # :DirectoryCallback::
+ # Allows preprocessing of directory requests. There is no default
+ # callback.
+ # :FancyIndexing::
+ # If true, show an index for directories. The default is true.
+ # :FileCallback::
+ # Allows preprocessing of file requests. There is no default callback.
+ # :HandlerCallback::
+ # Allows preprocessing of requests. There is no default callback.
+ # :HandlerTable::
+ # Maps file suffixes to file handlers. DefaultFileHandler is used by
+ # default but any servlet can be used.
+ # :NondisclosureName::
+ # Do not show files matching this array of globs. .ht* and *~ are
+ # excluded by default.
+ # :UserDir::
+ # Directory inside ~user to serve content from for /~user requests.
+ # Only works if mounted on /. Disabled by default.
+
+ FileHandler = {
+ :NondisclosureName => [".ht*", "*~"],
+ :FancyIndexing => false,
+ :HandlerTable => {},
+ :HandlerCallback => nil,
+ :DirectoryCallback => nil,
+ :FileCallback => nil,
+ :UserDir => nil, # e.g. "public_html"
+ :AcceptableLanguages => [] # ["en", "ja", ... ]
+ }
+
+ ##
+ # Default configuration for WEBrick::HTTPAuth::BasicAuth
+ #
+ # :AutoReloadUserDB:: Reload the user database provided by :UserDB
+ # automatically?
+
+ BasicAuth = {
+ :AutoReloadUserDB => true,
+ }
+
+ ##
+ # Default configuration for WEBrick::HTTPAuth::DigestAuth.
+ #
+ # :Algorithm:: MD5, MD5-sess (default), SHA1, SHA1-sess
+ # :Domain:: An Array of URIs that define the protected space
+ # :Qop:: 'auth' for authentication, 'auth-int' for integrity protection or
+ # both
+ # :UseOpaque:: Should the server send opaque values to the client? This
+ # helps prevent replay attacks.
+ # :CheckNc:: Should the server check the nonce count? This helps the
+ # server detect replay attacks.
+ # :UseAuthenticationInfoHeader:: Should the server send an
+ # AuthenticationInfo header?
+ # :AutoReloadUserDB:: Reload the user database provided by :UserDB
+ # automatically?
+ # :NonceExpirePeriod:: How long should we store used nonces? Default is
+ # 30 minutes.
+ # :NonceExpireDelta:: How long is a nonce valid? Default is 1 minute
+ # :InternetExplorerHack:: Hack which allows Internet Explorer to work.
+ # :OperaHack:: Hack which allows Opera to work.
+
+ DigestAuth = {
+ :Algorithm => 'MD5-sess', # or 'MD5'
+ :Domain => nil, # an array includes domain names.
+ :Qop => [ 'auth' ], # 'auth' or 'auth-int' or both.
+ :UseOpaque => true,
+ :UseNextNonce => false,
+ :CheckNc => false,
+ :UseAuthenticationInfoHeader => true,
+ :AutoReloadUserDB => true,
+ :NonceExpirePeriod => 30*60,
+ :NonceExpireDelta => 60,
+ :InternetExplorerHack => true,
+ :OperaHack => true,
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cookie.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cookie.rb
new file mode 100644
index 0000000..7b18782
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cookie.rb
@@ -0,0 +1,172 @@
+# frozen_string_literal: true
+#
+# cookie.rb -- Cookie class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $
+
+require 'time'
+require_relative 'httputils'
+
+module WEBrick
+
+ ##
+ # Processes HTTP cookies
+
+ class Cookie
+
+ ##
+ # The cookie name
+
+ attr_reader :name
+
+ ##
+ # The cookie value
+
+ attr_accessor :value
+
+ ##
+ # The cookie version
+
+ attr_accessor :version
+
+ ##
+ # The cookie domain
+ attr_accessor :domain
+
+ ##
+ # The cookie path
+
+ attr_accessor :path
+
+ ##
+ # Is this a secure cookie?
+
+ attr_accessor :secure
+
+ ##
+ # The cookie comment
+
+ attr_accessor :comment
+
+ ##
+ # The maximum age of the cookie
+
+ attr_accessor :max_age
+
+ #attr_accessor :comment_url, :discard, :port
+
+ ##
+ # Creates a new cookie with the given +name+ and +value+
+
+ def initialize(name, value)
+ @name = name
+ @value = value
+ @version = 0 # Netscape Cookie
+
+ @domain = @path = @secure = @comment = @max_age =
+ @expires = @comment_url = @discard = @port = nil
+ end
+
+ ##
+ # Sets the cookie expiration to the time +t+. The expiration time may be
+ # a false value to disable expiration or a Time or HTTP format time string
+ # to set the expiration date.
+
+ def expires=(t)
+ @expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
+ end
+
+ ##
+ # Retrieves the expiration time as a Time
+
+ def expires
+ @expires && Time.parse(@expires)
+ end
+
+ ##
+ # The cookie string suitable for use in an HTTP header
+
+ def to_s
+ ret = +""
+ ret << @name << "=" << @value
+ ret << "; " << "Version=" << @version.to_s if @version > 0
+ ret << "; " << "Domain=" << @domain if @domain
+ ret << "; " << "Expires=" << @expires if @expires
+ ret << "; " << "Max-Age=" << @max_age.to_s if @max_age
+ ret << "; " << "Comment=" << @comment if @comment
+ ret << "; " << "Path=" << @path if @path
+ ret << "; " << "Secure" if @secure
+ ret
+ end
+
+ ##
+ # Parses a Cookie field sent from the user-agent. Returns an array of
+ # cookies.
+
+ def self.parse(str)
+ if str
+ ret = []
+ cookie = nil
+ ver = 0
+ str.split(/;\s+/).each{|x|
+ key, val = x.split(/=/,2)
+ val = val ? HTTPUtils::dequote(val) : ""
+ case key
+ when "$Version"; ver = val.to_i
+ when "$Path"; cookie.path = val
+ when "$Domain"; cookie.domain = val
+ when "$Port"; cookie.port = val
+ else
+ ret << cookie if cookie
+ cookie = self.new(key, val)
+ cookie.version = ver
+ end
+ }
+ ret << cookie if cookie
+ ret
+ end
+ end
+
+ ##
+ # Parses the cookie in +str+
+
+ def self.parse_set_cookie(str)
+ cookie_elem = str.split(/;/)
+ first_elem = cookie_elem.shift
+ first_elem.strip!
+ key, value = first_elem.split(/=/, 2)
+ cookie = new(key, HTTPUtils.dequote(value))
+ cookie_elem.each{|pair|
+ pair.strip!
+ key, value = pair.split(/=/, 2)
+ if value
+ value = HTTPUtils.dequote(value.strip)
+ end
+ case key.downcase
+ when "domain" then cookie.domain = value
+ when "path" then cookie.path = value
+ when "expires" then cookie.expires = value
+ when "max-age" then cookie.max_age = Integer(value)
+ when "comment" then cookie.comment = value
+ when "version" then cookie.version = Integer(value)
+ when "secure" then cookie.secure = true
+ end
+ }
+ return cookie
+ end
+
+ ##
+ # Parses the cookies in +str+
+
+ def self.parse_set_cookies(str)
+ return str.split(/,(?=[^;,]*=)|,$/).collect{|c|
+ parse_set_cookie(c)
+ }
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/htmlutils.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/htmlutils.rb
new file mode 100644
index 0000000..7ff0bde
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/htmlutils.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+#--
+# htmlutils.rb -- HTMLUtils Module
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: htmlutils.rb,v 1.7 2002/09/21 12:23:35 gotoyuzo Exp $
+
+module WEBrick
+ module HTMLUtils
+
+ ##
+ # Escapes &, ", > and < in +string+
+
+ def escape(string)
+ return "" unless string
+ str = string.b
+ str.gsub!(/&/n, '&amp;')
+ str.gsub!(/\"/n, '&quot;')
+ str.gsub!(/>/n, '&gt;')
+ str.gsub!(/</n, '&lt;')
+ str.force_encoding(string.encoding)
+ end
+ module_function :escape
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth.rb
new file mode 100644
index 0000000..4f5321c
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+#
+# httpauth.rb -- HTTP access authentication
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httpauth.rb,v 1.14 2003/07/22 19:20:42 gotoyuzo Exp $
+
+require_relative 'httpauth/basicauth'
+require_relative 'httpauth/digestauth'
+require_relative 'httpauth/htpasswd'
+require_relative 'httpauth/htdigest'
+require_relative 'httpauth/htgroup'
+
+module WEBrick
+
+ ##
+ # HTTPAuth provides both basic and digest authentication.
+ #
+ # To enable authentication for requests in WEBrick you will need a user
+ # database and an authenticator. To start, here's an Htpasswd database for
+ # use with a DigestAuth authenticator:
+ #
+ # config = { :Realm => 'DigestAuth example realm' }
+ #
+ # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file'
+ # htpasswd.auth_type = WEBrick::HTTPAuth::DigestAuth
+ # htpasswd.set_passwd config[:Realm], 'username', 'password'
+ # htpasswd.flush
+ #
+ # The +:Realm+ is used to provide different access to different groups
+ # across several resources on a server. Typically you'll need only one
+ # realm for a server.
+ #
+ # This database can be used to create an authenticator:
+ #
+ # config[:UserDB] = htpasswd
+ #
+ # digest_auth = WEBrick::HTTPAuth::DigestAuth.new config
+ #
+ # To authenticate a request call #authenticate with a request and response
+ # object in a servlet:
+ #
+ # def do_GET req, res
+ # @authenticator.authenticate req, res
+ # end
+ #
+ # For digest authentication the authenticator must not be created every
+ # request, it must be passed in as an option via WEBrick::HTTPServer#mount.
+
+ module HTTPAuth
+ module_function
+
+ def _basic_auth(req, res, realm, req_field, res_field, err_type,
+ block) # :nodoc:
+ user = pass = nil
+ if /^Basic\s+(.*)/o =~ req[req_field]
+ userpass = $1
+ user, pass = userpass.unpack("m*")[0].split(":", 2)
+ end
+ if block.call(user, pass)
+ req.user = user
+ return
+ end
+ res[res_field] = "Basic realm=\"#{realm}\""
+ raise err_type
+ end
+
+ ##
+ # Simple wrapper for providing basic authentication for a request. When
+ # called with a request +req+, response +res+, authentication +realm+ and
+ # +block+ the block will be called with a +username+ and +password+. If
+ # the block returns true the request is allowed to continue, otherwise an
+ # HTTPStatus::Unauthorized error is raised.
+
+ def basic_auth(req, res, realm, &block) # :yield: username, password
+ _basic_auth(req, res, realm, "Authorization", "WWW-Authenticate",
+ HTTPStatus::Unauthorized, block)
+ end
+
+ ##
+ # Simple wrapper for providing basic authentication for a proxied request.
+ # When called with a request +req+, response +res+, authentication +realm+
+ # and +block+ the block will be called with a +username+ and +password+.
+ # If the block returns true the request is allowed to continue, otherwise
+ # an HTTPStatus::ProxyAuthenticationRequired error is raised.
+
+ def proxy_basic_auth(req, res, realm, &block) # :yield: username, password
+ _basic_auth(req, res, realm, "Proxy-Authorization", "Proxy-Authenticate",
+ HTTPStatus::ProxyAuthenticationRequired, block)
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/authenticator.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/authenticator.rb
new file mode 100644
index 0000000..13b1c7e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/authenticator.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+#--
+# httpauth/authenticator.rb -- Authenticator mix-in module.
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: authenticator.rb,v 1.3 2003/02/20 07:15:47 gotoyuzo Exp $
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # Module providing generic support for both Digest and Basic
+ # authentication schemes.
+
+ module Authenticator
+
+ RequestField = "Authorization" # :nodoc:
+ ResponseField = "WWW-Authenticate" # :nodoc:
+ ResponseInfoField = "Authentication-Info" # :nodoc:
+ AuthException = HTTPStatus::Unauthorized # :nodoc:
+
+ ##
+ # Method of authentication, must be overridden by the including class
+
+ AuthScheme = nil
+
+ ##
+ # The realm this authenticator covers
+
+ attr_reader :realm
+
+ ##
+ # The user database for this authenticator
+
+ attr_reader :userdb
+
+ ##
+ # The logger for this authenticator
+
+ attr_reader :logger
+
+ private
+
+ # :stopdoc:
+
+ ##
+ # Initializes the authenticator from +config+
+
+ def check_init(config)
+ [:UserDB, :Realm].each{|sym|
+ unless config[sym]
+ raise ArgumentError, "Argument #{sym.inspect} missing."
+ end
+ }
+ @realm = config[:Realm]
+ @userdb = config[:UserDB]
+ @logger = config[:Logger] || Log::new($stderr)
+ @reload_db = config[:AutoReloadUserDB]
+ @request_field = self::class::RequestField
+ @response_field = self::class::ResponseField
+ @resp_info_field = self::class::ResponseInfoField
+ @auth_exception = self::class::AuthException
+ @auth_scheme = self::class::AuthScheme
+ end
+
+ ##
+ # Ensures +req+ has credentials that can be authenticated.
+
+ def check_scheme(req)
+ unless credentials = req[@request_field]
+ error("no credentials in the request.")
+ return nil
+ end
+ unless match = /^#{@auth_scheme}\s+/i.match(credentials)
+ error("invalid scheme in %s.", credentials)
+ info("%s: %s", @request_field, credentials) if $DEBUG
+ return nil
+ end
+ return match.post_match
+ end
+
+ def log(meth, fmt, *args)
+ msg = format("%s %s: ", @auth_scheme, @realm)
+ msg << fmt % args
+ @logger.__send__(meth, msg)
+ end
+
+ def error(fmt, *args)
+ if @logger.error?
+ log(:error, fmt, *args)
+ end
+ end
+
+ def info(fmt, *args)
+ if @logger.info?
+ log(:info, fmt, *args)
+ end
+ end
+
+ # :startdoc:
+ end
+
+ ##
+ # Module providing generic support for both Digest and Basic
+ # authentication schemes for proxies.
+
+ module ProxyAuthenticator
+ RequestField = "Proxy-Authorization" # :nodoc:
+ ResponseField = "Proxy-Authenticate" # :nodoc:
+ ResponseInfoField = "Proxy-Authentication-Info" # :nodoc:
+ AuthException = HTTPStatus::ProxyAuthenticationRequired # :nodoc:
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/basicauth.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/basicauth.rb
new file mode 100644
index 0000000..cc8137a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/basicauth.rb
@@ -0,0 +1,116 @@
+# frozen_string_literal: true
+#
+# httpauth/basicauth.rb -- HTTP basic access authentication
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: basicauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $
+
+require_relative '../config'
+require_relative '../httpstatus'
+require_relative 'authenticator'
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # Basic Authentication for WEBrick
+ #
+ # Use this class to add basic authentication to a WEBrick servlet.
+ #
+ # Here is an example of how to set up a BasicAuth:
+ #
+ # config = { :Realm => 'BasicAuth example realm' }
+ #
+ # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file', password_hash: :bcrypt
+ # htpasswd.set_passwd config[:Realm], 'username', 'password'
+ # htpasswd.flush
+ #
+ # config[:UserDB] = htpasswd
+ #
+ # basic_auth = WEBrick::HTTPAuth::BasicAuth.new config
+
+ class BasicAuth
+ include Authenticator
+
+ AuthScheme = "Basic" # :nodoc:
+
+ ##
+ # Used by UserDB to create a basic password entry
+
+ def self.make_passwd(realm, user, pass)
+ pass ||= ""
+ pass.crypt(Utils::random_string(2))
+ end
+
+ attr_reader :realm, :userdb, :logger
+
+ ##
+ # Creates a new BasicAuth instance.
+ #
+ # See WEBrick::Config::BasicAuth for default configuration entries
+ #
+ # You must supply the following configuration entries:
+ #
+ # :Realm:: The name of the realm being protected.
+ # :UserDB:: A database of usernames and passwords.
+ # A WEBrick::HTTPAuth::Htpasswd instance should be used.
+
+ def initialize(config, default=Config::BasicAuth)
+ check_init(config)
+ @config = default.dup.update(config)
+ end
+
+ ##
+ # Authenticates a +req+ and returns a 401 Unauthorized using +res+ if
+ # the authentication was not correct.
+
+ def authenticate(req, res)
+ unless basic_credentials = check_scheme(req)
+ challenge(req, res)
+ end
+ userid, password = basic_credentials.unpack("m*")[0].split(":", 2)
+ password ||= ""
+ if userid.empty?
+ error("user id was not given.")
+ challenge(req, res)
+ end
+ unless encpass = @userdb.get_passwd(@realm, userid, @reload_db)
+ error("%s: the user is not allowed.", userid)
+ challenge(req, res)
+ end
+
+ 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
+ info("%s: authentication succeeded.", userid)
+ req.user = userid
+ end
+
+ ##
+ # Returns a challenge response which asks for authentication information
+
+ def challenge(req, res)
+ res[@response_field] = "#{@auth_scheme} realm=\"#{@realm}\""
+ raise @auth_exception
+ end
+ end
+
+ ##
+ # Basic authentication for proxy servers. See BasicAuth for details.
+
+ class ProxyBasicAuth < BasicAuth
+ include ProxyAuthenticator
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/digestauth.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/digestauth.rb
new file mode 100644
index 0000000..25ce8ba
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/digestauth.rb
@@ -0,0 +1,395 @@
+# frozen_string_literal: true
+#
+# httpauth/digestauth.rb -- HTTP digest access authentication
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers.
+# Copyright (c) 2003 H.M.
+#
+# The original implementation is provided by H.M.
+# URL: http://rwiki.jin.gr.jp/cgi-bin/rw-cgi.rb?cmd=view;name=
+# %C7%A7%BE%DA%B5%A1%C7%BD%A4%F2%B2%FE%C2%A4%A4%B7%A4%C6%A4%DF%A4%EB
+#
+# $IPR: digestauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $
+
+require_relative '../config'
+require_relative '../httpstatus'
+require_relative 'authenticator'
+require 'digest/md5'
+require 'digest/sha1'
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # RFC 2617 Digest Access Authentication for WEBrick
+ #
+ # Use this class to add digest authentication to a WEBrick servlet.
+ #
+ # Here is an example of how to set up DigestAuth:
+ #
+ # config = { :Realm => 'DigestAuth example realm' }
+ #
+ # htdigest = WEBrick::HTTPAuth::Htdigest.new 'my_password_file'
+ # htdigest.set_passwd config[:Realm], 'username', 'password'
+ # htdigest.flush
+ #
+ # config[:UserDB] = htdigest
+ #
+ # digest_auth = WEBrick::HTTPAuth::DigestAuth.new config
+ #
+ # When using this as with a servlet be sure not to create a new DigestAuth
+ # object in the servlet's #initialize. By default WEBrick creates a new
+ # servlet instance for every request and the DigestAuth object must be
+ # used across requests.
+
+ class DigestAuth
+ include Authenticator
+
+ AuthScheme = "Digest" # :nodoc:
+
+ ##
+ # Struct containing the opaque portion of the digest authentication
+
+ OpaqueInfo = Struct.new(:time, :nonce, :nc) # :nodoc:
+
+ ##
+ # Digest authentication algorithm
+
+ attr_reader :algorithm
+
+ ##
+ # Quality of protection. RFC 2617 defines "auth" and "auth-int"
+
+ attr_reader :qop
+
+ ##
+ # Used by UserDB to create a digest password entry
+
+ def self.make_passwd(realm, user, pass)
+ pass ||= ""
+ Digest::MD5::hexdigest([user, realm, pass].join(":"))
+ end
+
+ ##
+ # Creates a new DigestAuth instance. Be sure to use the same DigestAuth
+ # instance for multiple requests as it saves state between requests in
+ # order to perform authentication.
+ #
+ # See WEBrick::Config::DigestAuth for default configuration entries
+ #
+ # You must supply the following configuration entries:
+ #
+ # :Realm:: The name of the realm being protected.
+ # :UserDB:: A database of usernames and passwords.
+ # A WEBrick::HTTPAuth::Htdigest instance should be used.
+
+ def initialize(config, default=Config::DigestAuth)
+ check_init(config)
+ @config = default.dup.update(config)
+ @algorithm = @config[:Algorithm]
+ @domain = @config[:Domain]
+ @qop = @config[:Qop]
+ @use_opaque = @config[:UseOpaque]
+ @use_next_nonce = @config[:UseNextNonce]
+ @check_nc = @config[:CheckNc]
+ @use_auth_info_header = @config[:UseAuthenticationInfoHeader]
+ @nonce_expire_period = @config[:NonceExpirePeriod]
+ @nonce_expire_delta = @config[:NonceExpireDelta]
+ @internet_explorer_hack = @config[:InternetExplorerHack]
+
+ case @algorithm
+ when 'MD5','MD5-sess'
+ @h = Digest::MD5
+ when 'SHA1','SHA1-sess' # it is a bonus feature :-)
+ @h = Digest::SHA1
+ else
+ msg = format('Algorithm "%s" is not supported.', @algorithm)
+ raise ArgumentError.new(msg)
+ end
+
+ @instance_key = hexdigest(self.__id__, Time.now.to_i, Process.pid)
+ @opaques = {}
+ @last_nonce_expire = Time.now
+ @mutex = Thread::Mutex.new
+ end
+
+ ##
+ # Authenticates a +req+ and returns a 401 Unauthorized using +res+ if
+ # the authentication was not correct.
+
+ def authenticate(req, res)
+ unless result = @mutex.synchronize{ _authenticate(req, res) }
+ challenge(req, res)
+ end
+ if result == :nonce_is_stale
+ challenge(req, res, true)
+ end
+ return true
+ end
+
+ ##
+ # Returns a challenge response which asks for authentication information
+
+ def challenge(req, res, stale=false)
+ nonce = generate_next_nonce(req)
+ if @use_opaque
+ opaque = generate_opaque(req)
+ @opaques[opaque].nonce = nonce
+ end
+
+ param = Hash.new
+ param["realm"] = HTTPUtils::quote(@realm)
+ param["domain"] = HTTPUtils::quote(@domain.to_a.join(" ")) if @domain
+ param["nonce"] = HTTPUtils::quote(nonce)
+ param["opaque"] = HTTPUtils::quote(opaque) if opaque
+ param["stale"] = stale.to_s
+ param["algorithm"] = @algorithm
+ param["qop"] = HTTPUtils::quote(@qop.to_a.join(",")) if @qop
+
+ res[@response_field] =
+ "#{@auth_scheme} " + param.map{|k,v| "#{k}=#{v}" }.join(", ")
+ info("%s: %s", @response_field, res[@response_field]) if $DEBUG
+ raise @auth_exception
+ end
+
+ private
+
+ # :stopdoc:
+
+ MustParams = ['username','realm','nonce','uri','response']
+ MustParamsAuth = ['cnonce','nc']
+
+ def _authenticate(req, res)
+ unless digest_credentials = check_scheme(req)
+ return false
+ end
+
+ auth_req = split_param_value(digest_credentials)
+ if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
+ req_params = MustParams + MustParamsAuth
+ else
+ req_params = MustParams
+ end
+ req_params.each{|key|
+ unless auth_req.has_key?(key)
+ error('%s: parameter missing. "%s"', auth_req['username'], key)
+ raise HTTPStatus::BadRequest
+ end
+ }
+
+ if !check_uri(req, auth_req)
+ raise HTTPStatus::BadRequest
+ end
+
+ if auth_req['realm'] != @realm
+ error('%s: realm unmatch. "%s" for "%s"',
+ auth_req['username'], auth_req['realm'], @realm)
+ return false
+ end
+
+ auth_req['algorithm'] ||= 'MD5'
+ if auth_req['algorithm'].upcase != @algorithm.upcase
+ error('%s: algorithm unmatch. "%s" for "%s"',
+ auth_req['username'], auth_req['algorithm'], @algorithm)
+ return false
+ end
+
+ if (@qop.nil? && auth_req.has_key?('qop')) ||
+ (@qop && (! @qop.member?(auth_req['qop'])))
+ error('%s: the qop is not allowed. "%s"',
+ auth_req['username'], auth_req['qop'])
+ return false
+ end
+
+ password = @userdb.get_passwd(@realm, auth_req['username'], @reload_db)
+ unless password
+ error('%s: the user is not allowed.', auth_req['username'])
+ return false
+ end
+
+ nonce_is_invalid = false
+ if @use_opaque
+ info("@opaque = %s", @opaque.inspect) if $DEBUG
+ if !(opaque = auth_req['opaque'])
+ error('%s: opaque is not given.', auth_req['username'])
+ nonce_is_invalid = true
+ elsif !(opaque_struct = @opaques[opaque])
+ error('%s: invalid opaque is given.', auth_req['username'])
+ nonce_is_invalid = true
+ elsif !check_opaque(opaque_struct, req, auth_req)
+ @opaques.delete(auth_req['opaque'])
+ nonce_is_invalid = true
+ end
+ elsif !check_nonce(req, auth_req)
+ nonce_is_invalid = true
+ end
+
+ if /-sess$/i =~ auth_req['algorithm']
+ ha1 = hexdigest(password, auth_req['nonce'], auth_req['cnonce'])
+ else
+ ha1 = password
+ end
+
+ if auth_req['qop'] == "auth" || auth_req['qop'] == nil
+ ha2 = hexdigest(req.request_method, auth_req['uri'])
+ ha2_res = hexdigest("", auth_req['uri'])
+ elsif auth_req['qop'] == "auth-int"
+ 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"
+ param2 = ['nonce', 'nc', 'cnonce', 'qop'].map{|key|
+ auth_req[key]
+ }.join(':')
+ digest = hexdigest(ha1, param2, ha2)
+ digest_res = hexdigest(ha1, param2, ha2_res)
+ else
+ digest = hexdigest(ha1, auth_req['nonce'], ha2)
+ digest_res = hexdigest(ha1, auth_req['nonce'], ha2_res)
+ end
+
+ if digest != auth_req['response']
+ error("%s: digest unmatch.", auth_req['username'])
+ return false
+ elsif nonce_is_invalid
+ error('%s: digest is valid, but nonce is not valid.',
+ auth_req['username'])
+ return :nonce_is_stale
+ elsif @use_auth_info_header
+ auth_info = {
+ 'nextnonce' => generate_next_nonce(req),
+ 'rspauth' => digest_res
+ }
+ if @use_opaque
+ opaque_struct.time = req.request_time
+ opaque_struct.nonce = auth_info['nextnonce']
+ opaque_struct.nc = "%08x" % (auth_req['nc'].hex + 1)
+ end
+ if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
+ ['qop','cnonce','nc'].each{|key|
+ auth_info[key] = auth_req[key]
+ }
+ end
+ res[@resp_info_field] = auth_info.keys.map{|key|
+ if key == 'nc'
+ key + '=' + auth_info[key]
+ else
+ key + "=" + HTTPUtils::quote(auth_info[key])
+ end
+ }.join(', ')
+ end
+ info('%s: authentication succeeded.', auth_req['username'])
+ req.user = auth_req['username']
+ return true
+ end
+
+ def split_param_value(string)
+ ret = {}
+ string.scan(/\G\s*([\w\-.*%!]+)=\s*(?:\"((?>\\.|[^\"])*)\"|([^,\"]*))\s*,?/) do
+ ret[$1] = $3 || $2.gsub(/\\(.)/, "\\1")
+ end
+ ret
+ end
+
+ def generate_next_nonce(req)
+ now = "%012d" % req.request_time.to_i
+ pk = hexdigest(now, @instance_key)[0,32]
+ nonce = [now + ":" + pk].pack("m0") # it has 60 length of chars.
+ nonce
+ end
+
+ def check_nonce(req, auth_req)
+ username = auth_req['username']
+ nonce = auth_req['nonce']
+
+ pub_time, pk = nonce.unpack("m*")[0].split(":", 2)
+ if (!pub_time || !pk)
+ error("%s: empty nonce is given", username)
+ return false
+ elsif (hexdigest(pub_time, @instance_key)[0,32] != pk)
+ error("%s: invalid private-key: %s for %s",
+ username, hexdigest(pub_time, @instance_key)[0,32], pk)
+ return false
+ end
+
+ diff_time = req.request_time.to_i - pub_time.to_i
+ if (diff_time < 0)
+ error("%s: difference of time-stamp is negative.", username)
+ return false
+ elsif diff_time > @nonce_expire_period
+ error("%s: nonce is expired.", username)
+ return false
+ end
+
+ return true
+ end
+
+ def generate_opaque(req)
+ @mutex.synchronize{
+ now = req.request_time
+ if now - @last_nonce_expire > @nonce_expire_delta
+ @opaques.delete_if{|key,val|
+ (now - val.time) > @nonce_expire_period
+ }
+ @last_nonce_expire = now
+ end
+ begin
+ opaque = Utils::random_string(16)
+ end while @opaques[opaque]
+ @opaques[opaque] = OpaqueInfo.new(now, nil, '00000001')
+ opaque
+ }
+ end
+
+ def check_opaque(opaque_struct, req, auth_req)
+ if (@use_next_nonce && auth_req['nonce'] != opaque_struct.nonce)
+ error('%s: nonce unmatched. "%s" for "%s"',
+ auth_req['username'], auth_req['nonce'], opaque_struct.nonce)
+ return false
+ elsif !check_nonce(req, auth_req)
+ return false
+ end
+ if (@check_nc && auth_req['nc'] != opaque_struct.nc)
+ error('%s: nc unmatched."%s" for "%s"',
+ auth_req['username'], auth_req['nc'], opaque_struct.nc)
+ return false
+ end
+ true
+ end
+
+ def check_uri(req, auth_req)
+ uri = auth_req['uri']
+ if uri != req.request_uri.to_s && uri != req.unparsed_uri &&
+ (@internet_explorer_hack && uri != req.path)
+ error('%s: uri unmatch. "%s" for "%s"', auth_req['username'],
+ auth_req['uri'], req.request_uri.to_s)
+ return false
+ end
+ true
+ end
+
+ def hexdigest(*args)
+ @h.hexdigest(args.join(":"))
+ end
+
+ # :startdoc:
+ end
+
+ ##
+ # Digest authentication for proxy servers. See DigestAuth for details.
+
+ class ProxyDigestAuth < DigestAuth
+ include ProxyAuthenticator
+
+ private
+ def check_uri(req, auth_req) # :nodoc:
+ return true
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htdigest.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htdigest.rb
new file mode 100644
index 0000000..c7e853b
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htdigest.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+#
+# httpauth/htdigest.rb -- Apache compatible htdigest file
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $
+
+require_relative 'userdb'
+require_relative 'digestauth'
+require 'tempfile'
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # Htdigest accesses apache-compatible digest password files. Passwords are
+ # matched to a realm where they are valid. For security, the path for a
+ # digest password database should be stored outside of the paths available
+ # to the HTTP server.
+ #
+ # Htdigest is intended for use with WEBrick::HTTPAuth::DigestAuth and
+ # stores passwords using cryptographic hashes.
+ #
+ # htpasswd = WEBrick::HTTPAuth::Htdigest.new 'my_password_file'
+ # htpasswd.set_passwd 'my realm', 'username', 'password'
+ # htpasswd.flush
+
+ class Htdigest
+ include UserDB
+
+ ##
+ # Open a digest password database at +path+
+
+ def initialize(path)
+ @path = path
+ @mtime = Time.at(0)
+ @digest = Hash.new
+ @mutex = Thread::Mutex::new
+ @auth_type = DigestAuth
+ File.open(@path,"a").close unless File.exist?(@path)
+ reload
+ end
+
+ ##
+ # Reloads passwords from the database
+
+ def reload
+ mtime = File::mtime(@path)
+ if mtime > @mtime
+ @digest.clear
+ File.open(@path){|io|
+ while line = io.gets
+ line.chomp!
+ user, realm, pass = line.split(/:/, 3)
+ unless @digest[realm]
+ @digest[realm] = Hash.new
+ end
+ @digest[realm][user] = pass
+ end
+ }
+ @mtime = mtime
+ end
+ end
+
+ ##
+ # Flush the password database. If +output+ is given the database will
+ # be written there instead of to the original path.
+
+ def flush(output=nil)
+ output ||= @path
+ tmp = Tempfile.create("htpasswd", File::dirname(output))
+ renamed = false
+ begin
+ each{|item| tmp.puts(item.join(":")) }
+ tmp.close
+ File::rename(tmp.path, output)
+ renamed = true
+ ensure
+ tmp.close
+ File.unlink(tmp.path) if !renamed
+ end
+ end
+
+ ##
+ # Retrieves a password from the database for +user+ in +realm+. If
+ # +reload_db+ is true the database will be reloaded first.
+
+ def get_passwd(realm, user, reload_db)
+ reload() if reload_db
+ if hash = @digest[realm]
+ hash[user]
+ end
+ end
+
+ ##
+ # Sets a password in the database for +user+ in +realm+ to +pass+.
+
+ def set_passwd(realm, user, pass)
+ @mutex.synchronize{
+ unless @digest[realm]
+ @digest[realm] = Hash.new
+ end
+ @digest[realm][user] = make_passwd(realm, user, pass)
+ }
+ end
+
+ ##
+ # Removes a password from the database for +user+ in +realm+.
+
+ def delete_passwd(realm, user)
+ if hash = @digest[realm]
+ hash.delete(user)
+ end
+ end
+
+ ##
+ # Iterate passwords in the database.
+
+ def each # :yields: [user, realm, password_hash]
+ @digest.keys.sort.each{|realm|
+ hash = @digest[realm]
+ hash.keys.sort.each{|user|
+ yield([user, realm, hash[user]])
+ }
+ }
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htgroup.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htgroup.rb
new file mode 100644
index 0000000..df19b85
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htgroup.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+#
+# httpauth/htgroup.rb -- Apache compatible htgroup file
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: htgroup.rb,v 1.1 2003/02/16 22:22:56 gotoyuzo Exp $
+
+require 'tempfile'
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # Htgroup accesses apache-compatible group files. Htgroup can be used to
+ # provide group-based authentication for users. Currently Htgroup is not
+ # directly integrated with any authenticators in WEBrick. For security,
+ # the path for a digest password database should be stored outside of the
+ # paths available to the HTTP server.
+ #
+ # Example:
+ #
+ # htgroup = WEBrick::HTTPAuth::Htgroup.new 'my_group_file'
+ # htgroup.add 'superheroes', %w[spiderman batman]
+ #
+ # htgroup.members('superheroes').include? 'magneto' # => false
+
+ class Htgroup
+
+ ##
+ # Open a group database at +path+
+
+ def initialize(path)
+ @path = path
+ @mtime = Time.at(0)
+ @group = Hash.new
+ File.open(@path,"a").close unless File.exist?(@path)
+ reload
+ end
+
+ ##
+ # Reload groups from the database
+
+ def reload
+ if (mtime = File::mtime(@path)) > @mtime
+ @group.clear
+ File.open(@path){|io|
+ while line = io.gets
+ line.chomp!
+ group, members = line.split(/:\s*/, 2)
+ @group[group] = members.split(/\s+/)
+ end
+ }
+ @mtime = mtime
+ end
+ end
+
+ ##
+ # Flush the group database. If +output+ is given the database will be
+ # written there instead of to the original path.
+
+ def flush(output=nil)
+ output ||= @path
+ 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
+ if $!
+ File.unlink(tmp.path)
+ else
+ return File.rename(tmp.path, output)
+ end
+ end
+ end
+
+ ##
+ # Retrieve the list of members from +group+
+
+ def members(group)
+ reload
+ @group[group] || []
+ end
+
+ ##
+ # Add an Array of +members+ to +group+
+
+ def add(group, members)
+ @group[group] = members(group) | members
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htpasswd.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htpasswd.rb
new file mode 100644
index 0000000..db70125
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htpasswd.rb
@@ -0,0 +1,158 @@
+# frozen_string_literal: true
+#
+# httpauth/htpasswd -- Apache compatible htpasswd file
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: htpasswd.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $
+
+require_relative 'userdb'
+require_relative 'basicauth'
+require 'tempfile'
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # Htpasswd accesses apache-compatible password files. Passwords are
+ # matched to a realm where they are valid. For security, the path for a
+ # password database should be stored outside of the paths available to the
+ # HTTP server.
+ #
+ # Htpasswd is intended for use with WEBrick::HTTPAuth::BasicAuth.
+ #
+ # To create an Htpasswd database with a single user:
+ #
+ # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file'
+ # htpasswd.set_passwd 'my realm', 'username', 'password'
+ # htpasswd.flush
+
+ class Htpasswd
+ include UserDB
+
+ ##
+ # Open a password database at +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
+
+ ##
+ # Reload passwords from the database
+
+ def reload
+ mtime = File::mtime(@path)
+ if mtime > @mtime
+ @passwd.clear
+ File.open(@path){|io|
+ while line = io.gets
+ 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(":", 2)
+ 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(":", 2)
+ when /:\$/, /:{SHA}/
+ raise NotImplementedError,
+ 'MD5, SHA1 .htpasswd file not supported'
+ else
+ raise StandardError, 'bad .htpasswd file'
+ end
+ @passwd[user] = pass
+ end
+ }
+ @mtime = mtime
+ end
+ end
+
+ ##
+ # Flush the password database. If +output+ is given the database will
+ # be written there instead of to the original path.
+
+ def flush(output=nil)
+ output ||= @path
+ tmp = Tempfile.create("htpasswd", File::dirname(output))
+ renamed = false
+ begin
+ each{|item| tmp.puts(item.join(":")) }
+ tmp.close
+ File::rename(tmp.path, output)
+ renamed = true
+ ensure
+ tmp.close
+ File.unlink(tmp.path) if !renamed
+ end
+ end
+
+ ##
+ # Retrieves a password from the database for +user+ in +realm+. If
+ # +reload_db+ is true the database will be reloaded first.
+
+ def get_passwd(realm, user, reload_db)
+ reload() if reload_db
+ @passwd[user]
+ end
+
+ ##
+ # Sets a password in the database for +user+ in +realm+ to +pass+.
+
+ def set_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
+
+ ##
+ # Removes a password from the database for +user+ in +realm+.
+
+ def delete_passwd(realm, user)
+ @passwd.delete(user)
+ end
+
+ ##
+ # Iterate passwords in the database.
+
+ def each # :yields: [user, password]
+ @passwd.keys.sort.each{|user|
+ yield([user, @passwd[user]])
+ }
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/userdb.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/userdb.rb
new file mode 100644
index 0000000..0d0f72b
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/userdb.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+#--
+# httpauth/userdb.rb -- UserDB mix-in module.
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: userdb.rb,v 1.2 2003/02/20 07:15:48 gotoyuzo Exp $
+
+module WEBrick
+ module HTTPAuth
+
+ ##
+ # User database mixin for HTTPAuth. This mixin dispatches user record
+ # access to the underlying auth_type for this database.
+
+ module UserDB
+
+ ##
+ # The authentication type.
+ #
+ # WEBrick::HTTPAuth::BasicAuth or WEBrick::HTTPAuth::DigestAuth are
+ # built-in.
+
+ attr_accessor :auth_type
+
+ ##
+ # Creates an obscured password in +realm+ with +user+ and +password+
+ # using the auth_type of this database.
+
+ def make_passwd(realm, user, pass)
+ @auth_type::make_passwd(realm, user, pass)
+ end
+
+ ##
+ # Sets a password in +realm+ with +user+ and +password+ for the
+ # auth_type of this database.
+
+ def set_passwd(realm, user, pass)
+ self[user] = pass
+ end
+
+ ##
+ # Retrieves a password in +realm+ for +user+ for the auth_type of this
+ # database. +reload_db+ is a dummy value.
+
+ def get_passwd(realm, user, reload_db=false)
+ make_passwd(realm, user, self[user])
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpproxy.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpproxy.rb
new file mode 100644
index 0000000..189faa9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpproxy.rb
@@ -0,0 +1,354 @@
+# frozen_string_literal: true
+#
+# httpproxy.rb -- HTTPProxy Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2002 GOTO Kentaro
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $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_relative "httpserver"
+require "net/http"
+
+module WEBrick
+
+ NullReader = Object.new # :nodoc:
+ class << NullReader # :nodoc:
+ def read(*args)
+ nil
+ end
+ alias gets read
+ end
+
+ FakeProxyURI = Object.new # :nodoc:
+ class << FakeProxyURI # :nodoc:
+ def method_missing(meth, *args)
+ if %w(scheme host port path query userinfo).member?(meth.to_s)
+ return nil
+ end
+ super
+ end
+ end
+
+ # :startdoc:
+
+ ##
+ # An HTTP Proxy server which proxies GET, HEAD and POST requests.
+ #
+ # To create a simple proxy server:
+ #
+ # require 'webrick'
+ # require 'webrick/httpproxy'
+ #
+ # proxy = WEBrick::HTTPProxyServer.new Port: 8000
+ #
+ # trap 'INT' do proxy.shutdown end
+ # trap 'TERM' do proxy.shutdown end
+ #
+ # proxy.start
+ #
+ # See ::new for proxy-specific configuration items.
+ #
+ # == Modifying proxied responses
+ #
+ # To modify content the proxy server returns use the +:ProxyContentHandler+
+ # option:
+ #
+ # handler = proc do |req, res|
+ # if res['content-type'] == 'text/plain' then
+ # res.body << "\nThis content was proxied!\n"
+ # end
+ # end
+ #
+ # proxy =
+ # WEBrick::HTTPProxyServer.new Port: 8000, ProxyContentHandler: handler
+
+ class HTTPProxyServer < HTTPServer
+
+ ##
+ # Proxy server configurations. The proxy server handles the following
+ # configuration items in addition to those supported by HTTPServer:
+ #
+ # :ProxyAuthProc:: Called with a request and response to authorize a
+ # request
+ # :ProxyVia:: Appended to the via header
+ # :ProxyURI:: The proxy server's URI
+ # :ProxyContentHandler:: Called with a request and response and allows
+ # modification of the response
+ # :ProxyTimeout:: Sets the proxy timeouts to 30 seconds for open and 60
+ # seconds for read operations
+
+ def initialize(config={}, default=Config::HTTP)
+ super(config, default)
+ c = @config
+ @via = "#{c[:HTTPVersion]} #{c[:ServerName]}:#{c[:Port]}"
+ end
+
+ # :stopdoc:
+ def service(req, res)
+ if req.request_method == "CONNECT"
+ do_CONNECT(req, res)
+ elsif req.unparsed_uri =~ %r!^http://!
+ proxy_service(req, res)
+ else
+ super(req, res)
+ end
+ end
+
+ def proxy_auth(req, res)
+ if proc = @config[:ProxyAuthProc]
+ proc.call(req, res)
+ end
+ req.header.delete("proxy-authorization")
+ end
+
+ def proxy_uri(req, res)
+ # should return upstream proxy server's URI
+ return @config[:ProxyURI]
+ end
+
+ def proxy_service(req, res)
+ # Proxy Authentication
+ proxy_auth(req, res)
+
+ begin
+ public_send("do_#{req.request_method}", req, res)
+ rescue NoMethodError
+ raise HTTPStatus::MethodNotAllowed,
+ "unsupported method '#{req.request_method}'."
+ rescue => err
+ logger.debug("#{err.class}: #{err.message}")
+ raise HTTPStatus::ServiceUnavailable, err.message
+ end
+
+ # Process contents
+ if handler = @config[:ProxyContentHandler]
+ handler.call(req, res)
+ end
+ end
+
+ def do_CONNECT(req, res)
+ # Proxy Authentication
+ proxy_auth(req, res)
+
+ ua = Thread.current[:WEBrickSocket] # User-Agent
+ raise HTTPStatus::InternalServerError,
+ "[BUG] cannot get socket" unless ua
+
+ host, port = req.unparsed_uri.split(":", 2)
+ # Proxy authentication for upstream proxy server
+ if proxy = proxy_uri(req, res)
+ proxy_request_line = "CONNECT #{host}:#{port} HTTP/1.0"
+ if proxy.userinfo
+ credentials = "Basic " + [proxy.userinfo].pack("m0")
+ end
+ host, port = proxy.host, proxy.port
+ end
+
+ begin
+ @logger.debug("CONNECT: upstream proxy is '#{host}:#{port}'.")
+ os = TCPSocket.new(host, port) # origin server
+
+ if proxy
+ @logger.debug("CONNECT: sending a Request-Line")
+ os << proxy_request_line << CRLF
+ @logger.debug("CONNECT: > #{proxy_request_line}")
+ if credentials
+ @logger.debug("CONNECT: sending credentials")
+ os << "Proxy-Authorization: " << credentials << CRLF
+ end
+ os << CRLF
+ proxy_status_line = os.gets(LF)
+ @logger.debug("CONNECT: read Status-Line from the upstream server")
+ @logger.debug("CONNECT: < #{proxy_status_line}")
+ if %r{^HTTP/\d+\.\d+\s+200\s*} =~ proxy_status_line
+ while line = os.gets(LF)
+ break if /\A(#{CRLF}|#{LF})\z/om =~ line
+ end
+ else
+ raise HTTPStatus::BadGateway
+ end
+ end
+ @logger.debug("CONNECT #{host}:#{port}: succeeded")
+ res.status = HTTPStatus::RC_OK
+ rescue => ex
+ @logger.debug("CONNECT #{host}:#{port}: failed '#{ex.message}'")
+ res.set_error(ex)
+ raise HTTPStatus::EOFError
+ ensure
+ if handler = @config[:ProxyContentHandler]
+ handler.call(req, res)
+ end
+ res.send_response(ua)
+ access_log(@config, req, res)
+
+ # Should clear request-line not to send the response twice.
+ # see: HTTPServer#run
+ req.parse(NullReader) rescue nil
+ end
+
+ begin
+ while fds = IO::select([ua, os])
+ if fds[0].member?(ua)
+ buf = ua.readpartial(1024);
+ @logger.debug("CONNECT: #{buf.bytesize} byte from User-Agent")
+ os.write(buf)
+ elsif fds[0].member?(os)
+ buf = os.readpartial(1024);
+ @logger.debug("CONNECT: #{buf.bytesize} byte from #{host}:#{port}")
+ ua.write(buf)
+ end
+ end
+ rescue
+ os.close
+ @logger.debug("CONNECT #{host}:#{port}: closed")
+ end
+
+ raise HTTPStatus::EOFError
+ end
+
+ def do_GET(req, res)
+ perform_proxy_request(req, res, Net::HTTP::Get)
+ end
+
+ def do_HEAD(req, res)
+ perform_proxy_request(req, res, Net::HTTP::Head)
+ end
+
+ def do_POST(req, res)
+ perform_proxy_request(req, res, Net::HTTP::Post, req.body_reader)
+ end
+
+ def do_OPTIONS(req, res)
+ res['allow'] = "GET,HEAD,POST,OPTIONS,CONNECT"
+ end
+
+ private
+
+ # Some header fields should not be transferred.
+ HopByHop = %w( connection keep-alive proxy-authenticate upgrade
+ proxy-authorization te trailers transfer-encoding )
+ ShouldNotTransfer = %w( set-cookie proxy-connection )
+ def split_field(f) f ? f.split(/,\s+/).collect{|i| i.downcase } : [] end
+
+ def choose_header(src, dst)
+ connections = split_field(src['connection'])
+ src.each{|key, value|
+ key = key.downcase
+ if HopByHop.member?(key) || # RFC2616: 13.5.1
+ connections.member?(key) || # RFC2616: 14.10
+ ShouldNotTransfer.member?(key) # pragmatics
+ @logger.debug("choose_header: '#{key}: #{value}'")
+ next
+ end
+ dst[key] = value
+ }
+ end
+
+ # Net::HTTP is stupid about the multiple header fields.
+ # Here is workaround:
+ def set_cookie(src, dst)
+ if str = src['set-cookie']
+ cookies = []
+ str.split(/,\s*/).each{|token|
+ if /^[^=]+;/o =~ token
+ cookies[-1] << ", " << token
+ elsif /=/o =~ token
+ cookies << token
+ else
+ cookies[-1] << ", " << token
+ end
+ }
+ dst.cookies.replace(cookies)
+ end
+ end
+
+ def set_via(h)
+ if @config[:ProxyVia]
+ if h['via']
+ h['via'] << ", " << @via
+ else
+ h['via'] = @via
+ end
+ end
+ end
+
+ def setup_proxy_header(req, res)
+ # Choose header fields to transfer
+ header = Hash.new
+ choose_header(req, header)
+ set_via(header)
+ return header
+ end
+
+ def setup_upstream_proxy_authentication(req, res, header)
+ if upstream = proxy_uri(req, res)
+ if upstream.userinfo
+ header['proxy-authorization'] =
+ "Basic " + [upstream.userinfo].pack("m0")
+ end
+ return upstream
+ end
+ return FakeProxyURI
+ end
+
+ def create_net_http(uri, upstream)
+ Net::HTTP.new(uri.host, uri.port, upstream.host, upstream.port)
+ end
+
+ 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)
+
+ body_tmp = []
+ http = create_net_http(uri, upstream)
+ 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
+ end
+ end
+ # :stopdoc:
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httprequest.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httprequest.rb
new file mode 100644
index 0000000..7f9c002
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httprequest.rb
@@ -0,0 +1,668 @@
+# frozen_string_literal: true
+#
+# httprequest.rb -- HTTPRequest Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httprequest.rb,v 1.64 2003/07/13 17:18:22 gotoyuzo Exp $
+
+require 'fiber'
+require 'uri'
+require_relative 'httpversion'
+require_relative 'httpstatus'
+require_relative 'httputils'
+require_relative 'cookie'
+
+module WEBrick
+
+ ##
+ # An HTTP request. This is consumed by service and do_* methods in
+ # WEBrick servlets
+
+ class HTTPRequest
+
+ BODY_CONTAINABLE_METHODS = [ "POST", "PUT" ] # :nodoc:
+
+ # :section: Request line
+
+ ##
+ # The complete request line such as:
+ #
+ # GET / HTTP/1.1
+
+ attr_reader :request_line
+
+ ##
+ # The request method, GET, POST, PUT, etc.
+
+ attr_reader :request_method
+
+ ##
+ # The unparsed URI of the request
+
+ attr_reader :unparsed_uri
+
+ ##
+ # The HTTP version of the request
+
+ attr_reader :http_version
+
+ # :section: Request-URI
+
+ ##
+ # The parsed URI of the request
+
+ attr_reader :request_uri
+
+ ##
+ # The request path
+
+ attr_reader :path
+
+ ##
+ # The script name (CGI variable)
+
+ attr_accessor :script_name
+
+ ##
+ # The path info (CGI variable)
+
+ attr_accessor :path_info
+
+ ##
+ # The query from the URI of the request
+
+ attr_accessor :query_string
+
+ # :section: Header and entity body
+
+ ##
+ # The raw header of the request
+
+ attr_reader :raw_header
+
+ ##
+ # The parsed header of the request
+
+ attr_reader :header
+
+ ##
+ # The parsed request cookies
+
+ attr_reader :cookies
+
+ ##
+ # The Accept header value
+
+ attr_reader :accept
+
+ ##
+ # The Accept-Charset header value
+
+ attr_reader :accept_charset
+
+ ##
+ # The Accept-Encoding header value
+
+ attr_reader :accept_encoding
+
+ ##
+ # The Accept-Language header value
+
+ attr_reader :accept_language
+
+ # :section:
+
+ ##
+ # The remote user (CGI variable)
+
+ attr_accessor :user
+
+ ##
+ # The socket address of the server
+
+ attr_reader :addr
+
+ ##
+ # The socket address of the client
+
+ attr_reader :peeraddr
+
+ ##
+ # Hash of request attributes
+
+ attr_reader :attributes
+
+ ##
+ # Is this a keep-alive connection?
+
+ attr_reader :keep_alive
+
+ ##
+ # The local time this request was received
+
+ attr_reader :request_time
+
+ ##
+ # Creates a new HTTP request. WEBrick::Config::HTTP is the default
+ # configuration.
+
+ def initialize(config)
+ @config = config
+ @buffer_size = @config[:InputBufferSize]
+ @logger = config[:Logger]
+
+ @request_line = @request_method =
+ @unparsed_uri = @http_version = nil
+
+ @request_uri = @host = @port = @path = nil
+ @script_name = @path_info = nil
+ @query_string = nil
+ @query = nil
+
+ @raw_header = Array.new
+ @header = nil
+ @cookies = []
+ @accept = []
+ @accept_charset = []
+ @accept_encoding = []
+ @accept_language = []
+ @body = +""
+
+ @addr = []
+ @peeraddr = []
+ @attributes = {}
+ @user = nil
+ @keep_alive = false
+ @request_time = nil
+
+ @remaining_size = nil
+ @socket = nil
+
+ @forwarded_proto = @forwarded_host = @forwarded_port =
+ @forwarded_server = @forwarded_for = nil
+ end
+
+ ##
+ # Parses a request from +socket+. This is called internally by
+ # WEBrick::HTTPServer.
+
+ def parse(socket=nil)
+ @socket = socket
+ begin
+ @peeraddr = socket.respond_to?(:peeraddr) ? socket.peeraddr : []
+ @addr = socket.respond_to?(:addr) ? socket.addr : []
+ rescue Errno::ENOTCONN
+ raise HTTPStatus::EOFError
+ end
+
+ read_request_line(socket)
+ if @http_version.major > 0
+ read_header(socket)
+ @header['cookie'].each{|cookie|
+ @cookies += Cookie::parse(cookie)
+ }
+ @accept = HTTPUtils.parse_qvalues(self['accept'])
+ @accept_charset = HTTPUtils.parse_qvalues(self['accept-charset'])
+ @accept_encoding = HTTPUtils.parse_qvalues(self['accept-encoding'])
+ @accept_language = HTTPUtils.parse_qvalues(self['accept-language'])
+ end
+ return if @request_method == "CONNECT"
+ return if @unparsed_uri == "*"
+
+ begin
+ setup_forwarded_info
+ @request_uri = parse_uri(@unparsed_uri)
+ @path = HTTPUtils::unescape(@request_uri.path)
+ @path = HTTPUtils::normalize_path(@path)
+ @host = @request_uri.host
+ @port = @request_uri.port
+ @query_string = @request_uri.query
+ @script_name = ""
+ @path_info = @path.dup
+ rescue
+ raise HTTPStatus::BadRequest, "bad URI '#{@unparsed_uri}'."
+ end
+
+ if /\Aclose\z/io =~ self["connection"]
+ @keep_alive = false
+ elsif /\Akeep-alive\z/io =~ self["connection"]
+ @keep_alive = true
+ elsif @http_version < "1.1"
+ @keep_alive = false
+ else
+ @keep_alive = true
+ end
+ end
+
+ ##
+ # Generate HTTP/1.1 100 continue response if the client expects it,
+ # otherwise does nothing.
+
+ def continue # :nodoc:
+ if self['expect'] == '100-continue' && @config[:HTTPVersion] >= "1.1"
+ @socket << "HTTP/#{@config[:HTTPVersion]} 100 continue#{CRLF}#{CRLF}"
+ @header.delete('expect')
+ end
+ end
+
+ ##
+ # Returns the request body.
+
+ def body(&block) # :yields: body_chunk
+ block ||= Proc.new{|chunk| @body << chunk }
+ read_body(@socket, block)
+ @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.
+ def readpartial(size, buf = ''.b) # :nodoc
+ res = @body_tmp.shift or raise EOFError, 'end of file reached'
+ if res.length > size
+ @body_tmp.unshift(res[size..-1])
+ res = res[0..size - 1]
+ end
+ buf.replace(res)
+ res.clear
+ # get more chunks - check alive? because we can take a partial chunk
+ @body_rd.resume if @body_rd.alive?
+ buf
+ end
+
+ ##
+ # Request query as a Hash
+
+ def query
+ unless @query
+ parse_query()
+ end
+ @query
+ end
+
+ ##
+ # The content-length header
+
+ def content_length
+ return Integer(self['content-length'])
+ end
+
+ ##
+ # The content-type header
+
+ def content_type
+ return self['content-type']
+ end
+
+ ##
+ # Retrieves +header_name+
+
+ def [](header_name)
+ if @header
+ value = @header[header_name.downcase]
+ value.empty? ? nil : value.join
+ end
+ end
+
+ ##
+ # Iterates over the request headers
+
+ def each
+ if @header
+ @header.each{|k, v|
+ value = @header[k]
+ yield(k, value.empty? ? nil : value.join)
+ }
+ end
+ end
+
+ ##
+ # The host this request is for
+
+ def host
+ return @forwarded_host || @host
+ end
+
+ ##
+ # The port this request is for
+
+ def port
+ return @forwarded_port || @port
+ end
+
+ ##
+ # The server name this request is for
+
+ def server_name
+ return @forwarded_server || @config[:ServerName]
+ end
+
+ ##
+ # The client's IP address
+
+ def remote_ip
+ return self["client-ip"] || @forwarded_for || @peeraddr[3]
+ end
+
+ ##
+ # Is this an SSL request?
+
+ def ssl?
+ return @request_uri.scheme == "https"
+ end
+
+ ##
+ # Should the connection this request was made on be kept alive?
+
+ def keep_alive?
+ @keep_alive
+ end
+
+ def to_s # :nodoc:
+ ret = @request_line.dup
+ @raw_header.each{|line| ret << line }
+ ret << CRLF
+ ret << body if body
+ ret
+ end
+
+ ##
+ # Consumes any remaining body and updates keep-alive status
+
+ def fixup() # :nodoc:
+ begin
+ body{|chunk| } # read remaining body
+ rescue HTTPStatus::Error => ex
+ @logger.error("HTTPRequest#fixup: #{ex.class} occurred.")
+ @keep_alive = false
+ rescue => ex
+ @logger.error(ex)
+ @keep_alive = false
+ end
+ end
+
+ # This method provides the metavariables defined by the revision 3
+ # of "The WWW Common Gateway Interface Version 1.1"
+ # To browse the current document of CGI Version 1.1, see below:
+ # https://www.rfc-editor.org/rfc/rfc3875
+
+ def meta_vars
+ meta = Hash.new
+
+ cl = self["Content-Length"]
+ ct = self["Content-Type"]
+ meta["CONTENT_LENGTH"] = cl if cl.to_i > 0
+ meta["CONTENT_TYPE"] = ct.dup if ct
+ meta["GATEWAY_INTERFACE"] = "CGI/1.1"
+ meta["PATH_INFO"] = @path_info ? @path_info.dup : ""
+ #meta["PATH_TRANSLATED"] = nil # no plan to be provided
+ meta["QUERY_STRING"] = @query_string ? @query_string.dup : ""
+ meta["REMOTE_ADDR"] = @peeraddr[3]
+ meta["REMOTE_HOST"] = @peeraddr[2]
+ #meta["REMOTE_IDENT"] = nil # no plan to be provided
+ meta["REMOTE_USER"] = @user
+ meta["REQUEST_METHOD"] = @request_method.dup
+ meta["REQUEST_URI"] = @request_uri.to_s
+ meta["SCRIPT_NAME"] = @script_name.dup
+ meta["SERVER_NAME"] = @host
+ meta["SERVER_PORT"] = @port.to_s
+ meta["SERVER_PROTOCOL"] = "HTTP/" + @config[:HTTPVersion].to_s
+ meta["SERVER_SOFTWARE"] = @config[:ServerSoftware].dup
+
+ self.each{|key, val|
+ next if /^content-type$/i =~ key
+ next if /^content-length$/i =~ key
+ name = "HTTP_" + key
+ name.gsub!(/-/o, "_")
+ name.upcase!
+ meta[name] = val
+ }
+
+ meta
+ end
+
+ private
+
+ # :stopdoc:
+
+ 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
+ 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
+ if /^(\S+) (\S++)(?: HTTP\/(\d+\.\d+))?\r\n/mo =~ @request_line
+ @request_method = $1
+ @unparsed_uri = $2
+ @http_version = HTTPVersion.new($3 ? $3 : "0.9")
+ else
+ rl = @request_line.sub(/\x0d?\x0a\z/o, '')
+ raise HTTPStatus::BadRequest, "bad Request-Line '#{rl}'."
+ end
+ end
+
+ def read_header(socket)
+ if socket
+ end_of_headers = false
+
+ while line = read_line(socket)
+ if line == CRLF
+ end_of_headers = true
+ break
+ end
+ if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH
+ raise HTTPStatus::RequestEntityTooLarge, 'headers too large'
+ end
+ if line.include?("\x00")
+ raise HTTPStatus::BadRequest, 'null byte in header'
+ end
+ @raw_header << line
+ end
+
+ # Allow if @header already set to support chunked trailers
+ raise HTTPStatus::EOFError unless end_of_headers || @header
+ end
+ @header = HTTPUtils::parse_header(@raw_header.join)
+
+ if (content_length = @header['content-length']) && content_length.length != 0
+ if content_length.length > 1
+ raise HTTPStatus::BadRequest, "multiple content-length request headers"
+ elsif !/\A\d+\z/.match?(content_length[0])
+ raise HTTPStatus::BadRequest, "invalid content-length request header"
+ end
+ end
+ end
+
+ def parse_uri(str, scheme="http")
+ if @config[:Escape8bitURI]
+ str = HTTPUtils::escape8bit(str)
+ end
+ str.sub!(%r{\A/+}o, '/')
+ uri = URI::parse(str)
+ return uri if uri.absolute?
+ if @forwarded_host
+ host, port = @forwarded_host, @forwarded_port
+ elsif self["host"]
+ host, port = parse_host_request_line(self["host"])
+ elsif @addr.size > 0
+ host, port = @addr[2], @addr[1]
+ else
+ host, port = @config[:ServerName], @config[:Port]
+ end
+ uri.scheme = @forwarded_proto || scheme
+ uri.host = host
+ uri.port = port ? port.to_i : nil
+ return URI::parse(uri.to_s)
+ end
+
+ host_pattern = URI::RFC2396_Parser.new.pattern.fetch(:HOST)
+ HOST_PATTERN = /\A(#{host_pattern})(?::(\d+))?\z/n
+ def parse_host_request_line(host)
+ host.scan(HOST_PATTERN)[0]
+ end
+
+ def read_body(socket, block)
+ return unless socket
+ if tc = self['transfer-encoding']
+ if self['content-length']
+ raise HTTPStatus::BadRequest, "request with both transfer-encoding and content-length, possible request smuggling"
+ end
+
+ case tc
+ when /\Achunked\z/io then read_chunked(socket, block)
+ else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}."
+ end
+ elsif self['content-length'] || @remaining_size
+ @remaining_size ||= self['content-length'].to_i
+ while @remaining_size > 0
+ sz = [@buffer_size, @remaining_size].min
+ break unless buf = read_data(socket, sz)
+ @remaining_size -= buf.bytesize
+ block.call(buf)
+ end
+ if @remaining_size > 0 && @socket.eof?
+ raise HTTPStatus::BadRequest, "invalid body size."
+ end
+ elsif BODY_CONTAINABLE_METHODS.member?(@request_method)
+ raise HTTPStatus::LengthRequired
+ end
+ return @body
+ end
+
+ def read_chunk_size(socket)
+ line = read_line(socket)
+ if /\A([0-9a-fA-F]+)(?:;(\S+(?:=\S+)?))?\r\n\z/ =~ line
+ chunk_size = $1.hex
+ chunk_ext = $2
+ [ chunk_size, chunk_ext ]
+ else
+ raise HTTPStatus::BadRequest, "bad chunk '#{line}'."
+ end
+ end
+
+ def read_chunked(socket, block)
+ chunk_size, = read_chunk_size(socket)
+ while chunk_size > 0
+ 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
+
+ line = read_line(socket) # skip CRLF
+ unless line == "\r\n"
+ raise HTTPStatus::BadRequest, "extra data after chunk '#{line}'."
+ end
+
+ chunk_size, = read_chunk_size(socket)
+ end
+ read_header(socket) # trailer + CRLF
+ @header.delete("transfer-encoding")
+ @remaining_size = 0
+ end
+
+ def _read_data(io, method, *arg)
+ begin
+ WEBrick::Utils.timeout(@config[:RequestTimeout]){
+ return io.__send__(method, *arg)
+ }
+ rescue Errno::ECONNRESET
+ return nil
+ rescue Timeout::Error
+ raise HTTPStatus::RequestTimeout
+ end
+ end
+
+ def read_line(io, size=4096)
+ _read_data(io, :gets, LF, size)
+ end
+
+ def read_data(io, size)
+ _read_data(io, :read, size)
+ end
+
+ def parse_query()
+ begin
+ if @request_method == "GET" || @request_method == "HEAD"
+ @query = HTTPUtils::parse_query(@query_string)
+ elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/
+ @query = HTTPUtils::parse_query(body)
+ elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/
+ boundary = HTTPUtils::dequote($1)
+ @query = HTTPUtils::parse_form_data(body, boundary)
+ else
+ @query = Hash.new
+ end
+ rescue => ex
+ raise HTTPStatus::BadRequest, ex.message
+ end
+ end
+
+ PrivateNetworkRegexp = /
+ ^unknown$|
+ ^((::ffff:)?127.0.0.1|::1)$|
+ ^(::ffff:)?(10|172\.(1[6-9]|2[0-9]|3[01])|192\.168)\.
+ /ixo
+
+ # It's said that all X-Forwarded-* headers will contain more than one
+ # (comma-separated) value if the original request already contained one of
+ # these headers. Since we could use these values as Host header, we choose
+ # the initial(first) value. (apr_table_mergen() adds new value after the
+ # existing value with ", " prefix)
+ def setup_forwarded_info
+ if @forwarded_server = self["x-forwarded-server"]
+ @forwarded_server = @forwarded_server.split(",", 2).first
+ end
+ if @forwarded_proto = self["x-forwarded-proto"]
+ @forwarded_proto = @forwarded_proto.split(",", 2).first
+ end
+ if host_port = self["x-forwarded-host"]
+ host_port = host_port.split(",", 2).first
+ if host_port =~ /\A(\[[0-9a-fA-F:]+\])(?::(\d+))?\z/
+ @forwarded_host = $1
+ tmp = $2
+ else
+ @forwarded_host, tmp = host_port.split(":", 2)
+ end
+ @forwarded_port = (tmp || (@forwarded_proto == "https" ? 443 : 80)).to_i
+ end
+ if addrs = self["x-forwarded-for"]
+ addrs = addrs.split(",").collect(&:strip)
+ addrs.reject!{|ip| PrivateNetworkRegexp =~ ip }
+ @forwarded_for = addrs.first
+ end
+ end
+
+ # :startdoc:
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpresponse.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpresponse.rb
new file mode 100644
index 0000000..4ad9cc2
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpresponse.rb
@@ -0,0 +1,588 @@
+# frozen_string_literal: true
+#
+# httpresponse.rb -- HTTPResponse Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
+
+require 'time'
+require 'uri'
+require_relative 'httpversion'
+require_relative 'htmlutils'
+require_relative 'httputils'
+require_relative 'httpstatus'
+
+module WEBrick
+ ##
+ # An HTTP response. This is filled in by the service or do_* methods of a
+ # WEBrick HTTP Servlet.
+
+ class HTTPResponse
+ class InvalidHeader < StandardError
+ end
+
+ ##
+ # HTTP Response version
+
+ attr_reader :http_version
+
+ ##
+ # Response status code (200)
+
+ attr_reader :status
+
+ ##
+ # Response header
+
+ attr_reader :header
+
+ ##
+ # Response cookies
+
+ attr_reader :cookies
+
+ ##
+ # Response reason phrase ("OK")
+
+ attr_accessor :reason_phrase
+
+ ##
+ # Body may be:
+ # * a String;
+ # * an IO-like object that responds to +#read+ and +#readpartial+;
+ # * a Proc-like object that responds to +#call+.
+ #
+ # In the latter case, either #chunked= should be set to +true+,
+ # or <code>header['content-length']</code> explicitly provided.
+ # Example:
+ #
+ # server.mount_proc '/' do |req, res|
+ # res.chunked = true
+ # # or
+ # # res.header['content-length'] = 10
+ # res.body = proc { |out| out.write(Time.now.to_s) }
+ # end
+
+ attr_accessor :body
+
+ ##
+ # Request method for this response
+
+ attr_accessor :request_method
+
+ ##
+ # Request URI for this response
+
+ attr_accessor :request_uri
+
+ ##
+ # Request HTTP version for this response
+
+ attr_accessor :request_http_version
+
+ ##
+ # Filename of the static file in this response. Only used by the
+ # FileHandler servlet.
+
+ attr_accessor :filename
+
+ ##
+ # Is this a keep-alive response?
+
+ attr_accessor :keep_alive
+
+ ##
+ # Configuration for this response
+
+ attr_reader :config
+
+ ##
+ # Bytes sent in this response
+
+ attr_reader :sent_size
+
+ ##
+ # Set the response body proc as an streaming/upgrade response.
+
+ attr_accessor :upgrade
+
+ ##
+ # Creates a new HTTP response object. WEBrick::Config::HTTP is the
+ # default configuration.
+
+ def initialize(config)
+ @config = config
+ @buffer_size = config[:OutputBufferSize]
+ @logger = config[:Logger]
+ @header = Hash.new
+ @status = HTTPStatus::RC_OK
+ @reason_phrase = nil
+ @http_version = HTTPVersion::convert(@config[:HTTPVersion])
+ @body = +""
+ @keep_alive = true
+ @cookies = []
+ @request_method = nil
+ @request_uri = nil
+ @request_http_version = @http_version # temporary
+ @chunked = false
+ @filename = nil
+ @sent_size = 0
+ @bodytempfile = nil
+ end
+
+ ##
+ # The response's HTTP status line
+
+ def status_line
+ "HTTP/#@http_version #@status #@reason_phrase".rstrip << CRLF
+ end
+
+ ##
+ # Sets the response's status to the +status+ code
+
+ def status=(status)
+ @status = status
+ @reason_phrase = HTTPStatus::reason_phrase(status)
+ end
+
+ ##
+ # Retrieves the response header +field+
+
+ def [](field)
+ @header[field.downcase]
+ end
+
+ ##
+ # Sets the response header +field+ to +value+
+
+ def []=(field, value)
+ @chunked = value.to_s.downcase == 'chunked' if field.downcase == 'transfer-encoding'
+ @header[field.downcase] = value.to_s
+ end
+
+ ##
+ # The content-length header
+
+ def content_length
+ if len = self['content-length']
+ return Integer(len)
+ end
+ end
+
+ ##
+ # Sets the content-length header to +len+
+
+ def content_length=(len)
+ self['content-length'] = len.to_s
+ end
+
+ ##
+ # The content-type header
+
+ def content_type
+ self['content-type']
+ end
+
+ ##
+ # Sets the content-type header to +type+
+
+ def content_type=(type)
+ self['content-type'] = type
+ end
+
+ ##
+ # Iterates over each header in the response
+
+ def each
+ @header.each{|field, value| yield(field, value) }
+ end
+
+ ##
+ # Will this response body be returned using chunked transfer-encoding?
+
+ def chunked?
+ @chunked
+ end
+
+ ##
+ # Enables chunked transfer encoding.
+
+ def chunked=(val)
+ @chunked = val ? true : false
+ end
+
+ ##
+ # Will this response's connection be kept alive?
+
+ def keep_alive?
+ @keep_alive
+ end
+
+ ##
+ # Sets the response to be a streaming/upgrade response.
+ # This will disable keep-alive and chunked transfer encoding.
+
+ def upgrade!(protocol)
+ @upgrade = protocol
+ @keep_alive = false
+ @chunked = false
+ end
+
+ ##
+ # Sends the response on +socket+
+
+ def send_response(socket) # :nodoc:
+ begin
+ setup_header()
+ send_header(socket)
+ send_body(socket)
+ rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex
+ @logger.debug(ex)
+ @keep_alive = false
+ rescue Exception => ex
+ @logger.error(ex)
+ @keep_alive = false
+ end
+ end
+
+ ##
+ # Sets up the headers for sending
+
+ def setup_header() # :nodoc:
+ @reason_phrase ||= HTTPStatus::reason_phrase(@status)
+ @header['server'] ||= @config[:ServerSoftware]
+ @header['date'] ||= Time.now.httpdate
+
+ if @upgrade
+ @header['connection'] = 'upgrade'
+ @header['upgrade'] = @upgrade
+ @keep_alive = false
+
+ return
+ end
+
+ # HTTP/0.9 features
+ if @request_http_version < "1.0"
+ @http_version = HTTPVersion.new("0.9")
+ @keep_alive = false
+ end
+
+ # HTTP/1.0 features
+ if @request_http_version < "1.1"
+ if chunked?
+ @chunked = false
+ ver = @request_http_version.to_s
+ msg = "chunked is set for an HTTP/#{ver} request. (ignored)"
+ @logger.warn(msg)
+ end
+ end
+
+ # Determine the message length (RFC2616 -- 4.4 Message Length)
+ if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
+ @header.delete('content-length')
+ @body = ""
+ elsif chunked?
+ @header["transfer-encoding"] = "chunked"
+ @header.delete('content-length')
+ elsif %r{^multipart/byteranges} =~ @header['content-type']
+ @header.delete('content-length')
+ elsif @header['content-length'].nil?
+ if @body.respond_to?(:bytesize)
+ @header['content-length'] = @body.bytesize.to_s
+ else
+ @header['connection'] = 'close'
+ end
+ end
+
+ # Keep-Alive connection.
+ if @header['connection'] == "close"
+ @keep_alive = false
+ elsif keep_alive?
+ if chunked? || @header['content-length'] || @status == 304 || @status == 204 || HTTPStatus.info?(@status)
+ @header['connection'] = "Keep-Alive"
+ else
+ msg = "Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true"
+ @logger.warn(msg)
+ @header['connection'] = "close"
+ @keep_alive = false
+ end
+ else
+ @header['connection'] = "close"
+ end
+
+ # Location is a single absoluteURI.
+ if location = @header['location']
+ if @request_uri
+ @header['location'] = @request_uri.merge(location).to_s
+ end
+ end
+ end
+
+ def make_body_tempfile # :nodoc:
+ return if @bodytempfile
+ bodytempfile = Tempfile.create("webrick")
+ if @body.nil?
+ # nothing
+ elsif @body.respond_to? :readpartial
+ IO.copy_stream(@body, bodytempfile)
+ @body.close
+ elsif @body.respond_to? :call
+ @body.call(bodytempfile)
+ else
+ bodytempfile.write @body
+ end
+ bodytempfile.rewind
+ @body = @bodytempfile = bodytempfile
+ @header['content-length'] = bodytempfile.stat.size.to_s
+ end
+
+ def remove_body_tempfile # :nodoc:
+ if @bodytempfile
+ @bodytempfile.close
+ File.unlink @bodytempfile.path
+ @bodytempfile = nil
+ end
+ end
+
+
+ ##
+ # Sends the headers on +socket+
+
+ def send_header(socket) # :nodoc:
+ if @http_version.major > 0
+ data = status_line().dup
+ @header.each{|key, value|
+ tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
+ data << "#{tmp}: #{check_header(value)}" << CRLF
+ }
+ @cookies.each{|cookie|
+ data << "Set-Cookie: " << check_header(cookie.to_s) << CRLF
+ }
+ data << CRLF
+ socket.write(data)
+ end
+ rescue InvalidHeader => e
+ @header.clear
+ @cookies.clear
+ set_error e
+ retry
+ end
+
+ ##
+ # Sends the body on +socket+
+
+ def send_body(socket) # :nodoc:
+ if @body.respond_to? :readpartial then
+ send_body_io(socket)
+ elsif @body.respond_to?(:call) then
+ send_body_proc(socket)
+ else
+ send_body_string(socket)
+ end
+ end
+
+ ##
+ # Redirects to +url+ with a WEBrick::HTTPStatus::Redirect +status+.
+ #
+ # Example:
+ #
+ # 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
+ raise status
+ end
+
+ ##
+ # Creates an error page for exception +ex+ with an optional +backtrace+
+
+ def set_error(ex, backtrace=false)
+ case ex
+ when HTTPStatus::Status
+ @keep_alive = false if HTTPStatus::error?(ex.code)
+ self.status = ex.code
+ else
+ @keep_alive = false
+ self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
+ end
+ @header['content-type'] = "text/html; charset=ISO-8859-1"
+
+ if respond_to?(:create_error_page)
+ create_error_page()
+ return
+ end
+
+ if @request_uri
+ host, port = @request_uri.host, @request_uri.port
+ else
+ host, port = @config[:ServerName], @config[:Port]
+ end
+
+ error_body(backtrace, ex, host, port)
+ end
+
+ 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)
+ @body = +""
+ @body << <<-_end_of_html_
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+ <HEAD><TITLE>#{HTMLUtils::escape(@reason_phrase)}</TITLE></HEAD>
+ <BODY>
+ <H1>#{HTMLUtils::escape(@reason_phrase)}</H1>
+ #{HTMLUtils::escape(ex.message)}
+ <HR>
+ _end_of_html_
+
+ if backtrace && $DEBUG
+ @body << "backtrace of '#{HTMLUtils::escape(ex.class.to_s)}' "
+ @body << "#{HTMLUtils::escape(ex.message)}"
+ @body << "<PRE>"
+ ex.backtrace.each{|line| @body << "\t#{line}\n"}
+ @body << "</PRE><HR>"
+ end
+
+ @body << <<-_end_of_html_
+ <ADDRESS>
+ #{HTMLUtils::escape(@config[:ServerSoftware])} at
+ #{host}:#{port}
+ </ADDRESS>
+ </BODY>
+</HTML>
+ _end_of_html_
+ end
+
+ def send_body_io(socket)
+ begin
+ if @request_method == "HEAD"
+ # do nothing
+ elsif chunked?
+ buf = +''
+ begin
+ @body.readpartial(@buffer_size, buf)
+ size = buf.bytesize
+ data = +"#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
+ socket.write(data)
+ data.clear
+ @sent_size += size
+ rescue EOFError
+ break
+ end while true
+ buf.clear
+ socket.write("0#{CRLF}#{CRLF}")
+ else
+ 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
+ end
+ remove_body_tempfile
+ end
+
+ def send_body_string(socket)
+ if @request_method == "HEAD"
+ # do nothing
+ elsif chunked?
+ body ? @body.bytesize : 0
+ while buf = @body[@sent_size, @buffer_size]
+ break if buf.empty?
+ size = buf.bytesize
+ data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
+ buf.clear
+ socket.write(data)
+ @sent_size += size
+ end
+ socket.write("0#{CRLF}#{CRLF}")
+ else
+ if @body && @body.bytesize > 0
+ socket.write(@body)
+ @sent_size = @body.bytesize
+ end
+ end
+ end
+
+ def send_body_proc(socket)
+ if @request_method == "HEAD"
+ # do nothing
+ elsif chunked?
+ @body.call(ChunkedWrapper.new(socket, self))
+ socket.write("0#{CRLF}#{CRLF}")
+ else
+ if @bodytempfile
+ @bodytempfile.rewind
+ IO.copy_stream(@bodytempfile, socket)
+ else
+ @body.call(socket)
+ end
+
+ if content_length = @header['content-length']
+ @sent_size = content_length.to_i
+ end
+ end
+ end
+
+ class ChunkedWrapper
+ def initialize(socket, resp)
+ @socket = socket
+ @resp = resp
+ end
+
+ def write(buf)
+ return 0 if buf.empty?
+ socket = @socket
+ @resp.instance_eval {
+ size = buf.bytesize
+ data = +"#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
+ socket.write(data)
+ data.clear
+ @sent_size += size
+ size
+ }
+ end
+
+ def <<(*buf)
+ write(buf)
+ self
+ end
+ end
+
+ # preserved for compatibility with some 3rd-party handlers
+ def _write_data(socket, data)
+ socket << data
+ end
+
+ # :startdoc:
+ end
+
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/https.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/https.rb
new file mode 100644
index 0000000..7f00b30
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/https.rb
@@ -0,0 +1,152 @@
+# frozen_string_literal: true
+#
+# https.rb -- SSL/TLS enhancement for HTTPServer
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
+
+require_relative 'ssl'
+require_relative 'httpserver'
+
+module WEBrick
+ module Config
+ HTTP.update(SSL)
+ end
+
+ ##
+ #--
+ # Adds SSL functionality to WEBrick::HTTPRequest
+
+ class HTTPRequest
+
+ ##
+ # HTTP request SSL cipher
+
+ attr_reader :cipher
+
+ ##
+ # HTTP request server certificate
+
+ attr_reader :server_cert
+
+ ##
+ # HTTP request client certificate
+
+ attr_reader :client_cert
+
+ # :stopdoc:
+
+ alias orig_parse parse
+
+ def parse(socket=nil)
+ if socket.respond_to?(:cert)
+ @server_cert = socket.cert || @config[:SSLCertificate]
+ @client_cert = socket.peer_cert
+ @client_cert_chain = socket.peer_cert_chain
+ @cipher = socket.cipher
+ end
+ orig_parse(socket)
+ end
+
+ alias orig_parse_uri parse_uri
+
+ def parse_uri(str, scheme="https")
+ if server_cert
+ return orig_parse_uri(str, scheme)
+ end
+ return orig_parse_uri(str)
+ end
+ private :parse_uri
+
+ alias orig_meta_vars meta_vars
+
+ def meta_vars
+ meta = orig_meta_vars
+ if server_cert
+ meta["HTTPS"] = "on"
+ meta["SSL_SERVER_CERT"] = @server_cert.to_pem
+ meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
+ if @client_cert_chain
+ @client_cert_chain.each_with_index{|cert, i|
+ meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
+ }
+ end
+ meta["SSL_CIPHER"] = @cipher[0]
+ meta["SSL_PROTOCOL"] = @cipher[1]
+ meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s
+ meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s
+ end
+ meta
+ end
+
+ # :startdoc:
+ end
+
+ ##
+ #--
+ # Fake WEBrick::HTTPRequest for lookup_server
+
+ class SNIRequest
+
+ ##
+ # The SNI hostname
+
+ attr_reader :host
+
+ ##
+ # The socket address of the server
+
+ attr_reader :addr
+
+ ##
+ # The port this request is for
+
+ attr_reader :port
+
+ ##
+ # Creates a new SNIRequest.
+
+ def initialize(sslsocket, hostname)
+ @host = hostname
+ @addr = sslsocket.addr
+ @port = @addr[1]
+ end
+ end
+
+
+ ##
+ #--
+ # Adds SSL functionality to WEBrick::HTTPServer
+
+ class HTTPServer < ::WEBrick::GenericServer
+ ##
+ # ServerNameIndication callback
+
+ def ssl_servername_callback(sslsocket, hostname = nil)
+ req = SNIRequest.new(sslsocket, hostname)
+ server = lookup_server(req)
+ server ? server.ssl_context : nil
+ end
+
+ # :stopdoc:
+
+ ##
+ # Check whether +server+ is also SSL server.
+ # Also +server+'s SSL context will be created.
+
+ alias orig_virtual_host virtual_host
+
+ def virtual_host(server)
+ if @config[:SSLEnable] && !server.ssl_context
+ raise ArgumentError, "virtual host must set SSLEnable to true"
+ end
+ orig_virtual_host(server)
+ end
+
+ # :startdoc:
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpserver.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpserver.rb
new file mode 100644
index 0000000..6d9dc26
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpserver.rb
@@ -0,0 +1,294 @@
+# frozen_string_literal: true
+#
+# httpserver.rb -- HTTPServer Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $
+
+require 'io/wait'
+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
+
+ ##
+ # An HTTP Server
+
+ class HTTPServer < ::WEBrick::GenericServer
+ ##
+ # Creates a new HTTP server according to +config+
+ #
+ # An HTTP server uses the following attributes:
+ #
+ # :AccessLog:: An array of access logs. See WEBrick::AccessLog
+ # :BindAddress:: Local address for the server to bind to
+ # :DocumentRoot:: Root path to serve files from
+ # :DocumentRootOptions:: Options for the default HTTPServlet::FileHandler
+ # :HTTPVersion:: The HTTP version of this server
+ # :Port:: Port to listen on
+ # :RequestCallback:: Called with a request and response before each
+ # request is serviced.
+ # :RequestTimeout:: Maximum time to wait between requests
+ # :ServerAlias:: Array of alternate names for this server for virtual
+ # hosting
+ # :ServerName:: Name for this server for virtual hosting
+
+ def initialize(config={}, default=Config::HTTP)
+ super(config, default)
+ @http_version = HTTPVersion::convert(@config[:HTTPVersion])
+
+ @mount_tab = MountTable.new
+ if @config[:DocumentRoot]
+ mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot],
+ @config[:DocumentRootOptions])
+ end
+
+ unless @config[:AccessLog]
+ @config[:AccessLog] = [
+ [ $stderr, AccessLog::COMMON_LOG_FORMAT ],
+ [ $stderr, AccessLog::REFERER_LOG_FORMAT ]
+ ]
+ end
+
+ @virtual_hosts = Array.new
+ end
+
+ ##
+ # Processes requests on +sock+
+
+ def run(sock)
+ while true
+ req = create_request(@config)
+ res = create_response(@config)
+ server = self
+ begin
+ timeout = @config[:RequestTimeout]
+ while timeout > 0
+ break if sock.to_io.wait_readable(0.5)
+ break if @status != :Running
+ timeout -= 0.5
+ end
+ raise HTTPStatus::EOFError if timeout <= 0 || @status != :Running
+ raise HTTPStatus::EOFError if sock.eof?
+ req.parse(sock)
+ res.request_method = req.request_method
+ res.request_uri = req.request_uri
+ res.request_http_version = req.http_version
+ res.keep_alive = req.keep_alive?
+ server = lookup_server(req) || self
+ if callback = server[:RequestCallback]
+ callback.call(req, res)
+ elsif callback = server[:RequestHandler]
+ msg = ":RequestHandler is deprecated, please use :RequestCallback"
+ @logger.warn(msg)
+ callback.call(req, res)
+ end
+ server.service(req, res)
+ rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
+ res.set_error(ex)
+ rescue HTTPStatus::Error => ex
+ @logger.error(ex.message)
+ res.set_error(ex)
+ rescue HTTPStatus::Status => ex
+ res.status = ex.code
+ rescue StandardError => ex
+ @logger.error(ex)
+ res.set_error(ex, true)
+ ensure
+ if req.request_line
+ if req.keep_alive? && res.keep_alive?
+ req.fixup()
+ end
+ res.send_response(sock)
+ server.access_log(@config, req, res)
+ end
+ end
+ break if @http_version < "1.1"
+ break unless req.keep_alive?
+ break unless res.keep_alive?
+ end
+ end
+
+ ##
+ # Services +req+ and fills in +res+
+
+ def service(req, res)
+ if req.unparsed_uri == "*"
+ if req.request_method == "OPTIONS"
+ do_OPTIONS(req, res)
+ raise HTTPStatus::OK
+ end
+ raise HTTPStatus::NotFound, "'#{req.unparsed_uri}' not found."
+ end
+
+ servlet, options, script_name, path_info = search_servlet(req.path)
+ raise HTTPStatus::NotFound, "'#{req.path}' not found." unless servlet
+ req.script_name = script_name
+ req.path_info = path_info
+ si = servlet.get_instance(self, *options)
+ @logger.debug(format("%s is invoked.", si.class.name))
+ si.service(req, res)
+ end
+
+ ##
+ # The default OPTIONS request handler says GET, HEAD, POST and OPTIONS
+ # requests are allowed.
+
+ def do_OPTIONS(req, res)
+ res["allow"] = "GET,HEAD,POST,OPTIONS"
+ end
+
+ ##
+ # Mounts +servlet+ on +dir+ passing +options+ to the servlet at creation
+ # time
+
+ def mount(dir, servlet, *options)
+ @logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir))
+ @mount_tab[dir] = [ servlet, options ]
+ end
+
+ ##
+ # Mounts +proc+ or +block+ on +dir+ and calls it with a
+ # WEBrick::HTTPRequest and WEBrick::HTTPResponse
+
+ def mount_proc(dir, proc=nil, &block)
+ proc ||= block
+ raise HTTPServerError, "must pass a proc or block" unless proc
+ mount(dir, HTTPServlet::ProcHandler.new(proc))
+ end
+
+ ##
+ # Unmounts +dir+
+
+ def unmount(dir)
+ @logger.debug(sprintf("unmount %s.", dir))
+ @mount_tab.delete(dir)
+ end
+ alias umount unmount
+
+ ##
+ # Finds a servlet for +path+
+
+ def search_servlet(path)
+ script_name, path_info = @mount_tab.scan(path)
+ servlet, options = @mount_tab[script_name]
+ if servlet
+ [ servlet, options, script_name, path_info ]
+ end
+ end
+
+ ##
+ # Adds +server+ as a virtual host.
+
+ def virtual_host(server)
+ @virtual_hosts << server
+ @virtual_hosts = @virtual_hosts.sort_by{|s|
+ num = 0
+ num -= 4 if s[:BindAddress]
+ num -= 2 if s[:Port]
+ num -= 1 if s[:ServerName]
+ num
+ }
+ end
+
+ ##
+ # Finds the appropriate virtual host to handle +req+
+
+ def lookup_server(req)
+ @virtual_hosts.find{|s|
+ (s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) &&
+ (s[:Port].nil? || req.port == s[:Port]) &&
+ ((s[:ServerName].nil? || req.host == s[:ServerName]) ||
+ (!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host}))
+ }
+ end
+
+ ##
+ # Logs +req+ and +res+ in the access logs. +config+ is used for the
+ # server name.
+
+ def access_log(config, req, res)
+ param = AccessLog::setup_params(config, req, res)
+ @config[:AccessLog].each{|logger, fmt|
+ logger << AccessLog::format(fmt+"\n", param)
+ }
+ 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
+ # WEBrick::HTTPServer#mount, WEBrick::HTTPServer#unmount and
+ # WEBrick::HTTPServer#search_servlet
+
+ class MountTable # :nodoc:
+ def initialize
+ @tab = Hash.new
+ compile
+ end
+
+ def [](dir)
+ dir = normalize(dir)
+ @tab[dir]
+ end
+
+ def []=(dir, val)
+ dir = normalize(dir)
+ @tab[dir] = val
+ compile
+ val
+ end
+
+ def delete(dir)
+ dir = normalize(dir)
+ res = @tab.delete(dir)
+ compile
+ res
+ end
+
+ def scan(path)
+ @scanner =~ path
+ [ $&, $' ]
+ end
+
+ private
+
+ def compile
+ k = @tab.keys
+ k.sort!
+ k.reverse!
+ k.collect!{|path| Regexp.escape(path) }
+ @scanner = Regexp.new("\\A(" + k.join("|") +")(?=/|\\z)")
+ end
+
+ def normalize(dir)
+ ret = dir ? dir.dup : +""
+ ret.sub!(%r|/+\z|, "")
+ ret
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet.rb
new file mode 100644
index 0000000..4cb1822
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+#
+# httpservlet.rb -- HTTPServlet Utility File
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $
+
+require_relative 'httpservlet/abstract'
+require_relative 'httpservlet/filehandler'
+require_relative 'httpservlet/cgihandler'
+require_relative 'httpservlet/erbhandler'
+require_relative 'httpservlet/prochandler'
+
+module WEBrick
+ module HTTPServlet
+ FileHandler.add_handler("cgi", CGIHandler)
+ FileHandler.add_handler("rhtml", ERBHandler)
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/abstract.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/abstract.rb
new file mode 100644
index 0000000..280a4d3
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/abstract.rb
@@ -0,0 +1,152 @@
+# frozen_string_literal: true
+#
+# httpservlet.rb -- HTTPServlet Module
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $
+
+require_relative '../htmlutils'
+require_relative '../httputils'
+require_relative '../httpstatus'
+
+module WEBrick
+ module HTTPServlet
+ class HTTPServletError < StandardError; end
+
+ ##
+ # AbstractServlet allows HTTP server modules to be reused across multiple
+ # servers and allows encapsulation of functionality.
+ #
+ # By default a servlet will respond to GET, HEAD (through an alias to GET)
+ # and OPTIONS requests.
+ #
+ # By default a new servlet is initialized for every request. A servlet
+ # instance can be reused by overriding ::get_instance in the
+ # AbstractServlet subclass.
+ #
+ # == A Simple Servlet
+ #
+ # class Simple < WEBrick::HTTPServlet::AbstractServlet
+ # def do_GET request, response
+ # status, content_type, body = do_stuff_with request
+ #
+ # response.status = status
+ # response['Content-Type'] = content_type
+ # response.body = body
+ # end
+ #
+ # def do_stuff_with request
+ # return 200, 'text/plain', 'you got a page'
+ # end
+ # end
+ #
+ # This servlet can be mounted on a server at a given path:
+ #
+ # server.mount '/simple', Simple
+ #
+ # == Servlet Configuration
+ #
+ # Servlets can be configured via initialize. The first argument is the
+ # HTTP server the servlet is being initialized for.
+ #
+ # class Configurable < Simple
+ # def initialize server, color, size
+ # super server
+ # @color = color
+ # @size = size
+ # end
+ #
+ # def do_stuff_with request
+ # content = "<p " \
+ # %q{style="color: #{@color}; font-size: #{@size}"} \
+ # ">Hello, World!"
+ #
+ # return 200, "text/html", content
+ # end
+ # end
+ #
+ # This servlet must be provided two arguments at mount time:
+ #
+ # server.mount '/configurable', Configurable, 'red', '2em'
+
+ class AbstractServlet
+
+ ##
+ # Factory for servlet instances that will handle a request from +server+
+ # using +options+ from the mount point. By default a new servlet
+ # instance is created for every call.
+
+ def self.get_instance(server, *options)
+ self.new(server, *options)
+ end
+
+ ##
+ # Initializes a new servlet for +server+ using +options+ which are
+ # stored as-is in +@options+. +@logger+ is also provided.
+
+ def initialize(server, *options)
+ @server = @config = server
+ @logger = @server[:Logger]
+ @options = options
+ end
+
+ ##
+ # Dispatches to a +do_+ method based on +req+ if such a method is
+ # available. (+do_GET+ for a GET request). Raises a MethodNotAllowed
+ # exception if the method is not implemented.
+
+ def service(req, res)
+ method_name = "do_" + req.request_method.gsub(/-/, "_")
+ if respond_to?(method_name)
+ __send__(method_name, req, res)
+ else
+ raise HTTPStatus::MethodNotAllowed,
+ "unsupported method '#{req.request_method}'."
+ end
+ end
+
+ ##
+ # Raises a NotFound exception
+
+ def do_GET(req, res)
+ raise HTTPStatus::NotFound, "not found."
+ end
+
+ ##
+ # Dispatches to do_GET
+
+ def do_HEAD(req, res)
+ do_GET(req, res)
+ end
+
+ ##
+ # Returns the allowed HTTP request methods
+
+ def do_OPTIONS(req, res)
+ m = self.methods.grep(/\Ado_([A-Z]+)\z/) {$1}
+ m.sort!
+ res["allow"] = m.join(",")
+ end
+
+ private
+
+ ##
+ # Redirects to a path ending in /
+
+ def redirect_to_directory_uri(req, res)
+ if req.path[-1] != ?/
+ location = WEBrick::HTTPUtils.escape_path(req.path + "/")
+ if req.query_string && req.query_string.bytesize > 0
+ location << "?" << req.query_string
+ end
+ res.set_redirect(HTTPStatus::MovedPermanently, location)
+ end
+ end
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgi_runner.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgi_runner.rb
new file mode 100644
index 0000000..b0948ae
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgi_runner.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+#
+# cgi_runner.rb -- CGI launcher.
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: cgi_runner.rb,v 1.9 2002/09/25 11:33:15 gotoyuzo Exp $
+
+def sysread(io, size)
+ buf = +""
+ while size > 0
+ tmp = io.sysread(size)
+ buf << tmp
+ size -= tmp.bytesize
+ end
+ return buf
+end
+
+STDIN.binmode
+
+len = sysread(STDIN, 8).to_i
+out = sysread(STDIN, len)
+STDOUT.reopen(File.open(out, "w"))
+
+len = sysread(STDIN, 8).to_i
+err = sysread(STDIN, len)
+STDERR.reopen(File.open(err, "w"))
+
+len = sysread(STDIN, 8).to_i
+dump = sysread(STDIN, len)
+hash = Marshal.restore(dump)
+ENV.keys.each{|name| ENV.delete(name) }
+hash.each{|k, v| ENV[k] = v if v }
+
+dir = File::dirname(ENV["SCRIPT_FILENAME"])
+Dir::chdir dir
+
+if ARGV[0]
+ argv = ARGV.dup
+ argv << ENV["SCRIPT_FILENAME"]
+ exec(*argv)
+ # NOTREACHED
+end
+exec ENV["SCRIPT_FILENAME"]
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgihandler.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgihandler.rb
new file mode 100644
index 0000000..450aa38
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgihandler.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+#
+# cgihandler.rb -- CGIHandler Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: cgihandler.rb,v 1.27 2003/03/21 19:56:01 gotoyuzo Exp $
+
+require 'rbconfig'
+require 'tempfile'
+require_relative '../config'
+require_relative 'abstract'
+
+module WEBrick
+ module HTTPServlet
+
+ ##
+ # Servlet for handling CGI scripts
+ #
+ # Example:
+ #
+ # server.mount('/cgi/my_script', WEBrick::HTTPServlet::CGIHandler,
+ # '/path/to/my_script')
+
+ class CGIHandler < AbstractServlet
+ Ruby = RbConfig.ruby # :nodoc:
+ CGIRunner = "\"#{Ruby}\" \"#{WEBrick::Config::LIBDIR}/httpservlet/cgi_runner.rb\"" # :nodoc:
+ CGIRunnerArray = [Ruby, "#{WEBrick::Config::LIBDIR}/httpservlet/cgi_runner.rb".freeze].freeze # :nodoc:
+
+ ##
+ # Creates a new CGI script servlet for the script at +name+
+
+ def initialize(server, name)
+ super(server, name)
+ @script_filename = name
+ @tempdir = server[:TempDir]
+ interpreter = server[:CGIInterpreter]
+ if interpreter.is_a?(Array)
+ @cgicmd = CGIRunnerArray + interpreter
+ else
+ @cgicmd = "#{CGIRunner} #{interpreter}"
+ end
+ end
+
+ # :stopdoc:
+
+ def do_GET(req, res)
+ cgi_in = IO::popen(@cgicmd, "wb")
+ cgi_out = Tempfile.new("webrick.cgiout.", @tempdir, mode: IO::BINARY)
+ cgi_out.set_encoding("ASCII-8BIT")
+ cgi_err = Tempfile.new("webrick.cgierr.", @tempdir, mode: IO::BINARY)
+ cgi_err.set_encoding("ASCII-8BIT")
+ begin
+ cgi_in.sync = true
+ meta = req.meta_vars
+ meta["SCRIPT_FILENAME"] = @script_filename
+ meta["PATH"] = @config[:CGIPathEnv]
+ meta.delete("HTTP_PROXY")
+ if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+ meta["SystemRoot"] = ENV["SystemRoot"]
+ end
+ dump = Marshal.dump(meta)
+
+ cgi_in.write("%8d" % cgi_out.path.bytesize)
+ cgi_in.write(cgi_out.path)
+ cgi_in.write("%8d" % cgi_err.path.bytesize)
+ cgi_in.write(cgi_err.path)
+ cgi_in.write("%8d" % dump.bytesize)
+ cgi_in.write(dump)
+
+ req.body { |chunk| cgi_in.write(chunk) }
+ ensure
+ cgi_in.close
+ status = $?.exitstatus
+ sleep 0.1 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+ data = cgi_out.read
+ cgi_out.close(true)
+ if errmsg = cgi_err.read
+ if errmsg.bytesize > 0
+ @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg)
+ end
+ end
+ cgi_err.close(true)
+ end
+
+ if status != 0
+ @logger.error("CGIHandler: #{@script_filename} exit with #{status}")
+ end
+
+ data = "" unless data
+ raw_header, body = data.split(/^[\xd\xa]+/, 2)
+ raise HTTPStatus::InternalServerError,
+ "Premature end of script headers: #{@script_filename}" if body.nil?
+
+ begin
+ header = HTTPUtils::parse_header(raw_header)
+ if /^(\d+)/ =~ header['status'][0]
+ res.status = $1.to_i
+ header.delete('status')
+ end
+ if header.has_key?('location')
+ # RFC 3875 6.2.3, 6.2.4
+ res.status = 302 unless (300...400) === res.status
+ end
+ if header.has_key?('set-cookie')
+ header['set-cookie'].each{|k|
+ res.cookies << Cookie.parse_set_cookie(k)
+ }
+ header.delete('set-cookie')
+ end
+ header.each{|key, val| res[key] = val.join(", ") }
+ rescue => ex
+ raise HTTPStatus::InternalServerError, ex.message
+ end
+ res.body = body
+ end
+ alias do_POST do_GET
+
+ # :startdoc:
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/erbhandler.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/erbhandler.rb
new file mode 100644
index 0000000..3b232f7
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/erbhandler.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+#
+# erbhandler.rb -- ERBHandler Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: erbhandler.rb,v 1.25 2003/02/24 19:25:31 gotoyuzo Exp $
+
+require_relative 'abstract'
+
+require 'erb'
+
+module WEBrick
+ module HTTPServlet
+
+ ##
+ # ERBHandler evaluates an ERB file and returns the result. This handler
+ # is automatically used if there are .rhtml files in a directory served by
+ # the FileHandler.
+ #
+ # ERBHandler supports GET and POST methods.
+ #
+ # The ERB file is evaluated with the local variables +servlet_request+ and
+ # +servlet_response+ which are a WEBrick::HTTPRequest and
+ # WEBrick::HTTPResponse respectively.
+ #
+ # Example .rhtml file:
+ #
+ # Request to <%= servlet_request.request_uri %>
+ #
+ # Query params <%= servlet_request.query.inspect %>
+
+ class ERBHandler < AbstractServlet
+
+ ##
+ # Creates a new ERBHandler on +server+ that will evaluate and serve the
+ # ERB file +name+
+
+ def initialize(server, name)
+ super(server, name)
+ @script_filename = name
+ end
+
+ ##
+ # Handles GET requests
+
+ def do_GET(req, res)
+ unless defined?(ERB)
+ @logger.warn "#{self.class}: ERB not defined."
+ raise HTTPStatus::Forbidden, "ERBHandler cannot work."
+ end
+ begin
+ data = File.open(@script_filename, &:read)
+ res.body = evaluate(ERB.new(data), req, res)
+ res['content-type'] ||=
+ HTTPUtils::mime_type(@script_filename, @config[:MimeTypes])
+ rescue StandardError
+ raise
+ rescue Exception => ex
+ @logger.error(ex)
+ raise HTTPStatus::InternalServerError, ex.message
+ end
+ end
+
+ ##
+ # Handles POST requests
+
+ alias do_POST do_GET
+
+ private
+
+ ##
+ # Evaluates +erb+ providing +servlet_request+ and +servlet_response+ as
+ # local variables.
+
+ def evaluate(erb, servlet_request, servlet_response)
+ Module.new.module_eval{
+ servlet_request.meta_vars
+ servlet_request.query
+ erb.result(binding)
+ }
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/filehandler.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/filehandler.rb
new file mode 100644
index 0000000..4e759d8
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/filehandler.rb
@@ -0,0 +1,552 @@
+# frozen_string_literal: true
+#
+# filehandler.rb -- FileHandler Module
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: filehandler.rb,v 1.44 2003/06/07 01:34:51 gotoyuzo Exp $
+
+require 'time'
+
+require_relative '../htmlutils'
+require_relative '../httputils'
+require_relative '../httpstatus'
+
+module WEBrick
+ module HTTPServlet
+
+ ##
+ # Servlet for serving a single file. You probably want to use the
+ # FileHandler servlet instead as it handles directories and fancy indexes.
+ #
+ # Example:
+ #
+ # server.mount('/my_page.txt', WEBrick::HTTPServlet::DefaultFileHandler,
+ # '/path/to/my_page.txt')
+ #
+ # This servlet handles If-Modified-Since and Range requests.
+
+ class DefaultFileHandler < AbstractServlet
+
+ ##
+ # Creates a DefaultFileHandler instance for the file at +local_path+.
+
+ def initialize(server, local_path)
+ super(server, local_path)
+ @local_path = local_path
+ end
+
+ # :stopdoc:
+
+ def do_GET(req, res)
+ st = File::stat(@local_path)
+ mtime = st.mtime
+ res['etag'] = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i)
+
+ if not_modified?(req, res, mtime, res['etag'])
+ res.body = ''
+ raise HTTPStatus::NotModified
+ elsif req['range']
+ make_partial_content(req, res, @local_path, st.size)
+ raise HTTPStatus::PartialContent
+ else
+ mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes])
+ res['content-type'] = mtype
+ res['content-length'] = st.size.to_s
+ res['last-modified'] = mtime.httpdate
+ res.body = File.open(@local_path, "rb")
+ end
+ end
+
+ def not_modified?(req, res, mtime, etag)
+ if ir = req['if-range']
+ begin
+ if Time.httpdate(ir) >= mtime
+ return true
+ end
+ rescue
+ if HTTPUtils::split_header_value(ir).member?(res['etag'])
+ return true
+ end
+ end
+ end
+
+ if (ims = req['if-modified-since']) && Time.parse(ims) >= mtime
+ return true
+ end
+
+ if (inm = req['if-none-match']) &&
+ HTTPUtils::split_header_value(inm).member?(res['etag'])
+ return true
+ end
+
+ 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'])
+ raise HTTPStatus::BadRequest,
+ "Unrecognized range-spec: \"#{req['range']}\""
+ end
+ File.open(filename, "rb"){|io|
+ if ranges.size > 1
+ time = Time.now
+ boundary = "#{time.sec}_#{time.usec}_#{Process::pid}"
+ parts = []
+ ranges.each {|range|
+ prange = prepare_range(range, filesize)
+ next if prange[0] < 0
+ parts.concat(prange)
+ }
+ raise HTTPStatus::RequestRangeNotSatisfiable if parts.empty?
+ res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
+ 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
+ res['content-type'] = mtype
+ res['content-range'] = "bytes #{first}-#{last}/#{filesize}"
+ res['content-length'] = (last - first + 1).to_s
+ res.body = io.dup
+ else
+ raise HTTPStatus::BadRequest
+ end
+ }
+ end
+
+ def prepare_range(range, filesize)
+ first = range.first < 0 ? filesize + range.first : range.first
+ return -1, -1 if first < 0 || first >= filesize
+ last = range.last < 0 ? filesize + range.last : range.last
+ last = filesize - 1 if last >= filesize
+ return first, last
+ end
+
+ # :startdoc:
+ end
+
+ ##
+ # Serves a directory including fancy indexing and a variety of other
+ # options.
+ #
+ # Example:
+ #
+ # server.mount('/assets', WEBrick::HTTPServlet::FileHandler,
+ # '/path/to/assets')
+
+ class FileHandler < AbstractServlet
+ HandlerTable = Hash.new # :nodoc:
+
+ ##
+ # Allow custom handling of requests for files with +suffix+ by class
+ # +handler+
+
+ def self.add_handler(suffix, handler)
+ HandlerTable[suffix] = handler
+ end
+
+ ##
+ # Remove custom handling of requests for files with +suffix+
+
+ def self.remove_handler(suffix)
+ HandlerTable.delete(suffix)
+ end
+
+ ##
+ # Creates a FileHandler servlet on +server+ that serves files starting
+ # at directory +root+
+ #
+ # +options+ may be a Hash containing keys from
+ # WEBrick::Config::FileHandler or +true+ or +false+.
+ #
+ # If +options+ is true or false then +:FancyIndexing+ is enabled or
+ # disabled respectively.
+
+ def initialize(server, root, options={}, default=Config::FileHandler)
+ @config = server.config
+ @logger = @config[:Logger]
+ @root = File.expand_path(root)
+ if options == true || options == false
+ options = { :FancyIndexing => options }
+ end
+ @options = default.dup.update(options)
+ end
+
+ # :stopdoc:
+
+ def set_filesystem_encoding(str)
+ enc = Encoding.find('filesystem')
+ if enc == Encoding::US_ASCII
+ str.b
+ else
+ str.dup.force_encoding(enc)
+ end
+ end
+
+ def service(req, res)
+ # if this class is mounted on "/" and /~username is requested.
+ # we're going to override path information before invoking service.
+ if defined?(Etc) && @options[:UserDir] && req.script_name.empty?
+ if %r|^(/~([^/]+))| =~ req.path_info
+ script_name, user = $1, $2
+ path_info = $'
+ begin
+ passwd = Etc::getpwnam(user)
+ @root = File::join(passwd.dir, @options[:UserDir])
+ req.script_name = script_name
+ req.path_info = path_info
+ rescue
+ @logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed"
+ end
+ end
+ end
+ prevent_directory_traversal(req, res)
+ super(req, res)
+ end
+
+ def do_GET(req, res)
+ unless exec_handler(req, res)
+ set_dir_list(req, res)
+ end
+ end
+
+ def do_POST(req, res)
+ unless exec_handler(req, res)
+ raise HTTPStatus::NotFound, "'#{req.path}' not found."
+ end
+ end
+
+ def do_OPTIONS(req, res)
+ unless exec_handler(req, res)
+ super(req, res)
+ end
+ end
+
+ # ToDo
+ # RFC2518: HTTP Extensions for Distributed Authoring -- WEBDAV
+ #
+ # PROPFIND PROPPATCH MKCOL DELETE PUT COPY MOVE
+ # LOCK UNLOCK
+
+ # RFC3253: Versioning Extensions to WebDAV
+ # (Web Distributed Authoring and Versioning)
+ #
+ # VERSION-CONTROL REPORT CHECKOUT CHECK_IN UNCHECKOUT
+ # MKWORKSPACE UPDATE LABEL MERGE ACTIVITY
+
+ private
+
+ def trailing_pathsep?(path)
+ # check for trailing path separator:
+ # File.dirname("/aaaa/bbbb/") #=> "/aaaa")
+ # File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb")
+ # File.dirname("/aaaa/bbbb") #=> "/aaaa")
+ # File.dirname("/aaaa/bbbbx") #=> "/aaaa")
+ return File.dirname(path) != File.dirname(path+"x")
+ end
+
+ def prevent_directory_traversal(req, res)
+ # Preventing directory traversal on Windows platforms;
+ # Backslashes (0x5c) in path_info are not interpreted as special
+ # character in URI notation. So the value of path_info should be
+ # normalize before accessing to the filesystem.
+
+ # dirty hack for filesystem encoding; in nature, File.expand_path
+ # should not be used for path normalization. [Bug #3345]
+ path = req.path_info.dup.force_encoding(Encoding.find("filesystem"))
+ if trailing_pathsep?(req.path_info)
+ # File.expand_path removes the trailing path separator.
+ # Adding a character is a workaround to save it.
+ # File.expand_path("/aaa/") #=> "/aaa"
+ # File.expand_path("/aaa/" + "x") #=> "/aaa/x"
+ expanded = File.expand_path(path + "x")
+ expanded.chop! # remove trailing "x"
+ else
+ expanded = File.expand_path(path)
+ end
+ expanded.force_encoding(req.path_info.encoding)
+ req.path_info = expanded
+ end
+
+ def exec_handler(req, res)
+ raise HTTPStatus::NotFound, "'#{req.path}' not found." unless @root
+ if set_filename(req, res)
+ handler = get_handler(req, res)
+ call_callback(:HandlerCallback, req, res)
+ h = handler.get_instance(@config, res.filename)
+ h.service(req, res)
+ return true
+ end
+ call_callback(:HandlerCallback, req, res)
+ return false
+ end
+
+ def get_handler(req, res)
+ suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase
+ if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename
+ if @options[:AcceptableLanguages].include?($2.downcase)
+ suffix2 = $1.downcase
+ end
+ end
+ handler_table = @options[:HandlerTable]
+ return handler_table[suffix1] || handler_table[suffix2] ||
+ HandlerTable[suffix1] || HandlerTable[suffix2] ||
+ DefaultFileHandler
+ end
+
+ def set_filename(req, res)
+ res.filename = @root
+ path_info = req.path_info.scan(%r|/[^/]*|)
+
+ path_info.unshift("") # dummy for checking @root dir
+ while base = path_info.first
+ base = set_filesystem_encoding(base)
+ break if base == "/"
+ break unless File.directory?(File.expand_path(res.filename + base))
+ shift_path_info(req, res, path_info)
+ call_callback(:DirectoryCallback, req, res)
+ end
+
+ if base = path_info.first
+ base = set_filesystem_encoding(base)
+ if base == "/"
+ if file = search_index_file(req, res)
+ shift_path_info(req, res, path_info, file)
+ call_callback(:FileCallback, req, res)
+ return true
+ end
+ shift_path_info(req, res, path_info)
+ elsif file = search_file(req, res, base)
+ shift_path_info(req, res, path_info, file)
+ call_callback(:FileCallback, req, res)
+ return true
+ else
+ raise HTTPStatus::NotFound, "'#{req.path}' not found."
+ end
+ end
+
+ return false
+ end
+
+ def check_filename(req, res, name)
+ if nondisclosure_name?(name) || windows_ambiguous_name?(name)
+ @logger.warn("the request refers nondisclosure name '#{name}'.")
+ raise HTTPStatus::NotFound, "'#{req.path}' not found."
+ end
+ end
+
+ def shift_path_info(req, res, path_info, base=nil)
+ tmp = path_info.shift
+ base = base || set_filesystem_encoding(tmp)
+ req.path_info = path_info.join
+ req.script_name << base
+ res.filename = File.expand_path(res.filename + base)
+ check_filename(req, res, File.basename(res.filename))
+ end
+
+ def search_index_file(req, res)
+ @config[:DirectoryIndex].each{|index|
+ if file = search_file(req, res, "/"+index)
+ return file
+ end
+ }
+ return nil
+ end
+
+ def search_file(req, res, basename)
+ langs = @options[:AcceptableLanguages]
+ path = res.filename + basename
+ if File.file?(path)
+ return basename
+ elsif langs.size > 0
+ req.accept_language.each{|lang|
+ path_with_lang = path + ".#{lang}"
+ if langs.member?(lang) && File.file?(path_with_lang)
+ return basename + ".#{lang}"
+ end
+ }
+ (langs - req.accept_language).each{|lang|
+ path_with_lang = path + ".#{lang}"
+ if File.file?(path_with_lang)
+ return basename + ".#{lang}"
+ end
+ }
+ end
+ return nil
+ end
+
+ def call_callback(callback_name, req, res)
+ if cb = @options[callback_name]
+ cb.call(req, res)
+ end
+ end
+
+ def windows_ambiguous_name?(name)
+ return true if /[. ]+\z/ =~ name
+ return true if /::\$DATA\z/ =~ name
+ return false
+ end
+
+ def nondisclosure_name?(name)
+ @options[:NondisclosureName].each{|pattern|
+ if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
+ return true
+ end
+ }
+ return false
+ end
+
+ def set_dir_list(req, res)
+ redirect_to_directory_uri(req, res)
+ unless @options[:FancyIndexing]
+ raise HTTPStatus::Forbidden, "no access permission to '#{req.path}'"
+ end
+ local_path = res.filename
+ list = Dir::entries(local_path).collect{|name|
+ next if name == "." || name == ".."
+ next if nondisclosure_name?(name)
+ next if windows_ambiguous_name?(name)
+ st = (File::stat(File.join(local_path, name)) rescue nil)
+ if st.nil?
+ [ name, nil, -1 ]
+ elsif st.directory?
+ [ name + "/", st.mtime, -1 ]
+ else
+ [ name, st.mtime, st.size ]
+ end
+ }
+ list.compact!
+
+ query = req.query
+
+ d0 = nil
+ idx = nil
+ %w[N M S].each_with_index do |q, i|
+ if d = query.delete(q)
+ idx ||= i
+ d0 ||= d
+ end
+ end
+ d0 ||= "A"
+ idx ||= 0
+ d1 = (d0 == "A") ? "D" : "A"
+
+ if d0 == "A"
+ list.sort!{|a,b| a[idx] <=> b[idx] }
+ else
+ list.sort!{|a,b| b[idx] <=> a[idx] }
+ end
+
+ namewidth = query["NameWidth"]
+ if namewidth == "*"
+ namewidth = nil
+ elsif !namewidth or (namewidth = namewidth.to_i) < 2
+ namewidth = 25
+ end
+ query = query.inject('') {|s, (k, v)| s << '&' << HTMLUtils::escape("#{k}=#{v}")}.dup
+
+ type = +"text/html"
+ case enc = Encoding.find('filesystem')
+ when Encoding::US_ASCII, Encoding::ASCII_8BIT
+ else
+ type << "; charset=\"#{enc.name}\""
+ end
+ res['content-type'] = type
+
+ title = "Index of #{HTMLUtils::escape(req.path)}"
+ res.body = +<<-_end_of_html_
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+ <TITLE>#{title}</TITLE>
+ <style type="text/css">
+ <!--
+ .name, .mtime { text-align: left; }
+ .size { text-align: right; }
+ td { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }
+ table { border-collapse: collapse; }
+ tr th { border-bottom: 2px groove; }
+ //-->
+ </style>
+ </HEAD>
+ <BODY>
+ <H1>#{title}</H1>
+ _end_of_html_
+
+ res.body << "<TABLE width=\"100%\"><THEAD><TR>\n"
+ res.body << "<TH class=\"name\"><A HREF=\"?N=#{d1}#{query}\">Name</A></TH>"
+ res.body << "<TH class=\"mtime\"><A HREF=\"?M=#{d1}#{query}\">Last modified</A></TH>"
+ res.body << "<TH class=\"size\"><A HREF=\"?S=#{d1}#{query}\">Size</A></TH>\n"
+ res.body << "</TR></THEAD>\n"
+ res.body << "<TBODY>\n"
+
+ query.sub!(/\A&/, '?')
+ list.unshift [ "..", File::mtime(local_path+"/.."), -1 ]
+ list.each{ |name, time, size|
+ if name == ".."
+ dname = "Parent Directory"
+ elsif namewidth and name.size > namewidth
+ dname = name[0...(namewidth - 2)] << '..'
+ else
+ dname = name
+ end
+ s = +"<TR><TD class=\"name\"><A HREF=\"#{HTTPUtils::escape(name)}#{query if name.end_with?('/')}\">#{HTMLUtils::escape(dname)}</A></TD>"
+ s << "<TD class=\"mtime\">" << (time ? time.strftime("%Y/%m/%d %H:%M") : "") << "</TD>"
+ s << "<TD class=\"size\">" << (size >= 0 ? size.to_s : "-") << "</TD></TR>\n"
+ res.body << s
+ }
+ res.body << "</TBODY></TABLE>"
+ res.body << "<HR>"
+
+ res.body << <<-_end_of_html_
+ <ADDRESS>
+ #{HTMLUtils::escape(@config[:ServerSoftware])}<BR>
+ at #{req.host}:#{req.port}
+ </ADDRESS>
+ </BODY>
+</HTML>
+ _end_of_html_
+ end
+
+ # :startdoc:
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/prochandler.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/prochandler.rb
new file mode 100644
index 0000000..92e4f80
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/prochandler.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+#
+# prochandler.rb -- ProcHandler Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $
+
+require_relative 'abstract'
+
+module WEBrick
+ module HTTPServlet
+
+ ##
+ # Mounts a proc at a path that accepts a request and response.
+ #
+ # Instead of mounting this servlet with WEBrick::HTTPServer#mount use
+ # WEBrick::HTTPServer#mount_proc:
+ #
+ # server.mount_proc '/' do |req, res|
+ # res.body = 'it worked!'
+ # res.status = 200
+ # end
+
+ class ProcHandler < AbstractServlet
+ # :stopdoc:
+ def get_instance(server, *options)
+ self
+ end
+
+ def initialize(proc)
+ @proc = proc
+ end
+
+ def do_GET(request, response)
+ @proc.call(request, response)
+ end
+
+ alias do_POST do_GET
+ alias do_PUT do_GET
+ # :startdoc:
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpstatus.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpstatus.rb
new file mode 100644
index 0000000..c21c1d4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpstatus.rb
@@ -0,0 +1,194 @@
+# frozen_string_literal: true
+#--
+# httpstatus.rb -- HTTPStatus Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $
+
+require_relative 'accesslog'
+
+module WEBrick
+
+ ##
+ # This module is used to manager HTTP status codes.
+ #
+ # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html for more
+ # information.
+ module HTTPStatus
+
+ ##
+ # Root of the HTTP status class hierarchy
+ class Status < StandardError
+ class << self
+ attr_reader :code, :reason_phrase # :nodoc:
+ end
+
+ # Returns the HTTP status code
+ def code() self::class::code end
+
+ # Returns the HTTP status description
+ def reason_phrase() self::class::reason_phrase end
+
+ alias to_i code # :nodoc:
+ end
+
+ # Root of the HTTP info statuses
+ class Info < Status; end
+ # Root of the HTTP success statuses
+ class Success < Status; end
+ # Root of the HTTP redirect statuses
+ class Redirect < Status; end
+ # Root of the HTTP error statuses
+ class Error < Status; end
+ # Root of the HTTP client error statuses
+ class ClientError < Error; end
+ # Root of the HTTP server error statuses
+ class ServerError < Error; end
+
+ class EOFError < StandardError; end
+
+ # HTTP status codes and descriptions
+ StatusMessage = { # :nodoc:
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Request Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 426 => 'Upgrade Required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 451 => 'Unavailable For Legal Reasons',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 507 => 'Insufficient Storage',
+ 511 => 'Network Authentication Required',
+ }
+
+ # Maps a status code to the corresponding Status class
+ CodeToError = {} # :nodoc:
+
+ # Creates a status or error class for each status code and
+ # populates the CodeToError map.
+ StatusMessage.each{|code, message|
+ message.freeze
+ var_name = message.gsub(/[ \-]/,'_').upcase
+ err_name = message.gsub(/[ \-]/,'')
+
+ case code
+ when 100...200; parent = Info
+ when 200...300; parent = Success
+ when 300...400; parent = Redirect
+ when 400...500; parent = ClientError
+ when 500...600; parent = ServerError
+ end
+
+ const_set("RC_#{var_name}", code)
+ err_class = Class.new(parent)
+ err_class.instance_variable_set(:@code, code)
+ err_class.instance_variable_set(:@reason_phrase, message)
+ const_set(err_name, err_class)
+ CodeToError[code] = err_class
+ }
+
+ ##
+ # Returns the description corresponding to the HTTP status +code+
+ #
+ # WEBrick::HTTPStatus.reason_phrase 404
+ # => "Not Found"
+ def reason_phrase(code)
+ StatusMessage[code.to_i]
+ end
+
+ ##
+ # Is +code+ an informational status?
+ def info?(code)
+ code.to_i >= 100 and code.to_i < 200
+ end
+
+ ##
+ # Is +code+ a successful status?
+ def success?(code)
+ code.to_i >= 200 and code.to_i < 300
+ end
+
+ ##
+ # Is +code+ a redirection status?
+ def redirect?(code)
+ code.to_i >= 300 and code.to_i < 400
+ end
+
+ ##
+ # Is +code+ an error status?
+ def error?(code)
+ code.to_i >= 400 and code.to_i < 600
+ end
+
+ ##
+ # Is +code+ a client error status?
+ def client_error?(code)
+ code.to_i >= 400 and code.to_i < 500
+ end
+
+ ##
+ # Is +code+ a server error status?
+ def server_error?(code)
+ code.to_i >= 500 and code.to_i < 600
+ end
+
+ ##
+ # Returns the status class corresponding to +code+
+ #
+ # WEBrick::HTTPStatus[302]
+ # => WEBrick::HTTPStatus::NotFound
+ #
+ def self.[](code)
+ CodeToError[code]
+ end
+
+ module_function :reason_phrase
+ module_function :info?, :success?, :redirect?, :error?
+ module_function :client_error?, :server_error?
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httputils.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httputils.rb
new file mode 100644
index 0000000..e2c2a40
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httputils.rb
@@ -0,0 +1,543 @@
+# frozen_string_literal: true
+#
+# httputils.rb -- HTTPUtils Module
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httputils.rb,v 1.34 2003/06/05 21:34:08 gotoyuzo Exp $
+
+require 'socket'
+require 'tempfile'
+
+module WEBrick
+ CR = "\x0d" # :nodoc:
+ LF = "\x0a" # :nodoc:
+ CRLF = "\x0d\x0a" # :nodoc:
+
+ ##
+ # HTTPUtils provides utility methods for working with the HTTP protocol.
+ #
+ # This module is generally used internally by WEBrick
+
+ module HTTPUtils
+
+ ##
+ # Normalizes a request path. Raises an exception if the path cannot be
+ # normalized.
+
+ def normalize_path(path)
+ raise "abnormal path '#{path}'" if path[0] != ?/
+ ret = path.dup
+
+ ret.gsub!(%r{/+}o, '/') # // => /
+ while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => /
+ while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo
+
+ raise "abnormal path '#{path}'" if %r{/\.\.(/|\Z)} =~ ret
+ ret
+ end
+ module_function :normalize_path
+
+ ##
+ # Default mime types
+
+ DefaultMimeTypes = {
+ "ai" => "application/postscript",
+ "asc" => "text/plain",
+ "avi" => "video/x-msvideo",
+ "avif" => "image/avif",
+ "bin" => "application/octet-stream",
+ "bmp" => "image/bmp",
+ "class" => "application/octet-stream",
+ "cer" => "application/pkix-cert",
+ "crl" => "application/pkix-crl",
+ "crt" => "application/x-x509-ca-cert",
+ "css" => "text/css",
+ "dms" => "application/octet-stream",
+ "doc" => "application/msword",
+ "dvi" => "application/x-dvi",
+ "eps" => "application/postscript",
+ "etx" => "text/x-setext",
+ "exe" => "application/octet-stream",
+ "gif" => "image/gif",
+ "htm" => "text/html",
+ "html" => "text/html",
+ "ico" => "image/x-icon",
+ "jpe" => "image/jpeg",
+ "jpeg" => "image/jpeg",
+ "jpg" => "image/jpeg",
+ "js" => "application/javascript",
+ "json" => "application/json",
+ "lha" => "application/octet-stream",
+ "lzh" => "application/octet-stream",
+ "mjs" => "application/javascript",
+ "mov" => "video/quicktime",
+ "mp4" => "video/mp4",
+ "mpe" => "video/mpeg",
+ "mpeg" => "video/mpeg",
+ "mpg" => "video/mpeg",
+ "otf" => "font/otf",
+ "pbm" => "image/x-portable-bitmap",
+ "pdf" => "application/pdf",
+ "pgm" => "image/x-portable-graymap",
+ "png" => "image/png",
+ "pnm" => "image/x-portable-anymap",
+ "ppm" => "image/x-portable-pixmap",
+ "ppt" => "application/vnd.ms-powerpoint",
+ "ps" => "application/postscript",
+ "qt" => "video/quicktime",
+ "ras" => "image/x-cmu-raster",
+ "rb" => "text/plain",
+ "rd" => "text/plain",
+ "rtf" => "application/rtf",
+ "sgm" => "text/sgml",
+ "sgml" => "text/sgml",
+ "svg" => "image/svg+xml",
+ "tif" => "image/tiff",
+ "tiff" => "image/tiff",
+ "ttc" => "font/collection",
+ "ttf" => "font/ttf",
+ "txt" => "text/plain",
+ "wasm" => "application/wasm",
+ "webm" => "video/webm",
+ "webmanifest" => "application/manifest+json",
+ "webp" => "image/webp",
+ "woff" => "font/woff",
+ "woff2" => "font/woff2",
+ "xbm" => "image/x-xbitmap",
+ "xhtml" => "text/html",
+ "xls" => "application/vnd.ms-excel",
+ "xml" => "text/xml",
+ "xpm" => "image/x-xpixmap",
+ "xwd" => "image/x-xwindowdump",
+ "zip" => "application/zip",
+ }
+
+ ##
+ # Loads Apache-compatible mime.types in +file+.
+
+ def load_mime_types(file)
+ # note: +file+ may be a "| command" for now; some people may
+ # rely on this, but currently we do not use this method by default.
+ File.open(file){ |io|
+ hash = Hash.new
+ io.each{ |line|
+ next if /^#/ =~ line
+ line.chomp!
+ mimetype, ext0 = line.split(/\s+/, 2)
+ next unless ext0
+ next if ext0.empty?
+ ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype }
+ }
+ hash
+ }
+ end
+ module_function :load_mime_types
+
+ ##
+ # Returns the mime type of +filename+ from the list in +mime_tab+. If no
+ # mime type was found application/octet-stream is returned.
+
+ def mime_type(filename, mime_tab)
+ suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
+ suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase)
+ mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream"
+ end
+ module_function :mime_type
+
+ ##
+ # Parses an HTTP header +raw+ into a hash of header fields with an Array
+ # of values.
+
+ class SplitHeader < Array
+ def join(separator = ", ")
+ super
+ end
+ end
+
+ class CookieHeader < Array
+ def join(separator = "; ")
+ super
+ end
+ end
+
+ HEADER_CLASSES = Hash.new(SplitHeader).update({
+ "cookie" => CookieHeader,
+ })
+
+ def parse_header(raw)
+ header = Hash.new([].freeze)
+ field = nil
+ raw.each_line{|line|
+ case line
+ when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):([^\r\n\0]*?)\r\n\z/om
+ field, value = $1, $2
+ field.downcase!
+ header[field] = HEADER_CLASSES[field].new unless header.has_key?(field)
+ header[field] << value
+ when /^[ \t]+([^\r\n\0]*?)\r\n/om
+ unless field
+ raise HTTPStatus::BadRequest, "bad header '#{line}'."
+ end
+ value = line
+ value.gsub!(/\A[ \t]+/, '')
+ value.slice!(-2..-1)
+ header[field][-1] << " " << value
+ else
+ raise HTTPStatus::BadRequest, "bad header '#{line}'."
+ end
+ }
+ header.each{|key, values|
+ values.each{|value|
+ value.gsub!(/\A[ \t]+/, '')
+ value.gsub!(/[ \t]+\z/, '')
+ }
+ }
+ header
+ end
+ module_function :parse_header
+
+ ##
+ # Splits a header value +str+ according to HTTP specification.
+
+ def split_header_value(str)
+ str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]++)+)
+ (?:,[ \t]*|\Z)'xn).flatten
+ end
+ module_function :split_header_value
+
+ ##
+ # Parses a Range header value +ranges_specifier+
+
+ def parse_range_header(ranges_specifier)
+ if /^bytes=(.*)/ =~ ranges_specifier
+ byte_range_set = split_header_value($1)
+ byte_range_set.collect{|range_spec|
+ case range_spec
+ when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i
+ when /^(\d+)-/ then $1.to_i .. -1
+ when /^-(\d+)/ then -($1.to_i) .. -1
+ else return nil
+ end
+ }
+ end
+ end
+ module_function :parse_range_header
+
+ ##
+ # Parses q values in +value+ as used in Accept headers.
+
+ def parse_qvalues(value)
+ tmp = []
+ if value
+ parts = value.split(/,[ \t]*/)
+ parts.each {|part|
+ if m = %r{^([^ \t,]+?)(?:;[ \t]*q=(\d+(?:\.\d+)?))?$}.match(part)
+ val = m[1]
+ q = (m[2] or 1).to_f
+ tmp.push([val, q])
+ end
+ }
+ tmp = tmp.sort_by{|val, q| -q}
+ tmp.collect!{|val, q| val}
+ end
+ return tmp
+ end
+ module_function :parse_qvalues
+
+ ##
+ # Removes quotes and escapes from +str+
+
+ def dequote(str)
+ ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
+ ret.gsub!(/\\(.)/, "\\1")
+ ret
+ end
+ module_function :dequote
+
+ ##
+ # Quotes and escapes quotes in +str+
+
+ def quote(str)
+ +'"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
+ end
+ module_function :quote
+
+ ##
+ # Stores multipart form data. FormData objects are created when
+ # WEBrick::HTTPUtils.parse_form_data is called.
+
+ class FormData < String
+ EmptyRawHeader = [].freeze # :nodoc:
+ EmptyHeader = {}.freeze # :nodoc:
+
+ ##
+ # The name of the form data part
+
+ attr_accessor :name
+
+ ##
+ # The filename of the form data part
+
+ attr_accessor :filename
+
+ attr_accessor :next_data # :nodoc:
+ protected :next_data
+
+ ##
+ # Creates a new FormData object.
+ #
+ # +args+ is an Array of form data entries. One FormData will be created
+ # for each entry.
+ #
+ # This is called by WEBrick::HTTPUtils.parse_form_data for you
+
+ def initialize(*args)
+ @name = @filename = @next_data = nil
+ if args.empty?
+ @raw_header = []
+ @header = nil
+ super("")
+ else
+ @raw_header = EmptyRawHeader
+ @header = EmptyHeader
+ super(args.shift)
+ unless args.empty?
+ @next_data = self.class.new(*args)
+ end
+ end
+ end
+
+ ##
+ # Retrieves the header at the first entry in +key+
+
+ def [](*key)
+ begin
+ @header[key[0].downcase].join(", ")
+ rescue StandardError, NameError
+ super
+ end
+ end
+
+ ##
+ # Adds +str+ to this FormData which may be the body, a header or a
+ # header entry.
+ #
+ # This is called by WEBrick::HTTPUtils.parse_form_data for you
+
+ def <<(str)
+ if @header
+ super
+ elsif str == CRLF
+ @header = HTTPUtils::parse_header(@raw_header.join)
+ if cd = self['content-disposition']
+ if /[ \t]+name="(.*?)"/ =~ cd then @name = $1 end
+ if /[ \t]+filename="(.*?)"/ =~ cd then @filename = $1 end
+ end
+ else
+ @raw_header << str
+ end
+ self
+ end
+
+ ##
+ # Adds +data+ at the end of the chain of entries
+ #
+ # This is called by WEBrick::HTTPUtils.parse_form_data for you.
+
+ def append_data(data)
+ tmp = self
+ while tmp
+ unless tmp.next_data
+ tmp.next_data = data
+ break
+ end
+ tmp = tmp.next_data
+ end
+ self
+ end
+
+ ##
+ # Yields each entry in this FormData
+
+ def each_data
+ tmp = self
+ while tmp
+ next_data = tmp.next_data
+ yield(tmp)
+ tmp = next_data
+ end
+ end
+
+ ##
+ # Returns all the FormData as an Array
+
+ def list
+ ret = []
+ each_data{|data|
+ ret << data.to_s
+ }
+ ret
+ end
+
+ ##
+ # A FormData will behave like an Array
+
+ alias :to_ary :list
+
+ ##
+ # This FormData's body
+
+ def to_s
+ String.new(self)
+ end
+ end
+
+ ##
+ # Parses the query component of a URI in +str+
+
+ def parse_query(str)
+ query = Hash.new
+ if str
+ str.split(/[&;]/).each{|x|
+ next if x.empty?
+ key, val = x.split(/=/,2)
+ key = unescape_form(key)
+ val = unescape_form(val.to_s)
+ val = FormData.new(val)
+ val.name = key
+ if query.has_key?(key)
+ query[key].append_data(val)
+ next
+ end
+ query[key] = val
+ }
+ end
+ query
+ end
+ module_function :parse_query
+
+ ##
+ # Parses form data in +io+ with the given +boundary+
+
+ def parse_form_data(io, boundary)
+ boundary_regexp = /\A--#{Regexp.quote(boundary)}(--)?#{CRLF}\z/
+ form_data = Hash.new
+ return form_data unless io
+ data = nil
+ io.each_line{|line|
+ if boundary_regexp =~ line
+ if data
+ data.chop!
+ key = data.name
+ if form_data.has_key?(key)
+ form_data[key].append_data(data)
+ else
+ form_data[key] = data
+ end
+ end
+ data = FormData.new
+ next
+ else
+ if data
+ data << line
+ end
+ end
+ }
+ return form_data
+ end
+ module_function :parse_form_data
+
+ #####
+
+ reserved = ';/?:@&=+$,'
+ num = '0123456789'
+ lowalpha = 'abcdefghijklmnopqrstuvwxyz'
+ upalpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ mark = '-_.!~*\'()'
+ unreserved = num + lowalpha + upalpha + mark
+ control = (0x0..0x1f).collect{|c| c.chr }.join + "\x7f"
+ space = " "
+ delims = '<>#%"'
+ unwise = '{}|\\^[]`'
+ nonascii = (0x80..0xff).collect{|c| c.chr }.join
+
+ module_function
+
+ # :stopdoc:
+
+ def _make_regex(str) /([#{Regexp.escape(str)}])/n end
+ def _make_regex!(str) /([^#{Regexp.escape(str)}])/n end
+ def _escape(str, regex)
+ str = str.b
+ str.gsub!(regex) {"%%%02X" % $1.ord}
+ # %-escaped string should contain US-ASCII only
+ str.force_encoding(Encoding::US_ASCII)
+ end
+ def _unescape(str, regex)
+ str = str.b
+ str.gsub!(regex) {$1.hex.chr}
+ # encoding of %-unescaped string is unknown
+ str
+ end
+
+ UNESCAPED = _make_regex(control+space+delims+unwise+nonascii)
+ UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii)
+ NONASCII = _make_regex(nonascii)
+ ESCAPED = /%([0-9a-fA-F]{2})/
+ UNESCAPED_PCHAR = _make_regex!(unreserved+":@&=+$,")
+
+ # :startdoc:
+
+ ##
+ # Escapes HTTP reserved and unwise characters in +str+
+
+ def escape(str)
+ _escape(str, UNESCAPED)
+ end
+
+ ##
+ # Unescapes HTTP reserved and unwise characters in +str+
+
+ def unescape(str)
+ _unescape(str, ESCAPED)
+ end
+
+ ##
+ # Escapes form reserved characters in +str+
+
+ def escape_form(str)
+ ret = _escape(str, UNESCAPED_FORM)
+ ret.gsub!(/ /, "+")
+ ret
+ end
+
+ ##
+ # Unescapes form reserved characters in +str+
+
+ def unescape_form(str)
+ _unescape(str.gsub(/\+/, " "), ESCAPED)
+ end
+
+ ##
+ # Escapes path +str+
+
+ def escape_path(str)
+ result = +""
+ str.scan(%r{/([^/]*)}).each{|i|
+ result << "/" << _escape(i[0], UNESCAPED_PCHAR)
+ }
+ return result
+ end
+
+ ##
+ # Escapes 8 bit characters in +str+
+
+ def escape8bit(str)
+ _escape(str, NONASCII)
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpversion.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpversion.rb
new file mode 100644
index 0000000..6349590
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpversion.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+#--
+# HTTPVersion.rb -- presentation of HTTP version
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $
+
+module WEBrick
+
+ ##
+ # Represents an HTTP protocol version
+
+ class HTTPVersion
+ include Comparable
+
+ ##
+ # The major protocol version number
+
+ attr_accessor :major
+
+ ##
+ # The minor protocol version number
+
+ attr_accessor :minor
+
+ ##
+ # Converts +version+ into an HTTPVersion
+
+ def self.convert(version)
+ version.is_a?(self) ? version : new(version)
+ end
+
+ ##
+ # Creates a new HTTPVersion from +version+.
+
+ def initialize(version)
+ case version
+ when HTTPVersion
+ @major, @minor = version.major, version.minor
+ when String
+ if /^(\d+)\.(\d+)$/ =~ version
+ @major, @minor = $1.to_i, $2.to_i
+ end
+ end
+ if @major.nil? || @minor.nil?
+ raise ArgumentError,
+ format("cannot convert %s into %s", version.class, self.class)
+ end
+ end
+
+ ##
+ # Compares this version with +other+ according to the HTTP specification
+ # rules.
+
+ def <=>(other)
+ unless other.is_a?(self.class)
+ other = self.class.new(other)
+ end
+ if (ret = @major <=> other.major) == 0
+ return @minor <=> other.minor
+ end
+ return ret
+ end
+
+ ##
+ # The HTTP version as show in the HTTP request and response. For example,
+ # "1.1"
+
+ def to_s
+ format("%d.%d", @major, @minor)
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/log.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/log.rb
new file mode 100644
index 0000000..4de4bee
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/log.rb
@@ -0,0 +1,156 @@
+# frozen_string_literal: true
+#--
+# log.rb -- Log Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $
+
+module WEBrick
+
+ ##
+ # A generic logging class
+
+ class BasicLog
+
+ # Fatal log level which indicates a server crash
+
+ FATAL = 1
+
+ # Error log level which indicates a recoverable error
+
+ ERROR = 2
+
+ # Warning log level which indicates a possible problem
+
+ WARN = 3
+
+ # Information log level which indicates possibly useful information
+
+ INFO = 4
+
+ # Debugging error level for messages used in server development or
+ # debugging
+
+ DEBUG = 5
+
+ # log-level, messages above this level will be logged
+ attr_accessor :level
+
+ ##
+ # Initializes a new logger for +log_file+ that outputs messages at +level+
+ # or higher. +log_file+ can be a filename, an IO-like object that
+ # responds to #<< or nil which outputs to $stderr.
+ #
+ # If no level is given INFO is chosen by default
+
+ def initialize(log_file=nil, level=nil)
+ @level = level || INFO
+ case log_file
+ when String
+ @log = File.open(log_file, "a+")
+ @log.sync = true
+ @opened = true
+ when NilClass
+ @log = $stderr
+ else
+ @log = log_file # requires "<<". (see BasicLog#log)
+ end
+ end
+
+ ##
+ # Closes the logger (also closes the log device associated to the logger)
+ def close
+ @log.close if @opened
+ @log = nil
+ end
+
+ ##
+ # Logs +data+ at +level+ if the given level is above the current log
+ # level.
+
+ def log(level, data)
+ if @log && level <= @level
+ data += "\n" if /\n\Z/ !~ data
+ @log << data
+ end
+ end
+
+ ##
+ # Synonym for log(INFO, obj.to_s)
+ def <<(obj)
+ log(INFO, obj.to_s)
+ end
+
+ # Shortcut for logging a FATAL message
+ def fatal(msg) log(FATAL, "FATAL " + format(msg)); end
+ # Shortcut for logging an ERROR message
+ def error(msg) log(ERROR, "ERROR " + format(msg)); end
+ # Shortcut for logging a WARN message
+ def warn(msg) log(WARN, "WARN " + format(msg)); end
+ # Shortcut for logging an INFO message
+ def info(msg) log(INFO, "INFO " + format(msg)); end
+ # Shortcut for logging a DEBUG message
+ def debug(msg) log(DEBUG, "DEBUG " + format(msg)); end
+
+ # Will the logger output FATAL messages?
+ def fatal?; @level >= FATAL; end
+ # Will the logger output ERROR messages?
+ def error?; @level >= ERROR; end
+ # Will the logger output WARN messages?
+ def warn?; @level >= WARN; end
+ # Will the logger output INFO messages?
+ def info?; @level >= INFO; end
+ # Will the logger output DEBUG messages?
+ def debug?; @level >= DEBUG; end
+
+ private
+
+ ##
+ # Formats +arg+ for the logger
+ #
+ # * If +arg+ is an Exception, it will format the error message and
+ # the back trace.
+ # * If +arg+ responds to #to_str, it will return it.
+ # * Otherwise it will return +arg+.inspect.
+ def format(arg)
+ if arg.is_a?(Exception)
+ +"#{arg.class}: #{AccessLog.escape(arg.message)}\n\t" <<
+ arg.backtrace.join("\n\t") << "\n"
+ elsif arg.respond_to?(:to_str)
+ AccessLog.escape(arg.to_str)
+ else
+ arg.inspect
+ end
+ end
+ end
+
+ ##
+ # A logging class that prepends a timestamp to each message.
+
+ class Log < BasicLog
+ # Format of the timestamp which is applied to each logged line. The
+ # default is <tt>"[%Y-%m-%d %H:%M:%S]"</tt>
+ attr_accessor :time_format
+
+ ##
+ # Same as BasicLog#initialize
+ #
+ # You can set the timestamp format through #time_format
+ def initialize(log_file=nil, level=nil)
+ super(log_file, level)
+ @time_format = "[%Y-%m-%d %H:%M:%S]"
+ end
+
+ ##
+ # Same as BasicLog#log
+ def log(level, data)
+ tmp = Time.now.strftime(@time_format)
+ tmp << " " << data
+ super(level, tmp)
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/server.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/server.rb
new file mode 100644
index 0000000..d268394
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/server.rb
@@ -0,0 +1,380 @@
+# frozen_string_literal: true
+#
+# server.rb -- GenericServer Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
+
+require 'socket'
+require_relative 'config'
+require_relative 'log'
+
+module WEBrick
+
+ ##
+ # Server error exception
+
+ class ServerError < StandardError; end
+
+ ##
+ # Base server class
+
+ class SimpleServer
+
+ ##
+ # A SimpleServer only yields when you start it
+
+ def SimpleServer.start
+ yield
+ end
+ end
+
+ ##
+ # A generic module for daemonizing a process
+
+ class Daemon
+
+ ##
+ # Performs the standard operations for daemonizing a process. Runs a
+ # block, if given.
+
+ def Daemon.start
+ Process.daemon
+ File.umask(0)
+ yield if block_given?
+ end
+ end
+
+ ##
+ # Base TCP server class. You must subclass GenericServer and provide a #run
+ # method.
+
+ class GenericServer
+
+ ##
+ # The server status. One of :Stop, :Running or :Shutdown
+
+ attr_reader :status
+
+ ##
+ # The server configuration
+
+ attr_reader :config
+
+ ##
+ # The server logger. This is independent from the HTTP access log.
+
+ attr_reader :logger
+
+ ##
+ # Tokens control the number of outstanding clients. The
+ # <code>:MaxClients</code> configuration sets this.
+
+ attr_reader :tokens
+
+ ##
+ # Sockets listening for connections.
+
+ attr_reader :listeners
+
+ ##
+ # Creates a new generic server from +config+. The default configuration
+ # comes from +default+.
+
+ def initialize(config={}, default=Config::General)
+ @config = default.dup.update(config)
+ @status = :Stop
+ @config[:Logger] ||= Log::new
+ @logger = @config[:Logger]
+
+ @tokens = Thread::SizedQueue.new(@config[:MaxClients])
+ @config[:MaxClients].times{ @tokens.push(nil) }
+
+ webrickv = WEBrick::VERSION
+ rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
+ @logger.info("WEBrick #{webrickv}")
+ @logger.info("ruby #{rubyv}")
+
+ @listeners = []
+ @shutdown_pipe = nil
+ unless @config[:DoNotListen]
+ raise ArgumentError, "Port must be an integer" unless @config[:Port].to_s == @config[:Port].to_i.to_s
+
+ @config[:Port] = @config[:Port].to_i
+ if @config[:Listen]
+ warn(":Listen option is deprecated; use GenericServer#listen", uplevel: 1)
+ end
+ listen(@config[:BindAddress], @config[:Port])
+ if @config[:Port] == 0
+ @config[:Port] = @listeners[0].addr[1]
+ end
+ end
+ end
+
+ ##
+ # Retrieves +key+ from the configuration
+
+ def [](key)
+ @config[key]
+ end
+
+ ##
+ # Adds listeners from +address+ and +port+ to the server. See
+ # WEBrick::Utils::create_listeners for details.
+
+ def listen(address, port)
+ @listeners += Utils::create_listeners(address, port)
+ end
+
+ ##
+ # Starts the server and runs the +block+ for each connection. This method
+ # does not return until the server is stopped from a signal handler or
+ # another thread using #stop or #shutdown.
+ #
+ # If the block raises a subclass of StandardError the exception is logged
+ # and ignored. If an IOError or Errno::EBADF exception is raised the
+ # exception is ignored. If an Exception subclass is raised the exception
+ # is logged and re-raised which stops the server.
+ #
+ # To completely shut down a server call #shutdown from ensure:
+ #
+ # server = WEBrick::GenericServer.new
+ # # or WEBrick::HTTPServer.new
+ #
+ # begin
+ # server.start
+ # ensure
+ # server.shutdown
+ # end
+
+ def start(&block)
+ raise ServerError, "already started." if @status != :Stop
+ server_type = @config[:ServerType] || SimpleServer
+
+ setup_shutdown_pipe
+
+ server_type.start{
+ @logger.info \
+ "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
+ @status = :Running
+ call_callback(:StartCallback)
+
+ shutdown_pipe = @shutdown_pipe
+
+ thgroup = ThreadGroup.new
+ begin
+ while @status == :Running
+ begin
+ sp = shutdown_pipe[0]
+ if svrs = IO.select([sp, *@listeners])
+ if svrs[0].include? sp
+ # swallow shutdown pipe
+ buf = String.new
+ nil while String === sp.read_nonblock(8, buf, exception: false)
+ break
+ end
+ svrs[0].each{|svr|
+ @tokens.pop # blocks while no token is there.
+ if sock = accept_client(svr)
+ unless config[:DoNotReverseLookup].nil?
+ sock.do_not_reverse_lookup = !!config[:DoNotReverseLookup]
+ end
+ th = start_thread(sock, &block)
+ th[:WEBrickThread] = true
+ thgroup.add(th)
+ else
+ @tokens.push(nil)
+ end
+ }
+ end
+ rescue Errno::EBADF, Errno::ENOTSOCK, IOError => ex
+ # if the listening socket was closed in GenericServer#shutdown,
+ # IO::select raise it.
+ rescue StandardError => ex
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
+ @logger.error msg
+ rescue Exception => ex
+ @logger.fatal ex
+ raise
+ end
+ end
+ ensure
+ cleanup_shutdown_pipe(shutdown_pipe)
+ cleanup_listener
+ @status = :Shutdown
+ @logger.info "going to shutdown ..."
+ thgroup.list.each{|th| th.join if th[:WEBrickThread] }
+ call_callback(:StopCallback)
+ @logger.info "#{self.class}#start done."
+ @status = :Stop
+ end
+ }
+ end
+
+ ##
+ # Stops the server from accepting new connections.
+
+ def stop
+ if @status == :Running
+ @status = :Shutdown
+ end
+
+ alarm_shutdown_pipe {|f| f.write_nonblock("\0")}
+ end
+
+ ##
+ # Shuts down the server and all listening sockets. New listeners must be
+ # provided to restart the server.
+
+ def shutdown
+ stop
+
+ alarm_shutdown_pipe(&:close)
+ end
+
+ ##
+ # You must subclass GenericServer and implement \#run which accepts a TCP
+ # client socket
+
+ def run(sock)
+ @logger.fatal "run() must be provided by user."
+ end
+
+ private
+
+ # :stopdoc:
+
+ ##
+ # Accepts a TCP client socket from the TCP server socket +svr+ and returns
+ # the client socket.
+
+ def accept_client(svr)
+ case sock = svr.to_io.accept_nonblock(exception: false)
+ when :wait_readable
+ nil
+ else
+ if svr.respond_to?(:start_immediately)
+ sock = OpenSSL::SSL::SSLSocket.new(sock, ssl_context)
+ sock.sync_close = true
+ # we cannot do OpenSSL::SSL::SSLSocket#accept here because
+ # a slow client can prevent us from accepting connections
+ # from other clients
+ end
+ sock
+ end
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED,
+ Errno::EPROTO, Errno::EINVAL
+ nil
+ rescue StandardError => ex
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
+ @logger.error msg
+ nil
+ end
+
+ ##
+ # Starts a server thread for the client socket +sock+ that runs the given
+ # +block+.
+ #
+ # Sets the socket to the <code>:WEBrickSocket</code> thread local variable
+ # in the thread.
+ #
+ # If any errors occur in the block they are logged and handled.
+
+ def start_thread(sock, &block)
+ Thread.start{
+ begin
+ Thread.current[:WEBrickSocket] = sock
+ begin
+ addr = sock.peeraddr
+ @logger.debug "accept: #{addr[3]}:#{addr[1]}"
+ rescue SocketError
+ @logger.debug "accept: <address unknown>"
+ raise
+ end
+ if sock.respond_to?(:sync_close=) && @config[:SSLStartImmediately]
+ WEBrick::Utils.timeout(@config[:RequestTimeout]) do
+ begin
+ sock.accept # OpenSSL::SSL::SSLSocket#accept
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED,
+ Errno::EPROTO, Errno::EINVAL
+ Thread.exit
+ end
+ end
+ end
+ call_callback(:AcceptCallback, sock)
+ block ? block.call(sock) : run(sock)
+ rescue Errno::ENOTCONN
+ @logger.debug "Errno::ENOTCONN raised"
+ rescue ServerError => ex
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
+ @logger.error msg
+ rescue Exception => ex
+ @logger.error ex
+ ensure
+ @tokens.push(nil)
+ Thread.current[:WEBrickSocket] = nil
+ if addr
+ @logger.debug "close: #{addr[3]}:#{addr[1]}"
+ else
+ @logger.debug "close: <address unknown>"
+ end
+ sock.close
+ end
+ }
+ end
+
+ ##
+ # Calls the callback +callback_name+ from the configuration with +args+
+
+ def call_callback(callback_name, *args)
+ @config[callback_name]&.call(*args)
+ end
+
+ def setup_shutdown_pipe
+ return @shutdown_pipe ||= IO.pipe
+ end
+
+ def cleanup_shutdown_pipe(shutdown_pipe)
+ @shutdown_pipe = nil
+ shutdown_pipe&.each(&:close)
+ end
+
+ def alarm_shutdown_pipe
+ _, pipe = @shutdown_pipe # another thread may modify @shutdown_pipe.
+ if pipe
+ if !pipe.closed?
+ begin
+ yield pipe
+ rescue IOError # closed by another thread.
+ end
+ end
+ end
+ end
+
+ def cleanup_listener
+ @listeners.each{|s|
+ if @logger.debug?
+ addr = s.addr
+ @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
+ end
+ begin
+ s.shutdown
+ rescue Errno::ENOTCONN
+ # when 'Errno::ENOTCONN: Socket is not connected' on some platforms,
+ # call #close instead of #shutdown.
+ # (ignore @config[:ShutdownSocketWithoutClose])
+ s.close
+ else
+ unless @config[:ShutdownSocketWithoutClose]
+ s.close
+ end
+ end
+ }
+ @listeners.clear
+ end
+ end # end of GenericServer
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/ssl.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/ssl.rb
new file mode 100644
index 0000000..6937f93
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/ssl.rb
@@ -0,0 +1,219 @@
+# frozen_string_literal: true
+#
+# ssl.rb -- SSL/TLS enhancement for GenericServer
+#
+# Copyright (c) 2003 GOTOU Yuuzou All rights reserved.
+#
+# $Id$
+
+require 'webrick'
+require 'openssl'
+
+module WEBrick
+ module Config
+ svrsoft = General[:ServerSoftware]
+ osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
+
+ ##
+ # Default SSL server configuration.
+ #
+ # WEBrick can automatically create a self-signed certificate if
+ # <code>:SSLCertName</code> is set. For more information on the various
+ # SSL options see OpenSSL::SSL::SSLContext.
+ #
+ # :ServerSoftware ::
+ # The server software name used in the Server: header.
+ # :SSLEnable :: false,
+ # Enable SSL for this server. Defaults to false.
+ # :SSLCertificate ::
+ # The SSL certificate for the server.
+ # :SSLPrivateKey ::
+ # The SSL private key for the server certificate.
+ # :SSLClientCA :: nil,
+ # Array of certificates that will be sent to the client.
+ # :SSLExtraChainCert :: nil,
+ # Array of certificates that will be added to the certificate chain
+ # :SSLCACertificateFile :: nil,
+ # Path to a CA certificate file
+ # :SSLCACertificatePath :: nil,
+ # Path to a directory containing CA certificates
+ # :SSLCertificateStore :: nil,
+ # OpenSSL::X509::Store used for certificate validation of the client
+ # :SSLTmpDhCallback :: nil,
+ # Callback invoked when DH parameters are required.
+ # :SSLVerifyClient ::
+ # Sets whether the client is verified. This defaults to VERIFY_NONE
+ # which is typical for an HTTPS server.
+ # :SSLVerifyDepth ::
+ # Number of CA certificates to walk when verifying a certificate chain
+ # :SSLVerifyCallback ::
+ # Custom certificate verification callback
+ # :SSLServerNameCallback::
+ # Custom servername indication callback
+ # :SSLTimeout ::
+ # Maximum session lifetime
+ # :SSLOptions ::
+ # Various SSL options
+ # :SSLCiphers ::
+ # Ciphers to be used
+ # :SSLStartImmediately ::
+ # Immediately start SSL upon connection? Defaults to true
+ # :SSLCertName ::
+ # SSL certificate name. Must be set to enable automatic certificate
+ # creation.
+ # :SSLCertComment ::
+ # Comment used during automatic certificate creation.
+
+ SSL = {
+ :ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}",
+ :SSLEnable => false,
+ :SSLCertificate => nil,
+ :SSLPrivateKey => nil,
+ :SSLClientCA => nil,
+ :SSLExtraChainCert => nil,
+ :SSLCACertificateFile => nil,
+ :SSLCACertificatePath => nil,
+ :SSLCertificateStore => nil,
+ :SSLTmpDhCallback => nil,
+ :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
+ :SSLVerifyDepth => nil,
+ :SSLVerifyCallback => nil, # custom verification
+ :SSLTimeout => nil,
+ :SSLOptions => nil,
+ :SSLCiphers => nil,
+ :SSLStartImmediately => true,
+ # Must specify if you use auto generated certificate.
+ :SSLCertName => nil,
+ :SSLCertComment => "Generated by Ruby/OpenSSL"
+ }
+ General.update(SSL)
+ end
+
+ module Utils
+ ##
+ # Creates a self-signed certificate with the given number of +bits+,
+ # the issuer +cn+ and a +comment+ to be stored in the certificate.
+
+ def create_self_signed_cert(bits, cn, comment)
+ rsa = if $VERBOSE
+ OpenSSL::PKey::RSA.new(bits){|p, n|
+ case p
+ when 0; $stderr.putc "." # BN_generate_prime
+ when 1; $stderr.putc "+" # BN_generate_prime
+ when 2; $stderr.putc "*" # searching good prime,
+ # n = #of try,
+ # but also data from BN_generate_prime
+ when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
+ # but also data from BN_generate_prime
+ else; $stderr.putc "*" # BN_generate_prime
+ end
+ }
+ else
+ OpenSSL::PKey::RSA.new(bits)
+ end
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 1
+ name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn)
+ : OpenSSL::X509::Name.new(cn)
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + (365*24*60*60)
+ cert.public_key = rsa.public_key
+
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+ ef.issuer_certificate = cert
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("keyUsage", "keyEncipherment, digitalSignature, keyAgreement, dataEncipherment"),
+ ef.create_extension("subjectKeyIdentifier", "hash"),
+ ef.create_extension("extendedKeyUsage", "serverAuth"),
+ ef.create_extension("nsComment", comment),
+ ]
+ aki = ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always")
+ cert.add_extension(aki)
+ cert.sign(rsa, "SHA256")
+
+ return [ cert, rsa ]
+ end
+ module_function :create_self_signed_cert
+ end
+
+ ##
+ #--
+ # Updates WEBrick::GenericServer with SSL functionality
+
+ class GenericServer
+
+ ##
+ # SSL context for the server when run in SSL mode
+
+ def ssl_context # :nodoc:
+ @ssl_context ||= begin
+ if @config[:SSLEnable]
+ ssl_context = setup_ssl_context(@config)
+ @logger.info("\n" + @config[:SSLCertificate].to_text)
+ ssl_context
+ end
+ end
+ end
+
+ undef listen
+
+ ##
+ # Updates +listen+ to enable SSL when the SSL configuration is active.
+
+ def listen(address, port) # :nodoc:
+ listeners = Utils::create_listeners(address, port)
+ if @config[:SSLEnable]
+ listeners.collect!{|svr|
+ ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
+ ssvr.start_immediately = @config[:SSLStartImmediately]
+ ssvr
+ }
+ end
+ @listeners += listeners
+ setup_shutdown_pipe
+ end
+
+ ##
+ # Sets up an SSL context for +config+
+
+ def setup_ssl_context(config) # :nodoc:
+ unless config[:SSLCertificate]
+ cn = config[:SSLCertName]
+ comment = config[:SSLCertComment]
+ cert, key = Utils::create_self_signed_cert(2048, cn, comment)
+ config[:SSLCertificate] = cert
+ config[:SSLPrivateKey] = key
+ end
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.key = config[:SSLPrivateKey]
+ ctx.cert = config[:SSLCertificate]
+ ctx.client_ca = config[:SSLClientCA]
+ ctx.extra_chain_cert = config[:SSLExtraChainCert]
+ ctx.ca_file = config[:SSLCACertificateFile]
+ ctx.ca_path = config[:SSLCACertificatePath]
+ ctx.cert_store = config[:SSLCertificateStore]
+ ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
+ ctx.verify_mode = config[:SSLVerifyClient]
+ ctx.verify_depth = config[:SSLVerifyDepth]
+ ctx.verify_callback = config[:SSLVerifyCallback]
+ ctx.servername_cb = config[:SSLServerNameCallback] || proc { |args| ssl_servername_callback(*args) }
+ ctx.timeout = config[:SSLTimeout]
+ ctx.options = config[:SSLOptions]
+ ctx.ciphers = config[:SSLCiphers]
+ ctx
+ end
+
+ ##
+ # ServerNameIndication callback
+
+ def ssl_servername_callback(sslsocket, hostname = nil)
+ # default
+ end
+
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/utils.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/utils.rb
new file mode 100644
index 0000000..e4902d0
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/utils.rb
@@ -0,0 +1,265 @@
+# frozen_string_literal: true
+#
+# utils.rb -- Miscellaneous utilities
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $
+
+require 'socket'
+require 'io/nonblock'
+require 'etc'
+
+module WEBrick
+ module Utils
+ ##
+ # Sets IO operations on +io+ to be non-blocking
+ def set_non_blocking(io)
+ io.nonblock = true if io.respond_to?(:nonblock=)
+ end
+ module_function :set_non_blocking
+
+ ##
+ # Sets the close on exec flag for +io+
+ def set_close_on_exec(io)
+ io.close_on_exec = true if io.respond_to?(:close_on_exec=)
+ end
+ module_function :set_close_on_exec
+
+ ##
+ # Changes the process's uid and gid to the ones of +user+
+ def su(user)
+ if pw = Etc.getpwnam(user)
+ Process::initgroups(user, pw.gid)
+ Process::Sys::setgid(pw.gid)
+ Process::Sys::setuid(pw.uid)
+ else
+ warn("WEBrick::Utils::su doesn't work on this platform", uplevel: 1)
+ end
+ end
+ module_function :su
+
+ ##
+ # The server hostname
+ def getservername
+ Socket::gethostname
+ end
+ module_function :getservername
+
+ ##
+ # Creates TCP server sockets bound to +address+:+port+ and returns them.
+ #
+ # It will create IPV4 and IPV6 sockets on all interfaces.
+ def create_listeners(address, port)
+ unless port
+ raise ArgumentError, "must specify port"
+ end
+ sockets = Socket.tcp_server_sockets(address, port)
+ sockets = sockets.map {|s|
+ s.autoclose = false
+ ts = TCPServer.for_fd(s.fileno)
+ s.close
+ ts
+ }
+ return sockets
+ end
+ module_function :create_listeners
+
+ ##
+ # Characters used to generate random strings
+ RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "0123456789" +
+ "abcdefghijklmnopqrstuvwxyz"
+
+ ##
+ # Generates a random string of length +len+
+ def random_string(len)
+ rand_max = RAND_CHARS.bytesize
+ ret = +""
+ len.times{ ret << RAND_CHARS[rand(rand_max)] }
+ ret
+ end
+ module_function :random_string
+
+ ###########
+
+ require "timeout"
+ require "singleton"
+
+ ##
+ # Class used to manage timeout handlers across multiple threads.
+ #
+ # Timeout handlers should be managed by using the class methods which are
+ # synchronized.
+ #
+ # id = TimeoutHandler.register(10, Timeout::Error)
+ # begin
+ # sleep 20
+ # puts 'foo'
+ # ensure
+ # TimeoutHandler.cancel(id)
+ # end
+ #
+ # will raise Timeout::Error
+ #
+ # id = TimeoutHandler.register(10, Timeout::Error)
+ # begin
+ # sleep 5
+ # puts 'foo'
+ # ensure
+ # TimeoutHandler.cancel(id)
+ # end
+ #
+ # will print 'foo'
+ #
+ class TimeoutHandler
+ include Singleton
+
+ ##
+ # Mutex used to synchronize access across threads
+ TimeoutMutex = Thread::Mutex.new # :nodoc:
+
+ ##
+ # Registers a new timeout handler
+ #
+ # +time+:: Timeout in seconds
+ # +exception+:: Exception to raise when timeout elapsed
+ def TimeoutHandler.register(seconds, exception)
+ at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
+ instance.register(Thread.current, at, exception)
+ end
+
+ ##
+ # Cancels the timeout handler +id+
+ def TimeoutHandler.cancel(id)
+ instance.cancel(Thread.current, id)
+ end
+
+ def self.terminate
+ instance.terminate
+ end
+
+ ##
+ # Creates a new TimeoutHandler. You should use ::register and ::cancel
+ # instead of creating the timeout handler directly.
+ def initialize
+ TimeoutMutex.synchronize{
+ @timeout_info = Hash.new
+ }
+ @queue = Thread::Queue.new
+ @watcher = nil
+ end
+
+ # :nodoc:
+ private \
+ def watch
+ to_interrupt = []
+ while true
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ wakeup = nil
+ to_interrupt.clear
+ TimeoutMutex.synchronize{
+ @timeout_info.each {|thread, ary|
+ next unless ary
+ ary.each{|info|
+ time, exception = *info
+ if time < now
+ to_interrupt.push [thread, info.object_id, exception]
+ elsif !wakeup || time < wakeup
+ wakeup = time
+ end
+ }
+ }
+ }
+ to_interrupt.each {|arg| interrupt(*arg)}
+ if !wakeup
+ @queue.pop
+ elsif (wakeup -= now) > 0
+ begin
+ (th = Thread.start {@queue.pop}).join(wakeup)
+ ensure
+ th&.kill&.join
+ end
+ end
+ @queue.clear
+ end
+ end
+
+ # :nodoc:
+ private \
+ def watcher
+ (w = @watcher)&.alive? and return w # usual case
+ TimeoutMutex.synchronize{
+ (w = @watcher)&.alive? and next w # pathological check
+ @watcher = Thread.start(&method(:watch))
+ }
+ end
+
+ ##
+ # Interrupts the timeout handler +id+ and raises +exception+
+ def interrupt(thread, id, exception)
+ if cancel(thread, id) && thread.alive?
+ thread.raise(exception, "execution timeout")
+ end
+ end
+
+ ##
+ # Registers a new timeout handler
+ #
+ # +time+:: Timeout in seconds
+ # +exception+:: Exception to raise when timeout elapsed
+ def register(thread, time, exception)
+ info = nil
+ TimeoutMutex.synchronize{
+ (@timeout_info[thread] ||= []) << (info = [time, exception])
+ }
+ @queue.push nil
+ watcher
+ return info.object_id
+ end
+
+ ##
+ # Cancels the timeout handler +id+
+ def cancel(thread, id)
+ TimeoutMutex.synchronize{
+ if ary = @timeout_info[thread]
+ ary.delete_if{|info| info.object_id == id }
+ if ary.empty?
+ @timeout_info.delete(thread)
+ end
+ return true
+ end
+ return false
+ }
+ end
+
+ ##
+ def terminate
+ TimeoutMutex.synchronize{
+ @timeout_info.clear
+ @watcher&.kill&.join
+ }
+ end
+ end
+
+ ##
+ # Executes the passed block and raises +exception+ if execution takes more
+ # than +seconds+.
+ #
+ # If +seconds+ is zero or nil, simply executes the block
+ def timeout(seconds, exception=Timeout::Error)
+ return yield if seconds.nil? or seconds.zero?
+ # raise ThreadError, "timeout within critical session" if Thread.critical
+ id = TimeoutHandler.register(seconds, exception)
+ begin
+ yield(seconds)
+ ensure
+ TimeoutHandler.cancel(id)
+ end
+ end
+ module_function :timeout
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/version.rb b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/version.rb
new file mode 100644
index 0000000..0debb77
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/version.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+#--
+# version.rb -- version and release date
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: version.rb,v 1.74 2003/07/22 19:20:43 gotoyuzo Exp $
+
+module WEBrick
+
+ ##
+ # The WEBrick version
+
+ VERSION = "1.9.2"
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/accesslog.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/accesslog.rbs
new file mode 100644
index 0000000..ffdb91d
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/accesslog.rbs
@@ -0,0 +1,24 @@
+module WEBrick
+ module AccessLog
+ class AccessLogError < StandardError
+ end
+
+ CLF_TIME_FORMAT: String
+
+ COMMON_LOG_FORMAT: String
+
+ CLF: String
+
+ REFERER_LOG_FORMAT: String
+
+ AGENT_LOG_FORMAT: String
+
+ COMBINED_LOG_FORMAT: String
+
+ def self?.setup_params: (Hash[Symbol, untyped] config, HTTPRequest req, HTTPResponse res) -> Hash[String, untyped]
+
+ def self?.format: (String format_string, Hash[String, untyped] params) -> String
+
+ def self?.escape: (String data) -> String
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cgi.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cgi.rbs
new file mode 100644
index 0000000..582adb7
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cgi.rbs
@@ -0,0 +1,92 @@
+module WEBrick
+ class CGI
+ @options: Array[untyped]
+
+ class CGIError < StandardError
+ end
+
+ attr_reader config: Hash[Symbol, untyped]
+
+ attr_reader logger: BasicLog
+
+ def initialize: (*untyped args) -> void
+
+ def []: (Symbol key) -> untyped
+
+ interface _Env
+ def []: (String) -> String?
+ end
+
+ def start: (?_Env env, ?IO stdin, ?IO stdout) -> void
+
+ def self.setup_header: () -> untyped
+
+ def self.status_line: () -> ""
+
+ def service: (HTTPRequest req, HTTPResponse res) -> void
+
+ class Socket
+ @config: Hash[Symbol, untyped]
+
+ @env: _Env
+
+ @header_part: StringIO
+
+ @body_part: IO
+
+ @out_port: IO
+
+ @server_addr: String
+
+ @server_name: String?
+
+ @server_port: String?
+
+ @remote_addr: String?
+
+ @remote_host: String?
+
+ @remote_port: (String | 0)
+
+ include Enumerable[String]
+
+ private
+
+ def initialize: (Hash[Symbol, untyped] config, _Env env, IO stdin, IO stdout) -> void
+
+ def request_line: () -> String
+
+ def setup_header: () -> void
+
+ def add_header: (String hdrname, String value) -> void
+
+ def input: () -> (IO | StringIO)
+
+ public
+
+ def peeraddr: () -> [nil, (String | 0), String?, String?]
+
+ def addr: () -> [nil, String?, String?, String]
+
+ def gets: (?String eol, ?Integer? size) -> String?
+
+ def read: (?Integer? size) -> String?
+
+ def each: () { (String) -> void } -> void
+
+ def eof?: () -> bool
+
+ def <<: (_ToS data) -> IO
+
+ def write: (_ToS data) -> Integer
+
+ def cert: () -> OpenSSL::X509::Certificate?
+
+ def peer_cert: () -> OpenSSL::X509::Certificate?
+
+ def peer_cert_chain: () -> Array[OpenSSL::X509::Certificate]?
+
+ def cipher: () -> [String?, String?, String?, String?]?
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/compat.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/compat.rbs
new file mode 100644
index 0000000..8d5b745
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/compat.rbs
@@ -0,0 +1,18 @@
+#
+# System call error module used by webrick for cross platform compatibility.
+#
+# EPROTO:: protocol error
+# ECONNRESET:: remote host reset the connection request
+# ECONNABORTED:: Client sent TCP reset (RST) before server has accepted the
+# connection requested by client.
+#
+module Errno
+ class EPROTO < SystemCallError
+ end
+
+ class ECONNRESET < SystemCallError
+ end
+
+ class ECONNABORTED < SystemCallError
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/config.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/config.rbs
new file mode 100644
index 0000000..be0a6a6
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/config.rbs
@@ -0,0 +1,17 @@
+module WEBrick
+ module Config
+ LIBDIR: String
+
+ # for GenericServer
+ General: Hash[Symbol, untyped]
+
+ # for HTTPServer, HTTPRequest, HTTPResponse ...
+ HTTP: Hash[Symbol, untyped]
+
+ FileHandler: Hash[Symbol, untyped]
+
+ BasicAuth: Hash[Symbol, untyped]
+
+ DigestAuth: Hash[Symbol, untyped]
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cookie.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cookie.rbs
new file mode 100644
index 0000000..6a7dc10
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cookie.rbs
@@ -0,0 +1,37 @@
+module WEBrick
+ class Cookie
+ @expires: String?
+
+ attr_reader name: String?
+
+ attr_accessor value: String?
+
+ attr_accessor version: Integer
+
+ #
+ # The cookie domain
+ attr_accessor domain: String?
+
+ attr_accessor path: String?
+
+ attr_accessor secure: true?
+
+ attr_accessor comment: String?
+
+ attr_accessor max_age: Integer?
+
+ def initialize: (untyped name, untyped value) -> void
+
+ def expires=: ((Time | _ToS)? t) -> untyped
+
+ def expires: () -> Time?
+
+ def to_s: () -> String
+
+ def self.parse: (String? str) -> Array[instance]?
+
+ def self.parse_set_cookie: (String str) -> instance
+
+ def self.parse_set_cookies: (String str) -> Array[instance]
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/htmlutils.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/htmlutils.rbs
new file mode 100644
index 0000000..00331b6
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/htmlutils.rbs
@@ -0,0 +1,5 @@
+module WEBrick
+ module HTMLUtils
+ def self?.escape: (String? string) -> String
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth.rbs
new file mode 100644
index 0000000..90f2977
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth.rbs
@@ -0,0 +1,13 @@
+module WEBrick
+ module HTTPAuth
+ interface _Callable
+ def call: (String user, String pass) -> bool
+ end
+
+ def self?._basic_auth: (HTTPRequest req, HTTPResponse res, String realm, String req_field, String res_field, HTTPStatus::Error err_type, _Callable block) -> void
+
+ def self?.basic_auth: (HTTPRequest req, HTTPResponse res, String realm) { (String user, String pass) -> bool } -> void
+
+ def self?.proxy_basic_auth: (HTTPRequest req, HTTPResponse res, String realm) { (String user, String pass) -> bool } -> void
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/authenticator.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/authenticator.rbs
new file mode 100644
index 0000000..fe94762
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/authenticator.rbs
@@ -0,0 +1,55 @@
+module WEBrick
+ module HTTPAuth
+ module Authenticator
+ @reload_db: bool?
+
+ @request_field: String
+
+ @response_field: String
+
+ @resp_info_field: String
+
+ @auth_exception: singleton(HTTPStatus::ClientError)
+
+ @auth_scheme: String
+
+ RequestField: String
+
+ ResponseField: String
+
+ ResponseInfoField: String
+
+ AuthException: singleton(HTTPStatus::ClientError)
+
+ AuthScheme: String?
+
+ attr_reader realm: String?
+
+ attr_reader userdb: UserDB
+
+ attr_reader logger: Log
+
+ private
+
+ def check_init: (Hash[Symbol, untyped] config) -> void
+
+ def check_scheme: (HTTPRequest req) -> String?
+
+ def log: (interned meth, String fmt, *untyped args) -> void
+
+ def error: (String fmt, *untyped args) -> void
+
+ def info: (String fmt, *untyped args) -> void
+ end
+
+ module ProxyAuthenticator
+ RequestField: String
+
+ ResponseField: String
+
+ ResponseInfoField: String
+
+ AuthException: singleton(HTTPStatus::ClientError)
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/basicauth.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/basicauth.rbs
new file mode 100644
index 0000000..4eb41df
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/basicauth.rbs
@@ -0,0 +1,29 @@
+module WEBrick
+ module HTTPAuth
+ class BasicAuth
+ @config: Hash[Symbol, untyped]
+
+ include Authenticator
+
+ AuthScheme: String
+
+ def self.make_passwd: (String? realm, String? user, String? pass) -> String
+
+ attr_reader realm: String?
+
+ attr_reader userdb: UserDB
+
+ attr_reader logger: Log
+
+ def initialize: (Hash[Symbol, untyped] config, ?Hash[Symbol, untyped] default) -> void
+
+ def authenticate: (HTTPRequest req, HTTPResponse res) -> void
+
+ def challenge: (HTTPRequest req, HTTPResponse res) -> bot
+ end
+
+ class ProxyBasicAuth < BasicAuth
+ include ProxyAuthenticator
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/digestauth.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/digestauth.rbs
new file mode 100644
index 0000000..8d12f91
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/digestauth.rbs
@@ -0,0 +1,85 @@
+module WEBrick
+ module HTTPAuth
+ class DigestAuth
+ @config: Hash[Symbol, untyped]
+
+ @domain: Array[String]?
+
+ @use_opaque: bool
+
+ @use_next_nonce: bool
+
+ @check_nc: bool
+
+ @use_auth_info_header: bool
+
+ @nonce_expire_period: Integer
+
+ @nonce_expire_delta: Integer
+
+ @internet_explorer_hack: bool
+
+ @h: singleton(Digest::Base)
+
+ @instance_key: String
+
+ @opaques: Hash[String, OpaqueInfo]
+
+ @last_nonce_expire: Time
+
+ @mutex: Thread::Mutex
+
+ include Authenticator
+
+ AuthScheme: String
+
+ class OpaqueInfo < Struct[untyped]
+ attr_accessor time(): Time
+ attr_accessor nonce(): String?
+ attr_accessor nc(): String
+ end
+
+ attr_reader algorithm: String?
+
+ attr_reader qop: Array[String]
+
+ def self.make_passwd: (String realm, String user, String pass) -> untyped
+
+ def initialize: (Hash[Symbol, untyped] config, ?Hash[Symbol, untyped] default) -> void
+
+ def authenticate: (HTTPRequest req, HTTPResponse res) -> void
+
+ def challenge: (HTTPRequest req, HTTPResponse res, ?bool stale) -> bot
+
+ private
+
+ MustParams: Array[String]
+
+ MustParamsAuth: Array[String]
+
+ def _authenticate: (HTTPRequest req, HTTPResponse res) -> (:nonce_is_stale | bool)
+
+ def split_param_value: (String string) -> Hash[String, String]
+
+ def generate_next_nonce: (HTTPRequest req) -> String
+
+ def check_nonce: (HTTPRequest req, Hash[String, String] auth_req) -> bool
+
+ def generate_opaque: (HTTPRequest req) -> String
+
+ def check_opaque: (OpaqueInfo opaque_struct, untyped req, Hash[String, String] auth_req) -> bool
+
+ def check_uri: (HTTPRequest req, Hash[String, String] auth_req) -> bool
+
+ def hexdigest: (*_ToS? args) -> String
+ end
+
+ class ProxyDigestAuth < DigestAuth
+ include ProxyAuthenticator
+
+ private
+
+ def check_uri: (HTTPRequest req, Hash[String, String] auth_req) -> true
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htdigest.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htdigest.rbs
new file mode 100644
index 0000000..19037e7
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htdigest.rbs
@@ -0,0 +1,31 @@
+module WEBrick
+ module HTTPAuth
+ class Htdigest
+ @path: String
+
+ @mtime: Time
+
+ @digest: Hash[String, Hash[String, String]]
+
+ @mutex: Thread::Mutex
+
+ @auth_type: String
+
+ include UserDB
+
+ def initialize: (String path) -> void
+
+ def reload: () -> void
+
+ def flush: (?String? output) -> void
+
+ def get_passwd: (String realm, String user, bool reload_db) -> String?
+
+ def set_passwd: (String realm, String user, String pass) -> String
+
+ def delete_passwd: (String realm, String user) -> String?
+
+ def each: () { (String user, String realm, String password_hash) -> void } -> void
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htgroup.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htgroup.rbs
new file mode 100644
index 0000000..00ca7a6
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htgroup.rbs
@@ -0,0 +1,21 @@
+module WEBrick
+ module HTTPAuth
+ class Htgroup
+ @path: String
+
+ @mtime: Time
+
+ @group: Hash[String, Array[String]]
+
+ def initialize: (String path) -> void
+
+ def reload: () -> void
+
+ def flush: (?String? output) -> void
+
+ def members: (String group) -> Array[String]
+
+ def add: (String group, Array[String] members) -> void
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htpasswd.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htpasswd.rbs
new file mode 100644
index 0000000..6b4cc3e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htpasswd.rbs
@@ -0,0 +1,31 @@
+module WEBrick
+ module HTTPAuth
+ class Htpasswd
+ @path: String
+
+ @mtime: Time
+
+ @passwd: Hash[String, String]
+
+ @auth_type: String
+
+ @password_hash: (:crypt | :bcrypt)
+
+ include UserDB
+
+ def initialize: (String path, ?password_hash: (:crypt | :bcrypt)?) -> void
+
+ def reload: () -> void
+
+ def flush: (?String? output) -> void
+
+ def get_passwd: (String realm, String user, bool reload_db) -> String?
+
+ def set_passwd: (String realm, String user, String pass) -> void
+
+ def delete_passwd: (String realm, String user) -> String
+
+ def each: () { ([String, String]) -> void } -> void
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/userdb.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/userdb.rbs
new file mode 100644
index 0000000..a6aefd9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/userdb.rbs
@@ -0,0 +1,13 @@
+module WEBrick
+ module HTTPAuth
+ module UserDB
+ attr_accessor auth_type: String
+
+ def make_passwd: (String realm, String user, String pass) -> String
+
+ def set_passwd: (String realm, String user, String pass) -> void
+
+ def get_passwd: (String realm, String user, ?bool reload_db) -> String
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpproxy.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpproxy.rbs
new file mode 100644
index 0000000..c2bc26b
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpproxy.rbs
@@ -0,0 +1,61 @@
+module WEBrick
+ NullReader: untyped
+
+ def self.read: (*untyped args) -> nil
+
+ alias self.gets self.read
+
+ FakeProxyURI: untyped
+
+ def self.method_missing: (untyped meth, *untyped args) -> (nil | untyped)
+
+ class HTTPProxyServer < HTTPServer
+ @via: untyped
+
+ def initialize: (?::Hash[untyped, untyped] config, ?untyped default) -> void
+
+ # :stopdoc:
+ def service: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def proxy_auth: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def proxy_uri: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def proxy_service: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def do_CONNECT: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def do_GET: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def do_HEAD: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def do_POST: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def do_OPTIONS: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ private
+
+ # Some header fields should not be transferred.
+ HopByHop: ::Array["connection" | "keep-alive" | "proxy-authenticate" | "upgrade" | "proxy-authorization" | "te" | "trailers" | "transfer-encoding"]
+
+ ShouldNotTransfer: ::Array["set-cookie" | "proxy-connection"]
+
+ def split_field: (untyped f) -> (untyped | ::Array[untyped])
+
+ def choose_header: (untyped src, untyped dst) -> untyped
+
+ # Net::HTTP is stupid about the multiple header fields.
+ # Here is workaround:
+ def set_cookie: (untyped src, untyped dst) -> (untyped | nil)
+
+ def set_via: (untyped h) -> (untyped | nil)
+
+ def setup_proxy_header: (HTTPRequest req, HTTPResponse res) -> untyped
+
+ def setup_upstream_proxy_authentication: (HTTPRequest req, HTTPResponse res, untyped header) -> untyped
+
+ def create_net_http: (untyped uri, untyped upstream) -> untyped
+
+ def perform_proxy_request: (HTTPRequest req, HTTPResponse res, untyped req_class, ?untyped? body_stream) -> untyped
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httprequest.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httprequest.rbs
new file mode 100644
index 0000000..82c229e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httprequest.rbs
@@ -0,0 +1,167 @@
+module WEBrick
+ class HTTPRequest
+ @config: Hash[Symbol, untyped]
+
+ @buffer_size: Integer
+
+ @logger: Log
+
+ @query: Hash[String, HTTPUtils::FormData]?
+
+ @body: String
+
+ @remaining_size: Integer?
+
+ @socket: TCPSocket?
+
+ @forwarded_proto: String?
+
+ @host: String?
+
+ @port: Integer?
+
+ @body_tmp: Array[String]
+
+ @body_rd: Fiber
+
+ @request_bytes: Integer
+
+ @forwarded_server: String?
+
+ @forwarded_host: String?
+
+ @forwarded_port: Integer?
+
+ @forwarded_for: String?
+
+ BODY_CONTAINABLE_METHODS: Array[String]
+
+ attr_reader request_line: String?
+
+ attr_reader request_method: String?
+
+ attr_reader unparsed_uri: String?
+
+ attr_reader http_version: HTTPVersion?
+
+ attr_reader request_uri: URI::Generic?
+
+ attr_reader path: String?
+
+ attr_accessor script_name: String?
+
+ attr_accessor path_info: String?
+
+ attr_accessor query_string: String?
+
+ attr_reader raw_header: Array[String]
+
+ attr_reader header: Hash[String, Array[String]]?
+
+ attr_reader cookies: Array[Cookie]
+
+ attr_reader accept: Array[String]
+
+ attr_reader accept_charset: Array[String]
+
+ attr_reader accept_encoding: Array[String]
+
+ attr_reader accept_language: Array[String]
+
+ attr_accessor user: String?
+
+ attr_reader addr: ([String, Integer, String, String] | [])
+
+ attr_reader peeraddr: ([String, Integer, String, String] | [])
+
+ attr_reader attributes: Hash[untyped, untyped]
+
+ attr_reader keep_alive: bool
+
+ attr_reader request_time: Time?
+
+ def initialize: (Hash[Symbol, untyped] config) -> void
+
+ def parse: (?TCPSocket? socket) -> void
+
+ def continue: () -> void
+
+ type body_chunk_block = ^(String body_chunk) -> void
+
+ def body: () ?{ (String body_chunk) -> void } -> String
+
+ def body_reader: () -> self
+
+ # for IO.copy_stream.
+ def readpartial: (Integer size, ?String buf) -> String
+
+ def query: () -> Hash[String, HTTPUtils::FormData]
+
+ def content_length: () -> Integer
+
+ def content_type: () -> String?
+
+ def []: (String header_name) -> String?
+
+ def each: [T] () { (String, String) -> T } -> T?
+
+ def host: () -> String?
+
+ def port: () -> Integer?
+
+ def server_name: () -> String?
+
+ def remote_ip: () -> String?
+
+ def ssl?: () -> bool
+
+ def keep_alive?: () -> bool
+
+ def to_s: () -> String
+
+ def fixup: () -> void
+
+ def meta_vars: () -> Hash[String, String]
+
+ private
+
+ MAX_URI_LENGTH: Integer
+
+ # same as Mongrel, Thin and Puma
+ MAX_HEADER_LENGTH: Integer
+
+ def read_request_line: (IO socket) -> void
+
+ def read_header: (IO socket) -> void
+
+ def parse_uri: (String str, ?String scheme) -> URI::Generic
+
+ HOST_PATTERN: Regexp
+
+ def parse_host_request_line: (String host) -> [String, String]
+
+ def read_body: (IO socket, body_chunk_block block) -> String
+ | (nil socket, top block) -> nil
+
+ def read_chunk_size: (IO socket) -> [Integer, String?]
+
+ def read_chunked: (IO socket, body_chunk_block block) -> void
+
+ def _read_data: (IO io, Symbol method, *untyped arg) -> String?
+
+ def read_line: (IO io, ?Integer size) -> String?
+
+ def read_data: (IO io, Integer size) -> String?
+
+ def parse_query: () -> void
+
+ PrivateNetworkRegexp: Regexp
+
+ # It's said that all X-Forwarded-* headers will contain more than one
+ # (comma-separated) value if the original request already contained one of
+ # these headers. Since we could use these values as Host header, we choose
+ # the initial(first) value. (apr_table_mergen() adds new value after the
+ # existing value with ", " prefix)
+ def setup_forwarded_info: () -> void
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpresponse.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpresponse.rbs
new file mode 100644
index 0000000..2baf093
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpresponse.rbs
@@ -0,0 +1,117 @@
+module WEBrick
+ class HTTPResponse
+ @buffer_size: Integer
+
+ @logger: Log
+
+ @chunked: bool
+
+ @bodytempfile: File | Tempfile | nil
+
+ class InvalidHeader < StandardError
+ end
+
+ attr_reader http_version: HTTPVersion
+
+ attr_reader status: Integer
+
+ attr_reader header: Hash[String, String]
+
+ attr_reader cookies: Array[Cookie]
+
+ attr_accessor reason_phrase: String
+
+ interface _CallableBody
+ def call: (_Writer) -> void
+ end
+
+ attr_accessor body: String | _ReaderPartial | _CallableBody
+
+ attr_accessor request_method: String?
+
+ attr_accessor request_uri: URI::Generic?
+
+ attr_accessor request_http_version: HTTPVersion?
+
+ attr_accessor filename: String?
+
+ attr_accessor keep_alive: bool
+
+ attr_reader config: Hash[Symbol, untyped]
+
+ attr_reader sent_size: Integer
+
+ attr_accessor upgrade: String?
+
+ def initialize: (Hash[Symbol, untyped] config) -> void
+
+ def status_line: () -> String
+
+ def status=: (Integer status) -> Integer
+
+ def []: (String field) -> String?
+
+ def []=: (String field, _ToS value) -> _ToS
+
+ def content_length: () -> Integer?
+
+ def content_length=: (Integer len) -> Integer
+
+ def content_type: () -> String?
+
+ def content_type=: (String type) -> String
+
+ def each: () { (String, String) -> void } -> void
+
+ def chunked?: () -> bool
+
+ def chunked=: (boolish val) -> boolish
+
+ def keep_alive?: () -> bool
+
+ def upgrade!: (String protocol) -> void
+
+ def send_response: (_Writer socket) -> void
+
+ def setup_header: () -> void
+
+ def make_body_tempfile: () -> void
+
+ def remove_body_tempfile: () -> void
+
+ def send_header: (_Writer socket) -> void
+
+ def send_body: (_Writer socket) -> void
+
+ def set_redirect: (singleton(WEBrick::HTTPStatus::Redirect) status, URI::Generic | String url) -> bot
+
+ def set_error: (singleton(Exception) ex, ?bool backtrace) -> void
+
+ private
+
+ def check_header: (_ToS header_value) -> String
+
+ def error_body: (bool backtrace, singleton(Exception) ex, String? host, Integer? port) -> void
+
+ def send_body_io: (_Writer socket) -> void
+
+ def send_body_string: (_Writer socket) -> void
+
+ def send_body_proc: (_Writer socket) -> void
+
+ class ChunkedWrapper
+ @socket: _Writer
+
+ @resp: HTTPResponse
+
+ def initialize: (_Writer socket, HTTPResponse resp) -> void
+
+ def write: (_ToS buf) -> Integer
+
+ def <<: (*_ToS buf) -> self
+ end
+
+ # preserved for compatibility with some 3rd-party handlers
+ def _write_data: [T] (T socket, _ToS data) -> T
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/https.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/https.rbs
new file mode 100644
index 0000000..43dcd1e
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/https.rbs
@@ -0,0 +1,49 @@
+module WEBrick
+ class HTTPRequest
+ @client_cert_chain: Array[OpenSSL::X509::Certificate]
+
+ attr_reader cipher: [String, String, Integer, Integer]?
+
+ attr_reader server_cert: OpenSSL::X509::Certificate
+
+ attr_reader client_cert: OpenSSL::X509::Certificate?
+
+ alias orig_parse parse
+
+ def parse: (?(TCPSocket | OpenSSL::SSL::SSLSocket)? socket) -> void
+ | ...
+
+ alias orig_parse_uri parse_uri
+
+ private
+
+ def parse_uri: (String str, ?::String scheme) -> URI::Generic
+ | ...
+
+ public
+
+ alias orig_meta_vars meta_vars
+
+ def meta_vars: () -> Hash[String, String]
+ | ...
+ end
+
+ class SNIRequest
+ attr_reader host: String?
+
+ attr_reader addr: [String, Integer, String, String]
+
+ attr_reader port: Integer
+
+ def initialize: (OpenSSL::SSL::SSLSocket sslsocket, ?String? hostname) -> void
+ end
+
+ class HTTPServer < ::WEBrick::GenericServer
+ def ssl_servername_callback: (OpenSSL::SSL::SSLSocket sslsocket, ?String? hostname) -> OpenSSL::SSL::SSLContext?
+
+ alias orig_virtual_host virtual_host
+
+ def virtual_host: (instance server) -> void
+ | ...
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpserver.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpserver.rbs
new file mode 100644
index 0000000..6c966e9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpserver.rbs
@@ -0,0 +1,71 @@
+module WEBrick
+ class HTTPServerError < ServerError
+ end
+
+ class HTTPServer < ::WEBrick::GenericServer
+ @http_version: HTTPVersion
+
+ @mount_tab: MountTable
+
+ @virtual_hosts: Array[untyped]
+
+ def initialize: (?Hash[Symbol, untyped] config, ?Hash[Symbol, untyped] default) -> void
+
+ def run: (TCPSocket sock) -> void
+
+ def service: (HTTPRequest req, HTTPResponse res) -> void
+
+ def do_OPTIONS: (HTTPRequest req, HTTPResponse res) -> void
+
+ def mount: (String dir, singleton(HTTPServlet::AbstractServlet) servlet, *untyped options) -> void
+
+ def mount_proc: (String dir, ?HTTPServlet::ProcHandler::_Callable proc) -> void
+ | (String dir, ?nil proc) { (HTTPRequest, HTTPResponse) -> void } -> void
+
+ def unmount: (String dir) -> MountTable::value_type
+
+ alias umount unmount
+
+ def search_servlet: (String path) -> [singleton(HTTPServlet::AbstractServlet), Array[untyped], String, String]?
+
+ def virtual_host: (instance server) -> void
+
+ def lookup_server: (HTTPRequest req) -> instance?
+
+ def access_log: (Hash[Symbol, untyped] config, HTTPRequest req, HTTPResponse res) -> void
+
+ #
+ # Creates the HTTPRequest used when handling the HTTP
+ # request. Can be overridden by subclasses.
+ def create_request: (Hash[Symbol, untyped] with_webrick_config) -> HTTPRequest
+
+ #
+ # Creates the HTTPResponse used when handling the HTTP
+ # request. Can be overridden by subclasses.
+ def create_response: (Hash[Symbol, untyped] with_webrick_config) -> HTTPResponse
+
+ class MountTable
+ type value_type = [singleton(HTTPServlet::AbstractServlet), Array[untyped]]
+
+ @tab: Hash[String, value_type]
+
+ @scanner: Regexp
+
+ def initialize: () -> void
+
+ def []: (String dir) -> value_type
+
+ def []=: (String dir, value_type val) -> value_type
+
+ def delete: (String dir) -> value_type
+
+ def scan: (String path) -> [String, String]
+
+ private
+
+ def compile: () -> void
+
+ def normalize: (String dir) -> String
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet.rbs
new file mode 100644
index 0000000..36122e9
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet.rbs
@@ -0,0 +1,4 @@
+module WEBrick
+ module HTTPServlet
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/abstract.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/abstract.rbs
new file mode 100644
index 0000000..b067deb
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/abstract.rbs
@@ -0,0 +1,36 @@
+module WEBrick
+ module HTTPServlet
+ class HTTPServletError < StandardError
+ end
+
+ class AbstractServlet
+ @server: HTTPServer
+
+ interface _Config
+ def []: (Symbol) -> untyped
+ end
+
+ @config: _Config
+
+ @logger: Log
+
+ @options: untyped # Array[untyped] causes RBS::InstanceVariableTypeError
+
+ def self.get_instance: (HTTPServer server, *untyped options) -> instance
+
+ def initialize: (HTTPServer server, *untyped options) -> void
+
+ def service: (HTTPRequest req, HTTPResponse res) -> void
+
+ def do_GET: (HTTPRequest req, HTTPResponse res) -> bot
+
+ def do_HEAD: (HTTPRequest req, HTTPResponse res) -> bot
+
+ def do_OPTIONS: (HTTPRequest req, HTTPResponse res) -> void
+
+ private
+
+ def redirect_to_directory_uri: (HTTPRequest req, HTTPResponse res) -> void
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgi_runner.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgi_runner.rbs
new file mode 100644
index 0000000..3112976
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgi_runner.rbs
@@ -0,0 +1,3 @@
+class Object
+ def sysread: (IO io, Integer size) -> String
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgihandler.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgihandler.rbs
new file mode 100644
index 0000000..f56427c
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgihandler.rbs
@@ -0,0 +1,23 @@
+module WEBrick
+ module HTTPServlet
+ class CGIHandler < AbstractServlet
+ @script_filename: String
+
+ @tempdir: String?
+
+ @cgicmd: Array[String] | String
+
+ Ruby: String
+
+ CGIRunner: String
+
+ CGIRunnerArray: [String, String]
+
+ def initialize: (HTTPServer server, String name) -> void
+
+ def do_GET: (HTTPRequest req, HTTPResponse res) -> void
+
+ alias do_POST do_GET
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/erbhandler.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/erbhandler.rbs
new file mode 100644
index 0000000..9ffa569
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/erbhandler.rbs
@@ -0,0 +1,17 @@
+module WEBrick
+ module HTTPServlet
+ class ERBHandler < AbstractServlet
+ @script_filename: String
+
+ def initialize: (HTTPServer server, String name) -> void
+
+ def do_GET: (HTTPRequest req, HTTPResponse res) -> void
+
+ alias do_POST do_GET
+
+ private
+
+ def evaluate: (ERB erb, HTTPRequest servlet_request, HTTPResponse servlet_response) -> String
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/filehandler.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/filehandler.rbs
new file mode 100644
index 0000000..792fd2a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/filehandler.rbs
@@ -0,0 +1,76 @@
+module WEBrick
+ module HTTPServlet
+ class DefaultFileHandler < AbstractServlet
+ @local_path: String
+
+ def initialize: (HTTPServer server, String local_path) -> void
+
+ def do_GET: (HTTPRequest req, HTTPResponse res) -> void
+
+ def not_modified?: (HTTPRequest req, HTTPResponse res, Time mtime, String etag) -> bool
+
+ # returns a lambda for webrick/httpresponse.rb send_body_proc
+ def multipart_body: (File body, Array[[Numeric, Numeric]] parts, String boundary, String mtype, Integer filesize) -> HTTPResponse::_CallableBody
+
+ def make_partial_content: (HTTPRequest req, HTTPResponse res, String filename, Integer filesize) -> void
+
+ def prepare_range: (Range[Integer] range, Integer filesize) -> [Numeric, Numeric]
+ end
+
+ class FileHandler < AbstractServlet
+ @config: AbstractServlet::_Config
+
+ @logger: Log
+
+ @root: String
+
+ @options: Hash[Symbol, untyped]
+
+ HandlerTable: Hash[String, singleton(AbstractServlet)]
+
+ def self.add_handler: (String suffix, singleton(AbstractServlet) handler) -> singleton(AbstractServlet)
+
+ def self.remove_handler: (String suffix) -> singleton(AbstractServlet)
+
+ def initialize: (HTTPServer server, String root, ?Hash[Symbol, untyped] options, ?Hash[Symbol, untyped] default) -> void
+
+ def set_filesystem_encoding: (String str) -> String
+
+ def service: (HTTPRequest req, HTTPResponse res) -> void
+
+ def do_GET: (HTTPRequest req, HTTPResponse res) -> void
+
+ def do_POST: (HTTPRequest req, HTTPResponse res) -> void
+
+ def do_OPTIONS: (HTTPRequest req, HTTPResponse res) -> void
+
+ private
+
+ def trailing_pathsep?: (String path) -> bool
+
+ def prevent_directory_traversal: (HTTPRequest req, HTTPResponse res) -> void
+
+ def exec_handler: (HTTPRequest req, HTTPResponse res) -> bool
+
+ def get_handler: (HTTPRequest req, HTTPResponse res) -> singleton(AbstractServlet)
+
+ def set_filename: (HTTPRequest req, HTTPResponse res) -> bool
+
+ def check_filename: (HTTPRequest req, HTTPResponse res, String name) -> void
+
+ def shift_path_info: (HTTPRequest req, HTTPResponse res, String path_info, ?String? base) -> void
+
+ def search_index_file: (HTTPRequest req, HTTPResponse res) -> String?
+
+ def search_file: (HTTPRequest req, HTTPResponse res, String basename) -> String?
+
+ def call_callback: (Symbol callback_name, HTTPRequest req, HTTPResponse res) -> void
+
+ def windows_ambiguous_name?: (String name) -> bool
+
+ def nondisclosure_name?: (String name) -> bool
+
+ def set_dir_list: (HTTPRequest req, HTTPResponse res) -> void
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/prochandler.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/prochandler.rbs
new file mode 100644
index 0000000..66f6929
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/prochandler.rbs
@@ -0,0 +1,21 @@
+module WEBrick
+ module HTTPServlet
+ class ProcHandler < AbstractServlet
+ interface _Callable
+ def call: (WEBrick::HTTPRequest, WEBrick::HTTPResponse) -> void
+ end
+
+ @proc: _Callable
+
+ def get_instance: (HTTPServer server, *untyped options) -> self
+
+ def initialize: (_Callable proc) -> void
+
+ def do_GET: (HTTPRequest request, HTTPResponse response) -> void
+
+ alias do_POST do_GET
+
+ alias do_PUT do_GET
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpstatus.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpstatus.rbs
new file mode 100644
index 0000000..0b83ada
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpstatus.rbs
@@ -0,0 +1,255 @@
+module WEBrick
+ #
+ # This module is used to manager HTTP status codes.
+ #
+ # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html for more
+ # information.
+ module HTTPStatus
+ #
+ # Root of the HTTP status class hierarchy
+ class Status < StandardError
+ attr_reader self.code: Integer
+
+ attr_reader self.reason_phrase: String
+
+ # Returns the HTTP status code
+ def code: () -> Integer
+
+ # Returns the HTTP status description
+ def reason_phrase: () -> String
+
+ alias to_i code
+ end
+
+ # Root of the HTTP info statuses
+ class Info < Status
+ end
+
+ # Root of the HTTP success statuses
+ class Success < Status
+ end
+
+ # Root of the HTTP redirect statuses
+ class Redirect < Status
+ end
+
+ # Root of the HTTP error statuses
+ class Error < Status
+ end
+
+ # Root of the HTTP client error statuses
+ class ClientError < Error
+ end
+
+ # Root of the HTTP server error statuses
+ class ServerError < Error
+ end
+
+ class EOFError < StandardError
+ end
+
+ # HTTP status codes and descriptions
+ StatusMessage: Hash[Integer, String]
+
+ # Maps a status code to the corresponding Status class
+ CodeToError: Hash[Integer, singleton(Status)]
+
+ # WEBrick::HTTPStatus::constants.grep(/\ARC_/).map{"#{_1}: #{WEBrick::HTTPStatus.const_get(_1)}"}
+
+ RC_CONTINUE: 100
+ RC_SWITCHING_PROTOCOLS: 101
+ RC_OK: 200
+ RC_CREATED: 201
+ RC_ACCEPTED: 202
+ RC_NON_AUTHORITATIVE_INFORMATION: 203
+ RC_NO_CONTENT: 204
+ RC_RESET_CONTENT: 205
+ RC_PARTIAL_CONTENT: 206
+ RC_MULTI_STATUS: 207
+ RC_MULTIPLE_CHOICES: 300
+ RC_MOVED_PERMANENTLY: 301
+ RC_FOUND: 302
+ RC_SEE_OTHER: 303
+ RC_NOT_MODIFIED: 304
+ RC_USE_PROXY: 305
+ RC_TEMPORARY_REDIRECT: 307
+ RC_BAD_REQUEST: 400
+ RC_UNAUTHORIZED: 401
+ RC_PAYMENT_REQUIRED: 402
+ RC_FORBIDDEN: 403
+ RC_NOT_FOUND: 404
+ RC_METHOD_NOT_ALLOWED: 405
+ RC_NOT_ACCEPTABLE: 406
+ RC_PROXY_AUTHENTICATION_REQUIRED: 407
+ RC_REQUEST_TIMEOUT: 408
+ RC_CONFLICT: 409
+ RC_GONE: 410
+ RC_PRECONDITION_FAILED: 412
+ RC_LENGTH_REQUIRED: 411
+ RC_REQUEST_ENTITY_TOO_LARGE: 413
+ RC_REQUEST_URI_TOO_LARGE: 414
+ RC_UNSUPPORTED_MEDIA_TYPE: 415
+ RC_EXPECTATION_FAILED: 417
+ RC_UNPROCESSABLE_ENTITY: 422
+ RC_LOCKED: 423
+ RC_FAILED_DEPENDENCY: 424
+ RC_REQUEST_RANGE_NOT_SATISFIABLE: 416
+ RC_UPGRADE_REQUIRED: 426
+ RC_PRECONDITION_REQUIRED: 428
+ RC_TOO_MANY_REQUESTS: 429
+ RC_REQUEST_HEADER_FIELDS_TOO_LARGE: 431
+ RC_UNAVAILABLE_FOR_LEGAL_REASONS: 451
+ RC_INTERNAL_SERVER_ERROR: 500
+ RC_NOT_IMPLEMENTED: 501
+ RC_BAD_GATEWAY: 502
+ RC_SERVICE_UNAVAILABLE: 503
+ RC_GATEWAY_TIMEOUT: 504
+ RC_HTTP_VERSION_NOT_SUPPORTED: 505
+ RC_INSUFFICIENT_STORAGE: 507
+ RC_NETWORK_AUTHENTICATION_REQUIRED: 511
+
+ # WEBrick::HTTPStatus::CodeToError.each_value.map{"class #{_1.name.split(/::/).last} < #{_1.superclass.name.split(/::/).last}\nend"}
+
+ class Continue < Info
+ end
+ class SwitchingProtocols < Info
+ end
+ class OK < Success
+ end
+ class Created < Success
+ end
+ class Accepted < Success
+ end
+ class NonAuthoritativeInformation < Success
+ end
+ class NoContent < Success
+ end
+ class ResetContent < Success
+ end
+ class PartialContent < Success
+ end
+ class MultiStatus < Success
+ end
+ class MultipleChoices < Redirect
+ end
+ class MovedPermanently < Redirect
+ end
+ class Found < Redirect
+ end
+ class SeeOther < Redirect
+ end
+ class NotModified < Redirect
+ end
+ class UseProxy < Redirect
+ end
+ class TemporaryRedirect < Redirect
+ end
+ class BadRequest < ClientError
+ end
+ class Unauthorized < ClientError
+ end
+ class PaymentRequired < ClientError
+ end
+ class Forbidden < ClientError
+ end
+ class NotFound < ClientError
+ end
+ class MethodNotAllowed < ClientError
+ end
+ class NotAcceptable < ClientError
+ end
+ class ProxyAuthenticationRequired < ClientError
+ end
+ class RequestTimeout < ClientError
+ end
+ class Conflict < ClientError
+ end
+ class Gone < ClientError
+ end
+ class LengthRequired < ClientError
+ end
+ class PreconditionFailed < ClientError
+ end
+ class RequestEntityTooLarge < ClientError
+ end
+ class RequestURITooLarge < ClientError
+ end
+ class UnsupportedMediaType < ClientError
+ end
+ class RequestRangeNotSatisfiable < ClientError
+ end
+ class ExpectationFailed < ClientError
+ end
+ class UnprocessableEntity < ClientError
+ end
+ class Locked < ClientError
+ end
+ class FailedDependency < ClientError
+ end
+ class UpgradeRequired < ClientError
+ end
+ class PreconditionRequired < ClientError
+ end
+ class TooManyRequests < ClientError
+ end
+ class RequestHeaderFieldsTooLarge < ClientError
+ end
+ class UnavailableForLegalReasons < ClientError
+ end
+ class InternalServerError < ServerError
+ end
+ class NotImplemented < ServerError
+ end
+ class BadGateway < ServerError
+ end
+ class ServiceUnavailable < ServerError
+ end
+ class GatewayTimeout < ServerError
+ end
+ class HTTPVersionNotSupported < ServerError
+ end
+ class InsufficientStorage < ServerError
+ end
+ class NetworkAuthenticationRequired < ServerError
+ end
+
+ #
+ # Returns the description corresponding to the HTTP status +code+
+ #
+ # WEBrick::HTTPStatus.reason_phrase 404
+ # => "Not Found"
+ def self?.reason_phrase: (Integer code) -> String
+
+ #
+ # Is +code+ an informational status?
+ def self?.info?: (Integer code) -> bool
+
+ #
+ # Is +code+ a successful status?
+ def self?.success?: (Integer code) -> bool
+
+ #
+ # Is +code+ a redirection status?
+ def self?.redirect?: (Integer code) -> bool
+
+ #
+ # Is +code+ an error status?
+ def self?.error?: (Integer code) -> bool
+
+ #
+ # Is +code+ a client error status?
+ def self?.client_error?: (Integer code) -> bool
+
+ #
+ # Is +code+ a server error status?
+ def self?.server_error?: (Integer code) -> bool
+
+ #
+ # Returns the status class corresponding to +code+
+ #
+ # WEBrick::HTTPStatus[302]
+ # => WEBrick::HTTPStatus::NotFound
+ #
+ def self.[]: (Integer code) -> singleton(Status)
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httputils.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httputils.rbs
new file mode 100644
index 0000000..a554cdf
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httputils.rbs
@@ -0,0 +1,116 @@
+module WEBrick
+ CR: String
+
+ LF: String
+
+ CRLF: String
+
+ module HTTPUtils
+ def self?.normalize_path: (String path) -> String
+
+ type mime_types = Hash[String, String]
+
+ DefaultMimeTypes: mime_types
+
+ def self?.load_mime_types: (string | _ToPath file) -> mime_types
+
+ def self?.mime_type: (String filename, mime_types mime_tab) -> String
+
+ class SplitHeader < Array[String]
+ def join: (?String separator) -> String
+ end
+
+ class CookieHeader < Array[String]
+ def join: (?String separator) -> String
+ end
+
+ HEADER_CLASSES: Hash[String, untyped]
+
+ def self?.parse_header: (String raw) -> Hash[String, Array[String]]
+
+ def self?.split_header_value: (String str) -> Array[String]
+
+ def self?.parse_range_header: (String? ranges_specifier) -> Array[Range[Integer]]?
+
+ def self?.parse_qvalues: (String? value) -> Array[String]
+
+ def self?.dequote: (String str) -> String
+
+ def self?.quote: (String str) -> String
+
+ class FormData < String
+ @raw_header: Array[String]
+
+ @header: Hash[String, Array[String]]
+
+ EmptyRawHeader: Array[String]
+
+ EmptyHeader: Hash[String, Array[String]]
+
+ attr_accessor name: String?
+
+ attr_accessor filename: String?
+
+ attr_accessor next_data: instance?
+
+ def initialize: (*String args) -> void
+
+ def []: (*String key) -> String
+ # following is as same as String#[]
+ | (int start, ?int length) -> String?
+ | (range[int?] range) -> String?
+ | (Regexp regexp, ?MatchData::capture backref) -> String?
+ | (String substring) -> String?
+
+ def <<: (String str) -> self
+
+ def append_data: (instance data) -> self
+
+ def each_data: () { (instance) -> void } -> void
+
+ def list: () -> Array[String]
+
+ alias to_ary list
+
+ def to_s: () -> String
+ end
+
+ def self?.parse_query: (String? str) -> Hash[String, FormData]
+
+ interface _EachLine
+ def each_line: () { (String) -> void } -> void
+ end
+
+ def self?.parse_form_data: (_EachLine? io, interned boundary) -> Hash[String, FormData]
+
+ def self?._make_regex: (String str) -> Regexp
+
+ def self?._make_regex!: (String str) -> Regexp
+
+ def self?._escape: (String str, Regexp regex) -> String
+
+ def self?._unescape: (String str, Regexp regex) -> String
+
+ UNESCAPED: Regexp
+
+ UNESCAPED_FORM: Regexp
+
+ NONASCII: Regexp
+
+ ESCAPED: Regexp
+
+ UNESCAPED_PCHAR: Regexp
+
+ def self?.escape: (String str) -> String
+
+ def self?.unescape: (String str) -> String
+
+ def self?.escape_form: (String str) -> String
+
+ def self?.unescape_form: (String str) -> String
+
+ def self?.escape_path: (String str) -> String
+
+ def self?.escape8bit: (String str) -> String
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpversion.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpversion.rbs
new file mode 100644
index 0000000..92c8940
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpversion.rbs
@@ -0,0 +1,17 @@
+module WEBrick
+ class HTTPVersion
+ include Comparable
+
+ attr_accessor major: Integer
+
+ attr_accessor minor: Integer
+
+ def self.convert: (HTTPVersion | String version) -> instance
+
+ def initialize: (HTTPVersion | String version) -> void
+
+ def <=>: (HTTPVersion | String other) -> Integer?
+
+ def to_s: () -> String
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/log.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/log.rbs
new file mode 100644
index 0000000..e985f4a
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/log.rbs
@@ -0,0 +1,93 @@
+module WEBrick
+ class BasicLog
+ @log: IO?
+
+ @opened: TrueClass?
+
+ FATAL: 1
+
+ ERROR: 2
+
+ WARN: 3
+
+ INFO: 4
+
+ DEBUG: 5
+
+ # log-level, messages above this level will be logged
+ attr_accessor level: Integer
+
+ type log_file = (IO | String)?
+
+ def initialize: (?log_file log_file, ?Integer? level) -> void
+
+ #
+ # Closes the logger (also closes the log device associated to the logger)
+ def close: () -> void
+
+ def log: (Integer level, String data) -> IO?
+
+ #
+ # Synonym for log(INFO, obj.to_s)
+ def <<: (_ToS obj) -> IO?
+
+ type message = Exception | _ToStr | Object
+
+ # Shortcut for logging a FATAL message
+ def fatal: (message msg) -> IO?
+
+ # Shortcut for logging an ERROR message
+ def error: (message msg) -> IO?
+
+ # Shortcut for logging a WARN message
+ def warn: (message msg) -> IO?
+
+ # Shortcut for logging an INFO message
+ def info: (message msg) -> IO?
+
+ # Shortcut for logging a DEBUG message
+ def debug: (message msg) -> IO?
+
+ # Will the logger output FATAL messages?
+ def fatal?: () -> bool
+
+ # Will the logger output ERROR messages?
+ def error?: () -> bool
+
+ # Will the logger output WARN messages?
+ def warn?: () -> bool
+
+ # Will the logger output INFO messages?
+ def info?: () -> bool
+
+ # Will the logger output DEBUG messages?
+ def debug?: () -> bool
+
+ private
+
+ #
+ # Formats +arg+ for the logger
+ #
+ # * If +arg+ is an Exception, it will format the error message and
+ # the back trace.
+ # * If +arg+ responds to #to_str, it will return it.
+ # * Otherwise it will return +arg+.inspect.
+ def format: (message arg) -> String
+ end
+
+ class Log < BasicLog
+ # Format of the timestamp which is applied to each logged line. The
+ # default is <tt>"[%Y-%m-%d %H:%M:%S]"</tt>
+ attr_accessor time_format: String
+
+ #
+ # Same as BasicLog#initialize
+ #
+ # You can set the timestamp format through #time_format
+ def initialize: (?BasicLog::log_file log_file, ?Integer? level) -> void
+
+ #
+ # Same as BasicLog#log
+ def log: (Integer level, String data) -> IO?
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/manifest.yaml b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/manifest.yaml
new file mode 100644
index 0000000..7ce3ffe
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/manifest.yaml
@@ -0,0 +1,8 @@
+dependencies:
+ - name: digest
+ - name: erb
+ - name: openssl
+ - name: singleton
+ - name: socket
+ - name: tempfile
+ - name: uri
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/server.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/server.rbs
new file mode 100644
index 0000000..74db11f
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/server.rbs
@@ -0,0 +1,57 @@
+module WEBrick
+ class ServerError < StandardError
+ end
+
+ class SimpleServer
+ def self.start: [T] () { () -> T } -> T
+ end
+
+ class Daemon
+ def self.start: () -> void
+ | [T] () { () -> T } -> T
+ end
+
+ class GenericServer
+ @shutdown_pipe: [IO, IO]?
+
+ attr_reader status: :Stop | :Running | :Shutdown
+
+ attr_reader config: Hash[Symbol, untyped]
+
+ attr_reader logger: BasicLog
+
+ attr_reader tokens: Thread::SizedQueue
+
+ attr_reader listeners: Array[TCPServer| OpenSSL::SSL::SSLServer]
+
+ def initialize: (?Hash[Symbol, untyped] config, ?Hash[Symbol, untyped] default) -> void
+
+ def []: (Symbol key) -> untyped
+
+ def listen: (String address, Integer port) -> void
+
+ def start: () ?{ (TCPSocket) -> void } -> void
+
+ def stop: () -> void
+
+ def shutdown: () -> void
+
+ def run: (TCPSocket sock) -> void
+
+ private
+
+ def accept_client: (TCPServer svr) -> TCPSocket?
+
+ def start_thread: (TCPSocket sock) ?{ (TCPSocket) -> void } -> Thread
+
+ def call_callback: (Symbol callback_name, *untyped args) -> untyped
+
+ def setup_shutdown_pipe: () -> [IO, IO]
+
+ def cleanup_shutdown_pipe: ([IO, IO]? shutdown_pipe) -> void
+
+ def alarm_shutdown_pipe: [T] () { (IO) -> T } -> T?
+
+ def cleanup_listener: () -> void
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/ssl.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/ssl.rbs
new file mode 100644
index 0000000..83f08f7
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/ssl.rbs
@@ -0,0 +1,19 @@
+module WEBrick
+ module Config
+ SSL: Hash[Symbol, untyped]
+ end
+
+ module Utils
+ def self?.create_self_signed_cert: (untyped bits, untyped cn, untyped comment) -> ::Array[untyped]
+ end
+
+ class GenericServer
+ @ssl_context: OpenSSL::SSL::SSLContext?
+
+ def ssl_context: () -> OpenSSL::SSL::SSLContext?
+
+ def setup_ssl_context: (Hash[Symbol, untyped] config) -> OpenSSL::SSL::SSLContext
+
+ def ssl_servername_callback: (untyped sslsocket, ?untyped? hostname) -> untyped
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/utils.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/utils.rbs
new file mode 100644
index 0000000..c7d7a68
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/utils.rbs
@@ -0,0 +1,122 @@
+module WEBrick
+ module Utils
+ #
+ # Sets IO operations on +io+ to be non-blocking
+ def self?.set_non_blocking: (IO io) -> void
+
+ #
+ # Sets the close on exec flag for +io+
+ def self?.set_close_on_exec: (IO io) -> void
+
+ #
+ # Changes the process's uid and gid to the ones of +user+
+ def self?.su: (String user) -> void
+
+ #
+ # The server hostname
+ def self?.getservername: () -> String
+
+ #
+ # Creates TCP server sockets bound to +address+:+port+ and returns them.
+ #
+ # It will create IPV4 and IPV6 sockets on all interfaces.
+ def self?.create_listeners: (String host, Integer port) -> Array[TCPServer]
+
+ #
+ # Characters used to generate random strings
+ RAND_CHARS: String
+
+ #
+ # Generates a random string of length +len+
+ def self?.random_string: (Integer len) -> String
+
+ #
+ # Class used to manage timeout handlers across multiple threads.
+ #
+ # Timeout handlers should be managed by using the class methods which are
+ # synchronized.
+ #
+ # id = TimeoutHandler.register(10, Timeout::Error)
+ # begin
+ # sleep 20
+ # puts 'foo'
+ # ensure
+ # TimeoutHandler.cancel(id)
+ # end
+ #
+ # will raise Timeout::Error
+ #
+ # id = TimeoutHandler.register(10, Timeout::Error)
+ # begin
+ # sleep 5
+ # puts 'foo'
+ # ensure
+ # TimeoutHandler.cancel(id)
+ # end
+ #
+ # will print 'foo'
+ #
+ class TimeoutHandler
+ @queue: Thread::Queue
+
+ @watcher: Thread?
+
+ include Singleton
+
+ #
+ # Mutex used to synchronize access across threads
+ TimeoutMutex: Thread::Mutex
+
+ #
+ # Registers a new timeout handler
+ #
+ # +time+:: Timeout in seconds
+ # +exception+:: Exception to raise when timeout elapsed
+ def self.register: (Numeric seconds, singleton(Exception) exception) -> Integer
+
+ #
+ # Cancels the timeout handler +id+
+ def self.cancel: (Integer id) -> bool
+
+ def self.terminate: () -> Thread?
+
+ #
+ # Creates a new TimeoutHandler. You should use ::register and ::cancel
+ # instead of creating the timeout handler directly.
+ def initialize: () -> void
+
+ private
+
+ def watch: () -> bot
+
+ def watcher: () -> Thread
+
+ public
+
+ #
+ # Interrupts the timeout handler +id+ and raises +exception+
+ def interrupt: (Thread thread, Integer id, singleton(Exception) exception) -> nil
+
+ #
+ # Registers a new timeout handler
+ #
+ # +time+:: Timeout in seconds
+ # +exception+:: Exception to raise when timeout elapsed
+ def register: (Thread thread, Numeric time, singleton(Exception) exception) -> Integer
+
+ #
+ # Cancels the timeout handler +id+
+ def cancel: (Thread thread, Integer id) -> bool
+
+ #
+ def terminate: () -> Thread?
+ end
+
+ #
+ # Executes the passed block and raises +exception+ if execution takes more
+ # than +seconds+.
+ #
+ # If +seconds+ is zero or nil, simply executes the block
+ def self?.timeout: [T] (Numeric? seconds, ?singleton(Exception) exception) { (?Numeric) -> T } -> T
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/version.rbs b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/version.rbs
new file mode 100644
index 0000000..64d0ef0
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/version.rbs
@@ -0,0 +1,3 @@
+module WEBrick
+ VERSION: String
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/webrick.gemspec b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/webrick.gemspec
new file mode 100644
index 0000000..1ebc674
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/webrick.gemspec
@@ -0,0 +1,105 @@
+# 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 = [
+ "Gemfile",
+ "LICENSE.txt",
+ "README.md",
+ "Rakefile",
+ "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/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/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",
+ "sig/accesslog.rbs",
+ "sig/cgi.rbs",
+ "sig/compat.rbs",
+ "sig/config.rbs",
+ "sig/cookie.rbs",
+ "sig/htmlutils.rbs",
+ "sig/httpauth.rbs",
+ "sig/httpauth/authenticator.rbs",
+ "sig/httpauth/basicauth.rbs",
+ "sig/httpauth/digestauth.rbs",
+ "sig/httpauth/htdigest.rbs",
+ "sig/httpauth/htgroup.rbs",
+ "sig/httpauth/htpasswd.rbs",
+ "sig/httpauth/userdb.rbs",
+ "sig/httpproxy.rbs",
+ "sig/httprequest.rbs",
+ "sig/httpresponse.rbs",
+ "sig/https.rbs",
+ "sig/httpserver.rbs",
+ "sig/httpservlet.rbs",
+ "sig/httpservlet/abstract.rbs",
+ "sig/httpservlet/cgi_runner.rbs",
+ "sig/httpservlet/cgihandler.rbs",
+ "sig/httpservlet/erbhandler.rbs",
+ "sig/httpservlet/filehandler.rbs",
+ "sig/httpservlet/prochandler.rbs",
+ "sig/httpstatus.rbs",
+ "sig/httputils.rbs",
+ "sig/httpversion.rbs",
+ "sig/log.rbs",
+ "sig/manifest.yaml",
+ "sig/server.rbs",
+ "sig/ssl.rbs",
+ "sig/utils.rbs",
+ "sig/version.rbs",
+ "webrick.gemspec",
+ ]
+ s.required_ruby_version = ">= 2.4.0"
+
+ s.authors = ["TAKAHASHI Masayoshi", "GOTOU YUUZOU", "Eric Wong"]
+ s.email = [nil, nil, 'normal@ruby-lang.org']
+ s.homepage = "https://github.com/ruby/webrick"
+ s.licenses = ["Ruby", "BSD-2-Clause"]
+
+ if s.respond_to?(:metadata=)
+ s.metadata = {
+ "bug_tracker_uri" => "https://github.com/ruby/webrick/issues",
+ }
+ end
+end