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. ࣗྗͰHTTPΛ஻Δ? ΫϥΠΞϯτ αʔό HTTP/1.0 200 OK! Date: Mon, 21 Sep

    2015 11:40:04 GMT! Content-Length: 14! ! Hello, World! GET / HTTP/1.0
  2. ΞοϋΠɺεϛϚηϯʜ ΫϥΠΞϯτ αʔό GET / HTTP/1.1! Host: example.com! Connection: Upgrade,

    HTTP2-Settings! Upgrade: h2c 1! HTTP2-Settings: … ਖ਼͘͠HTTPͰձ࿩͢Δͷ͸೉͍͠
  3. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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;! }
  4. };! 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Λࢦఆ ໊લղܾΛڐՄ
  5. };! 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ͷΠϯελϯεΛ࡞Δ
  6. 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()͸αʔό͕ఀࢭ͢Δ·ͰฦΒͳ͍
  7. 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Λܧঝ ϦΫΤετ͕དྷͨ࣌ʹߦ͏ॲཧ ϦΫΤετϋϯυϥϑΝΫτϦ
  8. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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Λܧঝ
  9. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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ϦΫΤετͷ ϔομ͕ಧ͍ͨ࣌఺Ͱݺ͹ΕΔ
  10. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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ϦΫΤετΛ શͯड৴ͨ࣌͠఺Ͱݺ͹ΕΔ
  11. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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ϦΫΤετͷ ຊจΛड৴ͨ࣌͠఺Ͱݺ͹ΕΔ
  12. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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ͩͬͨ৔߹ʹݺ͹ΕΔ
  13. void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf>

    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 ΫϥΠΞϯτଆ͔Β੾அ͞ΕΔ౳ Ϩεϙϯεͷૹ৴׬ྃ·Ͱ౸ୡग़དྷͳ͘ͳͬͨΒ ݺ͹ΕΔ
  14. 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͕ੜϙΠϯλ͔͠ѲΕͳ͍ͷͰ ͜͏͢Δ͔͠ͳ͍
  15. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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()Ͱ ϨεϙϯεΛऴྃͤ͞Δ
  16. $ 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Ͱ઀ଓͯ͠ΈΑ͏ Ϩεϙϯε͕དྷͨ!
  17. tx.body( "Hello, World!" ).sendWithEOM(); tx.body( "hoge" ).send();! tx.body( "fuga" ).send();!

    tx.body( "piyo" ).send();! tx.body( "foo" ).sendWithEOM(); send()Λ࢖͏ͱνϟϯΫసૹʹͳΔ
  18. 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! ! νϟϯΫ
  19. public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void

    onBody(std::unique_ptr<folly::IOBuf> 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 Λ௥Ճ
  20. $ 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
  21. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void onBody(std::unique_ptr<folly::IOBuf> 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;! }
  22. public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {}! void

    onBody(std::unique_ptr<folly::IOBuf> 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ͷ’[’ େ͖ͳຊจͩ!ѹॖ͠Α͏!
  23. ) 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
  24. ) 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
  25. ) 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Λ౉͢ͱѹॖ͕ࣦഊ͠ αʔό͕Τϥʔऴྃ͢Δ(ͭ·Γઃఆඞਢ)
  26. 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͕͜ΕΒʹ߹க͢Δ৔߹ͷΈ ѹॖΛߦ͏
  27. $ 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
  28. $ 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Ͱѹॖ͞Ε͍ͯΔ
  29. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! path = headers->getPath();! }! void onBody(std::unique_ptr<folly::IOBuf> 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;! }
  30. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! path = headers->getPath();! }! void onBody(std::unique_ptr<folly::IOBuf> 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()Ͱ ύεΛจࣈྻͰऔಘ
  31. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! path = headers->getPath();! }! void onBody(std::unique_ptr<folly::IOBuf> 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Ͱฦ͢ίϯςϯπΛ ύεʹΑͬͯม͑Δ͚ͩ
  32. $ 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. ύεʹΑͬͯ ҟͳΔ Ϩεϙϯε
  33. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! arg = headers->getDecodedQueryParam( "hoge" );! }! void onBody(std::unique_ptr<folly::IOBuf> 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;! }
  34. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! arg = headers->getDecodedQueryParam( "hoge" );! }! void onBody(std::unique_ptr<folly::IOBuf> 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()Ͱ ஋ΛจࣈྻͰऔಘ
  35. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! arg = headers->getDecodedQueryParam( "hoge" );! }! void onBody(std::unique_ptr<folly::IOBuf> 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Ͱฦ͢ίϯςϯπΛ ஋ʹΑͬͯม͑Δ͚ͩ
  36. $ 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. ΫΤϦʹΑͬͯ ҟͳΔ Ϩεϙϯε
  37. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! host = headers->getHeaders().getSingleOrEmpty( "Host" );! }! void onBody(std::unique_ptr<folly::IOBuf> 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;! }
  38. 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;! } ෳ਺ͷϗετ໊͔Βͷ ઀ଓΛड͚෇͚ΔΑ͏ʹ͢Δ
  39. #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler : public

    proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! host = headers->getHeaders().getSingleOrEmpty( "Host" );! }! void onBody(std::unique_ptr<folly::IOBuf> 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
  40. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! host = headers->getHeaders().getSingleOrEmpty( "Host" );! }! void onBody(std::unique_ptr<folly::IOBuf> 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Ͱฦ͢ίϯςϯπΛ ஋ʹΑͬͯม͑Δ͚ͩ
  41. ஫ҙ 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 ֎޲͖ΞυϨεͰΞΫηε ಺޲͖ΞυϨεΛࣗশ ಺޲͖ίϯςϯπ͕ฦͬͯ͠·ͬͨ!
  42. #include <boost/spirit/include/qi.hpp>! #include <boost/spirit/include/karma.hpp>! #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>!

    #include <proxygen/httpserver/ResponseBuilder.h>! class handler : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> 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<folly::IOBuf> 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;! }
  43. #include <boost/spirit/include/karma.hpp>! #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>!

    class handler : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> 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<folly::IOBuf> 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Λऔಘ
  44. 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<folly::IOBuf> 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()
  45. $ 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Λ࢖ͬͯ Կ౓໨ͷΞΫηε͔Λௐ΂Δ
  46. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! is_tls = headers->isSecure();! }! void onBody(std::unique_ptr<folly::IOBuf> 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;! }
  47. 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༻ͷϙʔτΛ։͚Δ
  48. };! 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ӽ͠ʹ໊લϕʔεόʔνϟϧϗετ͕ग़དྷͳ͍
  49. };! 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ʹ௥Ճ͢Δ αʔόূ໌ॻ ൿີ伴 ূ໌ॻͷύεϫʔυ
  50. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! is_tls = headers->isSecure();! }! void onBody(std::unique_ptr<folly::IOBuf> 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()Ͱ൑ผͰ͖Δ
  51. #include <proxygen/httpserver/ResponseBuilder.h>! class handler : public proxygen::RequestHandler {! public:! void

    onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! is_tls = headers->isSecure();! }! void onBody(std::unique_ptr<folly::IOBuf> 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αΠτͱ͞Ε͍ͯΔ
  52. 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Ͱ؍࡯
  53. 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], ΫϥΠΞϯτ͔Βͷ ฏจϦΫΤετ
  54. 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Ͱܨ͗௚ͤʯϨεϙϯε
  55. 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ͷ઀ଓཁٻ
  56. ! 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! ϓϦϚελγʔΫϨοτ
  57. [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)! ҉߸Խ͞ΕͯಡΊͳ͘ͳ͍ͬͯΔ
  58. 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%:ͷ઀ଓΛ଴ͪड͚Δ
  59. 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͍͚ΔΑ!
  60. #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! class handler

    : public proxygen::RequestHandler {! public:! void onRequest(! std::unique_ptr<proxygen::HTTPMessage> headers! ) noexcept override {! is_tls = headers->isSecure();! std::cout << int( headers->getPriority() ) << std::endl;! }! void onBody(std::unique_ptr<folly::IOBuf> 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͘Εɺ஗ͯ͘΋ྑ͍
  61. #include <cstdio>! #include <cstdlib>! #include <iostream>! #include <unordered_map>! #include <boost/filesystem.hpp>!

    #include <boost/range/iterator_range.hpp>! #include <sys/mman.h>! #include <sys/stat.h>! #include <fcntl.h>! #include <unistd.h>! #include <rapidjson/rapidjson.h>! ! #include <folly/Memory.h>! #include <folly/Portability.h>! #include <folly/io/async/EventBaseManager.h>! #include <proxygen/httpserver/HTTPServer.h>! #include <proxygen/httpserver/RequestHandlerFactory.h>! #include <proxygen/httpserver/RequestHandler.h>! #include <proxygen/httpserver/ResponseBuilder.h>! #include <proxygen/httpserver/WebSocket.h>! ! 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͋ͨΓʹ্͓͖͛ͯ·͢
  62. 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<proxygen::HTTPMessage> 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<folly::IOBuf> 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ͷΠϕϯτͰݺͼग़͞ΕΔ ίʔϧόοΫΛઃఆ͢Δ
  63. 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<folly::IOBuf> 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ͷΠϯελϯεʹ·Θ͢
  64. void onBody(std::unique_ptr<folly::IOBuf> 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ͰԿ΋ฦ͞ͳ͍
  65. std::unique_ptr<proxygen::WebSocketFrame> 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<folly::IOBuf> 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()ͰΫϥΠΞϯτʹσʔλΛૹΔ
  66. ͜͜Ͱ ඞཁͳը૾౳͕ ෼͔Δ ΫϥΠΞϯτ αʔό ͘Ε ͓લ͸࣍ʹ ը૾ͱ$44͕ཉ͍͠ͱ ݴ͍ग़ͩ͢Ζ͏ ը૾౳Λ

    (&5͠Α͏ͱ ࢥͬͨΒ Կނ͔΋͏͋Δ SPDY͸ϦΫΤετ͞ΕΔલʹϨεϙϯεΛฦ͢ ServerPushͰ͜ͷ໰୊Λղܾ͢Δ
  67. /**! * @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ͷҝͱࢥΘΕΔ ؔ਺͕༻ҙ͞Ε͍ͯΔ
  68. XBOHMF )551$PEFD 41%:$PEFD )5515SBOTBDUJPO )5514FSWFS ඇಉظ*0 ݸʑͷϓϩτίϧͰͷ )551ϝοηʔδͷૢ࡞ ϓϩτίϧඇґଘͷ )551ϝοηʔδͷૢ࡞

    ͜ͷลΓʹ͸ Server Pushͷ࣮૷Β͖͠෺͕͋Δ HTTP Server͔ΒServer PushΛ ୟ͘࢓૊Έ͕ݟ౰ͨΒͳ͍ ֎޲͖ͷ"1*
  69. void onTrailersComplete(HTTPCodec::StreamID streamID,! std::unique_ptr<HTTPHeaders> 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<folly::IOBuf>,! 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ͷதʹ͋Δ
  70. XBOHMF )551$PEFD 41%:$PEFD )5514FTTJPO )5514FSWFS ඇಉظ*0 ݸʑͷϓϩτίϧͰͷ )551ϝοηʔδͷૢ࡞ ϓϩτίϧඇґଘͷ )551ϝοηʔδͷૢ࡞

    ֎޲͖ͷ"1* ͜ͷลΓʹ͸ Trailerͷ࣮૷Β͖͠෺͕͋Δ HTTP ServerͷResponseBuilderͰ TrailerΛ࡞Δ࢓૊Έ͕ݟ౰ͨΒͳ͍
  71. /**! * 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
  72. ALPN ͜ͷ҉߸͕࢖͑ΔΑ (Զ࣮͸HTTP/2͍͚ΔΜͩΑͶ) ҉߸Խͨ͠ ϓϦϚελγʔΫϨοτͩΑ ͜Ε͕ূ໌ॻͩΑ (͡Ό͋HTTP/2ͰΑΖ) ४උͰ͖ͨΘ ४උͰ͖ͨΘ 伴ੜ੒

    伴ੜ੒ αʔό͕ ຊ෺͔֬ೝ ϓϩτίϧ ܾఆ ΫϥΠΞϯτ αʔό ࢖͑Δϓϩτίϧ͕ແ͔ͬͨ৔߹ʹ TLSͷ伴ੜ੒ʹೖΔલʹ઀ଓΛ੾ΕΔ