Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b90d699
Single-file output is MHT, which browsers no longer open
xroche Jul 26, 2026
71ca31e
Merge origin/master into feat/single-file
xroche Jul 26, 2026
a122640
tests: renumber the single-file test to 87, run the self-test last
xroche Jul 26, 2026
c6b7c40
Fix the parser and path bugs review found, and cover them
xroche Jul 26, 2026
f50307d
singlefile: tighten two comments
xroche Jul 26, 2026
906906e
tests: cover the option plumbing review found untested
xroche Jul 26, 2026
4a62cfb
tests: stand the single-file GUI check down where htsserver is absent
xroche Jul 26, 2026
5f3787e
Merge origin/master into feat/single-file
xroche Jul 26, 2026
42072f5
tests: check the sprintfbuff master just made warn_unused_result
xroche Jul 26, 2026
06dc54f
single-file: translate the new GUI strings into the remaining 28 loca…
xroche Jul 26, 2026
37ee129
Merge origin/master into feat/single-file
xroche Jul 26, 2026
b5db9bb
single-file: restore the mirror file mode, and give the guards real c…
xroche Jul 26, 2026
a228ced
Merge origin/master into feat/single-file
xroche Jul 26, 2026
6bd4209
Merge origin/master into feat/single-file
xroche Jul 26, 2026
15e2c70
single-file: document the inlined-stylesheet limitation in the CLI guide
xroche Jul 26, 2026
d3a9156
tests: move the Windows note down to the gate it explains
xroche Jul 26, 2026
5ee188b
ci: register the single-file test's Windows skip
xroche Jul 26, 2026
8b72e3d
Merge origin/master into feat/single-file
xroche Jul 26, 2026
0130473
single-file: merge master and take test number 94
xroche Jul 27, 2026
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
5 changes: 3 additions & 2 deletions .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ jobs:
# tested nothing: pin the skips, and floor the passes in case the glob empties.
# footer-overflow skips on Windows (needs a path past MAX_PATH); crange pending #581;
# webdav-mime needs a reapable background listener, which MSYS cannot give it;
# badmtime needs a filesystem that stores an mtime past gmtime's range.
expected_skips=" 01_engine-footer-overflow.test 48_local-crange-memresume.test 71_local-crange-repaircache.test 79_local-proxytrack-webdav-mime.test 88_local-proxytrack-badmtime.test"
# badmtime needs a filesystem that stores an mtime past gmtime's range;
# single-file ends on a GUI half needing htsserver, which this job does not build.
expected_skips=" 01_engine-footer-overflow.test 48_local-crange-memresume.test 71_local-crange-repaircache.test 79_local-proxytrack-webdav-mime.test 88_local-proxytrack-badmtime.test 94_local-single-file.test"
[ "$pass" -ge 90 ] || { echo "::error::only $pass tests passed ($skip skipped)"; exit 1; }
[ "$skipped" = "$expected_skips" ] || { echo "::error::unexpected skips:$skipped"; exit 1; }
[ "$fail" -eq 0 ] || { echo "::error::failing:$failed"; exit 1; }
Expand Down
9 changes: 7 additions & 2 deletions fuzz/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
if FUZZERS
noinst_PROGRAMS = fuzz-charset fuzz-meta fuzz-idna fuzz-entities \
fuzz-unescape fuzz-filters fuzz-url fuzz-header fuzz-cachendx \
fuzz-htsparse
fuzz-htsparse fuzz-singlefile
endif

AM_CPPFLAGS = \
Expand All @@ -27,6 +27,7 @@ fuzz_url_SOURCES = fuzz-url.c fuzz.h
fuzz_header_SOURCES = fuzz-header.c fuzz.h
fuzz_cachendx_SOURCES = fuzz-cachendx.c fuzz.h
fuzz_htsparse_SOURCES = fuzz-htsparse.c fuzz.h
fuzz_singlefile_SOURCES = fuzz-singlefile.c fuzz.h

# List corpus files explicitly: automake does not expand EXTRA_DIST globs.
EXTRA_DIST = README.md run-fuzzers.sh \
Expand All @@ -47,4 +48,8 @@ EXTRA_DIST = README.md run-fuzzers.sh \
corpus/cachendx/regress-overadvance.bin \
corpus/cachendx/regress-truncated-entry.bin \
corpus/htsparse/basic.html corpus/htsparse/script-inscript.html \
corpus/htsparse/meta-usemap.html corpus/htsparse/malformed.html
corpus/htsparse/meta-usemap.html corpus/htsparse/malformed.html \
corpus/singlefile/img-src.html corpus/singlefile/link-rel.html \
corpus/singlefile/style-block.html corpus/singlefile/style-attr.html \
corpus/singlefile/srcset.html corpus/singlefile/rawtext.html \
corpus/singlefile/malformed.html corpus/singlefile/many-attrs.html
3 changes: 3 additions & 0 deletions fuzz/corpus/singlefile/img-src.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<img src="a.png">
<img src=big.png alt=over-cap>
<img src="../escape.png"><img src="/abs.png"><img src="data:,x">
4 changes: 4 additions & 0 deletions fuzz/corpus/singlefile/link-rel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<link rel="stylesheet" href="s.css">
<link rel=icon href=a.png>
<link rel="next" href="p2.html">
<link rel="preload" href="j.js">
5 changes: 5 additions & 0 deletions fuzz/corpus/singlefile/malformed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<img src="unterminated.png
<div style="background:url(a.png">
<style>@import url(
<!-- unterminated comment
<a href=
1 change: 1 addition & 0 deletions fuzz/corpus/singlefile/many-attrs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<img src="a.png" a0="v" a1="v" a2="v" a3="v" a4="v" a5="v" a6="v" a7="v" a8="v" a9="v" a10="v" a11="v" a12="v" a13="v" a14="v" a15="v" a16="v" a17="v" a18="v" a19="v" a20="v" a21="v" a22="v" a23="v" a24="v" a25="v" a26="v" a27="v" a28="v" a29="v" a30="v" a31="v" a32="v" a33="v" a34="v" a35="v" a36="v" a37="v" a38="v" a39="v" a40="v" a41="v" a42="v" a43="v" a44="v" a45="v" a46="v" a47="v" a48="v" a49="v" a50="v" a51="v" a52="v" a53="v" a54="v" a55="v" a56="v" a57="v" a58="v" a59="v" a60="v" a61="v" a62="v" a63="v" a64="v" a65="v" a66="v" a67="v" a68="v" a69="v">
4 changes: 4 additions & 0 deletions fuzz/corpus/singlefile/rawtext.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<script>var s="</scripting>"; if(a</b) x=1;</script>
<script src="j.js"></script>
<textarea></textareas></textarea>
<title></titles></title>
2 changes: 2 additions & 0 deletions fuzz/corpus/singlefile/srcset.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<img srcset="a.png 1x, big.png 2x, a.png 100w">
<source srcset="a.png,, a.png 2x," src="a.png">
2 changes: 2 additions & 0 deletions fuzz/corpus/singlefile/style-attr.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<div style="background:url(a.png);list-style:url('a.png')"></div>
<p style='background:url("a.png")'>x</p>
5 changes: 5 additions & 0 deletions fuzz/corpus/singlefile/style-block.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<style>@import "s.css";
@import url(sub/b.css);
div{background:url(a.png)}
/* url(a.png) */ p:after{content:"url(a.png)"}
</style>
131 changes: 131 additions & 0 deletions fuzz/fuzz-singlefile.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* ------------------------------------------------------------ */
/*
HTTrack Website Copier, Offline Browser for Windows and Unix
Copyright (C) 2026 Xavier Roche and other contributors

SPDX-License-Identifier: GPL-3.0-or-later

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Ethical use: we kindly ask that you NOT use this software to harvest email
addresses or to collect any other private information about people. Doing so
would dishonor our work and waste the many hours we have spent on it.

Please visit our Website: http://www.httrack.com
*/

/* Fuzz the --single-file rewriter (htssinglefile.c): hostile HTML walked
through the tag, CSS url()/@import and srcset parsers, then re-serialized.
The resolver is aimed at a private temp tree, so the inlining half (MIME
guess, base64, nested stylesheet) is reached and nothing else on disk is. */
#include "fuzz.h"

#include "httrack-library.h"
#include "htssinglefile.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

/* Between a.png and big.png, so one input reaches both the inline path and the
over-cap fallback. */
#define FUZZ_SF_CAP 64

static char sf_root[512];
static char sf_page[600];

/* The asset tree, in removal order: the subdirectory comes after its file. */
static const char *const sf_files[] = {"a.png", "big.png", "j.js", "s.css",
"sub/b.css", "sub", NULL};

static void sf_cleanup(void) {
char path[700];
int i;

for (i = 0; sf_files[i] != NULL; i++) {
snprintf(path, sizeof(path), "%s/%s", sf_root, sf_files[i]);
(void) remove(path);
}
(void) remove(sf_root);
}

/* A missing asset would silently reduce the target to its parser half. */
static void sf_write(const char *name, const char *data, size_t len) {
char path[700];
FILE *fp;

snprintf(path, sizeof(path), "%s/%s", sf_root, name);
fp = fopen(path, "wb");
if (fp == NULL || fwrite(data, 1, len, fp) != len)
abort();
fclose(fp);
}

static void sf_text(const char *name, const char *data) {
sf_write(name, data, strlen(data));
}

static void sf_init(void) {
static const char png[] = "\x89PNG\r\n\x1a\n";
static const char big[4096] = "\x89PNG";
const char *tmp = getenv("TMPDIR");
char path[700];

hts_init();
snprintf(sf_root, sizeof(sf_root), "%s/httrack-fuzz-sf-XXXXXX",
tmp != NULL && tmp[0] != '\0' ? tmp : "/tmp");
if (mkdtemp(sf_root) == NULL)
abort();
atexit(sf_cleanup);
snprintf(sf_page, sizeof(sf_page), "%s/page.html", sf_root);
snprintf(path, sizeof(path), "%s/sub", sf_root);
if (mkdir(path, 0700) != 0)
abort();
sf_write("a.png", png, sizeof(png) - 1);
sf_write("big.png", big, sizeof(big));
sf_text("j.js", "var x=1;\n");
/* @import plus a url(), so an inlined stylesheet recurses and its own
relative reference is rebased. */
sf_text("s.css", "@import url(sub/b.css);\ndiv{background:url(a.png)}\n");
sf_text("sub/b.css", "p{background:url(../a.png)}\n");
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
static int inited = 0;

String out = STRING_EMPTY;
httrackp *opt;
/* Exact-length, unterminated: the rewriter is span-based, so ASan bounds a
read past html_len instead of it landing on a terminator. */
char *html = malloct(size != 0 ? size : 1);

if (!inited) {
sf_init();
inited = 1;
}
memcpy(html, data, size);

opt = hts_create_opt();
opt->log = opt->errlog = NULL;
opt->single_file_max_size = FUZZ_SF_CAP;

StringClear(out);
(void) singlefile_rewrite_html(opt, sf_root, sf_page, html, size,
SINGLEFILE_MAX_PAGE_SIZE, &out);

StringFree(out);
freet(html);
hts_free_opt(opt);
return 0;
}
20 changes: 20 additions & 0 deletions html/cmdguide.html
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ <h3 id="links">6. Links and page building</h3>
<tr><td><tt>--preserve (-%p), --disable-passwords (-%x)</tt></td><td>Leave HTML untouched (no rewriting), and strip passwords out of saved links.</td></tr>
<tr><td><tt>--extended-parsing (-%P), --parse-java (-j)</tt></td><td>Aggressive link discovery, and how much script content is parsed for links.</td></tr>
<tr><td><tt>--mime-html (-%M)</tt></td><td>Save the whole mirror as a single MIME-encapsulated <tt>.mht</tt> archive (<tt>index.mht</tt>).</td></tr>
<tr><td><tt>--single-file (-%Z), --single-file-max-size N</tt></td><td>Once the mirror is finished, rewrite every saved page with its stylesheets, scripts, images and fonts embedded as <tt>data:</tt> URIs. Assets over the cap (10&nbsp;MB by default) keep their link, as do audio, video, and the links from one page to another. A sibling of <tt>-%M</tt>, not a replacement: see the recipe below for which to pick.</td></tr>
<tr><td><tt>--index (-I), --build-top-index (-%i), --search-index (-%I)</tt></td><td>Build a per-mirror index, a top index across projects, and a searchable keyword index.</td></tr>
</table>

Expand Down Expand Up @@ -491,6 +492,25 @@ <h4>See what a re-crawl changed</h4>
are reported whether or not <tt>--purge-old</tt> is deleting them. The format is
documented in <a href="changes.html">the change report specification</a>.</small></p>

<h4>Pages you can hand to someone as one file</h4>
<p><tt>httrack https://example.com/ --single-file --path mydir</tt><br>
<small>Rewrites each saved page after the crawl so its stylesheets, scripts,
images and fonts are embedded as <tt>data:</tt> URIs. The mirror stays a normal
browsable tree, with links between pages relative and the assets still on disk,
but any single <tt>.html</tt> file can now be mailed or archived on its own.
Raise or lower the 10&nbsp;MB per-asset limit with
<tt>--single-file-max-size N</tt>; anything over it, plus audio and video, keeps
its link. One caveat if you raise it: an inlined stylesheet becomes a
<tt>data:</tt> URL, whose path is opaque, so an asset it referenced that stayed
over the cap no longer resolves from inside it. Raising the cap past that asset
embeds it too and the question goes away.<br>
Reach for this when the file has to open for someone you cannot make assumptions
about: it is plain HTML and needs no add-on. Reach for <tt>--mime-html</tt>
instead when a Chromium-family browser is a given and the mirror is large: MIME
carries text parts without the base64 tax, keeps each resource's original URL,
and stores a shared asset once rather than re-embedding it in every page that
uses it.</small></p>

<h4>HTTrack as a fetch tool</h4>
<p><tt>httrack --get https://host/file.bin --path tmp</tt><br>
<small><tt>--get</tt> fetches one file with cache, index, depth, cookies and robots
Expand Down
25 changes: 22 additions & 3 deletions html/httrack.man.html

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

8 changes: 8 additions & 0 deletions html/server/option2.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ <h2 align="center"><em>${LANG_O2} - ${LANG_IOPT2}</em></h2>
<input type="hidden" name="hidepwd" value="">
<input type="hidden" name="hidequery" value="">
<input type="hidden" name="nopurge" value="">
<input type="hidden" name="singlefile" value="">

${LANG_I33}
<br>
Expand Down Expand Up @@ -143,6 +144,13 @@ <h2 align="center"><em>${LANG_O2} - ${LANG_IOPT2}</em></h2>
<tr><td><input type="checkbox" name="nopurge" ${checked:nopurge}
title='${html:LANG_I1a}' onMouseOver="info('${html:LANG_I1a}'); return true" onMouseOut="info('&nbsp;'); return true"
> ${LANG_I57}</td></tr>
<tr><td><input type="checkbox" name="singlefile" ${checked:singlefile}
title='${html:LANG_SINGLEFILETIP}' onMouseOver="info('${html:LANG_SINGLEFILETIP}'); return true" onMouseOut="info('&nbsp;'); return true"
> ${LANG_SINGLEFILE}</td></tr>
<tr><td>${LANG_SINGLEFILEMAX}
<input name="singlefilemax" value="${singlefilemax}" size="12"
title='${html:LANG_SINGLEFILEMAXTIP}' onMouseOver="info('${html:LANG_SINGLEFILEMAXTIP}'); return true" onMouseOut="info('&nbsp;'); return true"
></td></tr>
</table>

<tr><td>
Expand Down
2 changes: 2 additions & 0 deletions html/server/step2.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ <h2 align="center"><em>${fexist:index.html:LANG_G42}</em></h2>
${do:copy:Warc:warc}
${do:copy:WarcFile:warcfile}
${do:copy:Changes:changes}
${do:copy:SingleFile:singlefile}
${do:copy:SingleFileMaxSize:singlefilemax}
${do:copy:LogType:logtype}
${do:copy:UseHTTPProxyForFTP:ftpprox}
${do:copy:ProxyType:proxytype}
Expand Down
4 changes: 4 additions & 0 deletions html/server/step4.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ <h2 align="center"><em>${LANG_J9}</em></h2>
${test:warc:--warc}
${test:warcfile:--warc-file "}${arg:warcfile}${test:warcfile:"}
${test:changes:--changes}
${test:singlefile:--single-file}
${test:singlefilemax:--single-file-max-size=}${unquoted:singlefilemax}
${test:norecatch:--do-not-recatch}
${test:logf:--single-log}
${test:logtype:::--extra-log:--debug-log}
Expand Down Expand Up @@ -244,6 +246,8 @@ <h2 align="center"><em>${LANG_J9}</em></h2>
Warc=${ztest:warc:0:1}
WarcFile=${warcfile}
Changes=${ztest:changes:0:1}
SingleFile=${ztest:singlefile:0:1}
SingleFileMaxSize=${singlefilemax}
LogType=${logtype}
UseHTTPProxyForFTP=${ztest:ftpprox:0:1}
ProxyType=${proxytype}
Expand Down
8 changes: 8 additions & 0 deletions lang.def
Original file line number Diff line number Diff line change
Expand Up @@ -1046,3 +1046,11 @@ LANG_CHANGES
Report what changed since the previous mirror
LANG_CHANGESTIP
Also write hts-changes.json listing what this crawl left new, changed, unchanged and gone compared to the previous mirror.
LANG_SINGLEFILE
Inline assets as data: URIs (self-contained pages)
LANG_SINGLEFILETIP
Once the mirror is finished, rewrite every saved page with its stylesheets, scripts, images and fonts embedded, so a page can also be opened on its own.
LANG_SINGLEFILEMAX
Largest inlined asset (bytes):
LANG_SINGLEFILEMAXTIP
An asset above this size keeps an ordinary link; leave blank for the 10485760-byte default.
8 changes: 8 additions & 0 deletions lang/Bulgarian.txt
Original file line number Diff line number Diff line change
Expand Up @@ -968,3 +968,11 @@ Report what changed since the previous mirror
Îò÷åò çà ïðîìåíèòå ñïðÿìî ïðåäèøíîòî îãëåäàëî
Also write hts-changes.json listing what this crawl left new, changed, unchanged and gone compared to the previous mirror.
Çàïèñâàíå è íà hts-changes.json ñúñ ñïèñúê íà íîâèòå, ïðîìåíåíèòå, íåïðîìåíåíèòå è èç÷åçíàëèòå ôàéëîâå ñïðÿìî ïðåäèøíîòî îãëåäàëî.
Inline assets as data: URIs (self-contained pages)
Âãðàæäàíå íà ðåñóðñèòå êàòî data: URI (ñàìîñòîÿòåëíè ñòðàíèöè)
Once the mirror is finished, rewrite every saved page with its stylesheets, scripts, images and fonts embedded, so a page can also be opened on its own.
Ñëåä çàâúðøâàíå íà îãëåäàëîòî âñÿêà çàïàçåíà ñòðàíèöà ñå ïðåçàïèñâà ñ âãðàäåíè ñòèëîâå, ñêðèïòîâå, èçîáðàæåíèÿ è øðèôòîâå, òàêà ÷å ñòðàíèöàòà äà ìîæå äà ñå îòâîðè è ñàìîñòîÿòåëíî.
Largest inlined asset (bytes):
Íàé-ãîëÿì âãðàäåí ðåñóðñ (áàéòîâå):
An asset above this size keeps an ordinary link; leave blank for the 10485760-byte default.
Ðåñóðñ íàä òîçè ðàçìåð çàïàçâà îáèêíîâåíà âðúçêà; îñòàâåòå ïðàçíî çà ñòîéíîñòòà ïî ïîäðàçáèðàíå îò 10485760 áàéòà.
8 changes: 8 additions & 0 deletions lang/Castellano.txt
Original file line number Diff line number Diff line change
Expand Up @@ -968,3 +968,11 @@ Report what changed since the previous mirror
Informar de los cambios desde la copia anterior
Also write hts-changes.json listing what this crawl left new, changed, unchanged and gone compared to the previous mirror.
Escribir también hts-changes.json con la lista de lo que esta captura deja como nuevo, modificado, sin cambios o desaparecido respecto a la copia anterior.
Inline assets as data: URIs (self-contained pages)
Incrustar los recursos como URI data: (páginas autónomas)
Once the mirror is finished, rewrite every saved page with its stylesheets, scripts, images and fonts embedded, so a page can also be opened on its own.
Una vez terminada la copia, reescribir cada página guardada con sus hojas de estilo, scripts, imágenes y fuentes incrustadas, de modo que una página también pueda abrirse por sí sola.
Largest inlined asset (bytes):
Tamaño máximo del recurso incrustado (bytes):
An asset above this size keeps an ordinary link; leave blank for the 10485760-byte default.
Un recurso mayor que este tamaño conserva un enlace normal; déjelo vacío para el valor predeterminado de 10485760 bytes.
8 changes: 8 additions & 0 deletions lang/Cesky.txt
Original file line number Diff line number Diff line change
Expand Up @@ -968,3 +968,11 @@ Report what changed since the previous mirror
Hlásit, co se od pøedchozího zrcadlení zmìnilo
Also write hts-changes.json listing what this crawl left new, changed, unchanged and gone compared to the previous mirror.
Zapsat také hts-changes.json se seznamem toho, co je oproti pøedchozímu zrcadlení nové, zmìnìné, nezmìnìné nebo chybìjící.
Inline assets as data: URIs (self-contained pages)
Vložit zdroje jako URI data: (samostatné stránky)
Once the mirror is finished, rewrite every saved page with its stylesheets, scripts, images and fonts embedded, so a page can also be opened on its own.
Po dokonèení zrcadlení pøepsat každou uloženou stránku s vloženými styly, skripty, obrázky a písmy, aby ji bylo možné otevøít i samostatnì.
Largest inlined asset (bytes):
Nejvìtší vložený zdroj (bajty):
An asset above this size keeps an ordinary link; leave blank for the 10485760-byte default.
Zdroj vìtší než tato velikost si ponechá bìžný odkaz; ponechte prázdné pro výchozí hodnotu 10485760 bajtù.
8 changes: 8 additions & 0 deletions lang/Chinese-BIG5.txt
Original file line number Diff line number Diff line change
Expand Up @@ -968,3 +968,11 @@ Report what changed since the previous mirror
¦^³ø¦Û¤W¦¸Ãè®g¥H¨ÓªºÅܧó
Also write hts-changes.json listing what this crawl left new, changed, unchanged and gone compared to the previous mirror.
¦P®É¼g¤J hts-changes.json¡A¦C¥X³o¦¸Â^¨ú¬Û¹ï©ó¤W¦¸Ãè®gªº·s¼W¡BÅܧó¡B¥¼Åܧó»P®ø¥¢ªº¶µ¥Ø¡C
Inline assets as data: URIs (self-contained pages)
±N¸ê·½¤º´O¬° data: URI¡]¿W¥ßºô­¶¡^
Once the mirror is finished, rewrite every saved page with its stylesheets, scripts, images and fonts embedded, so a page can also be opened on its own.
Ãè®g§¹¦¨«á¡A­«¼g¨C­Ó¤wÀx¦sªººô­¶¡A±N¼Ë¦¡ªí¡B«ü¥O½X¡B¹Ï¤ù»P¦r«¬¤º´O¨ä¤¤¡AÅýºô­¶¤]¯à³æ¿W¶}±Ò¡C
Largest inlined asset (bytes):
¤º´O¸ê·½¤j¤p¤W­­¡]¦ì¤¸²Õ¡^¡G
An asset above this size keeps an ordinary link; leave blank for the 10485760-byte default.
¶W¹L¦¹¤j¤pªº¸ê·½·|«O¯d¤@¯ë³sµ²¡F¯dªÅ«h¨Ï¥Î¹w³]ªº 10485760 ¦ì¤¸²Õ¡C
Loading
Loading