Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion raven/knowledge/_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ def document_path(self, document_id: str) -> Path | None:

Beside ``read_document`` rather than instead of it: the indexer wants
the bytes, and a viewer wants a handle it can stream and convert from.
Reading a 25 MB upload into memory to hand it back out again is the
Reading a 100 MB upload into memory to hand it back out again is the
thing this exists to avoid.

The path is inside raven's state directory, which the viewer's own path
Expand Down
26 changes: 18 additions & 8 deletions raven/rpc/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,24 @@
# does anything useful with the bytes, and the read would stall the event loop.
MAX_VIEW_BYTES = 25 * 1024 * 1024

# The largest file `fs.upload` accepts. It sits beside the viewer's ceiling
# because the two are one story told in both directions, and here rather than
# in the method that enforces it because the WebSocket transport has to size
# its own frame ceiling from it: an upload rides as base64 inside one JSON-RPC
# frame, so a transport ceiling below this one rejects the upload before the
# method can explain why, and the page sees a dropped socket instead of a
# reason. See `frame_ceiling_for_upload`.
MAX_UPLOAD_BYTES = 25 * 1024 * 1024
# The largest file `fs.upload` accepts. Deliberately above the viewer's
# ceiling: the two answer different questions. An upload only has to land a
# path in the workspace -- a non-image attachment is named to the model, never
# read into the message -- while the viewer has to render what it serves, which
# is what keeps MAX_VIEW_BYTES where it is. A file between the two ceilings can
# therefore be attached and not previewed.
#
# It lives here rather than in the method that enforces it because the
# WebSocket transport has to size its own frame ceiling from it: an upload
# rides as base64 inside one JSON-RPC frame, so a transport ceiling below this
# one rejects the upload before the method can explain why, and the page sees a
# dropped socket instead of a reason. See `frame_ceiling_for_upload`.
#
# The ceiling is memory, not policy. One upload at this size costs the gateway
# the frame, the JSON string parsed out of it and the decoded bytes at once,
# and the parse holds the event loop while it runs. Raising this much further
# wants the streamed HTTP upload path instead, not a bigger number.
MAX_UPLOAD_BYTES = 100 * 1024 * 1024

# Room for the JSON-RPC envelope around a maximal upload: the method name, the
# session key and the file name, plus escaping. Two orders of magnitude more
Expand Down
2 changes: 1 addition & 1 deletion tests/test_rpc_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ async def test_the_socket_carries_a_frame_larger_than_aiohttp_would_allow_by_def
def test_the_frame_ceiling_can_carry_the_largest_upload_the_method_accepts() -> None:
"""The two limits are one limit, and this is what keeps them that way.

Sized arithmetically rather than by building a 25 MB payload: the envelope
Sized arithmetically rather than by building a maximal payload: the envelope
is what has to fit around a maximal base64 body, and materialising one to
learn its length would cost the suite a second to answer a question about
two integers.
Expand Down
2 changes: 1 addition & 1 deletion ui-web/src/lib/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import { t } from '../i18n/t'

const UPLOAD_MAX_BYTES = 25 * 1024 * 1024
const UPLOAD_MAX_BYTES = 100 * 1024 * 1024

/* Two entries because the two callers hold the file in different forms, and
asking for the wrong one costs the reader real time: a caller with the `File`
Expand Down
Loading