Overview
WEBrick provides Ruby's standard library HTTP server implementation. The library includes WEBrick::HTTPServer
as the primary server class, along with supporting classes for request handling, response generation, and servlet management. WEBrick operates as a pure Ruby solution, making it platform-independent and easy to embed within Ruby applications.
The server architecture centers around a main server instance that listens on a specified port and dispatches incoming requests to registered servlets. Each servlet handles specific URL patterns and generates appropriate HTTP responses. WEBrick supports both single-threaded and multi-threaded operation modes, with configurable thread pools for concurrent request handling.
WEBrick handles the complete HTTP protocol implementation, including request parsing, header processing, status code management, and response formatting. The library automatically manages connection lifecycle, request routing, and error response generation.
require 'webrick'
# Basic server creation
server = WEBrick::HTTPServer.new(Port: 8000)
# Mount a simple servlet
server.mount_proc('/hello') do |req, res|
res.body = 'Hello, World!'
end
# Start the server
server.start
require 'webrick'
# Server with custom document root
server = WEBrick::HTTPServer.new(
Port: 8000,
DocumentRoot: './public'
)
# Serve static files from public directory
server.start
The WEBrick::HTTPServer
class accepts configuration options through its constructor, including port numbers, document roots, access logs, and security settings. The server automatically handles static file serving when a document root is specified, while custom servlets handle dynamic content generation.
Basic Usage
WEBrick servers require explicit configuration and servlet mounting before starting. The WEBrick::HTTPServer.new
method accepts a configuration hash specifying operational parameters. Common configuration options include :Port
, :Host
, :DocumentRoot
, and :AccessLog
.
require 'webrick'
server = WEBrick::HTTPServer.new(
Port: 3000,
Host: '127.0.0.1',
AccessLog: [[STDOUT, WEBrick::AccessLog::COMMON_LOG_FORMAT]]
)
# Mount a dynamic servlet
server.mount_proc('/time') do |request, response|
response.content_type = 'text/plain'
response.body = Time.now.to_s
end
# Mount static file serving
server.mount('/', WEBrick::HTTPServlet::FileHandler, './public')
server.start
The mount_proc
method attaches block-based request handlers to specific URL paths. The block receives WEBrick::HTTPRequest
and WEBrick::HTTPResponse
objects, allowing full control over request processing and response generation. Request objects provide access to HTTP methods, headers, parameters, and body content.
require 'webrick'
server = WEBrick::HTTPServer.new(Port: 8080)
server.mount_proc('/form') do |req, res|
if req.request_method == 'GET'
res.content_type = 'text/html'
res.body = '<form method="post"><input name="message"><button>Send</button></form>'
elsif req.request_method == 'POST'
message = req.query['message']
res.content_type = 'text/plain'
res.body = "Received: #{message}"
end
end
server.start
Response objects support setting HTTP status codes, headers, and body content. The content_type
attribute sets the Content-Type
header, while the body
attribute contains the response content. WEBrick automatically calculates content length and handles header formatting.
require 'webrick'
server = WEBrick::HTTPServer.new(Port: 8080)
server.mount_proc('/api/data') do |req, res|
res.status = 200
res.content_type = 'application/json'
res['Cache-Control'] = 'no-cache'
data = { timestamp: Time.now.to_i, status: 'ok' }
res.body = JSON.generate(data)
end
server.start
The mount
method attaches servlet classes to URL paths. WEBrick includes built-in servlet classes like WEBrick::HTTPServlet::FileHandler
for static file serving and WEBrick::HTTPServlet::CGIHandler
for CGI script execution. Custom servlet classes inherit from WEBrick::HTTPServlet::AbstractServlet
and implement HTTP method handlers.
Advanced Usage
WEBrick supports custom servlet classes for complex request handling logic. Servlet classes inherit from WEBrick::HTTPServlet::AbstractServlet
and implement methods corresponding to HTTP verbs: do_GET
, do_POST
, do_PUT
, and do_DELETE
. Each method receives request and response objects as parameters.
require 'webrick'
class APIServlet < WEBrick::HTTPServlet::AbstractServlet
def initialize(server, data_store)
super(server)
@data_store = data_store
end
def do_GET(request, response)
id = request.query['id']
if id && @data_store[id]
response.status = 200
response.content_type = 'application/json'
response.body = JSON.generate(@data_store[id])
else
response.status = 404
response.body = 'Not Found'
end
end
def do_POST(request, response)
data = JSON.parse(request.body)
id = SecureRandom.uuid
@data_store[id] = data.merge('id' => id)
response.status = 201
response.content_type = 'application/json'
response.body = JSON.generate(@data_store[id])
end
end
data_store = {}
server = WEBrick::HTTPServer.new(Port: 8080)
server.mount('/api', APIServlet, data_store)
server.start
WEBrick configuration accepts detailed server options through the configuration hash. The :Logger
option specifies logging behavior, :MaxClients
controls concurrent connection limits, and :RequestTimeout
sets request processing timeouts. SSL/TLS support requires :SSLEnable
, :SSLCertificate
, and :SSLPrivateKey
options.
require 'webrick'
require 'webrick/https'
require 'openssl'
config = {
Port: 8443,
SSLEnable: true,
SSLCertificate: OpenSSL::X509::Certificate.new(File.read('server.crt')),
SSLPrivateKey: OpenSSL::PKey::RSA.new(File.read('server.key')),
SSLVerifyClient: OpenSSL::SSL::VERIFY_NONE,
MaxClients: 100,
RequestTimeout: 30,
Logger: WEBrick::Log.new('server.log', WEBrick::Log::INFO)
}
server = WEBrick::HTTPServer.new(config)
server.mount_proc('/secure') do |req, res|
res.body = "Secure connection established"
end
server.start
The WEBrick::HTTPAuth
module provides HTTP authentication mechanisms including Basic and Digest authentication. Authentication requires configuring user databases, password stores, and authentication handlers. The authentication system integrates with servlet mounting to protect specific URL paths.
require 'webrick'
# Create password database
htpasswd = WEBrick::HTTPAuth::Htpasswd.new('users.htpasswd')
htpasswd.auth_type = WEBrick::HTTPAuth::BasicAuth
htpasswd.set_passwd('admin', 'admin', 'secret123')
htpasswd.set_passwd('admin', 'user', 'password456')
# Configure authentication
auth = WEBrick::HTTPAuth::BasicAuth.new(
Realm: 'Admin Area',
UserDB: htpasswd
)
server = WEBrick::HTTPServer.new(Port: 8080)
server.mount_proc('/admin') do |req, res|
auth.authenticate(req, res)
res.body = 'Admin panel access granted'
end
server.start
WEBrick supports virtual hosting through the WEBrick::HTTPServer::MountTable
class. Virtual hosts allow different servlet configurations based on the Host
header value. Each virtual host maintains separate servlet mountings and configuration options, enabling multi-domain server setups.
Error Handling & Debugging
WEBrick generates specific exception types for different error conditions. WEBrick::HTTPStatus::Error
serves as the base class for HTTP status exceptions. Subclasses like WEBrick::HTTPStatus::NotFound
and WEBrick::HTTPStatus::InternalServerError
represent specific HTTP status codes. Servlets can raise these exceptions to generate appropriate error responses.
require 'webrick'
class SafeServlet < WEBrick::HTTPServlet::AbstractServlet
def do_GET(request, response)
begin
resource_id = request.query['id']
raise WEBrick::HTTPStatus::BadRequest, "Missing id parameter" unless resource_id
# Simulate resource lookup
if resource_id.to_i > 1000
raise WEBrick::HTTPStatus::NotFound, "Resource not found"
end
response.content_type = 'application/json'
response.body = JSON.generate({ id: resource_id, data: 'example' })
rescue WEBrick::HTTPStatus::Status => e
# WEBrick automatically handles HTTPStatus exceptions
raise e
rescue StandardError => e
# Convert unexpected errors to 500 responses
raise WEBrick::HTTPStatus::InternalServerError, e.message
end
end
end
server = WEBrick::HTTPServer.new(Port: 8080)
server.mount('/resource', SafeServlet)
server.start
WEBrick provides comprehensive logging through the WEBrick::Log
class. The logger supports different log levels including DEBUG
, INFO
, WARN
, ERROR
, and FATAL
. Access logs record HTTP requests using configurable formats, while error logs capture server exceptions and debugging information.
require 'webrick'
# Configure detailed logging
access_log = []
access_log << [STDOUT, WEBrick::AccessLog::COMBINED_LOG_FORMAT]
access_log << [File.open('access.log', 'w'), WEBrick::AccessLog::COMMON_LOG_FORMAT]
error_logger = WEBrick::Log.new('error.log', WEBrick::Log::DEBUG)
server = WEBrick::HTTPServer.new(
Port: 8080,
AccessLog: access_log,
Logger: error_logger
)
server.mount_proc('/debug') do |req, res|
server.logger.debug("Debug request received: #{req.request_uri}")
server.logger.info("Request from: #{req.remote_ip}")
res.body = 'Debug response'
server.logger.debug("Response sent successfully")
end
server.start
Request validation requires explicit parameter checking and data sanitization. WEBrick does not provide built-in validation mechanisms, so servlets must implement appropriate checks for required parameters, data types, and security constraints. Input validation prevents common security vulnerabilities and improves error reporting.
require 'webrick'
class ValidatingServlet < WEBrick::HTTPServlet::AbstractServlet
def do_POST(request, response)
begin
# Validate Content-Type header
content_type = request.content_type
unless content_type&.include?('application/json')
raise WEBrick::HTTPStatus::UnsupportedMediaType,
"Expected application/json, got #{content_type}"
end
# Parse and validate JSON body
data = JSON.parse(request.body || '{}')
required_fields = %w[name email]
missing_fields = required_fields.select { |field| data[field].nil? || data[field].empty? }
unless missing_fields.empty?
raise WEBrick::HTTPStatus::BadRequest,
"Missing required fields: #{missing_fields.join(', ')}"
end
# Validate email format
email_regex = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
unless data['email'].match?(email_regex)
raise WEBrick::HTTPStatus::BadRequest, "Invalid email format"
end
response.status = 200
response.content_type = 'application/json'
response.body = JSON.generate({ status: 'created', id: SecureRandom.uuid })
rescue JSON::ParserError
raise WEBrick::HTTPStatus::BadRequest, "Invalid JSON in request body"
end
end
end
Thread Safety & Concurrency
WEBrick operates in multi-threaded mode by default, creating new threads for each client connection. The :MaxClients
configuration option limits concurrent connections, while :RequestTimeout
prevents resource exhaustion from slow clients. Thread safety becomes critical when servlets access shared data structures or external resources.
require 'webrick'
require 'thread'
class ThreadSafeCounter < WEBrick::HTTPServlet::AbstractServlet
def initialize(server)
super(server)
@counter = 0
@mutex = Mutex.new
end
def do_GET(request, response)
action = request.query['action']
result = @mutex.synchronize do
case action
when 'increment'
@counter += 1
when 'decrement'
@counter -= 1
when 'get'
@counter
else
raise WEBrick::HTTPStatus::BadRequest, "Invalid action: #{action}"
end
end
response.content_type = 'application/json'
response.body = JSON.generate({ counter: result, thread_id: Thread.current.object_id })
end
end
server = WEBrick::HTTPServer.new(
Port: 8080,
MaxClients: 10,
RequestTimeout: 30
)
server.mount('/counter', ThreadSafeCounter)
server.start
Connection pools and resource management require careful synchronization when servlets access databases, file systems, or external services. Ruby's ConnectionPool
gem integrates well with WEBrick for managing shared resources across request threads.
require 'webrick'
require 'connection_pool'
class DatabaseServlet < WEBrick::HTTPServlet::AbstractServlet
def initialize(server, db_pool)
super(server)
@db_pool = db_pool
end
def do_GET(request, response)
user_id = request.query['user_id']
@db_pool.with do |connection|
# Simulate database query
user_data = connection.execute("SELECT * FROM users WHERE id = ?", user_id)
response.content_type = 'application/json'
response.body = JSON.generate(user_data)
end
rescue => e
server.logger.error("Database error: #{e.message}")
raise WEBrick::HTTPStatus::InternalServerError, "Database unavailable"
end
end
# Create connection pool (pseudo-code for database connections)
db_pool = ConnectionPool.new(size: 5, timeout: 5) do
# Database connection creation logic
MockDatabaseConnection.new
end
server = WEBrick::HTTPServer.new(Port: 8080)
server.mount('/users', DatabaseServlet, db_pool)
server.start
WEBrick supports single-threaded operation through custom server configurations. Single-threaded servers avoid synchronization overhead but cannot handle concurrent requests. This mode works well for development environments or applications with minimal concurrent load requirements.
require 'webrick'
# Custom single-threaded server
class SingleThreadServer < WEBrick::HTTPServer
def start(&block)
@listen_socket = TCPServer.new(@config[:BindAddress], @config[:Port])
loop do
begin
sock = @listen_socket.accept
req = WEBrick::HTTPRequest.new(@config)
res = WEBrick::HTTPResponse.new(@config)
req.parse(sock)
service(req, res)
res.send_response(sock)
ensure
sock&.close
end
end
end
end
server = SingleThreadServer.new(Port: 8080)
server.mount_proc('/single') do |req, res|
res.body = "Single-threaded response from #{Thread.current.object_id}"
end
server.start
Production Patterns
WEBrick deployment in production environments requires careful configuration of security settings, logging, and process management. While WEBrick handles small to medium traffic loads, high-traffic applications typically use WEBrick behind reverse proxies like nginx or Apache for static content serving and SSL termination.
require 'webrick'
require 'logger'
class ProductionServer
def initialize(port, document_root)
@config = {
Port: port,
DocumentRoot: document_root,
DirectoryIndex: %w[index.html index.htm],
AccessLog: setup_access_logging,
Logger: setup_error_logging,
MaxClients: 50,
RequestTimeout: 60,
ServerType: WEBrick::Daemon,
ServerSoftware: "MyApp/1.0",
DoNotReverseLookup: true
}
@server = WEBrick::HTTPServer.new(@config)
setup_signal_handling
mount_applications
end
private
def setup_access_logging
access_log = []
# Console logging for development
if ENV['RACK_ENV'] != 'production'
access_log << [STDOUT, WEBrick::AccessLog::COMBINED_LOG_FORMAT]
end
# File logging
log_file = File.open('log/access.log', 'a')
access_log << [log_file, WEBrick::AccessLog::COMBINED_LOG_FORMAT]
access_log
end
def setup_error_logging
WEBrick::Log.new('log/error.log', WEBrick::Log::INFO)
end
def setup_signal_handling
%w[INT TERM].each do |signal|
Signal.trap(signal) { @server.shutdown }
end
end
def mount_applications
# Static file serving
@server.mount('/', WEBrick::HTTPServlet::FileHandler, 'public')
# API endpoints
@server.mount('/api/health', HealthCheckServlet)
@server.mount('/api/v1', APIServlet)
# Error pages
@server.mount('/404.html', WEBrick::HTTPServlet::FileHandler, 'public/404.html')
end
def start
@server.start
end
end
# Usage
server = ProductionServer.new(8080, 'public')
server.start
Health check endpoints enable monitoring systems to verify server availability and application status. These endpoints typically return JSON responses with system metrics, dependency status, and application version information.
require 'webrick'
class HealthCheckServlet < WEBrick::HTTPServlet::AbstractServlet
def do_GET(request, response)
health_data = {
status: 'healthy',
timestamp: Time.now.iso8601,
version: '1.0.0',
uptime: Process.clock_gettime(Process::CLOCK_MONOTONIC).to_i,
checks: perform_health_checks
}
if health_data[:checks].any? { |check| check[:status] != 'ok' }
response.status = 503
health_data[:status] = 'unhealthy'
else
response.status = 200
end
response.content_type = 'application/json'
response.body = JSON.generate(health_data)
end
private
def perform_health_checks
checks = []
# Database connectivity
checks << {
name: 'database',
status: database_connected? ? 'ok' : 'error',
response_time_ms: measure_database_response_time
}
# External service availability
checks << {
name: 'external_api',
status: external_api_available? ? 'ok' : 'error',
response_time_ms: measure_api_response_time
}
# Disk space
checks << {
name: 'disk_space',
status: sufficient_disk_space? ? 'ok' : 'warning',
available_gb: available_disk_space_gb
}
checks
end
end
Process management for production WEBrick servers requires implementing graceful shutdown handling, process monitoring, and restart mechanisms. Daemon mode operation detaches the server process from the controlling terminal, while proper signal handling ensures clean resource cleanup.
require 'webrick'
class ManagedServer
def initialize
@server = nil
@running = false
setup_signal_handlers
end
def start(daemonize: false)
config = {
Port: ENV['PORT'] || 8080,
ServerType: daemonize ? WEBrick::Daemon : nil,
PidFile: 'tmp/server.pid',
Logger: WEBrick::Log.new('log/server.log', WEBrick::Log::INFO),
AccessLog: [[File.open('log/access.log', 'a'), WEBrick::AccessLog::COMBINED_LOG_FORMAT]]
}
@server = WEBrick::HTTPServer.new(config)
@running = true
# Write PID file for process management
File.write(config[:PidFile], Process.pid) unless daemonize
mount_routes
begin
@server.start
ensure
cleanup
end
end
def stop
return unless @running
@server&.shutdown
@running = false
end
private
def setup_signal_handlers
%w[INT TERM].each do |signal|
Signal.trap(signal) do
puts "Received #{signal}, shutting down gracefully..."
stop
end
end
Signal.trap('USR1') do
puts "Received USR1, reloading configuration..."
reload_config
end
end
def cleanup
File.delete('tmp/server.pid') if File.exist?('tmp/server.pid')
puts "Server stopped"
end
def reload_config
# Implement configuration reloading logic
@server.logger.info("Configuration reloaded")
end
def mount_routes
@server.mount_proc('/') do |req, res|
res.body = 'Server running'
end
end
end
# Usage
server = ManagedServer.new
server.start(daemonize: ARGV.include?('--daemon'))
Reference
WEBrick::HTTPServer Configuration Options
Option | Type | Default | Description |
---|---|---|---|
:Port |
Integer | 80 | TCP port number for server binding |
:Host |
String | '0.0.0.0' | IP address for server binding |
:BindAddress |
String | nil | Alias for :Host option |
:DocumentRoot |
String | nil | Directory path for static file serving |
:DirectoryIndex |
Array | ['index.html'] | Default files for directory requests |
:MaxClients |
Integer | 100 | Maximum concurrent client connections |
:RequestTimeout |
Integer | 30 | Request processing timeout in seconds |
:ServerType |
Class | nil | WEBrick::Daemon for background operation |
:ServerSoftware |
String | "WEBrick/#{VERSION}" | Server identification string |
:Logger |
WEBrick::Log | BasicLog | Error logging configuration |
:AccessLog |
Array | [] | Access logging configuration |
:SSLEnable |
Boolean | false | Enable SSL/TLS encryption |
:SSLCertificate |
OpenSSL::X509::Certificate | nil | SSL certificate object |
:SSLPrivateKey |
OpenSSL::PKey | nil | SSL private key object |
:SSLVerifyClient |
Integer | VERIFY_NONE | SSL client verification mode |
Request Object Methods
Method | Returns | Description |
---|---|---|
#request_method |
String | HTTP method (GET, POST, PUT, DELETE) |
#request_uri |
URI | Complete request URI object |
#path |
String | URL path component |
#query |
Hash | Parsed query parameters |
#body |
String | Request body content |
#content_type |
String | Content-Type header value |
#content_length |
Integer | Content-Length header value |
#remote_ip |
String | Client IP address |
#header |
Hash | HTTP headers hash |
#cookies |
Array | Cookie objects array |
#user |
String | Authenticated username |
Response Object Methods
Method | Parameters | Description |
---|---|---|
#status= |
Integer | Set HTTP status code |
#content_type= |
String | Set Content-Type header |
#body= |
String | Set response body content |
#[]=(key, value) |
String, String | Set custom HTTP header |
#cookies |
Cookie | Access response cookies |
#set_redirect |
String | Set redirect location |
#send_response |
IO | Send response to output stream |
Built-in Servlet Classes
Class | Purpose | Constructor Parameters |
---|---|---|
WEBrick::HTTPServlet::FileHandler |
Static file serving | server, document_root, options |
WEBrick::HTTPServlet::CGIHandler |
CGI script execution | server, script_path |
WEBrick::HTTPServlet::ERBHandler |
ERB template processing | server, template_path |
WEBrick::HTTPServlet::ProcHandler |
Proc-based request handling | proc_object |
WEBrick::HTTPServlet::DefaultFileHandler |
Directory index generation | server, local_path |
HTTP Status Exception Classes
Class | Status Code | Description |
---|---|---|
WEBrick::HTTPStatus::BadRequest |
400 | Malformed request syntax |
WEBrick::HTTPStatus::Unauthorized |
401 | Authentication required |
WEBrick::HTTPStatus::Forbidden |
403 | Access denied |
WEBrick::HTTPStatus::NotFound |
404 | Resource not found |
WEBrick::HTTPStatus::MethodNotAllowed |
405 | HTTP method not supported |
WEBrick::HTTPStatus::InternalServerError |
500 | Server processing error |
WEBrick::HTTPStatus::NotImplemented |
501 | Feature not implemented |
WEBrick::HTTPStatus::BadGateway |
502 | Upstream server error |
WEBrick::HTTPStatus::ServiceUnavailable |
503 | Service temporarily unavailable |
Authentication Classes
Class | Type | Required Parameters |
---|---|---|
WEBrick::HTTPAuth::BasicAuth |
HTTP Basic | :Realm, :UserDB |
WEBrick::HTTPAuth::DigestAuth |
HTTP Digest | :Realm, :UserDB, :Algorithm |
WEBrick::HTTPAuth::Htpasswd |
Password file | filename, password_hash |
WEBrick::HTTPAuth::Htdigest |
Digest password file | filename |
Log Levels
Level | Numeric Value | Description |
---|---|---|
WEBrick::Log::FATAL |
1 | Fatal errors only |
WEBrick::Log::ERROR |
2 | Error conditions |
WEBrick::Log::WARN |
3 | Warning messages |
WEBrick::Log::INFO |
4 | Informational messages |
WEBrick::Log::DEBUG |
5 | Debug information |
Common MIME Types
Extension | MIME Type | WEBrick Constant |
---|---|---|
.html |
text/html | WEBrick::HTTPUtils::DefaultMimeTypes['.html'] |
.css |
text/css | WEBrick::HTTPUtils::DefaultMimeTypes['.css'] |
.js |
application/javascript | WEBrick::HTTPUtils::DefaultMimeTypes['.js'] |
.json |
application/json | WEBrick::HTTPUtils::DefaultMimeTypes['.json'] |
.png |
image/png | WEBrick::HTTPUtils::DefaultMimeTypes['.png'] |
.jpg |
image/jpeg | WEBrick::HTTPUtils::DefaultMimeTypes['.jpg'] |