mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-01-08 10:45:04 +02:00
Extract processing handler and imageType functions from server.go
This commit is contained in:
parent
86c883f04b
commit
a9244a7063
96
image_type.go
Normal file
96
image_type.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -s -w
|
||||||
|
#include "vips.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type imageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
imageTypeUnknown = imageType(C.UNKNOWN)
|
||||||
|
imageTypeJPEG = imageType(C.JPEG)
|
||||||
|
imageTypePNG = imageType(C.PNG)
|
||||||
|
imageTypeWEBP = imageType(C.WEBP)
|
||||||
|
imageTypeGIF = imageType(C.GIF)
|
||||||
|
imageTypeICO = imageType(C.ICO)
|
||||||
|
imageTypeSVG = imageType(C.SVG)
|
||||||
|
imageTypeHEIC = imageType(C.HEIC)
|
||||||
|
|
||||||
|
contentDispositionFilenameFallback = "image"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
imageTypes = map[string]imageType{
|
||||||
|
"jpeg": imageTypeJPEG,
|
||||||
|
"jpg": imageTypeJPEG,
|
||||||
|
"png": imageTypePNG,
|
||||||
|
"webp": imageTypeWEBP,
|
||||||
|
"gif": imageTypeGIF,
|
||||||
|
"ico": imageTypeICO,
|
||||||
|
"svg": imageTypeSVG,
|
||||||
|
"heic": imageTypeHEIC,
|
||||||
|
}
|
||||||
|
|
||||||
|
mimes = map[imageType]string{
|
||||||
|
imageTypeJPEG: "image/jpeg",
|
||||||
|
imageTypePNG: "image/png",
|
||||||
|
imageTypeWEBP: "image/webp",
|
||||||
|
imageTypeGIF: "image/gif",
|
||||||
|
imageTypeICO: "image/x-icon",
|
||||||
|
imageTypeHEIC: "image/heif",
|
||||||
|
}
|
||||||
|
|
||||||
|
contentDispositionsFmt = map[imageType]string{
|
||||||
|
imageTypeJPEG: "inline; filename=\"%s.jpg\"",
|
||||||
|
imageTypePNG: "inline; filename=\"%s.png\"",
|
||||||
|
imageTypeWEBP: "inline; filename=\"%s.webp\"",
|
||||||
|
imageTypeGIF: "inline; filename=\"%s.gif\"",
|
||||||
|
imageTypeICO: "inline; filename=\"%s.ico\"",
|
||||||
|
imageTypeHEIC: "inline; filename=\"%s.heic\"",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (it imageType) String() string {
|
||||||
|
for k, v := range imageTypes {
|
||||||
|
if v == it {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it imageType) Mime() string {
|
||||||
|
if mime, ok := mimes[it]; ok {
|
||||||
|
return mime
|
||||||
|
} else {
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it imageType) ContentDisposition(imageURL string) string {
|
||||||
|
format, ok := contentDispositionsFmt[it]
|
||||||
|
if !ok {
|
||||||
|
return "inline"
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := url.Parse(imageURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf(format, contentDispositionFilenameFallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, filename := filepath.Split(url.Path)
|
||||||
|
if len(filename) == 0 {
|
||||||
|
return fmt.Sprintf(format, contentDispositionFilenameFallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(format, strings.TrimSuffix(filename, filepath.Ext(filename)))
|
||||||
|
}
|
149
processing_handler.go
Normal file
149
processing_handler.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
responseGzipBufPool *bufPool
|
||||||
|
responseGzipPool *gzipPool
|
||||||
|
|
||||||
|
processingSem chan struct{}
|
||||||
|
|
||||||
|
headerVaryValue string
|
||||||
|
)
|
||||||
|
|
||||||
|
func initProcessingHandler() {
|
||||||
|
processingSem = make(chan struct{}, conf.Concurrency)
|
||||||
|
|
||||||
|
if conf.GZipCompression > 0 {
|
||||||
|
responseGzipBufPool = newBufPool("gzip", conf.Concurrency, conf.GZipBufferSize)
|
||||||
|
responseGzipPool = newGzipPool(conf.Concurrency)
|
||||||
|
}
|
||||||
|
|
||||||
|
vary := make([]string, 0)
|
||||||
|
|
||||||
|
if conf.EnableWebpDetection || conf.EnforceWebp {
|
||||||
|
vary = append(vary, "Accept")
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.GZipCompression > 0 {
|
||||||
|
vary = append(vary, "Accept-Encoding")
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.EnableClientHints {
|
||||||
|
vary = append(vary, "DPR", "Viewport-Width", "Width")
|
||||||
|
}
|
||||||
|
|
||||||
|
headerVaryValue = strings.Join(vary, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func respondWithImage(ctx context.Context, reqID string, r *http.Request, rw http.ResponseWriter, data []byte) {
|
||||||
|
po := getProcessingOptions(ctx)
|
||||||
|
|
||||||
|
rw.Header().Set("Expires", time.Now().Add(time.Second*time.Duration(conf.TTL)).Format(http.TimeFormat))
|
||||||
|
rw.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d, public", conf.TTL))
|
||||||
|
rw.Header().Set("Content-Type", po.Format.Mime())
|
||||||
|
rw.Header().Set("Content-Disposition", po.Format.ContentDisposition(getImageURL(ctx)))
|
||||||
|
|
||||||
|
if len(headerVaryValue) > 0 {
|
||||||
|
rw.Header().Set("Vary", headerVaryValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.GZipCompression > 0 && strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||||
|
buf := responseGzipBufPool.Get(0)
|
||||||
|
defer responseGzipBufPool.Put(buf)
|
||||||
|
|
||||||
|
gz := responseGzipPool.Get(buf)
|
||||||
|
defer responseGzipPool.Put(gz)
|
||||||
|
|
||||||
|
gz.Write(data)
|
||||||
|
gz.Close()
|
||||||
|
|
||||||
|
rw.Header().Set("Content-Encoding", "gzip")
|
||||||
|
rw.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
|
||||||
|
|
||||||
|
rw.WriteHeader(200)
|
||||||
|
rw.Write(buf.Bytes())
|
||||||
|
} else {
|
||||||
|
rw.Header().Set("Content-Length", strconv.Itoa(len(data)))
|
||||||
|
rw.WriteHeader(200)
|
||||||
|
rw.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
logResponse(reqID, 200, fmt.Sprintf("Processed in %s: %s; %+v", getTimerSince(ctx), getImageURL(ctx), po))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if newRelicEnabled {
|
||||||
|
var newRelicCancel context.CancelFunc
|
||||||
|
ctx, newRelicCancel = startNewRelicTransaction(ctx, rw, r)
|
||||||
|
defer newRelicCancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if prometheusEnabled {
|
||||||
|
prometheusRequestsTotal.Inc()
|
||||||
|
defer startPrometheusDuration(prometheusRequestDuration)()
|
||||||
|
}
|
||||||
|
|
||||||
|
processingSem <- struct{}{}
|
||||||
|
defer func() { <-processingSem }()
|
||||||
|
|
||||||
|
ctx, timeoutCancel := startTimer(ctx, time.Duration(conf.WriteTimeout)*time.Second)
|
||||||
|
defer timeoutCancel()
|
||||||
|
|
||||||
|
ctx, err := parsePath(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, downloadcancel, err := downloadImage(ctx)
|
||||||
|
defer downloadcancel()
|
||||||
|
if err != nil {
|
||||||
|
if newRelicEnabled {
|
||||||
|
sendErrorToNewRelic(ctx, err)
|
||||||
|
}
|
||||||
|
if prometheusEnabled {
|
||||||
|
incrementPrometheusErrorsTotal("download")
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTimeout(ctx)
|
||||||
|
|
||||||
|
if conf.ETagEnabled {
|
||||||
|
eTag := calcETag(ctx)
|
||||||
|
rw.Header().Set("ETag", eTag)
|
||||||
|
|
||||||
|
if eTag == r.Header.Get("If-None-Match") {
|
||||||
|
logResponse(reqID, 304, "Not modified")
|
||||||
|
rw.WriteHeader(304)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTimeout(ctx)
|
||||||
|
|
||||||
|
imageData, processcancel, err := processImage(ctx)
|
||||||
|
defer processcancel()
|
||||||
|
if err != nil {
|
||||||
|
if newRelicEnabled {
|
||||||
|
sendErrorToNewRelic(ctx, err)
|
||||||
|
}
|
||||||
|
if prometheusEnabled {
|
||||||
|
incrementPrometheusErrorsTotal("processing")
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTimeout(ctx)
|
||||||
|
|
||||||
|
respondWithImage(ctx, reqID, r, rw, imageData)
|
||||||
|
}
|
@ -1,11 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo LDFLAGS: -s -w
|
|
||||||
#include "vips.h"
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
@ -20,19 +14,6 @@ import (
|
|||||||
|
|
||||||
type urlOptions map[string][]string
|
type urlOptions map[string][]string
|
||||||
|
|
||||||
type imageType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
imageTypeUnknown = imageType(C.UNKNOWN)
|
|
||||||
imageTypeJPEG = imageType(C.JPEG)
|
|
||||||
imageTypePNG = imageType(C.PNG)
|
|
||||||
imageTypeWEBP = imageType(C.WEBP)
|
|
||||||
imageTypeGIF = imageType(C.GIF)
|
|
||||||
imageTypeICO = imageType(C.ICO)
|
|
||||||
imageTypeSVG = imageType(C.SVG)
|
|
||||||
imageTypeHEIC = imageType(C.HEIC)
|
|
||||||
)
|
|
||||||
|
|
||||||
type processingHeaders struct {
|
type processingHeaders struct {
|
||||||
Accept string
|
Accept string
|
||||||
Width string
|
Width string
|
||||||
@ -40,17 +21,6 @@ type processingHeaders struct {
|
|||||||
DPR string
|
DPR string
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageTypes = map[string]imageType{
|
|
||||||
"jpeg": imageTypeJPEG,
|
|
||||||
"jpg": imageTypeJPEG,
|
|
||||||
"png": imageTypePNG,
|
|
||||||
"webp": imageTypeWEBP,
|
|
||||||
"gif": imageTypeGIF,
|
|
||||||
"ico": imageTypeICO,
|
|
||||||
"svg": imageTypeSVG,
|
|
||||||
"heic": imageTypeHEIC,
|
|
||||||
}
|
|
||||||
|
|
||||||
type gravityType int
|
type gravityType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -158,15 +128,6 @@ var (
|
|||||||
errInvalidPath = newError(404, "Invalid path", msgInvalidURL)
|
errInvalidPath = newError(404, "Invalid path", msgInvalidURL)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (it imageType) String() string {
|
|
||||||
for k, v := range imageTypes {
|
|
||||||
if v == it {
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gt gravityType) String() string {
|
func (gt gravityType) String() string {
|
||||||
for k, v := range gravityTypes {
|
for k, v := range gravityTypes {
|
||||||
if v == gt {
|
if v == gt {
|
||||||
|
209
server.go
209
server.go
@ -6,47 +6,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/netutil"
|
"golang.org/x/net/netutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
contextDispositionFilenameFallback = "image"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mimes = map[imageType]string{
|
|
||||||
imageTypeJPEG: "image/jpeg",
|
|
||||||
imageTypePNG: "image/png",
|
|
||||||
imageTypeWEBP: "image/webp",
|
|
||||||
imageTypeGIF: "image/gif",
|
|
||||||
imageTypeICO: "image/x-icon",
|
|
||||||
imageTypeHEIC: "image/heif",
|
|
||||||
}
|
|
||||||
|
|
||||||
contentDispositionsFmt = map[imageType]string{
|
|
||||||
imageTypeJPEG: "inline; filename=\"%s.jpg\"",
|
|
||||||
imageTypePNG: "inline; filename=\"%s.png\"",
|
|
||||||
imageTypeWEBP: "inline; filename=\"%s.webp\"",
|
|
||||||
imageTypeGIF: "inline; filename=\"%s.gif\"",
|
|
||||||
imageTypeICO: "inline; filename=\"%s.ico\"",
|
|
||||||
imageTypeHEIC: "inline; filename=\"%s.heic\"",
|
|
||||||
}
|
|
||||||
|
|
||||||
imgproxyIsRunningMsg = []byte("imgproxy is running")
|
imgproxyIsRunningMsg = []byte("imgproxy is running")
|
||||||
|
|
||||||
errInvalidMethod = newError(422, "Invalid request method", "Method doesn't allowed")
|
|
||||||
errInvalidSecret = newError(403, "Invalid secret", "Forbidden")
|
errInvalidSecret = newError(403, "Invalid secret", "Forbidden")
|
||||||
|
|
||||||
responseGzipBufPool *bufPool
|
|
||||||
responseGzipPool *gzipPool
|
|
||||||
|
|
||||||
processingSem chan struct{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildRouter() *router {
|
func buildRouter() *router {
|
||||||
@ -62,8 +30,6 @@ func buildRouter() *router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startServer() *http.Server {
|
func startServer() *http.Server {
|
||||||
processingSem = make(chan struct{}, conf.Concurrency)
|
|
||||||
|
|
||||||
l, err := net.Listen("tcp", conf.Bind)
|
l, err := net.Listen("tcp", conf.Bind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logFatal(err.Error())
|
logFatal(err.Error())
|
||||||
@ -76,10 +42,7 @@ func startServer() *http.Server {
|
|||||||
MaxHeaderBytes: 1 << 20,
|
MaxHeaderBytes: 1 << 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.GZipCompression > 0 {
|
initProcessingHandler()
|
||||||
responseGzipBufPool = newBufPool("gzip", conf.Concurrency, conf.GZipBufferSize)
|
|
||||||
responseGzipPool = newGzipPool(conf.Concurrency)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
logNotice("Starting server at %s", conf.Bind)
|
logNotice("Starting server at %s", conf.Bind)
|
||||||
@ -100,86 +63,6 @@ func shutdownServer(s *http.Server) {
|
|||||||
s.Shutdown(ctx)
|
s.Shutdown(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func contentDisposition(imageURL string, imgtype imageType) string {
|
|
||||||
url, err := url.Parse(imageURL)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Sprintf(contentDispositionsFmt[imgtype], contextDispositionFilenameFallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, filename := filepath.Split(url.Path)
|
|
||||||
if len(filename) == 0 {
|
|
||||||
return fmt.Sprintf(contentDispositionsFmt[imgtype], contextDispositionFilenameFallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(contentDispositionsFmt[imgtype], strings.TrimSuffix(filename, filepath.Ext(filename)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func respondWithImage(ctx context.Context, reqID string, r *http.Request, rw http.ResponseWriter, data []byte) {
|
|
||||||
po := getProcessingOptions(ctx)
|
|
||||||
|
|
||||||
rw.Header().Set("Expires", time.Now().Add(time.Second*time.Duration(conf.TTL)).Format(http.TimeFormat))
|
|
||||||
rw.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d, public", conf.TTL))
|
|
||||||
rw.Header().Set("Content-Type", mimes[po.Format])
|
|
||||||
rw.Header().Set("Content-Disposition", contentDisposition(getImageURL(ctx), po.Format))
|
|
||||||
|
|
||||||
addVaryHeader(rw)
|
|
||||||
|
|
||||||
if conf.GZipCompression > 0 && strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
|
||||||
buf := responseGzipBufPool.Get(0)
|
|
||||||
defer responseGzipBufPool.Put(buf)
|
|
||||||
|
|
||||||
gz := responseGzipPool.Get(buf)
|
|
||||||
defer responseGzipPool.Put(gz)
|
|
||||||
|
|
||||||
gz.Write(data)
|
|
||||||
gz.Close()
|
|
||||||
|
|
||||||
rw.Header().Set("Content-Encoding", "gzip")
|
|
||||||
rw.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
|
|
||||||
|
|
||||||
rw.WriteHeader(200)
|
|
||||||
rw.Write(buf.Bytes())
|
|
||||||
} else {
|
|
||||||
rw.Header().Set("Content-Length", strconv.Itoa(len(data)))
|
|
||||||
rw.WriteHeader(200)
|
|
||||||
rw.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
logResponse(reqID, 200, fmt.Sprintf("Processed in %s: %s; %+v", getTimerSince(ctx), getImageURL(ctx), po))
|
|
||||||
}
|
|
||||||
|
|
||||||
func addVaryHeader(rw http.ResponseWriter) {
|
|
||||||
vary := make([]string, 0)
|
|
||||||
|
|
||||||
if conf.EnableWebpDetection || conf.EnforceWebp {
|
|
||||||
vary = append(vary, "Accept")
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.GZipCompression > 0 {
|
|
||||||
vary = append(vary, "Accept-Encoding")
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.EnableClientHints {
|
|
||||||
vary = append(vary, "DPR", "Viewport-Width", "Width")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(vary) > 0 {
|
|
||||||
rw.Header().Set("Vary", strings.Join(vary, ", "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func respondWithError(reqID string, rw http.ResponseWriter, err *imgproxyError) {
|
|
||||||
logResponse(reqID, err.StatusCode, err.Message)
|
|
||||||
|
|
||||||
rw.WriteHeader(err.StatusCode)
|
|
||||||
|
|
||||||
if conf.DevelopmentErrorsMode {
|
|
||||||
rw.Write([]byte(err.Message))
|
|
||||||
} else {
|
|
||||||
rw.Write([]byte(err.PublicMessage))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func withCORS(h routeHandler) routeHandler {
|
func withCORS(h routeHandler) routeHandler {
|
||||||
return func(reqID string, rw http.ResponseWriter, r *http.Request) {
|
return func(reqID string, rw http.ResponseWriter, r *http.Request) {
|
||||||
if len(conf.AllowOrigin) > 0 {
|
if len(conf.AllowOrigin) > 0 {
|
||||||
@ -202,7 +85,7 @@ func withSecret(h routeHandler) routeHandler {
|
|||||||
if subtle.ConstantTimeCompare([]byte(r.Header.Get("Authorization")), authHeader) == 1 {
|
if subtle.ConstantTimeCompare([]byte(r.Header.Get("Authorization")), authHeader) == 1 {
|
||||||
h(reqID, rw, r)
|
h(reqID, rw, r)
|
||||||
} else {
|
} else {
|
||||||
respondWithError(reqID, rw, errInvalidSecret)
|
panic(errInvalidSecret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,10 +93,23 @@ func withSecret(h routeHandler) routeHandler {
|
|||||||
func handlePanic(reqID string, rw http.ResponseWriter, r *http.Request, err error) {
|
func handlePanic(reqID string, rw http.ResponseWriter, r *http.Request, err error) {
|
||||||
reportError(err, r)
|
reportError(err, r)
|
||||||
|
|
||||||
if ierr, ok := err.(*imgproxyError); ok {
|
var (
|
||||||
respondWithError(reqID, rw, ierr)
|
ierr *imgproxyError
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if ierr, ok = err.(*imgproxyError); !ok {
|
||||||
|
ierr = newUnexpectedError(err.Error(), 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
logResponse(reqID, ierr.StatusCode, ierr.Message)
|
||||||
|
|
||||||
|
rw.WriteHeader(ierr.StatusCode)
|
||||||
|
|
||||||
|
if conf.DevelopmentErrorsMode {
|
||||||
|
rw.Write([]byte(ierr.Message))
|
||||||
} else {
|
} else {
|
||||||
respondWithError(reqID, rw, newUnexpectedError(err.Error(), 3))
|
rw.Write([]byte(ierr.PublicMessage))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,72 +123,3 @@ func handleOptions(reqID string, rw http.ResponseWriter, r *http.Request) {
|
|||||||
logResponse(reqID, 200, "Respond with options")
|
logResponse(reqID, 200, "Respond with options")
|
||||||
rw.WriteHeader(200)
|
rw.WriteHeader(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
if newRelicEnabled {
|
|
||||||
var newRelicCancel context.CancelFunc
|
|
||||||
ctx, newRelicCancel = startNewRelicTransaction(ctx, rw, r)
|
|
||||||
defer newRelicCancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
if prometheusEnabled {
|
|
||||||
prometheusRequestsTotal.Inc()
|
|
||||||
defer startPrometheusDuration(prometheusRequestDuration)()
|
|
||||||
}
|
|
||||||
|
|
||||||
processingSem <- struct{}{}
|
|
||||||
defer func() { <-processingSem }()
|
|
||||||
|
|
||||||
ctx, timeoutCancel := startTimer(ctx, time.Duration(conf.WriteTimeout)*time.Second)
|
|
||||||
defer timeoutCancel()
|
|
||||||
|
|
||||||
ctx, err := parsePath(ctx, r)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, downloadcancel, err := downloadImage(ctx)
|
|
||||||
defer downloadcancel()
|
|
||||||
if err != nil {
|
|
||||||
if newRelicEnabled {
|
|
||||||
sendErrorToNewRelic(ctx, err)
|
|
||||||
}
|
|
||||||
if prometheusEnabled {
|
|
||||||
incrementPrometheusErrorsTotal("download")
|
|
||||||
}
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkTimeout(ctx)
|
|
||||||
|
|
||||||
if conf.ETagEnabled {
|
|
||||||
eTag := calcETag(ctx)
|
|
||||||
rw.Header().Set("ETag", eTag)
|
|
||||||
|
|
||||||
if eTag == r.Header.Get("If-None-Match") {
|
|
||||||
logResponse(reqID, 304, "Not modified")
|
|
||||||
rw.WriteHeader(304)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkTimeout(ctx)
|
|
||||||
|
|
||||||
imageData, processcancel, err := processImage(ctx)
|
|
||||||
defer processcancel()
|
|
||||||
if err != nil {
|
|
||||||
if newRelicEnabled {
|
|
||||||
sendErrorToNewRelic(ctx, err)
|
|
||||||
}
|
|
||||||
if prometheusEnabled {
|
|
||||||
incrementPrometheusErrorsTotal("processing")
|
|
||||||
}
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkTimeout(ctx)
|
|
||||||
|
|
||||||
respondWithImage(ctx, reqID, r, rw, imageData)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user