From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-3.0 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, URIBL_BLOCKED shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: yahns-public@yhbt.net Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id D028F202ED; Fri, 12 Feb 2016 04:05:49 +0000 (UTC) Date: Fri, 12 Feb 2016 04:05:49 +0000 From: Eric Wong To: yahns-public@yhbt.net Subject: [PATCH 4/3] set HTTPS and rack.url_scheme in Rack env as appropriate Message-ID: <20160212040549.GA3901@dcvr.yhbt.net> References: <20160212014713.32163-1-e@80x24.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20160212014713.32163-1-e@80x24.org> List-Id: Eric Wong wrote: > Things like rack.url_scheme, SERVER_NAME, SERVER_PORT, etc... > will all need to be set properly. SERVER_NAME and SERVER_PORT will be set inside the unicorn HTTP parser based on the value of the Host: header -----------8<----------- Subject: [PATCH] set HTTPS and rack.url_scheme in Rack env as appropriate env['HTTPS'] is not documented in rack SPEC, but appears to be used by Rack::Request since 2010[*]. Also, set rack.url_scheme as documented by rack SPEC. [*] - commit 4defbe5d7c07b3ba721ff34a8ff59fde480a4a9f ("Improves performance by lazy loading the session.") --- lib/yahns/http_context.rb | 2 +- lib/yahns/server.rb | 3 +++ test/test_ssl.rb | 43 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/yahns/http_context.rb b/lib/yahns/http_context.rb index 10be062..c02eefd 100644 --- a/lib/yahns/http_context.rb +++ b/lib/yahns/http_context.rb @@ -17,7 +17,7 @@ module Yahns::HttpContext # :nodoc: attr_accessor :qegg attr_accessor :queue # set right before spawning acceptors attr_reader :app - attr_reader :app_defaults + attr_accessor :app_defaults attr_writer :input_buffer_tmpdir attr_accessor :output_buffer_tmpdir diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb index 09ddbef..d6a03f3 100644 --- a/lib/yahns/server.rb +++ b/lib/yahns/server.rb @@ -382,6 +382,9 @@ def fdmap_init ctx.__send__(:include, l.expire_mod) if ssl_ctx = opts[:ssl_ctx] ctx.__send__(:include, Yahns::OpenSSLClient) + env = ctx.app_defaults = ctx.app_defaults.dup + env['HTTPS'] = 'on' # undocumented, but Rack::Request uses this + env['rack.url_scheme'] = 'https' # call OpenSSL::SSL::SSLContext#setup explicitly here to detect # errors and avoid race conditions. We avoid calling this in the diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 172d8e4..fe7e09e 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -63,12 +63,21 @@ def srv_ctx def test_ssl_basic err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1] + insecure = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0) ctx = srv_ctx raw = File.read(__FILE__) pid = mkserver(cfg) do + ENV["YAHNS_FD"] += ",#{insecure.fileno.to_s}" cfg.instance_eval do ru = lambda do |env| - case env['PATH_INFO'] + case path_info = env['PATH_INFO'] + when '/rack.url_scheme', '/HTTPS' + s = env[path_info[1..-1]] # remove leading slash + s = s.inspect if s.nil? + [ 200, { + 'Content-Length' => s.bytesize.to_s, + 'Content-Type'=>'text/plain', + }, [ s ] ] when '/static' f = File.open(__FILE__) [ 200, { @@ -80,19 +89,36 @@ def test_ssl_basic [ 200, {'Content-Length'=>'2'}, ['HI'] ] end end - app(:rack, ru) { listen "#{host}:#{port}", ssl_ctx: ctx } + app(:rack, ru) { + listen "#{host}:#{port}", ssl_ctx: ctx + listen "#{insecure.addr[3]}:#{insecure.addr[1]}" + } logger(Logger.new(err.path)) end end client = ssl_client(host, port) - client.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") buf = ''.dup - Timeout.timeout(60) do - buf << client.readpartial(111) until buf =~ /HI\z/ + { '/' => 'HI', + '/rack.url_scheme' => 'https', + '/HTTPS' => 'on' + }.each do |path, exp| + client.write("GET #{path} HTTP/1.1\r\nHost: example.com\r\n\r\n") + buf.clear + re = /#{Regexp.escape(exp)}\z/ + Timeout.timeout(60) do + buf << client.readpartial(111) until buf =~ re + end + head, body = buf.split("\r\n\r\n", 2) + assert_equal exp, body + assert_match %r{\AHTTP/1\.\d 200 OK\r\n}, head + end + + Net::HTTP.start(insecure.addr[3], insecure.addr[1]) do |h| + res = h.get('/rack.url_scheme') + assert_equal 'http', res.body + res = h.get('/HTTPS') + assert_equal 'nil', res.body end - head, body = buf.split("\r\n\r\n", 2) - assert_equal "HI", body - assert_match %r{\AHTTP/1\.\d 200 OK\r\n}, head # read static file client.write("GET /static HTTP/1.1\r\nHost: example.com\r\n\r\n") @@ -109,6 +135,7 @@ def test_ssl_basic assert_equal "HI", body assert_match %r{\AHTTP/1\.\d 200 OK\r\n}, head ensure + insecure.close if insecure client.close if client quit_wait(pid) end -- EW