Rack 为开发 Ruby web 应用提供了一个最小的模块化和适应性接口。通过对 HTTP 请求与响应 的尽可能最简单的方式包装,它统一和提炼 Web 服务器 ,Web 框架,和之间的软件(所谓的中间件)的 API 为单一方法调用。
什么是rack app
A Rack application is any Ruby object that responds to the call method, takes a single hash parameter and returns an array containing the response status code, HTTP response headers and the response body as an array of strings.
defstart(&block)...while@status==:Running...ifsvrs=IO.select(@listeners,nil,nil,2.0)@logger.debug(svrs.to_s)svrs[0].each{|svr|@tokens.pop# blocks while no token is there.ifsock=accept_client(svr)sock.do_not_reverse_lookup=config[:DoNotReverseLookup]th=start_thread(sock,&block)th[:WEBrickThread]=truethgroup.add(th)else@tokens.push(nil)end}end...end...}end
defrun(sock)whiletrueres=HTTPResponse.new(@config)req=HTTPRequest.new(@config)server=selfbegintimeout=@config[:RequestTimeout]whiletimeout>0breakifIO.select([sock],nil,nil,0.5)timeout=0if@status!=:Runningtimeout-=0.5endraiseHTTPStatus::EOFErroriftimeout<=0raiseHTTPStatus::EOFErrorifsock.eof?req.parse(sock)res.request_method=req.request_methodres.request_uri=req.request_urires.request_http_version=req.http_versionres.keep_alive=req.keep_alive?server=lookup_server(req)||selfifcallback=server[:RequestCallback]callback.call(req,res)elsifcallback=server[:RequestHandler]msg=":RequestHandler is deprecated, please use :RequestCallback"@logger.warn(msg)callback.call(req,res)endserver.service(req,res)rescueHTTPStatus::EOFError,HTTPStatus::RequestTimeout=>exres.set_error(ex)rescueHTTPStatus::Error=>ex@logger.error(ex.message)res.set_error(ex)rescueHTTPStatus::Status=>exres.status=ex.coderescueStandardError=>ex@logger.error(ex)res.set_error(ex,true)ensureifreq.request_lineifreq.keep_alive?&&res.keep_alive?req.fixup()endres.send_response(sock)server.access_log(@config,req,res)endendbreakif@http_version<"1.1"breakunlessreq.keep_alive?breakunlessres.keep_alive?endend
defparse(socket=nil)@socket=socketbegin@peeraddr=socket.respond_to?(:peeraddr)?socket.peeraddr:[]@addr=socket.respond_to?(:addr)?socket.addr:[]rescueErrno::ENOTCONNraiseHTTPStatus::EOFErrorendread_request_line(socket)if@http_version.major>0read_header(socket)@header['cookie'].each{|cookie|@cookies+=Cookie::parse(cookie)}@accept=HTTPUtils.parse_qvalues(self['accept'])@accept_charset=HTTPUtils.parse_qvalues(self['accept-charset'])@accept_encoding=HTTPUtils.parse_qvalues(self['accept-encoding'])@accept_language=HTTPUtils.parse_qvalues(self['accept-language'])endreturnif@request_method=="CONNECT"returnif@unparsed_uri=="*"beginsetup_forwarded_info@request_uri=parse_uri(@unparsed_uri)@path=HTTPUtils::unescape(@request_uri.path)@path=HTTPUtils::normalize_path(@path)@host=@request_uri.host@port=@request_uri.port@query_string=@request_uri.query@script_name=""@path_info=@path.duprescueraiseHTTPStatus::BadRequest,"bad URI `#{@unparsed_uri}'."endif/close/io=~self["connection"]@keep_alive=falseelsif/keep-alive/io=~self["connection"]@keep_alive=trueelsif@http_version<"1.1"@keep_alive=falseelse@keep_alive=trueendend