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"
- "github.com/imgproxy/imgproxy/v3/handlers/stream"
- "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/processing"
- "github.com/imgproxy/imgproxy/v3/security"
- "github.com/imgproxy/imgproxy/v3/server"
- "github.com/imgproxy/imgproxy/v3/workers"
- )
- // HandlerContext provides access to shared handler dependencies
- type HandlerContext interface {
- Workers() *workers.Workers
- FallbackImage() auximageprovider.Provider
- WatermarkImage() auximageprovider.Provider
- ImageDataFactory() *imagedata.Factory
- Security() *security.Checker
- OptionsFactory() *options.Factory
- Processor() *processing.Processor
- }
- // Handler handles image processing requests
- type Handler struct {
- HandlerContext
- stream *stream.Handler // Stream handler for raw image streaming
- config *Config // Handler configuration
- }
- // New creates new handler object
- func New(
- hCtx HandlerContext,
- stream *stream.Handler,
- config *Config,
- ) (*Handler, error) {
- if err := config.Validate(); err != nil {
- return nil, err
- }
- return &Handler{
- HandlerContext: hCtx,
- config: config,
- stream: stream,
- }, nil
- }
- // Execute handles the image processing request
- func (h *Handler) Execute(
- reqID string,
- rw server.ResponseWriter,
- req *http.Request,
- ) error {
- // Increment the number of requests in progress
- stats.IncRequestsInProgress()
- defer stats.DecRequestsInProgress()
- ctx := req.Context()
- // Verify URL signature and extract image url and processing options
- imageURL, po, mm, err := h.newRequest(ctx, req)
- if err != nil {
- return err
- }
- // if processing options indicate raw image streaming, stream it and return
- if po.Raw {
- return h.stream.Execute(ctx, req, imageURL, reqID, po, rw)
- }
- hReq := &request{
- HandlerContext: h,
- reqID: reqID,
- req: req,
- rw: rw,
- config: h.config,
- po: po,
- imageURL: imageURL,
- monitoringMeta: mm,
- }
- return hReq.execute(ctx)
- }
- // newRequest extracts image url and processing options from request URL and verifies them
- func (h *Handler) newRequest(
- ctx context.Context,
- req *http.Request,
- ) (string, *options.ProcessingOptions, monitoring.Meta, error) {
- // let's extract signature and valid request path from a request
- path, signature, err := handlers.SplitPathSignature(req)
- if err != nil {
- return "", nil, nil, err
- }
- // verify the signature (if any)
- if err = h.Security().VerifySignature(signature, path); err != nil {
- return "", nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.CategorySecurity))
- }
- // parse image url and processing options
- po, imageURL, err := h.OptionsFactory().ParsePath(path, req.Header)
- if err != nil {
- return "", nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.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(req, "Source Image URL", imageURL)
- errorreport.SetMetadata(req, "Source Image Origin", imageOrigin)
- errorreport.SetMetadata(req, "Processing Options", po)
- monitoring.SetMetadata(ctx, mm)
- // verify that image URL came from the valid source
- err = h.Security().VerifySourceURL(imageURL)
- if err != nil {
- return "", nil, mm, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.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 ""
- }
|