Skip to content

Commit cad9d53

Browse files
authored
Merge pull request #7763 from sagemathinc/share-pdf-embed
next/share: embed PDF
2 parents a38f73e + b8fd915 commit cad9d53

File tree

8 files changed

+94
-73
lines changed

8 files changed

+94
-73
lines changed

src/packages/hub/hub.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,23 @@
77
// middle of the action, connected to potentially thousands of clients,
88
// many Sage sessions, and PostgreSQL database.
99

10+
import TTLCache from "@isaacs/ttlcache";
1011
import { callback } from "awaiting";
1112
import blocked from "blocked";
1213
import { spawn } from "child_process";
1314
import { program as commander, Option } from "commander";
15+
1416
import basePath from "@cocalc/backend/base-path";
1517
import {
1618
pghost as DEFAULT_DB_HOST,
1719
pgdatabase as DEFAULT_DB_NAME,
1820
pguser as DEFAULT_DB_USER,
1921
} from "@cocalc/backend/data";
22+
import { trimLogFileSize } from "@cocalc/backend/logger";
2023
import port from "@cocalc/backend/port";
2124
import { init_start_always_running_projects } from "@cocalc/database/postgres/always-running";
25+
import { load_server_settings_from_env } from "@cocalc/database/settings/server-settings";
26+
import { init_passport } from "@cocalc/server/hub/auth";
2227
import { initialOnPremSetup } from "@cocalc/server/initial-onprem-setup";
2328
import initHandleMentions from "@cocalc/server/mentions/handle";
2429
import initProjectControl, {
@@ -28,23 +33,20 @@ import initIdleTimeout from "@cocalc/server/projects/control/stop-idle-projects"
2833
import initNewProjectPoolMaintenanceLoop from "@cocalc/server/projects/pool/maintain";
2934
import initPurchasesMaintenanceLoop from "@cocalc/server/purchases/maintenance";
3035
import initSalesloftMaintenance from "@cocalc/server/salesloft/init";
31-
import { load_server_settings_from_env } from "@cocalc/database/settings/server-settings";
3236
import { stripe_sync } from "@cocalc/server/stripe/sync";
3337
import { callback2, retry_until_success } from "@cocalc/util/async-utils";
34-
import { init_passport } from "@cocalc/server/hub/auth";
3538
import { getClients } from "./clients";
3639
import { set_agent_endpoint } from "./health-checks";
3740
import { start as startHubRegister } from "./hub_register";
3841
import { getLogger } from "./logger";
39-
import { trimLogFileSize } from "@cocalc/backend/logger";
4042
import initDatabase, { database } from "./servers/database";
4143
import initExpressApp from "./servers/express-app";
4244
import initHttpRedirect from "./servers/http-redirect";
4345
import initPrimus from "./servers/primus";
4446
import initVersionServer from "./servers/version";
47+
4548
const { COOKIE_OPTIONS } = require("./client"); // import { COOKIE_OPTIONS } from "./client";
4649
const MetricsRecorder = require("./metrics-recorder"); // import * as MetricsRecorder from "./metrics-recorder";
47-
import TTLCache from "@isaacs/ttlcache";
4850

4951
// Logger tagged with 'hub' for this file.
5052
const winston = getLogger("hub");

src/packages/hub/servers/app/next.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66
- ... and more?!
77
*/
88

9+
import { Application, NextFunction, Request, Response } from "express";
910
import { join } from "path";
10-
import { Application, Request, Response, NextFunction } from "express";
11+
1112
// @ts-ignore -- TODO: typescript doesn't like @cocalc/next/init (it is a js file).
1213
import initNextServer from "@cocalc/next/init";
13-
import handleRaw from "@cocalc/next/lib/share/handle-raw";
14-
import { getLogger } from "@cocalc/hub/logger";
15-
import shareRedirect from "./share-redirect";
16-
import createLandingRedirect from "./landing-redirect";
14+
1715
import basePath from "@cocalc/backend/base-path";
18-
import { database } from "../database";
16+
import { getLogger } from "@cocalc/hub/logger";
17+
import handleRaw from "@cocalc/next/lib/share/handle-raw";
1918
import { callback2 } from "@cocalc/util/async-utils";
19+
import { database } from "../database";
20+
import createLandingRedirect from "./landing-redirect";
21+
import shareRedirect from "./share-redirect";
22+
import { separate_file_extension } from "@cocalc/util/misc";
2023

2124
export default async function init(app: Application) {
2225
const winston = getLogger("nextjs");
@@ -48,18 +51,22 @@ export default async function init(app: Application) {
4851
// etc. servers is definitely too much, so we just disable this.
4952
// For serving actual raw content, the solution will be to use
5053
// a vhost.
54+
5155
// 1: The raw static server:
5256
const raw = join(shareBasePath, "raw");
5357
app.all(
5458
join(raw, "*"),
5559
(req: Request, res: Response, next: NextFunction) => {
60+
// Embedding only enabled for PDF files -- see note above
61+
const download =
62+
separate_file_extension(req.path).ext.toLowerCase() !== "pdf";
5663
try {
5764
handleRaw({
5865
...parseURL(req, raw),
5966
req,
6067
res,
6168
next,
62-
download: true /* do not change this by default -- see above. */,
69+
download,
6370
});
6471
} catch (_err) {
6572
res.status(404).end();

src/packages/hub/servers/express-app.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,37 @@
22
The main hub express app.
33
*/
44

5-
import { path as WEBAPP_PATH } from "@cocalc/assets";
6-
import basePath from "@cocalc/backend/base-path";
7-
import { path as CDN_PATH } from "@cocalc/cdn";
8-
import vhostShare from "@cocalc/next/lib/share/virtual-hosts";
9-
import { path as STATIC_PATH } from "@cocalc/static";
105
import compression from "compression";
116
import cookieParser from "cookie-parser";
127
import express from "express";
138
import ms from "ms";
149
import { join } from "path";
1510
import { parse as parseURL } from "url";
11+
import webpackDevMiddleware from "webpack-dev-middleware";
12+
import webpackHotMiddleware from "webpack-hot-middleware";
13+
14+
import { path as WEBAPP_PATH } from "@cocalc/assets";
15+
import basePath from "@cocalc/backend/base-path";
16+
import { path as CDN_PATH } from "@cocalc/cdn";
17+
import vhostShare from "@cocalc/next/lib/share/virtual-hosts";
18+
import { path as STATIC_PATH } from "@cocalc/static";
1619
import { initAnalytics } from "../analytics";
1720
import { setup_health_checks as setupHealthChecks } from "../health-checks";
1821
import { getLogger } from "../logger";
1922
import initProxy from "../proxy";
2023
import initAPI from "./app/api";
2124
import initAppRedirect from "./app/app-redirect";
22-
import initBlobs from "./app/blobs";
2325
import initBlobUpload from "./app/blob-upload";
24-
import initStripeWebhook from "./app/webhooks/stripe";
26+
import initBlobs from "./app/blobs";
2527
import initCustomize from "./app/customize";
26-
import { setupInstrumentation, initMetricsEndpoint } from "./app/metrics";
28+
import { initMetricsEndpoint, setupInstrumentation } from "./app/metrics";
2729
import initNext from "./app/next";
2830
import initSetCookies from "./app/set-cookies";
2931
import initStats from "./app/stats";
32+
import initStripeWebhook from "./app/webhooks/stripe";
3033
import { database } from "./database";
3134
import initHttpServer from "./http";
3235
import initRobots from "./robots";
33-
import webpackHotMiddleware from "webpack-hot-middleware";
34-
import webpackDevMiddleware from "webpack-dev-middleware";
3536

3637
// Used for longterm caching of files. This should be in units of seconds.
3738
const MAX_AGE = Math.round(ms("10 days") / 1000);

src/packages/next/components/path/path.tsx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6-
import { useEffect, useState } from "react";
76
import {
87
Alert,
98
Avatar as AntdAvatar,
@@ -13,32 +12,34 @@ import {
1312
Tooltip,
1413
} from "antd";
1514
import Link from "next/link";
16-
import PathContents from "components/share/path-contents";
17-
import PathActions from "components/share/path-actions";
18-
import LinkedPath from "components/share/linked-path";
19-
import Loading from "components/share/loading";
20-
import License from "components/share/license";
21-
import ProjectLink from "components/share/project-link";
22-
import useCounter from "lib/share/counter";
23-
import { Layout } from "components/share/layout";
24-
import { Customize } from "lib/share/customize";
25-
import type { CustomizeType } from "lib/customize";
26-
import { getTitle } from "lib/share/util";
27-
import SanitizedMarkdown from "components/misc/sanitized-markdown";
28-
import Badge from "components/misc/badge";
15+
import { useRouter } from "next/router";
16+
import { join } from "path";
17+
import { useEffect, useState } from "react";
18+
2919
import { Icon } from "@cocalc/frontend/components/icon";
3020
import {
31-
SHARE_AUTHENTICATED_ICON,
3221
SHARE_AUTHENTICATED_EXPLANATION,
22+
SHARE_AUTHENTICATED_ICON,
3323
} from "@cocalc/util/consts/ui";
34-
import apiPost from "lib/api/post";
3524
import InPlaceSignInOrUp from "components/auth/in-place-sign-in-or-up";
36-
import { useRouter } from "next/router";
37-
import type { PathContents as PathContentsType } from "lib/share/get-contents";
38-
import Avatar from "components/share/proxy/avatar";
39-
import A from "components/misc/A";
40-
import { join } from "path";
4125
import { Tagline } from "components/landing/tagline";
26+
import A from "components/misc/A";
27+
import Badge from "components/misc/badge";
28+
import SanitizedMarkdown from "components/misc/sanitized-markdown";
29+
import { Layout } from "components/share/layout";
30+
import License from "components/share/license";
31+
import LinkedPath from "components/share/linked-path";
32+
import Loading from "components/share/loading";
33+
import PathActions from "components/share/path-actions";
34+
import PathContents from "components/share/path-contents";
35+
import ProjectLink from "components/share/project-link";
36+
import Avatar from "components/share/proxy/avatar";
37+
import apiPost from "lib/api/post";
38+
import type { CustomizeType } from "lib/customize";
39+
import useCounter from "lib/share/counter";
40+
import { Customize } from "lib/share/customize";
41+
import type { PathContents as PathContentsType } from "lib/share/get-contents";
42+
import { getTitle } from "lib/share/util";
4243

4344
import { SocialMediaShareLinks } from "components/landing/social-media-share-links";
4445

src/packages/next/components/share/file-contents.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,28 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6-
import { getExtension } from "lib/share/util";
6+
import Markdown from "@cocalc/frontend/editors/slate/static-markdown";
77
import {
88
isAudio,
99
isCodemirror,
10-
isImage,
1110
isHTML,
11+
isImage,
1212
isMarkdown,
1313
isVideo,
1414
} from "@cocalc/frontend/file-extensions";
15-
import rawURL from "lib/share/raw-url";
16-
import { isIOS, isSafari } from "lib/share/feature";
17-
import CodeMirror from "./codemirror";
18-
import SageWorksheet from "./sage-worksheet";
19-
import JupyterNotebook from "@cocalc/frontend/jupyter/nbviewer/nbviewer";
20-
import Markdown from "@cocalc/frontend/editors/slate/static-markdown";
21-
import Whiteboard from "@cocalc/frontend/frame-editors/whiteboard-editor/share/index";
2215
import Slides from "@cocalc/frontend/frame-editors/slides-editor/share";
16+
import Whiteboard from "@cocalc/frontend/frame-editors/whiteboard-editor/share/index";
17+
import JupyterNotebook from "@cocalc/frontend/jupyter/nbviewer/nbviewer";
18+
import { FileContext } from "@cocalc/frontend/lib/file-context";
2319
import A from "components/misc/A";
24-
import { containingPath } from "lib/share/util";
20+
import { isIOS, isSafari } from "lib/share/feature";
21+
import rawURL from "lib/share/raw-url";
2522
import getUrlTransform from "lib/share/url-transform";
26-
import getAnchorTagComponent from "./anchor-tag-component";
27-
import { FileContext } from "@cocalc/frontend/lib/file-context";
23+
import { containingPath, getExtension } from "lib/share/util";
2824
import useCustomize from "lib/use-customize";
25+
import getAnchorTagComponent from "./anchor-tag-component";
26+
import CodeMirror from "./codemirror";
27+
import SageWorksheet from "./sage-worksheet";
2928

3029
interface Props {
3130
id: string;
@@ -74,7 +73,7 @@ export default function FileContents({
7473
);
7574
} else if (isAudio(ext)) {
7675
return <audio src={raw} autoPlay={true} controls={true} loop={false} />;
77-
} else if (ext == "pdf") {
76+
} else if (ext === "pdf") {
7877
// iOS and iPADOS does not have any way to embed PDF's in pages.
7978
// I think pretty much every other web browser does, though
8079
// strangely even desktop Safari seems often broken, so we also block that.

src/packages/next/components/share/path-contents.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6+
import { FileInfo } from "lib/share/get-contents";
67
import DirectoryListing from "./directory-listing";
78
import FileContents from "./file-contents";
8-
import { FileInfo } from "lib/share/get-contents";
99
import Loading from "./loading";
1010

1111
interface Props {

src/packages/next/lib/share/handle-raw.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ It confirms that the request is valid (so the content is
55
actually currently publicly shared) then sends the result.
66
*/
77

8-
import { join } from "path";
98
import type { Request, Response } from "express";
109
import { static as ExpressStatic } from "express";
11-
import DirectoryListing from "serve-index";
12-
import { getExtension, isSha1Hash } from "./util";
13-
import { pathFromID } from "./path-to-files";
1410
import LRU from "lru-cache";
1511
import ms from "ms";
12+
import { join } from "path";
13+
import DirectoryListing from "serve-index";
14+
15+
import { pathFromID } from "./path-to-files";
16+
import { getExtension, isSha1Hash } from "./util";
17+
1618
const MAX_AGE = Math.round(ms("15 minutes") / 1000);
1719

1820
interface Options {
@@ -98,7 +100,7 @@ export function staticHandler(
98100
res: Response,
99101
next: Function,
100102
) {
101-
//console.log("staticHandler", { fsPath, url: req.url });
103+
// console.log("staticHandler", { fsPath, url: req.url });
102104
const handler = getStaticFileHandler(fsPath);
103105
// @ts-ignore -- TODO
104106
handler(req, res, () => {
@@ -127,20 +129,28 @@ export function staticHandler(
127129
});
128130
}
129131

130-
const staticFileCache = new LRU({ max: 200 });
131-
function getStaticFileHandler(path: string) {
132-
if (staticFileCache.has(path)) {
133-
return staticFileCache.get(path);
132+
const staticFileCache = new LRU<string, ReturnType<typeof ExpressStatic>>({
133+
max: 200,
134+
});
135+
function getStaticFileHandler(path: string): ReturnType<typeof ExpressStatic> {
136+
const sfh = staticFileCache.get(path);
137+
if (sfh) {
138+
return sfh;
134139
}
135140
const handler = ExpressStatic(path);
136141
staticFileCache.set(path, handler);
137142
return handler;
138143
}
139144

140-
const directoryCache = new LRU({ max: 200 });
141-
function getDirectoryHandler(path: string) {
142-
if (directoryCache.has(path)) {
143-
return directoryCache.get(path);
145+
const directoryCache = new LRU<string, ReturnType<typeof DirectoryListing>>({
146+
max: 200,
147+
});
148+
function getDirectoryHandler(
149+
path: string,
150+
): ReturnType<typeof DirectoryListing> {
151+
const dh = directoryCache.get(path);
152+
if (dh) {
153+
return dh;
144154
}
145155
const handler = DirectoryListing(path, { icons: true, view: "details" });
146156
directoryCache.set(path, handler);

src/packages/next/lib/share/virtual-hosts.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ Support for virtual hosts.
88
*/
99

1010
import type { Request, Response } from "express";
11+
12+
import basePath from "@cocalc/backend/base-path";
1113
import { getLogger } from "@cocalc/backend/logger";
12-
import pathToFiles from "./path-to-files";
1314
import isAuthenticated from "./authenticate";
1415
import getVirtualHostInfo from "./get-vhost-info";
1516
import { staticHandler } from "./handle-raw";
16-
import basePath from "@cocalc/backend/base-path";
17+
import pathToFiles from "./path-to-files";
1718

1819
const logger = getLogger("virtual-hosts");
1920

@@ -23,7 +24,7 @@ export default function virtualHostsMiddleware() {
2324
return async function (
2425
req: Request,
2526
res: Response,
26-
next: Function
27+
next: Function,
2728
): Promise<void> {
2829
// For debugging in cc-in-cc dev, just manually set host to something
2930
// else and comment this out. That's the only way, since dev is otherwise
@@ -69,7 +70,7 @@ export default function virtualHostsMiddleware() {
6970
logger.debug(
7071
"not authenticated -- denying vhost='%s', path='%s'",
7172
vhost,
72-
path
73+
path,
7374
);
7475
res.status(403).end();
7576
return;

0 commit comments

Comments
 (0)