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.

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);