Skip to content

Commit

Permalink
[desktop] Fix making excessive handshakes
Browse files Browse the repository at this point in the history
fix #6053
  • Loading branch information
charlag committed Oct 30, 2023
1 parent ba0ebd9 commit 3bbaa96
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 8 deletions.
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"qrcode-svg": "1.0.0",
"squire-rte": "2.0.3",
"systemjs": "6.10.2",
"undici": "^5.27.0",
"winreg": "1.2.4"
},
"devDependencies": {
Expand Down
30 changes: 22 additions & 8 deletions src/desktop/net/ProtocolProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,42 @@ import { Session } from "electron"
import { errorToObj } from "../../api/common/threading/MessageDispatcher.js"
import { lazyMemoized } from "@tutao/tutanota-utils"
import { getMimeTypeForFile } from "../DesktopFileFacade.js"
import { ServiceUnavailableError } from "../../api/common/error/RestError.js"
import { Agent, fetch, RequestInfo as UndiciRequestInfo, RequestInit as UndiciRequestInit } from "undici"

type GlobalFetch = typeof global.fetch

const TAG = "[ProtocolProxy]"

export const ASSET_PROTOCOL = "asset"
const PROXIED_REQUEST_READ_TIMEOUT = 20000
const PROXIED_REQUEST_READ_TIMEOUT_MS = 20_000
// server has a 7200s tls session ticket timeout, so we keep the socket for 7000s
const SOCKET_IDLE_TIMEOUT_MS = 7200 * 1000 * 1000

/**
* intercept & proxy https, http and asset requests on a session
* @param session the webContents session we want to intercept requests on
* @param assetDir the base directory of allowable scripts, images and other resources that the app may load.
*/
export function handleProtocols(session: Session, assetDir: string): void {
doHandleProtocols(session, assetDir, fetch, path, fs)
const agent = new Agent({
connections: 4,
keepAliveTimeout: SOCKET_IDLE_TIMEOUT_MS,
bodyTimeout: PROXIED_REQUEST_READ_TIMEOUT_MS,
})
const customFetch: typeof fetch = (info: UndiciRequestInfo, requestInit?: UndiciRequestInit) => {
return fetch(info, {
...(requestInit ?? {}),
dispatcher: agent,
})
}
// It's a little crime to say that our fetch is like builtin fetch but it actually is, it's just TS is a bit uncooperative.
doHandleProtocols(session, assetDir, customFetch as GlobalFetch, path, fs)
}

/**
* exported for testing
*/
export function doHandleProtocols(session: Session, assetDir: string, fetchImpl: typeof fetch, pathModule: typeof path, fsModule: typeof fs): void {
export function doHandleProtocols(session: Session, assetDir: string, fetchImpl: GlobalFetch, pathModule: typeof path, fsModule: typeof fs): void {
if (!interceptProtocol("http", session, fetchImpl)) throw new Error("could not intercept http protocol")
if (!interceptProtocol("https", session, fetchImpl)) throw new Error("could not intercept https protocol")
if (!handleAssetProtocol(session, assetDir, pathModule, fsModule)) throw new Error("could not register asset protocol")
Expand All @@ -37,12 +53,11 @@ export function doHandleProtocols(session: Session, assetDir: string, fetchImpl:
* @param protocol http and https use different modules, so we need to intercept them separately.
* @param fetchImpl an implementation of the fetch API (Request) => Promise<Response>
*/
function interceptProtocol(protocol: string, session: Session, fetchImpl: typeof fetch): boolean {
function interceptProtocol(protocol: string, session: Session, fetchImpl: GlobalFetch): boolean {
if (session.protocol.isProtocolHandled(protocol)) return true
session.protocol.handle(protocol, async (request: Request): Promise<Response> => {
session.protocol.handle(protocol, async (request: GlobalRequest): Promise<Response> => {
const { method, url, headers } = request
const startTime: number = Date.now()

if (!url.startsWith(protocol)) {
return new Response(null, { status: 400 })
} else if (method == "OPTIONS") {
Expand All @@ -56,7 +71,6 @@ function interceptProtocol(protocol: string, session: Session, fetchImpl: typeof
headers,
method,
keepalive: true,
signal: AbortSignal.timeout(PROXIED_REQUEST_READ_TIMEOUT),
}
const body = await request.arrayBuffer()
if (body.byteLength > 0) {
Expand Down

0 comments on commit 3bbaa96

Please sign in to comment.