Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実録 Let's build a simple Rack compatible server

実録 Let's build a simple Rack compatible server

Transcript

  1. ࣮࿥ -FU`TCVJMEBTJNQMF 3BDLDPNQBUJCMFTFSWFS⚡⚡⚡ ԘҪඒ࡙!DPF@ 'FC େߐށ3VCZձٞ

  2. ࣗݾ঺հ ԘҪඒ࡙ ͓͍͠ !DPF@  8FCϓϩάϥϚ "TBLVTBSCɺ5BNBSCɺ'VLVPLBSCʢ࿦ཧʣʹ͍·͢ "TBLVTBSCʹ௨͍࢝ΊͯૣҰ೥൒ ࠷ۙ8FCαʔόʔΛ࡞Γ·ͨ͠

  3. ࣗݾ঺հ ԘҪඒ࡙ ͓͍͠ !DPF@  8FCϓϩάϥϚ "TBLVTBSCɺ5BNBSCɺ'VLVPLBSCʢ࿦ཧʣʹ͍·͢ "TBLVTBSCʹ௨͍࢝ΊͯૣҰ೥൒ ࠷ۙ8FCαʔόʔΛ࡞Γ·ͨ͠ ‐ࠓ೔ͷ͓࿩

  4. 3VCZ$POG/BTIWJMMF /PWFNCFS 

  5. ग़యɿIUUQTOPUJTUFTUIFSD(V(+MFUTCVJMEBTJNQMFIUUQTFSWFSXJUISVCZ ʮ-FU`TCVJMEBTJNQMF)551TFSWFSʯ &45)&30-"56/%&͞Μ!FTUIFS ‎

  6. ‎JHBJHB͞Μ!JHBJHB‎ ग़యɿIUUQTUXJUUFSDPNJHBJHBTUBUVT T

  7. ‎͏ͮΒ͞Μ!VE[VSB 'VLVPLBSC ‎ ‎Θͨ͠ !DPF@ ग़యɿIUUQTUXJUUFSDPNVE[VSBTUBUVT T !DPF@

  8. ͱ͍͏͜ͱͰɺ ൃදࢿྉΛࢀߟʹ γϯϓϧͳ)551αʔόʔΛ ࡞ͬͯΈ·ͨ͠

  9. ग़དྷ্͕ͬͨͷ͕ͪ͜Β 1 require ‘socket’ 2 3 server = TCPServer.new(‘localhost’, 5000)

    4 5 loop do 6 client = server.accept 7 request = client.readpartial(2048) 8 9 puts request 10 11 client.puts response <<~MESSAGE 12 HTTP/1.1 200 OK\r\n 13 Content-Type: text/plain\r\n 14 \r\n 15 Hello!\r\n 16 MESSAGE 17 end TPDLFUϥΠϒϥϦΛSFRVJSF
  10. 1 require ‘socket’ 2 3 server = TCPServer.new(‘localhost’, 5000) 4

    5 loop do 6 client = server.accept 7 request = client.readpartial(2048) 8 9 puts request 10 11 client.puts response <<~MESSAGE 12 HTTP/1.1 200 OK\r\n 13 Content-Type: text/plain\r\n 14 \r\n 15 Hello!\r\n 16 MESSAGE 17 end αʔόʔ઀ଓΛPQFO ΫϥΠΞϯτ͔Βͷ઀ଓཁٻΛड͚෇͚Δ ϦΫΤετϝοηʔδΛಡΈࠐΉ ϦΫΤετϝοηʔδΛαʔόʔଆʹग़ྗ ద౰ͳϨεϙϯεϝοηʔδ ϨεϙϯεϝοηʔδΛΫϥΠΞϯτଆʹग़ྗ ग़དྷ্͕ͬͨͷ͕ͪ͜Β
  11. DVSMMPDBMIPTU ࡞ͬͨαʔόʔͷϗετͱϙʔτ൪߸

  12. ಈ͖·ͨ͠ αʔόʔଆ ΫϥΠΞϯτଆ ϦΫΤετϝοηʔδ͕ ग़ྗ͞Ε͍ͯΔ ϨεϙϯεϘσΟ͕ ग़ྗ͞Ε͍ͯΔ

  13. ͔͠͠

  14. ಈతͳΞϓϦέʔγϣϯʹ͸ରԠ͍ͯ͠ͳ͍⚠ 1 require ‘socket’ 2 3 server = TCPServer.new(‘localhost’, 5000)

    4 5 loop do 6 client = server.accept 7 request = client.readpartial(2048) 8 9 puts request 10 11 client.puts response <<~MESSAGE 12 HTTP/1.1 200 OK\r\n 13 Content-Type: text/plain\r\n 14 \r\n 15 Hello!\r\n 16 MESSAGE 17 end ͦ΋ͦ΋ ΞϓϦέʔγϣϯ͕ ଘࡏ͠ͳ͍ ΞΫηε͢Δͨͼɺຖճ ಉ͡Ϩεϙϯεϝοηʔδ͕ ग़ྗ͞ΕΔ
  15. ͔ͤͬ͘ͳͷͰ 3BDLDPNQBUJCMFʹ͍ͨ͠

  16. γϯϓϧͰ3BDLDPNQBUJCMFͳ 4JNQMF3BDL$PNQBUJCMF4FSWFS ͱ͍͏໊લͷαʔόʔΛ ࡞ͬͯΈ͍ͨͱࢥ͍·͢

  17. 1 require ‘rack’ 2 require_relative ‘../server/simple_rack_compatible_server’ 3 4 class App

    5 def call(env) 6 [ 7 200, 8 { ‘Content-Type’ => ‘text/html’ }, 9 [“<div><h1>Hello.</h1><p>This app is running on .…</p></div>”] 10 ] 11 end 12 end 13 14 run App.new ݕূ༻ͷ3BDLΞϓϦέʔγϣϯ͕ͪ͜Β app/sample.ru
  18. 1 require ‘rack’ 2 require_relative ‘../server/simple_rack_compatible_server’ 3 4 class App

    5 def call(env) 6 [ 7 200, 8 { ‘Content-Type’ => ‘text/html’ }, 9 [“<div><h1>Hello.</h1><p>This app is running on .…</p></div>”] 10 ] 11 end 12 end 13 14 run App.new εςʔλε‎)5510, ϔομ‎$POUFOU5ZQFUFYUIUNM ϘσΟ‎EJW I)FMMPI Q5IJTBQQJTʜQ EJW ݕূ༻ͷ3BDLΞϓϦέʔγϣϯ͕ͪ͜Β app/sample.ru ࣮ߦ͢Δͱʜ
  19. 3BDLΞϓϦέʔγϣϯ͕ىಈ͢ΔྲྀΕ SBDLVQίϚϯυΛ࣮ߦ ϋϯυϥʔΛىಈ ϋϯυϥʔʹαʔόʔΛొ࿥ αʔόʔຊମ͕ॲཧΛ։࢝ αʔόʔΛىಈ 3BDLຊମͱ αʔόʔຊମΛ઀ଓ αʔόʔ͕ ΞϓϦέʔγϣϯΛ࣮ߦ

    ىಈ։࢝ 3BDLΞϓϦέʔγϣϯΛ࣮ߦ
  20. 3BDLΞϓϦέʔγϣϯ͕ىಈ͢ΔྲྀΕ SBDLVQίϚϯυΛ࣮ߦ ϋϯυϥʔΛىಈ ϋϯυϥʔʹαʔόʔΛొ࿥ αʔόʔຊମ͕ॲཧΛ։࢝ αʔόʔΛىಈ 3BDLΞϓϦέʔγϣϯΛ࣮ߦ 3BDLຊମͷ )BOEMFSϞδϡʔϧΛ࢖ͬͨ αʔόʔຊମͷॲཧ

    αʔόʔຊମͷॲཧ 3BDLຊମͷॲཧ
  21. 3BDLDPNQBUJCMFͳαʔόʔͷػೳཁ݅ 3BDLΞϓϦέʔγϣϯ͕ىಈ͢ΔྲྀΕΛ౿·͑ͯɺ αʔόʔʹඞཁͳػೳΛߟ͑Δ ᶃϋϯυϥʔ  3BDL)BOEMFS4JNQMF3BDL$PNQBUJCMF4FSWFS  ⚡3BDLຊମͷ)BOEMFSϞδϡʔϧʹαʔόʔΛొ࿥͢Δ ⚡αʔόʔΛىಈ͢Δ ᶄαʔόʔຊମ

     4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFS  ⚡ϦΫΤετΛड͚Δ ⚡ΞϓϦέʔγϣϯΛ࣮ߦ͢Δ ⚡ϨεϙϯεΛฦ͢
  22. 1 require ‘rack/handler’ 2 3 module Rack 4 module Handler

    5 class SimpleRackCompatibleServer 6 def self.run(app, options = {}) 7 environment = ENV[‘RACK_ENV’] || ‘development’ 8 default_host = environment == ‘development’ ? ‘localhost’ : ‘0.0.0.0’ 9 10 host = options.delete(:Host) || default_host 11 port = options.delete(:Port) || 9292 12 args = [host, port, app] 13 ::SimpleRackCompatibleServer::Server.new(*args).start 14 end 15 end 16 17 register :simple_rack_compatible_server, SimpleRackCompatibleServer 18 end 19 end ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO rack/handler/simple_rack_compatible_server.rb ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO 3BDL)BOEMFSϞδϡʔϧΛSFRVJSF
  23. 1 require ‘rack/handler’ 2 3 module Rack 4 module Handler

    5 class SimpleRackCompatibleServer 6 def self.run(app, options = {}) 7 environment = ENV[‘RACK_ENV’] || ‘development’ 8 default_host = environment == ‘development’ ? ‘localhost’ : ‘0.0.0.0’ 9 10 host = options.delete(:Host) || default_host 11 port = options.delete(:Port) || 9292 12 args = [host, port, app] 13 ::SimpleRackCompatibleServer::Server.new(*args).start 14 end 15 end 16 17 register :simple_rack_compatible_server, SimpleRackCompatibleServer 18 end 19 end rack/handler/simple_rack_compatible_server.rb 3BDL)BOEMFSϞδϡʔϧʹαʔόʔΛొ࿥͢Δ ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO
  24. 1 require ‘rack/handler’ 2 3 module Rack 4 module Handler

    5 class SimpleRackCompatibleServer 6 def self.run(app, options = {}) 7 environment = ENV[‘RACK_ENV’] || ‘development’ 8 default_host = environment == ‘development’ ? ‘localhost’ : ‘0.0.0.0’ 9 10 host = options.delete(:Host) || default_host 11 port = options.delete(:Port) || 9292 12 args = [host, port, app] 13 ::SimpleRackCompatibleServer::Server.new(*args).start 14 end 15 end 16 17 register :simple_rack_compatible_server, SimpleRackCompatibleServer 18 end 19 end rack/handler/simple_rack_compatible_server.rb ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO αʔόʔΛىಈ͢Δϝιου ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO
  25. 1 require ‘rack/handler’ 2 3 module Rack 4 module Handler

    5 class SimpleRackCompatibleServer 6 def self.run(app, options = {}) 7 environment = ENV[‘RACK_ENV’] || ‘development’ 8 default_host = environment == ‘development’ ? ‘localhost’ : ‘0.0.0.0’ 9 10 host = options.delete(:Host) || default_host 11 port = options.delete(:Port) || 9292 12 13 14 end 15 end 16 17 18 end 19 end rack/handler/simple_rack_compatible_server.rb ࣮ߦ؀ڥ͔Βϗετͱϙʔτ൪߸Λઃఆ͢Δ  ˞σϑΥϧτͰMPDBMIPTUʹ઀ଓ ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO
  26. 1 require ‘rack/handler’ 2 3 module Rack 4 module Handler

    5 class SimpleRackCompatibleServer 6 def self.run(app, options = {}) 7 environment = ENV[‘RACK_ENV’] || ‘development’ 8 default_host = environment == ‘development’ ? ‘localhost’ : ‘0.0.0.0’ 9 10 host = options.delete(:Host) || default_host 11 port = options.delete(:Port) || 9292 12 args = [host, port, app] 13 14 end 15 end 16 17 18 end 19 end rack/handler/simple_rack_compatible_server.rb αʔόʔʹ౉͢Ҿ਺Λ༻ҙ͢Δ ⚡ϗετ ⚡ϙʔτ൪߸ ⚡3BDLΞϓϦέʔγϣϯຊମ ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO
  27. 1 require ‘rack/handler’ 2 3 module Rack 4 module Handler

    5 class SimpleRackCompatibleServer 6 def self.run(app, options = {}) 7 environment = ENV[‘RACK_ENV’] || ‘development’ 8 default_host = environment == ‘development’ ? ‘localhost’ : ‘0.0.0.0’ 9 10 host = options.delete(:Host) || default_host 11 port = options.delete(:Port) || 9292 12 args = [host, port, app] 13 ::SimpleRackCompatibleServer::Server.new(*args).start 14 end 15 end 16 17 18 end 19 end rack/handler/simple_rack_compatible_server.rb αʔόʔ 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFS Λ ΠϯελϯεԽ͠ OFX ɺىಈ͢Δ TUBSU  ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO
  28. 1 require ‘socket’ 2 3 module SimpleRackCompatibleServer 4 class Server

    5 def initialize(*args) 6 @host, @port, @app = args 7 end 8 9 def start 26 end 27 end 28 end simple_rack_compatible_server.rb αʔόʔΛ࣮૷શମ૾ ʜ ϋϯυϥʔ͔ΒҾ͖ܧ͍ͩ ⚡ϗετ ⚡ϙʔτ൪߸ ⚡3BDLΞϓϦέʔγϣϯຊମ ͰΠϯελϯεΛॳظԽ͢Δ ݩʑͷ)551αʔόʔͷॲཧʹ ͭͷมߋ఺Λ௥Ճ  ৄ͘͠͸࣍ͷεϥΠυ
  29. 9 def start 10 server = TCPServer.new(@host, @port) 11 12

    loop do 13 client = server.accept 14 request = client.readpartial(2048) 15 16 @status, @header, @body = @app.call 17 18 puts request 19 20 client.puts <<~MESSAGE 21 #{‘HTTP/1.1 200 OK’ if @status.eql? 200}\r\n 22 #{@header.map { |k, v| [k, v].join(’: ’) }.join(“\r\n”)}\r\n 23 \r\n 24 #{@body} 25 MESSAGE 26 end simple_rack_compatible_server.rb มߋ఺ᶄ 3BDLΞϓϦέʔγϣϯ࣮ߦ ฦΓ஋Λऔಘ͢Δ มߋ఺ᶅ ฦΓ஋͔ΒϨεϙϯεϝοηʔδΛੜ੒ αʔόʔΛ࣮૷TUBSUϝιου มߋ఺ᶃ ϋϯυϥʔ͔Β౉ͨ͠ ϗετͱϙʔτ൪߸Λઃఆ
  30. ͔͠͠

  31. 9 def start 10 server = TCPServer.new(@host, @port) 11 12

    loop do 13 client = server.accept 14 request = client.readpartial(2048) 15 16 @status, @header, @body = @app.call(???) 17 18 puts request 19 20 client.puts <<~MESSAGE 21 #{‘HTTP/1.1 200 OK’ if @status.eql? 200}\r\n 22 #{@header.map { |k, v| [k, v].join(’: ’) }.join(“\r\n”)}\r\n 23 \r\n 24 #{@body} 25 MESSAGE 26 end simple_rack_compatible_server.rb Ͳ͏͠Α͏ʜ DBMMϝιουʹ౉͢Ҿ਺͕Θ͔Βͳ͍⚠ ؀ڥม਺ΛϋογϡͷܗͰ ೖΕΔඞཁ͕͋Δ
  32. 9 def start 10 server = TCPServer.new(@host, @port) 11 12

    loop do 13 client = server.accept 14 request = client.readpartial(2048) 15 16 @status, @header, @body = @app.call({ }) 17 18 puts request 19 20 client.puts <<~MESSAGE 21 #{‘HTTP/1.1 200 OK’ if @status.eql? 200}\r\n 22 #{@header.map { |k, v| [k, v].join(’: ’) }.join(“\r\n”)}\r\n 23 \r\n 24 #{@body} 25 MESSAGE 26 end simple_rack_compatible_server.rb Θ͔Βͳ͍ͷͰ ۭϋογϡΛ ೖΕͯΈ·ͨ͠
  33. SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS ͱΓ͋͑ͣ

  34. ‎ͩΊͰͨ͠ ר͖ى͜ΔΤϥʔ☠☠☠

  35. ೖྗඞਢͷ؀ڥม਺͕͋ΔΒ͍͠ FOWNJTTJOHSFRVJSFELFZ3&26&45@.&5)0%  3BDL-JOU-JOU&SSPS

  36. rack/lib/rack/lint.rb 3BDL-JOUΫϥεΛ֬ೝ

  37. rack/lib/rack/lint.rb 3BDL-JOUΫϥεΛ֬ೝ ඞཁͳ؀ڥม਺ʹ͍ͭͯղઆͯ͘͠Ε͍ͯΔʂ ʜ

  38. ⚡1"5)@*/'0‎ϦΫΤετ63-ͷύε ⚡26&3:@453*/(‎ΫΤϦจࣈྻ ⚡.&5)0%‎)551ϝιου ⚡4&37&3@/".&‎4$3*15@/".&ͱ1"5)@*/'0ͱͷ ૊Έ߹ΘͤͰ63-Λߏங͢Δ ⚡4&37&3@1035‎4$3*15@/".&ͱ1"5)@*/'0ͱͷ ૊Έ߹ΘͤͰ63-Λߏங͢Δ 1&1Ͱఆٛ͞Εͨ؀ڥม਺ 1&1‎1ZUIPO8FC4FSWFS(BUFXBZ*OUFSGBDFW IUUQTXXXQZUIPOPSHEFWQFQTQFQ

  39. ⚡SBDLWFSTJPO‎3BDLͷόʔδϣϯ ഑ྻ  ⚡SBDLJOQVU‎ೖྗετϦʔϜ  *0ϥΠΫͳΦϒδΣΫτ  ⚡SBDLFSSPST‎ΤϥʔετϦʔϜ  QVUTXSJUFqVTIΛݺ΂ΔΦϒδΣΫτ

     ⚡SBDLNVMUJQSPDFTT‎ΞϓϦέʔγϣϯ͕ෳ਺ͷϓϩηεʹΑͬͯ ಉ࣌ʹݺͼग़͞ΕΔ͔Ͳ͏͔ ⚡SBDLNVMUJUISFBE‎ΞϓϦέʔγϣϯ͕ ಉ͡ϓϩηε಺ͷෳ਺ͷεϨουʹΑͬͯ ಉ࣌ʹݺͼग़͞ΕΔ͔Ͳ͏͔ ⚡SBDLSVO@PODF‎ΞϓϦέʔγϣϯ͕ͦͷϓϩηεͷ࣮ߦதʹ Ұ౓͚ͩݺͼग़͞ΕΔ͔Ͳ͏͔  $(*ϕʔεͷαʔόʔͰͷΈUSVFʹͳΔ  ⚡SBDLVSM@TDIFNF‎63*εΩʔϜ IUUQPSIUUQT 3BDL؀ڥݻ༗ͷ؀ڥม਺
  40. 18 def env 19 { 20 ‘PATH_INFO’ => @path ||

    ‘/’, 21 ‘QUERY_STRING’ => @query || ‘’, 22 ‘METHOD’ => @method || ‘GET’, 23 ‘SERVER_NAME’ => ‘simple_rack_compatible_server’, 24 ‘SERVER_PORT’ => @port.to_s, 25 ‘rack.version’ => Rack::VERSION, 26 ‘rack.input’ => StringIO.new(@input || ‘’).set_encoding(‘ASCII_8BIT’), 27 ‘rack.errors’ => $stderr, 28 ‘rack.multiprocess’ => false, 29 ‘rack.multithread’ => false, 30 ‘rack.run_once’ => false, 31 ‘rack.url_scheme’ => @scheme&.downcase&.slice(/http[a-z]*/) || ‘http’ 32 } 33 end simple_rack_compatible_server.rb 3BDL-JOUΛࢀߟʹ؀ڥม਺Λઃఆ ϦΫΤετ͔Βಈతʹੜ੒ͨ͠؀ڥม਺ PSσϑΥϧτ஋
  41. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    loop do 39 client = server.accept 40 41 request = client.readpartial(2048).split(“\r\n”) 42 @method, path, @scheme = request.first.split 43 @path, @query = path.split(‘?’) 44 @input = request.index(‘’) ? request[request.index(‘’) + 1] : ‘’ 45 46 puts “Received request message: #{@method} #{@path} #{@scheme}” 47 48 @status, @header, @body = @app.call(env) 49 50 client.puts <<~MESSAGE 51 # … simple_rack_compatible_server.rb ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒ ؀ڥม਺Λੜ੒͢ΔίʔυΛ௥Ճ
  42. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    loop do 39 client = server.accept 40 41 request = client.readpartial(2048).split(“\r\n”) 42 @method, path, @scheme = request.first.split 43 44 45 46 47 48 49 50 51 simple_rack_compatible_server.rb !NFUIPE‎)551ϝιου ˏTDIFNB‎63*εΩʔϜ ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒
  43. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    loop do 39 client = server.accept 40 41 request = client.readpartial(2048).split(“\r\n”) 42 @method, path, @scheme = request.first.split 43 @path, @query = path.split(‘?’) 44 45 46 47 48 49 50 51 simple_rack_compatible_server.rb !QBUI‎ϦΫΤετ63-ͷύε !RVFSZ‎ΫΤϦจࣈྻ ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒
  44. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    loop do 39 client = server.accept 40 41 request = client.readpartial(2048).split(“\r\n”) 42 @method, path, @scheme = request.first.split 43 @path, @query = path.split(‘?’) 44 @input = request.index(‘’) ? request[request.index(‘’) + 1] : ‘’ 45 46 47 48 49 50 51 simple_rack_compatible_server.rb !JOQVU‎ೖྗετϦʔϜ ϦΫΤετϘσΟ ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒
  45. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    loop do 39 client = server.accept 40 41 request = client.readpartial(2048).split(“\r\n”) 42 @method, path, @scheme = request.first.split 43 @path, @query = path.split(‘?’) 44 @input = request.index(‘’) ? request[request.index(‘’) + 1] : ‘’ 45 46 puts “Received request message: #{@method} #{@path} #{@scheme}” 47 48 49 50 51 simple_rack_compatible_server.rb ͔ͤͬ͘ͳͷͰϩά ΋ग़ྗ ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒
  46. SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS ͋ΒͨΊͯ

  47. ‎ಈ͖·ͨ͠ 3FDFJWFESFRVFTUNFTTBHF(&5)551 3BDL-JOU-JOU&SSPSΤϥʔ͕ফ͑ͯ ϩά͕ग़ྗ͞Ε͍ͯΔʂ λʔϛφϧʹͯ

  48. ϒϥ΢βͷݕূπʔϧʹͯ 3BDLΞϓϦέʔγϣϯ͔Βऔಘͨ͠ εςʔλείʔυͱϔομΛ ΫϥΠΞϯτଆʹ౉͢͜ͱ͕Ͱ͖͍ͯΔʂ ϔομ $POUFOU5ZQFUFYUIUNM εςʔλείʔυ 

  49. ϨεϙϯεϘσΟ͸ʜ

  50. ϨεϙϯεϘσΟ͸ʜ 

  51. Կ͔͕͓͔͍͠ ཧ૝ ݱ࣮ SBDLCPEZQSPYZ ϨεϙϯεϘσΟΛಡΈࠐΜͰ %0.͕ੜ੒͞ΕΔ

  52. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    loop do … 47 48 @status, @header, @body = @app.call(env) 49 50 client.puts <<~MESSAGE 51 #{‘HTTP/1.1 200 OK’ if @status.eql? 200}\r\n 52 #{@header.map { |k, v| [k, v].join(’: ’) }.join(“\r\n”)}\r\n 53 \r\n 54 #{@body} 55 MESSAGE 56 end 57 end simple_rack_compatible_server.rb Ϩεϙϯεϝοηʔδ͸Ͳ͏ͳ͍ͬͯΔʁ ཧ૝ͷϨεϙϯεϘσΟ͸ [“<div><h1>Hello.</h1><p>This app is …</p></div>”] 3BDLΞϓϦέʔγϣϯΛ࣮ߦͯ͠ฦΓ஋Λऔಘ ‎<εςʔλείʔυ \ϔομ^ <ϘσΟ>>
  53. !CPEZͷத਎͸Ͳ͏ͳ͍ͬͯΔʁ JSC 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSYʜ QQ!CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLDPNNPO@MPHHFSSC  !CPEZ 3BDL-JOUYʜ

    !BQQ 3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ  !CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLUFNQpMF@SFBQFSSC  !CPEZ <lEJWI)FMMPIQ5IJTBQQJTSVOOJOHPOʜQEJWz>  !DMPTFEGBMTF
  54. !CPEZͷத਎͸Ͳ͏ͳ͍ͬͯΔʁ JSC 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSYʜ QQ!CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLDPNNPO@MPHHFSSC  !CPEZ 3BDL-JOUYʜ

    !BQQ 3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ  !CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLUFNQpMF@SFBQFSSC  !CPEZ <lEJWI)FMMPIQ5IJTBQQJTSVOOJOHʜQEJWz>  !DMPTFEGBMTF 3BDL#PEZ1SPYZͷΠϯελϯεʂ
  55. JSC 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSYʜ QQ!CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLDPNNPO@MPHHFSSC  !CPEZ 3BDL-JOUYʜ !BQQ

    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ  !CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLUFNQpMF@SFBQFSSC  !CPEZ <lEJWI)FMMPIQ5IJTBQQJTʜQEJWz>  !DMPTFEGBMTF ͋Δ औΓग़͠ํ͕Θ͔Βͳ͍ʜ  !CPEZͷத਎͸Ͳ͏ͳ͍ͬͯΔʁ
  56. !CPEZΛDBMMͯ͠Έ·ͨ͠ JSC 4JNQMF3BDL$PNQBUJCMF4FSWFSTFSWʜ QQ!CPEZDBMM FOW  <  \$POUFOU5ZQFUFYUIUNM^ 

    3BDL-JOUYʜ !BQQ 3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ  !CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLUFNQpMF@SFBQFSSC  !CPEZ <EJWI)FMMPIQ5IJTBQQJTʜQEJW>  !DMPTFEGBMTF  !DPOUFOU@MFOHUIOJM  !IFBE@SFRVFTUGBMTF>
  57. !CPEZΛDBMMͯ͠Έ·ͨ͠ JSC 4JNQMF3BDL$PNQBUJCMF4FSWFSTFSWFʜ QQ!CPEZDBMM FOW  <  \$POUFOU5ZQFUFYUIUNM^ 

    3BDL-JOUYʜ !BQQ 3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ  !CPEZ 3BDL#PEZ1SPYZYʜ !CMPDL 1SPDYʜ!ʜSBDLMJCSBDLUFNQpMF@SFBQFSSC  !CPEZ <lEJWI)FMMPIQ5IJTBQQJTʜQEJWz>  !DMPTFEGBMTF  !DPOUFOU@MFOHUIOJM  !IFBE@SFRVFTUGBMTF> ԕ͍ʜ ϨεϙϯεϘσΟͦͷ΋ͷ͕ औಘͰ͖ΔΑ͏ʹͳΔ·Ͱ ԆʑDBMM͠ଓ͚Δ͔͠ͳ͍ʜʁʁ ϘσΟ 3BDL-JOUͷΠϯελϯε 
  58. ߴڮ͞Μ͔Βͷώϯτ DBMMϝιουͷฦ͢ཁૉ഑ྻͷͭ໨͸CPEZͰɺ CPEZ͸FBDIϝιουͱ͔UP@QBUIϝιουͱ͔Λୟ͚Δ ΦϒδΣΫτͰ͔͠ͳ͘

  59. ʜFBDIϝιουʁ ߴڮ͞Μ͔Βͷώϯτ DBMMϝιουͷฦ͢ཁૉ഑ྻͷͭ໨͸CPEZͰɺ CPEZ͸FBDIϝιουͱ͔UP@QBUIϝιουͱ͔Λୟ͚Δ ΦϒδΣΫτͰ͔͠ͳ͘

  60. 3BDL#PCZ1SPYZFBDI 3BDL#PCZ1SPYZ͸FBDIϝιουΛ࣋ͭ ࢖͑ΔͷͰ͸ʁ

  61. 1 require ‘socket’ 2 3 module SimpleRackCompatibleServer 4 class Server

    69 def body 70 res_body = [] 71 @body.each { |body| res_body << body } 72 res_body.join(“\n”) 73 end 74 end 75 end simple_rack_compatible_server.rb FBDIΛ࢖ͬͯϨεϙϯεϘσΟΛऔΓग़͢ … !CPEZʹFBDIΛݺͼ഑ྻͱͯ͠୅ೖ͠௚͢ ࠷ޙʹจࣈྻʹ௚͢
  62. 35 def start 48 @status, @header, @body = @app.call(env) 49

    50 client.puts <<~MESSAGE 51 #{‘HTTP/1.1 200 OK’ if @status.eql? 200}\r\n 52 #{@header.map { |k, v| [k, v].join(’: ’) }.join(“\r\n”)}\r\n 53 \r\n 54 #{body} 55 MESSAGE 56 end 57 end simple_rack_compatible_server.rb ϨεϙϯεϘσΟΛݺͼग़͢ … CPEZϝιουΛݺͿ
  63. SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS ͋ΒͨΊͯ

  64. ಈ͖·ͨ͠ ϨεϙϯεϘσΟ΋දࣔͰ͖·ͨ͠

  65. εςʔλείʔυɺϔομɺϘσΟͷશͯΛ ΫϥΠΞϯτଆʹग़ྗͰ͖·ͨ͠ʂ ಈ͖·ͨ͠ εςʔλε‎)5510, ϔομ‎$POUFOU5ZQFUFYUIUNM ϘσΟ‎EJW I)FMMPI Q5IJTBQQJTʜQ EJW

  66. ࠷ऴతʹ͜͏ͳΓ·ͨ͠⚡

  67. 1 require ‘socket’ 2 3 module SimpleRackCompatibleServer 4 class Server

    5 def initialize(*args) 6 @host, @port, @app = args 7 @method = nil 8 @path = nil 9 @scheme = nil 10 @query = nil 11 @input = nil 12 @status = nil 13 @header = nil 14 @body = nil 15 end simple_rack_compatible_server.rb 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSJOJUJBMJ[F ⚡TPDLFUϥΠϒϥϦΛSFRVJSF ⚡ඞཁͳΠϯελϯεม਺ΛॳظԽ
  68. 18 def env 19 { 20 ‘PATH_INFO’ => @path ||

    ‘/’, 21 ‘QUERY_STRING’ => @query || ‘’, 22 ‘METHOD’ => @method || ‘GET’, 23 ‘SERVER_NAME’ => ‘simple_rack_campatible_server’, 24 ‘SERVER_PORT’ => @port.to_s, 25 ‘rack.version’ => Rack::VERSION, 26 ‘rack.input’ => StringIO.new(@input || ‘’).set_encoding(‘ASCII_8BIT’), 27 ‘rack.errors’ => $stderr, 28 ‘rack.multiprocess’ => false, 29 ‘rack.multithread’ => false, 30 ‘rack.run_once’ => false, 31 ‘rack.url_scheme’ => @scheme&.downcase&.slice(/http[a-z]*/) || ‘http’ 32 } 33 end simple_rack_compatible_server.rb 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSFOW ⚡3BDLΞϓϦέʔγϣϯͷ࣮ߦʹඞཁͳ؀ڥม਺Λ༻ҙ
  69. 35 def start 36 server = TCPServer.new(@host, @port) 37 38

    puts <<~MESSAGE 39 #{@app} is running on #{@host}: #{@port} 40 => Use Ctrl-C to stop 41 MESSAGE 42 43 loop do 44 client = server.accept 60 end 61 end simple_rack_compatible_server.rb … 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSTUBSU ⚡ϧʔϓॲཧΛ։࢝͢Δ ⚡ΫϥΠΞϯτ͔Βͷ઀ଓཁٻΛड͚෇͚Δ ⚡αʔόʔ઀ଓΛ։࢝͢Δ ⚡։࢝ϝοηʔδΛग़ྗ͢Δ
  70. 46 begin 47 request = client.readpartial(2048).split(“\r\n”) 48 @method, path, @scheme

    = request.first.split 49 @path, @query = path.split(‘?’) 50 @input = request.index(‘’) ? request[request.index(‘’) + 1] : ‘’ 51 52 puts “Received request message: #{@method} #{@path} #{@schema}” 53 54 55 56 57 58 59 end simple_rack_compatible_server.rb 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSTUBSU ⚡ϦΫΤετϝοηʔδΛಡΈࠐΉ ⚡3BDLΞϓϦέʔγϣϯͷ࣮ߦʹඞཁͳ؀ڥม਺Λੜ੒͢Δ ⚡αʔόʔʹϩάΛग़ྗ͢Δ
  71. 46 begin 47 48 49 50 51 52 53 54

    @status, @header, @body = @app.call(env) 55 56 client.puts [status, header, ‘’, body].join(“\r\n”) 57 ensure 58 client.close 59 end simple_rack_compatible_server.rb 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSTUBSU ⚡3BDLΞϓϦέʔγϣϯΛ࣮ߦ͠ɺฦΓ஋Λऔಘ͢Δ ⚡ฦΓ஋͔ΒϨεϙϯεϝοηʔδΛੜ੒͠ɺग़ྗ͢Δ ⚡ιέοτΛด͡Δ
  72. 46 begin 47 48 49 50 51 52 53 54

    55 56 client.puts [status, header, ‘’, body].join(“\r\n”) 57 ensure 58 client.close 59 end simple_rack_compatible_server.rb 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSTUBSU 67 def status 68 case @status 69 when 200 70 “#{@schema} 200 OK” 82 def header 83 @header.map { |k, v| [k, v].join(’: ’) }.join(“\r\n”) 84 end 86 def body 87 res_body = [] 88 @body.each { |body| res_body << body } 89 res_body.join(“\n”) 90 end
  73. ͓ർΕ༷Ͱͨ͠✨

  74. ը૾ɿIUUQTUXJUUFSDPNUFOEFSMPWF ग़యɿIUUQTTQFBLFSEFDLDPNUFOEFSMPWFHBPEVOBLPEP "BSPO͞Μɹɹɹɹ

  75. ײ૝ 3BDLΛ࢖ͬͯ 3BDLDPNQBUJCMFͳ 8FCαʔόʔΛ࡞Δͷ͸ ָ

  76. ⚡Ұ෦͸Ծ࣮૷ͷ··ͩ͠ɺ ·ͩ·ͩߟ͑Δ΂͖͜ͱ͸ͨ͘͞Μ͋Δ  ೖྗʁฒྻԽʁύϑΥʔϚϯεʁFUD  ⚡΋ͬͱ3BDLͷ͜ͱΛ஌Γ͍ͨʂ ⚡օ͞Μ͔Βͷٕज़తࢦఠΛ͓଴͍ͪͯ͠·͢ IUUQTHJUIVCDPNTIJPJNNTJNQMF@SBDL@DPNQBUJCMF@TFSWFS ͱ͸͍͑

  77. 3BDL͸ָɹ

  78. 3BDL͸ָ͍͠ʂ

  79. ͓ΘΓʹ⚡⚡⚡

  80. ࣗݾ঺հ࠶ͼ

  81. Ұ೥൒લʹԿ͕͔͋ͬͨ օ͞Μ͍֮͑ͯ·͔͢ʜʁ

  82. ೥݄೔ େߐށ3VCZձٞ ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP

  83. લճͷେߐށ3VCZձٞͷ௚લʹॳࢀՃ "TBLVTBSCͷFTBʹΑΔͱ ͦͯͦ͠ͷ৔Ͱେߐށ3VCZձٞʹ ਃ͠ࠐΈΛͨ͠هԱ͕ʜ  ୈճ ը૾ɿIUUQTBTBLVTBSCFTBJPQPTUT

  84. લճͷେߐށ3VCZձٞ ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP

  85. લճͷେߐށ3VCZձٞ ָ͔ͬͨ͘͢͝͠ ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP

  86. લճͷେߐށ3VCZձٞ جௐߨԋ +POBO͞Μʮ)PXUPCFσΧʯ ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP

  87. લճͷେߐށ3VCZձٞ جௐߨԋ +POBO͞Μʮ)PXUPCFσΧʯ Have your heroes ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP

  88. Ұ೥൒લͷࣗ෼ʹͱͬͯ "TBLVTBSCͷਓʑ͸ ʮώʔϩʔʯ

  89. Ұ೥൒ܦͬͨࠓ͸ ʮಉ͡ίϛϡχςΟͷਓʑʯ Ͱ΋͋Δ

  90. 3VCZ ͳͲͳͲ ͷ͓࿩Λͨ͠Γ✨ ίʔυΛॻ͍ͨΓ+ ͓͍͍͠΋ͷΛ௖͍ͨΓ Θͨ͠ʹͱͬͯͷ"TBLVTBSC͸ɺ 3VCZJTU͕ू·ͬͯ ͍ͭ΋Θ͍Θ͍͍ͯ͠Δ৔ॴ

  91. "TBLVTBSC͸ָ͍͠ʂ

  92. 4QFDJBM5IBOLT ܟশུ ✨ JOTQJSFEGSPN !FTUIFS !UFOEFSMPWFUIF3BDLUFBN ŠŠ !JHBJHB!VE[VSB !UBLBIBTIJN!PLVSBNBTBGVNJ !UIFKPOBOTIPX"TBLVTBSC'VLVPLBSC

    ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠⚡⚡⚡