Skip to content

_was_pushed in chrome is inconsistent #261

@worenga

Description

@worenga

Currently, i am performing measurements with pages that use HTTP/2 Server push.

However, i found that the "_was_pushed" key in the har of browsertime is inaccurate or misleading.
Note for all Websites presented here i am not affiliated with any of them. They are just examples and came up in a scan.
I stumbled upon a multitude of anomalies here are some examples:

  1. ) Example Website: https://erisrenee.com/

This website pushes 3 resources:

nghttp https://erisrenee.com -v | grep -C4 PUSH
[  0.601] recv (stream_id=13) :path: /assets/css/screen.css?v=84ca1c7d60
[  0.601] recv (stream_id=13) :scheme: https
[  0.601] recv (stream_id=13, sensitive) accept-encoding: gzip, deflate
[  0.601] recv (stream_id=13, sensitive) user-agent: nghttp2/1.14.0-DEV
[  0.601] recv PUSH_PROMISE frame <length=74, flags=0x04, stream_id=13>
          ; END_HEADERS
          (padlen=0, promised_stream_id=2)
[  0.601] recv (stream_id=13) :authority: erisrenee.com
[  0.601] recv (stream_id=13) :method: GET
[  0.601] recv (stream_id=13) :path: /assets/css/github.css?v=84ca1c7d60
[  0.601] recv (stream_id=13) :scheme: https
[  0.601] recv (stream_id=13, sensitive) accept-encoding: gzip, deflate
[  0.601] recv (stream_id=13, sensitive) user-agent: nghttp2/1.14.0-DEV
[  0.601] recv PUSH_PROMISE frame <length=74, flags=0x04, stream_id=13>
          ; END_HEADERS
          (padlen=0, promised_stream_id=4)
[  0.601] recv (stream_id=13) :authority: erisrenee.com
[  0.601] recv (stream_id=13) :method: GET
[  0.601] recv (stream_id=13) :path: /assets/js/index.js?v=84ca1c7d60
[  0.601] recv (stream_id=13) :scheme: https
[  0.601] recv (stream_id=13, sensitive) accept-encoding: gzip, deflate
[  0.601] recv (stream_id=13, sensitive) user-agent: nghttp2/1.14.0-DEV
[  0.601] recv PUSH_PROMISE frame <length=73, flags=0x04, stream_id=13>

/assets/css/screen.css?v=84ca1c7d60,
/assets/css/github.css?v=84ca1c7d60, and
/assets/js/index.js?v=84ca1c7d60.

Now lets open the page manually in chrome and see whether these resources appear in the network view.
Screenshot: https://www.dropbox.com/s/kj9aesotzxb7na3/Selection_006.png?dl=0
In this scenario it is a cloudflare-hosted website so cloudflare even tells us what has been pushed:

cf-h2-pushed:</assets/css/screen.css?v=84ca1c7d60>,</assets/css/github.css?v=84ca1c7d60>,</assets/js/index.js?v=84ca1c7d60>

As expected we discover the .css files, but where is the index.js?
A look into the source shows

<script data-rocketsrc="/assets/js/index.js?v=84ca1c7d60" type="text/rocketscript"></script>

So it is loaded using cloudflares rocket loader.
After a long search for the resource we find it is included in some XHR call.
Screenshot: https://www.dropbox.com/s/82qmlq3r1u6t214/Screenshot%20at%202017-02-07%2017%3A38%3A22.png?dl=0

Since the resource was pushed and is now requested again using javascript does that mean the push was useless? I don't know. But let's now request the page with browsertime.

➜  browsertime git:(master) ✗ mkdir enisrenee && cd enisrenee
➜  enisrenee git:(master) ✗ ../bin/browsertime.js https://erisrenee.com/
[2017-02-07 17:41:41] Running chrome for url: https://erisrenee.com/
[2017-02-07 17:41:41] Testing url https://erisrenee.com/ run 1
[2017-02-07 17:41:45] Testing url https://erisrenee.com/ run 2
[2017-02-07 17:41:49] Testing url https://erisrenee.com/ run 3
[2017-02-07 17:41:53] 24 requests, 308.33 kb, firstPaint: 1.15s (±36.03ms), DOMContentLoaded: 984ms (±44.63ms), Load: 1.21s (±35.43ms), rumSpeedIndex: 1145 (±36.03) (3 runs)
[2017-02-07 17:41:53] Wrote data to browsertime-results/erisrenee.com/2017-02-07T174141+0100

Now lets see whether any pushes were recorded in the har:

➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.har | jq . | grep was_push | wc -l
0

Well weird that is weird. We know that resources are pushed from our previous exploration.

Lets see if we find the pushed resources.

➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.har | jq -cr '.log.entries[] | .request.url' | grep github.css | wc -l
0
➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.har | jq -cr '.log.entries[] | .request.url' | grep screen.css | wc -l
0
➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.har | jq -cr '.log.entries[] | .request.url' | grep index.js          
https://erisrenee.com/cdn-cgi/pe/bag2?r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F1.12.2%2Fjquery.min.js&r[]=https%3A%2F%2Ferisrenee.com%2Fassets%2Fjs%2Findex.js%3Fv%3D84ca1c7d60&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fsmooth-scroll%2F9.1.2%2Fjs%2Fsmooth-scroll.min.js&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fhighlight.js%2F9.2.0%2Fhighlight.min.js
https://erisrenee.com/cdn-cgi/pe/bag2?r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F1.12.2%2Fjquery.min.js&r[]=https%3A%2F%2Ferisrenee.com%2Fassets%2Fjs%2Findex.js%3Fv%3D84ca1c7d60&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fsmooth-scroll%2F9.1.2%2Fjs%2Fsmooth-scroll.min.js&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fhighlight.js%2F9.2.0%2Fhighlight.min.js
https://erisrenee.com/cdn-cgi/pe/bag2?r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F1.12.2%2Fjquery.min.js&r[]=https%3A%2F%2Ferisrenee.com%2Fassets%2Fjs%2Findex.js%3Fv%3D84ca1c7d60&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fsmooth-scroll%2F9.1.2%2Fjs%2Fsmooth-scroll.min.js&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fhighlight.js%2F9.2.0%2Fhighlight.min.js

So we do not find the css files in the .har and only the rocket-loader request for the index.js.

Now lets look at the browsertime.json, maybe there are some clues what is going on.

➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.json | jq . | grep screen.css
            "name": "https://erisrenee.com/assets/css/screen.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/screen.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/screen.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/screen.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/screen.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/screen.css?v=84ca1c7d60",
➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.json | jq . | grep github.css
            "name": "https://erisrenee.com/assets/css/github.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/github.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/github.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/github.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/github.css?v=84ca1c7d60",
            "name": "https://erisrenee.com/assets/css/github.css?v=84ca1c7d60",
➜  enisrenee git:(master) ✗ cat browsertime-results/erisrenee.com/2017-02-07T174141+0100/browsertime.json | jq . | grep index.js  
            "name": "https://erisrenee.com/cdn-cgi/pe/bag2?r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F1.12.2%2Fjquery.min.js&r[]=https%3A%2F%2Ferisrenee.com%2Fassets%2Fjs%2Findex.js%3Fv%3D84ca1c7d60&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fsmooth-scroll%2F9.1.2%2Fjs%2Fsmooth-scroll.min.js&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fhighlight.js%2F9.2.0%2Fhighlight.min.js",
            "name": "https://erisrenee.com/assets/js/index.js?v=84ca1c7d60",
            "name": "https://erisrenee.com/cdn-cgi/pe/bag2?r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F1.12.2%2Fjquery.min.js&r[]=https%3A%2F%2Ferisrenee.com%2Fassets%2Fjs%2Findex.js%3Fv%3D84ca1c7d60&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fsmooth-scroll%2F9.1.2%2Fjs%2Fsmooth-scroll.min.js&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fhighlight.js%2F9.2.0%2Fhighlight.min.js",
            "name": "https://erisrenee.com/assets/js/index.js?v=84ca1c7d60",
            "name": "https://erisrenee.com/cdn-cgi/pe/bag2?r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F1.12.2%2Fjquery.min.js&r[]=https%3A%2F%2Ferisrenee.com%2Fassets%2Fjs%2Findex.js%3Fv%3D84ca1c7d60&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fsmooth-scroll%2F9.1.2%2Fjs%2Fsmooth-scroll.min.js&r[]=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fhighlight.js%2F9.2.0%2Fhighlight.min.js",
            "name": "https://erisrenee.com/assets/js/index.js?v=84ca1c7d60",

So the css appears twice each run with different timings and the index.js appears once for the push and once for the rocket loader. This is very weird.
HAR: https://gist.github.com/worenga/cfd6cfaefe606f27b37153f4e1d6bef2
JSON: https://gist.github.com/worenga/c3e6d6c2069c750e2dbf67efec3bbc76

  1. ) Example
    Example Website: https://www.thecopycamp.com
    Again, not affiliated in any kind.
    Note that this website pushes 13 resources.
➜  ~ nghttp https://www.photographerstechsupport.com -v | grep PUSH
[  0.691] recv PUSH_PROMISE frame <length=91, flags=0x04, stream_id=13>
[  0.691] recv PUSH_PROMISE frame <length=104, flags=0x04, stream_id=13>
[  0.691] recv PUSH_PROMISE frame <length=90, flags=0x04, stream_id=13>
[  0.691] recv PUSH_PROMISE frame <length=96, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=88, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=96, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=94, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=93, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=110, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=103, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=103, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=104, flags=0x04, stream_id=13>
[  0.692] recv PUSH_PROMISE frame <length=86, flags=0x04, stream_id=13>
➜  ~ nghttp https://www.photographerstechsupport.com -v | grep PUSH | wc -l
13

Also in chrome we see 13 pushes:
https://www.dropbox.com/s/mt4q1tqe8ddgji3/Selection_009.png?dl=0

Now lets fetch this page using browsertime:

➜  browsertime git:(master) ✗ ./bin/browsertime.js https://www.photographerstechsupport.com 
[2017-02-07 18:29:41] Running chrome for url: https://www.photographerstechsupport.com
[2017-02-07 18:29:41] Testing url https://www.photographerstechsupport.com run 1
[2017-02-07 18:29:45] Testing url https://www.photographerstechsupport.com run 2
[2017-02-07 18:29:49] Testing url https://www.photographerstechsupport.com run 3
[2017-02-07 18:29:52] 9 requests, 110.11 kb, firstPaint: 807ms (±121.39ms), DOMContentLoaded: 820ms (±121.76ms), Load: 872ms (±123.10ms), rumSpeedIndex: 807 (±121.39) (3 runs)
[2017-02-07 18:29:52] Wrote data to browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100

lets scan the HAR file

➜  browsertime git:(master) ✗ cat browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100/browsertime.har| jq . | grep -i push
              "name": "cf-h2-pushed",
              "name": "cf-h2-pushed",
        "_was_pushed": 1,
              "name": "cf-h2-pushed",
        "_was_pushed": 1,
        "_was_pushed": 1,

These are clearly not 13*3 resources...,

➜  browsertime git:(master) ✗ cat browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100/browsertime.har| jq  -r '.log.entries[] | select(contains({'_was_pushed'})) | "\(.pageref): \(.request.url)"'
page_1-1: https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js
page_1-1-1: https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js
page_1-1-1: https://www.photographerstechsupport.com/wp-content/themes/interface/js/jquery.cycle.all.min.js

So according to the har, in the 1st run nothing was pushed, in the 2nd run jquery.js was pushed and in the 3rd run jquery.js and jquery.cycle.all.min.js were pushed.

Now we know that for example jquery.js and style.css were pushed, but are they contained in the har?

➜  browsertime git:(master) ✗ cat browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100/browsertime.har| jq  -r '.log.entries[] | select(.request.url | contains("jquery.js")) | "\(.pageref): \(.request.url)"'  
page_1-1: https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js
page_1-1-1: https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js
➜  browsertime git:(master) ✗ cat browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100/browsertime.har| jq  -r '.log.entries[] | select(.request.url | contains("style.css")) | "\(.pageref): \(.request.url)"'  | wc -l
0

Now what about browsertime.json?

➜  browsertime git:(master) ✗ cat browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100/browsertime.json | jq . | grep style.css
            "name": "https://www.photographerstechsupport.com/wp-content/themes/interface/style.css",
            "name": "https://www.photographerstechsupport.com/wp-content/themes/interface/style.css",
            "name": "https://www.photographerstechsupport.com/wp-content/themes/interface/style.css",
➜  browsertime git:(master) ✗ cat browsertime-results/www.photographerstechsupport.com/2017-02-07T182941+0100/browsertime.json | jq . | grep jquery.js 
            "name": "https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js",
            "name": "https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js",
            "name": "https://www.photographerstechsupport.com/wp-includes/js/jquery/jquery.js",

This is weird as well.
HAR: https://gist.github.com/worenga/eae418783fde60278787806404775584
JSON: https://gist.github.com/worenga/371766ad2379f5b660c9f71e72dd7408

Is there a reliable way to tell which and whether resources have been pushed?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions