Skip to content

Commit 5ff9f08

Browse files
committed
first draft to measure compressed and uncompressed size
1 parent a47c3b3 commit 5ff9f08

File tree

5 files changed

+133
-2
lines changed

5 files changed

+133
-2
lines changed

server/app.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import staticRouter from "./src/static/staticRouter.js";
55
import * as ejs from "ejs";
66
import * as fastifyView from "@fastify/view";
77
import minifier from "html-minifier";
8+
import { Stream } from "stream";
9+
import toArray from "stream-to-array";
10+
import zlib from "node:zlib";
11+
import { pipeline } from "node:stream";
12+
import { promisify } from "node:util";
13+
import { getSizeRouter } from "./src/responseSize/responseSizeRouter.js";
814

915
/**
1016
* Builds the server but does not start it. Need it for testing API
@@ -23,8 +29,92 @@ function buildServer(options = {}) {
2329
},
2430
});
2531

32+
fastify.decorate("responseSize", {
33+
use_compression: false,
34+
size_uncompressed: 0,
35+
size_compressed: 0,
36+
get: function() {
37+
return {
38+
use_compression: this.use_compression,
39+
size_uncompressed: this.size_uncompressed,
40+
size_compressed: this.size_compressed,
41+
};
42+
},
43+
reset: function() {
44+
this.size_uncompressed = 0;
45+
this.size_compressed = 0;
46+
},
47+
enableCompression: function(val) {
48+
this.use_compression = val;
49+
},
50+
add: function(uncompressed, compressed) {
51+
this.size_uncompressed += uncompressed;
52+
this.size_compressed += compressed;
53+
},
54+
});
55+
56+
fastify.register(getSizeRouter);
57+
58+
fastify.addHook("onSend", async (request, reply, payload) => {
59+
// const MISSING_HEADERS_AND_HTTP = 99;
60+
let getSizeInfo = (original, compressed) => {
61+
if (!compressed) {
62+
compressed = original;
63+
} else {
64+
reply.header("Content-Length", compressed.length);
65+
reply.header("Content-Encoding", "br");
66+
}
67+
let headers = Object.entries(reply.getHeaders()).reduce((p, [e, v]) => p + `${e}: ${v} \n`, "");
68+
// console.log(request.url, reply.statusCode, "\n", headers);
69+
return {
70+
compressed: compressed.length, // + headers.length + MISSING_HEADERS_AND_HTTP,
71+
uncompressed: original.length, // + headers.length + MISSING_HEADERS_AND_HTTP
72+
};
73+
};
74+
75+
if (request.url.startsWith("/css") || reply.statusCode != 200 || !fastify.responseSize.use_compression) {
76+
return payload;
77+
} else {
78+
if (typeof payload == "string") {
79+
let { uncompressed, compressed } = getSizeInfo(payload);
80+
fastify.responseSize.add(uncompressed, compressed);
81+
console.log(
82+
`onSend: ${request.url} as string with uncompressed size ${uncompressed} sum uncompressed ${fastify.responseSize.size_uncompressed}, compressed ${fastify.responseSize.size_compressed}`
83+
);
84+
} else if (payload instanceof Stream) {
85+
return toArray(payload)
86+
.then((chunks) => {
87+
const buffer = Buffer.concat(chunks);
88+
if (buffer.length >= 1024) {
89+
let out = zlib.brotliCompressSync(buffer);
90+
let { uncompressed, compressed } = getSizeInfo(buffer, out);
91+
fastify.responseSize.add(uncompressed, compressed);
92+
console.log(
93+
`onSend: ${request.url} as stream with uncompressed size ${uncompressed} compressed ${compressed} sum uncompressed ${fastify.responseSize.size_uncompressed}, compressed ${fastify.responseSize.size_compressed}`
94+
);
95+
return out;
96+
} else {
97+
let { uncompressed, compressed } = getSizeInfo(buffer);
98+
fastify.responseSize.add(uncompressed, compressed);
99+
console.log(
100+
`onSend: ${request.url} as stream with uncompressed size ${uncompressed} (not compressed since below threshold) sum uncompressed ${fastify.responseSize.size_uncompressed}, compressed ${fastify.responseSize.size_compressed}`
101+
);
102+
return buffer;
103+
}
104+
})
105+
.catch((err) => {
106+
console.log("onSend: Error", err);
107+
});
108+
} else {
109+
console.log("onSend: Unknown payload type", typeof payload, payload);
110+
}
111+
return payload;
112+
}
113+
});
114+
26115
fastify.addHook("onRequest", (request, reply, done) => {
27116
if (request.url.endsWith("index.html")) {
117+
fastify.responseSize.reset();
28118
reply.header("Cross-Origin-Embedder-Policy", "require-corp");
29119
reply.header("Cross-Origin-Opener-Policy", "same-origin");
30120
}

server/package-lock.json

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"@fastify/view": "^8.2.0",
1919
"ejs": "^3.1.9",
2020
"fastify": "^4.23.2",
21-
"html-minifier": "^4.0.0"
21+
"html-minifier": "^4.0.0",
22+
"stream-to-array": "^2.3.0"
2223
},
2324
"devDependencies": {
2425
"@types/ejs": "^3.1.2",
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export function getSize(request, reply) {
2+
console.log("/getSize");
3+
reply.send({
4+
size_uncompressed: request.server.responseSize.size_uncompressed,
5+
size_compressed: request.server.responseSize.size_compressed,
6+
});
7+
}
8+
9+
export function enableCompression(request, reply) {
10+
console.log("/enableCompression");
11+
request.server.responseSize.enableCompression(true);
12+
reply.send("OK");
13+
}
14+
15+
export function disableCompression(request, reply) {
16+
console.log("/disableCompression");
17+
request.server.responseSize.enableCompression(false);
18+
reply.send("OK");
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { disableCompression, enableCompression, getSize } from "./responseSizeController.js";
2+
3+
export async function getSizeRouter(fastify) {
4+
fastify.get("/enableCompression", enableCompression);
5+
fastify.get("/disableCompression", disableCompression);
6+
fastify.get("/getSize", getSize);
7+
}

0 commit comments

Comments
 (0)