config.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. package main
  2. import (
  3. "bufio"
  4. "encoding/hex"
  5. "flag"
  6. "fmt"
  7. "math"
  8. "os"
  9. "runtime"
  10. "strconv"
  11. "strings"
  12. )
  13. func intEnvConfig(i *int, name string) {
  14. if env, err := strconv.Atoi(os.Getenv(name)); err == nil {
  15. *i = env
  16. }
  17. }
  18. func floatEnvConfig(i *float64, name string) {
  19. if env, err := strconv.ParseFloat(os.Getenv(name), 64); err == nil {
  20. *i = env
  21. }
  22. }
  23. func megaIntEnvConfig(f *int, name string) {
  24. if env, err := strconv.ParseFloat(os.Getenv(name), 64); err == nil {
  25. *f = int(env * 1000000)
  26. }
  27. }
  28. func strEnvConfig(s *string, name string) {
  29. if env := os.Getenv(name); len(env) > 0 {
  30. *s = env
  31. }
  32. }
  33. func strSliceEnvConfig(s *[]string, name string) {
  34. if env := os.Getenv(name); len(env) > 0 {
  35. parts := strings.Split(env, ",")
  36. for i, p := range parts {
  37. parts[i] = strings.TrimSpace(p)
  38. }
  39. *s = parts
  40. return
  41. }
  42. *s = []string{}
  43. }
  44. func boolEnvConfig(b *bool, name string) {
  45. if env, err := strconv.ParseBool(os.Getenv(name)); err == nil {
  46. *b = env
  47. }
  48. }
  49. func imageTypesEnvConfig(it *[]imageType, name string) {
  50. *it = []imageType{}
  51. if env := os.Getenv(name); len(env) > 0 {
  52. parts := strings.Split(env, ",")
  53. for _, p := range parts {
  54. pt := strings.TrimSpace(p)
  55. if t, ok := imageTypes[pt]; ok {
  56. *it = append(*it, t)
  57. } else {
  58. logWarning("Unknown image format to skip: %s", pt)
  59. }
  60. }
  61. }
  62. }
  63. func formatQualityEnvConfig(m map[imageType]int, name string) {
  64. if env := os.Getenv(name); len(env) > 0 {
  65. parts := strings.Split(env, ",")
  66. for _, p := range parts {
  67. i := strings.Index(p, "=")
  68. if i < 0 {
  69. logWarning("Invalid format quality string: %s", p)
  70. continue
  71. }
  72. imgtypeStr, qStr := strings.TrimSpace(p[:i]), strings.TrimSpace(p[i+1:])
  73. imgtype, ok := imageTypes[imgtypeStr]
  74. if !ok {
  75. logWarning("Invalid format: %s", p)
  76. }
  77. q, err := strconv.Atoi(qStr)
  78. if err != nil || q <= 0 || q > 100 {
  79. logWarning("Invalid quality: %s", p)
  80. }
  81. m[imgtype] = q
  82. }
  83. }
  84. }
  85. func hexEnvConfig(b *[]securityKey, name string) error {
  86. var err error
  87. if env := os.Getenv(name); len(env) > 0 {
  88. parts := strings.Split(env, ",")
  89. keys := make([]securityKey, len(parts))
  90. for i, part := range parts {
  91. if keys[i], err = hex.DecodeString(part); err != nil {
  92. return fmt.Errorf("%s expected to be hex-encoded strings. Invalid: %s\n", name, part)
  93. }
  94. }
  95. *b = keys
  96. }
  97. return nil
  98. }
  99. func hexFileConfig(b *[]securityKey, filepath string) error {
  100. if len(filepath) == 0 {
  101. return nil
  102. }
  103. f, err := os.Open(filepath)
  104. if err != nil {
  105. return fmt.Errorf("Can't open file %s\n", filepath)
  106. }
  107. keys := []securityKey{}
  108. scanner := bufio.NewScanner(f)
  109. for scanner.Scan() {
  110. part := scanner.Text()
  111. if len(part) == 0 {
  112. continue
  113. }
  114. if key, err := hex.DecodeString(part); err == nil {
  115. keys = append(keys, key)
  116. } else {
  117. return fmt.Errorf("%s expected to contain hex-encoded strings. Invalid: %s\n", filepath, part)
  118. }
  119. }
  120. if err := scanner.Err(); err != nil {
  121. return fmt.Errorf("Failed to read file %s: %s", filepath, err)
  122. }
  123. *b = keys
  124. return nil
  125. }
  126. func presetEnvConfig(p presets, name string) error {
  127. if env := os.Getenv(name); len(env) > 0 {
  128. presetStrings := strings.Split(env, ",")
  129. for _, presetStr := range presetStrings {
  130. if err := parsePreset(p, presetStr); err != nil {
  131. return fmt.Errorf(err.Error())
  132. }
  133. }
  134. }
  135. return nil
  136. }
  137. func presetFileConfig(p presets, filepath string) error {
  138. if len(filepath) == 0 {
  139. return nil
  140. }
  141. f, err := os.Open(filepath)
  142. if err != nil {
  143. return fmt.Errorf("Can't open file %s\n", filepath)
  144. }
  145. scanner := bufio.NewScanner(f)
  146. for scanner.Scan() {
  147. if err := parsePreset(p, scanner.Text()); err != nil {
  148. return fmt.Errorf(err.Error())
  149. }
  150. }
  151. if err := scanner.Err(); err != nil {
  152. return fmt.Errorf("Failed to read presets file: %s", err)
  153. }
  154. return nil
  155. }
  156. type config struct {
  157. Network string
  158. Bind string
  159. ReadTimeout int
  160. WriteTimeout int
  161. KeepAliveTimeout int
  162. DownloadTimeout int
  163. Concurrency int
  164. MaxClients int
  165. TTL int
  166. CacheControlPassthrough bool
  167. SetCanonicalHeader bool
  168. SoReuseport bool
  169. PathPrefix string
  170. MaxSrcDimension int
  171. MaxSrcResolution int
  172. MaxSrcFileSize int
  173. MaxAnimationFrames int
  174. MaxSvgCheckBytes int
  175. JpegProgressive bool
  176. PngInterlaced bool
  177. PngQuantize bool
  178. PngQuantizationColors int
  179. AvifSpeed int
  180. Quality int
  181. FormatQuality map[imageType]int
  182. GZipCompression int
  183. StripMetadata bool
  184. StripColorProfile bool
  185. AutoRotate bool
  186. EnableWebpDetection bool
  187. EnforceWebp bool
  188. EnableAvifDetection bool
  189. EnforceAvif bool
  190. EnableClientHints bool
  191. SkipProcessingFormats []imageType
  192. UseLinearColorspace bool
  193. DisableShrinkOnLoad bool
  194. Keys []securityKey
  195. Salts []securityKey
  196. AllowInsecure bool
  197. SignatureSize int
  198. Secret string
  199. AllowOrigin string
  200. UserAgent string
  201. IgnoreSslVerification bool
  202. DevelopmentErrorsMode bool
  203. AllowedSources []string
  204. LocalFileSystemRoot string
  205. S3Enabled bool
  206. S3Region string
  207. S3Endpoint string
  208. GCSEnabled bool
  209. GCSKey string
  210. ABSEnabled bool
  211. ABSName string
  212. ABSKey string
  213. ABSEndpoint string
  214. ETagEnabled bool
  215. BaseURL string
  216. Presets presets
  217. OnlyPresets bool
  218. WatermarkData string
  219. WatermarkPath string
  220. WatermarkURL string
  221. WatermarkOpacity float64
  222. FallbackImageData string
  223. FallbackImagePath string
  224. FallbackImageURL string
  225. NewRelicAppName string
  226. NewRelicKey string
  227. PrometheusBind string
  228. PrometheusNamespace string
  229. BugsnagKey string
  230. BugsnagStage string
  231. HoneybadgerKey string
  232. HoneybadgerEnv string
  233. SentryDSN string
  234. SentryEnvironment string
  235. SentryRelease string
  236. AirbrakeProjecID int
  237. AirbrakeProjecKey string
  238. AirbrakeEnv string
  239. ReportDownloadingErrors bool
  240. EnableDebugHeaders bool
  241. FreeMemoryInterval int
  242. DownloadBufferSize int
  243. GZipBufferSize int
  244. BufferPoolCalibrationThreshold int
  245. }
  246. var conf = config{
  247. Network: "tcp",
  248. Bind: ":8080",
  249. ReadTimeout: 10,
  250. WriteTimeout: 10,
  251. KeepAliveTimeout: 10,
  252. DownloadTimeout: 5,
  253. Concurrency: runtime.NumCPU() * 2,
  254. TTL: 3600,
  255. MaxSrcResolution: 16800000,
  256. MaxAnimationFrames: 1,
  257. MaxSvgCheckBytes: 32 * 1024,
  258. SignatureSize: 32,
  259. PngQuantizationColors: 256,
  260. Quality: 80,
  261. AvifSpeed: 5,
  262. FormatQuality: map[imageType]int{imageTypeAVIF: 50},
  263. StripMetadata: true,
  264. StripColorProfile: true,
  265. AutoRotate: true,
  266. UserAgent: fmt.Sprintf("imgproxy/%s", version),
  267. Presets: make(presets),
  268. WatermarkOpacity: 1,
  269. BugsnagStage: "production",
  270. HoneybadgerEnv: "production",
  271. SentryEnvironment: "production",
  272. SentryRelease: fmt.Sprintf("imgproxy/%s", version),
  273. AirbrakeEnv: "production",
  274. ReportDownloadingErrors: true,
  275. FreeMemoryInterval: 10,
  276. BufferPoolCalibrationThreshold: 1024,
  277. }
  278. func configure() error {
  279. keyPath := flag.String("keypath", "", "path of the file with hex-encoded key")
  280. saltPath := flag.String("saltpath", "", "path of the file with hex-encoded salt")
  281. presetsPath := flag.String("presets", "", "path of the file with presets")
  282. flag.Parse()
  283. if port := os.Getenv("PORT"); len(port) > 0 {
  284. conf.Bind = fmt.Sprintf(":%s", port)
  285. }
  286. strEnvConfig(&conf.Network, "IMGPROXY_NETWORK")
  287. strEnvConfig(&conf.Bind, "IMGPROXY_BIND")
  288. intEnvConfig(&conf.ReadTimeout, "IMGPROXY_READ_TIMEOUT")
  289. intEnvConfig(&conf.WriteTimeout, "IMGPROXY_WRITE_TIMEOUT")
  290. intEnvConfig(&conf.KeepAliveTimeout, "IMGPROXY_KEEP_ALIVE_TIMEOUT")
  291. intEnvConfig(&conf.DownloadTimeout, "IMGPROXY_DOWNLOAD_TIMEOUT")
  292. intEnvConfig(&conf.Concurrency, "IMGPROXY_CONCURRENCY")
  293. intEnvConfig(&conf.MaxClients, "IMGPROXY_MAX_CLIENTS")
  294. intEnvConfig(&conf.TTL, "IMGPROXY_TTL")
  295. boolEnvConfig(&conf.CacheControlPassthrough, "IMGPROXY_CACHE_CONTROL_PASSTHROUGH")
  296. boolEnvConfig(&conf.SetCanonicalHeader, "IMGPROXY_SET_CANONICAL_HEADER")
  297. boolEnvConfig(&conf.SoReuseport, "IMGPROXY_SO_REUSEPORT")
  298. strEnvConfig(&conf.PathPrefix, "IMGPROXY_PATH_PREFIX")
  299. intEnvConfig(&conf.MaxSrcDimension, "IMGPROXY_MAX_SRC_DIMENSION")
  300. megaIntEnvConfig(&conf.MaxSrcResolution, "IMGPROXY_MAX_SRC_RESOLUTION")
  301. intEnvConfig(&conf.MaxSrcFileSize, "IMGPROXY_MAX_SRC_FILE_SIZE")
  302. intEnvConfig(&conf.MaxSvgCheckBytes, "IMGPROXY_MAX_SVG_CHECK_BYTES")
  303. if _, ok := os.LookupEnv("IMGPROXY_MAX_GIF_FRAMES"); ok {
  304. logWarning("`IMGPROXY_MAX_GIF_FRAMES` is deprecated and will be removed in future versions. Use `IMGPROXY_MAX_ANIMATION_FRAMES` instead")
  305. intEnvConfig(&conf.MaxAnimationFrames, "IMGPROXY_MAX_GIF_FRAMES")
  306. }
  307. intEnvConfig(&conf.MaxAnimationFrames, "IMGPROXY_MAX_ANIMATION_FRAMES")
  308. strSliceEnvConfig(&conf.AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
  309. intEnvConfig(&conf.AvifSpeed, "IMGPROXY_AVIF_SPEED")
  310. boolEnvConfig(&conf.JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE")
  311. boolEnvConfig(&conf.PngInterlaced, "IMGPROXY_PNG_INTERLACED")
  312. boolEnvConfig(&conf.PngQuantize, "IMGPROXY_PNG_QUANTIZE")
  313. intEnvConfig(&conf.PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS")
  314. intEnvConfig(&conf.Quality, "IMGPROXY_QUALITY")
  315. formatQualityEnvConfig(conf.FormatQuality, "IMGPROXY_FORMAT_QUALITY")
  316. intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION")
  317. boolEnvConfig(&conf.StripMetadata, "IMGPROXY_STRIP_METADATA")
  318. boolEnvConfig(&conf.StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE")
  319. boolEnvConfig(&conf.AutoRotate, "IMGPROXY_AUTO_ROTATE")
  320. boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
  321. boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
  322. boolEnvConfig(&conf.EnableAvifDetection, "IMGPROXY_ENABLE_AVIF_DETECTION")
  323. boolEnvConfig(&conf.EnforceAvif, "IMGPROXY_ENFORCE_AVIF")
  324. boolEnvConfig(&conf.EnableClientHints, "IMGPROXY_ENABLE_CLIENT_HINTS")
  325. imageTypesEnvConfig(&conf.SkipProcessingFormats, "IMGPROXY_SKIP_PROCESSING_FORMATS")
  326. boolEnvConfig(&conf.UseLinearColorspace, "IMGPROXY_USE_LINEAR_COLORSPACE")
  327. boolEnvConfig(&conf.DisableShrinkOnLoad, "IMGPROXY_DISABLE_SHRINK_ON_LOAD")
  328. if err := hexEnvConfig(&conf.Keys, "IMGPROXY_KEY"); err != nil {
  329. return err
  330. }
  331. if err := hexEnvConfig(&conf.Salts, "IMGPROXY_SALT"); err != nil {
  332. return err
  333. }
  334. intEnvConfig(&conf.SignatureSize, "IMGPROXY_SIGNATURE_SIZE")
  335. if err := hexFileConfig(&conf.Keys, *keyPath); err != nil {
  336. return err
  337. }
  338. if err := hexFileConfig(&conf.Salts, *saltPath); err != nil {
  339. return err
  340. }
  341. strEnvConfig(&conf.Secret, "IMGPROXY_SECRET")
  342. strEnvConfig(&conf.AllowOrigin, "IMGPROXY_ALLOW_ORIGIN")
  343. strEnvConfig(&conf.UserAgent, "IMGPROXY_USER_AGENT")
  344. boolEnvConfig(&conf.IgnoreSslVerification, "IMGPROXY_IGNORE_SSL_VERIFICATION")
  345. boolEnvConfig(&conf.DevelopmentErrorsMode, "IMGPROXY_DEVELOPMENT_ERRORS_MODE")
  346. strEnvConfig(&conf.LocalFileSystemRoot, "IMGPROXY_LOCAL_FILESYSTEM_ROOT")
  347. boolEnvConfig(&conf.S3Enabled, "IMGPROXY_USE_S3")
  348. strEnvConfig(&conf.S3Region, "IMGPROXY_S3_REGION")
  349. strEnvConfig(&conf.S3Endpoint, "IMGPROXY_S3_ENDPOINT")
  350. boolEnvConfig(&conf.GCSEnabled, "IMGPROXY_USE_GCS")
  351. strEnvConfig(&conf.GCSKey, "IMGPROXY_GCS_KEY")
  352. boolEnvConfig(&conf.ABSEnabled, "IMGPROXY_USE_ABS")
  353. strEnvConfig(&conf.ABSName, "IMGPROXY_ABS_NAME")
  354. strEnvConfig(&conf.ABSKey, "IMGPROXY_ABS_KEY")
  355. strEnvConfig(&conf.ABSEndpoint, "IMGPROXY_ABS_ENDPOINT")
  356. boolEnvConfig(&conf.ETagEnabled, "IMGPROXY_USE_ETAG")
  357. strEnvConfig(&conf.BaseURL, "IMGPROXY_BASE_URL")
  358. if err := presetEnvConfig(conf.Presets, "IMGPROXY_PRESETS"); err != nil {
  359. return err
  360. }
  361. if err := presetFileConfig(conf.Presets, *presetsPath); err != nil {
  362. return err
  363. }
  364. boolEnvConfig(&conf.OnlyPresets, "IMGPROXY_ONLY_PRESETS")
  365. strEnvConfig(&conf.WatermarkData, "IMGPROXY_WATERMARK_DATA")
  366. strEnvConfig(&conf.WatermarkPath, "IMGPROXY_WATERMARK_PATH")
  367. strEnvConfig(&conf.WatermarkURL, "IMGPROXY_WATERMARK_URL")
  368. floatEnvConfig(&conf.WatermarkOpacity, "IMGPROXY_WATERMARK_OPACITY")
  369. strEnvConfig(&conf.FallbackImageData, "IMGPROXY_FALLBACK_IMAGE_DATA")
  370. strEnvConfig(&conf.FallbackImagePath, "IMGPROXY_FALLBACK_IMAGE_PATH")
  371. strEnvConfig(&conf.FallbackImageURL, "IMGPROXY_FALLBACK_IMAGE_URL")
  372. strEnvConfig(&conf.NewRelicAppName, "IMGPROXY_NEW_RELIC_APP_NAME")
  373. strEnvConfig(&conf.NewRelicKey, "IMGPROXY_NEW_RELIC_KEY")
  374. strEnvConfig(&conf.PrometheusBind, "IMGPROXY_PROMETHEUS_BIND")
  375. strEnvConfig(&conf.PrometheusNamespace, "IMGPROXY_PROMETHEUS_NAMESPACE")
  376. strEnvConfig(&conf.BugsnagKey, "IMGPROXY_BUGSNAG_KEY")
  377. strEnvConfig(&conf.BugsnagStage, "IMGPROXY_BUGSNAG_STAGE")
  378. strEnvConfig(&conf.HoneybadgerKey, "IMGPROXY_HONEYBADGER_KEY")
  379. strEnvConfig(&conf.HoneybadgerEnv, "IMGPROXY_HONEYBADGER_ENV")
  380. strEnvConfig(&conf.SentryDSN, "IMGPROXY_SENTRY_DSN")
  381. strEnvConfig(&conf.SentryEnvironment, "IMGPROXY_SENTRY_ENVIRONMENT")
  382. strEnvConfig(&conf.SentryRelease, "IMGPROXY_SENTRY_RELEASE")
  383. intEnvConfig(&conf.AirbrakeProjecID, "IMGPROXY_AIRBRAKE_PROJECT_ID")
  384. strEnvConfig(&conf.AirbrakeProjecKey, "IMGPROXY_AIRBRAKE_PROJECT_KEY")
  385. strEnvConfig(&conf.AirbrakeEnv, "IMGPROXY_AIRBRAKE_ENVIRONMENT")
  386. boolEnvConfig(&conf.ReportDownloadingErrors, "IMGPROXY_REPORT_DOWNLOADING_ERRORS")
  387. boolEnvConfig(&conf.EnableDebugHeaders, "IMGPROXY_ENABLE_DEBUG_HEADERS")
  388. intEnvConfig(&conf.FreeMemoryInterval, "IMGPROXY_FREE_MEMORY_INTERVAL")
  389. intEnvConfig(&conf.DownloadBufferSize, "IMGPROXY_DOWNLOAD_BUFFER_SIZE")
  390. intEnvConfig(&conf.GZipBufferSize, "IMGPROXY_GZIP_BUFFER_SIZE")
  391. intEnvConfig(&conf.BufferPoolCalibrationThreshold, "IMGPROXY_BUFFER_POOL_CALIBRATION_THRESHOLD")
  392. if len(conf.Keys) != len(conf.Salts) {
  393. return fmt.Errorf("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(conf.Keys), len(conf.Salts))
  394. }
  395. if len(conf.Keys) == 0 {
  396. logWarning("No keys defined, so signature checking is disabled")
  397. conf.AllowInsecure = true
  398. }
  399. if len(conf.Salts) == 0 {
  400. logWarning("No salts defined, so signature checking is disabled")
  401. conf.AllowInsecure = true
  402. }
  403. if conf.SignatureSize < 1 || conf.SignatureSize > 32 {
  404. return fmt.Errorf("Signature size should be within 1 and 32, now - %d\n", conf.SignatureSize)
  405. }
  406. if len(conf.Bind) == 0 {
  407. return fmt.Errorf("Bind address is not defined")
  408. }
  409. if conf.ReadTimeout <= 0 {
  410. return fmt.Errorf("Read timeout should be greater than 0, now - %d\n", conf.ReadTimeout)
  411. }
  412. if conf.WriteTimeout <= 0 {
  413. return fmt.Errorf("Write timeout should be greater than 0, now - %d\n", conf.WriteTimeout)
  414. }
  415. if conf.KeepAliveTimeout < 0 {
  416. return fmt.Errorf("KeepAlive timeout should be greater than or equal to 0, now - %d\n", conf.KeepAliveTimeout)
  417. }
  418. if conf.DownloadTimeout <= 0 {
  419. return fmt.Errorf("Download timeout should be greater than 0, now - %d\n", conf.DownloadTimeout)
  420. }
  421. if conf.Concurrency <= 0 {
  422. return fmt.Errorf("Concurrency should be greater than 0, now - %d\n", conf.Concurrency)
  423. }
  424. if conf.MaxClients <= 0 {
  425. conf.MaxClients = conf.Concurrency * 10
  426. }
  427. if conf.TTL <= 0 {
  428. return fmt.Errorf("TTL should be greater than 0, now - %d\n", conf.TTL)
  429. }
  430. if conf.MaxSrcDimension < 0 {
  431. return fmt.Errorf("Max src dimension should be greater than or equal to 0, now - %d\n", conf.MaxSrcDimension)
  432. } else if conf.MaxSrcDimension > 0 {
  433. logWarning("IMGPROXY_MAX_SRC_DIMENSION is deprecated and can be removed in future versions. Use IMGPROXY_MAX_SRC_RESOLUTION")
  434. }
  435. if conf.MaxSrcResolution <= 0 {
  436. return fmt.Errorf("Max src resolution should be greater than 0, now - %d\n", conf.MaxSrcResolution)
  437. }
  438. if conf.MaxSrcFileSize < 0 {
  439. return fmt.Errorf("Max src file size should be greater than or equal to 0, now - %d\n", conf.MaxSrcFileSize)
  440. }
  441. if conf.MaxAnimationFrames <= 0 {
  442. return fmt.Errorf("Max animation frames should be greater than 0, now - %d\n", conf.MaxAnimationFrames)
  443. }
  444. if conf.PngQuantizationColors < 2 {
  445. return fmt.Errorf("Png quantization colors should be greater than 1, now - %d\n", conf.PngQuantizationColors)
  446. } else if conf.PngQuantizationColors > 256 {
  447. return fmt.Errorf("Png quantization colors can't be greater than 256, now - %d\n", conf.PngQuantizationColors)
  448. }
  449. if conf.Quality <= 0 {
  450. return fmt.Errorf("Quality should be greater than 0, now - %d\n", conf.Quality)
  451. } else if conf.Quality > 100 {
  452. return fmt.Errorf("Quality can't be greater than 100, now - %d\n", conf.Quality)
  453. }
  454. if conf.AvifSpeed <= 0 {
  455. return fmt.Errorf("Avif speed should be greater than 0, now - %d\n", conf.AvifSpeed)
  456. } else if conf.AvifSpeed > 8 {
  457. return fmt.Errorf("Avif speed can't be greater than 8, now - %d\n", conf.AvifSpeed)
  458. }
  459. if conf.GZipCompression < 0 {
  460. return fmt.Errorf("GZip compression should be greater than or equal to 0, now - %d\n", conf.GZipCompression)
  461. } else if conf.GZipCompression > 9 {
  462. return fmt.Errorf("GZip compression can't be greater than 9, now - %d\n", conf.GZipCompression)
  463. }
  464. if conf.GZipCompression > 0 {
  465. logWarning("GZip compression is deprecated and can be removed in future versions")
  466. }
  467. if conf.IgnoreSslVerification {
  468. logWarning("Ignoring SSL verification is very unsafe")
  469. }
  470. if conf.LocalFileSystemRoot != "" {
  471. stat, err := os.Stat(conf.LocalFileSystemRoot)
  472. if err != nil {
  473. return fmt.Errorf("Cannot use local directory: %s", err)
  474. }
  475. if !stat.IsDir() {
  476. return fmt.Errorf("Cannot use local directory: not a directory")
  477. }
  478. if conf.LocalFileSystemRoot == "/" {
  479. logWarning("Exposing root via IMGPROXY_LOCAL_FILESYSTEM_ROOT is unsafe")
  480. }
  481. }
  482. if _, ok := os.LookupEnv("IMGPROXY_USE_GCS"); !ok && len(conf.GCSKey) > 0 {
  483. logWarning("Set IMGPROXY_USE_GCS to true since it may be required by future versions to enable GCS support")
  484. conf.GCSEnabled = true
  485. }
  486. if conf.WatermarkOpacity <= 0 {
  487. return fmt.Errorf("Watermark opacity should be greater than 0")
  488. } else if conf.WatermarkOpacity > 1 {
  489. return fmt.Errorf("Watermark opacity should be less than or equal to 1")
  490. }
  491. if len(conf.PrometheusBind) > 0 && conf.PrometheusBind == conf.Bind {
  492. return fmt.Errorf("Can't use the same binding for the main server and Prometheus")
  493. }
  494. if conf.FreeMemoryInterval <= 0 {
  495. return fmt.Errorf("Free memory interval should be greater than zero")
  496. }
  497. if conf.DownloadBufferSize < 0 {
  498. return fmt.Errorf("Download buffer size should be greater than or equal to 0")
  499. } else if conf.DownloadBufferSize > math.MaxInt32 {
  500. return fmt.Errorf("Download buffer size can't be greater than %d", math.MaxInt32)
  501. }
  502. if conf.GZipBufferSize < 0 {
  503. return fmt.Errorf("GZip buffer size should be greater than or equal to 0")
  504. } else if conf.GZipBufferSize > math.MaxInt32 {
  505. return fmt.Errorf("GZip buffer size can't be greater than %d", math.MaxInt32)
  506. }
  507. if conf.BufferPoolCalibrationThreshold < 64 {
  508. return fmt.Errorf("Buffer pool calibration threshold should be greater than or equal to 64")
  509. }
  510. return nil
  511. }