123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- package processing
- import (
- "context"
- "net/http"
- "net/url"
- "github.com/imgproxy/imgproxy/v3/auximageprovider"
- "github.com/imgproxy/imgproxy/v3/errorreport"
- "github.com/imgproxy/imgproxy/v3/handlers/stream"
- "github.com/imgproxy/imgproxy/v3/headerwriter"
- "github.com/imgproxy/imgproxy/v3/ierrors"
- "github.com/imgproxy/imgproxy/v3/imagedata"
- "github.com/imgproxy/imgproxy/v3/monitoring"
- "github.com/imgproxy/imgproxy/v3/monitoring/stats"
- "github.com/imgproxy/imgproxy/v3/options"
- "github.com/imgproxy/imgproxy/v3/security"
- "github.com/imgproxy/imgproxy/v3/semaphores"
- )
- // Handler handles image processing requests
- type Handler struct {
- hw *headerwriter.Writer // Configured HeaderWriter instance
- stream *stream.Handler // Stream handler for raw image streaming
- config *Config // Handler configuration
- semaphores *semaphores.Semaphores
- fallbackImage auximageprovider.Provider
- watermarkImage auximageprovider.Provider
- imageData *imagedata.Factory
- }
- // New creates new handler object
- func New(
- stream *stream.Handler,
- hw *headerwriter.Writer,
- semaphores *semaphores.Semaphores,
- fi auximageprovider.Provider,
- wi auximageprovider.Provider,
- idf *imagedata.Factory,
- config *Config,
- ) (*Handler, error) {
- if err := config.Validate(); err != nil {
- return nil, err
- }
- return &Handler{
- hw: hw,
- config: config,
- stream: stream,
- semaphores: semaphores,
- fallbackImage: fi,
- watermarkImage: wi,
- imageData: idf,
- }, nil
- }
- // Execute handles the image processing request
- func (h *Handler) Execute(
- reqID string,
- rw http.ResponseWriter,
- imageRequest *http.Request,
- ) error {
- // Increment the number of requests in progress
- stats.IncRequestsInProgress()
- defer stats.DecRequestsInProgress()
- ctx := imageRequest.Context()
- // Verify URL signature and extract image url and processing options
- imageURL, po, mm, err := h.newRequest(ctx, imageRequest)
- if err != nil {
- return err
- }
- // if processing options indicate raw image streaming, stream it and return
- if po.Raw {
- return h.stream.Execute(ctx, imageRequest, imageURL, reqID, po, rw)
- }
- req := &request{
- handler: h,
- imageRequest: imageRequest,
- reqID: reqID,
- rw: rw,
- config: h.config,
- po: po,
- imageURL: imageURL,
- monitoringMeta: mm,
- semaphores: h.semaphores,
- hwr: h.hw.NewRequest(),
- idf: h.imageData,
- }
- return req.execute(ctx)
- }
- // newRequest extracts image url and processing options from request URL and verifies them
- func (h *Handler) newRequest(
- ctx context.Context,
- imageRequest *http.Request,
- ) (string, *options.ProcessingOptions, monitoring.Meta, error) {
- // let's extract signature and valid request path from a request
- path, signature, err := splitPathSignature(imageRequest, h.config)
- if err != nil {
- return "", nil, nil, err
- }
- // verify the signature (if any)
- if err = security.VerifySignature(signature, path); err != nil {
- return "", nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(categorySecurity))
- }
- // parse image url and processing options
- po, imageURL, err := options.ParsePath(path, imageRequest.Header)
- if err != nil {
- return "", nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(categoryPathParsing))
- }
- // get image origin and create monitoring meta object
- imageOrigin := imageOrigin(imageURL)
- mm := monitoring.Meta{
- monitoring.MetaSourceImageURL: imageURL,
- monitoring.MetaSourceImageOrigin: imageOrigin,
- monitoring.MetaProcessingOptions: po.Diff().Flatten(),
- }
- // set error reporting and monitoring context
- errorreport.SetMetadata(imageRequest, "Source Image URL", imageURL)
- errorreport.SetMetadata(imageRequest, "Source Image Origin", imageOrigin)
- errorreport.SetMetadata(imageRequest, "Processing Options", po)
- monitoring.SetMetadata(ctx, mm)
- // verify that image URL came from the valid source
- err = security.VerifySourceURL(imageURL)
- if err != nil {
- return "", nil, mm, ierrors.Wrap(err, 0, ierrors.WithCategory(categorySecurity))
- }
- return imageURL, po, mm, nil
- }
- // imageOrigin extracts image origin from URL
- func imageOrigin(imageURL string) string {
- if u, uerr := url.Parse(imageURL); uerr == nil {
- return u.Scheme + "://" + u.Host
- }
- return ""
- }
|