-
-
Save rkh/1136499 to your computer and use it in GitHub Desktop.
Checking size of each request
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rack' | |
## | |
# Tries to calculate size of the complete response. | |
# This middleware should be chained in front of everything else. | |
# Middleware taking care of compression, etag handling etc could | |
# produce wrong results. | |
# | |
# Leaves streaming intact and does work file bodies from sockets | |
# and files. | |
# | |
# Assumes server supports keep-alive for HTTP 1.0 requests. | |
# | |
# This code has not been tested, I just wrote it down to | |
# demonstrate the general approach! | |
# | |
# Usage: | |
# | |
# use(ResponseSize) { |size| puts "size is: #{size}" } | |
# | |
# Enjoy! | |
class ResponseSize | |
# we need this to not sabotage streaming | |
class Proxy < Rack::BodyProxy | |
def initialize(body, size, &callback) | |
super(body) { callback.call(@size) } | |
@size = size | |
end | |
def each | |
@body.each do |str| | |
@size += str.bytesize | |
yield str | |
end | |
end | |
end | |
BASE_OVERHEAD = "HTTP/1.1 xxx \r\n\r\n".bytesize | |
KEEP_ALIVE = "Connection: Keep-Alive\r\n".bytesize | |
HEADER_OVERHEAD = ": \r\n".bytesize | |
def initialize(app, &callback) | |
@app, @callback = app, callback | |
end | |
def call(env) | |
status, headers, body = @app.call(env) | |
# base overhead for every response | |
size = BASE_OVERHEAD | |
# size of the http messsage, like the "OK" in "HTTP/1.1 200 OK" | |
size += Rack::Utils::HTTP_STATUS_CODES[status.to_i].bytesize | |
# header size | |
header.each do |key, values| | |
values.split("\n").each do |value| | |
size += key.bytesize + value.bytesize + HEADER_OVERHEAD | |
end | |
end | |
# body size | |
if headers['Content-Length'] or [204, 304].include?(status.to_i) | |
size += KEEP_ALIVE if env['HTTP_VERSION'] == 'HTTP/1.0' | |
size += Integer headers['Content-Length'] | |
callback.call(size) | |
else | |
body = Proxy.new(body, size, &callback) | |
end | |
# you still want to send that response, right? | |
[status, headers, body] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Lines 63 & 65 should be 'Content-Length'