diff --git a/pkg/authorization/authz.go b/pkg/authorization/authz.go index c5559a3c9d..c0ef3877fb 100644 --- a/pkg/authorization/authz.go +++ b/pkg/authorization/authz.go @@ -1,16 +1,19 @@ package authorization import ( + "bufio" "bytes" "fmt" "io" - "io/ioutil" "net/http" "strings" "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/ioutils" ) +const maxBodySize = 1048576 // 1MB + // NewCtx creates new authZ context, it is used to store authorization information related to a specific docker // REST http session // A context provides two method: @@ -52,18 +55,12 @@ type Ctx struct { func (ctx *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error { var body []byte if sendBody(ctx.requestURI, r.Header) { - var ( - err error - drainedBody io.ReadCloser - ) - drainedBody, r.Body, err = drainBody(r.Body) - if err != nil { - return err - } - defer drainedBody.Close() - body, err = ioutil.ReadAll(drainedBody) - if err != nil { - return err + if r.ContentLength < maxBodySize { + var err error + body, r.Body, err = drainBody(r.Body) + if err != nil { + return err + } } } @@ -126,15 +123,21 @@ func (ctx *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { // drainBody dump the body, it reads the body data into memory and // see go sources /go/src/net/http/httputil/dump.go -func drainBody(b io.ReadCloser) (io.ReadCloser, io.ReadCloser, error) { - var buf bytes.Buffer - if _, err := buf.ReadFrom(b); err != nil { +func drainBody(body io.ReadCloser) ([]byte, io.ReadCloser, error) { + bufReader := bufio.NewReaderSize(body, maxBodySize) + newBody := ioutils.NewReadCloserWrapper(bufReader, func() error { return body.Close() }) + + data, err := bufReader.Peek(maxBodySize) + if err != io.EOF { + // This means the request is larger than our max + if err == bufio.ErrBufferFull { + return nil, newBody, nil + } + // This means we had an error reading return nil, nil, err } - if err := b.Close(); err != nil { - return nil, nil, err - } - return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil + + return data, newBody, nil } // sendBody returns true when request/response body should be sent to AuthZPlugin