Rackã®åãã«ã¤ãã¦ã³ã¼ãã追ã£ã¦ã¿ãã
Rackã®ãã¼ã¸ã§ã³ã¯1.4.1ã§ãã
Rackã®åãã®åã«ãã¾ãã¯ãã£ããRackã§åããã£ã¦ããã®ã確èªãã¦ã¿ããã
rack up!
ã¾ãã¯é©å½ã«Rackã®è¨å®ãã¡ã¤ã«å ¼ã¯ã©ã¹ãå®ç¾©ãã
require 'rack' require 'pp' class Sample def call(env) pp env [200, {"Content-Type" => "text/plain"}, ["rack up!\n"]] end end run Sample.new
ããã rack up ãã
sugamasao@GRAM% rackup sample.ru [2012-02-13 23:35:44] INFO WEBrick 1.3.1 [2012-02-13 23:35:44] INFO ruby 1.9.3 (2011-11-30) [x86_64-darwin10.8.0] [2012-02-13 23:35:44] INFO WEBrick::HTTPServer#start: pid=1660 port=9292
èµ·åããã
ã¢ã¯ã»ã¹ãã¦ã¿ããã
sugamasao@GRAM% curl http://localhost:9292
rack up!
æååãè¿ã£ã¦ãããcallã¡ã½ãããåãåãå¼æ°ã¨ãªã£ã¦ãenvã¯ä½ãåºã¦ãã®ããªï¼
{"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/", "QUERY_STRING"=>"", "REMOTE_ADDR"=>"127.0.0.1", "REMOTE_HOST"=>"localhost", "REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"http://localhost:9292/", "SCRIPT_NAME"=>"", "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"9292", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2011-11-30)", "HTTP_USER_AGENT"=> "curl/7.21.2 (x86_64-apple-darwin10.5.0) libcurl/7.21.2 OpenSSL/1.0.0g zlib/1.2.5 libidn/1.22", "HTTP_HOST"=>"localhost:9292", "HTTP_ACCEPT"=>"*/*", "rack.version"=>[1, 1], "rack.input"=> #<Rack::Lint::InputWrapper:0x000001022bd178 @input=#<StringIO:0x000001022b8f10>>, "rack.errors"=> #<Rack::Lint::ErrorWrapper:0x000001022bd100 @error=#<IO:<STDERR>>>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "rack.url_scheme"=>"http", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_PATH"=>"/"} 127.0.0.1 - - [13/Feb/2012 23:36:13] "GET / HTTP/1.1" 200 - 0.0051
ãªãã»ã©ãããããç°å¢å¤æ°ã渡ã£ã¦ãã¦ããããã ã
ããã§ã¯æ¬é¡
ãã®ä¸é£ã®æµãã¯ã©ã®ããã«åãã¦ããã®ãï¼
rackup ã³ãã³ããã追ã£ã¦ããã
rackup ã£ã¦ã³ãã³ãã使ã£ã¦ããããã ãããã³ãã³ããæ¢ãã¦ããã¨è¯ãã«éããªããã¨ããããrackã®gemsã®å ´æã¸ç§»åãã¦ã¿ãããã©ããããããªã人㯠gem envã³ãã³ãã使ã£ã¦GEM PATH: ã®ãã¹ã¸ç§»åãã¦ã¿ãã¨è¯ããã
gemsãã£ã¬ã¯ããªå
ã«rackã®gemã®ãã£ã¬ã¯ããªãããã®ã§ç§»åãããå½ç¶binãã£ã¬ã¯ããªãããã®ã§ä¸èº«ãè¦ã¦ã¿ããã
#!/usr/bin/env ruby require "rack" Rack::Server.start
ããããããããªãã®ãããããServer#startãè¦ãã°è¯ããã ãªï¼
server㯠lib/rack/server.rb ãã
éãã¦ã¿ãã¨ãã¤ãã㪠Server ã¯ã©ã¹å
ã«ããã« Option ã¯ã©ã¹ãåºã¦ãããOptParser使ã£ã¦ããããã ããå¼æ°è§£æç¨ã®å
é¨ã¯ã©ã¹ãªãã ãããã¨äºæ³ãç«ã¦ã¦èªã¿é£ã°ããã¨ããããrdefs*1ããã»ããèªã¿ãããããªæ°ããããªã
sugamasao@GRAM% rdefs lib/rack/server.rb module Rack class Server class Options def parse!(args) def handler_opts(options) def self.start(options = nil) attr_writer :options def initialize(options = nil) def options def default_options def app def self.logging_middleware def self.middleware def middleware def start &blk def server private def parse_options(args) def opt_parser def build_app(app) def wrapped_app def daemonize_app def write_pid
ãªãã»ã©ãself.startãç®çã®ã¡ã½ããã®ããã ãªãè¦ã«è¡ã£ã¦ã¿ããã
136 def self.start(options = nil) 137 new(options).start 138 end
ãµã¼ããããã®newã£ã¦ã®ã¯èªèº«ï¼Rack::Serverï¼ãã¤ã³ã¹ã¿ã³ã¹åãã¦ããã ãªãã¤ã¾ããRack::Server.new(options).startã£ã¦ããã ãããã¦ãã¤ã³ã¹ã¿ã³ã¹ã®startãå¼ãã§ããã¨ã
ã¡ãã£ã¨ã³ã³ã¹ãã©ã¯ã¿ãè¦ã¦ã¿ããã
174 def initialize(options = nil) 175 @options = options 176 @app = options[:app] if options && options[:app] 177 end 178 179 def options 180 @options ||= parse_options(ARGV) 181 end
ã¤ãã§ã«ã³ã³ã¹ãã©ã¯ã¿å
ã§å¼ãã§ã options ã¡ã½ãããæç²ãããparse_optionsã£ã¦ã®ãã¡ã½ããã§ããã®ä¸ã§Optionsã¯ã©ã¹ã使ã£ãããã¦ARGVã®è§£æãRACK_ENVã®è¨å®ã¨ããè¡ãªã£ã¦ããããã ã
ã¨ãããã¨ã¯ãããã§å¼æ°ã®sample.ruãèªãã§ããã®ãï¼
ã¨ã¯ãããOptionsã¯ã©ã¹ã¯æ®éã«opt.onã§å¼æ°ã®keyã¨valueã®çµã¿åãããã»ã¨ãã©ãªãã ããªãâ¦â¦ã£ã¨ãä¸çªæå¾ã«ããããããããªããããargsãparse!ãããå¾ã«æ®ã£ã¦ãããâ¦â¦ã¤ã¾ãããã¯-s ãã³ãã£ã©ã¿ãããªãã¼ã¯ã¼ãä»ãã®å¼æ°ãããªãã¦ãåç¬ã®å¼æ°ã£ã¦ãã¨ã«ãªããããã¤ã¾ãsample.ruã¨ãããã¨ã§ã¯ãªãã ãããï¼ï¼ããã§printãããã°ããããã®ã¨ããã ã£ãwï¼
92 options[:config] = args.last if args.last 93 options
ãªãã»ã©ãå¼æ°ã§æ¸¡ãã sample.ru 㯠options[:config] ã«å
¥ã£ã¦ããã®ã ãªã
ãã¦ãããã§ã¯ãã£ãã¯ãã©è¦ã§ãã¾ãã¦ãããå¼æ°ã®å¦çãæ¹ãã¦è¦ã¦ã¿ãããoptions[:config]ã絶対ãã¹ã«ãã¦ããªããããã¤ã¯ãã¤è©ä¾¡ãããã®ã ãããï¼
273 def parse_options(args) 274 options = default_options 275 276 # Don't evaluate CGI ISINDEX parameters. 277 # http://hoohoo.ncsa.uiuc.edu/cgi/cl.html 278 args.clear if ENV.include?("REQUEST_METHOD") 279 280 options.merge! opt_parser.parse!(args) 281 options[:config] = ::File.expand_path(options[:config]) 282 ENV["RACK_ENV"] = options[:environment] 283 options 284 end
ããã§optionã®è§£æã¯çµããã ããã¤ã³ã¹ã¿ã³ã¹ã¡ã½ããã®startã®æ¹ã«é²ãã ã»ããè¯ãããã ã
229 def start &blk (çç¥) 249 250 # Touch the wrapped app, so that the config.ru is loaded before 251 # daemonization (i.e. before chdir, etc). 252 wrapped_app 253 254 daemonize_app if options[:daemonize] 255 write_pid if options[:pid] 256 257 trap(:INT) do 258 if server.respond_to?(:shutdown) 259 server.shutdown 260 else 261 exit 262 end 263 end 264 265 server.run wrapped_app, options, &blk 266 end
ååã¯debugãã©ã°ãã©ãã¨ãã ããé¢ä¿ãªããªãdaemonã¨ãpidã¨ããSIGNALã®åãåã£ã¦ãæã¨ãããããªã«éè¦ã§ã¯ãªãã ãããããããã¨ãwrapped_appãæªãããæå¾ã«server.runã§ã使ã£ã¦ããã
ä¸ä½ä½ããã¦ããã ã£ã¦ã°ãï¼
ã£ã¦ããããã³ã¡ã³ãã«æ¸ãã¦ãããã©ãwrapped_appãå¼ãã§ãããã¨ã§ daemonizeããåã« config.ru ï¼ã¤ã¾ããã£ã¨ä»åã¯sample.ruã®ãã¨ã ããï¼ãloadãã¦ãã£ã¦ãã¨ãï¼
300 def wrapped_app 301 @wrapped_app ||= build_app app 302 end
build_app ã¡ã½ãããå¼ãã§ãããããããã§ãå¼æ°ã«appã使ã£ã¦ããã©ãã®appãã¾ãã¡ã½ããã§ããããããã
194 def app 195 @app ||= begin 196 if !::File.exist? options[:config] 197 abort "configuration #{options[:config]} not found" 198 end 199 200 app, options = Rack::Builder.parse_file(self.options[:config], opt_parser) 201 self.options.merge! options 202 app 203 end 204 end
options[:config]ã«sample.ruã®ãã¹ãå
¥ã£ã¦ãã®ã§ããããããã¡ã¤ã«ã®ãã¼ããè¡ãããããã ã
lib/rack/builder.rbãéãã¦ã¿ãããã¡ãã£ã¨ç²ãã¦ããããããparse_fileãã
32 def self.parse_file(config, opts = Server::Options.new) 33 options = {} 34 if config =~ /\.ru$/ 35 cfgfile = ::File.read(config) 36 if cfgfile[/^#\\(.*)/] && opts 37 options = opts.parse! $1.split(/\s+/) 38 end 39 cfgfile.sub!(/^__END__\n.*\Z/m, '') 40 app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app", 41 TOPLEVEL_BINDING, config 42 else 43 require config 44 app = Object.const_get(::File.basename(config, '.rb').capitalize) 45 end 46 return app, options 47 end
ããã¾ãã«ãæ¡å¼µåã.ruã§ããã° eval ã§Rack::Builder.newã®å¼æ°ã¨ãã¦é£ããã¦appã¨ããããã ããããããªããã°æ®éã«requireãã¦ããã¡ã¤ã«åããã¯ã©ã¹åãæ¨æ¸¬ãã¦appã¨ããã¨*2ã
å¿ãæãããã ãã©ãããã°ã£ã¦Rack::Builder.newãè¦ã¦ã¿ãããã
49 def initialize(default_app = nil,&block) 50 @use, @map, @run = [], nil, default_app 51 instance_eval(&block) if block_given? 52 end
ããããã®ã³ã¼ããè¦ãã¾ã§åãããªãã£ããã ãã©ãevalã§ä¸ãã¦ãå¼æ°ã£ã¦ããã©ã«ãå¼æ°ã«ãªã£ã¦ãdefault_appã®é¨åãçç¥ãã¦ãããã¯ã ã渡ãã¦ããã ãã¤ã¾ããdefault_appã¯nilã§ãblockã®æ¹ã«sample.ruã®ä¸èº«ã渡ã£ã¦ãã¦ãã£ã¦ãã¨ãã¨ããã¨ãããã«å®éã¯instance_evalãå®è¡ããã¦ããã£ã¦ãã¨ã ãinstance_evalã£ã¦ã®ã¯instance_evalã¡ã½ããã®ããã¹ã³ã¼ãã§ãã®blockãå®è¡ããã£ã¦ãããã¥ã¢ã³ã¹ã ã¨æã£ã¦ããã®ã§ãã¤ã¾ããã®initializeã¡ã½ããå
ã§sample.ruã®ä¸èº«ãå®è¡ããã¦ããã¨æãã°è¯ãã ããã
ãããã¦ãsample.ruãæãè¿ãã¨ãrunã¡ã½ããã§ãã¯ã©ã¹ãnewããã¤ã³ã¹ã¿ã³ã¹ã渡ãã¦ããããã ãã¯ã©ã¹ãnewããã®ã¯æ®éãªã®ã§ç½®ãã¦ããã¦ãrunã¡ã½ããã ããã®runã¡ã½ããã¯instance_evalããæ¨æ¸¬ããã«ãã£ã¨ãã®Rack:Builderã¯ã©ã¹ã®runã¡ã½ããã使ã£ã¦ããã®ã ã
99 def run(app) 100 @run = app 101 end
ãã£ããããã ãã¤ã¾ã@runã«ã¯sample.rnå
ã§å®ç¾©ããSample.newã®ã¤ã³ã¹ã¿ã³ã¹ãå
¥ã£ã¦ããã®ã !!
ãã§ãã¡ãã£ã¨ãã©ã£ã¦æåã®evalã«æ»ãã¨ãnewããå¾ã« to_app ããã¦ãããto_appã¨ã¯ï¼
127 def to_app 128 app = @map ? generate_map(@run, @map) : @run 129 fail "missing run or map statement" unless app 130 @use.reverse.inject(app) { |a,e| e[a] } 131 end
ãã¼ããã¨ãããã«ã¼ãã£ã³ã°ã¨ãã®è¨å®ããå§ããã®ã ãããï¼ã¾ãååã®ãã®ã¿ã¤ãã³ã°ã«éã£ã¦è¨ãã°@mapã¯nilã ãã@useã¯ç©ºã®é
åãªã®ã§ãinjectã®çµæ app â¦â¦ã¤ã¾ã @run ãè¿ãã ããªãã ãã©ãã
ã¡ãã£ã¨ç²ãã¦ããã®ã§generate_mapã¨ãã¯ç½®ãã¦ããããããããå°ãã§ã´ã¼ã«ãè¦ãã¦ãããã ã
ãã¦ãå度server.rbã¸æ»ã£ã¦ãããã
194 def app 195 @app ||= begin 196 if !::File.exist? options[:config] 197 abort "configuration #{options[:config]} not found" 198 end 199 200 app, options = Rack::Builder.parse_file(self.options[:config], opt_parser) 201 self.options.merge! options 202 app 203 end 204 end
ãããã¦ã¿ãã¨ããã®appã«ã¯sample.ruå
ã«æ¸ãã¦ããSampleã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ãå
¥ã£ã¦ããã¨ããã®ããããã
ããããããããç¶ããè¦ããã
290 def build_app(app) 291 middleware[options[:environment]].reverse_each do |middleware| 292 middleware = middleware.call(self) if middleware.respond_to?(:call) 293 next unless middleware 294 klass = middleware.shift 295 app = klass.new(app, *middleware) 296 end 297 app 298 end
build_appã«è¡ãã¨çªç¶middlewareã¨ãè¨ãã®ãã§ã¦ãããããã追ãã¨ãã¤ã³ã¹ã¿ã³ã¹ã¡ã½ããã®middlewareããããã«ã¯ã©ã¹ã¡ã½ããã®middlewareã«ç§»ãã
212 def self.middleware 213 @middleware ||= begin 214 m = Hash.new {|h,k| h[k] = []} 215 m["deployment"].concat [ 216 [Rack::ContentLength], 217 [Rack::Chunked], 218 logging_middleware 219 ] 220 m["development"].concat m["deployment"] + [[Rack::ShowExceptions], [Rack::Lint]] 221 m 222 end 223 end
ããã§ã¯ãContentLengthã¨ããäºãcallã¡ã½ãããæã£ãRackããã«ã¦ã§ã¢ç¾¤ã®ä¸ã§ããã©ã«ãã§Rackãç©ãã§ããããã®ãç»é²ãã¦ããããã ã
build_appã«æ»ã£ã¦ã¿ãã¨ããã®ç©ã¾ããããã«ã¦ã§ã¢ãcallããããnewãã¦ãããnewãã¦ããå ´åï¼ä»åãããã ï¼ã¯ãååã¯å¼æ°ããäºåç®ä»¥éã¯ãã®newãããªãã¸ã§ã¯ããããã«å¼æ°ã¨ãã¦æ¬¡ã®ããã«ã¦ã§ã¢ã«è¼ãã¦è¡ã£ã¦ãããã¤ã¾ããç»é²ãããããã«ã¦ã§ã¢ã¨ã¢ããªã±ã¼ã·ã§ã³ãã³ã³ã¹ãã©ã¯ã¿ã®å¼æ°ã§ãã³ãã³ç©ã¿ä¸ãã¦ããã¨ããããæ¼ãè¾¼ãã§ããã®ã ã
ãããã¦æçµçã«ä½æãããããã«ã¦ã§ã¢ãappã¨ãã¦returnãããã®ã§ãã£ãã
290 def build_app(app) 291 middleware[options[:environment]].reverse_each do |middleware| 292 middleware = middleware.call(self) if middleware.respond_to?(:call) 293 next unless middleware 294 klass = middleware.shift 295 app = klass.new(app, *middleware) 296 end 297 app 298 end
build_appã§è¿ã£ã¦ãããªãã¸ã§ã¯ãã¯ãã®ã¾ã¾wrapped_appã«è¿ããããã§ããããå
ã«ãããããã
ã§ãstartã¡ã½ããã®æå¾ã®è¡ã«å°éããã®ã§ãã£ãã
265 server.run wrapped_app, options, &blk
wrapped_appã¯ãã£ãã®éããç©ã¿ä¸ãã£ãããã«ã¦ã§ã¢ã ãoptionsã¯å¼æ°ãããªã®ã§æ°ã«ããªãã¦è¯ãã ãããblkãä»åã®startã¡ã½ããã®å¼ã³åºãã§ã¯ä½¿ã£ã¦ããªãã®ã§ç¡ããã¤ã¾ãããã¨ã¯server.runãè¦ãã°çãããããã¯ãã§ããã
ã§ãserverã£ã¦ä½ãï¼
268 def server 269 @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default(options) 270 end
Rack::Handlerããããã
options[:server]ã¯å¼æ°ã§æå®ã§ããã¿ããã ãã©ãç¹ã«æå®ãã¦ããªãã®ã§nilãå
¥ã£ã¦ãããã®ã§ãå®éã¯Rack::Handler.defaultãå¼ã°ãã¦ããã¯ãã§ããã
lib/rack/handler.rb ã® default ã¡ã½ãããè¦ã¦ã¿ããã
29 def self.default(options = {}) 30 # Guess. 31 if ENV.include?("PHP_FCGI_CHILDREN") 32 # We already speak FastCGI 33 options.delete :File 34 options.delete :Port 35 36 Rack::Handler::FastCGI 37 elsif ENV.include?("REQUEST_METHOD") 38 Rack::Handler::CGI 39 else 40 begin 41 Rack::Handler::Thin 42 rescue LoadError 43 Rack::Handler::WEBrick 44 end 45 end 46 end
handlerãæ示ããªãå ´åã«ã¯ç°å¢ã«åããã¦ä½ãå¼ã¶ã決ãã¦ããããã ãä»åã®ãµã³ãã«ã§ã¯webricãèµ·åãã¦ããã®ã§ãä¸çªæå¾ã®rescueã¾ã§è½ã¡ããã¨ãããã¨ãªãã ããã
ã§ããã®handlerã®runã¡ã½ããã¨ã¯ï¼
lib/rack/handler/webrick.rb ã® run ã¡ã½ãããè¦ã¦ã¿ããã
8 def self.run(app, options={}) 9 options[:BindAddress] = options.delete(:Host) if options[:Host] 10 @server = ::WEBrick::HTTPServer.new(options) 11 @server.mount "/", Rack::Handler::WEBrick, app 12 yield @server if block_given? 13 @server.start 14 end
æçµçã«ã¯webrickã®mountã§URLããããã³ã°ãã¦ãèªèº«ã®ã¯ã©ã¹ï¼Rack::Handler::WEBrickï¼ã¨ãããã«ã¦ã§ã¢ç¾¤ã渡ãã¦ãããã¨ãããã¨ãªã®ã ãªã
ã¨ããããã§mountã調ã¹ãã¨
第ä¸å¼æ°ããã£ã¬ã¯ããªï¼ãã®å ´å"/"ã ï¼ã第äºå¼æ°ããµã¼ãã¬ããã第ä¸å¼æ°ããªãã·ã§ã³ã¨ãããã¨ãããã
ã§ãããã¥ã¡ã³ãã«ããã¨ã第äºå¼æ°ã§ãããµã¼ãã¬ããã®ãªãã¸ã§ã¯ããçæãã¦ãserviceã¡ã½ãããã³ã¼ã«ããããããããã¦ãªãã¸ã§ã¯ããçæããéã«ãå¼æ°ã¨ãã¦ç¬¬ä¸å¼æ°ã®ãªãã¸ã§ã¯ãã渡ãã¦ãããããã ã
ããããã¨ãå®éã«HTTPãªã¯ã¨ã¹ããæ¥ãæã®æµãã¯Rack::Handler::WEBrickã®ã³ã³ã¹ãã©ã¯ã¿ã¨serviceã¡ã½ãããè¦ãã°è¯ãããã ã
ã³ã³ã¹ãã©ã¯ã¿ã¯superã¯ã©ã¹ãå¼ã¶ã®ã¨optionã§æ¸¡ã£ã¦ããããã«ã¦ã§ã¢ãªãã¸ã§ã¯ãã確ä¿ããã¦ããã ãã
ããããserviceã¡ã½ããã¯ãã¨ããã¨
33 def service(req, res) (çç¥) 59 status, headers, body = @app.call(env) 60 begin (çç¥) 71 body.each { |part| 72 res.body << part 73 } 74 ensure 75 body.close if body.respond_to? :close 76 end 77 end
ã¨ããããã§ãç¡äºã«Rackããã«ã¦ã§ã¢ã®callã«ãã©ãçãããããã«ã¦ã§ã¢éã¯ã²ãããcallã§èªåã®ä¸ã«ä¹ã£ã¦ããããã«ã¦ã§ã¢ãå¼ã¶ã®ã§ãæçµçã«ã¯Sampleã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ã«ãã©ãçãã¨ãã寸æ³ã§ããã
ããã§é·å¹´ã® run Sample.newã®è¬ãã¨ãã¦ãã£ããããã
ããã¼ããããé·ãã£ãããã