# encoding: binary# Phusion Passenger - https://www.phusionpassenger.com/# Copyright (c) 2010-2013 Phusion## "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.## Permission is hereby granted, free of charge, to any person obtaining a copy# of this software and associated documentation files (the "Software"), to deal# in the Software without restriction, including without limitation the rights# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell# copies of the Software, and to permit persons to whom the Software is# furnished to do so, subject to the following conditions:## The above copyright notice and this permission notice shall be included in# all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN# THE SOFTWARE.require'phusion_passenger/utils/tee_input'modulePhusionPassengermoduleRackmoduleThreadHandlerExtension# Constants which exist to relieve Ruby's garbage collector.RACK_VERSION="rack.version"# :nodoc:RACK_VERSION_VALUE=[1,2]# :nodoc:RACK_INPUT="rack.input"# :nodoc:RACK_ERRORS="rack.errors"# :nodoc:RACK_MULTITHREAD="rack.multithread"# :nodoc:RACK_MULTIPROCESS="rack.multiprocess"# :nodoc:RACK_RUN_ONCE="rack.run_once"# :nodoc:RACK_URL_SCHEME="rack.url_scheme"# :nodoc:RACK_HIJACK_P="rack.hijack?"# :nodoc:RACK_HIJACK="rack.hijack"# :nodoc:SCRIPT_NAME="SCRIPT_NAME"# :nodoc:HTTPS="HTTPS"# :nodoc:HTTPS_DOWNCASE="https"# :nodoc:HTTP="http"# :nodoc:YES="yes"# :nodoc:ON="on"# :nodoc:ONE="1"# :nodoc:CRLF="\r\n"# :nodoc:NEWLINE="\n"# :nodoc:STATUS="Status: "# :nodoc:NAME_VALUE_SEPARATOR=": "# :nodoc:defprocess_request(env,connection,socket_wrapper,full_http_response)rewindable_input=PhusionPassenger::Utils::TeeInput.new(connection,env)beginenv[RACK_VERSION]=RACK_VERSION_VALUEenv[RACK_INPUT]=rewindable_inputenv[RACK_ERRORS]=STDERRenv[RACK_MULTITHREAD]=@request_handler.concurrency>1env[RACK_MULTIPROCESS]=trueenv[RACK_RUN_ONCE]=falseifenv[HTTPS]==YES||env[HTTPS]==ON||env[HTTPS]==ONEenv[RACK_URL_SCHEME]=HTTPS_DOWNCASEelseenv[RACK_URL_SCHEME]=HTTPendenv[RACK_HIJACK_P]=trueenv[RACK_HIJACK]=lambdadoenv[RACK_HIJACK_IO]||=beginconnection.stop_simulating_eof!connectionendendbeginstatus,headers,body=@app.call(env)rescue=>eifshould_reraise_app_error?(e,socket_wrapper)raiseeelsif!should_swallow_app_error?(e,socket_wrapper)# It's a good idea to catch application exceptions here because# otherwise maliciously crafted responses can crash the app,# forcing it to be respawned, and thereby effectively DoSing it.print_exception("Rack application object",e)endreturnfalseend# Application requested a full socket hijack.returntrueifenv[RACK_HIJACK_IO]beginiffull_http_responseconnection.write("HTTP/1.1 #{status.to_i.to_s} Whatever#{CRLF}")connection.write("Connection: close#{CRLF}")endheaders_output=[STATUS,status.to_i.to_s,CRLF]headers.eachdo|key,values|ifvalues.is_a?(String)values=values.split(NEWLINE)elsifkey==RACK_HIJACK# We do not check for this key name in every loop# iteration as an optimization.nextendvalues.eachdo|value|headers_output<<keyheaders_output<<NAME_VALUE_SEPARATORheaders_output<<valueheaders_output<<CRLFendendheaders_output<<CRLFifhijack_callback=headers[RACK_HIJACK]# Application requested a partial socket hijack.body=nilconnection.writev(headers_output)connection.flushhijacked_socket=env[RACK_HIJACK].callhijack_callback.call(hijacked_socket)returntrueelsifbody.is_a?(Array)# The body may be an ActionController::StringCoercion::UglyBody# object instead of a real Array, even when #is_a? claims so.# Call #to_a just to be sure.connection.writev2(headers_output,body.to_a)returnfalseelsifbody.is_a?(String)headers_output<<bodyconnection.writev(headers_output)returnfalseelseconnection.writev(headers_output)ifbodybeginbody.eachdo|s|connection.write(s)endrescue=>eifshould_reraise_app_error?(e,socket_wrapper)raiseeelsif!should_swallow_app_error?(e,socket_wrapper)# Body objects can raise exceptions in #each.print_exception("Rack body object #each method",e)endreturnfalseendendreturnfalseendensurebody.closeifbody&&body.respond_to?(:close)endensurerewindable_input.closeendendprivateendend# module Rackend# module PhusionPassenger