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

More Decks by Misaki Shioi(塩井美咲/しおい)

Other Decks in Programming

Transcript

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

    View full-size slide

  2. ࣗݾ঺հ
    ԘҪඒ࡙ ͓͍͠
    !DPF@

    8FCϓϩάϥϚ
    "TBLVTBSCɺ5BNBSCɺ'VLVPLBSCʢ࿦ཧʣʹ͍·͢
    "TBLVTBSCʹ௨͍࢝ΊͯૣҰ೥൒
    ࠷ۙ8FCαʔόʔΛ࡞Γ·ͨ͠

    View full-size slide

  3. ࣗݾ঺հ
    ԘҪඒ࡙ ͓͍͠
    !DPF@

    8FCϓϩάϥϚ
    "TBLVTBSCɺ5BNBSCɺ'VLVPLBSCʢ࿦ཧʣʹ͍·͢
    "TBLVTBSCʹ௨͍࢝ΊͯૣҰ೥൒
    ࠷ۙ8FCαʔόʔΛ࡞Γ·ͨ͠
    ‐ࠓ೔ͷ͓࿩

    View full-size slide

  4. 3VCZ$POG/BTIWJMMF
    /PWFNCFS

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  7. ‎͏ͮΒ͞Μ!VE[VSB 'VLVPLBSC

    ‎Θͨ͠ !DPF@

    ग़యɿIUUQTUXJUUFSDPNVE[VSBTUBUVT T
    !DPF@

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  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
    ΫϥΠΞϯτ͔Βͷ઀ଓཁٻΛड͚෇͚Δ
    ϦΫΤετϝοηʔδΛಡΈࠐΉ
    ϦΫΤετϝοηʔδΛαʔόʔଆʹग़ྗ
    ద౰ͳϨεϙϯεϝοηʔδ
    ϨεϙϯεϝοηʔδΛΫϥΠΞϯτଆʹग़ྗ
    ग़དྷ্͕ͬͨͷ͕ͪ͜Β

    View full-size slide

  11. DVSMMPDBMIPTU
    ࡞ͬͨαʔόʔͷϗετͱϙʔτ൪߸

    View full-size slide

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

    View full-size slide

  13. ಈతͳΞϓϦέʔγϣϯʹ͸ରԠ͍ͯ͠ͳ͍⚠
    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
    ͦ΋ͦ΋
    ΞϓϦέʔγϣϯ͕
    ଘࡏ͠ͳ͍
    ΞΫηε͢Δͨͼɺຖճ
    ಉ͡Ϩεϙϯεϝοηʔδ͕
    ग़ྗ͞ΕΔ

    View full-size slide

  14. ͔ͤͬ͘ͳͷͰ
    3BDLDPNQBUJCMFʹ͍ͨ͠

    View full-size slide

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

    View full-size slide

  16. 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 [“Hello.This app is running on .…”]

    10 ]

    11 end

    12 end

    13

    14 run App.new

    ݕূ༻ͷ3BDLΞϓϦέʔγϣϯ͕ͪ͜Β
    app/sample.ru

    View full-size slide

  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 [“Hello.This app is running on .…”]

    10 ]

    11 end

    12 end

    13

    14 run App.new

    εςʔλε‎)5510,
    ϔομ‎$POUFOU5ZQFUFYUIUNM
    ϘσΟ‎EJW
    I)FMMPI
    Q5IJTBQQJTʜQ
    EJW
    ݕূ༻ͷ3BDLΞϓϦέʔγϣϯ͕ͪ͜Β
    app/sample.ru
    ࣮ߦ͢Δͱʜ

    View full-size slide

  18. 3BDLΞϓϦέʔγϣϯ͕ىಈ͢ΔྲྀΕ
    SBDLVQίϚϯυΛ࣮ߦ
    ϋϯυϥʔΛىಈ
    ϋϯυϥʔʹαʔόʔΛొ࿥
    αʔόʔຊମ͕ॲཧΛ։࢝
    αʔόʔΛىಈ
    3BDLຊମͱ
    αʔόʔຊମΛ઀ଓ
    αʔόʔ͕
    ΞϓϦέʔγϣϯΛ࣮ߦ
    ىಈ։࢝
    3BDLΞϓϦέʔγϣϯΛ࣮ߦ

    View full-size slide

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

    View full-size slide

  20. 3BDLDPNQBUJCMFͳαʔόʔͷػೳཁ݅
    3BDLΞϓϦέʔγϣϯ͕ىಈ͢ΔྲྀΕΛ౿·͑ͯɺ
    αʔόʔʹඞཁͳػೳΛߟ͑Δ
    ᶃϋϯυϥʔ
    3BDL)BOEMFS4JNQMF3BDL$PNQBUJCMF4FSWFS

    ⚡3BDLຊମͷ)BOEMFSϞδϡʔϧʹαʔόʔΛొ࿥͢Δ
    ⚡αʔόʔΛىಈ͢Δ
    ᶄαʔόʔຊମ
    4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFS

    ⚡ϦΫΤετΛड͚Δ
    ⚡ΞϓϦέʔγϣϯΛ࣮ߦ͢Δ
    ⚡ϨεϙϯεΛฦ͢

    View full-size slide

  21. 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

    View full-size slide

  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
    rack/handler/simple_rack_compatible_server.rb
    3BDL)BOEMFSϞδϡʔϧʹαʔόʔΛొ࿥͢Δ
    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO

    View full-size slide

  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
    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    αʔόʔΛىಈ͢Δϝιου
    ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO

    View full-size slide

  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

    13

    14 end

    15 end

    16

    17

    18 end

    19 end
    rack/handler/simple_rack_compatible_server.rb
    ࣮ߦ؀ڥ͔Βϗετͱϙʔτ൪߸Λઃఆ͢Δ
    ˞σϑΥϧτͰMPDBMIPTUʹ઀ଓ

    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    ϋϯυϥʔΛ࣮૷ ࢀߟ5IJO

    View full-size slide

  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 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

    View full-size slide

  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 ::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

    View full-size slide

  27. 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αʔόʔͷॲཧʹ
    ͭͷมߋ఺Λ௥Ճ
    ৄ͘͠͸࣍ͷεϥΠυ

    View full-size slide

  28. 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ϝιου
    มߋ఺ᶃ
    ϋϯυϥʔ͔Β౉ͨ͠
    ϗετͱϙʔτ൪߸Λઃఆ

    View full-size slide

  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
    Ͳ͏͠Α͏ʜ
    DBMMϝιουʹ౉͢Ҿ਺͕Θ͔Βͳ͍⚠
    ؀ڥม਺ΛϋογϡͷܗͰ
    ೖΕΔඞཁ͕͋Δ

    View full-size slide

  30. 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
    Θ͔Βͳ͍ͷͰ
    ۭϋογϡΛ
    ೖΕͯΈ·ͨ͠

    View full-size slide

  31. SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS
    ͱΓ͋͑ͣ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  36. ⚡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

    View full-size slide

  37. ⚡SBDLWFSTJPO‎3BDLͷόʔδϣϯ ഑ྻ

    ⚡SBDLJOQVU‎ೖྗετϦʔϜ
    *0ϥΠΫͳΦϒδΣΫτ

    ⚡SBDLFSSPST‎ΤϥʔετϦʔϜ
    QVUTXSJUFqVTIΛݺ΂ΔΦϒδΣΫτ

    ⚡SBDLNVMUJQSPDFTT‎ΞϓϦέʔγϣϯ͕ෳ਺ͷϓϩηεʹΑͬͯ
    ಉ࣌ʹݺͼग़͞ΕΔ͔Ͳ͏͔
    ⚡SBDLNVMUJUISFBE‎ΞϓϦέʔγϣϯ͕
    ಉ͡ϓϩηε಺ͷෳ਺ͷεϨουʹΑͬͯ
    ಉ࣌ʹݺͼग़͞ΕΔ͔Ͳ͏͔
    ⚡SBDLSVO@PODF‎ΞϓϦέʔγϣϯ͕ͦͷϓϩηεͷ࣮ߦதʹ
    Ұ౓͚ͩݺͼग़͞ΕΔ͔Ͳ͏͔
    $(*ϕʔεͷαʔόʔͰͷΈUSVFʹͳΔ

    ⚡SBDLVSM@TDIFNF‎63*εΩʔϜ IUUQPSIUUQT

    3BDL؀ڥݻ༗ͷ؀ڥม਺

    View full-size slide

  38. 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σϑΥϧτ஋

    View full-size slide

  39. 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
    ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒
    ؀ڥม਺Λੜ੒͢ΔίʔυΛ௥Ճ

    View full-size slide

  40. 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*εΩʔϜ
    ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒

    View full-size slide

  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

    45

    46

    47

    48

    49

    50

    51
    simple_rack_compatible_server.rb
    !QBUI‎ϦΫΤετ63-ͷύε
    !RVFSZ‎ΫΤϦจࣈྻ
    ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒

    View full-size slide

  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 @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‎ೖྗετϦʔϜ ϦΫΤετϘσΟ

    ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒

    View full-size slide

  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 @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
    ͔ͤͬ͘ͳͷͰϩά
    ΋ग़ྗ
    ϦΫΤετϝοηʔδ͔Β؀ڥม਺Λੜ੒

    View full-size slide

  44. SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS
    ͋ΒͨΊͯ

    View full-size slide

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

    View full-size slide

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

    εςʔλείʔυ


    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  50. 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
    Ϩεϙϯεϝοηʔδ͸Ͳ͏ͳ͍ͬͯΔʁ
    ཧ૝ͷϨεϙϯεϘσΟ͸
    [“Hello.This app is …”]
    3BDLΞϓϦέʔγϣϯΛ࣮ߦͯ͠ฦΓ஋Λऔಘ
    ‎<εςʔλείʔυ \ϔομ^ <ϘσΟ>>

    View full-size slide

  51. !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

    !DMPTFEGBMTF

    View full-size slide

  52. !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

    !DMPTFEGBMTF
    3BDL#PEZ1SPYZͷΠϯελϯεʂ

    View full-size slide

  53. 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

    !DMPTFEGBMTF
    ͋Δ औΓग़͠ํ͕Θ͔Βͳ͍ʜ

    !CPEZͷத਎͸Ͳ͏ͳ͍ͬͯΔʁ

    View full-size slide

  54. !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>

    View full-size slide

  55. !CPEZΛDBMMͯ͠Έ·ͨ͠
    JSC 4JNQMF3BDL$PNQBUJCMF4FSWFSTFSWFʜ
    QQ!CPEZDBMM FOW

    <
    \$POUFOU5ZQFUFYUIUNM^
    3BDL-JOUYʜ
    !BQQ
    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ
    !CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜSBDLMJCSBDLUFNQpMF@SFBQFSSC
    !CPEZ

    !DMPTFEGBMTF
    !DPOUFOU@MFOHUIOJM
    !IFBE@SFRVFTUGBMTF>
    ԕ͍ʜ
    ϨεϙϯεϘσΟͦͷ΋ͷ͕
    औಘͰ͖ΔΑ͏ʹͳΔ·Ͱ
    ԆʑDBMM͠ଓ͚Δ͔͠ͳ͍ʜʁʁ
    ϘσΟ 3BDL-JOUͷΠϯελϯε

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  59. 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Λݺͼ഑ྻͱͯ͠୅ೖ͠௚͢
    ࠷ޙʹจࣈྻʹ௚͢

    View full-size slide

  60. 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ϝιουΛݺͿ

    View full-size slide

  61. SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS
    ͋ΒͨΊͯ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  65. 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
    ⚡ඞཁͳΠϯελϯεม਺ΛॳظԽ

    View full-size slide

  66. 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ΞϓϦέʔγϣϯͷ࣮ߦʹඞཁͳ؀ڥม਺Λ༻ҙ

    View full-size slide

  67. 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
    ⚡ϧʔϓॲཧΛ։࢝͢Δ
    ⚡ΫϥΠΞϯτ͔Βͷ઀ଓཁٻΛड͚෇͚Δ
    ⚡αʔόʔ઀ଓΛ։࢝͢Δ
    ⚡։࢝ϝοηʔδΛग़ྗ͢Δ

    View full-size slide

  68. 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ΞϓϦέʔγϣϯͷ࣮ߦʹඞཁͳ؀ڥม਺Λੜ੒͢Δ
    ⚡αʔόʔʹϩάΛग़ྗ͢Δ

    View full-size slide

  69. 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ΞϓϦέʔγϣϯΛ࣮ߦ͠ɺฦΓ஋Λऔಘ͢Δ
    ⚡ฦΓ஋͔ΒϨεϙϯεϝοηʔδΛੜ੒͠ɺग़ྗ͢Δ
    ⚡ιέοτΛด͡Δ

    View full-size slide

  70. 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

    View full-size slide

  71. ͓ർΕ༷Ͱͨ͠✨

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  74. ⚡Ұ෦͸Ծ࣮૷ͷ··ͩ͠ɺ
    ·ͩ·ͩߟ͑Δ΂͖͜ͱ͸ͨ͘͞Μ͋Δ
    ೖྗʁฒྻԽʁύϑΥʔϚϯεʁFUD

    ⚡΋ͬͱ3BDLͷ͜ͱΛ஌Γ͍ͨʂ
    ⚡օ͞Μ͔Βͷٕज़తࢦఠΛ͓଴͍ͪͯ͠·͢
    IUUQTHJUIVCDPNTIJPJNNTJNQMF@SBDL@DPNQBUJCMF@TFSWFS
    ͱ͸͍͑

    View full-size slide

  75. 3BDL͸ָ͍͠ʂ

    View full-size slide

  76. ͓ΘΓʹ⚡⚡⚡

    View full-size slide

  77. ࣗݾ঺հ࠶ͼ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    ୈճ
    ը૾ɿIUUQTBTBLVTBSCFTBJPQPTUT

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  88. "TBLVTBSC͸ָ͍͠ʂ

    View full-size slide

  89. 4QFDJBM5IBOLT ܟশུ

    JOTQJSFEGSPN
    !FTUIFS
    !UFOEFSMPWFUIF3BDLUFBN
    ŠŠ
    !JHBJHB!VE[VSB
    !UBLBIBTIJN!PLVSBNBTBGVNJ
    !UIFKPOBOTIPX"TBLVTBSC'VLVPLBSC
    ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠⚡⚡⚡

    View full-size slide