CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/hub/servers/app/blobs.ts
Views: 687
1
import { Router } from "express";
2
import { database } from "../database";
3
import { is_valid_uuid_string } from "@cocalc/util/misc";
4
import { database_is_working } from "@cocalc/hub/hub_register";
5
import { callback2 } from "@cocalc/util/async-utils";
6
import { getLogger } from "@cocalc/hub/logger";
7
8
const logger = getLogger("hub:servers:app:blobs");
9
export default function init(router: Router) {
10
// return uuid-indexed blobs (mainly used for graphics)
11
router.get("/blobs/*", async (req, res) => {
12
logger.debug(`${JSON.stringify(req.query)}, ${req.path}`);
13
const uuid = `${req.query.uuid}`;
14
if (req.headers["if-none-match"] === uuid) {
15
res.sendStatus(304);
16
return;
17
}
18
if (!is_valid_uuid_string(uuid)) {
19
res.status(404).send(`invalid uuid=${uuid}`);
20
return;
21
}
22
if (!database_is_working()) {
23
res.status(404).send("can't get blob -- not connected to database");
24
return;
25
}
26
27
try {
28
const data = await callback2(database.get_blob, { uuid });
29
if (data == null) {
30
res.status(404).send(`blob ${uuid} not found`);
31
} else {
32
const filename = req.path.slice(req.path.lastIndexOf("/") + 1);
33
if (req.query.download != null) {
34
// tell browser to download the link as a file instead
35
// of displaying it in browser
36
res.attachment(filename);
37
} else {
38
res.type(filename);
39
}
40
// Cache as long as possible (e.g., One year in seconds), since
41
// what we are returning is defined by a sha1 hash, so cannot change.
42
res.set("Cache-Control", `public, max-age=${365 * 24 * 60 * 60}`);
43
// "public means that the response may be cached by clients and any
44
// intermediary caches (like CDNs). max-age determines the amount
45
// of time (in seconds) a client should cache the response."
46
// The maximum value that you can set for max-age is 1 year
47
// (in seconds), which is compliant with the HTTP/1.1
48
// specifications (RFC2616)."
49
res.set("ETag", uuid);
50
res.send(data);
51
}
52
} catch (err) {
53
logger.error(`internal error ${err} getting blob ${uuid}`);
54
res.status(500).send(`internal error: ${err}`);
55
}
56
});
57
}
58
59