archivebox.misc.serve_static

Module Contents

Classes

_StreamingQueueWriter

Expose a write-only file-like object so zipfile can stream into a queue.

RangedFileReader

Wraps a file like object with an iterator that runs over part (or all) of the file defined by start and stop. Blocks of block_size will be returned from the starting position, up to, but not including the stop point. https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d

Functions

add_replay_image_fallback

Add a best-effort responsive-image fallback to the locally served replay worker.

_load_hash_map

_hash_for_path

_resolve_archive_path

_cache_policy

_format_direntry_timestamp

_safe_zip_stem

_iter_visible_files

Yield non-hidden files in a stable order so ZIP output is deterministic.

_build_directory_zip_response

_stream_ranged_file_async

_render_directory_index

_extract_markdown_candidate

_looks_like_markdown

_render_text_preview_document

_render_image_preview_document

_encoded_responses_image_url

_index_responses_paths_for_html_images

_rewrite_html_image_sources_to_responses

_rewrite_html_image_sources_for_request

_apply_transformed_html_preview_style

_set_transformed_response_headers

_render_markdown_fallback

_render_markdown_document

_content_type_base

_is_risky_replay_document

_apply_archive_replay_headers

_is_asgi_request

serve_static_with_byterange_support

Overrides Django’s built-in django.views.static.serve function to support byte range requests. This allows you to do things like seek into the middle of a huge mp4 or WACZ without downloading the whole file. https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d

serve_static

Serve static files below a given point in the directory structure or from locations inferred from the staticfiles finders.

parse_range_header

Parses a range header into a list of two-tuples (start, stop) where start is the starting byte of the range (inclusive) and stop is the ending byte position of the range (exclusive). Returns None if the value of the header is not syntactically valid. https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d

Data

_HASHES_CACHE

DIRECTORY_PREVIEW_MAX_BYTES

FAVICON_CACHE_CONTROL

IMG_SRC_ATTR_RE

TRANSFORMED_HTML_PREVIEW_STYLE

MARKDOWN_INLINE_LINK_RE

MARKDOWN_INLINE_IMAGE_RE

MARKDOWN_BOLD_RE

MARKDOWN_ITALIC_RE

HTML_TAG_RE

HTML_BODY_RE

RISKY_REPLAY_MIMETYPES

RISKY_REPLAY_EXTENSIONS

RISKY_REPLAY_MARKERS

API

archivebox.misc.serve_static._HASHES_CACHE: dict[pathlib.Path, tuple[float, dict[str, str]]][source]

None

archivebox.misc.serve_static.DIRECTORY_PREVIEW_MAX_BYTES[source]

None

archivebox.misc.serve_static.FAVICON_CACHE_CONTROL[source]

‘public, max-age=31536000, s-maxage=31536000, immutable’

archivebox.misc.serve_static.IMG_SRC_ATTR_RE[source]

‘compile(…)’

archivebox.misc.serve_static.TRANSFORMED_HTML_PREVIEW_STYLE = <Multiline-String>[source]
archivebox.misc.serve_static.add_replay_image_fallback(response: django.http.HttpResponse) → django.http.HttpResponse[source]

Add a best-effort responsive-image fallback to the locally served replay worker.

WHY: a recorder saves the image Chrome selected, not every srcset candidate. Replaying at another viewport/DPR can select an uncaptured URL (the motivating case was Drive’s missing 2x logo with its 1x logo already in the same WACZ). WACZ requests are answered inside Webrecorder’s service worker, so a Django 404 handler cannot repair them. Append this adapter when serving that worker; do not change captures, request more live assets, or resize the recorded page.

Only an image GET that already returned 404 is eligible. The worker reads the referring HTML from the SAME archive and tries src/srcset candidates declared on that img or its enclosing picture. It never guesses filename substitutions or borrows an unrelated nearby image. The original response wins on absent metadata, unsupported worker APIs, parse errors, timeout, or failed candidates. This deliberately does not promise to fix JS-only srcsets, CSS backgrounds, corrupt images returning 200, or pages whose archived HTML is too large.

Keep this self-contained in the static-file server: it is a replay repair, independent of the capturing plugin/site. Feature detection makes upstream worker changes disable the repair rather than break ordinary replay. The archive’s HTML/ZIP bytes and successful HTTP responses remain untouched.

archivebox.misc.serve_static._load_hash_map(snapshot_dir: pathlib.Path) → dict[str, str] | None[source]
archivebox.misc.serve_static._hash_for_path(document_root: pathlib.Path, rel_path: str) → str | None[source]
archivebox.misc.serve_static._resolve_archive_path(document_root: str | pathlib.Path, rel_path: str) → tuple[pathlib.Path, str][source]
archivebox.misc.serve_static._cache_policy(config=None, **config_kwargs) → str[source]
archivebox.misc.serve_static._format_direntry_timestamp(stat_result: os.stat_result) → str[source]
archivebox.misc.serve_static._safe_zip_stem(name: str) → str[source]
class archivebox.misc.serve_static._StreamingQueueWriter(output_queue: queue.Queue[bytes | BaseException | object])[source]

Expose a write-only file-like object so zipfile can stream into a queue.

Initialization

write(data: bytes) → int[source]
tell() → int[source]
flush() → None[source]
close() → None[source]
writable() → bool[source]
seekable() → bool[source]
archivebox.misc.serve_static._iter_visible_files(root: pathlib.Path)[source]

Yield non-hidden files in a stable order so ZIP output is deterministic.

archivebox.misc.serve_static._build_directory_zip_response(fullpath: pathlib.Path, path: str, *, is_archive_replay: bool, use_async_stream: bool, config=None) → django.http.StreamingHttpResponse[source]
async archivebox.misc.serve_static._stream_ranged_file_async(ranged_file: RangedFileReader)[source]
archivebox.misc.serve_static._render_directory_index(request, path: str, fullpath: pathlib.Path) → django.http.HttpResponse[source]

‘compile(…)’

archivebox.misc.serve_static.MARKDOWN_INLINE_IMAGE_RE[source]

‘compile(…)’

archivebox.misc.serve_static.MARKDOWN_BOLD_RE[source]

‘compile(…)’

archivebox.misc.serve_static.MARKDOWN_ITALIC_RE[source]

‘compile(…)’

archivebox.misc.serve_static.HTML_TAG_RE[source]

‘compile(…)’

archivebox.misc.serve_static.HTML_BODY_RE[source]

‘compile(…)’

archivebox.misc.serve_static.RISKY_REPLAY_MIMETYPES[source]

None

archivebox.misc.serve_static.RISKY_REPLAY_EXTENSIONS[source]

None

archivebox.misc.serve_static.RISKY_REPLAY_MARKERS[source]

(‘<!doctype html’, ‘<html’, ‘<svg’)

archivebox.misc.serve_static._extract_markdown_candidate(text: str) → str[source]
archivebox.misc.serve_static._looks_like_markdown(text: str) → bool[source]
archivebox.misc.serve_static._render_text_preview_document(text: str, title: str) → str[source]
archivebox.misc.serve_static._render_image_preview_document(image_url: str, title: str) → str[source]
archivebox.misc.serve_static._encoded_responses_image_url(image_url: str, page_url: str | None) → str | None[source]
archivebox.misc.serve_static._index_responses_paths_for_html_images(snapshot_root: pathlib.Path, html_rel_path: str, encoded_urls: set[str]) → dict[str, str][source]
archivebox.misc.serve_static._rewrite_html_image_sources_to_responses(html_text: str, snapshot_root: pathlib.Path, html_rel_path: str, page_url: str | None) → tuple[str, int][source]
archivebox.misc.serve_static._rewrite_html_image_sources_for_request(request, html_text: str, document_root: pathlib.Path | None, html_rel_path: str) → tuple[str, int][source]
archivebox.misc.serve_static._apply_transformed_html_preview_style(html_text: str) → str[source]
archivebox.misc.serve_static._set_transformed_response_headers(response, fullpath: pathlib.Path, statobj: os.stat_result, encoding: str | None, cache_policy: str) → None[source]
archivebox.misc.serve_static._render_markdown_fallback(text: str) → str[source]
archivebox.misc.serve_static._render_markdown_document(markdown_text: str) → str[source]
archivebox.misc.serve_static._content_type_base(content_type: str) → str[source]
archivebox.misc.serve_static._is_risky_replay_document(fullpath: pathlib.Path, content_type: str) → bool[source]
archivebox.misc.serve_static._apply_archive_replay_headers(response: django.http.HttpResponse, *, fullpath: pathlib.Path, content_type: str, is_archive_replay: bool, config=None, **config_kwargs) → django.http.HttpResponse[source]
archivebox.misc.serve_static._is_asgi_request(request) → bool[source]
archivebox.misc.serve_static.serve_static_with_byterange_support(request, path, document_root=None, show_indexes=False, is_archive_replay: bool = False)[source]

Overrides Django’s built-in django.views.static.serve function to support byte range requests. This allows you to do things like seek into the middle of a huge mp4 or WACZ without downloading the whole file. https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d

archivebox.misc.serve_static.serve_static(request, path, **kwargs)[source]

Serve static files below a given point in the directory structure or from locations inferred from the staticfiles finders.

To use, put a URL pattern such as::

from django.contrib.staticfiles import views

path('<path:path>', views.serve)

in your URLconf.

It uses the django.views.static.serve() view to serve the found files.

archivebox.misc.serve_static.parse_range_header(header, resource_size)[source]

Parses a range header into a list of two-tuples (start, stop) where start is the starting byte of the range (inclusive) and stop is the ending byte position of the range (exclusive). Returns None if the value of the header is not syntactically valid. https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d

class archivebox.misc.serve_static.RangedFileReader(file_like, start=0, stop=float('inf'), block_size=None)[source]

Wraps a file like object with an iterator that runs over part (or all) of the file defined by start and stop. Blocks of block_size will be returned from the starting position, up to, but not including the stop point. https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d

Initialization

block_size[source]

8192

__iter__()[source]
close()[source]