class Middleware
Protocol::HTTP::Middleware for recording complete HTTP interactions.
This middleware captures both HTTP requests and responses, waiting for both to be fully processed before recording the complete interaction.
Definitions
def initialize(app, store:)
Initialize the recording middleware.
Signature
-
parameter
app
Protocol::HTTP::Middleware
The next middleware in the chain.
-
parameter
store
Object
An object that responds to #call(interaction) to handle recorded interactions.
Implementation
def initialize(app, store:)
super(app)
@store = store
end
def call(request)
Process an HTTP request, capturing both request and response.
Signature
-
parameter
request
Protocol::HTTP::Request
The incoming HTTP request.
-
returns
Protocol::HTTP::Response
The response from the next middleware.
Implementation
def call(request)
# Check if we should capture this request:
unless capture?(request)
return super(request)
end
# Create completion tracker for this interaction:
tracker = create_interaction_tracker(request)
# Capture request body with completion tracking:
captured_request = capture_request_with_completion(request, tracker)
# Get response from downstream middleware/app:
response = super(captured_request)
# Capture response body with completion tracking:
capture_response_with_completion(captured_request, response, tracker)
end
def capture?(request)
Determine whether to capture the given request. Override this method in subclasses to implement custom filtering logic.
Signature
-
parameter
request
Protocol::HTTP::Request
The incoming HTTP request.
-
returns
Boolean
True if the request should be captured, false otherwise.
Implementation
def capture?(request)
true
end
def create_interaction_tracker(request)
Create a completion tracker for a single interaction.
Signature
-
parameter
request
Protocol::HTTP::Request
The original request.
-
returns
InteractionTracker
A new tracker instance.
Implementation
def create_interaction_tracker(request)
InteractionTracker.new(@store, request)
end
def capture_request_with_completion(request, tracker)
Capture the request body with completion tracking.
Signature
-
parameter
request
Protocol::HTTP::Request
The original request.
-
parameter
tracker
InteractionTracker
The completion tracker.
-
returns
Protocol::HTTP::Request
A request with rewindable body.
Implementation
def capture_request_with_completion(request, tracker)
return tracker.mark_request_ready(request) unless request.body && !request.body.empty?
# Make the request body rewindable:
rewindable_body = ::Protocol::HTTP::Body::Rewindable.wrap(request)
# Wrap with completion callback:
::Protocol::HTTP::Body::Completable.wrap(request) do |error|
# Always capture whatever body data we have, even if there was an error
captured_body = rewindable_body.buffered rescue nil
if error
tracker.request_completed(body: captured_body, error: error)
else
tracker.request_completed(body: captured_body)
end
end
return request
end
def capture_response_with_completion(request, response, tracker)
Capture the response body with completion tracking.
Signature
-
parameter
request
Protocol::HTTP::Request
The captured request.
-
parameter
response
Protocol::HTTP::Response
The response to capture.
-
parameter
tracker
InteractionTracker
The completion tracker.
-
returns
Protocol::HTTP::Response
The wrapped response.
Implementation
def capture_response_with_completion(request, response, tracker)
# Set the response on the tracker:
tracker.set_response(response)
return tracker.mark_response_ready(response) unless response.body && !response.body.empty?
# Make the response body rewindable:
rewindable_body = ::Protocol::HTTP::Body::Rewindable.wrap(response)
# Wrap with completion callback:
::Protocol::HTTP::Body::Completable.wrap(response) do |error|
# Always capture whatever body data we have, even if there was an error
captured_body = rewindable_body.buffered rescue nil
if error
tracker.response_completed(body: captured_body, error: error)
else
tracker.response_completed(body: captured_body)
end
end
return response
end