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

Toycol: Define your own application protocol

Toycol: Define your own application protocol

5b3338b3676d4f7091a575e584f3a4f4?s=128

Misaki Shioi(塩井美咲/しおい)
PRO

September 09, 2021
Tweet

Transcript

  1. .JTBLJ4IJPJ TIJPJNN!DPF@  4FQ 3VCZ,BJHJ5BLFPVU 5PZDPM %F fi OFZPVSPXOBQQMJDBUJPOQSPUPDPM

  2. "CPVUNF (JU)VC!TIJPJNN 5XJUUFS!DPF@ 8FCBQQMJDBUJPOEFWFMPQFSBU$BUBM *OD .FNCFSPG"TBLVTBSC'VLVPLBSC

  3. "CPVUNF IUUQTSVCZLBJHJPSH ʜBOEXBTBIFMQFSTUB ff  BU3VCZ,BJHJJO'VLVPLB

  4. *`NWFSZIBQQZUPCFBTQFBLFSBU 3VCZ,BJHJ5BLFPVU

  5. #ZUIFXBZ

  6. 8IBUEPZPVMJLFBCPVU 5$1*1QSPUPDPMTUBDL  *ONZPQJOJPOʜ

  7. 5IFGBDUUIBUFBDIMBZFS EPFTJUTPXOKPC 5IFZEPOUDBSFXIBU PUIFSMBZFSTBSFEPJOH Application Layer Transport Layer Internet Layer

    Link Layer 8IBU*MJLFBCPVU5$1*1QSPUPDPMTUBDLᶃ 5$1*1QSPUPDPMTUBDL
  8. 8IBU*MJLFBCPVU5$1*1QSPUPDPMTUBDLᶄ /FUXPSLOPEF Application Layer Transport Layer Internet Layer Link Layer

    /FUXPSLOPEF Application Layer Transport Layer Internet Layer Link Layer  5IFGBDUUIBUMBZFSTPGUIFTBNFMFWFMPGUIFBCTUSBDUJPO DPNNVOJDBUFXJUIFBDIPUIFSVTJOHUIFTBNFQSPUPDPM
  9. 4P XIBUJTB JOUIFDPOUFYUPGDPNQVUFSOFUXPSL QSPUPDPM

  10. *UJTBTFUPGSVMFTGPSDPNNVOJDBUJPO CFUXFFOOFUXPSLOPEFT

  11. 'PSFYBNQMF $MJFOU/PEF 4FSWFS/PEF 0O888 BDMJFOUBOEBTFSWFSBSFUSBOTNJUUJOH IZQFSNFEJBEPDVNFOUTVTJOH)551QSPUPDPM World Wide Web Transport

    Layer Internet Layer Link Layer World Wide Web Transport Layer Internet Layer Link Layer )551
  12. 'PSFYBNQMF $MJFOU/PEF 4FSWFS/PEF #VUUIFMBZFSTCFMPXUIFUSBOTQPSUMBZFSEPO`ULOPX XIBUUIFQSPUPDPMJTMJLF888JTVTJOH World Wide Web Transport Layer

    Internet Layer Link Layer World Wide Web Transport Layer Internet Layer Link Layer ˕
  13. 'PSFYBNQMF $MJFOU/PEF 4FSWFS/PEF 4UJMM UIFMBZFSTCFMPXUIFUSBOTQPSUMBZFSDBOUSBOTGFS XIBUFWFSEBUB888VTFT World Wide Web Transport

    Layer Internet Layer Link Layer World Wide Web Transport Layer Internet Layer Link Layer )551 )551
  14. 'PSFYBNQMF $MJFOU/PEF 4FSWFS/PEF "HBJO UIFOFUXPSLOPEFTDBODPNNVOJDBUFXJUIFBDIPUIFS BTMPOHBTUIFZCPUIVOEFSTUBOEUIFTBNFQSPUPDPM World Wide Web Transport

    Layer Internet Layer Link Layer World Wide Web Transport Layer Internet Layer Link Layer )551
  15. 'PSFYBNQMF $MJFOU/PEF 4FSWFS/PEF *OPUIFSXPSET UIFQSPUPDPMGPSDPNNVOJDBUJPOEPFTOU IBWFUPCF)551 BTMPOHBTUIFZVOEFSTUBOEJU World Wide Web

    Transport Layer Internet Layer Link Layer World Wide Web Transport Layer Internet Layer Link Layer ˕
  16. 4P  *IBWFDSFBUFEBTNBMMGSBNFXPSL UIBUBMMPXTZPVUPDSFBUF ZPVSPXOQSPUPDPMGPSDPNNVOJDBUJPO CFUXFFOBDMJFOUBOEBTFSWFSPO888  JOTUFBEPG)551 

  17. *OUIJTGSBNFXPSL  UIFQSPUPDPMZPVEF fi OFXPSLTBT BXSBQQFSGPSUIF)551 BOEDBOCFVTFEUPSVOBQQMJDBUJPOT

  18. -FUTTFFIPXJUXPSLT

  19. FH%VDLQSPUPDPM

  20. FH%VDLQSPUPDPM RVBDL RVBDLQPTUTVTFS@JE *OUIJTQSPUPDPM BDMJFOUTQFBLTUPBTFSWFSXJUI RVBDL RVBDLQPTUTVTFS@JEz 5IFOUIFTFSWFSVOEFSTUBOETJU Client Server

    
  21. 4FSWFSFYFDVUFTUIFBQQMJDBUJPOBOESFUVSOTUIFSFTVMU PGUIFBQQMJDBUJPOFYFDVUJPOUPUIFDMJFOU Client Server Application )5510,ʜ FH%VDLQSPUPDPM

  22. *UHPFTMJLFUIJT

  23. $ toycol server 4UBSUVQBTFSWFSUIBUVOEFSTUBOET%VDLQSPUPDPM $ toycol client “quack, quack /posts<3user_id=1”

    4FOESFRVFTUNFTTBHFCZ%VDLQSPUPDPMUPUIFTFSWFS FH%VDLQSPUPDPM
  24. $ toycol server [Toycol] Start built-in server, listening on unix:///tmp/toycol.socket

    [Toycol] Start proxy server on duck protocol, listening on localhost:9292 => Use Ctrl-C to stop [Toycol] Received message: "quack, quack /posts<3user_id=1” [Toycol] Message has been translated to HTTP request message: "GET /posts? user_id=1 HTTP/1.1\r\nContent-Length: 0\r\n\r\n" [Toycol] Successed to Send HTTP request message to server [Toycol] Received response message from server: HTTP/1.1 200 OK [Toycol] Finished to response to client -PHTPOUIFTFSWFSTJEF
  25. $ toycol client “quack, quack /posts<3user_id=1” [Toycol] Sent request message:

    quack, quack /posts<3user_id=1 --- [Toycol] Received response message: HTTP/1.1 200 OK Content-Type: text/html Content-Length: 32 quack quack, I am the No.1 duck -PHTPOUIFDMJFOUTJEF
  26. )PXFWFS JOUIFSFBMXPSME  UIFSFJT ZFU OPGVMM fl FEHFEXFCTFSWFS PSCSPXTFSJOUIFXPSMEUIBUSVOT POUIFQSPUPDPMZPVEFWJTFE

    4P UIFQSPUPDPMEF fi OFE CZUIJTGSBNFXPSLJTJOGBDUBlUPZz
  27. 'PSUIJTSFBTPO  *OBNFEUIJTGSBNFXPSLBTGPMMPXT

  28. 5PZ 1SPUPDPM 5PZDPM

  29. 5PZ 1SPUPDPM 5PZDPM IUUQTHJUIVCDPNTIJPJNNUPZDPM

  30. *OEFFE 5PZDPMJTBGSBNFXPSLGPSUPZ )PXFWFS CZVTJOHUIJTGSBNFXPSL ZPVXJMMCF BCMFUPFYQFSJFODFBOEMFBSO )PXUIFBQQMJDBUJPOMBZFSJTDPOOFDUFEUP UIFUSBOTQPSUMBZFSz BOE)PXUIFBQQMJDBUJPOQSPUPDPMXPSLTPO UIFUSBOTQPSUMBZFS

  31. 5PEBZ *XPVMEMJLFUPTIBSFJUXJUIZPV

  32. 5PEBZTBHFOEB )PXUPVTF5PZDPM XJUIBFYBNQMFPGTJNQMFEF fi OJUJPOT *OUFSOBMJNQMFNFOUBUJPOPG5PZDPM "EWBODFEQSPUPDPMEF fi OJUJPOT

  33. )PXUPVTF5PZDPM XJUIBFYBNQMFPGTJNQMFEF fi OJUJPOT

  34. -FU`TEF fi OFBOFXQSPUPDPMXJUI5PZDPM  BOETFFIPXJUXPSLTJOQSBDUJDF 5IJTUJNF MFUTDSFBUF BOFXQSPUPDPMOBNFE3VCZMJLF XPSLTXJUI3VCZMJLFTZOUBYQSPUPDPM

  35. 5PEF fi OFBOFXQSPUPDPM ZPVOFFEUPQSFQBSF UIJTGPMMPXJOHUXPJUFNT "DPO fi HVSBUJPO fi MF

    'PSEF fi OJOHQSPUPDPM 5IJT fi MFOFFETUPCFOBNFE l1SPUPDPM fi MFzPSl1SPUPDPM fi MFSVCZMJLFzBOETPPO "3BDLDPNQBUJCMFBQQMJDBUJPO FHDPO fi HSV ᶃ1SFQBSFBDPO fi HVSBUJPO fi MFBBQQMJDBUJPO
  36. ᶃ1SFQBSFBDPO fi HVSBUJPO fi MFBBQQMJDBUJPO :PVDBOFBTJMZDSFBUFUIFTFTLFMFUPOTCZVTJOH UPZDPMHFOFSBUFDPNNBOE $ toycol generate

    rubylike [Toycol] Generate Protocol fi le.rubylike in /path/to/current_directory [Toycol] Generate con fi g_rubylike.ru in /path/to/current_directory :PVDBOQBTTUIFQSPUPDPMOBNF BTBOBSHVNFOUUP UPZDPMHFOFSBUFDPNNBOE  6TFS
  37. ᶄ%F fi OFZPVSQSPUPDPMJOUIF1SPUPDPM fi MF Toycol::Protocol.de fi ne(:rubylike) do request.path

    do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else “Raise" end end additional_request_methods "Raise" custom_status_codes( 600 => "SyntaxError...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF /FYU EF fi OF3VCZMJLFQSPUPDPM JOUIF1SPUPDPM fi MF
  38. Toycol::Protocol.de fi ne(:rubylike) do request.path do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method

    do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else “Raise" end end additional_request_methods "Raise" custom_status_codes( 600 => "SyntaxError...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF 1BTTUIFQSPUPDPMOBNFBTBOBSHVNFOU BOEBCMPDLGPSEF fi OJOHUIFQSPUPDPM UP5PZDPM1SPUPDPMEF fi OF ᶄ%F fi OFZPVSQSPUPDPMJOUIF1SPUPDPM fi MF
  39. Toycol::Protocol.de fi ne(:rubylike) do request.path do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method

    do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else “Raise" end end additional_request_methods "Raise" custom_status_codes( 600 => "SyntaxError...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF :PVOFFEUPEF fi OFIPXUPQBSTF UIFSFRVFTUNFTTBHFJOUIFTFCMPDLTPG SFRVFTUQBUISFRVFTUIUUQ@NFUIPE ᶄ%F fi OFZPVSQSPUPDPMJOUIF1SPUPDPM fi MF
  40. Toycol::Protocol.de fi ne(:rubylike) do request.path do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method

    do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else “Raise" end end additional_request_methods "Raise" custom_status_codes( 600 => "SyntaxError...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF #FTJEFT ZPVDBOEF fi OFZPVSPXOTUBUVTDPEFT CZBEEJUJPOBM@SFRVFTU@NFUIPET BEEOFXSFRVFTUNFUIPETCZ DVTUPN@TUBUVT@DPEFTNFUIPE ᶄ%F fi OFZPVSQSPUPDPMJOUIF1SPUPDPM fi MF
  41. Toycol::Protocol.de fi ne(:rubylike) do request.path do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method

    do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else “Raise" end end additional_request_methods "Raise" custom_status_codes( 600 => "SyntaxError...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF *OUIJT3VCZMJLFQSPUPDPM  *BEEFE3BJTFBTBOFXSFRVFTUNFUIPE BOEEF fi OFEBTBDVTUPNTUBUVTDPEF ᶄ%F fi OFZPVSQSPUPDPMJOUIF1SPUPDPM fi MF
  42. Toycol::Protocol.de fi ne(:rubylike) do request.path do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method

    do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else “Raise" end end additional_request_methods "Raise" custom_status_codes( 600 => "SyntaxError...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF ᶄ%F fi OFZPVSQSPUPDPMJOUIF1SPUPDPM fi MF *GUIFSFRVFTUNFTTBHFJTTVDDFTTGVMMZQBSTFE  UIFSFRVFTUNFUIPEJT(&5  PUIFSXJTFJUJT3BJTF
  43. ᶅ#VJMEB3BDLDPNQBUJCMFBQQMJDBUJPO require "rack" require "toycol" Toycol::Protocol.use(:rubylike) class App def call(env)

    case env["REQUEST_METHOD"] when “GET” [200, { "Content-Type" => "text/html" }, [“I love Ruby!”\n”, ”I love RubyKaigi!\n”]] when “Raise” [600, { "Content-Type" => "text/html" }, [“Unexpected request message”]] end end end run App.new  6TFS DPO fi H@SVCZJMLFSV /FYU CVJMEB3BDLDPNQBUJCMFBQQMJDBUJPO UIBUSVOTPO3VCZMJLFQSPUPDPM
  44. require "rack" require "toycol" Toycol::Protocol.use(:rubylike) class App def call(env) case

    env["REQUEST_METHOD"] when “GET” [200, { "Content-Type" => "text/html" }, [“I love Ruby!”\n”, ”I love RubyKaigi!\n”]] when “Raise” [600, { "Content-Type" => "text/html" }, [“Unexpected request message”]] end end end run App.new :PVOFFEUPSFRVJSFlUPZDPMz  BOEDBMM5PZDPM1SPUPDPMVTFUPTQFDJGZ XIJDIQSPUPDPMZPVXPVMEMJLFUPVTF  6TFS DPO fi H@SVCZJMLFSV ᶅ#VJMEB3BDLDPNQBUJCMFBQQMJDBUJPO
  45. require "rack" require "toycol" Toycol::Protocol.use(:rubylike) class App def call(env) case

    env["REQUEST_METHOD"] when “GET” [200, { "Content-Type" => "text/html" }, [“I love Ruby!”\n”, ”I love RubyKaigi!\n”]] when “Raise” [600, { "Content-Type" => "text/html" }, [“Unexpected request message”]] end end end run App.new *OUIJTBQQMJDBUJPO *EF fi OFEUPSFUVSO TUBUVTDPEFGPS(&5SFRVFTU BOETUBUVTDPEFGPS4ZOUBY&SSPSSFRVFTU  6TFS DPO fi H@SVCZJMLFSV ᶅ#VJMEB3BDLDPNQBUJCMFBQQMJDBUJPO
  46. ᶆ3VOUIFTFSWFS4FOEBSFRVFTUNFTTBHF 5IFTFSWFSQSPHSBNUPSVOUIFQSPUPDPMBOEUIFDMJFOU QSPHSBNJOUPTFOEUIFSFRVFTUNFTTBHFCZUIFQSPUPDPM BSFCVJMUJOBTDPNNBOEMJOFUPPMT -FU`TTUBSUUIFTFSWFSTFOETPNFUIJOHUPSFRVFTU $ toycol client ??? (A

    request message by Rubylike protocol) $ toycol server con fi g_rubylike.ru 4FSWFS$-* $MJFOU$-*
  47. -FUTTFOEBNFTTBHFUIBUTFFNTUPCF3VCZMJLFTZOUBY $ toycol client “‘/posts’.get” [Toycol] Sent request message: '/posts'.get

    --- [Toycol] Received response message: HTTP/1.1 200 OK Content-Type: text/html Content-Length: 31 I love Ruby! I love RubyKaigi! 5IJTJT3VCZMJLF JTO`UJU 5IFBQQMJDBUJPOSFUVSOT0, ᶆ3VOUIFTFSWFS4FOEBSFRVFTUNFTTBHF
  48. -FU`TUSZBOBOPUIFSNFTTBHFUIBUNJHIUNJHIUSBJTFBFSSPS $ toycol client “get(‘/posts’)” [Toycol] Sent request message: get(‘/posts’)

    --- [Toycol] Received response message: HTTP/1.1 600 SyntaxError Content-Type: text/html Content-Length: 64 Unexpected request message *TJUQBSTFBCMFCZ3VCZMJLFQSPUPDPMʜ 5IFBQQMJDBUJPOSFUVSOT4ZOUBY&SSPS ᶆ3VOUIFTFSWFS4FOEBSFRVFTUNFTTBHF *U`TXPSLJOHDPSSFDUMZ
  49. *OUFSOBMJNQMFNFOUBUJPOPG5PZDPM

  50. /PXMFU`TFYQMPSFUIFJOTJEFPG5PZDPM GSPNUXPBTQFDUT 5IFOFUXPSLDPNNVOJDBUJPO fl PX )PXUPUSBOTMBUFBSFRVFTUNFTTBHF

  51. 5IFOFUXPSLDPNNVOJDBUJPO fl PX

  52. 5IFOFUXPSLDPNNVOJDBUJPO fl PX -FUTUBLFBMPPLBUIPX5PZDPMXPSLTJOUFSOBMMZXJUIUIF OFUXPSLDPNNVOJDBUJPO fl PX)FSFJTBPWFSBMMWJFX $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS

    "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi OJUJPO
  53. 4UBSUTFSWFSTCZ3BDLIBOEMFS 5PZDPMSVOT3BDLDPNQBUJCMFBQQMJDBUJPOT 4PZPVTUBSUTFSWFSTGPS5PZDPMCZ3BDLIBOEMFS $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi

    OJUJPO
  54. 4UBSUTFSWFSTXJUIUPZDPMTFSWFS UPZDPMTFSWFSDPNNBOEDBMMT3BDL4FSWFSTUBSUJOTJEF 3BDL 5IFO3BDL4FSWFSTUBSUDBMMT3BDL)BOEMFS5PZDPMSVO 3BDL)BOEMFS5PZDPMSVO 5PZDPM 3BDL UPZDPMTFSWFS 3BDL4FSWFSTUBSU

  55. 3BDL)BOEMFS5PZDPMSVO4UBSUTFSWFST module Rack module Handler class Toycol def self.run(app, _

    = {}) @app = app @host ||= ::Toycol::DEFAULT_HOST @port ||= "9292" if (child_pid = fork) ::Toycol::Proxy.new(@host, @port).start Process.waitpid(child_pid) else run_background_server end end end end end MJCSBDLIBOEMFSUPZDPMSC 3BDL)BOEMFS5PZDPMSVO
  56. module Rack module Handler class Toycol def self.run(app, _ =

    {}) @app = app @host ||= ::Toycol::DEFAULT_HOST @port ||= "9292" if (child_pid = fork) ::Toycol::Proxy.new(@host, @port).start Process.waitpid(child_pid) else run_background_server end end end end end 4UBSUBQSPYZTFSWFS 4UBSUBCBDLHSPVOETFSWFS MJCSBDLIBOEMFSUPZDPMSC 'PSLUPTUBSUUXPLJOEPGTFSWFST  BQSPYZTFSWFSBCBDLHSPVOETFSWFS  JOUIJTNFUIPE 3BDL)BOEMFS5PZDPMSVO4UBSUTFSWFST
  57. 5IFSPMFTPGUIFUXPTFSWFST 5IFQSPYZTFSWFSJTGPSSFDFJWJOHSFRVFTUTUSBOTMBUJOH QSPUPDPM $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi

    OJUJPO
  58. 5IFSPMFTPGUIFUXPTFSWFST 5IFCBDLHSPVOETFSWFSJTGPSSVOOJOHUIFBQQMJDBUJPO $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi OJUJPO

  59. 3BDL)BOEMFS5PZDPMTFMFDU@CBDLHSPVOE@TFSWFS def self.select_background_server case @prefferd_background_server when “puma” return “puma” if

    try_require_puma_handler raise LordError, “Puma is not installed in your environment.” when nil try_require_puma_handler ? “puma” : “builtin” else “builtin” rescue LordError Process.kill(:INT, Process.ppid) abort end MJCSBDLIBOEMFSUPZDPMSC "TBCBDLHSPVOETFSWFS VTF1VNBJGJUJTJOTUBMMFE JOZPVSFOWJSPONFOU0SVTFBTFSWFSUIBUJTCVJMUJOUP 5PZDPMJUTFMGJGJUJTOPU
  60. 28IZTIPVMEXFVTFCPUI BQSPYZTFSWFSBOEBCBDLHSPVOETFSWFS

  61. "5PQFSGPSNNFTTBHFUSBOTMBUJPO BOEBQQMJDBUJPOFYFDVUJPOTFQBSBUFMZ 4PNFBQQMJDBUJPOTCVJMUCZGSBNFXPSLTTVDIBT 4JOBUSBPS3BJMTVTF1VNBCZEFGBVMU  BOE*XPVMEO`UMJLFUPNPEJGZ1VNBPSUIFGSBNFXPSL UPNBLFUIFNXPSL

  62. 3FDFJWFBSFRVFTUNFTTBHFGSPNUIFDMJFOU 4PGBS XFWFHPUUIFTFSWFSTVQBOESVOOJOH/FYU UIF QSPYZTFSWFSSFDFJWFTBSFRVFTUNFTTBHFGSPNUIFDMJFOU $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS

    1SPUPDPM%F fi OJUJPO
  63. 5SBOTMBUFUIFSFRVFTUNFTTBHF "OEUIFOUIFQSPYZTFSWFSUSBOTMBUFTJUJOUPB)551 GPSNBUUFESFRVFTUNFTTBHFVTJOHUIFQSPUPDPMEF fi OJUJPO $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS

    1SPUPDPM%F fi OJUJPO
  64. def start … loop do trap(:INT) { shutdown } @client

    = @proxy.accept while !@client.closed? && !@client.eof? begin request = @client.readpartial(CHUNK_SIZE) logger “Received message: #{request.inspect.chomp}” safe_execution! { @protocol.run!(request) } … end end @client.close end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZTUBSU 5PZDPM1SPYZTUBSU3FDFJWF5SBOTMBUF
  65. def start … loop do trap(:INT) { shutdown } @client

    = @proxy.accept while !@client.closed? && !@client.eof? begin request = @client.readpartial(CHUNK_SIZE) logger “Received message: #{request.inspect.chomp}” safe_execution! { @protocol.run!(request) } … end end @client.close end end !QSPYZ5$14FSWFSOFX !IPTU !QPSU MJCUPZDPMQSPYZSC 3FDFJWFBSFRVFTUNFTTBHFGSPNUIFDMJFOU 5PZDPM1SPYZTUBSU3FDFJWF5SBOTMBUF
  66. def start … loop do trap(:INT) { shutdown } @client

    = @proxy.accept while !@client.closed? && !@client.eof? begin request = @client.readpartial(CHUNK_SIZE) logger “Received message: #{request.inspect.chomp}” safe_execution! { @protocol.run!(request) } … end end @client.close end end !QSPUPDPM5PZDPM1SPUPDPM MJCUPZDPMQSPYZSC &YFDVUF5PZDPM1SPUPDPMSVOUPUSBOTMBUF UIFSFRVFTUNFTTBHFJOUP)551GPSNBU 5PZDPM1SPYZTUBSU3FDFJWF5SBOTMBUF
  67. 4FOEBSFRVFTUNFTTBHFUPCBDLHSPVOETFSWFS 5IFQSPYZTFSWFSTFOETB)551GPSNBUUFESFRVFTU NFTTBHFUPUIFCBDLHSPVOETFSWFS $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi

    OJUJPO
  68. 3FDFJWFBSFTQPOTFNFTTBHFGSPNUIFCBDLHSPVOETFSWFS ʜBOESFDFJWFTUIFSFTVMUTPGUIFBQQMJDBUJPOFYFDVUFE GSPNUIFCBDLHSPVOETFSWFS $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi

    OJUJPO
  69. 5PZDPM1SPYZTUBSU$BMMUSBOTGFS@UP@TFSWFS def start … loop do trap(:INT) { shutdown }

    @client = @proxy.accept while !@client.closed? && !@client.eof? begin … http_request_message = build_http_request_message … transfer_to_server(http_request_message) end end @client.close end end MJCUPZDPMQSPYZSC $BMM5PZDPM1SPYZUSBOTGFS@UP@TFSWFS UIBUTFOETUIFSFRVFTUNFTTBHFUP UIFCBDLHSPVOETFSWFS
  70. 5PZDPM1SPYZUSBOTGFS@UP@TFSWFS3FRVFTU3FTQPOTF def transfer_to_server UNIXSocket.open(UNIIX_SOCKET_PATH) do |server| server.write request_message server.close_write …

    response_message = [] response_message << server.readpartial(CHUNK_SIZE) until server.eof? response_message = response_message.join … end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZUSBOTGFS@UP@TFSWFS
  71. 5PZDPM1SPYZUSBOTGFS@UP@TFSWFS3FRVFTU3FTQPOTF def transfer_to_server UNIXSocket.open(UNIIX_SOCKET_PATH) do |server| server.write request_message server.close_write …

    response_message = [] response_message << server.readpartial(CHUNK_SIZE) until server.eof? response_message = response_message.join … end end MJCUPZDPMQSPYZSC $POOFDUUPUIFCBDLHSPVOETFSWFSXJUI B6/*9EPNBJOTPDLFU
  72. 5PZDPM1SPYZUSBOTGFS@UP@TFSWFS3FRVFTU3FTQPOTF def transfer_to_server UNIXSocket.open(UNIIX_SOCKET_PATH) do |server| server.write request_message server.close_write …

    response_message = [] response_message << server.readpartial(CHUNK_SIZE) until server.eof? response_message = response_message.join … end end MJCUPZDPMQSPYZSC 4FOEUIFSFRVFTUNFTTBHFUP UIFCBDLHSPVOETFSWFS  5IFOUIFCBDLHSPVOETFSWFSSVOTUIFBQQMJDBUJPOʜ
  73. 5PZDPM1SPYZUSBOTGFS@UP@TFSWFS3FRVFTU3FTQPOTF def transfer_to_server UNIXSocket.open(UNIIX_SOCKET_PATH) do |server| server.write request_message server.close_write …

    response_message = [] response_message << server.readpartial(CHUNK_SIZE) until server.eof? response_message = response_message.join … end end MJCUPZDPMQSPYZSC  ʜPOUIFCBDLHSPVOE  3FDFJWFUIFSFTQPOTFNFTTBHFGSPN UIFCBDLHSPVOETFSWFS
  74. 3FUVSOUIFSFTQPOTFNFTTBHFUPUIFDMJFOU 5IFOUIFQSPYZTFSWFSSFUVSOTUIFSFTQPOTFNFTTBHF SFDFJWFEGSPNUIFCBDLHSPVOETFSWFSUPUIFDMJFOU $MJFOU 1SPYZ4FSWFS #BDLHSPVOE4FSWFS "QQMJDBUJPO 3BDL)BOEMFS 1SPUPDPM%F fi

    OJUJPO
  75. 5PZDPM1SPYZUSBOTGFS@UP@TFSWFS3FUVSOUIFSFTQPOTF def transfer_to_server UNIXSocket.open(UNIIX_SOCKET_PATH) do |server| … response_message = []

    response_message << server.readpartial(CHUNK_SIZE) until server.eof? response_message = response_message.join … @client.write response_message @client.close_write logger "Finished to response to client" server.close end end MJCUPZDPMQSPYZSC 3FUVSOTUIFSFTQPOTFNFTTBHFSFDFJWFE GSPNUIFCBDLHSPVOETFSWFSUPUIFDMJFOU
  76. )PXUPUSBOTMBUFBSFRVFTUNFTTBHF

  77. 5IJTJTIPX5PZDPMXPSLTJOUFSOBMMZGSPNUIFEF fi OJOHPG UIFQSPUPDPMVOUJMUSBOTMBUJOHBSFRVFTUNFTTBHFXJUIJU DMBTT1SPUPDPM $MJFOU 1SPUPDPM%F fi OJUJPO 1SPYZ4FSWFS

    UPZDPMTFSWFS "QQMJDBUJPO )PXUPUSBOTMBUFBSFRVFTUNFTTBHF
  78. "HBJO UIFTUBSUJOHQPJOUGPSUIFQSPHSBNFYFDVUJPOJT UPZDPMTFSWFSDPNNBOE DMBTT1SPUPDPM $MJFOU 1SPYZ4FSWFS "QQMJDBUJPO UPZDPMTFSWFS 1SPUPDPM%F fi

    OJUJPO 4UBSUUIFQSPHSBNXJUIUPZDPMTFSWFS
  79. 4UBSUUIFQSPHSBNXJUIUPZDPMTFSWFS "DUVBMMZ 3BDL4FSWFSTUBSUDBMMT3BDL#VJMEFSMPBE@ fi MF BOE3BDL#VJMEFSOFX@GSPN@TUSJOHUPMPBEUIFBQQMJDBUJPO fi MFCFGPSFDBMMJOH3BDL)BOEMFS5PZDPMSVO 3BDL)BOEMFS5PZDPMSVO 5PZDPM

    3BDL UPZDPMTFSWFS 3BDL4FSWFSTUBSU 3BDL#VJMEFSMPBE@ fi MF 3BDL#VJMEFSOFX@GSPN@TUSJOH
  80. 4P UIFQSPHSBNXJMMMPBEUIFBQQMJDBUJPO fi MFCFGPSF TUBSUJOHUIFTFSWFS $MJFOU 1SPYZ4FSWFS "QQMJDBUJPO UPZDPMTFSWFS -PBEUIFBQQMJDBUJPO

    fi MF DMBTT1SPUPDPM 1SPUPDPM%F fi OJUJPO
  81. 5IFBQQMJDBUJPO3FRVJSFlUPZDPMz require "rack" require "toycol" Toycol::Protocol.use(:rubylike) class App def call(env)

    case env["REQUEST_METHOD"] when “GET” [200, { "Content-Type" => "text/html" }, [“I love Ruby!”\n”, ”I love RubyKaigi!\n”]] when “OTHER” [600, { "Content-Type" => "text/html" }, [“Sorry, but I'd like you to speak more like a Ruby programmer…”]] end end end run App.new  6TFS DPO fi H@SVCZJMLFSV *OUIFBQQMJDBUJPO fi MF  UPZDPMJTSFRVJSFEUPSVO5PZDPM
  82. NPEVMF5PZDPM-PBE1SPUPDPM fi MFT require " fi leutiils" require “optparse" require

    “rack" require “scoket” require “stringio” … module Toycol … end Dir["#{FileUtils.pwd}/Protocol fi le*"].sort.each { |f| load f } MJCUPZDPMSC 8IFO5PZDPMJTSFRVJSFE  UIJT fi MFOBNFEUPZDPMSCJOUIF5PZDPMHFN XJMMCFMPBEFE
  83. require " fi leutiils" require “optparse" require “rack" require “scoket”

    require “stringio” … module Toycol … end Dir["#{FileUtils.pwd}/Protocol fi le*"].sort.each { |f| load f } 5PZDPMMPBET1SPUPDPM fi MFTUIBUBSFQMBDFE JOUIFTBNFEJSFDUPSZBTUIFBQQMJDBUJPO fi MF NPEVMF5PZDPM-PBE1SPUPDPM fi MFT 1SPUPDPM fi MF"DPO fi HVSBUJPO fi MFDPOUBJOJOHQSPUPDPMEF fi OJUJPOT MJCUPZDPMSC
  84. 4P UIF fi STUDPEFTUPCFMPBEFEJTUIFQSPUPDPMEF fi OJUJPO XIFOUIFQSPHSBNJTTUBSUFE $MJFOU 1SPYZ4FSWFS "QQMJDBUJPO

    UPZDPMTFSWFS -PBE1SPUPDPM fi MFT DMBTT1SPUPDPM 1SPUPDPM%F fi OJUJPO
  85. 1SPUPDPM fi MF4UPSFUIFFOUJSFEF fi OJUJPO Toycol::Protocol.de fi ne(:rubylike) do request.path

    do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else "OTHER" end end additional_request_methods "OTHER" custom_status_codes( 600 => "Hmm...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF 'PSFYBNQMF1SPUPDPM fi MFPG3VCZMJLFQSPUPDPM
  86. 1SPUPDPM fi MF4UPSFUIFFOUJSFEF fi OJUJPO Toycol::Protocol.de fi ne(:rubylike) do request.path

    do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else "OTHER" end end additional_request_methods "OTHER" custom_status_codes( 600 => "Hmm...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF 5IFDPEFTJOUIFCMPDLPG 5PZDPM1SPUPDPMEF fi OFBSFTUPSFE JO5PZDPM1SPUPDPMDMBTT
  87. 5PZDPM1SPUPDPMEF fi OF4UPSFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM !EF fi OFNFOUT\^

    ʜ EFGTFMGEF fi OF QSPUPDPM@OBNFEFGBVMU CMPDL  ʜ !EF fi OFNFOUT<QSPUPDPM@OBNF>CMPDL FOE ʜ FOE FOE MJCUPZDPMQSPUPDPMSC 5PZDPM1SPUPDPMEF fi OF
  88. 5PZDPM1SPUPDPMEF fi OF4UPSFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM !EF fi OFNFOUT\^

    ʜ EFGTFMGEF fi OF QSPUPDPM@OBNFEFGBVMU CMPDL  ʜ !EF fi OFNFOUT<QSPUPDPM@OBNF>CMPDL FOE ʜ FOE FOE MJCUPZDPMQSPUPDPMSC "TTJHOBIBTIPCKFDUUPBJOTUBODFWBSJBCMF!EF fi OFNFOUT 4UPSFUIFQSPUPDPMOBNFBTUIFLFZBOEUIFCMPDLEF fi OJOH UIFQSPUPDPMBTUIFWBMVFJOUIJTIBTIPCKFDU
  89. 1SPUPDPM fi MF4UPSFBEFUBJMFEEF fi OJUJPOGPSFBDI Toycol::Protocol.de fi ne(:rubylike) do request.path

    do |message| /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else "OTHER" end end additional_request_methods "OTHER" custom_status_codes( 600 => "Hmm...", ) end  6TFS 1SPUPDPM fi MFSVCZMJLF &BDIMPHJDTEF fi OFEJOUIFTFCMPDLTJT TUPSFEJOFBDIWBSJBCMFTPG 5PZDPM1SPUPDPMDMBTT
  90. NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU !SFRVFTUcc$MBTTOFXEP EFGTFMGQBUI CMPDL  !QBUICMPDL FOE

    EFGTFMGIUUQ@NFUIPE CMPDL  !IUUQ@NFUIPECMPDL FOE ʜ FOE FOE ʜ FOE FOE FH5PZDPM1SPUPDPMSFRVFTU4UPSFUIFEF fi OJUJPO MJCUPZDPMQSPUPDPMSC 'PSFYBNQMF5PZDPM1SPUPDPMSFRVFTU
  91. NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU !SFRVFTUcc$MBTTOFXEP EFGTFMGQBUI CMPDL  !QBUICMPDL FOE

    EFGTFMGIUUQ@NFUIPE CMPDL  !IUUQ@NFUIPECMPDL FOE ʜ FOE FOE ʜ FOE FOE FH5PZDPM1SPUPDPMSFRVFTU4UPSFUIFEF fi OJUJPO MJCUPZDPMQSPUPDPMSC 5IJTJTGPSBTTJHOJOHBOBOPOZNPVTDMBTTUP !SFRVFTUPG5PZDPM1SPUPDPM 5IJTBOPOZNPVTDMBTTJTVTFEUPTUPSFFBDIMPHJDGPS QBSTJOHUIFSFRVFTUNFTTBHFJOJUTPXOJOTUBODFWBSJBCMF
  92. FH5PZDPM1SPUPDPMSFRVFTU4UPSFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU !SFRVFTUcc$MBTTOFXEP EFGTFMGQBUI CMPDL

     !QBUICMPDL FOE EFGTFMGIUUQ@NFUIPE CMPDL  !IUUQ@NFUIPECMPDL FOE ʜ FOE FOE ʜ FOE FOE MJCUPZDPMQSPUPDPMSC &BDIJOTUBODFWBSJBCMFPGUIJTBOPOZNPVT DMBTTTUPSFTBCMPDLPGMPHJDUPHFU UIFSFRVFTUQBUI )551NFUIPE FUD SFRVFTUQBUIEPcNFTTBHFc /['"](?<path>.+)['"]/.match(message)[:path] end request.http_method do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else "OTHER" end end  6TFS 1SPUPDPM fi MFSVCZMJLF
  93. FH5PZDPM1SPUPDPMSFRVFTU4UPSFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU !SFRVFTUcc$MBTTOFXEP EFGTFMGQBUI CMPDL

     !QBUICMPDL FOE EFGTFMGIUUQ@NFUIPE CMPDL  !IUUQ@NFUIPECMPDL FOE ʜ FOE FOE ʜ FOE FOE MJCUPZDPMQSPUPDPMSC :PVDBOSFUSJFWFUIFTUPSFEMPHJDTCZFYFDVUJOHDBMMNFUIPE POFBDICMPDLTUPSFEJOUIFTFWBSJBCMFT 5PZDPM1SPUPDPMDMBTTIBTTPNFJOUFSGBDFTUIBU BMMPXTUIFTFUPCFDBMMFEBUBOZUJNF
  94. FH5PZDPM1SPUPDPMSFRVFTU@QBUI3FUSJFWFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU@QBUI SFRVFTU@QBUISFRVFTUJOTUBODF@WBSJBCMF@HFU l!QBUIz DBMM

    SFRVFTU@NFTTBHF  ʜ SFRVFTU@QBUI FOE FOE FOE MJCUPZDPMQSPUPDPMSC 'PSFYBNQMF5PZDPM1SPUPDPMSFRVFTU@QBUI
  95. FH5PZDPM1SPUPDPMSFRVFTU@QBUI3FUSJFWFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU@QBUI SFRVFTU@QBUISFRVFTUJOTUBODF@WBSJBCMF@HFU l!QBUIz DBMM

    SFRVFTU@NFTTBHF  ʜ SFRVFTU@QBUI FOE FOE FOE MJCUPZDPMQSPUPDPMSC 5IJTJTUIFNFUIPEUPHFUUIFSFRVFTUQBUI GSPNBSFRVFTUNFTTBHFBOE BMPHJDUPQBSTFUIFSFRVFTUNFTTBHF
  96. FH5PZDPM1SPUPDPMSFRVFTU@QBUI3FUSJFWFUIFEF fi OJUJPO NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSFRVFTU@QBUI SFRVFTU@QBUISFRVFTUJOTUBODF@WBSJBCMF@HFU l!QBUIz DBMM

    SFRVFTU@NFTTBHF  ʜ SFRVFTU@QBUI FOE FOE FOE MJCUPZDPMQSPUPDPMSC EFGBTTJHO@QBSTFE@BUUSJCVUFT ʜ !QBUI!QSPUPDPMSFRVFTU@QBUI ʜ FOE MJCUPZDPMQSPYZSC 5IFQSPYZTFSWFSVTFTUIJTNFUIPEUPSFUSJFWF UIFSFRVFTUQBUI XIFOUIFQSPYZTFSWFSCVJMET B)551GPSNBUUFESFRVFTUNFTTBHF
  97. "GUFSUIF1SPUPDPM fi MFIBTCFFOMPBEFE UIFBQQMJDBUJPO TFMFDUTXIJDIQSPUPDPMUPVTF $MJFOU 1SPYZ4FSWFS "QQMJDBUJPO UPZDPMTFSWFS 4FMFDUXIJDIQSPUPDPMUPVTF

    DMBTT1SPUPDPM 1SPUPDPM%F fi OJUJPO
  98. "QQMJDBUJPO4FMFDUXIJDIQSPUPDPMUPVTF require "rack" require "toycol" Toycol::Protocol.use(:rubylike) class App def call(env)

    case env["REQUEST_METHOD"] when “GET” [200, { "Content-Type" => "text/html" }, [“I love Ruby!”\n”, ”I love RubyKaigi!\n”]] when “OTHER” [600, { "Content-Type" => "text/html" }, [“Sorry, but I'd like you to speak more like a Ruby programmer…”]] end end end run App.new DPO fi H@SVCZJMLFSV 1BTTUIFQSPUPDPMOBNFZPVXBOUUPVTFUP 5PZDPM1SPUPDPMVTF
  99. NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGVTF QSPUPDPM@OBNFEFGBVMU  !QSPUPDPM@OBNFQSPUPDPM@OBNF FOE ʜ FOE

    FOE 5PZDPM1SPUPDPMVTF4UPSFUIFQSPUPDPMOBNF MJCUPZDPMQSPUPDPMSC 5PZDPM1SPUPDPMVTF
  100. 5SBOTMBUFBNFTTBHFXJUIQSPUPDPMUPVTF 'JOBMMZ USBOTMBUFUIFSFRVFTUNFTTBHFVTJOHUIFQSPUPDPM ZPVEF fi OFE $MJFOU 1SPYZ4FSWFS "QQMJDBUJPO UPZDPMTFSWFS

    DMBTT1SPUPDPM 1SPUPDPM%F fi OJUJPO
  101. def start … loop do trap(:INT) { shutdown } @client

    = @proxy.accept while !@client.closed? && !@client.eof? begin … safe_execution! { @protocol.run!(request) } assign_parsed_attributes! http_request_message = build_http_request_message … end end @client.close end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZTUBSU"QQMZUIFQSPUPDPM 5PZDPM1SPYZTUBSUFYFDVUFT UIFQSPUPDPMUSBOTMBUJPO
  102. def start … loop do trap(:INT) { shutdown } @client

    = @proxy.accept while !@client.closed? && !@client.eof? begin … safe_execution! { @protocol.run!(request) } assign_parsed_attributes! http_request_message = build_http_request_message … end end @client.close end end !QSPUPDPM5PZDPM1SPUPDPM MJCUPZDPMQSPYZSC 5PZDPM1SPYZTUBSU"QQMZUIFQSPUPDPM &YFDVUF5PZDPM1SPUPDPMSVO  UIFOUIFQSPUPDPMXJMMCFBQQMJFE UPUIFSFRVFTUNFTTBHF
  103. NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSVO NFTTBHF  !SFRVFTU@NFTTBHFNFTTBHFDIPNQ SFUVSOVOMFTT CMPDL!EF fi

    OFNFOUT<!QSPUPDPM@OBNF>  JOTUBODF@FYFD !SFRVFTU@NFTTBHF CMPDL  FOE ʜ FOE FOE 5PZDPM1SPUPDPMSVO"QQMZUIFQSPUPDPM MJCUPZDPMQSPUPDPMSC 5PZDPM1SPUPDPMSVO
  104. NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSVO NFTTBHF  !SFRVFTU@NFTTBHFNFTTBHFDIPNQ SFUVSOVOMFTT CMPDL!EF fi

    OFNFOUT<!QSPUPDPM@OBNF>  JOTUBODF@FYFD !SFRVFTU@NFTTBHF CMPDL  FOE ʜ FOE FOE 5PZDPM1SPYZTUBSU"QQMZUIFQSPUPDPM MJCUPZDPMQSPUPDPMSC 'JOEUIFQSPUPDPMEF fi OJUJPO DPSSFTQPOEJOHUP!QSPUPDPM@OBNF JO!EF fi OFNFOUTIBTI
  105. NPEVMF5PZDPM DMBTT1SPUPDPM ʜ EFGTFMGSVO NFTTBHF  !SFRVFTU@NFTTBHFNFTTBHFDIPNQ SFUVSOVOMFTT CMPDL!EF fi

    OFNFOUT<!QSPUPDPM@OBNF>  JOTUBODF@FYFD !SFRVFTU@NFTTBHF CMPDL  FOE ʜ FOE FOE 5PZDPM1SPYZTUBSU"QQMZUIFQSPUPDPM MJCUPZDPMQSPUPDPMSC &YFDVUFUIJTCMPDLJOJOTUBODF@FYFD 5IFSFRVFTUNFTTBHFQBTTFEBT UIFBSHVNFOUXJMMCFUSBOTMBUFE
  106. def start … loop do trap(:INT) { shutdown } @client

    = @proxy.accept while !@client.closed? && !@client.eof? begin … safe_execution! { @protocol.run!(request) } assign_parsed_attributes! http_request_message = build_http_request_message … end end @client.close end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZTUBSU#VJMEBSFRVFTUNFTTBHF 5IFOFYFDVUF5PZDPM1SPYZBTTJHO@QBSTFE@BUUSJCVUFT BOE5PZDPM1SPYZCVJME@IUUQ@SFRVFTU@NFTTBHFUP CVJMEB)551GPSNBUUFESFRVFTUNFTTBHF
  107. NPEVMF5PZDPM DMBTT1SPUPDPM … def assign_parsed_attibutes @request_method = @protocol.request_method @path =

    @protocol.request_path @query = @protocol.query @input = @protocol.input end … end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZBTTJHO@QBSTFE@BUUSJCVUFT#VJMEBSFRVFTUNFTTBHF 5PZDPM1SPYZBTTJHO@QBSTFE@BUUSJCVUFTFYUSBDUT WBMVFTTUPSFEJO5PZDPM1SPUPDPMDMBTT "OEBTTJHOTUIFNUPFBDIJOTUBODFWBSJBCMFT
  108. NPEVMF5PZDPM DMBTT1SPUPDPM … def build_http_request_message request_message = "#{request_line}#{request_header}\r\n" request_message +=

    @input if @input request_message end … end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZCVJME@IUUQ@SFRVFTU@NFTTBHF#VJMEBSFRVFTUNFTTBHF 5PZDPM1SPYZCVJME@IUUQ@SFRVFTU@NFTTBHFCVJMET B)551GPSNBUUFESFRVFTUNFTTBHF VTJOHUIPTFJOTUBODFWBSJBCMFT
  109. NPEVMF5PZDPM DMBTT1SPUPDPM … def build_http_request_message request_message = "#{request_line}#{request_header}\r\n" request_message +=

    @input if @input request_message end … end end MJCUPZDPMQSPYZSC 5PZDPM1SPYZCVJME@IUUQ@SFRVFTU@NFTTBHF#VJMEBSFRVFTUNFTTBHF FH 5PZDPM1SPYZCVJME@IUUQ@SFRVFTU@NFTTBHFSFUVSOT BWBMVFMJLF (&5QPTUT)551aSaO$POUFOU-FOHUIaSaOaSaO "#{@request_method} #{request_path} HTTP/1.1\r\n" “#{@path}#{"?#{@query}" if @query && !@query.empty?}" "Content-Length: #{@input&.bytesize || 0}\r\n"
  110. "EWBODFEQSPUPDPMEF fi OJUJPOT

  111. -FUTDPOTJEFSTPNFNPSF BEWBODFEEF fi OJUJPOTPGQSPUPDPM

  112. -FU`TDPOTJEFSBHBJO3VCZMJLFQSPUPDPM XFKVTUEF fi OFE 5IJTQSPUPDPMUBLFTB3VCZMJLFTZOUBY SFRVFTUNFTTBHFBTBTUSJOH  QBSTFTJU BOEUSBOTMBUFTJUJOUP B)551GPSNBUUFESFRVFTUNFTTBHF

  113. 'PSFYBNQMF  JGZPVSFDFJWFBTUSJOH lbQPTUT`HFUz BTBSFRVFTUNFTTBHF XJUIUIF3VCZMJLFQSPUPDPMʜ

  114. 3VCZMJLFQSPUPDPM1BSTJOHUIFTUSJOHlbQPTUT`HFUz Toycol::Protocol.de fi ne(:rubylike) do request.path do |message| /['"](?<path>.+)['"]/.match(message)[:path] end

    request.http_method do |message| case /\.(?<method>[A-z]+)/.match(message)&.captures&. fi rst when "get" then "GET" else "OTHER" end end … end  6TFS 1SPUPDPM fi MFSVCZMJLF 1BSTFUIFTUSJOHlbQPTUTHFUzUPHFUBSFRVFTUQBUI BOESFRVFTUNFUIPE TUPSFUIFNJO5PZDPM1SPUPDPM DMBTT BOEUSBOTMBUFUIFNUP)551GPSNBU lQPTUTzBTBSFRVFTUQBUI l(&5zBTBSFRVFTUNFUIPE
  115. 8IBUBCPVUBQSPUPDPMUIBUDBOSFDFJWF BOEFYFDVUFUIFSFRVFTUNFTTBHF BTBOBDUVBM3VCZTDSJQU  SBUIFSUIBOBTBTUSJOH

  116. 'PSFYBNQMF  JGZPVSFDFJWFB3VCZTDSJQU bQPTUT`HFU UIBUDBMMTBNFUIPEHFU POB4USJOHPCKFDUbQPTUT` BTBSFRVFTUNFTTBHFʜ

  117. Toycol::Protocol.de fi ne(:ruby) do |message| using Module.new { re fi

    ne String do def get Toycol::Protocol.request.path { self } Toycol::Protocol.request.http_method { "GET" } end end } instance_eval message end 3VCZQSPUPDPM  6TFS 1SPUPDPM fi MFSVCZ 5IJTJTBEF fi OJUJPOPG3VCZQSPUPDPM UIBUJTCFBCMFUPFYFDVUF BSFRVFTUNFTTBHFBTB3VCZTDSJQU 3VCZQSPUPDPM
  118. 3VCZQSPUPDPM Toycol::Protocol.de fi ne(:ruby) do |message| using Module.new { re

    fi ne String do def get Toycol::Protocol.request.path { self } Toycol::Protocol.request.http_method { "GET" } end end } instance_eval message end  6TFS 1SPUPDPM fi MFSVCZ "EEHFUNFUIPEUP4USJOHDMBTTUPCFBCMF UPDBMMJUGPSlQPTUTzBTB4USJOHPCKFDU
  119. Toycol::Protocol.de fi ne(:ruby) do |message| using Module.new { re fi

    ne String do def get Toycol::Protocol.request.path { self } Toycol::Protocol.request.http_method { "GET" } end end } instance_eval message end 3VCZQSPUPDPM  6TFS 1SPUPDPM fi MFSVCZ 5IFOVTFJOTUBODF@FWBMUPFYFDVUF UIFSFDFJWFESFRVFTUNFTTBHF lQPTUTzHFU  BTB3VCZTDSJQU lQPTUTzHFU
  120. )PXFWFS BTZPVDBOTFF UIJTMPHJD DPOUBJOTBOJOKFDUJPOWVMOFSBCJMJUZ 5IFSFJTOPXBZUPQSFWFOU UIFFYFDVUJPOPGBEBOHFSPVTTDSJQU XIFOJUJTSFDFJWFE  TVDIBTTZTUFN lSNSGz

    
  121. 6OGPSUVOBUFMZ XFEPOULOPX XIBULJOEPGNFTTBHFT UIFDMJFOUXJMMTFOEUPUIFTFSWFS 5IFSFGPSF 5PZDPMEPFTOPUBMMPXUP XSJUFDPEFTDPOUBJOJOHTVDI WVMOFSBCJMJUJFTJO1SPUPDPM fi MF

  122. def start … while !@client.closed? && !@client.eof? begin request =

    @client.readpartial(CHUNK_SIZE) logger “Received message: #{request.inspect.chomp}” safe_execution! { @protocol.run!(request) } … end end … end MJCUPZDPMQSPYZSC 4BGFFYFDVUJPOPGUIFQSPUPDPM 5PZDPM1SPUPDPMSVOJTFYFDVUFEJOTJEF BCMPDLPGTBGF@FYFDVUJPOUPFOTVSFUIBU OPWVMOFSBCMFEF fi OJUJPOTBSFJO1SPUPDPM fi MFT
  123. def safe_execution!(&block) safe_executionable_tp.enable(&block) end def safe_executionable_tp @safe_executionable_tp ||= TracePoint.new(:script_compiled) do

    |tp| if tp.binding.receiver == Protocol \ && tp.method_id.to_s.match? /(.*eval|.*exec|`.+|%x\(|system|open|require|load)/ raise UnauthorizeError, … end end end 5PZDPM)FMQFSTBGF@FYFDVUJPO MJCUPZDPMIFMQFSSC 5PZDPM)FMQFSTBGF@FYFDVUJPO  "OE5PZDPM)FMQFSTBGF@FYFDVUJPOBCMF@UQ UIBUTBGF@FYFDVUJPOVTFTJOUFSOBMMZ
  124. def safe_execution!(&block) safe_executionable_tp.enable(&block) end def safe_executionable_tp @safe_executionable_tp ||= TracePoint.new(:script_compiled) do

    |tp| if tp.binding.receiver == Protocol \ && tp.method_id.to_s.match? /(.*eval|.*exec|`.+|%x\(|system|open|require|load)/ raise UnauthorizeError, … end end end 5PZDPM)FMQFSTBGF@FYFDVUJPO MJCUPZDPMIFMQFSSC 6TF5SBDF1PJOUUPEFUFDUJGBOZEBOHFSPVT NFUIPETBSFCFJOHFYFDVUFEUIBUDPVME DBVTFJOKFDUJPOWVMOFSBCJMJUJFTɹ
  125. def safe_execution!(&block) safe_executionable_tp.enable(&block) end def safe_executionable_tp @safe_executionable_tp ||= TracePoint.new(:script_compiled) do

    |tp| if tp.binding.receiver == Protocol \ && tp.method_id.to_s.match? /(.*eval|.*exec|`.+|%x\(|system|open|require|load)/ raise UnauthorizeError, … end end end 5PZDPM)FMQFSTBGF@FYFDVUJPO MJCUPZDPMIFMQFSSC 5BSHFUNFUIPETBSFJODMVEJOHFWBMPSFYFD JOUIBUOBNF FYFDVUJOHFYUFSOBMDPNNBOET  BOEMPBEJOH fi MFTGSPNPVUTJEF
  126. 4P XFOFFEUPDPOTJEFSPG BNPSFTFDVSFXBZUPEF fi OFBQSPUPDPM UPSVOUIFBQQMJDBUJPO XJUI3VCZTDSJQUTBTSFRVFTUNFTTBHFT

  127. )PXBCPVUUIJT

  128. 'PSFYBNQMF BTCFGPSF  JGZPVSFDFJWFB3VCZTDSJQU bQPTUT`HFU UIBUDBMMTBNFUIPEHFU POB4USJOHPCKFDUbQPTUT` BTBSFRVFTUNFTTBHFʜ

  129. 4BGF3VCZQSPUPDPM module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby)

    do |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end  6TFS 1SPUPDPM fi MFTBGF@SVCZ 4BGF3VCZQSPUPDPM
  130. module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby) do

    |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end 4BGF3VCZQSPUPDPM"EEBQBSTFS3FHFY  6TFS 1SPUPDPM fi MFTBGF@SVCZ 1SFQBSFBSFHVMBSFYQSFTTJPOUPQBSTF UIFSFRVFTUNFTTBHF
  131. module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby) do

    |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end 6TJOHUIJTSFHVMBSFYQSFTTJPO HFUUXPTUSJOHT ᶃQBUIlQPTUTz "SFRVFTUQBUI  ᶄNFUIPElHFUz "NFUIPEOBNFUPCFDBMMFEGPSUIFSFRVFTUQBUI 4BGF3VCZQSPUPDPM(FUBSFRVFTUQBUINFUIPE  6TFS 1SPUPDPM fi MFTBGF@SVCZ ᶃ ᶄ
  132. module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby) do

    |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end 1SPUPDPM fi MFTBGF@SVCZ 4BGF3VCZQSPUPDPM4UPSFUIFSFRVFTUQBUI 4UPSFlQPTUTzBTBSFRVFTUQBUI JO5PZDPM1SPUPDPMSFRVFTUQBUI
  133. module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby) do

    |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end 1SPUPDPM fi MFTBGF@SVCZ 4BGF3VCZQSPUPDPM3FUSJFWFUIFSFRVFTUQBUI 5IFO 5PZDPM1SPUPDPMSFRVFTU@QBUI SFUVSOTB4USJOHPCKFDUlQPTUTz KVTUTUPSFEBTBSFRVFTUQBUI
  134. module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby) do

    |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end 1SPUPDPM fi MFTBGF@SVCZ 4BGF3VCZQSPUPDPM"EEHFUUP4USJOHDMBTT "EEHFUNFUIPEUPUIF4USJOHDMBTT 5IJTJTUPTUPSFBTUSJOH(&5JO 5PZDPM1SPUPDPMSFRVFTUIUUQ@NFUIPE
  135. module SafeRuby PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/ end Toycol::Protocol.de fi ne(:safe_ruby) do

    |message| using Module.new { re fi ne String do def get Toycol::Protocol.request.http_method { “GET" } end end } path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] } request.path { path } request_path.public_send(method) end 1SPUPDPM fi MFTBGF@SVCZ 4BGF3VCZQSPUPDPM$BMMHFUGPSlQPTUTz $BMMUIFHFUNFUIPEPOUIF4USJOHPCKFDUlQPTUTz &YFDVUJOHUIJTMJOFXJMMHJWFZPVUIFTBNFSFTVMU BTFYFDVUJOHUIFSFRVFTUNFTTBHFlQPTUTzHFU
  136. -FUTUSZUIJTPVU

  137. require "rack" require "toycol" Toycol::Protocol.use(:safe_ruby) class App def call(env) case

    env["REQUEST_METHOD"] when “GET” [200, { "Content-Type" => "text/html" }, [“User<1> I love Ruby!\n”, “User<2> I love RubyKaigi!\n”]] end end end run App.new )FSFJTBOBQQMJDBUJPO fi MFGPSUIJTQSPKFDU  6TFS DPO fi H@TBGF@SVCZSV 3VO4BGF3VCZQSPUPDPM
  138. 4FOEBSFRVFTUNFTTBHFCZ4BGF3VCZQSPUPDPM 4UBSUVQUIFTFSWFST 3VO4BGF3VCZQSPUPDPM

  139. *UXPSLFE 3VO4BGF3VCZQSPUPDPM

  140. /PX MFUTUSZ4BGF3VCZQSPUPDPMJO TPNFBQQMJDBUJPOTCVJMUXJUIPUIFSXBZT

  141. 8IBUBCPVUBOBQQMJDBUJPOCVJMUXJUI 4JOBUSB

  142. require “sinatra/base" require "toycol" Toycol::Protocol.use(:safe_ruby) class App < Sinatra::Base get

    “/posts” do [“User<1> I love Ruby!\n”, “User<2> I love RubyKaigi!\n”] end run! if app_ fi le == $PROGRAM_NAME end  6TFS BQQSC 3VO4BGF3VCZQSPUPDPMXJUIB4JOBUSBBQQ 4JOBUSBBQQGPS4BGF3VCZQSPUPDPM
  143. 3VO4BGF3VCZQSPUPDPMXJUIB4JOBUSBBQQ 4FOEBSFRVFTUNFTTBHFCZ4BGF3VCZQSPUPDPM 4UBSUVQUIFTFSWFST

  144. "HBJO JUXPSLFE 3VO4BGF3VCZQSPUPDPMXJUIB4JOBUSBBQQ

  145. 'JOBMMZ MFUTHFUB3BJMTBQQMJDBUJPO SVOOJOHXJUIPVS4BGF3VCZQSPUPDPM

  146. require_relative “con fi g/environment" require "toycol" Toycol::Protocol.use(:safe_ruby) run! Rails.application Rails.application.load_server

     6TFS DPO fi HSV 4BGF3VCZQSPUPDPMXJUIB3BJMTBQQ "3BJMTBQQGPS4BGF3VCZQSPUPDPM  SBJMTHFOFSBUFTDB ff PMEQPTUT DPNNBOEIBTCFFOFYFDVUFE
  147. 4BGF3VCZQSPUPDPMXJUIB3BJMTBQQ 4FOEBSFRVFTUNFTTBHFCZ4BGF3VCZQSPUPDPM 4UBSUVQUIFTFSWFST

  148. "OEBHBJO JUXPSLFE XJUIMPUTPGIFBEFST 4BGF3VCZQSPUPDPMXJUIB3BJMTBQQ ʜ

  149. :PVDBOBMTPTFFUIFCPEZ 4BGF3VCZQSPUPDPMXJUIB3BJMTBQQ

  150. "TZPVDBOTFF XFXFSFBCMFUPSVO BWBSJFUZPGBQQMJDBUJPOT XJUI4BGF3VCZQSPUPDPM

  151. *OBEEJUJPO  ZPVDBO fi OEFYBNQMFTPG HFUUJOHRVFSZQBSBNFUFST BOEIBOEMJOH1045NFUIPET JOUIF5PZDPMSFQPTJUPSZ 1MFBTFFOKPZUIFNJGZPVMJLF IUUQTHJUIVCDPNTIJPJNNUPZDPMCMPCNBJOFYBNQMFT

  152. "OETQFDJBMUIBOLTUP !PLVSBNBTBGVNJ !VE[VSB'VLVPLBSC 5IBOLZPVGPSZPVSBUUFOUJPO