[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.

Fee39f0c0ffb29d9ac21607ed188be6b?s=128

Davey Shafik

October 19, 2016
Tweet

Transcript

  1. 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. 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. 3.

    Ȑ

  4. 4.

    Ȑ

  5. 7.

    { "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. 8.

    { "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. 9.

    Ȑ

  8. 10.

    Ȑ

  9. 14.

    Ȑ

  10. 15.

    Ȑ

  11. 26.

    M U LT I P L E X E D

    Ȑ GET /post/example/comments/3
  12. 27.

    M U LT I P L E X E D

    Ȑ GET /post/example/comments/3 GET /post/example/comments/1
  13. 28.

    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. 29.

    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. 30.

    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. 31.

    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. 32.

    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. 34.

    { "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. 35.

    { "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. 36.

    { "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. 37.

    "gravatar": "fee39f0c0ffb29d9ac21607ed188be6b" }, "comments": [ { "type": "comment", "id": "1",

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

    } }, { "type": "comment", "id": "3", "content": "third", "author":

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

    } }, { "type": "comment", "id": "3", "content": "third", "author":

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

    } }, { "type": "comment", "id": "4", "content": "fourth", "author":

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

    Ȑ

  27. 43.

    Ȑ

  28. 50.

    Ȑ 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
  29. 51.

    Ȑ 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
  30. 52.

    D E P E N D E N C I

    E S CC-BY-SA 2.0: David Gamez
  31. 55.

    A P I R E Q U E ST GET

    /post/1 Ɇ ɂ Ȑ
  32. 56.

    A P I R E Q U E ST GET

    /post/1 200 OK application/json Ɇ ɂ Ȑ
  33. 57.

    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
  34. 58.

    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
  35. 59.

    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/…
  36. 60.

    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/…
  37. 61.

    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/…
  38. 62.

    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/…
  39. 63.
  40. 65.
  41. 66.

    $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. 67.

    $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. 68.

    $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. 69.

    $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
  45. 70.

    $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
  46. 71.

    $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
  47. 72.

    4 7 . 6 7 
 s e co n

    d s CC-BY: Hernán Piñera
  48. 73.

    $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
  49. 74.

    $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
  50. 75.

    $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
  51. 76.

    $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
  52. 77.

    $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
  53. 78.

    $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
  54. 79.

    6 2 . 1 9 
 s e co n

    d s CC-BY-NC: Scott Beckner
  55. 80.

    $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. 81.

    $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
  57. 82.

    $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
  58. 83.

    $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
  59. 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); } }
  60. 86.

    $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();
  61. 87.

    $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;
  62. 88.

    $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
 );
  63. 89.

    $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
 );
  64. 90.

    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); } }
  65. 91.

    2 . 1 4 
 s e co n d

    s CC-BY: motoracereports
  66. 92.

    H A N D L I N G S E

    R V E R P US H
  67. 93.

    $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);
  68. 94.

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  69. 95.

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  70. 96.

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  71. 97.

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

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

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  73. 99.

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  74. 100.

    $transfers = 1; $cb = function( $parent, $pushed, $headers )

    use (&$transfers) { $transfers++; // increment to keep track of return CURL_PUSH_OK; }; $mh = curl_multi_init();
  75. 101.

    $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. 102.

    $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. 103.

    $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/"
 );
  78. 104.

    $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/"
 );
  79. 105.

    $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/"
 );
  80. 106.

    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 {
  81. 107.

    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 {
  82. 108.

    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 {
  83. 109.

    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. 110.

    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. 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--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  86. 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--; // remaining requests $out = curl_multi_getcontent(
 $info['handle']
 ); // Response body
  87. 113.

    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
  88. 114.

    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
  89. 115.

    $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. 116.

    $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);
  91. 117.

    $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);
  92. 118.

    $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);
  93. 119.

    B LO G A P I + S E R

    V E R P U S H
  94. 120.

    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) {
  95. 121.

    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. 122.

    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,
  97. 123.

    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,
  98. 124.

    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,
  99. 125.

    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; } }
  100. 126.

    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; } }
  101. 127.

    static function add($handle) { $found = false; foreach (self::$pushHandles as

    $url => $h) { if ($handle == $h) { $found = $url; } } if (!$found) { $found = curl_getinfo($handle)['url']; }
  102. 128.

    static function add($handle) { $found = false; foreach (self::$pushHandles as

    $url => $h) { if ($handle == $h) { $found = $url; } } if (!$found) { $found = curl_getinfo($handle)['url']; }
  103. 129.

    static function add($handle) { $found = false; foreach (self::$pushHandles as

    $url => $h) { if ($handle == $h) { $found = $url; } } if (!$found) { $found = curl_getinfo($handle)['url']; }
  104. 130.

    self::$cache[$found] = 
 curl_multi_getcontent($handle); } static function exists($url) { if

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

    self::$cache[$found] = 
 curl_multi_getcontent($handle); } static function exists($url) { if

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

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

    static function get($url) { return self::$cache[$url]; } }
  107. 133.

    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
  108. 134.

    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. 135.

    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,
  110. 136.

    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,
  111. 137.

    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,
  112. 138.

    $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
  113. 139.

    $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
  114. 140.

    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,
  115. 141.

    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,
  116. 142.

    $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); }
  117. 143.

    $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); }
  118. 144.

    $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. 145.

    $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. 146.

    $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);
  121. 147.

    $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);
  122. 148.

    $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);
  123. 149.

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