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

[Edge 2016] HTTP/2 and Asynchronous APIs

[Edge 2016] 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 how to handle HTTP/2 Server Push programmatically, and how it can affect your application architecture.

Avatar for Davey Shafik

Davey Shafik

October 19, 2016
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. F E TC H I N G A B LO

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

  4. Ȑ

  5. { "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" }
  6. { "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" }
  7. Ȑ

  8. Ȑ

  9. Ȑ

  10. Ȑ

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

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

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1
  13. 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
  14. 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
  15. 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
  16. 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
  17. S T I L L M A K I N

    G L O T S O F R E Q U E S T S
  18. { "type": "post", "id": "1", "title": "JSON API paints my

    bikeshed!", "tags": ["json", "api", "relationships"], "author": { "type": "author", "id": 1, "name": "Davey Shafik", "twitter": "@dshafik", "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" }, "comments": [ { "type": "comment", "id": "1", "content": "FIRST!", "author": { "type": "author", "id": 2, "name": "Jill Random", "gravatar": "706b16b2fb732ab6079a10fea61d078b" } }, { "type": "comment", "id": "2", "content": "second", "author": { "type": "author", "id": 3, "name": "John Person", "gravatar": "8e2279479945ca4778eb3cb8d88cda58" } }, { "type": "comment", "id": "3", "content": "third", "author": { "type": "author", "id": 1, "name": "Davey Shafik", "twitter": "@dshafik", "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" } }, { "type": "comment", "id": "4", "content": "fourth", "author": { "type": "author", "id": 2, "name": "Jill Random", "gravatar": "706b16b2fb732ab6079a10fea61d078b" } } ] }
  19. { "type": "post", "id": "1", "title": "JSON API paints my

    bikeshed!", "tags": ["json", "api", "relationships"], "author": { "type": "author", "id": 1, "name": "Davey Shafik", "twitter": "@dshafik", "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" }, "comments": [ { "type": "comment", "id": "1",
  20. { "type": "post", "id": "1", "title": "JSON API paints my

    bikeshed!", "tags": ["json", "api", "relationships"], "author": { "type": "author", "id": 1, "name": "Davey Shafik", "twitter": "@dshafik", "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" }, "comments": [ { "type": "comment", "id": "1",
  21. "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" }, "comments": [ { "type": "comment", "id": "1",

    "content": "FIRST!", "author": { "type": "author", "id": 2, "name": "Jill Random", "gravatar": "706b16b2fb732ab6079a10fea61d078b" } }, { "type": "comment", "id": "2",
  22. } }, { "type": "comment", "id": "3", "content": "third", "author":

    { "type": "author", "id": 1, "name": "Davey Shafik", "twitter": "@dshafik", "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" } }, { "type": "comment", "id": "4",
  23. } }, { "type": "comment", "id": "3", "content": "third", "author":

    { "type": "author", "id": 1, "name": "Davey Shafik", "twitter": "@dshafik", "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" } }, { "type": "comment", "id": "4",
  24. } }, { "type": "comment", "id": "4", "content": "fourth", "author":

    { "type": "author", "id": 2, "name": "Jill Random", "gravatar": "706b16b2fb732ab6079a10fea61d078b" } } ] }
  25. Ȑ

  26. Ȑ

  27. Ȑ 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
  28. Ȑ 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
  29. D E P E N D E N C I

    E S CC-BY-SA 2.0: David Gamez
  30. A P I R E Q U E ST GET

    /post/1 Ɇ ɂ Ȑ
  31. A P I R E Q U E ST GET

    /post/1 200 OK application/json Ɇ ɂ Ȑ
  32. S U B - R E S O U R

    C E P US H W I T H D E P E N D E N C I E S Ɇ Ȑ GET /post/1 200 OK application/json
  33. S U B - R E S O U R

    C E P US H W I T H D E P E N D E N C I E S Ɇ Ȑ GET /post/1 200 OK application/json /post/1/comments /author/1
  34. S U B - R E S O U R

    C E P US H W I T H D E P E N D E N C I E S Ɇ Ȑ GET /post/1 200 OK application/json /post/1/comments /author/1 /comment/1 /comment/…
  35. S U B - R E S O U R

    C E P US H W I T H D E P E N D E N C I E S Ɇ Ȑ GET /post/1 200 OK application/json /post/1/comments /author/1 /comment/1 /images/author/1 /comment/…
  36. S U B - R E S O U R

    C E P US H W I T H D E P E N D E N C I E S Ɇ Ȑ GET /post/1 200 OK application/json /post/1/comments /author/1 /comment/1 /author/2 /images/author/1 /comment/…
  37. S U B - R E S O U R

    C E P US H W I T H D E P E N D E N C I E S Ɇ Ȑ GET /post/1 200 OK application/json /post/1/comments /author/1 /comment/1 /author/2 /images/author/1 /comment/… /author/…
  38. $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests;

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

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

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

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

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

    $i++) { $ch = curl_init();
 $opts[CURLOPT_URL] = sprintf($url, $i); curl_setopt_array($ch, $opts); curl_exec($ch); curl_close($ch); } H T T P/ 1 . 1 : SY N C H R O N O US
  44. 4 7 . 6 7 
 s e co n

    d s CC-BY: Hernán Piñera
  45. $url = 'https://http2.akamai.com/demo/tile-%d.png'; for ($i = 0; $i <= $numRequests;

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

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

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

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

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

    $i++) { $ch = curl_init();
 $opts[CURLOPT_URL] = sprintf($url, $i);
 curl_setopt_array($ch, $opts); curl_exec($ch); curl_close($ch); } $opts[CURLOPT_HTTP_VERSION] = HTTP_VERSION_2_0; H T T P/ 2 : SY N C H R O N O US
  51. 6 2 . 1 9 
 s e co n

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

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

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

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

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $opts[CURLOPT_URL] = sprintf($url, '%d');
 curl_setopt_array($ch, $opts); curl_multi_add_handle($mh, $ch); } H T T P/ 1 . 1 : CO N CU R R E N T
  56. 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); } }
  57. $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0; $i <= $numRequests;

    $i++) { $handles[] = $ch = curl_init(); $opts[CURLOPT_URL] = sprintf($url, '%d'); curl_setopt_array($ch, $opts); 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();
  58. $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0; $i <= $numRequests;

    $i++) { $handles[] = $ch = curl_init(); $opts[CURLOPT_URL] = sprintf($url, '%d'); curl_setopt_array($ch, $opts); 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(); $opts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2;
  59. $opts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2; $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0;

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $opts[CURLOPT_URL] = sprintf($url, '%d'); curl_setopt_array($ch, $opts); curl_multi_add_handle($mh, $ch); } $mh = curl_multi_init(); curl_multi_setopt(
 $mh, 
 CURLMOPT_PIPELINING, 
 CURLPIPE_MULTIPLEX
 );
  60. $opts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2; $url = 'https://http2.akamai.com/demo/tile-%d.png';
 for ($i = 0;

    $i <= $numRequests; $i++) { $handles[] = $ch = curl_init(); $opts[CURLOPT_URL] = sprintf($url, '%d'); curl_setopt_array($ch, $opts); curl_multi_add_handle($mh, $ch); } $mh = curl_multi_init(); curl_multi_setopt(
 $mh, 
 CURLMOPT_PIPELINING, 
 CURLPIPE_MULTIPLEX
 );
  61. 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); } }
  62. 2 . 1 4 
 s e co n d

    s CC-BY: motoracereports
  63. H A N D L I N G S E

    R V E R P US H
  64. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init(); curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $cb); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://localhost:8080/index.html"); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_multi_add_handle($mh, $ch); $active = null; do { $status = curl_multi_exec($mh, $active);
  65. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  66. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  67. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  68. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  69. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  70. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  71. $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  72. $mh = curl_multi_init(); curl_multi_setopt($mh, 
 CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
 ); curl_multi_setopt($mh, 


    CURLMOPT_PUSHFUNCTION, $cb
 ); $ch = curl_init(); curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 );
  73. $mh = curl_multi_init(); curl_multi_setopt($mh, 
 CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
 ); curl_multi_setopt($mh, 


    CURLMOPT_PUSHFUNCTION, $cb
 ); $ch = curl_init(); curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 );
  74. $mh = curl_multi_init(); curl_multi_setopt($mh, 
 CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
 ); curl_multi_setopt($mh, 


    CURLMOPT_PUSHFUNCTION, $cb
 ); $ch = curl_init(); curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 );
  75. $mh = curl_multi_init(); curl_multi_setopt($mh, 
 CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
 ); curl_multi_setopt($mh, 


    CURLMOPT_PUSHFUNCTION, $cb
 ); $ch = curl_init(); curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 );
  76. $mh = curl_multi_init(); curl_multi_setopt($mh, 
 CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
 ); curl_multi_setopt($mh, 


    CURLMOPT_PUSHFUNCTION, $cb
 ); $ch = curl_init(); curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 );
  77. curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 ); curl_setopt($ch, 
 CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2
 );

    curl_setopt($ch, 
 CURLOPT_RETURNTRANSFER, 1
 ); curl_multi_add_handle($mh, $ch); $active = null; do {
  78. curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 ); curl_setopt($ch, 
 CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2
 );

    curl_setopt($ch, 
 CURLOPT_RETURNTRANSFER, 1
 ); curl_multi_add_handle($mh, $ch); $active = null; do {
  79. curl_setopt($ch, 
 CURLOPT_URL, "https://localhost/"
 ); curl_setopt($ch, 
 CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2
 );

    curl_setopt($ch, 
 CURLOPT_RETURNTRANSFER, 1
 ); curl_multi_add_handle($mh, $ch); $active = null; do {
  80. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && 
 $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  81. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && 
 $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  82. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && 
 $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  83. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && 
 $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  84. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && 
 $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  85. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && 
 $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  86. $handle = $info['handle']; if ($handle !== null) { $transfers--; //

    remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body curl_multi_remove_handle($mh, $handle); curl_close($handle); } } } while ($info); } while ($transfers); curl_multi_close($mh);
  87. $handle = $info['handle']; if ($handle !== null) { $transfers--; //

    remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body curl_multi_remove_handle($mh, $handle); curl_close($handle); } } } while ($info); } while ($transfers); curl_multi_close($mh);
  88. $handle = $info['handle']; if ($handle !== null) { $transfers--; //

    remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body curl_multi_remove_handle($mh, $handle); curl_close($handle); } } } while ($info); } while ($transfers); curl_multi_close($mh);
  89. $handle = $info['handle']; if ($handle !== null) { $transfers--; //

    remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body curl_multi_remove_handle($mh, $handle); curl_close($handle); } } } while ($info); } while ($transfers); curl_multi_close($mh);
  90. B LO G A P I + S E R

    V E R P U S H
  91. class H2PushCache { static $cache = []; static $pushHandles =

    []; static function addPushHandle($headers, $handle) { foreach ($headers as $header) { if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path, $url ); self::$pushHandles[$url] = $handle; } } } static function add($handle) {
  92. class H2PushCache { static $cache = []; static $pushHandles =

    []; static function addPushHandle($headers, $handle) { foreach ($headers as $header) { if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path,
  93. class H2PushCache { static $cache = []; static $pushHandles =

    []; static function addPushHandle($headers, $handle) { foreach ($headers as $header) { if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path,
  94. class H2PushCache { static $cache = []; static $pushHandles =

    []; static function addPushHandle($headers, $handle) { foreach ($headers as $header) { if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path,
  95. class H2PushCache { static $cache = []; static $pushHandles =

    []; static function addPushHandle($headers, $handle) { foreach ($headers as $header) { if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path,
  96. static function addPushHandle($headers, $handle) { foreach ($headers as $header) {

    if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path, $url ); self::$pushHandles[$url] = $handle; } }
  97. static function addPushHandle($headers, $handle) { foreach ($headers as $header) {

    if (strpos($header, ':path:') === 0) { $path = substr($header, 6); $url = curl_getinfo($handle)['url']; $url = str_replace( parse_url($url, PHP_URL_PATH), $path, $url ); self::$pushHandles[$url] = $handle; } }
  98. static function add($handle) { $found = false; foreach (self::$pushHandles as

    $url => $h) { if ($handle == $h) { $found = $url; } } if (!$found) { $found = curl_getinfo($handle)['url']; }
  99. static function add($handle) { $found = false; foreach (self::$pushHandles as

    $url => $h) { if ($handle == $h) { $found = $url; } } if (!$found) { $found = curl_getinfo($handle)['url']; }
  100. static function add($handle) { $found = false; foreach (self::$pushHandles as

    $url => $h) { if ($handle == $h) { $found = $url; } } if (!$found) { $found = curl_getinfo($handle)['url']; }
  101. self::$cache[$found] = 
 curl_multi_getcontent($handle); } static function exists($url) { if

    (isset(self::$cache[$url])) { return true; } return false; }
  102. self::$cache[$found] = 
 curl_multi_getcontent($handle); } static function exists($url) { if

    (isset(self::$cache[$url])) { return true; } return false; }
  103. { if (isset(self::$cache[$url])) { return true; } return false; }

    static function get($url) { return self::$cache[$url]; } }
  104. function get_request($url) { if (H2PushCache::exists($url)) { return H2PushCache::get($url); } $transfers

    = 1; $cb = function ($parent, $pushed, $headers) use (&$transfers) { $transfers++; // increment to keep track of the number of concurrent requests H2PushCache::addPushHandle($headers, $pushed); return CURL_PUSH_OK; }; $mh = curl_multi_init(); curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX ); curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $cb ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url ); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2 ); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1
  105. function get_request($url) { if (H2PushCache::exists($url)) { return H2PushCache::get($url); } $transfers

    = 1; $cb = function ($parent, $pushed, $headers) use (&$transfers) { $transfers++; // increment to keep track of the number of concurrent requests H2PushCache::addPushHandle($headers,
  106. function get_request($url) { if (H2PushCache::exists($url)) { return H2PushCache::get($url); } $transfers

    = 1; $cb = function ($parent, $pushed, $headers) use (&$transfers) { $transfers++; // increment to keep track of the number of concurrent requests H2PushCache::addPushHandle($headers,
  107. function get_request($url) { if (H2PushCache::exists($url)) { return H2PushCache::get($url); } $transfers

    = 1; $cb = function ($parent, $pushed, $headers) use (&$transfers) { $transfers++; // increment to keep track of the number of concurrent requests H2PushCache::addPushHandle($headers,
  108. function get_request($url) { if (H2PushCache::exists($url)) { return H2PushCache::get($url); } $transfers

    = 1; $cb = function ($parent, $pushed, $headers) use (&$transfers) { $transfers++; // increment to keep track of the number of concurrent requests H2PushCache::addPushHandle($headers,
  109. $transfers = 1; $cb = function ($parent, $pushed, $headers) use

    (&$transfers) { $transfers++; H2PushCache::addPushHandle($headers, $pushed); return CURL_PUSH_OK; }; $mh = curl_multi_init(); curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
  110. $transfers = 1; $cb = function ($parent, $pushed, $headers) use

    (&$transfers) { $transfers++; H2PushCache::addPushHandle($headers, $pushed); return CURL_PUSH_OK; }; $mh = curl_multi_init(); curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX
  111. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // decrement remaining H2PushCache::add($handle); curl_multi_remove_handle($mh,
  112. do { $status = curl_multi_exec($mh, $active); do { $info =

    curl_multi_info_read($mh); if (false !== $info && $info['msg'] == CURLMSG_DONE) { $handle = $info['handle']; if ($handle !== null) { $transfers--; // decrement remaining H2PushCache::add($handle); curl_multi_remove_handle($mh,
  113. $transfers--; // decrement remaining H2PushCache::add($handle); curl_multi_remove_handle($mh, $handle); curl_close($handle); } }

    } while ($info); } while ($transfers); curl_multi_close($mh); return H2PushCache::get($url); }
  114. $transfers--; // decrement remaining H2PushCache::add($handle); curl_multi_remove_handle($mh, $handle); curl_close($handle); } }

    } while ($info); } while ($transfers); curl_multi_close($mh); return H2PushCache::get($url); }
  115. $url = 'https://example/post/1'; $response = get_request($url); $post = json_decode($response); $response

    = get_request($post->comments); $comments = json_decode($reponse); $response = get_request($post->author); $author = json_decode($response);
  116. $url = 'https://example/post/1'; $response = get_request($url); $post = json_decode($response); $response

    = get_request($post->comments); $comments = json_decode($reponse); $response = get_request($post->author); $author = json_decode($response);
  117. $url = 'https://example/post/1'; $response = get_request($url); $post = json_decode($response); $response

    = get_request($post->comments); $comments = json_decode($reponse); $response = get_request($post->author); $author = json_decode($response);
  118. $url = 'https://example/post/1'; $response = get_request($url); $post = json_decode($response); $response

    = get_request($post->comments); $comments = json_decode($reponse); $response = get_request($post->author); $author = json_decode($response);
  119. $url = 'https://example/post/1'; $response = get_request($url); $post = json_decode($response); $response

    = get_request($post->comments); $comments = json_decode($reponse); $response = get_request($post->author); $author = json_decode($response);
  120. $url = 'https://example/post/1'; $response = get_request($url); $post = json_decode($response); $response

    = get_request($post->comments); $comments = json_decode($reponse); $response = get_request($post->author); $author = json_decode($response);