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

PROXYGEN

Fadis
October 10, 2015

 PROXYGEN

facebookが作ったC++のWebフレームワーク Proxygen の使い方を解説します

Fadis

October 10, 2015
Tweet

More Decks by Fadis

Other Decks in Technology

Transcript

  1. PROXYGEN
    NAOMASA MATSUBAYASHI

    View Slide

  2. @fadis_
    Twitter
    Github
    Speakerdeck
    https://speakerdeck.com/fadis
    https://github.com/Fadis/
    NAOMASA MATSUBAYASHI
    ීஈ͸େࡕͰήʔϜ࡞ͬͯ·͢

    View Slide

  3. C++Ͱ
    WebΞϓϦέʔγϣϯͷαʔό
    Λॻ͖ͨ͘ͳͬͨΒ

    View Slide

  4. ࣗྗͰHTTPΛ஻Δ?
    ΫϥΠΞϯτ αʔό
    HTTP/1.0 200 OK!
    Date: Mon, 21 Sep 2015 11:40:04 GMT!
    Content-Length: 14!
    !
    Hello, World!
    GET / HTTP/1.0

    View Slide

  5. ΞοϋΠɺεϛϚηϯʜ
    ΫϥΠΞϯτ αʔό
    GET / HTTP/1.1!
    Host: example.com!
    Connection: Upgrade, HTTP2-Settings!
    Upgrade: h2c 1!
    HTTP2-Settings: …
    ਖ਼͘͠HTTPͰձ࿩͢Δͷ͸೉͍͠

    View Slide

  6. ਖ਼͍͠HTTPΛ஻Δ෦෼ͱ
    ΞϓϦέʔγϣϯຊମΛ෼཭͠Α͏
    WebϑϨʔϜϫʔΫ

    View Slide

  7. C++Ͱ࢖͑ΔWebϑϨʔϜϫʔΫ
    CppCMS
    cpp-netlib
    IUUQDQQDNTDPN
    IUUQDQQOFUMJCPSH
    Proxygen
    IUUQTHJUIVCDPNGBDFCPPLQSPYZHFO
    QHttpServer
    IUUQTHJUIVCDPNOJLIJMNRIUUQTFSWFS

    View Slide

  8. IUUQTDPEFGBDFCPPLDPNQPTUT

    View Slide

  9. Facebook͕
    ಉࣾͷαʔϏεΛ࣮૷͢Δҝʹ࡞ͬͨWebϑϨʔϜϫʔΫ
    2014೥11݄ʹ3৚߲BSDϥΠηϯεͰ
    ΦʔϓϯιʔεԽ͞Εͨ
    HTTP/1.x SPDY/2 SPDY/3.x HPACK TLS౳ʹରԠ
    HTTP/2ͷαϙʔτ͸ݱࡏਐߦத

    View Slide

  10. Hello, World!Λฦ͢
    WebαʔόΛॻ͍ͯΈΑ͏

    View Slide

  11. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  12. };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    ΫϥΠΞϯτ͔ΒͷΞΫηεΛड͚෇͚Δ
    ΞυϨεͱϙʔτ൪߸ͷϦετ
    ϓϩτίϧʹHTTPΛࢦఆ
    ໊લղܾΛڐՄ

    View Slide

  13. };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    ϦΫΤετϋϯυϥͷfactoryΛొ࿥
    HTTPServer͸઀ଓΛड͚෇͚Δͱ
    ొ࿥͞ΕͨfactoryͰϦΫΤετϋϯυϥΛੜ੒
    Ҏޙϔομ΍ຊจ͕ಧ͘ͱ
    ϦΫΤετϋϯυϥͷϝϯό͕ݺ͹ΕΔ
    HTTPServerͷΠϯελϯεΛ࡞Δ

    View Slide

  14. void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    ઀ଓΛ଴ͪड͚ΔΞυϨεΛࢦఆ
    start()ͰHTTPαʔόΛىಈ
    start()͸αʔό͕ఀࢭ͢Δ·ͰฦΒͳ͍

    View Slide

  15. proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    αʔόىಈ࣌ʹߦ͏ॲཧ
    ऴྃ࣌ʹߦ͏ॲཧ
    RequestHandlerFactoryΛܧঝ
    ϦΫΤετ͕དྷͨ࣌ʹߦ͏ॲཧ
    ϦΫΤετϋϯυϥϑΝΫτϦ

    View Slide

  16. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    ϦΫΤετϋϯυϥ
    RequestHandlerΛܧঝ

    View Slide

  17. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    ϦΫΤετϋϯυϥ
    onRequest
    HTTPϦΫΤετͷ
    ϔομ͕ಧ͍ͨ࣌఺Ͱݺ͹ΕΔ

    View Slide

  18. HTTPϦΫΤετͷߏ଄
    ϔομ
    ຊจ
    &OEPG.FTTBHF
    ϦΫΤετͷछྨ΍
    ෇ਵ͢Δύϥϝλ
    POSTͰαʔόʹૹΔ
    σʔλ౳
    ຊจͷऴྃΛදۭ͢ߦ

    View Slide

  19. ϔομ
    ຊจ
    &OEPG.FTTBHF
    ͜͜·Ͱड৴ͨ͠Β
    onRequest

    View Slide

  20. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    ϦΫΤετϋϯυϥ
    onEOM
    HTTPϦΫΤετΛ
    શͯड৴ͨ࣌͠఺Ͱݺ͹ΕΔ

    View Slide

  21. ϔομ
    ຊจ
    &OEPG.FTTBHF
    ͜͜·Ͱड৴ͨ͠Β
    onEOM

    View Slide

  22. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    ϦΫΤετϋϯυϥ
    onBody
    HTTPϦΫΤετͷ
    ຊจΛड৴ͨ࣌͠఺Ͱݺ͹ΕΔ

    View Slide

  23. ϔομ
    ຊจ
    &OEPG.FTTBHF
    ͜͜·Ͱड৴ͨ͠Β
    onBody
    ͦΕͬͯ
    onEOMͱ
    ҰॹͳͷͰ͸?
    ͜͜·Ͱड৴ͨ͠Β
    onEOM

    View Slide

  24. ϔομ
    &OEPG.FTTBHF
    શମͷ௕͕͞෼͔Βͳͯ͘΋
    ຊจΛૹΓ࢝ΊΔࣄ͕Ͱ͖Δ
    νϟϯΫ
    νϟϯΫ
    νϟϯΫ
    νϟϯΫసૹ
    HTTPͷຊจ͸
    ෳ਺ʹ෼ׂͯ͠
    ૹΔ͜ͱ͕Ͱ͖Δ
    ϔομʹຊจͷ௕͞Λ
    ॻ͘୅ΘΓʹ
    νϟϯΫʹνϟϯΫͷ௕͞Λॻ͘

    View Slide

  25. ϔομ
    &OEPG.FTTBHF
    νϟϯΫ
    νϟϯΫ
    νϟϯΫ ͜͜·Ͱड৴ͨ͠Β
    onBody
    ͜͜΋
    ͬͪ͜΋
    onBody͸ෳ਺ճݺ͹ΕΔՄೳੑ͕͋Δ

    View Slide

  26. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    ϦΫΤετϋϯυϥ
    onUpgrade
    ϦΫΤετͷ಺༰͕
    UPGRADEͩͬͨ৔߹ʹݺ͹ΕΔ

    View Slide

  27. UPGRADE
    HTTP/1.1Ͱ௥Ճ͞Εͨ
    ผͷϓϩτίϧʹ੾Γସ͑ΔҝͷϦΫΤετ
    ࠓͷͱ͜Ζ
    WebSocketͱHTTP/2(ฏจ൛)͕࢖͍ͬͯΔ

    View Slide

  28. void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    ϦΫΤετϋϯυϥ
    requestComplete
    ΫϥΠΞϯτʹϨεϙϯεΛૹΓ੾Δͱݺ͹ΕΔ
    onError
    ΫϥΠΞϯτଆ͔Β੾அ͞ΕΔ౳
    Ϩεϙϯεͷૹ৴׬ྃ·Ͱ౸ୡग़དྷͳ͘ͳͬͨΒ
    ݺ͹ΕΔ

    View Slide

  29. void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    ϦΫΤετϋϯυϥ
    ͜ΕҎ߱ϦΫΤετϋϯυϥ͕
    ݺ͹ΕΔࣄ͸ແ͍ͨΊɺ͜͜Ͱࣗ਎Λdelete͢Δ
    ໌ࣔతͳdelete͸େมΠέͯͳ͍͕
    Proxygen͕ੜϙΠϯλ͔͠ѲΕͳ͍ͷͰ
    ͜͏͢Δ͔͠ͳ͍

    View Slide

  30. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" ).body( "Hello, World!" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    Hello,World!ͷྫͰ΍͍ͬͯΔࣄ
    ΫϥΠΞϯτ͕ϦΫΤετΛૹΓ੾ͬͨΒ
    ResponseBuilderΛ࡞ͬͯ
    εςʔλείʔυʹ200 OKΛࢦఆͯ͠
    ຊจʹ”Hello, World!”
    ࠷ޙʹsendWithEOM()Ͱ
    ϨεϙϯεΛऴྃͤ͞Δ

    View Slide

  31. $ telnet www41050u.sakura.ne.jp 8080
    Trying xxx.xxx.xxx.xxx...
    Connected to www41050u.sakura.ne.jp.
    Escape character is '^]'.
    GET / HTTP/1.1
    !
    HTTP/1.1 200 OK
    Date: Wed, 30 Sep 2015 17:11:43 GMT
    Connection: keep-alive
    Content-Length: 13
    !
    Hello, World!
    telnetͰ઀ଓͯ͠ΈΑ͏
    Ϩεϙϯε͕དྷͨ!

    View Slide

  32. tx.body( "Hello, World!" ).sendWithEOM();
    tx.body( "hoge" ).send();!
    tx.body( "fuga" ).send();!
    tx.body( "piyo" ).send();!
    tx.body( "foo" ).sendWithEOM();
    send()Λ࢖͏ͱνϟϯΫసૹʹͳΔ

    View Slide

  33. send()Λ࢖͏ͱνϟϯΫసૹʹͳΔ
    $ telnet www41050u.sakura.ne.jp 8080!
    Trying xxx.xxx.xxx.xxx….!
    Connected to www41050u.sakura.ne.jp.!
    Escape character is '^]'.!
    GET / HTTP/1.1!
    !
    HTTP/1.1 200 OK!
    Transfer-Encoding: chunked!
    Date: Wed, 30 Sep 2015 16:39:34 GMT!
    Connection: keep-alive!
    !
    4!
    hoge!
    4!
    fuga!
    4!
    piyo!
    3!
    foo!
    0!
    !
    νϟϯΫ

    View Slide

  34. public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" );!
    tx.header( "Content-Type", "text/plain" );!
    tx.body( "Hello, World!” ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    Ϩεϙϯεϔομ
    ResponseBuilderͷheader()Λ࢖ͬͯ
    ϨεϙϯεϔομΛ௥Ճ͢Δ
    Content-Type: text/plain Λ௥Ճ

    View Slide

  35. $ telnet www41050u.sakura.ne.jp 8080!
    Trying xxx.xxx.xxx.xxx...!
    Connected to www41050u.sakura.ne.jp.!
    Escape character is '^]'.!
    GET / HTTP/1.1!
    !
    HTTP/1.1 200 OK!
    Content-Type: text/plain!
    Date: Thu, 01 Oct 2015 15:04:42 GMT!
    Connection: keep-alive!
    Content-Length: 13!
    !
    Hello, World!
    Ϩεϙϯεϔομ
    Content-Type

    View Slide

  36. ѹॖ
    HTTP͸ϨεϙϯεͷຊจΛ
    deflate΍gzipͰѹॖͯ͠ૹΔࣄ͕ग़དྷΔ
    Proxygenʹ͸
    gzipʹΑΔѹॖ͕࠷ॳ͔Β༻ҙ͞Ε͍ͯΔ

    View Slide

  37. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" );!
    tx.header( "Content-Type", "text/plain" );!
    tx.body( std::string( 10000, '[' ) ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.enableContentCompression = true;!
    options.contentCompressionMinimumSize = 5;!
    options.contentCompressionLevel = 4;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  38. public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {}!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    tx.status( 200, "OK" );!
    tx.header( "Content-Type", "text/plain" );!
    tx.body( std::string( 10000, '[' ) ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    10000bytesͷ’[’
    େ͖ͳຊจͩ!ѹॖ͠Α͏!

    View Slide

  39. ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.enableContentCompression = true;!
    options.contentCompressionMinimumSize = 5;!
    options.contentCompressionLevel = 4;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    HTTPServerOptionʹ
    ѹॖʹඞཁͳ৘ใΛઃఆ
    enableContentCompression
    ѹॖΛ༗ޮʹ͢Δ
    σϑΥϧτfalse

    View Slide

  40. ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.enableContentCompression = true;!
    options.contentCompressionMinimumSize = 5;!
    options.contentCompressionLevel = 4;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    HTTPServerOptionʹ
    ѹॖʹඞཁͳ৘ใΛઃఆ
    contentCompressionMinimumSize
    ͜ͷαΠζະຬͷຊจ͸ѹॖ͠ͳ͍
    σϑΥϧτ1000

    View Slide

  41. ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) { !
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.enableContentCompression = true;!
    options.contentCompressionMinimumSize = 5;!
    options.contentCompressionLevel = 4;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    HTTPServerOptionʹ
    ѹॖʹඞཁͳ৘ใΛઃఆ
    contentCompressionLevel
    zlibͷѹॖϨϕϧ
    σϑΥϧτ-1
    zlibʹѹॖϨϕϧ-1Λ౉͢ͱѹॖ͕ࣦഊ͠
    αʔό͕Τϥʔऴྃ͢Δ(ͭ·Γઃఆඞਢ)

    View Slide

  42. proxygen::HTTPServer::Protocol::HTTP!
    }}; !
    proxygen::HTTPServerOptions options;!
    options.enableContentCompression = true;!
    options.contentCompressionMinimumSize = 5;!
    options.contentCompressionLevel = 4;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    contentCompressionTypes
    ͜͜Ͱ͸σϑΥϧτͷ··ʹ͍ͯ͠ΔΦϓγϣϯ
    ѹॖ͢ΔContent-Type
    σϑΥϧτ͸
    ”application/javascript”,”application/json","application/x-javascript",
    “application/xhtml+xml","application/xml","application/xml+rss",
    “text/css","text/html","text/javascript","text/plain","text/xml"
    Content-Type͕͜ΕΒʹ߹க͢Δ৔߹ͷΈ
    ѹॖΛߦ͏

    View Slide

  43. $ telnet www41050u.sakura.ne.jp 8080
    Trying xxx.xxx.xxx.xxx...
    Connected to www41050u.sakura.ne.jp.
    Escape character is '^]'.
    GET / HTTP/1.1
    !
    HTTP/1.1 200 OK
    Content-Type: text/plain
    Date: Thu, 01 Oct 2015 16:13:37 GMT
    Connection: keep-alive
    Content-Length: 10000
    !
    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[(ҎԼུ)
    ಛʹԿ΋ࢦఆͤͣʹGET

    View Slide

  44. $ telnet www41050u.sakura.ne.jp 8080!
    Trying xxx.xxx.xxx.xxx...!
    Connected to www41050u.sakura.ne.jp.!
    Escape character is '^]'.!
    GET / HTTP/1.1!
    Accept-Encoding: gzip !
    !
    HTTP/1.1 200 OK!
    Content-Type: text/plain!
    Content-Encoding: gzip!
    Date: Thu, 01 Oct 2015 16:16:56 GMT!
    Connection: keep-alive!
    Content-Length: 46!
    !
    ?n@???#'
    Accept-Encoding: gzip ͰGET
    ΫϥΠΞϯτʮgzipͰѹॖͯ͠ྑ͍ʯ
    αʔόʮgzipͰѹॖͯ͋͠ΔΑʯ
    ຊจ͕gzipͰѹॖ͞Ε͍ͯΔ

    View Slide

  45. ύεʹΑͬͯҧ͏ϨεϙϯεΛฦͦ͏
    http://example.com/hoge/fuga
    ͜ͷ෦෼

    View Slide

  46. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    path = headers->getPath();!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( path == "/" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "It's a top page." ).sendWithEOM();!
    } !
    else if( path == "/foo.txt" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Foo." ).sendWithEOM();!
    } !
    else tx.status( 404, "File not found" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    private:!
    std::string path;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }};!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  47. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    path = headers->getPath();!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( path == "/" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "It's a top page." ).sendWithEOM();!
    } !
    else if( path == "/foo.txt" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Foo." ).sendWithEOM();!
    } !
    else tx.status( 404, "File not found" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    onRequestͰ౉ͬͯ͘Δ
    HTTPMessageʹύε͕ೖ͍ͬͯΔ
    HTTPMessage::getPath()Ͱ
    ύεΛจࣈྻͰऔಘ

    View Slide

  48. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    path = headers->getPath();!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( path == "/" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "It's a top page." ).sendWithEOM();!
    } !
    else if( path == "/foo.txt" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Foo." ).sendWithEOM();!
    } !
    else tx.status( 404, "File not found" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    ޙ͸onEOMͰฦ͢ίϯςϯπΛ
    ύεʹΑͬͯม͑Δ͚ͩ

    View Slide

  49. $ telnet www41050u.sakura.ne.jp 8080!
    Trying xxx.xxx.xxx.xxx...!
    Connected to www41050u.sakura.ne.jp.!
    Escape character is '^]'.!
    GET / HTTP/1.1!
    !
    HTTP/1.1 200 OK!
    Content-Type: text/plain!
    Date: Thu, 01 Oct 2015 17:38:49 GMT!
    Connection: keep-alive!
    Content-Length: 16!
    !
    It's a top page.!
    !
    GET /foo.txt HTTP/1.1!
    !
    HTTP/1.1 200 OK!
    Content-Type: text/plain!
    Date: Thu, 01 Oct 2015 17:39:03 GMT!
    Connection: keep-alive!
    Content-Length: 4!
    !
    Foo.
    ύεʹΑͬͯ
    ҟͳΔ
    Ϩεϙϯε

    View Slide

  50. http://example.com/hoge/fuga?piyo=1
    ͜ͷ෦෼
    ΫΤϦʹΑͬͯҧ͏ϨεϙϯεΛฦͦ͏

    View Slide

  51. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    arg = headers->getDecodedQueryParam( "hoge" );!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( arg == "fuga" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Fuga." ).sendWithEOM();!
    } !
    else if( arg == "foo" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Foo." ).sendWithEOM();!
    } !
    else tx.status( 400, "Bad Request" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    private:!
    std::string arg;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }};!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  52. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    arg = headers->getDecodedQueryParam( "hoge" );!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( arg == "fuga" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Fuga." ).sendWithEOM();!
    } !
    else if( arg == "foo" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Foo." ).sendWithEOM();!
    } !
    else tx.status( 400, "Bad Request" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    ΫΤϦ΋HTTPMessageʹೖ͍ͬͯΔ
    HTTPMessage::getDecodedQueryParam()Ͱ
    ஋ΛจࣈྻͰऔಘ

    View Slide

  53. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    arg = headers->getDecodedQueryParam( "hoge" );!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( arg == "fuga" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Fuga." ).sendWithEOM();!
    } !
    else if( arg == "foo" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Foo." ).sendWithEOM();!
    } !
    else tx.status( 400, "Bad Request" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    ޙ͸onEOMͰฦ͢ίϯςϯπΛ
    ஋ʹΑͬͯม͑Δ͚ͩ

    View Slide

  54. $ telnet www41050u.sakura.ne.jp 8080!
    Trying xxx.xxx.xxx.xxx...!
    Connected to www41050u.sakura.ne.jp.!
    Escape character is '^]'.!
    GET / HTTP/1.1!
    !
    HTTP/1.1 400 Bad Request!
    Date: Sat, 03 Oct 2015 05:46:54 GMT!
    Connection: keep-alive!
    Content-Length: 0!
    !
    GET /?hoge=fuga HTTP/1.1!
    !
    HTTP/1.1 200 OK!
    Content-Type: text/plain!
    Date: Sat, 03 Oct 2015 05:47:12 GMT!
    Connection: keep-alive!
    Content-Length: 5!
    !
    Fuga.
    ΫΤϦʹΑͬͯ
    ҟͳΔ
    Ϩεϙϯε

    View Slide

  55. http://example.com/
    ͜ͷ෦෼
    ϗετ໊ʹΑͬͯҧ͏ϨεϙϯεΛฦͦ͏
    ॴҦ໊લϕʔεόʔνϟϧϗετ

    View Slide

  56. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    host = headers->getHeaders().getSingleOrEmpty( "Host" );!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( host == "www41050u.sakura.ne.jp:8080" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "First webpage\n" ).sendWithEOM();!
    } !
    else if( host == "localhost:8080" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Second webpage\n" ).sendWithEOM();!
    } !
    else tx.status( 400, "Bad Request" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    private:!
    std::string host;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "localhost", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP }!
    };!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  57. std::string host;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "localhost", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP }!
    };!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    ෳ਺ͷϗετ໊͔Βͷ
    ઀ଓΛड͚෇͚ΔΑ͏ʹ͢Δ

    View Slide

  58. #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    host = headers->getHeaders().getSingleOrEmpty( "Host" );!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( host == "www41050u.sakura.ne.jp:8080" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "First webpage\n" ).sendWithEOM();!
    } !
    else if( host == "localhost:8080" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Second webpage\n" ).sendWithEOM();!
    } !
    else tx.status( 400, "Bad Request" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    ϦΫΤετϔομ͔ΒHostΛऔಘ
    HTTPMessage::getSingleOrEmpty( ϑΟʔϧυ໊ )Ͱ
    ϦΫΤετϔομʹઃఆ͞Εͨ஋Λऔಘ
    §14.23 Host
    A client MUST include a Host header field in
    all HTTP/1.1 request messages.
    http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
    HTTP/1.1Ͱ͸Host͸ඞਢͳͷͰ
    ۭจࣈྻ͕ฦͬͯདྷͨΒ400Ͱฦͯ͠OK

    View Slide

  59. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    host = headers->getHeaders().getSingleOrEmpty( "Host" );!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( host == "www41050u.sakura.ne.jp:8080" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "First webpage\n" ).sendWithEOM();!
    } !
    else if( host == "localhost:8080" ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Second webpage\n" ).sendWithEOM();!
    } !
    else tx.status( 400, "Bad Request" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    ޙ͸onEOMͰฦ͢ίϯςϯπΛ
    ஋ʹΑͬͯม͑Δ͚ͩ

    View Slide

  60. $ curl http://www41050u.sakura.ne.jp:8080/!
    First webpage!
    $ curl http://localhost:8080/
    Second webpage
    ϗετ໊ʹΑͬͯҧ͏݁Ռ͕ฦͬͯ͘Δ

    View Slide

  61. ஫ҙ
    Host͸ΫϥΠΞϯτͷࣗݾਃࠂ͔ͩΒ
    ؆୯ʹِ૷Ͱ͖Δ
    $ telnet www41050u.sakura.ne.jp 8080!
    Trying xxx.xxx.xxx.xx...!
    Connected to www41050u.sakura.ne.jp.!
    Escape character is '^]'.!
    GET / HTTP/1.1!
    Host: localhost:8080!
    !
    HTTP/1.1 200 OK!
    Content-Type: text/plain!
    Date: Sat, 03 Oct 2015 15:35:57 GMT!
    Connection: keep-alive!
    Content-Length: 15!
    !
    Second webpage
    ֎޲͖ΞυϨεͰΞΫηε
    ಺޲͖ΞυϨεΛࣗশ
    ಺޲͖ίϯςϯπ͕ฦͬͯ͠·ͬͨ!

    View Slide

  62. HTTPMessage::getClientAddress()
    ઀ଓ͖ͯͨ͠ΫϥΠΞϯτͷΞυϨεΛಘΔ
    HTTPMessage::getDstAddress()
    ઀ଓΛड͚෇͚ͨαʔόͷΞυϨεΛಘΔ
    ಛఆͷϗετҎ֎͔Β
    ΞΫηεͤͨ͘͞ͳ͍৔߹͸
    ͜ΕΒͷ৘ใΛ࢖ͬͯ·͍ͣϦΫΤετΛऽΔ

    View Slide

  63. Cookie
    ΫϥΠΞϯτ αʔό
    ʮ͓લͷID͸hogeͳʯ
    ʮhogeͷਓͰ͢ʯ
    ʮ௨ͬͯΑ͠ʯ
    ΫϥΠΞϯτʹ஋Λอଘ͓ͯ͘͠࢓૊Έ
    IPHF

    View Slide

  64. #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    const auto count_ = headers->getCookie( "count" );!
    if( count_.empty() ) count = 0;!
    else {!
    auto iter = count_.begin();!
    namespace qi = boost::spirit::qi;!
    if( !qi::parse( iter, count_.end(), qi::uint_, count ) ) !
    count = 0;!
    } !
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    namespace karma = boost::spirit::karma;!
    std::string h, b;!
    ++count;!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( !
    karma::generate(!
    std::back_inserter( h ), "count=" << karma::uint_ <";expires=Thu, 1-Jan-2030 00:00:00 GMT",!
    count!
    ) &&!
    karma::generate(!
    std::back_inserter( b ),!
    "You accessed " << karma::uint_ << " times" << karma::eol,!
    count!
    ) !
    ) {!
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.header( "Set-Cookie", h ).body( b ).sendWithEOM();!
    }!
    else tx.status( 500, "Internal Server Error" ).sendWithEOM();!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    private:!
    uint32_t count;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {{!
    folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP!
    }};!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  65. #include !
    #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    const auto count_ = headers->getCookie( "count" );!
    if( count_.empty() ) count = 0;!
    else {!
    auto iter = count_.begin();!
    namespace qi = boost::spirit::qi;!
    if( !qi::parse( iter, count_.end(), qi::uint_, count ) ) !
    count = 0;!
    } !
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    namespace karma = boost::spirit::karma;!
    std::string h, b;!
    ++count;!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( !
    karma::generate(!
    HTTPMessage::getCookie( ύϥϝλ໊ )Ͱ
    ΫϥΠΞϯτ͔Βಧ͍ͨCookieΛऔಘ

    View Slide

  66. auto iter = count_.begin();!
    namespace qi = boost::spirit::qi;!
    if( !qi::parse( iter, count_.end(), qi::uint_, count ) ) !
    count = 0;!
    } !
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    namespace karma = boost::spirit::karma;!
    std::string h, b;!
    ++count;!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( !
    karma::generate(!
    std::back_inserter( h ), "count=" << karma::uint_ <";expires=Thu, 1-Jan-2030 00:00:00 GMT",!
    count!
    ) &&!
    karma::generate(!
    std::back_inserter( b ),!
    "You accessed " << karma::uint_ << " times" << karma::eol,!
    count!
    ) !
    ) {!
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.header( "Set-Cookie", h ).body( b ).sendWithEOM();!
    }!
    CookieΛૹΔํ͸Կނ͔༻ҙ͞Ε͍ͯͳ͍ͷͰ
    ؾ߹͍Ͱ૊Έཱͯͯheader()

    View Slide

  67. $ curl -b cookie.db -c cookie.db http://www41050u.sakura.ne.jp:8080/!
    You accessed 1 times!
    $ curl -b cookie.db -c cookie.db http://www41050u.sakura.ne.jp:8080/!
    You accessed 2 times!
    $ curl -b cookie.db -c cookie.db http://www41050u.sakura.ne.jp:8080/!
    You accessed 3 times
    CookieΛ࢖ͬͯ
    Կ౓໨ͷΞΫηε͔Λௐ΂Δ

    View Slide

  68. TLS
    ΫϥΠΞϯτ αʔό
    ʮxxxxxxxʯ
    ʮxxxxxxxʯ
    ωΰγΤʔγϣϯ
    ѱҙ͋Δୈࡾऀ

    View Slide

  69. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    is_tls = headers->isSecure();!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( is_tls ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Hello, World!\n" ).sendWithEOM();!
    } !
    else {!
    tx.status( 301, "Moved Permanently" );!
    tx.header( "Location", "https://www41050u.sakura.ne.jp:8443/" );!
    tx.sendWithEOM();!
    } !
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    private:!
    bool is_tls;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8443, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    };!
    wangle::SSLContextConfig ssl;!
    ssl.isDefault = true;!
    ssl.setCertificate(!
    "./server.crt",!
    "./server.key",!
    "./password"!
    );!
    IPs.back().sslConfigs.push_back( ssl );!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }

    View Slide

  70. void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8443, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    };!
    wangle::SSLContextConfig ssl;!
    ssl.isDefault = true;!
    ssl.setCertificate(!
    "./server.crt",!
    "./server.key",!
    "./password"!
    );!
    IPs.back().sslConfigs.push_back( ssl );!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    ฏจ༻ͷϙʔτͱ͸ผʹ
    TLS༻ͷϙʔτΛ։͚Δ

    View Slide

  71. };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8443, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    };!
    wangle::SSLContextConfig ssl;!
    ssl.isDefault = true;!
    ssl.setCertificate(!
    "./server.crt",!
    "./server.key",!
    "./password"!
    );!
    IPs.back().sslConfigs.push_back( ssl );!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    SSLContextConfigΛ࡞ͬͯ
    TLS༻ͷϙʔτͷํͷsslConfigsʹ௥Ճ͢Δ
    ͜ͷSSLͷઃఆΛ࢖͏ϗετΛ
    SNIͷࢦఆ͕ແ͔ͬͨ৔߹ͷ
    σϑΥϧτʹ͢Δ
    SNI
    Server Name Indication
    Webαʔόʹෳ਺ͷ໊લͰΞΫηεग़དྷΔ࣌ʹ
    Ͳͷ໊લʹରԠ͢Δূ໌ॻ͕ཉ͍͔͠Λ
    αʔόʹ఻͑Δ࢓૊Έ
    ͜Ε͕ແ͍ͱਖ਼͍͠ূ໌ॻ͕໯͑ͳͯ͘
    TLSӽ͠ʹ໊લϕʔεόʔνϟϧϗετ͕ग़དྷͳ͍

    View Slide

  72. };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8443, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    };!
    wangle::SSLContextConfig ssl;!
    ssl.isDefault = true;!
    ssl.setCertificate(!
    "./server.crt",!
    "./server.key",!
    "./password"!
    );!
    IPs.back().sslConfigs.push_back( ssl );!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    server.start();!
    return 0;!
    }
    SSLContextConfigΛ࡞ͬͯ
    TLS༻ͷϙʔτͷํͷsslConfigsʹ௥Ճ͢Δ
    αʔόূ໌ॻ
    ൿີ伴
    ূ໌ॻͷύεϫʔυ

    View Slide

  73. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    is_tls = headers->isSecure();!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( is_tls ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Hello, World!\n" ).sendWithEOM();!
    } !
    else {!
    tx.status( 301, "Moved Permanently" );!
    tx.header( "Location", "https://www41050u.sakura.ne.jp:8443/" );!
    tx.sendWithEOM();!
    } !
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    ฏจ͔TLSܦ༝͔͸
    HTTPMessage::isSecure()Ͱ൑ผͰ͖Δ

    View Slide

  74. #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    is_tls = headers->isSecure();!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( is_tls ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Hello, World!\n" ).sendWithEOM();!
    } !
    else {!
    tx.status( 301, "Moved Permanently" );!
    tx.header( "Location", "https://www41050u.sakura.ne.jp:8443/" );!
    tx.sendWithEOM();!
    } !
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    void requestComplete() noexcept override { delete this; }!
    void onError(proxygen::ProxygenError err) noexcept override {!
    delete this;!
    }!
    private:!
    ඞਢͰ͸ͳ͍͕
    TLSͳWebαΠτʹฏจͰΞΫηε͕͋ͬͨ৔߹
    TLSܦ༝ʹϦμΠϨΫτ͢Δͷ͕
    ͓ߦّͷྑ͍WebαΠτͱ͞Ε͍ͯΔ

    View Slide

  75. $ curl -L --insecure http://www41050u.sakura.ne.jp:8080!
    Hello, World!
    ϦμΠϨΫτΛḷΔΑ͏ʹࢦࣔ
    ΦϨΦϨূ໌ॻ͚ͩͲ
    ؾʹͤͣܨ͙Α͏ࢦࣔ
    (ͪΌΜͱͨ͠ূ໌ॻΛ࢖͏৔߹͸ෆཁ)

    View Slide

  76. 13:55:02.906915 IP (tos 0x0, ttl 64, id 41559, offset 0, flags [DF],
    proto TCP (6), length 60)!
    www41050u.sakura.ne.jp.58268 > www41050u.sakura.ne.jp.http-alt:
    Flags [S], cksum 0x3c87 (incorrect -> 0x684b), seq 2056417443, win
    43690, options [mss 65495,sackOK,TS val 1027003124 ecr 0,nop,wscale
    7], length 0!
    ! 0x0000: 4500 003c a257 4000 4006 5c0c 31d4 6c58!
    ! 0x0010: 31d4 6c58 e39c 1f90 7a92 70a3 0000 0000!
    ! 0x0020: a002 aaaa 3c87 0000 0204 ffd7 0402 080a!
    ! 0x0030: 3d36 d2f4 0000 0000 0103 0307!
    13:55:02.906930 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF],
    proto TCP (6), length 60)!
    www41050u.sakura.ne.jp.http-alt > www41050u.sakura.ne.jp.58268:
    Flags [S.], cksum 0x3c87 (incorrect -> 0x908a), seq 270579556, ack
    2056417444, win 43690, options [mss 65495,sackOK,TS val 1027003124
    ecr 1027003124,nop,wscale 7], length 0!
    ! 0x0000: 4500 003c 0000 4000 4006 fe63 31d4 6c58!
    ! 0x0010: 31d4 6c58 1f90 e39c 1020 b764 7a92 70a4!
    ! 0x0020: a012 aaaa 3c87 0000 0204 ffd7 0402 080a!
    ! 0x0030: 3d36 d2f4 3d36 d2f4 0103 0307!
    13:55:02.906942 IP (tos 0x0, ttl 64, id 41560, offset 0, flags [DF],
    proto TCP (6), length 52)!
    www41050u.sakura.ne.jp.58268 > www41050u.sakura.ne.jp.http-alt:
    Flags [.], cksum 0x3c7f (incorrect -> 0x62cf), seq 1, ack 1, win 342,
    options [nop,nop,TS val 1027003124 ecr 1027003124], length 0!
    ! 0x0000: 4500 0034 a258 4000 4006 5c13 31d4 6c58!
    ͜ͷHello, World!͕ฦΔ·Ͱͷ௨৴Λ
    tcpdumpͰ؍࡯

    View Slide

  77. Flags [.], cksum 0x3c7f (incorrect -> 0x62cf), seq 1, ack 1, win 342,
    options [nop,nop,TS val 1027003124 ecr 1027003124], length 0!
    ! 0x0000: 4500 0034 a258 4000 4006 5c13 31d4 6c58!
    ! 0x0010: 31d4 6c58 e39c 1f90 7a92 70a4 1020 b765!
    ! 0x0020: 8010 0156 3c7f 0000 0101 080a 3d36 d2f4!
    ! 0x0030: 3d36 d2f4!
    13:55:02.907163 IP (tos 0x0, ttl 64, id 41561, offset 0, flags [DF],
    proto TCP (6), length 143)!
    www41050u.sakura.ne.jp.58268 > www41050u.sakura.ne.jp.http-alt:
    Flags [P.], cksum 0x3cda (incorrect -> 0x7b94), seq 1:92, ack 1, win
    342, options [nop,nop,TS val 1027003124 ecr 1027003124], length 91:
    HTTP, length: 91!
    ! GET / HTTP/1.1!
    ! Host: www41050u.sakura.ne.jp:8080!
    ! User-Agent: curl/7.43.0!
    ! Accept: */*!
    ! !
    ! 0x0000: 4500 008f a259 4000 4006 5bb7 31d4 6c58!
    ! 0x0010: 31d4 6c58 e39c 1f90 7a92 70a4 1020 b765!
    ! 0x0020: 8018 0156 3cda 0000 0101 080a 3d36 d2f4!
    ! 0x0030: 3d36 d2f4 4745 5420 2f20 4854 5450 2f31!
    ! 0x0040: 2e31 0d0a 486f 7374 3a20 7777 7734 3130!
    ! 0x0050: 3530 752e 7361 6b75 7261 2e6e 652e 6a70!
    ! 0x0060: 3a38 3038 300d 0a55 7365 722d 4167 656e!
    ! 0x0070: 743a 2063 7572 6c2f 372e 3433 2e30 0d0a!
    ! 0x0080: 4163 6365 7074 3a20 2a2f 2a0d 0a0d 0a!
    13:55:02.907175 IP (tos 0x0, ttl 64, id 26001, offset 0, flags [DF],
    ΫϥΠΞϯτ͔Βͷ
    ฏจϦΫΤετ

    View Slide

  78. Flags [.], cksum 0x3c7f (incorrect -> 0x6274), seq 1, ack 92, win 342,
    options [nop,nop,TS val 1027003124 ecr 1027003124], length 0!
    ! 0x0000: 4500 0034 6591 4000 4006 98da 31d4 6c58!
    ! 0x0010: 31d4 6c58 1f90 e39c 1020 b765 7a92 70ff!
    ! 0x0020: 8010 0156 3c7f 0000 0101 080a 3d36 d2f4!
    ! 0x0030: 3d36 d2f4!
    13:55:02.907332 IP (tos 0x0, ttl 64, id 26002, offset 0, flags [DF],
    proto TCP (6), length 214)!
    www41050u.sakura.ne.jp.http-alt > www41050u.sakura.ne.jp.58268:
    Flags [P.], cksum 0x3d21 (incorrect -> 0xc00f), seq 1:163, ack 92, win
    342, options [nop,nop,TS val 1027003124 ecr 1027003124], length 162:
    HTTP, length: 162!
    ! HTTP/1.1 301 Moved Permanently!
    ! Location: https://www41050u.sakura.ne.jp:8443/!
    ! Date: Sun, 04 Oct 2015 04:55:02 GMT!
    ! Connection: keep-alive!
    ! Content-Length: 0!
    ! !
    ! 0x0000: 4500 00d6 6592 4000 4006 9837 31d4 6c58!
    ! 0x0010: 31d4 6c58 1f90 e39c 1020 b765 7a92 70ff!
    ! 0x0020: 8018 0156 3d21 0000 0101 080a 3d36 d2f4!
    ! 0x0030: 3d36 d2f4 4854 5450 2f31 2e31 2033 3031!
    ! 0x0040: 204d 6f76 6564 2050 6572 6d61 6e65 6e74!
    ! 0x0050: 6c79 0d0a 4c6f 6361 7469 6f6e 3a20 6874!
    ! 0x0060: 7470 733a 2f2f 7777 7734 3130 3530 752e!
    ! 0x0070: 7361 6b75 7261 2e6e 652e 6a70 3a38 3434!
    αʔό͔Βͷ
    ʮTLSͰܨ͗௚ͤʯϨεϙϯε

    View Slide

  79. Flags [.], cksum 0x3c7f (incorrect -> 0x61ca), seq 92, ack 163, win
    350, options [nop,nop,TS val 1027003124 ecr 1027003124], length 0!
    ! 0x0000: 4500 0034 a25a 4000 4006 5c11 31d4 6c58!
    ! 0x0010: 31d4 6c58 e39c 1f90 7a92 70ff 1020 b807!
    ! 0x0020: 8010 015e 3c7f 0000 0101 080a 3d36 d2f4!
    ! 0x0030: 3d36 d2f4!
    13:55:02.915656 IP (tos 0x0, ttl 64, id 22547, offset 0, flags [DF],
    proto TCP (6), length 60)!
    www41050u.sakura.ne.jp.50461 > www41050u.sakura.ne.jp.8443: Flags
    [S], cksum 0x3c87 (incorrect -> 0x04f9), seq 3768879855, win 43690,
    options [mss 65495,sackOK,TS val 1027003132 ecr 0,nop,wscale 7],
    length 0!
    ! 0x0000: 4500 003c 5813 4000 4006 a650 31d4 6c58!
    ! 0x0010: 31d4 6c58 c51d 20fb e0a4 8aef 0000 0000!
    ! 0x0020: a002 aaaa 3c87 0000 0204 ffd7 0402 080a!
    ! 0x0030: 3d36 d2fc 0000 0000 0103 0307!
    13:55:02.915669 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF],
    proto TCP (6), length 60)!
    www41050u.sakura.ne.jp.8443 > www41050u.sakura.ne.jp.50461: Flags
    [S.], cksum 0x3c87 (incorrect -> 0xf1d1), seq 3389733079, ack
    3768879856, win 43690, options [mss 65495,sackOK,TS val 1027003132
    ecr 1027003132,nop,wscale 7], length 0!
    ! 0x0000: 4500 003c 0000 4000 4006 fe63 31d4 6c58!
    ! 0x0010: 31d4 6c58 20fb c51d ca0b 38d7 e0a4 8af0!
    ! 0x0020: a012 aaaa 3c87 0000 0204 ffd7 0402 080a!
    ! 0x0030: 3d36 d2fc 3d36 d2fc 0103 0307!
    ΫϥΠΞϯτ͔ΒͷTLSͷ઀ଓཁٻ

    View Slide

  80. ! 0x0010: 31d4 6c58 c51d 20fb e0a4 8af0 ca0b 38d8!
    ! 0x0020: 8010 0156 3c7f 0000 0101 080a 3d36 d2fc!
    ! 0x0030: 3d36 d2fc!
    13:55:02.927662 IP (tos 0x0, ttl 64, id 22549, offset 0, flags [DF],
    proto TCP (6), length 569)!
    www41050u.sakura.ne.jp.50461 > www41050u.sakura.ne.jp.8443: Flags
    [P.], cksum 0x3e84 (incorrect -> 0x4010), seq 1:518, ack 1, win 342,
    options [nop,nop,TS val 1027003144 ecr 1027003132], length 517!
    ! 0x0000: 4500 0239 5815 4000 4006 a451 31d4 6c58!
    ! 0x0010: 31d4 6c58 c51d 20fb e0a4 8af0 ca0b 38d8!
    ! 0x0020: 8018 0156 3e84 0000 0101 080a 3d36 d308!
    ! 0x0030: 3d36 d2fc 1603 0102 0001 0001 fc03 03ab!
    ! 0x0040: e5e2 86b6 2fb4 ee39 ea2b ff28 830b 307a!
    ! 0x0050: 807c f51a 6c3d 9012 6122 b87a b6a7 5a00!
    ! 0x0060: 00a0 c030 c02c c028 c024 c014 c00a 00a5!
    ! 0x0070: 00a3 00a1 009f 006b 006a 0069 0068 0039!
    ! 0x0080: 0038 0037 0036 0088 0087 0086 0085 c032!
    ! 0x0090: c02e c02a c026 c00f c005 009d 003d 0035!
    ! 0x00a0: 0084 c02f c02b c027 c023 c013 c009 00a4!
    ! 0x00b0: 00a2 00a0 009e 0067 0040 003f 003e 0033!
    ! 0x00c0: 0032 0031 0030 009a 0099 0098 0097 0045!
    ! 0x00d0: 0044 0043 0042 c031 c02d c029 c025 c00e!
    ! 0x00e0: c004 009c 003c 002f 0096 0041 0007 c012!
    ! 0x00f0: c008 0016 0013 0010 000d c00d c003 000a!
    ! 0x0100: 00ff 0100 0133 0000 001b 0019 0000 1677!
    ! 0x0110: 7777 3431 3035 3075 2e73 616b 7572 612e!
    ! 0x0120: 6e65 2e6a 7000 0b00 0403 0001 0200 0a00!
    ϓϦϚελγʔΫϨοτ

    View Slide

  81. [P.], cksum 0x3cb2 (incorrect -> 0x8f50), seq 929:980, ack 836, win
    359, options [nop,nop,TS val 1027003148 ecr 1027003145], length 51!
    ! 0x0000: 4500 0067 ea26 4000 4006 1412 31d4 6c58!
    ! 0x0010: 31d4 6c58 20fb c51d ca0b 3c78 e0a4 8e33!
    ! 0x0020: 8018 0167 3cb2 0000 0101 080a 3d36 d30c!
    ! 0x0030: 3d36 d309 1403 0300 0101 1603 0300 284b!
    ! 0x0040: 54b2 7c66 e641 15ea b1ac 4c0f 5ee4 6dad!
    ! 0x0050: 2c45 2228 f3d8 6acf 9b11 760c 9b53 6789!
    ! 0x0060: 5346 75cd d26f e0!
    13:55:02.931226 IP (tos 0x0, ttl 64, id 22552, offset 0, flags [DF],
    proto TCP (6), length 172)!
    www41050u.sakura.ne.jp.50461 > www41050u.sakura.ne.jp.8443: Flags
    [P.], cksum 0x3cf7 (incorrect -> 0xdfd4), seq 836:956, ack 980, win
    356, options [nop,nop,TS val 1027003148 ecr 1027003148], length 120!
    ! 0x0000: 4500 00ac 5818 4000 4006 a5db 31d4 6c58!
    ! 0x0010: 31d4 6c58 c51d 20fb e0a4 8e33 ca0b 3cab!
    ! 0x0020: 8018 0164 3cf7 0000 0101 080a 3d36 d30c!
    ! 0x0030: 3d36 d30c 1703 0300 739b 9377 77a5 eb88!
    ! 0x0040: 4cfa a634 de4e 8622 e62b 9866 c908 d0ab!
    ! 0x0050: d71b a211 f499 df04 359c 1e7f a782 d889!
    ! 0x0060: ee82 2248 1771 89dd 5b4d 9b3a 125b 18dd!
    ! 0x0070: 58b1 ad18 0b0a b3c1 4e19 2bcb 7a57 c007!
    ! 0x0080: b65d b991 fc89 33fb 61be 19cc 9904 b521!
    ! 0x0090: 83b1 e8c0 2807 773f 2ae6 bd8d 60e1 4442!
    ! 0x00a0: 2e79 b164 fa63 4955 85ce cdce!
    13:55:02.931411 IP (tos 0x0, ttl 64, id 59943, offset 0, flags [DF],
    proto TCP (6), length 221)!
    ҉߸Խ͞ΕͯಡΊͳ͘ͳ͍ͬͯΔ

    View Slide

  82. SPDY
    Google͕։ൃͨ͠
    HTTP/1.1ʹ୅ΘΔϓϩτίϧ
    SPDY/3.1·Ͱ࡞ΒΕͨޙ
    SPDY/4͸HTTP/2ʹ౷߹͞Εͨ
    ͢ͽʔͰ͌ʔ

    View Slide

  83. HTTP/1.1ͷԿ͕͍͚ͳ͔ͬͨͷ͔
    )5.-
    ελΠϧγʔτ
    ը૾
    +BWB4DSJQU
    ಈը
    9.-)UUQ3FRVFTU
    ࠓ೔ͷWeb͸HTML͚ͩͰ׬݁͢Δࣄ͸كͰ
    ଓ͚͍ͯΖ͍Ζͳ෺ΛGET͢Δඞཁ͕͋Δ

    View Slide

  84. ΫϥΠΞϯτ αʔό
    ͘Ε
    ͘Ε
    ͘Ε
    ͕࣌ؒ
    ͔͔Γ͗͢Δ
    RTT

    View Slide

  85. ΫϥΠΞϯτ αʔό
    ͘Ε
    ͘Ε
    ͘Ε
    HTTP͸ϦΫΤετͱϨεϙϯεΛ
    ަޓʹ౤͛͋͏ϓϩτίϧͳҝ
    1ຊͷηογϣϯͰ͜ΕΛ࣮ݱͰ͖ͳ͍
    ͜͏͍ͨ͠

    View Slide

  86. ड͚औΓ͍ͨ෺ͷ਺͚ͩηογϣϯΛுΕ͹
    ϦΫΤετΛ౤͛ͳ͕Βड৴ग़དྷΔΑ
    ΫϥΠΞϯτ αʔό
    ΛૹΔ༻ηογϣϯ
    ΛૹΔ༻ηογϣϯ
    ΛૹΔ༻ηογϣϯ
    Ұੲલͷϒϥ΢βͰྲྀߦͬͨςΫχοΫ

    View Slide

  87. ͍͚ͯͳ͍఺
    େྔʹுΒΕͨηογϣϯ͸
    ޓ͍Λ஌Βͳ͍ҝ
    ద੾ͳ2P4͕࣮ݱग़དྷͳ͍
    ͍͚ͯͳ͍఺
    ͦ΋ͦ΋5$1ͷηογϣϯ਺͸
    γεςϜͷݶΒΕͨࢿݯ
    ड͚औΓ͍ͨ෺ͷ਺͚ͩηογϣϯΛுΕ͹
    ϦΫΤετΛ౤͛ͳ͕Βड৴ग़དྷΔΑ

    View Slide

  88. SPDY͸1ຊͷηογϣϯͷ্ʹ
    ༏ઌ౓͕ઃఆ͞Εͨ
    ෳ਺ͷετϦʔϜΛ࡞Γ
    !
    ͦͷ্ʹHTTPͱಉ͡৘ใΛྲྀ͢
    ΫϥΠΞϯτ αʔό
    ηογϣϯ

    View Slide

  89. bool is_tls;!
    };!
    class factory : public proxygen::RequestHandlerFactory {!
    public:!
    void onServerStart() noexcept override {}!
    void onServerStop() noexcept override {}!
    proxygen::RequestHandler* onRequest(!
    proxygen::RequestHandler*, proxygen::HTTPMessage*!
    ) noexcept override { return new handler(); }!
    };!
    int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8443, true ),!
    proxygen::HTTPServer::Protocol::SPDY },!
    };!
    wangle::SSLContextConfig ssl;!
    ssl.isDefault = true;!
    ssl.setCertificate(!
    "./server.crt",!
    "./server.key",!
    "./password"!
    );!
    IPs.back().sslConfigs.push_back( ssl );!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    ͳΜͱ!
    Proxygen͸SPDYʹରԠ͍ͯ͠Δ
    ͜ͷΞυϨεͰ
    41%:ͷ઀ଓΛ଴ͪड͚Δ

    View Slide

  90. ͋ͱ͸SPDYରԠͷϒϥ΢βͰ
    ΞΫηε͢Ε͹ϓϩτίϧ͕SPDYʹ
    ͳͬͯͳ͍!

    View Slide

  91. ΫϥΠΞϯτ αʔό
    )551
    )551
    ΫϥΠΞϯτ αʔό
    41%:
    41%:
    SPDYαʔό͸ΫϥΠΞϯτ͕HTTP/1.1Λ
    ஻ͬͨ৔߹͸HTTPαʔόͱͯ͠ৼΔ෣͏

    View Slide

  92. ΫϥΠΞϯτ αʔό
    )551
    )551
    ૬ख͸ී௨ͷ
    HTTPαʔόͩͱࢥͬͯΔ
    ૬ख͕HTTP஻ͬͯΔ͔Β
    SPDY஻Εͳ͍ࢠͩͱࢥͬͯΔ
    αʔό͔ΒΫϥΠΞϯτʹ
    SPDY͕࢖͑ΔࣄΛ௨஌͢Δඞཁ͕͋Δ

    View Slide

  93. NPN
    /FYU1SPUPDPM/FHPUJBUJPO
    TLSͷ֦ு
    ϋϯυγΣΠΫ࣌ʹ
    αʔό͕ରԠ͍ͯ͠ΔϓϩτίϧͷϦετΛ
    ΫϥΠΞϯτʹૹΔ

    View Slide

  94. NPN͕ͳ͍࣌
    ΫϥΠΞϯτ αʔό
    ͜ͷ҉߸͕࢖͑ΔΑ
    ҉߸Խͨ͠
    ϓϦϚελγʔΫϨοτͩΑ
    ͜Ε͕ূ໌ॻͩΑ
    ४උͰ͖ͨΘ
    ४උͰ͖ͨΘ
    伴ੜ੒ 伴ੜ੒
    αʔό͕
    ຊ෺͔֬ೝ

    View Slide

  95. NPN͕͋Δ࣌
    ΫϥΠΞϯτ αʔό
    ͜ͷ҉߸͕࢖͑ΔΑ
    (ͱ͜ΖͰϓϩτίϧԿ͍͚Δ?)
    ҉߸Խͨ͠
    ϓϦϚελγʔΫϨοτͩΑ
    ͜Ε͕ূ໌ॻͩΑ
    (HTTP/1.1͔SPDY/3͕͍͚Δͥ)
    ४උͰ͖ͨΘ
    (Μ͡ΌSPDY/3ͰΑΖ)
    ४උͰ͖ͨΘ
    伴ੜ੒ 伴ੜ੒
    αʔό͕
    ຊ෺͔֬ೝ
    ϓϩτίϧ
    ܾఆ

    View Slide

  96. int main( int argc, char* argv[] ) {!
    std::vector< proxygen::HTTPServer::IPConfig > IPs = {!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8080, true ),!
    proxygen::HTTPServer::Protocol::HTTP },!
    { folly::SocketAddress( "www41050u.sakura.ne.jp", 8443, true ),!
    proxygen::HTTPServer::Protocol::SPDY },!
    };!
    wangle::SSLContextConfig ssl;!
    ssl.isDefault = true;!
    ssl.setCertificate(!
    "./server.crt",!
    "./server.key",!
    "./password"!
    );!
    std::list< std::string > nps;!
    nps.push_back( "spdy/3.1-hpack" );!
    nps.push_back( "spdy/3.1" );!
    nps.push_back( "spdy/3" );!
    nps.push_back( "http/1.1" );!
    ssl.setNextProtocols( nps );!
    IPs.back().sslConfigs.push_back( ssl );!
    proxygen::HTTPServerOptions options;!
    options.handlerFactories =!
    proxygen::RequestHandlerChain().addThen< factory >().build();!
    proxygen::HTTPServer server( std::move( options ) );!
    server.bind( IPs );!
    Proxygen͔ΒOpenSSLʹ
    NPNΛૹΔΑ͏ʹࢦࣔ͢Δ
    SPDY͍͚ΔΑ!

    View Slide

  97. ͋ͱ͸SPDYରԠͷϒϥ΢βͰ
    ΞΫηε͢Ε͹ϓϩτίϧ͕SPDYʹ
    ͳͬͨ!

    View Slide

  98. #include !
    #include !
    #include !
    #include !
    class handler : public proxygen::RequestHandler {!
    public:!
    void onRequest(!
    std::unique_ptr headers!
    ) noexcept override {!
    is_tls = headers->isSecure();!
    std::cout << int( headers->getPriority() ) << std::endl;!
    }!
    void onBody(std::unique_ptr body) noexcept override {}!
    void onEOM() noexcept override {!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( is_tls ) { !
    tx.status( 200, "OK" ).header( "Content-Type", "text/plain" );!
    tx.body( "Hello, World!\n" ).sendWithEOM();!
    } !
    else {!
    tx.status( 301, "Moved Permanently" );!
    tx.header( "Location", "https://www41050u.sakura.ne.jp:8443/" );!
    tx.sendWithEOM();!
    } !
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {}!
    SPDYͰ௨৴த͸ϦΫΤετͷ
    HTTPMessage::getPriority()Ͱ༏ઌ౓͕औΕΔ
    ./spdy_sample
    0!
    2
    ຊମ͘Εɺࠓ͙͢
    GBWJDPO͘Εɺ஗ͯ͘΋ྑ͍

    View Slide

  99. WebSocket

    View Slide

  100. ΫϥΠΞϯτ αʔό
    ৽ண͋ΔΑ
    ӾཡதͷWebϖʔδʹߋ৽͕͋ͬͨΒ
    ௚ͪʹ൓ө͍ͨ͠

    View Slide

  101. ݹయతͳղܾํ๏
    ΫϥΠΞϯτ αʔό
    ϙʔϦϯάִؒΛڱΊΔͱαʔό͕ࢮ͵
    ϙʔϦϯάִؒΛ৳͹͢ͱ௨஌͕஗ΕΔ
    ৽ண͋Δ?
    ৽ண͋Δ?
    ৽ண͋Δ?
    ͳ͍
    ͳ͍
    ͋Δ ৽ண

    View Slide

  102. Comet
    ΫϥΠΞϯτ αʔό
    αʔό͸௨஌͢΂͖෺͕དྷΔ·Ͱ
    ΫϥΠΞϯτ͔ΒͷϦΫΤετʹฦ౴͠ͳ͍
    ΫϥΠΞϯτ͸Ϩεϙϯε͕དྷͨΒ͙͢ʹϦΫΤετ͢Δ
    ৽ண͋Δ?
    ࠓདྷͨ
    ʜ
    ৽ண

    View Slide

  103. Comet
    ΫϥΠΞϯτ αʔό
    αʔό͸௨஌͢΂͖෺͕དྷΔ·Ͱ
    ΫϥΠΞϯτ͔ΒͷϦΫΤετʹฦ౴͠ͳ͍
    ΫϥΠΞϯτ͸Ϩεϙϯε͕དྷͨΒ͙͢ʹϦΫΤετ͢Δ
    ৽ண͋Δ?
    ࠓདྷͨ
    ʜ
    ৽ண
    ͜Ε͸΋͸΍ϦΫΤετͰ͸ͳ͍
    ͜Ε͸΋͸΍ϨεϙϯεͰ͸ͳ͍

    View Slide

  104. HTTPͷ࿮ͷதͰ
    ղܾ͠Α͏ͱ͢Δͷ͕
    ؒҧ͍ͳͷͰ͸

    View Slide

  105. HTTPΛ஻ΔͷΛ΍Ίͯ
    WebαʔόͱΫϥΠΞϯτͷؒͰ
    ೚ҙͷλΠϛϯάͰ೚ҙͷσʔλΛ
    ౤͛͋͑ΔΑ͏ʹ͢Δ
    WebSocket
    ΫϥΠΞϯτ αʔό
    ࠓདྷͨ(౜ಥ) ৽ண

    View Slide

  106. Proxygenͷpull requestʹ
    WebSocketʹରԠͤ͞Δมߋ͕స͕͍ͬͯΔ

    View Slide

  107. #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    #include !
    !
    struct no_such_file {};!
    !
    class static_files {!
    public:!
    static_files() {}!
    static_files( const static_files& ) = delete;!
    static_files( static_files&& ) = delete;!
    static_files &operator=( const static_files& ) = delete;!
    WebSocketΛ࢖͏αʔό
    ௕͍ͷͰޙͰgithub͋ͨΓʹ্͓͖͛ͯ·͢

    View Slide

  108. std::unordered_map< const proxygen::RequestHandler*, connection_state >
    sockets;!
    std::mutex guard;!
    };!
    class hello : public proxygen::RequestHandler {!
    public:!
    explicit hello( const static_files &files_, broadcaster &broad_ ) : files(
    files_ ), broad( broad_ ), is_ws( false ) {}!
    void onRequest( std::unique_ptr headers ) noexcept
    override {!
    if(proxygen::WebSocket::isWebSocketRequest(*headers)) {!
    broad.open( this,
    std::move(proxygen::WebSocket::acceptWebSocket(downstream_, *headers,
    std::bind( &broadcaster::receive, &broad, this, std::placeholders::_1))) );!
    is_ws = true;!
    }!
    else!
    file = files[ headers->getPath() ];!
    }!
    void onBody(std::unique_ptr body) noexcept override {!
    if(is_ws) {!
    broad.processData( this, std::move(body));!
    }!
    }!
    void onEOM() noexcept override {!
    if(is_ws)!
    return;!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( file ) {!
    tx.status( 200, "OK" )!
    onRequestͰ
    WebSocket΁ͷUPGRADE͔Λௐ΂ͯ
    WebSocketͩͬͨΒ
    proxygen::WebSocket::acceptWebSocket
    ͜ͷ࣌WebSocketͷΠϕϯτͰݺͼग़͞ΕΔ
    ίʔϧόοΫΛઃఆ͢Δ

    View Slide

  109. for( auto &receiver: receivers )!
    receiver->sendFrame( frame->frameType,
    folly::IOBuf::maybeCopyBuffer( data ), frame->endOfMessage );!
    return true;!
    }!
    void processData( const proxygen::RequestHandler*k,
    std::unique_ptr body ) {!
    auto search_result = sockets.find( k );!
    std::shared_ptr< proxygen::WebSocket > socket;!
    {!
    std::lock_guard< std::mutex > lock( guard );!
    if( search_result != sockets.end() ) {!
    if( search_result->second.message_revision == 0ull )!
    search_result->second.message_revision = ++revision;!
    socket = search_result->second.socket;!
    }!
    }!
    if( socket ) socket->processData( std::move( body ) );!
    }!
    private:!
    revision_t revision;!
    std::unordered_map< const proxygen::RequestHandler*, connection_state >
    sockets;!
    std::mutex guard;!
    };!
    class hello : public proxygen::RequestHandler {!
    public:!
    explicit hello( const static_files &files_, broadcaster &broad_ ) : files(
    files_ ), broad( broad_ ), is_ws( false ) {}!
    onBodyͰWebSocketͷσʔλ͕དྷͨΒ
    WebSocketͷΠϯελϯεʹ·Θ͢

    View Slide

  110. void onBody(std::unique_ptr body) noexcept override {!
    if(is_ws) {!
    broad.processData( this, std::move(body));!
    }!
    }!
    void onEOM() noexcept override {!
    if(is_ws)!
    return;!
    proxygen::ResponseBuilder tx( downstream_ );!
    if( file ) {!
    tx.status( 200, "OK" )!
    .header( "Hoge", "fuga" )!
    .header( "Content-Type", file->first )!
    .body( file->second )!
    .sendWithEOM();!
    }!
    else {!
    tx.status( 404, "File Not Found" )!
    .header( "Hoge", "fuga" )!
    .body( "" )!
    .sendWithEOM();!
    }!
    }!
    void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override {!
    }!
    void requestComplete() noexcept override {!
    if(is_ws)!
    broad.close( this );!
    delete this;!
    WebSocketͰ࢖ͬͨηογϣϯ͸
    onEOMͰԿ΋ฦ͞ͳ͍

    View Slide

  111. std::unique_ptr frame ) {!
    const std::string data = std::string( frame->payload->data(), frame-
    >payload->tail() );!
    std::vector< std::shared_ptr< proxygen::WebSocket > > receivers;!
    if( !data.empty() ) {!
    std::lock_guard< std::mutex > lock( guard );!
    auto search_result = sockets.find( k );!
    if( search_result != sockets.end() ) {!
    revision_t highest_revision = search_result-
    >second.message_revision;!
    for( auto &socket: sockets )!
    if( socket.second.joined_at < highest_revision )!
    receivers.emplace_back( socket.second.socket );!
    }!
    if( frame->endOfMessage )!
    search_result->second.message_revision = 0ull;!
    }!
    for( auto &receiver: receivers )!
    receiver->sendFrame( frame->frameType,
    folly::IOBuf::maybeCopyBuffer( data ), frame->endOfMessage );!
    return true;!
    }!
    void processData( const proxygen::RequestHandler*k,
    std::unique_ptr body ) {!
    auto search_result = sockets.find( k );!
    std::shared_ptr< proxygen::WebSocket > socket;!
    {!
    std::lock_guard< std::mutex > lock( guard );!
    if( search_result != sockets.end() ) {!
    if( search_result->second.message_revision == 0ull )!
    SendFrame()ͰΫϥΠΞϯτʹσʔλΛૹΔ

    View Slide

  112. WebSocketΛ࢖ͬͨνϟοτͷσϞ
    ΠϚυΩͷϒϥ΢β͕खݩʹ͋Δํ͸
    IUUQXXXVTBLVSBOFKQ
    ʹΞΫηεͯ͠ΈͯԼ͍͞

    View Slide

  113. ࣮૷ͷҰ෦΍ςετ͕֬ೝग़དྷΔ͕
    HTTPServer͔Β࢖͑Δঢ়ଶʹ
    ͳ͍ͬͯͳ͍ػೳ

    View Slide

  114. ServerPush

    View Slide

  115. ΫϥΠΞϯτ αʔό
    ͘Ε
    ͘Ε
    ͘Ε
    HTMLΛύʔεͯ͠ΈΔ·Ͱඞཁͳը૾౳͕෼͔Βͣ
    ͜ͷؒଞͷϑΝΠϧͷϩʔυΛಉ࣌ਐߦͰ͖ͳ͍
    ͕͜͜
    Ψϥۭ͖ʹ
    ͳΔ
    ͜͜Ͱ
    ඞཁͳը૾౳͕
    ෼͔Δ

    View Slide

  116. ͜͜Ͱ
    ඞཁͳը૾౳͕
    ෼͔Δ
    ΫϥΠΞϯτ αʔό
    ͘Ε
    ͓લ͸࣍ʹ
    ը૾ͱ$44͕ཉ͍͠ͱ
    ݴ͍ग़ͩ͢Ζ͏
    ը૾౳Λ
    (&5͠Α͏ͱ
    ࢥͬͨΒ
    Կނ͔΋͏͋Δ
    SPDY͸ϦΫΤετ͞ΕΔલʹϨεϙϯεΛฦ͢
    ServerPushͰ͜ͷ໰୊Λղܾ͢Δ

    View Slide

  117. /**!
    * @return true iff this transaction can be used to push resources to!
    * the remote side.!
    */!
    bool supportsPushTransactions() const {!
    return direction_ == TransportDirection::DOWNSTREAM &&!
    transport_.getCodec().supportsPushTransactions();!
    }!
    !
    /** !
    * Create a new pushed transaction associated with this transaction,!
    * and assign the given handler and priority.!
    *!
    * @return the new transaction for the push, or nullptr if a new push!
    * transaction is impossible right now.!
    */!
    virtual HTTPTransaction* newPushedTransaction(!
    HTTPPushTransactionHandler* handler, uint8_t priority) {!
    if (isEgressEOMSeen()) {!
    return nullptr;!
    } !
    auto txn = transport_.newPushedTransaction(id_, handler, priority);!
    if (txn) {!
    pushedTransactions_.insert(txn->getID());!
    } !
    return txn; !
    }!
    !
    /** !
    * Invoked by the session (upstream only) when a new pushed transaction!
    Proxygenͷ಺෦ͷਵॴʹServer PushͷҝͱࢥΘΕΔ
    ؔ਺͕༻ҙ͞Ε͍ͯΔ

    View Slide

  118. XBOHMF
    )551$PEFD 41%:$PEFD
    )5515SBOTBDUJPO
    )5514FSWFS
    ඇಉظ*0
    ݸʑͷϓϩτίϧͰͷ
    )551ϝοηʔδͷૢ࡞
    ϓϩτίϧඇґଘͷ
    )551ϝοηʔδͷૢ࡞
    ͜ͷลΓʹ͸
    Server Pushͷ࣮૷Β͖͠෺͕͋Δ
    HTTP Server͔ΒServer PushΛ
    ୟ͘࢓૊Έ͕ݟ౰ͨΒͳ͍
    ֎޲͖ͷ"1*

    View Slide

  119. Trailer
    ϔομ
    ຊจ
    &OEPG.FTTBHF
    τϨΠϥ
    HTTPϨεϙϯεͷ
    ϔομͷҰ෦Λ
    ຊจΑΓޙΖʹ
    ॻ͘࢓૊Έ
    ຊจੜ੒ͯ͠Έͳ͍ͱ
    ஋͕ఆ·Βͳ͍
    νΣοΫαϜ౳ʹ࢖͏

    View Slide

  120. void onTrailersComplete(HTTPCodec::StreamID streamID,!
    std::unique_ptr trailers) override;!
    void onMessageComplete(HTTPCodec::StreamID streamID, bool upgrade)
    override;!
    void onError(HTTPCodec::StreamID streamID,!
    const HTTPException& error, bool newTxn) override;!
    void onAbort(HTTPCodec::StreamID streamID,!
    ErrorCode code) override;!
    void onGoaway(uint64_t lastGoodStreamID,!
    ErrorCode code) override;!
    void onPingRequest(uint64_t uniqueID) override;!
    void onPingReply(uint64_t uniqueID) override;!
    void onWindowUpdate(HTTPCodec::StreamID stream, uint32_t amount) override;!
    …!
    // HTTPTransaction::Transport methods!
    void pauseIngress(HTTPTransaction* txn) noexcept override;!
    void resumeIngress(HTTPTransaction* txn) noexcept override;!
    void transactionTimeout(HTTPTransaction* txn) noexcept override;!
    void sendHeaders(HTTPTransaction* txn,!
    const HTTPMessage& headers,!
    HTTPHeaderSize* size) noexcept override;!
    size_t sendBody(HTTPTransaction* txn, std::unique_ptr,!
    bool includeEOM) noexcept override;!
    size_t sendChunkHeader(HTTPTransaction* txn,!
    size_t length) noexcept override;!
    size_t sendChunkTerminator(HTTPTransaction* txn) noexcept override;!
    size_t sendTrailers(HTTPTransaction* txn,!
    const HTTPHeaders& trailers) noexcept override;!
    size_t sendEOM(HTTPTransaction* txn) noexcept override;!
    Trailerૹ৴ͷҝͷؔ਺ͱࢥ͖͠෺͕
    HTTPSessionͷதʹ͋Δ

    View Slide

  121. XBOHMF
    )551$PEFD 41%:$PEFD
    )5514FTTJPO
    )5514FSWFS
    ඇಉظ*0
    ݸʑͷϓϩτίϧͰͷ
    )551ϝοηʔδͷૢ࡞
    ϓϩτίϧඇґଘͷ
    )551ϝοηʔδͷૢ࡞
    ֎޲͖ͷ"1*
    ͜ͷลΓʹ͸
    Trailerͷ࣮૷Β͖͠෺͕͋Δ
    HTTP ServerͷResponseBuilderͰ
    TrailerΛ࡞Δ࢓૊Έ͕ݟ౰ͨΒͳ͍

    View Slide

  122. HTTP/2
    41%:ͷొ৔Λड͚ͯ
    ೥ͿΓʹվగ͞Εͨ)551
    ຊͷηογϣϯʹෳ਺ͷετϦʔϜ
    ΫϥΠΞϯτ αʔό
    ηογϣϯ
    4FSWFS1VTIʹରԠ
    ϔομͷѹॖͱࠩ෼ૹ৴ʹରԠ

    View Slide

  123. SPDYऴྃͷ͓஌Βͤ
    ࣍ੈ୅HTTPͷ࣮ݧͱͯ͠࡞ΒΕͨSPDY͸
    HTTP/2ͷඪ४ԽͰ໾໨Λऴ͑ͨͱݟ၏͞Ε͓ͯΓ
    Google͸2016೥ͷૣ͍͏ͪʹ
    ChromeͷSPDYαϙʔτΛऴྃ͢Δͱ͍ͯ͠Δ
    ͳΜͯͬͨ͜!
    ProxygenͰ࡞ͬͨWebαΠτ΋
    HTTP/2ʹ͠ͳ͖Ό
    IUUQCMPHDISPNJVNPSHIFMMPIUUQ
    HPPECZFTQEZIUUQJT@IUNM

    View Slide

  124. /**!
    * An implementation of the framing layer for HTTP/2. Instances of this!
    * class must not be used from multiple threads concurrently.!
    */!
    class HTTP2Codec: public HTTPParallelCodec, HeaderCodec::StreamingCallback {!
    public:!
    void onHeader(const std::string& name,!
    const std::string& value) override;!
    void onHeadersComplete() override;!
    void onDecodeError(HeaderDecodeError decodeError) override;!
    !
    explicit HTTP2Codec(TransportDirection direction);!
    ~HTTP2Codec() override;!
    !
    // HTTPCodec API!
    CodecProtocol getProtocol() const override {!
    return CodecProtocol::HTTP_2;!
    }!
    !
    size_t onIngress(const folly::IOBuf& buf) override;!
    size_t generateConnectionPreface(folly::IOBufQueue& writeBuf) override;!
    void generateHeader(folly::IOBufQueue& writeBuf,!
    StreamID stream,!
    const HTTPMessage& msg,!
    StreamID assocStream = 0,!
    bool eom = false,!
    HTTPHeaderSize* size = nullptr) override;!
    size_t generateBody(folly::IOBufQueue& writeBuf,!
    StreamID stream,!
    HTTP/2ͷϦΫΤετΛύʔεͨ͠Γ
    ϨεϙϯεΛੜ੒͢Δ HTTP2Codec

    View Slide

  125. XBOHMF
    )551$PEFD 41%:$PEFD
    )5515SBOTBDUJPO
    )5514FSWFS
    ΋͔ͯ͠͠
    ΋͏࢖͑Δ?
    )551$PEFD

    View Slide

  126. HTTP/2͸HTTP/1.1͔Βͷ੾Γସ͑ʹ
    NPNͰ͸ͳ͘ALPNΛ࢖͏
    ALPN
    Application Layer Protocol Negotiation
    TLSͷ֦ு
    ϋϯυγΣΠΫ࣌ʹ
    ΫϥΠΞϯτ͕ରԠ͍ͯ͠ΔϓϩτίϧͷϦετΛ
    αʔόʹૹΔ

    View Slide

  127. NPN
    ΫϥΠΞϯτ αʔό
    ͜ͷ҉߸͕࢖͑ΔΑ
    (ͱ͜ΖͰϓϩτίϧԿ͍͚Δ?)
    ҉߸Խͨ͠
    ϓϦϚελγʔΫϨοτͩΑ
    ͜Ε͕ূ໌ॻͩΑ
    (HTTP/1.1͔SPDY/3͕͍͚Δͥ)
    ४උͰ͖ͨΘ
    (Μ͡ΌSPDY/3ͰΑΖ)
    ४උͰ͖ͨΘ
    伴ੜ੒ 伴ੜ੒
    αʔό͕
    ຊ෺͔֬ೝ
    ϓϩτίϧ
    ܾఆ

    View Slide

  128. ALPN
    ͜ͷ҉߸͕࢖͑ΔΑ
    (Զ࣮͸HTTP/2͍͚ΔΜͩΑͶ)
    ҉߸Խͨ͠
    ϓϦϚελγʔΫϨοτͩΑ
    ͜Ε͕ূ໌ॻͩΑ
    (͡Ό͋HTTP/2ͰΑΖ)
    ४උͰ͖ͨΘ
    ४උͰ͖ͨΘ
    伴ੜ੒ 伴ੜ੒
    αʔό͕
    ຊ෺͔֬ೝ
    ϓϩτίϧ
    ܾఆ
    ΫϥΠΞϯτ αʔό

    View Slide

  129. ALPN
    ͜ͷ҉߸͕࢖͑ΔΑ
    (Զ࣮͸HTTP/2͍͚ΔΜͩΑͶ)
    ҉߸Խͨ͠
    ϓϦϚελγʔΫϨοτͩΑ
    ͜Ε͕ূ໌ॻͩΑ
    (͡Ό͋HTTP/2ͰΑΖ)
    ४උͰ͖ͨΘ
    ४උͰ͖ͨΘ
    伴ੜ੒ 伴ੜ੒
    αʔό͕
    ຊ෺͔֬ೝ
    ϓϩτίϧ
    ܾఆ
    ΫϥΠΞϯτ αʔό
    ࢖͑Δϓϩτίϧ͕ແ͔ͬͨ৔߹ʹ
    TLSͷ伴ੜ੒ʹೖΔલʹ઀ଓΛ੾ΕΔ

    View Slide

  130. Proxygenʹ͸
    ALPNΛૹΔҝͷ࢓૊Έ͕ݟ౰ͨΒͳ͍
    ͓ͦΒ͘ProxygenͷHTTP/2ͷ࣮૷͸
    ϦΫΤετͱϨεϙϯεͷύʔε͸ग़དྷΔ͕
    ࣮ࡍʹΫϥΠΞϯτ͔Βͷ௨৴Λ
    ड͚෇͚ΒΕΔॴ·Ͱ͸࣮૷͞Ε͍ͯͳ͍
    (2015೥10݄8೔࣌఺)

    View Slide

  131. ·ͱΊ
    C++ͳWebϑϨʔϜϫʔΫProxygen
    TLSͰ͖ΔΑ
    SPDY΋Ͱ͖ΔΑ
    WebSocket΋ҰԠͰ͖ΔΑ
    HTTP/2͸·ͩͩΑ

    View Slide