github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/mw_request_size_limit.go (about)

     1  package gateway
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"strconv"
     7  
     8  	"github.com/sirupsen/logrus"
     9  
    10  	"github.com/TykTechnologies/tyk/apidef"
    11  	"github.com/TykTechnologies/tyk/headers"
    12  )
    13  
    14  // TransformMiddleware is a middleware that will apply a template to a request body to transform it's contents ready for an upstream API
    15  type RequestSizeLimitMiddleware struct {
    16  	BaseMiddleware
    17  }
    18  
    19  func (t *RequestSizeLimitMiddleware) Name() string {
    20  	return "RequestSizeLimitMiddleware"
    21  }
    22  
    23  func (t *RequestSizeLimitMiddleware) EnabledForSpec() bool {
    24  	for _, version := range t.Spec.VersionData.Versions {
    25  		if len(version.ExtendedPaths.SizeLimit) > 0 {
    26  			return true
    27  		}
    28  	}
    29  	return false
    30  }
    31  
    32  func (t *RequestSizeLimitMiddleware) checkRequestLimit(r *http.Request, sizeLimit int64) (error, int) {
    33  	statedCL := r.Header.Get(headers.ContentLength)
    34  	if statedCL == "" {
    35  		return errors.New("Content length is required for this request"), 411
    36  	}
    37  
    38  	size, err := strconv.ParseInt(statedCL, 0, 64)
    39  	if err != nil {
    40  		t.Logger().WithError(err).Error("String conversion for content length failed")
    41  		return errors.New("content length is not a valid Integer"), http.StatusBadRequest
    42  	}
    43  	if r.ContentLength > size {
    44  		size = r.ContentLength
    45  	}
    46  
    47  	// Check stated size
    48  	if size > sizeLimit {
    49  		t.Logger().WithFields(logrus.Fields{"size": size, "limit": sizeLimit}).Info("Attempted access with large request size, blocked.")
    50  
    51  		return errors.New("Request is too large"), http.StatusBadRequest
    52  	}
    53  
    54  	return nil, http.StatusOK
    55  }
    56  
    57  // RequestSizeLimit will check a request for maximum request size, this can be a global limit or a matched limit.
    58  func (t *RequestSizeLimitMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
    59  	logger := t.Logger()
    60  	logger.Debug("Request size limiter active")
    61  
    62  	vInfo, versionPaths, _, _ := t.Spec.Version(r)
    63  
    64  	logger.Debug("Global limit is: ", vInfo.GlobalSizeLimit)
    65  	// Manage global headers first
    66  	if vInfo.GlobalSizeLimit > 0 {
    67  		logger.Debug("Checking global limit")
    68  		err, code := t.checkRequestLimit(r, vInfo.GlobalSizeLimit)
    69  		// If not OK, block
    70  		if code != http.StatusOK {
    71  			return err, code
    72  		}
    73  	}
    74  
    75  	// if there's no paths at all path check
    76  	if len(vInfo.ExtendedPaths.SizeLimit) == 0 {
    77  		return nil, http.StatusOK
    78  	}
    79  
    80  	// If there's a potential match, try to match
    81  	found, meta := t.Spec.CheckSpecMatchesStatus(r, versionPaths, RequestSizeLimit)
    82  	if found {
    83  		logger.Debug("Request size limit matched for this URL, checking...")
    84  		rmeta := meta.(*apidef.RequestSizeMeta)
    85  		return t.checkRequestLimit(r, rmeta.SizeLimit)
    86  	}
    87  
    88  	return nil, http.StatusOK
    89  }