config.go 19 KB

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