@@ -43,6 +43,12 @@ type request struct {
4343 Meta map [string ]string `json:"meta,omitempty"`
4444}
4545
46+ // Limit request size. Ideally this limit should be specific for each field
47+ // in the JSON request but as a simple defensive measure we just limit the
48+ // entire HTTP body.
49+ // Configured by WithMaxRequestSize.
50+ const DEFAULT_MAX_REQUEST_SIZE = 100 << 20 // 100 MiB
51+
4652type respError struct {
4753 Code int `json:"code"`
4854 Message string `json:"message"`
@@ -111,7 +117,33 @@ func (s *RPCServer) handleReader(ctx context.Context, r io.Reader, w io.Writer,
111117 }
112118
113119 var req request
114- if err := json .NewDecoder (r ).Decode (& req ); err != nil {
120+ // We read the entire request upfront in a buffer to be able to tell if the
121+ // client sent more than maxRequestSize and report it back as an explicit error,
122+ // instead of just silently truncating it and reporting a more vague parsing
123+ // error.
124+ bufferedRequest := new (bytes.Buffer )
125+ // We use LimitReader to enforce maxRequestSize. Since it won't return an
126+ // EOF we can't actually know if the client sent more than the maximum or
127+ // not, so we read one byte more over the limit to explicitly query that.
128+ // FIXME: Maybe there's a cleaner way to do this.
129+ reqSize , err := bufferedRequest .ReadFrom (io .LimitReader (r , s .maxRequestSize + 1 ))
130+ if err != nil {
131+ // ReadFrom will discard EOF so any error here is unexpected and should
132+ // be reported.
133+ rpcError (wf , & req , rpcParseError , xerrors .Errorf ("reading request: %w" , err ))
134+ return
135+ }
136+ if reqSize > s .maxRequestSize {
137+ rpcError (wf , & req , rpcParseError ,
138+ // rpcParseError is the closest we have from the standard errors defined
139+ // in [jsonrpc spec](https://www.jsonrpc.org/specification#error_object)
140+ // to report the maximum limit.
141+ xerrors .Errorf ("request bigger than maximum %d allowed" ,
142+ s .maxRequestSize ))
143+ return
144+ }
145+
146+ if err := json .NewDecoder (bufferedRequest ).Decode (& req ); err != nil {
115147 rpcError (wf , & req , rpcParseError , xerrors .Errorf ("unmarshaling request: %w" , err ))
116148 return
117149 }
0 commit comments