返回 DeepSeek-Reasonix
markdown_image_budget.go
根目录 / desktop / markdown_image_budget.go
1 package main
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "image"
8 _ "image/gif"
9 _ "image/jpeg"
10 _ "image/png"
11 "io"
12 "os"
13
14 _ "golang.org/x/image/bmp"
15 "golang.org/x/image/webp"
16 )
17
18 const markdownImageMaxPixels int64 = 40_000_000
19
20 var errMarkdownImageTooLarge = errors.New("markdown image exceeds the decode budget")
21
22 func validateOpenMarkdownImageFile(f *os.File, mimeType string, size int64) error {
23 if size <= 0 {
24 return fmt.Errorf("empty image")
25 }
26 if size > remoteMarkdownImageMaxBytes {
27 return errMarkdownImageTooLarge
28 }
29 return validateMarkdownImageConfig(f, mimeType)
30 }
31
32 func validateMarkdownImageBytes(body []byte, mimeType string) error {
33 if len(body) == 0 {
34 return fmt.Errorf("empty image")
35 }
36 if len(body) > remoteMarkdownImageMaxBytes {
37 return errMarkdownImageTooLarge
38 }
39 return validateMarkdownImageConfig(bytes.NewReader(body), mimeType)
40 }
41
42 func validateMarkdownImageConfig(r io.Reader, mimeType string) error {
43 // SVG is sanitized by the remote proxy and does not allocate a source-sized
44 // raster during Go-side validation. ICO remains byte-bounded; Go has no
45 // decoder for it in the supported dependency set.
46 if mimeType == "image/svg+xml" || mimeType == "image/x-icon" {
47 return nil
48 }
49
50 var (
51 cfg image.Config
52 format string
53 err error
54 )
55 if mimeType == "image/webp" {
56 cfg, err = webp.DecodeConfig(r)
57 format = "webp"
58 } else {
59 cfg, format, err = image.DecodeConfig(r)
60 }
61 if err != nil {
62 return fmt.Errorf("decode image config: %w", err)
63 }
64 wantFormat := map[string]string{
65 "image/png": "png",
66 "image/jpeg": "jpeg",
67 "image/gif": "gif",
68 "image/bmp": "bmp",
69 "image/webp": "webp",
70 }[mimeType]
71 if wantFormat == "" || format != wantFormat {
72 return fmt.Errorf("image MIME/format mismatch: %s/%s", mimeType, format)
73 }
74 if cfg.Width <= 0 || cfg.Height <= 0 {
75 return fmt.Errorf("invalid image dimensions")
76 }
77 if int64(cfg.Width) > markdownImageMaxPixels/int64(cfg.Height) {
78 return errMarkdownImageTooLarge
79 }
80 return nil
81 }
82
82 lines GO