# Copyright (C) 2013, Eric Wong and all contributors # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) require_relative 'server_helper' class TestRackHijack < Testcase parallelize_me! include ServerHelper alias setup server_helper_setup alias teardown server_helper_teardown class DieIfUsed def each abort "body.each called after response hijack\n" end def close abort "body.close called after response hijack\n" end end HIJACK_APP = lambda { |env| case env["PATH_INFO"] when "/hijack_req" io = env["rack.hijack"].call if io.respond_to?(:read_nonblock) && env["rack.hijack_io"].respond_to?(:read_nonblock) # exercise both, since we Rack::Lint may use different objects env["rack.hijack_io"].write("HTTP/1.0 200 OK\r\n\r\n") io.write("request.hijacked") io.close return [ 500, {}, DieIfUsed.new ] end [ 500, {}, [ "hijack BAD\n" ] ] when "/hijack_res" r = "response.hijacked" [ 200, { "X-Test" => "zzz", "Content-Length" => r.bytesize.to_s, "rack.hijack" => proc { |x| x.write(r); x.close } }, DieIfUsed.new ] end } def test_hijack err = @err cfg = Yahns::Config.new host, port = @srv.addr[3], @srv.addr[1] cfg.instance_eval do GTL.synchronize { app(:rack, HIJACK_APP) { listen "#{host}:#{port}" } } logger(Logger.new(err.path)) end srv = Yahns::Server.new(cfg) pid = fork do ENV["YAHNS_FD"] = @srv.fileno.to_s srv.start.join end res = Net::HTTP.start(host, port) { |h| h.get("/hijack_req") } assert_equal "request.hijacked", res.body assert_equal 200, res.code.to_i assert_equal "1.0", res.http_version res = Net::HTTP.start(host, port) { |h| h.get("/hijack_res") } assert_equal "response.hijacked", res.body assert_equal 200, res.code.to_i assert_equal "zzz", res["X-Test"] assert_equal "1.1", res.http_version ensure quit_wait(pid) end end