Skip to content

Commit fdd0148

Browse files
committed
Improved request validation and associated logging.
1 parent 2d28532 commit fdd0148

File tree

5 files changed

+44
-10
lines changed

5 files changed

+44
-10
lines changed

lib/falcon/middleware/proxy.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ def call(request)
152152
def call(request)
153153
attributes = {
154154
"authority" => request.authority,
155+
"method" => request.method,
156+
"path" => request.path,
157+
"version" => request.version,
155158
}
156159

157160
Traces.trace("falcon.middleware.proxy.call", attributes: attributes) do

lib/falcon/middleware/redirect.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ def call(request)
5050
location = "#{@endpoint.scheme}://#{host.authority}:#{@endpoint.port}#{request.path}"
5151
end
5252

53+
Console.info(self, "Redirecting incoming request...", request: request, location: location)
54+
5355
return Protocol::HTTP::Response[301, [["location", location]], []]
5456
else
5557
super

lib/falcon/middleware/validate.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2025, by Samuel Williams.
5+
6+
module Falcon
7+
module Middleware
8+
# A HTTP middleware for validating incoming requests.
9+
class Validate < Protocol::HTTP::Middleware
10+
# Initialize the validate middleware.
11+
# @parameter app [Protocol::HTTP::Middleware] The middleware to wrap.
12+
def initialize(app)
13+
super(app)
14+
end
15+
16+
# Validate the incoming request.
17+
def call(request)
18+
unless request.path.start_with?("/")
19+
return Protocol::HTTP::Response[400, {}, ["Invalid request path!"]]
20+
end
21+
22+
return super
23+
end
24+
end
25+
end
26+
end

lib/falcon/middleware/verbose.rb

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Verbose < Protocol::HTTP::Middleware
1313
# Initialize the verbose middleware.
1414
# @parameter app [Protocol::HTTP::Middleware] The middleware to wrap.
1515
# @parameter logger [Console::Logger] The logger to use.
16-
def initialize(app, logger = Console.logger)
16+
def initialize(app, logger = Console)
1717
super(app)
1818

1919
@logger = logger
@@ -24,7 +24,7 @@ def annotate(request)
2424
task = Async::Task.current
2525
address = request.remote_address
2626

27-
@logger.info(request) {"Headers: #{request.headers.to_h} from #{address.inspect}"}
27+
@logger.info(request, "-> #{request.method} #{request.path}", headers: request.headers.to_h, address: address.inspect)
2828

2929
task.annotate("#{request.method} #{request.path} from #{address.inspect}")
3030
end
@@ -37,10 +37,8 @@ def call(request)
3737

3838
response = super
3939

40-
statistics.wrap(response) do |statistics, error|
41-
@logger.info(request) {"Responding with: #{response.status} #{response.headers.to_h}; #{statistics.inspect}"}
42-
43-
@logger.error(request) {"#{error.class}: #{error.message}"} if error
40+
statistics.wrap(response) do |body, error|
41+
@logger.info(request, "<- #{request.method} #{request.path}", headers: response.headers.to_h, status: response.status, body: body.inspect, error: error)
4442
end
4543

4644
return response

lib/falcon/server.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,35 @@
99
require "protocol/http/content_encoding"
1010

1111
require "async/http/cache"
12-
1312
require_relative "middleware/verbose"
13+
require_relative "middleware/validate"
1414
require "protocol/rack"
1515

1616
module Falcon
1717
# A server listening on a specific endpoint, hosting a specific middleware.
1818
class Server < Async::HTTP::Server
1919
# Wrap a rack application into a middleware suitable the server.
2020
# @parameter rack_app [Proc | Object] A rack application/middleware.
21-
# @parameter verbose [Boolean] Whether to add the {Verbose} middleware.
21+
# @parameter validate [Boolean] Whether to add the {Middleware::Validate} middleware.
22+
# @parameter verbose [Boolean] Whether to add the {Middleware::Verbose} middleware.
2223
# @parameter cache [Boolean] Whether to add the {Async::HTTP::Cache} middleware.
23-
def self.middleware(rack_app, verbose: false, cache: true)
24+
def self.middleware(rack_app, verbose: false, validate: true, cache: true)
2425
::Protocol::HTTP::Middleware.build do
2526
if verbose
2627
use Middleware::Verbose
2728
end
2829

30+
if validate
31+
use Middleware::Validate
32+
end
33+
2934
if cache
3035
use Async::HTTP::Cache::General
3136
end
3237

3338
use ::Protocol::HTTP::ContentEncoding
34-
use ::Protocol::Rack::Adapter
3539

40+
use ::Protocol::Rack::Adapter
3641
run rack_app
3742
end
3843
end

0 commit comments

Comments
 (0)