Skip to content
Snippets Groups Projects
Commit bd72df1a authored by John Cai's avatar John Cai
Browse files

PreReceiveHook: Chunk stderr in response

Although we currently chunk the responses in PreReceiveHook, we just
send the stderr back in one whole response in the event of an error.
This might cause a "received message larger than max" error on the
client side if the stderr is large.

Use the chunker abstraction to send the stderr back to the client.
parent 2c98bb84
No related merge requests found
......@@ -7,10 +7,14 @@ import (
"os/exec"
"sync"
"github.com/golang/protobuf/ptypes/wrappers"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/chunk"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"gitlab.com/gitlab-org/gitaly/v16/streamio"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func (s *server) PreReceiveHook(stream gitalypb.HookService_PreReceiveHookServer) error {
......@@ -61,11 +65,56 @@ func validatePreReceiveHookRequest(ctx context.Context, locator storage.Locator,
return locator.ValidateRepository(ctx, in.GetRepository())
}
type preReceiveHookErrorSender struct {
errorCode int32
bytes *wrappers.BytesValue
send func(*wrappers.BytesValue, int32) error
}
func (p *preReceiveHookErrorSender) Reset() {
if p.bytes != nil {
p.bytes.Value = p.bytes.Value[:0]
return
}
p.bytes = &wrappers.BytesValue{}
}
func (p *preReceiveHookErrorSender) Append(m proto.Message) {
p.bytes.Value = append(p.bytes.Value, m.(*wrappers.BytesValue).Value...)
}
func (p *preReceiveHookErrorSender) Send() error {
return p.send(p.bytes, p.errorCode)
}
func preReceiveHookResponse(stream gitalypb.HookService_PreReceiveHookServer, code int32, stderr string) error {
if err := stream.Send(&gitalypb.PreReceiveHookResponse{
ExitStatus: &gitalypb.ExitStatus{Value: code},
Stderr: []byte(stderr),
}); err != nil {
if stderr == "" {
if err := stream.Send(&gitalypb.PreReceiveHookResponse{
ExitStatus: &gitalypb.ExitStatus{Value: code},
Stderr: []byte(""),
}); err != nil {
return structerr.NewInternal("sending response: %w", err)
}
return nil
}
chunker := chunk.New(&preReceiveHookErrorSender{
errorCode: code,
send: func(bytes *wrappers.BytesValue, errorCode int32) error {
return stream.Send(&gitalypb.PreReceiveHookResponse{
ExitStatus: &gitalypb.ExitStatus{Value: errorCode},
Stderr: []byte(bytes.Value),
})
},
})
if err := chunker.Send(wrapperspb.Bytes([]byte(stderr))); err != nil {
return structerr.NewInternal("sending response: %w", err)
}
if err := chunker.Flush(); err != nil {
return structerr.NewInternal("sending response: %w", err)
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment