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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
160
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
350
Webフレームワークの ベンチマークについて
yusukebe
0
130
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
230
CLIであることを活かしたGitHub Copilot CLI活用術 / GitHub Copilot CLI Pro Tips & Tricks
nao_mk2
1
1.2k
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
17
6k
Stage 3 Decorators でできること / できないこと / TSKaigi 2026
susisu
1
1.5k
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.1k
oxlintはeslint/typescript-eslintを置き換えられるのか
shomafujita
2
320
AIエージェントと協働するCLI開発 — BunとOpenClawで学んだこと
yoshikouki
1
240
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
120
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
150
Featured
See All Featured
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
190
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
390
Optimizing for Happiness
mojombo
378
71k
Why Our Code Smells
bkeepers
PRO
340
58k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
290
Believing is Seeing
oripsolob
1
140
Designing for Performance
lara
611
70k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
840
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Heart Work Chapter 1 - Part 1
lfama
PRO
7
36k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
130
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
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⚡⚡⚡