Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
[English ver]実録 Let's build a simple Rack compatible server
Misaki Shioi(塩井美咲/しおい)
February 11, 2020
Programming
1
76
[English ver]実録 Let's build a simple Rack compatible server
Misaki Shioi(塩井美咲/しおい)
February 11, 2020
Tweet
Share
More Decks by Misaki Shioi(塩井美咲/しおい)
See All by Misaki Shioi(塩井美咲/しおい)
coe401_
6
1.5k
coe401_
5
3.6k
coe401_
14
7.1k
coe401_
2
400
coe401_
8
460
Other Decks in Programming
See All in Programming
yasaichi
31
7.9k
takapy
0
110
alperhankendi
1
150
grapecity_dev
0
170
selcukusta
1
110
hyodol2513
0
600
hanasuke
1
590
mackee
0
580
manfredsteyer
PRO
0
120
xrdnk
0
110
boriswilhelms
0
130
antonshilov
1
120
Featured
See All Featured
jmmastey
10
610
yeseniaperezcruz
302
31k
notwaldorf
15
1.8k
bermonpainter
342
26k
searls
204
36k
smashingmag
283
47k
garrettdimon
288
110k
maltzj
502
36k
smashingmag
230
18k
davidbonilla
70
3.6k
ufuk
56
5.4k
jnunemaker
PRO
40
4.6k
Transcript
.JTBLJ4IJPJ!DPF@ 'FC 0FEP3VCZ,BJHJ ࣮ -FU`TCVJMEBTJNQMF 3BDLDPNQBUJCMFTFSWFS⚡⚡⚡
"CPVUNF .JTBLJ4IJPJ ͓͍͠ !DPF@ ⚡8FCQSPHSBNNFS ⚡#FMPOHTUP"TBLVTBSC 5BNBSC 'VLVPLBSC ⚡*UTCFFOZFBSBOEBIBMG
TJODF*KPJOFE"TBLVTBSCNFFUVQGPSUIFpSTUUJNF ⚡#VJMUBXFCTFSWFSSFDFOUMZ
.JTBLJ4IJPJ ͓͍͠ !DPF@ ⚡8FCQSPHSBNNFS ⚡#FMPOHTUP"TBLVTBSC 5BNBSC 'VLVPLBSC ⚡*UTCFFOZFBSBOEBIBMG TJODF*KPJOFE"TBLVTBSCNFFUVQGPSUIFpSTUUJNF
⚡#VJMUBXFCTFSWFSSFDFOUMZ "CPVUNF ‐5PEBZ`TUIFNF
BU 3VCZ$POG/BTIWJMMF /PWFNCFS
l-FU`TCVJMEBTJNQMF)551TFSWFSz XIJDIJTBWFSZJOUFSFTUJOHUBML CZ&45)&30-"56/%&!FTUIFS ग़యɿIUUQTOPUJTUFTUIFSD(V(+MFUTCVJMEBTJNQMFIUUQTFSWFSXJUISVCZ
ʜJTJOUSPEVDFECZ!JHBJHB`TUXFFU ग़యɿIUUQTUXJUUFSDPNJHBJHBTUBUVT T
ʜJTJOUSPEVDFECZ!VE[VSB GSPN'VLVPLBSC CZUXFFU UPNF ग़యɿIUUQTUXJUUFSDPNVE[VSBTUBUVT T ˞NF
4P XJUIUIFSFGFSFODFUPUIFTMJEF *CVJMUBTJNQMF)551TFSWFS
ʜ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
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
DVSMMPDBMIPTU )PTU1PSUXIJDIBSFPQFOFE
*UXPSLT POTFSWFSTJEF PODMJFOUTJEF 3FRVFTUNFTTBHF JTEJTQMBZFE 3FTQPOTFCPEZ JTEJTQMBZFE
#VU
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
*EMJLFUPNBLFUIJTTFSWFS 3BDLDPNQBUJCMF
4P *USJFEUPCVJME BTJNQMF3BDLDPNQBUJCMFTFSWFS XIJDIJTOBNFE 4JNQMF3BDL$PNQBUJCMF4FSWFS
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 )FSFJTB3BDLBQQGPSWFSJpDBUJPO app/sample.ru
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 4UBUVT)5510, )FBEFS$POUFOU5ZQFUFYUIUNM #PEZEJW I)FMMPI Q5IJTBQQJTʜQ EJW app/sample.ru )FSFJTB3BDLBQQGPSWFSJpDBUJPO 8IFOZPVSVOʜ
)PX3BDLBQQMJDBUJPOTUBSUT 6TFSFYFDVUFTSBDLVQ )BOEMFSJTDBMMFE 4FSWFSJTSFHJTUFSFEUP)BOEMFS 4FSWFSTUBSUTUPSVO )BOEMFSTUBSUT4FSWFS 5IFTFSWFS DPOOFDUFEUP3BDL 4FSWFSSVOT3BDLBQQ 4UBSU
4FSWFSDBMMT3BDLBQQ
JOUIFTFSWFS JO3BDL)BOEMFSNPEVMF JOUIFTFSWFS JO3BDL 6TFSFYFDVUFTSBDLVQ )BOEMFSJTDBMMFE 4FSWFSJTSFHJTUFSFEUP)BOEMFS 4FSWFSTUBSUTUPSVO )BOEMFSTUBSUT4FSWFS 4FSWFSDBMMT3BDLBQQ
)PX3BDLBQQMJDBUJPOTUBSUT
3FRVJSFNFOUPG3BDLDPNQBUJCMFTFSWFS *UIPVHIUBCPVUUIFSFRVJSFNFOUTGPSUIFTFSWFS CBTFEPOIPX3BDLBQQTUBSUT ᶃ)BOEMFS 3BDL)BOEMFS4JNQMF3BDL$PNQBUJCMF4FSWFS ⚡5PSFHJTUFSUIFTFSWFSUP3BDL)BOEMFSNPEVMF ⚡5PTUBSUUIFTFSWFS ᶄ4FSWFS
4JNQMF3BDL$PNQBUJCMF4FSWFS4FSWFS ⚡5PSFDFJWFBSFRVFTUNFTTBHF ⚡5PDBMM3BDLBQQMJDBUJPO ⚡5PSFUVSOBSFTQPOTFNFTTBHF
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
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
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
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
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
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
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
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
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
#VU
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
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
SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS "OZXBZʜ
(PUMPUTPGFSSPST ☠☠☠
*UTFFNTUIFSF`SFSFRVJSFEWBSJBCMFT FOWNJTTJOHSFRVJSFELFZ3&26&45@.&5)0% 3BDL-JOU-JOU&SSPS
rack/lib/rack/lint.rb 4FF3BDL-JOUDMBTT
rack/lib/rack/lint.rb &YQMBOBUJPOTBCPVUSFRVJSFEWBSJBCMFT ʜ 4FF3BDL-JOUDMBTT
⚡1"5)@*/'01BUIPGSFRVFTUFE63- ⚡26&3:@453*/(2VFSZTUSJOH ⚡.&5)0%)551NFUIPE ⚡4&37&3@/".&5PCVJMEB63-XJUI 4$3*15@/".&1"5)@*/'0 ⚡4&37&3@10355PCVJMEB63-XJUI 4$3*15@/".&1"5)@*/'0 7BSJBCMFTEFpOFEJO1&1 1&11ZUIPO8FC4FSWFS(BUFXBZ*OUFSGBDFW IUUQTXXXQZUIPOPSHEFWQFQTQFQ
⚡SBDLWFSTJPO3BDLWFSTJPO BO"SSBZPCKFDU ⚡SBDLJOQVU*OQVUTUSFBN BO*0MJLFPCKFDU ⚡SBDLFSSPST&SSPSTUSFBN BOPCKFDUSFTQPOTFUPQVUTXSJUFqVTI
⚡SBDLNVMUJQSPDFTT8IFUIFSUIFBQQMJDBUJPOJTJOWPLFE CZNVMUJQMFQSPDFTTFTTJNVMUBOFPVTMZ ⚡SBDLNVMUJUISFBE8IFUIFSUIFBQQMJDBUJPOJTJOWPLFE CZNVMUJQMFUISFBETJOUIFTBNFQSPDFTT BUUIFTBNFUJNF ⚡SBDLSVO@PODF'PSBTFSWFSCBTFEPO$(* ⚡SBDLVSM@TDIFNF63*TDIFNF IUUQPSIUUQT 3BDLTQFDJpDWBSJBCMFT
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
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
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 ˏTDIFNF63*TDIFNF (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF
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 !QBUI1BUIPGSFRVFTUFE63- !RVFSZ2VFSZTUSJOH (FOFSBUFWBSJBCMFTGSPNUIFSFRVFTUNFTTBHF
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
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
SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS "HBJOʜ
*UXPSLT 3FDFJWFESFRVFTUNFTTBHF(&5)551 3BDL-JOU-JOU&SSPSFSSPSDMFBSFE BOEMPHTBSFEJTQMBZFE BUNZUFSNJOBM
BU%FW5PPMTPGNZCSPXTFS 4UBUVTDPEFBOE)FBEFSSFUVSOFEGSPN3BDLBQQ BSFTVDDFTTGVMMZPVUQVUUPUIFDMJFOUTJEF )FBEFS $POUFOU5ZQFUFYUIUNM 4UBUVTDPEF
"OEUIFSFTQPOTFCPEZJTʜ
"OEUIFSFTQPOTFCPEZJTʜ
4PNFUIJOH`TXSPOH 0, /( SBDLCPEZQSPYZ %0.TIPVMECFHFOFSBUFE GSPNSFTQPOTFCPEZ
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 [“<div><h1>Hello.</h1><p>This app is …</p></div>”] $BMMUIF3BDLBQQHFUUIFSFUVSOWBMVFT <4UBUVT \)FBEFS^ <#PEZ>>
8IBUJTJOTJEF!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
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 *U`TBOJOTUBODFPG3BDL#PEZ1SPYZ 8IBUJTJOTJEF!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)FMMPIQ5IJTBQQJTʜQEJWz> !DMPTFEGBMTF "OEUIJTJTXIBU*XBOU )PXDBO*HFUUIJTʜ 8IBUJTJOTJEF!CPEZ
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> 5SJFEUPDBMM!CPEZ
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> 4PGBSʜ 4IPVME*LFFQDBMMJOHVOUJM UIFSFTQPOTFCPEZJUTFMG JTSFUVSOFE CPEZ BOJOTUBODFPG3BDL-JOU 5SJFEUPDBMM!CPEZ
*HPUBIJOUGSPN5BLBIBTIJTBO 5IFDBMMNFUIPESFUVSOTBO"SSBZPCKFDU XJUIFMFNFOUTBOEUIFUIJSEJTCPEZ "OECPEZJTBOPCKFDUSFTQPOEUP FBDINFUIPE UP@QBUINFUIPEBOETPPOʜ
*HPUBIJOUGSPN5BLBIBTIJTBO 5IFDBMMNFUIPESFUVSOTBO"SSBZPCKFDU XJUIFMFNFOUTBOEUIFUIJSEJTCPEZ "OECPEZJTBOPCKFDUSFTQPOEUP FBDINFUIPE UP@QBUINFUIPEBOETPPOʜ ʜFBDINFUIPE
3BDL#PCZ1SPYZFBDI 3BDL#PCZ1SPYZIBTFBDINFUIPE 5IJTNJHIUCFVTFGVM
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
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
SBDLVQTTJNQMF@SBDL@DPNQBUJCMF@TFSWFS "HBJOBOEBHBJO
BOEʜ
*UXPSLT 3FTQPOTFCPEZJTBMTPEJTQMBZFE
5IFTUBUVTDPEF IFBEFS BOECPEZBSF BMMPVUQVUUPUIFDMJFOUTJEF *UXPSLT 4UBUVT)5510, )FBEFS$POUFOU5ZQFUFYUIUNM #PEZEJW I)FMMPI Q5IJTBQQJTʜQ
EJW
5IJTJTUIFpYFEWFSTJPO⚡
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
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
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
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
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
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
͓ർΕ༷Ͱͨ͠✨
ը૾ɿIUUQTUXJUUFSDPNUFOEFSMPWF ग़యɿIUUQTTQFBLFSEFDLDPNUFOEFSMPWFHBPEVOBLPEP "BSPOTBOɹɹɹɹ
.ZJNQSFTTJPOBGUFSJNQMFNFOUBUJPO 3BDLΛͬͯ 3BDLDPNQBUJCMFͳ 8FCαʔόʔΛ࡞Δͷ ָ
"OEBMTPʜ ⚡5IFSFBSFTUJMMBMPUPGUIJOHTUPUIJOLBCPVU BTJUJTTUJMMQSPWJTJPOBMMZJNQMFNFOUFE *OQVU 1BSBMMFMJ[BUJPO 1FSGPSNBODFʜ ⚡*`EMPWFUPLOPXNPSFBOENPSFBCPVU3BDL ⚡*`NXBJUJOHGPSZPVSSFWJFX
IUUQTHJUIVCDPNTIJPJNNTJNQMF@SBDL@DPNQBUJCMF@TFSWFS
3BDLָɹ
3BDLָ͍͠ʂ
͓ΘΓʹ⚡⚡⚡
"CPVUNF BHBJO
%PZPVSFNFNCFSXIBUIBQQFOFE ZFBSBOEBIBMGBHP
4FQ 0FEP3VCZ,BJHJ ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP
.ZpSTUUJNFGPS"TBLVTBSC ʜJTEBZTCFGPSF UIFQSFWJPVT0FEP3VCZ,BJHJ GSPNUIFFTBPG"TBLVTBSC "OE*BQQMJFEGPSJUBUUIBUUJNFSJHIUBXBZ ୈճ ը૾ɿIUUQTBTBLVTBSCFTBJPQPTUT
ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP 5IFQSFWJPVT0FEP3VCZLBJHJ
XBTBHSFBUUJNF ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP 5IFQSFWJPVT0FEP3VCZLBJHJ
,FZOPUF +POBOTBOʮ)PXUPCFσΧʯ ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP 5IFQSFWJPVT0FEP3VCZLBJHJ
,FZOPUF +POBOTBOʮ)PXUPCFσΧʯ Have your heroes ը૾ɿIUUQTSFHJPOBMSVCZLBJHJPSHPFEP 5IFQSFWJPVT0FEP3VCZLBJHJ
'PSNF ZFBSBOEBIBMGBHP 5IFQFPQMFJO"TBLVTBSC XFSFSFBMlIFSPFTz
/PX BOEBIBMGZFBSTMBUFS 5IFZBSFBMTP QFFSTJOUIFTBNFDPNNVOJUZ
5BMLBCPVU3VCZ FUD ✨ 8SJUFDPEFT+ )BWFBEFMJDJPVTEJTIFTFUD 'PSNF "TBLVTBSCJTXIFSF 3VCZJTUTHBUIFS UPNBLFΘ͍Θ͍BOEFOKPZ
"TBLVTBSCָ͍͠ʂ
4QFDJBM5IBOLT✨ JOTQJSFEGSPN !FTUIFS !UFOEFSMPWFUIF3BDLUFBN !JHBJHB!VE[VSB !UBLBIBTIJN!PLVSBNBTBGVNJ !UIFKPOBOTIPX"TBLVTBSC'VLVPLBSC "OEUIBOLZPVGPSMJTUFOJOH⚡⚡⚡