$30 off During Our Annual Pro Sale. View Details »

[TLVPHPUG] HTTP/2 and Asynchronous APIs

Davey Shafik
November 22, 2015

[TLVPHPUG] HTTP/2 and Asynchronous APIs

HTTP/2 (H2) is coming, and along with it a whole new way of communicating over the web. Connection re-use, prioritization, multiplexing, and server push are just some of the features in H2.

In this talk we'll look at the HTTP/2 protocol, and at how we can use asynchronous request now with HTTP/1.x. We will also look at what asychronous requests and H2 mean for your API and clients in the future.

Davey Shafik

November 22, 2015
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. H T T P/ 2 A N D A SY

    N C H R O N O U S A P I S
  2. D AV E Y S H A F I K

    • Author of Zend PHP 5 Certification Study Guide, Sitepoints PHP Anthology: 101 Essential Tips, Tricks & Hacks & PHP Master: Write Cutting Edge Code • A contributor to Zend Framework 1 & 2, phpdoc, & PHP internals • Original creator of PHAR/ PHP_Archive • @dshafik
  3. h tt p : / /d e v e l

    o p e r. a ka m a i .co m
  4. Let’s&start&a&conversation&about& mental&health&in&tech mhprompt.org/support

  5. H T T P/ 2 A KA : H 2

  6. None
  7. W H AT I S H T T P/ 2

    ? CC-BY:
  8. R F C 7 5 4 0 H Y P

    E RT E XT T R A N S F E R P R OTO CO L V E RS I O N 2
  9. R F C 7 5 4 1 H PA C

    K - H E A D E R CO M P R E SS I O N FO R H T T P/ 2
  10. C R E AT E D BY I E T

    F H T T P W O R K I N G G R O U P C H A I R E D BY A K A M A I ' S M A R K N OT T I N G H A M
  11. –J O H N N Y A P P L

    E S E E D CC-BY: 1991 1996 1999 HTTP/0.9 HTTP/1.0 HTTP/1.1 2015 HTTP/2 2009 SPDY
  12. B R O W S E R S U P

    P O RT • Chrome + Chrome Mobile • Firefox • IE 11 on Windows 10 • MS Edge • Safari (El Capitan/iOS 9) • Opera
  13. B I N A R Y I N ST E

    A D O F T E XT CC-BY:
  14. F U L LY M U LT I P L

    E X E D CC-BY: I N S T E A D O F O R D E R E D A N D B L O C K I N G
  15. C A N US E O N E CO N

    N E CT I O N 
 FO R PA R A L L E L R E Q U E STS CC-BY: Alosh Bennett
  16. US E S H E A D E R CO

    M P R E SS I O N CC-BY-SA: R E D U C E S O V E R H E A D
  17. S E R V E R P U S H

    I S S U P E R CO O L ( N O R E A L LY ) CC-BY-SA:
  18. S E R V E R P U S H

    • Allows the server to proactively push assets like stylesheets and images to the client without them needing to parse the HTML page and make subsequent requests • Done by pushing the assets into the client cache, avoiding the roundtrip necessary to pull them up once the client makes the request
  19. W H AT D O E S H T T

    P/ 2 M E A N F O R M Y A P P L I C AT I O N ?
  20. T R A N S PA R E N T

    CC-BY-SA: H A N D L E D B Y N G I N X / A PA C H E
  21. S O W H AT ’ S T H E

    P O I N T ?
  22. H T T P/ 1 . X S U C

    K S CC-BY: Flóra Soós
  23. H T T P/ 1 . X S U C

    K S • Minify + Concat JavaScript and CSS • Inlining small JavaScript and CSS • Using image sprites • Using data: URIs • Domain sharding
  24. T H E S E T H I N G

    S A R E A L L " C L E V E R " H AC K S CC-BY: Matt Biddulph
  25. R E M E M B E R T H

    I S ? CC-BY: C A N US E O N E CO N N E CT I O N 
 FO R PA R A L L E L R E Q U E STS
  26. U P LO A D I N G M U

    LT I P L E I M A G E S CC-BY:
  27. S E R I A L U P LO A

    D S Ȑ
  28. S E R I A L U P LO A

    D S Ȑ
  29. S E R I A L U P LO A

    D S Ȑ
  30. S E R I A L U P LO A

    D S Ȑ 
  31. S E R I A L U P LO A

    D S Ȑ 
  32. S E R I A L U P LO A

    D S Ȑ  
  33. S E R I A L U P LO A

    D S Ȑ   
  34. CO N CU R R E N T Ȑ 

  35. CO N CU R R E N T Ȑ 

  36. CO N CU R R E N T Ȑ 

  37. CO N CU R R E N T Ȑ 

  38. CO N CU R R E N T Ȑ 

  39. A P I S

  40. F E TC H I N G A B LO

    G P O ST + CO M M E N TS CC-BY:
  41. Ȑ

  42. Ȑ

  43. Ȑ GET /post/1

  44. Ȑ GET /post/1 200 OK application/json

  45. { "type": "post", "id": "1", "title": "JSON API paints my

    bikeshed!", "tags": ["json", "api", "relationships"], "author": "http://example.com/posts/1/author", "comments": "http://example.com/posts/1/comments" }
  46. Ȑ

  47. Ȑ

  48. Ȑ GET /posts/1/comments

  49. Ȑ GET /posts/1/comments 200 OK application/json

  50. [ "http://example.org/post/1/comment/1", "http://example.org/post/1/comment/2", "http://example.org/post/1/comment/3", "http://example.org/post/1/comment/4" ]

  51. Ȑ

  52. Ȑ

  53. Ȑ GET /post/example/comments/1

  54. Ȑ GET /post/example/comments/ 200 OK application/json 1

  55. 2 Ȑ GET /post/example/comments/ 200 OK application/json 1

  56. 2 3 Ȑ GET /post/example/comments/ 200 OK application/json 1

  57. 2 3 4 Ȑ GET /post/example/comments/ 200 OK application/json 1

  58. { "type": "comment", "id": "1", "title": "FIRST!", "author": "http://example.com/post/1/comment/1/author" }

  59. 6 requests (possibly connections)

  60. 14 requests (possibly connections)

  61. M U LT I P L E X E D

    Ȑ
  62. M U LT I P L E X E D

    Ȑ GET /post/example/comments/3
  63. M U LT I P L E X E D

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1
  64. M U LT I P L E X E D

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1 GET /post/example/comments/2
  65. M U LT I P L E X E D

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1 GET /post/example/comments/2 200 OK application/json
  66. M U LT I P L E X E D

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1 GET /post/example/comments/2 200 OK application/json 200 OK application/json
  67. M U LT I P L E X E D

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1 GET /post/example/comments/2 200 OK application/json 200 OK application/json 200 OK application/json
  68. CO D E

  69. $numRequests = 378;

  70. None
  71. H T T P/ 1 . 1 : SY N

    C H R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_exec($ch); curl_close($ch); }
  72. H T T P/ 1 . 1 : SY N

    C H R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_exec($ch); curl_close($ch); }
  73. H T T P/ 1 . 1 : SY N

    C H R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_exec($ch); curl_close($ch); }
  74. H T T P/ 1 . 1 : SY N

    C H R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_exec($ch); curl_close($ch); }
  75. H T T P/ 1 . 1 : SY N

    C H R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_exec($ch); curl_close($ch); }
  76. 4 7 . 6 7 
 s e co n

    d s CC-BY:
  77. H T T P/ 2 : SY N C H

    R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_setopt($ch, CURLOPT_HTTP_VERSION, HTTP_VERSION_2_0); curl_exec($ch); curl_close($ch); }
  78. H T T P/ 2 : SY N C H

    R O N O US $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests; $i++) { $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, $i); curl_setopt($ch, CURLOPT_HTTP_VERSION, HTTP_VERSION_2_0); curl_exec($ch); curl_close($ch); }
  79. 6 2 . 1 9 
 s e co n

    d s CC-BY-NC:
  80. $mh = curl_multi_init();
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0;

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, ‘%d'); curl_multi_add_handle($mh, $ch); } H T T P/ 1 . 1 : CO N CU R R E N T
  81. $mh = curl_multi_init();
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0;

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, ‘%d'); curl_multi_add_handle($mh, $ch); } H T T P/ 1 . 1 : CO N CU R R E N T
  82. $mh = curl_multi_init();
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0;

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, ‘%d'); curl_multi_add_handle($mh, $ch); } H T T P/ 1 . 1 : CO N CU R R E N T
  83. $mh = curl_multi_init();
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0;

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, ‘%d'); curl_multi_add_handle($mh, $ch); } H T T P/ 1 . 1 : CO N CU R R E N T
  84. H T T P/ 1 . 1 : CO N

    CU R R E N T ( CO N T. ) do { $exec = curl_multi_exec($mh, $running); } while ($exec == CURLM_CALL_MULTI_PERFORM); while ($running && $exec == CURLM_OK) { $ready = curl_multi_select($mh); if ($ready != -1) { do { $exec = curl_multi_exec($mh, $running);
 } while ($exec == CURLM_CALL_MULTI_PERFORM); } }
  85. 8 . 6 6 
 s e co n d

    s
  86. $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0; $i <= $numRequests;

    $i++) { $handles[] = $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, ‘%d'); curl_multi_add_handle($mh, $ch); } H T T P/ 2 : M U LT I P L E X E D $mh = curl_multi_init();
  87. $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0; $i <= $numRequests;

    $i++) { $handles[] = $ch = curl_init(); $conf[CURLOPT_URL] = sprintf($url, ‘%d'); curl_multi_add_handle($mh, $ch); } H T T P/ 2 : M U LT I P L E X E D curl_multi_setopt($mh,
 CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX ); $mh = curl_multi_init();
  88. H T T P/ 2 : M U LT I

    P L E X E D ( CO N T. ) do { $exec = curl_multi_exec($mh, $running); } while ($exec == CURLM_CALL_MULTI_PERFORM); while ($running && $exec == CURLM_OK) { $ready = curl_multi_select($mh); if ($ready != -1) { do { $exec = curl_multi_exec($mh, $running);
 } while ($exec == CURLM_CALL_MULTI_PERFORM); } }
  89. 2 . 1 4 
 s e co n d

    s CC-BY:
  90. H T T P/ 2 N E G OT I

    AT I O N CC-BY-ND:
  91. P R OTO CO L I D E N T

    I F I E RS • h2 — HTTP/2 over TLS, negotiated via ALPN (Application-Layer Protocol Negotiation) • h2c — HTTP/2 over TCP (plain text), uses an HTTP/1.1 request with a 101 Switching Protocols status response if supported
  92. – W I K I P E D I A

    /A P P L I C AT I O N - L AY E R _ P R OTO CO L _ N E G OT I AT I O N Application-Layer Protocol Negotiation (ALPN) is a Transport Layer Security (TLS) extension for application layer protocol negotiation. ALPN allows the application layer to negotiate which protocol should be performed over a secure connection in a manner which avoids additional round trips and which is independent of the application layer protocols. It is used by HTTP/2. […] On July 11, 2014, ALPN was published as RFC 7301
  93. H 2 C U P G R A D E

    N E G OT I AT I O N > GET / HTTP/1.1 > Host: server.example.com > Connection: Upgrade, HTTP2-Settings > Upgrade: h2c > HTTP2-Settings: <base64url SETTINGS payload> < HTTP/1.1 101 Switching Protocols < Connection: Upgrade < Upgrade: h2c < < [ HTTP/2 connection ...
  94. H 2 C U P G R A D E

    N E G OT I AT I O N ( CO N T. ) • May be an OPTIONS request if concurrency of multiple requests is important • May be any request type (e.g. PUT/POST/GET/HEAD/DELETE) but any body must be sent in it's entirety before HTTP/2 can start • A server must ignore an "h2" token in an Upgrade header field. Presence of a token with "h2" implies HTTP/2 over TLS, which is instead negotiated via TLS-ALPN • It must include a settings payload with the initial request
  95. A L L B R O W S E RS

    R E Q U I R E T LS FO R H T T P/ 2 CC-BY: Jason Baker
  96. D I R E CT CO N N E CT

    W I T H H T T P/ 2
  97. P R I O R K N O W L

    E D G E • It is possible to set up a connection with HTTP/1.1 or ALPN negotiation when prior knowledge of HTTP/2 is known • Performance enhancement • Client/Server must send the HTTP/2 connection prefix • Not supported in curl yet
  98. S E R V E R P US H CC-BY:

  99. Ȑ

  100. Ȑ

  101. Ȑ GET /post/1

  102. Ȑ GET /post/1 200 OK application/json

  103. GET /post/1/comments Ȑ GET /post/1 200 OK application/json

  104. GET /post/1/comments GET /post/1/comment/1 Ȑ GET /post/1 200 OK application/json

  105. Ȑ GET /post/1/comments GET /post/1/comment/1

  106. Ȑ GET /post/1/comment/2 GET /post/1/comment/3 GET /post/1/comment/4 GET /post/1/comments GET

    /post/1/comment/1
  107. Ȑ GET /post/1/comment/2 GET /post/1/comment/3 GET /post/1/comment/4 GET /post/1/comment/1/author GET

    /post/1/comment/2/author GET /post/1/comment/3/author GET /post/1/comment/4/author GET /post/1/comments GET /post/1/comment/1
  108. Ȑ GET /post/1/comment/2 GET /post/1/comment/3 GET /post/1/comment/4 GET /post/1/comment/1/author GET

    /post/1/comment/2/author GET /post/1/comment/3/author GET /post/1/comment/4/author GET /post/1/comment/1/author/avatar.png GET /post/1/comment/2/author/avatar.png GET /post/1/comment/3/author/avatar.png GET /post/1/comment/4/author/avatar.png GET /post/1/comments GET /post/1/comment/1
  109. CSS /J S M I N I F I C

    AT I O N I S U N E C E SS A R Y CC-BY: G Z I P CO M P R E SS I O N + M U LT I P L E X I N G + S E R V E R P US H
  110. ST R E A M S CC-BY: Kylir Horton

  111. ST R E A M S • Each request/response is

    a stream • Streams are comprised of Frames • Streams may have a weight (1-256) • Streams may have a dependency
  112. ST R E A M W E I G H

    TS Stream A Weight: 1 Stream B Weight: 2 Stream C Weight: 3 2X Stream A 1.5X Stream B
 3X Stream A
  113. ST R E A M D E P E N

    D E N C I E S Stream A Stream B Depends: A Stream C Depends: B Delivered after A Delivered after B
  114. F R A M E S CC-BY: Bart Everson

  115. F R A M E S • Messages are composed

    of multiple frames, e.g. headers, data, and settings • Each frame has a common header • 9 byte, length prefixed • Easy & efficient to parse • Frames can be interleaved — this is multiplexing
  116. F R A M E S POST /search HTTP/1.1 Host:

    example.org Content-Type: application/json Content-Length: 58 {
 "keywords":"example",
 "location":"posts"
 } HEADERS
 frame Data
 frame } }
  117. H E A D E RS : H PAC K

    CC-BY-SA:
  118. H E A D E RS : H PA C

    K • Uses a table of known values as an index • Can represent a header name and value (e.g. :status: 404), or just a header name (e.g. accept:) • Values are either statically encoded, or use a static Huffman code
  119. # Name Value 1 :authority 2 :method GET 3 :method

    POST 4 :path / 5 :path /index.html 6 :scheme http 7 :scheme https 8 :status 200 9 :status 204 10 :status 206 11 :status 304 12 :status 400 13 :status 404 14 :status 500 15 accept-charset
  120. A KA M A I { O P E N

    } E D G E G R I D F O R P H P
  121. W E US E G U ZZ L E

  122. G U ZZ L E S U P P O

    RT • Some support • Doesn’t handle lack of http2 support in libcurl • Doesn’t handle multiplexing • Untested (but should be OK, as libcurl itself is tested) • Details: http://daveyshafik.com/guzzle-http2
  123. CO D E CC-BY:

  124. H T T P/ 1 . 1 : SY N

    C H R O N O US use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(); for ($i = 0; $i <= $numRequests; $i++) { $client->get(sprintf($url, $i)); }
  125. H T T P/ 1 . 1 : SY N

    C H R O N O US use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(); for ($i = 0; $i <= $numRequests; $i++) { $client->get(sprintf($url, $i)); }
  126. H T T P/ 1 . 1 : SY N

    C H R O N O US use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(); for ($i = 0; $i <= $numRequests; $i++) { $client->get(sprintf($url, $i)); }
  127. H T T P/ 1 . 1 : SY N

    C H R O N O US use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(); for ($i = 0; $i <= $numRequests; $i++) { $client->getAsync(sprintf($url, $i)); } $results = Promise\unwrap($promises);
  128. H T T P/ 1 . 1 : SY N

    C H R O N O US use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(); for ($i = 0; $i <= $numRequests; $i++) { $client->getAsync(sprintf($url, $i)); } $results = Promise\unwrap($promises);
  129. H T T P/ 1 . 1 : SY N

    C H R O N O US use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(); for ($i = 0; $i <= $numRequests; $i++) { $client->getAsync(sprintf($url, $i)); } $results = Promise\unwrap($promises);
  130. use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(

    for ($i = 0; $i <= $numRequests; $i++) { $client->get(sprintf($url, $i)); } H T T P/ 2 . 0 : SY N C H R O N O US );
  131. use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(

    for ($i = 0; $i <= $numRequests; $i++) { $client->get(sprintf($url, $i)); } ['version' => 2] H T T P/ 2 . 0 : SY N C H R O N O US );
  132. H T T P/ 2 : M U LT I

    P L E X E D use GuzzleHttp\Client; 
 $url = 'https://http2.akamai.com/demo/tile-%d.png';
 $client = new Client(['version' => 2]); for ($i = 0; $i <= $numRequests; $i++) { $client->getAsync(sprintf($url, $i)); } $results = Promise\unwrap($promises);
  133. H T T P/ 1 . 1 : CO N

    CU R R E N T U P LOA D S use \Akamai\NetStorage\Handler\Authentication as AuthHandler; use \Akamai\NetStorage\Authentication; $stack = \GuzzleHttp\HandlerStack::create(); 
 $handler = new AuthHandler();
 $handler->setSigner( (new Authentication())->setKey($key, $keyName) ); $client = new Akamai\Edgegrid\Open\Client([ 'handler' => $stack ]);
  134. $url = "http://example.akamaihd.net/cpCode/%s";
 foreach ($_FILES as $file) { $fileName =

    Ramsey\Uuid\Uuid::uuid4(); $promises = $client->putAsync(
 sprintf($url, $filename), 
 [ 'body' => fopen($file['tmp_name'], 'r+') ] ); }
 $results = Promise\unwrap($promises); H T T P/ 2 : M U LT I P L E X E D F I L E U P LO A D ( CO N T. )
  135. $url = "http://example.akamaihd.net/cpCode/%s";
 foreach ($_FILES as $file) { $fileName =

    Ramsey\Uuid\Uuid::uuid4(); $promises = $client->putAsync(
 sprintf($url, $filename), 
 [ 'body' => fopen($file['tmp_name'], 'r+') ] ); }
 $results = Promise\unwrap($promises); H T T P/ 2 : M U LT I P L E X E D F I L E U P LO A D ( CO N T. )
  136. $url = "http://example.akamaihd.net/cpCode/%s";
 foreach ($_FILES as $file) { $fileName =

    Ramsey\Uuid\Uuid::uuid4(); $promises = $client->putAsync(
 sprintf($url, $filename), 
 [ 'body' => fopen($file['tmp_name'], 'r+') ] ); }
 $results = Promise\unwrap($promises); H T T P/ 2 : M U LT I P L E X E D F I L E U P LO A D ( CO N T. )
  137. $url = "http://example.akamaihd.net/cpCode/%s";
 foreach ($_FILES as $file) { $fileName =

    Ramsey\Uuid\Uuid::uuid4(); $promises = $client->putAsync(
 sprintf($url, $filename), 
 [ 'body' => fopen($file['tmp_name'], 'r+') ] ); }
 $results = Promise\unwrap($promises); H T T P/ 2 : M U LT I P L E X E D F I L E U P LO A D ( CO N T. )
  138. $url = "http://example.akamaihd.net/cpCode/%s";
 foreach ($_FILES as $file) { $fileName =

    Ramsey\Uuid\Uuid::uuid4(); $promises = $client->putAsync(
 sprintf($url, $filename), 
 [ 'body' => fopen($file['tmp_name'], 'r+') ] ); }
 $results = Promise\unwrap($promises); H T T P/ 2 : M U LT I P L E X E D F I L E U P LO A D ( CO N T. )
  139. H T T P/ 2 : M U LT I

    P L E X E D F I L E U P LO A D ( P O S S I B L E A P I ) use \Akamai\NetStorage\Handler\Authentication as AuthHandler; use \Akamai\NetStorage\Authentication; $stack = \GuzzleHttp\HandlerStack::create(); 
 $handler = new AuthHandler();
 $handler->setSigner( (new Authentication())->setKey($key, $keyName) ); $client = new Akamai\Edgegrid\Open\Client([ 'handler' => $stack, 
 'version' => 2 ]);
  140. H T T P/ 2 : M U LT I

    P L E X E D F I L E U P LO A D ( P O S S I B L E A P I ) use \Akamai\NetStorage\Handler\Authentication as AuthHandler; use \Akamai\NetStorage\Authentication; $stack = \GuzzleHttp\HandlerStack::create(); 
 $handler = new AuthHandler();
 $handler->setSigner( (new Authentication())->setKey($key, $keyName) ); $client = new Akamai\Edgegrid\Open\Client([ 'handler' => $stack, 
 'version' => 2 ]);
  141. $url = "http://example.akamaihd.net/cpCode/%s";
 foreach ($_FILES as $file) { $fileName =

    Ramsey\Uuid\Uuid::uuid4(); $promises = $client->putAsync(
 sprintf($url, $filename), 
 [ 'body' => fopen($file['tmp_name'], 'r+') ] ); }
 $results = Promise\unwrap($promises); H T T P/ 2 : M U LT I P L E X E D F I L E U P LO A D ( CO N T. )
  142. R FC : CU R L H T T P/

    2 P US H S U P P O RT https://daveyshafik.com/curl-http2-push
  143. I N S U M M A R Y

  144. N O M O R E H AC K S

    !
  145. H U G E P E R FO R M

    A N C E W I N S
  146. 6 0 % + M A R K E T

    S H A R E
  147. H T T P / 2 I S A W

    E S O M E ! CC-BY-SA:
  148. F E E D B A C K & Q

    U E S T I O N S Twitter: Email: Slides: @dshafik dshafik@akamai.com http://daveyshafik.com/slides