Skip to content

Commit f335d34

Browse files
Reed Allmantreeder
authored andcommitted
add server option to limit request size (#320)
we're going to want to do this in our service version of this thing, but adding this here so that it's usable by everyone. just an option, can add it to server configuration, but response is nicely formatted, etc. closes #277
1 parent c6f9b50 commit f335d34

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

api/server/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ type Server struct {
5050
}
5151

5252
// NewFromEnv creates a new Functions server based on env vars.
53-
func NewFromEnv(ctx context.Context) *Server {
53+
func NewFromEnv(ctx context.Context, opts ...ServerOption) *Server {
5454
ds, err := datastore.New(viper.GetString(EnvDBURL))
5555
if err != nil {
5656
logrus.WithError(err).Fatalln("Error initializing datastore.")
@@ -69,7 +69,7 @@ func NewFromEnv(ctx context.Context) *Server {
6969
}
7070
}
7171

72-
return New(ctx, ds, mq, logDB)
72+
return New(ctx, ds, mq, logDB, opts...)
7373
}
7474

7575
// New creates a new Functions server with the passed in datastore, message queue and API URL

api/server/server_options.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package server
22

3-
import "context"
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/gin-gonic/gin"
9+
)
410

511
type ServerOption func(*Server)
612

@@ -9,3 +15,38 @@ func EnableShutdownEndpoint(halt context.CancelFunc) ServerOption {
915
s.Router.GET("/shutdown", s.handleShutdown(halt))
1016
}
1117
}
18+
19+
func LimitRequestBody(max int64) ServerOption {
20+
return func(s *Server) {
21+
s.Router.Use(limitRequestBody(max))
22+
}
23+
}
24+
25+
func limitRequestBody(max int64) func(c *gin.Context) {
26+
return func(c *gin.Context) {
27+
cl := int64(c.Request.ContentLength)
28+
if cl > max {
29+
// try to deny this quickly, instead of just letting it get lopped off
30+
31+
handleErrorResponse(c, errTooBig{cl, max})
32+
c.Abort()
33+
return
34+
}
35+
36+
// if no Content-Length specified, limit how many bytes we read and error
37+
// if we hit the max (intercontinental anti-air missile defense system).
38+
// read http.MaxBytesReader for gritty details..
39+
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, max)
40+
c.Next()
41+
}
42+
}
43+
44+
// models.APIError
45+
type errTooBig struct {
46+
n, max int64
47+
}
48+
49+
func (e errTooBig) Code() int { return http.StatusRequestEntityTooLarge }
50+
func (e errTooBig) Error() string {
51+
return fmt.Sprintf("Content-Length too large for this server, %d > max %d", e.n, e.max)
52+
}

0 commit comments

Comments
 (0)