Skip to content

Commit

Permalink
*: limit request size for v3
Browse files Browse the repository at this point in the history
  • Loading branch information
xiang90 committed Feb 8, 2016
1 parent b72a078 commit 3556722
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 0 deletions.
9 changes: 9 additions & 0 deletions Documentation/rfc/v3api.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ To prove out the design of the v3 API the team has also built [a number of examp
- easy for people to write simple etcd application


## Notes

### Request Size Limitation

The max request size is around 1MB. Since etcd replicates requests in a streaming fashion, a very large
request might block other requests for a long time. The use case for etcd is to store small configuration
values, so we prevent user from submitting large requests. This also applies to Txn requests. We might loosen
the size in the future a little bit or make it configurable.

## Protobuf Defined API

[api protobuf](../../etcdserver/etcdserverpb/rpc.proto)
Expand Down
2 changes: 2 additions & 0 deletions etcdserver/api/v3rpc/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ var (
ErrPeerURLExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: Peer URLs already exists")
ErrMemberBadURLs = grpc.Errorf(codes.InvalidArgument, "etcdserver: given member URLs are invalid")
ErrMemberNotFound = grpc.Errorf(codes.NotFound, "etcdserver: member not found")

ErrRequestTooLarge = grpc.Errorf(codes.InvalidArgument, "etcdserver: request is too large")
)
2 changes: 2 additions & 0 deletions etcdserver/api/v3rpc/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ func togRPCError(err error) error {
case lease.ErrLeaseNotFound:
return ErrLeaseNotFound
// TODO: handle error from raft and timeout
case etcdserver.ErrRequestTooLarge:
return ErrRequestTooLarge
default:
return grpc.Errorf(codes.Internal, err.Error())
}
Expand Down
1 change: 1 addition & 0 deletions etcdserver/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
ErrTimeoutDueToConnectionLost = errors.New("etcdserver: request timed out, possibly due to connection lost")
ErrNotEnoughStartedMembers = errors.New("etcdserver: re-configuration failed due to not enough started members")
ErrNoLeader = errors.New("etcdserver: no leader")
ErrRequestTooLarge = errors.New("etcdserver: request is too large")
)

func isKeyNotFound(err error) bool {
Expand Down
13 changes: 13 additions & 0 deletions etcdserver/v3demo_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import (
"github.com/coreos/etcd/storage/storagepb"
)

const (
// the max request size that raft accepts.
// TODO: make this a flag? But we probably do not want to
// accept large request which might block raft stream. User
// specify a large value might end up with shooting in the foot.
maxRequestBytes = 1.5 * 1024 * 1024
)

type RaftKV interface {
Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error)
Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error)
Expand Down Expand Up @@ -165,6 +173,11 @@ func (s *EtcdServer) processInternalRaftRequest(ctx context.Context, r pb.Intern
if err != nil {
return nil, err
}

if len(data) > maxRequestBytes {
return nil, ErrRequestTooLarge
}

ch := s.w.Register(r.ID)

s.r.Propose(ctx, data)
Expand Down
18 changes: 18 additions & 0 deletions integration/v3_grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,24 @@ func TestV3TxnInvaildRange(t *testing.T) {
}
}

func TestV3TooLargeRequest(t *testing.T) {
defer testutil.AfterTest(t)

clus := NewClusterV3(t, &ClusterConfig{Size: 3})
defer clus.Terminate(t)

kvc := clus.RandClient().KV

// 2MB request value
largeV := make([]byte, 2*1024*1024)
preq := &pb.PutRequest{Key: []byte("foo"), Value: largeV}

_, err := kvc.Put(context.Background(), preq)
if err != v3rpc.ErrRequestTooLarge {
t.Errorf("err = %v, want %v", err, v3rpc.ErrRequestTooLarge)
}
}

// TestV3Hash tests hash.
func TestV3Hash(t *testing.T) {
defer testutil.AfterTest(t)
Expand Down

0 comments on commit 3556722

Please sign in to comment.