Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
[English ver]実録 Let's build a simple Rack compa...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Misaki Shioi(塩井美咲/しおい)
February 11, 2020
Programming
310
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
[English ver]実録 Let's build a simple Rack compatible server
Misaki Shioi(塩井美咲/しおい)
February 11, 2020
More Decks by Misaki Shioi(塩井美咲/しおい)
See All by Misaki Shioi(塩井美咲/しおい)
The Less-Told Story of Socket Timeouts
coe401_
3
2.4k
Making TCPSocket.new "Happy"!
coe401_
1
9.3k
たのしいSocketのしくみ / Socket Under a Microscope
coe401_
10
3.2k
XPE2-bookclub Explained
coe401_
0
220
Some more adventure of Happy Eyeballs
coe401_
2
490
Introduction of Happy Eyeballs Version 2 (RFC8305) to the Socket library
coe401_
1
560
An adventure of Happy Eyeballs
coe401_
3
13k
Implementing "++" operator, stepping into parse.y
coe401_
4
14k
たのしいRubyの構文解析ツアー
coe401_
7
4.8k
Other Decks in Programming
See All in Programming
Inside Stream API
skrb
1
640
開発体験を左右するライブラリの API 設計 - GraphQL スキーマ構築ライブラリから考える #tskaigi
izumin5210
2
1.6k
Swiftのレキシカルスコープ管理
kntkymt
0
210
プラグインで拡張される Context をtype-safe にする難しさと設計判断
kazupon
2
590
ふつうのFeature Flag実践入門
irof
7
3.6k
AutonomyとControlのあいだ:Graflowで記述するAIエージェント協調
myui
0
110
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
The Arts and Crafts of Work in the AI Era — Toward Mastery in Software Development
kuranuki
1
720
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
1
620
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
1.9k
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
160
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
500
Featured
See All Featured
Bash Introduction
62gerente
615
210k
KATA
mclloyd
PRO
35
15k
How to Talk to Developers About Accessibility
jct
2
220
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
71
40k
WENDY [Excerpt]
tessaabrams
11
38k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
600
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.3k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
550
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.3k
So, you think you're a good person
axbom
PRO
2
2.1k
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⚡⚡⚡