Web Shared Libraries
Rob Flack (flackr@google.com)
Challenges of loading libraries
Can’t we do this with caching?
a.com/
b.com/
cdn.com/lib.js
GET
GET
Cache:
a.com/
cdn.com/lib.js
❌
❌
GET
b.com/
cdn.com/lib.js
✔️
❌
Makes your server depend on external server
ERROR!
a.com/
b.com/
cdn.com/lib.js
GET
GET
Cache:
a.com/
cdn.com/lib.js
❌
❗
GET
b.com/
cdn.com/lib.js
❌
❗
GET
Double keyed caching disables this sharing
a.com/
b.com/
cdn.com/lib.js
GET
GET
A.com cache
B.com cache
a.com/
cdn.com/lib.js
❌
❌
GET
cdn.com/lib.js
b.com/
❌
❌
GET
Web Shared Libraries proposal
Use integrity checksum on resources as the cache key.
Use shared-channel URL to look up:
Web Shared Libraries proposal
Example 1: integrity
a.com/:
<script src=”lib.js” integrity=”a23c2c…”>
a.com/lib.js:
function doCoolStuff() {
...
b.com/:
<script src=”cdn.com/lib.js” integrity=”a23c2c…”>
GET
GET
Cache:
a.com/
a.com/lib.js (a23c2c…)
❌
❌
GET
b.com/
✔️
❌
cdn.com/lib.js (a23c2c…)
cdn.com/lib.js:
function doCoolStuff() {
...
Web Shared Libraries proposal
Example 2: shared-channel
a.com/:
<script src=”lib.js” shared-channel=”lib.com”>
a.com/lib.js:
function doCoolStuff() {
...
b.com/:
<script src=”cdn.com/lib.js” shared-channel=”lib.com”>
lib.com/public_key:
<public-key>
a.com/lib.js*
Cache:
a.com/
❌
❓
❌
✔️
a23c2c…
verify
❌lib.com,
GET lib.js
a23c2c…
b.com/
❌
cdn.com/lib.js*
❓
✔️
✔️lib.com,
HEAD lib.js
cdn.com/lib.js:
function doCoolStuff() {
...
Potential impact
If the top 100 libraries (based on crawl of top 10k sites) were shared in cache:
Top 500?
* Assuming double keyed caching and you visited all 10k sites
Long-term potential
With the incentive to share common packages,
Privacy concern - learning about other sites
Hi lib.js user!
a.com/:
<script src=”lib.js” integrity=”a23c2c…” onload=”fn>
function fn() {
// User visited a site that uses lib.js
}
a.com/lib.js:
<404>
GET
Cache:
a.com/
✔️
❌
a.com/lib.js (a23c2c…)
Privacy concern - cooperative tracking
a.com/:
for (let i = 0; i < 32; i++) {
if (userId & (1 << i))
load(‘/bit’ + i + ‘.js’);
}
function load(lib) {
// looks up expected checksum and
// loads the library with it.
...
}
b.com/:
// Fetching /bit* will fail if not cached.
var userId = 0;
var bits = 0;
for (let i = 0; i < 32; i++) {
load(‘/bit’ + i + ‘.js’).then(() => {
setbit(i, 1);
}).catch(() => {
setbit(i, 0);
});
}
function setbit(i, value) {
userId |= (value << i);
if (++bits == 32)
setUser(userId);
}
Always fetch on first load from new domain
Always prefetch known list
Only share very commonly used libraries
Summary