MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s
- Table media (migration 5), files in $DATA_DIR/media/<docId>/.
- POST /documents/{id}/media (write access), POST .../media/fetch copies an
external https image (SSRF-guarded, not in the demo), GET /media/{id}
with range requests for readers of a note that shows the file.
- Format detected from the content (no SVG); own sandbox CSP on answers.
- Blocks point to files through their content (media:<id>), so the note
sync needs no change; compaction removes files no block mentions any
more after a day. Demo reset and demo start clear the folder.
- Limits MEDIA_MAX_IMAGE_MB, MEDIA_MAX_AUDIO_MB, MEDIA_QUOTA_MB,
MEDIA_DEMO_MAX_MB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 lines
1.5 KiB
Go
47 lines
1.5 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/sandrodach/mindsift/internal/storage"
|
|
)
|
|
|
|
// Request bodies are capped for every endpoint (FLAW-36), so a session or API key cannot tie up memory
|
|
// with huge uploads. Note sync and imports need more; their handlers apply the same limits again.
|
|
const defaultMaxBody = 2 << 20
|
|
|
|
func (s *Server) bodyLimitFor(path string) int64 {
|
|
switch {
|
|
case strings.HasPrefix(path, "/api/v1/documents/") && strings.HasSuffix(path, "/media"):
|
|
return s.mediaUploadLimit()
|
|
case path == "/api/v1/voice/transcribe":
|
|
return int64(s.cfg.Speech.MaxUploadMB)<<20 + 1<<20
|
|
case strings.HasPrefix(path, "/api/v1/import/"):
|
|
return storage.MaxImportUploadBytes + 1<<20
|
|
case strings.HasPrefix(path, "/api/v1/docs/") && strings.HasSuffix(path, "/sync"):
|
|
return syncMaxBody
|
|
}
|
|
return defaultMaxBody
|
|
}
|
|
|
|
func (s *Server) bodyLimit(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Body != nil && r.Body != http.NoBody {
|
|
r.Body = http.MaxBytesReader(w, r.Body, s.bodyLimitFor(r.URL.Path))
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// The server gives every request 15 s to send its body and 30 s for the answer. Whole archives on a slow
|
|
// line need longer: downloads of backups and exports, uploads of imports (FLAW-38).
|
|
const longTransferTime = 30 * time.Minute
|
|
|
|
func allowLongTransfer(w http.ResponseWriter) {
|
|
rc := http.NewResponseController(w)
|
|
_ = rc.SetWriteDeadline(time.Now().Add(longTransferTime))
|
|
_ = rc.SetReadDeadline(time.Now().Add(longTransferTime))
|
|
}
|