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

[English ver]実録 Let's build a simple Rack compatible server

[English ver]実録 Let's build a simple Rack compatible server

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

Other Decks in Programming

Transcript

  1. [email protected]
    'FC
    0FEP3VCZ,BJHJ
    ࣮࿥
    -FU`TCVJMEBTJNQMF
    3BDLDPNQBUJCMFTFSWFS⚡⚡⚡

    View Slide

  2. "CPVUNF
    .JTBLJ4IJPJ ͓͍͠
    [email protected]

    ⚡8FCQSPHSBNNFS
    ⚡#FMPOHTUP"TBLVTBSC 5BNBSC 'VLVPLBSC
    ⚡*UTCFFOZFBSBOEBIBMG
    TJODF*KPJOFE"TBLVTBSCNFFUVQGPSUIFpSTUUJNF
    ⚡#VJMUBXFCTFSWFSSFDFOUMZ

    View Slide

  3. .JTBLJ4IJPJ ͓͍͠
    [email protected]

    ⚡8FCQSPHSBNNFS
    ⚡#FMPOHTUP"TBLVTBSC 5BNBSC 'VLVPLBSC
    ⚡*UTCFFOZFBSBOEBIBMG
    TJODF*KPJOFE"TBLVTBSCNFFUVQGPSUIFpSTUUJNF
    ⚡#VJMUBXFCTFSWFSSFDFOUMZ
    "CPVUNF
    ‐5PEBZ`TUIFNF

    View Slide

  4. BU
    3VCZ$POG/BTIWJMMF
    /PWFNCFS

    View Slide

  5. l-FU`TCVJMEBTJNQMF)551TFSWFSz
    XIJDIJTBWFSZJOUFSFTUJOHUBML

    CZ&45)&30-"56/%&!FTUIFS
    ग़యɿIUUQTOPUJTUFTUIFSD(V(+MFUTCVJMEBTJNQMFIUUQTFSWFSXJUISVCZ

    View Slide

  6. ʜJTJOUSPEVDFECZ!JHBJHB`TUXFFU
    ग़యɿIUUQTUXJUUFSDPNJHBJHBTUBUVT T

    View Slide

  7. ʜJTJOUSPEVDFECZ!VE[VSB GSPN'VLVPLBSC
    CZUXFFU
    UPNF
    ग़యɿIUUQTUXJUUFSDPNVE[VSBTUBUVT T
    ˞NF

    View Slide

  8. 4P
    XJUIUIFSFGFSFODFUPUIFTMJEF
    *CVJMUBTJNQMF)551TFSWFS

    View Slide

  9. ʜBOEIFSFJUJT
    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 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
    $SFBUFBOFXTFSWFSTPDLFU
    "DDFQUBOJODPNJOHDPOOFDUJPO
    (FUBSFRVFTUNFTTBHF
    %JTQMBZSFRVFTUNFTTBHFUPTFSWFSTJEF
    1SPWJTJPOBMSFTQPOTFNFTTBHF
    %JTQMBZSFTQPOTFNFTTBHFUPDMJFOUTJEF
    ʜBOEIFSFJUJT

    View Slide

  11. DVSMMPDBMIPTU
    )PTU1PSUXIJDIBSFPQFOFE

    View Slide

  12. *UXPSLT
    POTFSWFSTJEF
    PODMJFOUTJEF
    3FRVFTUNFTTBHF
    JTEJTQMBZFE
    3FTQPOTFCPEZ
    JTEJTQMBZFE

    View Slide

  13. #VU

    View Slide

  14. 5IJTTFSWFSDBO`USVOBQQMJDBUJPO⚠
    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
    5IFSF`TOPBQQ
    4BNFNFTTBHFJTEJTQMBZFE
    FBDIUJNFZPVBDDFTTFE

    View Slide

  15. *EMJLFUPNBLFUIJTTFSWFS
    3BDLDPNQBUJCMF

    View Slide

  16. 4P *USJFEUPCVJME
    BTJNQMF3BDLDPNQBUJCMFTFSWFS
    XIJDIJTOBNFE
    4JNQMF3BDL$PNQBUJCMF4FSWFS

    View 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

    )FSFJTB3BDLBQQGPSWFSJpDBUJPO
    app/sample.ru

    View Slide

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

    10 ]

    11 end

    12 end

    13

    14 run App.new

    4UBUVT‎)5510,
    )FBEFS‎$POUFOU5ZQFUFYUIUNM
    #PEZ‎EJW
    I)FMMPI
    Q5IJTBQQJTʜQ
    EJW
    app/sample.ru
    )FSFJTB3BDLBQQGPSWFSJpDBUJPO
    8IFOZPVSVOʜ

    View Slide

  19. )PX3BDLBQQMJDBUJPOTUBSUT
    6TFSFYFDVUFTSBDLVQ
    )BOEMFSJTDBMMFE
    4FSWFSJTSFHJTUFSFEUP)BOEMFS
    4FSWFSTUBSUTUPSVO
    )BOEMFSTUBSUT4FSWFS
    5IFTFSWFS
    DPOOFDUFEUP3BDL
    4FSWFSSVOT3BDLBQQ
    4UBSU
    4FSWFSDBMMT3BDLBQQ

    View Slide

  20. JOUIFTFSWFS
    JO3BDL)BOEMFSNPEVMF

    JOUIFTFSWFS
    JO3BDL
    6TFSFYFDVUFTSBDLVQ
    )BOEMFSJTDBMMFE
    4FSWFSJTSFHJTUFSFEUP)BOEMFS
    4FSWFSTUBSUTUPSVO
    )BOEMFSTUBSUT4FSWFS
    4FSWFSDBMMT3BDLBQQ
    )PX3BDLBQQMJDBUJPOTUBSUT

    View Slide

  21. 3FRVJSFNFOUPG3BDLDPNQBUJCMFTFSWFS
    *UIPVHIUBCPVUUIFSFRVJSFNFOUTGPSUIFTFSWFS
    CBTFEPOIPX3BDLBQQTUBSUT
    ᶃ)BOEMFS
    3BDL)BOEMFS4JNQMF3BDL$PNQBUJCMF4FSWFS

    ⚡5PSFHJTUFSUIFTFSWFSUP3BDL)BOEMFSNPEVMF
    ⚡5PTUBSUUIFTFSWFS
    ᶄ4FSWFS
    4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFS

    ⚡5PSFDFJWFBSFRVFTUNFTTBHF
    ⚡5PDBMM3BDLBQQMJDBUJPO
    ⚡5PSFUVSOBSFTQPOTFNFTTBHF

    View 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
    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    rack/handler/simple_rack_compatible_server.rb
    *NQMFNFOUBUJPOPG)BOEMFS SFGTUIJO

    SFRVJSF3BDL)BOEMFS

    View 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
    5PSFHJTUFSUIFTFSWFSUP3BDL)BOEMFSNPEVMF
    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    *NQMFNFOUBUJPOPG)BOEMFS SFGTUIJO

    View 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 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
    5IFNFUIPEUPTUBSUUIFTFSWFS
    *NQMFNFOUBUJPOPG)BOEMFS SFGTUIJO

    View 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

    13

    14 end

    15 end

    16

    17

    18 end

    19 end
    rack/handler/simple_rack_compatible_server.rb
    4FUUIFIPTUQPSUCZFOWJSPONFOU
    ˞DPOOFDUUPMPDBMIPTUCZEFGBVMU

    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    *NQMFNFOUBUJPOPG)BOEMFS SFGTUIJO

    View 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

    14 end

    15 end

    16

    17

    18 end

    19 end
    rack/handler/simple_rack_compatible_server.rb
    "SHTUPJOJUJBMJ[FUIFTFSWFS
    ⚡)PTU
    ⚡1PSU
    ⚡3BDLBQQMJDBUJPO
    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    *NQMFNFOUBUJPOPG)BOEMFS SFGTUIJO

    View Slide

  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
    *OTUBOUJBUF OFX
    TUBSU TUBSU

    UIFTFSWFS 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFS

    ࢀߟɿIUUQTHJUIVCDPNNBDPVSOPZFSUIJO
    *NQMFNFOUBUJPOPG)BOEMFS SFGTUIJO

    View Slide

  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
    *NQMFNFOUBUJPOPGUIFTFSWFS0WFSBMM
    ʜ
    .PWFPSJHJOBMJNQMFNFOUBUJPOPGUIFTFSWFS
    UP4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSDMBTT

    View Slide

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

    27 end

    28 end

    29 end
    simple_rack_compatible_server.rb
    ʜ
    *OTUBOUJBUFXJUIBSHTGSPN)BOEMFS
    ⚡IPTU
    ⚡QPSU
    ⚡3BDLBQQMJDBUJPO
    "EEUIFGPMMPXJOHDIBOHFT
    UPUIFPSJHJOBM)551TFSWFS
    4FFUIFOFYUTMJEFGPSNPSFEFUBJMTʜ

    *NQMFNFOUBUJPOPGUIFTFSWFS0WFSBMM

    View 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
    DIBOHFTᶄ
    $BMMUIF3BDLBQQMJDBUJPO
    BOEHFUUIFSFUVSOWBMVFT
    DIBOHFTᶅ
    (FOFSBUFBSFTQPOTFNFTTBHF
    GSPNUIFSFUVSOWBMVFT
    *NQMFNFOUBUJPOPGUIFTFSWFSTUBSU
    DIBOHFTᶃ
    4FUUIFIPTUQPSU
    GSPN)BOEMFS

    View Slide

  31. #VU

    View Slide

  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
    8IBUTIPVME*EPʜ
    8IBUBSHTEPFTUIFDBMMNFUIPEOFFE ⚠
    4PNFFOWJSPONFOUWBSJBCMFT
    IBWFUPCFIFSF

    View Slide

  33. 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
    1SPWJTJPOBMMZ
    "OFNQUZ)BTIPCKFDU

    View Slide

  34. View Slide

  35. ‎(PUMPUTPGFSSPST
    ☠☠☠

    View Slide

  36. *UTFFNTUIFSF`SFSFRVJSFEWBSJBCMFT
    FOWNJTTJOHSFRVJSFELFZ3&26&[email protected]&5)0%
    3BDL-JOU-JOU&SSPS

    View Slide

  37. rack/lib/rack/lint.rb
    4FF3BDL-JOUDMBTT

    View Slide

  38. rack/lib/rack/lint.rb
    &YQMBOBUJPOTBCPVUSFRVJSFEWBSJBCMFT
    ʜ
    4FF3BDL-JOUDMBTT

    View Slide

  39. ⚡1"5)@*/'0‎1BUIPGSFRVFTUFE63-
    ⚡26&3:@453*/(‎2VFSZTUSJOH
    ⚡.&5)0%‎)551NFUIPE
    ⚡4&37&[email protected]/".&‎5PCVJMEB63-XJUI
    4$3*[email protected]/".&1"5)@*/'0
    ⚡4&37&[email protected]‎5PCVJMEB63-XJUI
    4$3*[email protected]/".&1"5)@*/'0
    7BSJBCMFTEFpOFEJO1&1
    1&1‎1ZUIPO8FC4FSWFS(BUFXBZ*OUFSGBDFW
    IUUQTXXXQZUIPOPSHEFWQFQTQFQ

    View Slide

  40. ⚡SBDLWFSTJPO‎3BDLWFSTJPO BO"SSBZPCKFDU

    ⚡SBDLJOQVU‎*OQVUTUSFBN
    BO*0MJLFPCKFDU

    ⚡SBDLFSSPST‎&SSPSTUSFBN
    BOPCKFDUSFTQPOTFUPQVUTXSJUFqVTI

    ⚡SBDLNVMUJQSPDFTT‎8IFUIFSUIFBQQMJDBUJPOJTJOWPLFE
    CZNVMUJQMFQSPDFTTFTTJNVMUBOFPVTMZ
    ⚡SBDLNVMUJUISFBE‎8IFUIFSUIFBQQMJDBUJPOJTJOWPLFE
    CZNVMUJQMFUISFBETJOUIFTBNFQSPDFTT
    BUUIFTBNFUJNF
    [email protected]‎'PSBTFSWFSCBTFEPO$(*
    [email protected]‎63*TDIFNF IUUQPSIUUQT

    3BDLTQFDJpDWBSJBCMFT

    View Slide

  41. 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
    %FpOFFOWNFUIPESFGTUP3BDL-JOU
    %ZOBNJDBMMZHFOFSBUFEWBSJBCMFTGSPNUIFSFRVFTU
    PSEFGBVMUWBMVF

    View 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 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
    (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF
    "EEDPEFTUPHFOFSBUFWBSJBCMFT

    View 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

    44

    45

    46

    47

    48

    49

    50

    51
    simple_rack_compatible_server.rb
    !NFUIPE‎)551NFUIPE
    ˏTDIFNF‎63*TDIFNF
    (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF

    View Slide

  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

    45

    46

    47

    48

    49

    50

    51
    simple_rack_compatible_server.rb
    !QBUI‎1BUIPGSFRVFTUFE63-
    !RVFSZ‎2VFSZTUSJOH
    (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF

    View Slide

  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

    47

    48

    49

    50

    51
    simple_rack_compatible_server.rb
    !JOQVU‎*OQVUTUSFBN 3FRVFTUCPEZ

    (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF

    View Slide

  46. 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
    *BMTPBEEFEMPHTUPEJTQMBZ
    (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF

    View Slide

  47. View Slide

  48. ‎*UXPSLT
    3FDFJWFESFRVFTUNFTTBHF(&5)551
    3BDL-JOU-JOU&SSPSFSSPSDMFBSFE
    BOEMPHTBSFEJTQMBZFE
    BUNZUFSNJOBM

    View Slide

  49. BU%FW5PPMTPGNZCSPXTFS
    4UBUVTDPEFBOE)FBEFSSFUVSOFEGSPN3BDLBQQ
    BSFTVDDFTTGVMMZPVUQVUUPUIFDMJFOUTJEF
    )FBEFS
    $POUFOU5ZQFUFYUIUNM

    4UBUVTDPEF


    View Slide

  50. "OEUIFSFTQPOTFCPEZJTʜ

    View Slide


  51. "OEUIFSFTQPOTFCPEZJTʜ

    View Slide

  52. 4PNFUIJOH`TXSPOH
    0,
    /(
    SBDLCPEZQSPYZ
    %0.TIPVMECFHFOFSBUFE
    GSPNSFTQPOTFCPEZ

    View Slide

  53. 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
    )FSFUIFSFTQPOTFNFTTBHFJT
    8IBU*XBTFYQFDUJOHJT
    [“Hello.This app is …”]
    $BMMUIF3BDLBQQHFUUIFSFUVSOWBMVFT
    <4UBUVT \)FBEFS^ <#PEZ>>

    View Slide

  54. 8IBUJTJOTJEF!CPEZ
    JSC 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSYʜ
    QQ!CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ
    3BDL-JOUYʜ
    !BQQ
    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ
    !CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ

    !DMPTFEGBMTF

    View Slide

  55. JSC 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSYʜ
    QQ!CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ
    3BDL-JOUYʜ
    !BQQ
    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ
    !CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ

    !DMPTFEGBMTF
    *U`TBOJOTUBODFPG3BDL#PEZ1SPYZ
    8IBUJTJOTJEF!CPEZ

    View Slide

  56. JSC 4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFSYʜ
    QQ!CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ
    3BDL-JOUYʜ
    !BQQ
    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ
    !CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ

    !DMPTFEGBMTF
    "OEUIJTJTXIBU*XBOU
    )PXDBO*HFUUIJTʜ

    8IBUJTJOTJEF!CPEZ

    View Slide

  57. JSC 4JNQMF3BDL$PNQBUJCMF4FSWFSTFSWʜ
    QQ!CPEZDBMM FOW

    <
    \$POUFOU5ZQFUFYUIUNM^
    3BDL-JOUYʜ
    !BQQ
    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ
    !CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ
    <EJWI)FMMPIQ5IJTBQQJTʜQEJW>
    !DMPTFEGBMTF
    [email protected]
    [email protected]>
    5SJFEUPDBMM!CPEZ

    View Slide

  58. JSC 4JNQMF3BDL$PNQBUJCMF4FSWFSTFSWFʜ
    QQ!CPEZDBMM FOW

    <
    \$POUFOU5ZQFUFYUIUNM^
    3BDL-JOUYʜ
    !BQQ
    3BDL5FNQpMF3FBQFSYʜ!BQQ"QQYʜ
    !CPEZ
    3BDL#PEZ1SPYZYʜ
    !CMPDL
    1SPDYʜ!ʜ[email protected]
    !CPEZ

    !DMPTFEGBMTF
    [email protected]
    [email protected]>
    4PGBSʜ
    4IPVME*LFFQDBMMJOHVOUJM
    UIFSFTQPOTFCPEZJUTFMG
    JTSFUVSOFE
    CPEZ BOJOTUBODFPG3BDL-JOU

    5SJFEUPDBMM!CPEZ

    View Slide

  59. *HPUBIJOUGSPN5BLBIBTIJTBO
    5IFDBMMNFUIPESFUVSOTBO"SSBZPCKFDU
    XJUIFMFNFOUTBOEUIFUIJSEJTCPEZ
    "OECPEZJTBOPCKFDUSFTQPOEUP
    FBDINFUIPE [email protected]ʜ

    View Slide

  60. *HPUBIJOUGSPN5BLBIBTIJTBO
    5IFDBMMNFUIPESFUVSOTBO"SSBZPCKFDU
    XJUIFMFNFOUTBOEUIFUIJSEJTCPEZ
    "OECPEZJTBOPCKFDUSFTQPOEUP
    FBDINFUIPE [email protected]ʜ
    ʜFBDINFUIPE

    View Slide

  61. 3BDL#PCZ1SPYZFBDI
    3BDL#PCZ1SPYZIBTFBDINFUIPE
    5IJTNJHIUCFVTFGVM

    View Slide

  62. 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
    (FUSFTQPOTFCPEZVTJOHFBDINFUIPE
    … $BMMFBDINFUIPEUP!CPEZ
    BOEHFOFSBUFBO"SSBZPCKFDU
    $POWFSUUPBTUSJOHBUUIFFOE

    View Slide

  63. 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
    $BMMCPEZNFUIPE

    $BMMUIFCPEZNFUIPE

    View Slide

  64. View Slide

  65. BOEʜ

    View Slide

  66. *UXPSLT
    3FTQPOTFCPEZJTBMTPEJTQMBZFE

    View Slide

  67. 5IFTUBUVTDPEF IFBEFS BOECPEZBSF
    BMMPVUQVUUPUIFDMJFOUTJEF
    *UXPSLT
    4UBUVT‎)5510,
    )FBEFS‎$POUFOU5ZQFUFYUIUNM
    #PEZ‎EJW
    I)FMMPI
    Q5IJTBQQJTʜQ
    EJW

    View Slide

  68. 5IJTJTUIFpYFEWFSTJPO⚡

    View Slide

  69. 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
    ⚡SFRVJSFTPDLFUMJCSBSZ
    ⚡*OJUJBMJ[FSFRVJSFEJOTUBODFWBSJBCMFT

    View Slide

  70. 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
    ⚡1SPWJEFUIFWBSJBCMFTSFRVJSFEUPDBMMUIF3BDLBQQ

    View Slide

  71. 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
    ⚡4UBSUMPPQJOH
    ⚡"DDFQUBOJODPNJOHDPOOFDUJPO
    ⚡$SFBUFBOFXTFSWFSTPDLFU
    ⚡%JTQMBZBTUBSUJOHNFTTBHF

    View Slide

  72. 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
    ⚡(FUUIFSFRVFTUNFTTBHF
    ⚡(FOFSBUFWBSJBCMFTGPSDBMMJOH3BDLBQQ
    ⚡%JTQMBZMPHUPUIFTFSWFSTJEF

    View Slide

  73. 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
    ⚡$BMMUIF3BDLBQQ(FUUIFSFUVSOFEWBMVFT
    ⚡(FOFSBUFUIFSFTQPOTFNFTTBHF
    GSPNUIFSFUVSOFEWBMVF0VUQVUJU
    ⚡$MPTFUIFTPDLFU

    View Slide

  74. 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 Slide

  75. ͓ർΕ༷Ͱͨ͠✨

    View Slide

  76. ը૾ɿIUUQTUXJUUFSDPNUFOEFSMPWF
    ग़యɿIUUQTTQFBLFSEFDLDPNUFOEFSMPWFHBPEVOBLPEP
    "BSPOTBOɹɹɹɹ

    View Slide

  77. .ZJNQSFTTJPOBGUFSJNQMFNFOUBUJPO
    3BDLΛ࢖ͬͯ
    3BDLDPNQBUJCMFͳ
    8FCαʔόʔΛ࡞Δͷ͸
    ָ

    View Slide

  78. "OEBMTPʜ
    ⚡5IFSFBSFTUJMMBMPUPGUIJOHTUPUIJOLBCPVU
    BTJUJTTUJMMQSPWJTJPOBMMZJNQMFNFOUFE
    *OQVU 1BSBMMFMJ[BUJPO 1FSGPSNBODFʜ

    ⚡*`EMPWFUPLOPXNPSFBOENPSFBCPVU3BDL
    ⚡*`NXBJUJOHGPSZPVSSFWJFX
    [email protected]@[email protected]

    View Slide

  79. 3BDL͸ָɹ

    View Slide

  80. 3BDL͸ָ͍͠ʂ

    View Slide

  81. ͓ΘΓʹ⚡⚡⚡

    View Slide

  82. "CPVUNF BHBJO

    View Slide

  83. %PZPVSFNFNCFSXIBUIBQQFOFE
    ZFBSBOEBIBMGBHP

    View Slide

  84. 4FQ
    0FEP3VCZ,BJHJ
    ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP

    View Slide

  85. .ZpSTUUJNFGPS"TBLVTBSC
    ʜJTEBZTCFGPSF
    UIFQSFWJPVT0FEP3VCZ,BJHJ

    GSPNUIFFTBPG"TBLVTBSC

    "OE*BQQMJFEGPSJUBUUIBUUJNFSJHIUBXBZ

    ୈճ
    ը૾ɿIUUQTBTBLVTBSCFTBJPQPTUT

    View Slide

  86. ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP
    5IFQSFWJPVT0FEP3VCZLBJHJ

    View Slide

  87. XBTBHSFBUUJNF
    ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP
    5IFQSFWJPVT0FEP3VCZLBJHJ

    View Slide

  88. ,FZOPUF
    +POBOTBOʮ)PXUPCFσΧʯ
    ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP
    5IFQSFWJPVT0FEP3VCZLBJHJ

    View Slide

  89. ,FZOPUF
    +POBOTBOʮ)PXUPCFσΧʯ
    Have your heroes
    ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP
    5IFQSFWJPVT0FEP3VCZLBJHJ

    View Slide

  90. 'PSNF
    ZFBSBOEBIBMGBHP
    5IFQFPQMFJO"TBLVTBSC
    XFSFSFBMlIFSPFTz

    View Slide

  91. /PX
    BOEBIBMGZFBSTMBUFS
    5IFZBSFBMTP
    QFFSTJOUIFTBNFDPNNVOJUZ

    View Slide

  92. 5BMLBCPVU3VCZ FUD


    8SJUFDPEFT+
    )BWFBEFMJDJPVTEJTIFTFUD
    'PSNF "TBLVTBSCJTXIFSF
    3VCZJTUTHBUIFS
    UPNBLFΘ͍Θ͍BOEFOKPZ

    View Slide

  93. "TBLVTBSC͸ָ͍͠ʂ

    View Slide

  94. 4QFDJBM5IBOLT✨
    JOTQJSFEGSPN
    !FTUIFS
    !UFOEFSMPWFUIF3BDLUFBN
    ŠŠ
    !JHBJHB!VE[VSB
    !UBLBIBTIJN!PLVSBNBTBGVNJ
    !UIFKPOBOTIPX"TBLVTBSC'VLVPLBSC
    "OEUIBOLZPVGPSMJTUFOJOH⚡⚡⚡

    View Slide