txn: don't try to decode request bodies > raft.SuggestedMaxDataSize (#6422)
txn: don't try to decode request bodies > raft.SuggestedMaxDataSize
This commit is contained in:
parent
70a5279114
commit
2254633d93
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -98,6 +99,18 @@ func isWrite(op api.KVOp) bool {
|
||||||
// a boolean, that if false means an error response has been generated and
|
// a boolean, that if false means an error response has been generated and
|
||||||
// processing should stop.
|
// processing should stop.
|
||||||
func (s *HTTPServer) convertOps(resp http.ResponseWriter, req *http.Request) (structs.TxnOps, int, bool) {
|
func (s *HTTPServer) convertOps(resp http.ResponseWriter, req *http.Request) (structs.TxnOps, int, bool) {
|
||||||
|
|
||||||
|
sizeStr := req.Header.Get("Content-Length")
|
||||||
|
if sizeStr != "" {
|
||||||
|
if size, err := strconv.Atoi(sizeStr); err != nil {
|
||||||
|
fmt.Fprintf(resp, "Failed to parse Content-Length: %v", err)
|
||||||
|
return nil, 0, false
|
||||||
|
} else if size > int(s.agent.config.KVMaxValueSize) {
|
||||||
|
fmt.Fprintf(resp, "Request body too large, max size: %v bytes", s.agent.config.KVMaxValueSize)
|
||||||
|
return nil, 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note the body is in API format, and not the RPC format. If we can't
|
// Note the body is in API format, and not the RPC format. If we can't
|
||||||
// decode it, we will return a 400 since we don't have enough context to
|
// decode it, we will return a 400 since we don't have enough context to
|
||||||
// associate the error with a given operation.
|
// associate the error with a given operation.
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -602,3 +603,50 @@ func TestTxnEndpoint_UpdateCheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
verify.Values(t, "", txnResp, expected)
|
verify.Values(t, "", txnResp, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertOps_ContentLength(t *testing.T) {
|
||||||
|
a := NewTestAgent(t, t.Name(), "")
|
||||||
|
defer a.Shutdown()
|
||||||
|
|
||||||
|
jsonBody := `[
|
||||||
|
{
|
||||||
|
"KV": {
|
||||||
|
"Verb": "set",
|
||||||
|
"Key": "key1",
|
||||||
|
"Value": "aGVsbG8gd29ybGQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
contentLength string
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{"", true},
|
||||||
|
{strconv.Itoa(len(jsonBody)), true},
|
||||||
|
{strconv.Itoa(raft.SuggestedMaxDataSize), true},
|
||||||
|
{strconv.Itoa(raft.SuggestedMaxDataSize + 100), false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run("contentLength: "+tc.contentLength, func(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
var body bytes.Buffer
|
||||||
|
|
||||||
|
// Doesn't matter what the request body size actually is, as we only
|
||||||
|
// check 'Content-Length' header in this test anyway.
|
||||||
|
body.WriteString(jsonBody)
|
||||||
|
|
||||||
|
req := httptest.NewRequest("POST", "http://foo.com", &body)
|
||||||
|
req.Header.Add("Content-Length", tc.contentLength)
|
||||||
|
|
||||||
|
_, _, ok := a.srv.convertOps(resp, req)
|
||||||
|
if ok != tc.ok {
|
||||||
|
t.Fatal("ok != tc.ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue