From 4d5c57d62e603cbadf6b896489ae49bb197b6fe8 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 26 Jul 2016 22:13:00 +0000 Subject: http_response: drop bodies for non-compliant responses Rack::Lint-compliant applications wouldn't have this problem; but apparently public-facing Rack servers (webrick/puma/thin) all implement this; so there is precedence for implementing this in yahns itself. --- lib/yahns/http_client.rb | 9 ++++++--- lib/yahns/http_response.rb | 12 +++++------- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/yahns/http_client.rb b/lib/yahns/http_client.rb index 1cdaa0f..873dd73 100644 --- a/lib/yahns/http_client.rb +++ b/lib/yahns/http_client.rb @@ -189,9 +189,11 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: mkinput_preread # keep looping (@state == :body) true else # :lazy, false - status, headers, body = k.app.call(env = @hs.env) + env = @hs.env + hdr_only = env['REQUEST_METHOD'] == 'HEAD'.freeze + status, headers, body = k.app.call(env) return :ignore if app_hijacked?(env, body) - http_response_write(status, headers, body) + http_response_write(status, headers, body, hdr_only) end end @@ -220,6 +222,7 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: env['SERVER_PORT'] = '443'.freeze end + hdr_only = env['REQUEST_METHOD'] == 'HEAD'.freeze # run the rack app status, headers, body = k.app.call(env) return :ignore if app_hijacked?(env, body) @@ -229,7 +232,7 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc: end # this returns :wait_readable, :wait_writable, :ignore, or nil: - http_response_write(status, headers, body) + http_response_write(status, headers, body, hdr_only) end # called automatically by kgio_write diff --git a/lib/yahns/http_response.rb b/lib/yahns/http_response.rb index d957df6..88ff9f9 100644 --- a/lib/yahns/http_response.rb +++ b/lib/yahns/http_response.rb @@ -9,7 +9,7 @@ require_relative 'wbuf_str' # You use it by simply doing: # # status, headers, body = rack_app.call(env) -# http_response_write(status, headers, body) +# http_response_write(status, headers, body, env['REQUEST_METHOD']=='HEAD') # # Most header correctness (including Content-Length and Content-Type) # is the job of Rack, with the exception of the "Date" header. @@ -118,13 +118,9 @@ module Yahns::HttpResponse # :nodoc: end end - def have_more?(value) - value.to_i > 0 && @hs.env['REQUEST_METHOD'] != 'HEAD'.freeze - end - # writes the rack_response to socket as an HTTP response # returns :wait_readable, :wait_writable, :forget, or nil - def http_response_write(status, headers, body) + def http_response_write(status, headers, body, hdr_only) offset = 0 count = hijack = nil k = self.class @@ -133,6 +129,7 @@ module Yahns::HttpResponse # :nodoc: if @hs.headers? code = status.to_i + hdr_only ||= Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(code) msg = Rack::Utils::HTTP_STATUS_CODES[code] buf = "#{response_start}#{msg ? %Q(#{code} #{msg}) : status}\r\n" \ "Date: #{httpdate}\r\n".dup @@ -150,7 +147,7 @@ module Yahns::HttpResponse # :nodoc: # allow Rack apps to tell us they want to drop the client alive = false if value =~ /\bclose\b/i when %r{\AContent-Length\z}i - flags |= MSG_MORE if have_more?(value) + flags |= MSG_MORE if value.to_i > 0 && !hdr_only kv_str(buf, key, value) when "rack.hijack" hijack = value @@ -181,6 +178,7 @@ module Yahns::HttpResponse # :nodoc: end return response_hijacked(hijack) if hijack + return http_response_done(alive) if hdr_only if body.respond_to?(:to_path) @state = body = Yahns::StreamFile.new(body, alive, offset, count) -- cgit v1.2.3-24-ge0c7