v0.128.0: chunked browser .fab upload on /import (tunnel-proof)
Cloudflare edge caps request bodies (~100 MB, probed live: 120 MiB -> edge 413,
80 MiB -> origin), so the client slices the file into 64 MiB strictly-sequential
chunks; the server streams each to a .part file in the default drive's exports
dir and finalize renames atomically. Scan/validate/import pipeline untouched.
upload/{init,chunk,finalize,abort} inside ServeExportAPI (inherits auth+CSRF);
single-flight; offset==received or 409+echo; free-space gate; collision ->
lowest-free "name (N).fab"; startup GC of *.part-*; 15-min idle abort.
appexport.DiskFree exported (seam web.uploadDiskFree). Scenarios A-F tested,
red-proofs run (traversal / out-of-order / overwrite).
This commit is contained in:
@@ -52,6 +52,17 @@ func (s *Server) ServeExportAPI(w http.ResponseWriter, r *http.Request) {
|
||||
case path == "/api/export/download" && r.Method == http.MethodGet:
|
||||
s.apiExportDownloadFetch(w, r)
|
||||
|
||||
// Chunked browser .fab upload (v0.128.0) — lands in the default drive's exports dir, then
|
||||
// the bundle scan + import pipeline take over untouched. See handler_export_upload.go.
|
||||
case path == "/api/export/upload/init" && r.Method == http.MethodPost:
|
||||
s.apiUploadInit(w, r)
|
||||
case path == "/api/export/upload/chunk" && r.Method == http.MethodPost:
|
||||
s.apiUploadChunk(w, r)
|
||||
case path == "/api/export/upload/finalize" && r.Method == http.MethodPost:
|
||||
s.apiUploadFinalize(w, r)
|
||||
case path == "/api/export/upload/abort" && r.Method == http.MethodPost:
|
||||
s.apiUploadAbort(w, r)
|
||||
|
||||
// GET /api/export/bundles — scan for .fab files on all drives
|
||||
case path == "/api/export/bundles" && r.Method == http.MethodGet:
|
||||
s.apiExportBundles(w, r)
|
||||
|
||||
Reference in New Issue
Block a user