MCPcopy
hub / github.com/caddyserver/caddy / copyBuffer

Method copyBuffer

modules/caddyhttp/reverseproxy/streaming.go:325–376  ·  view source on GitHub ↗

copyBuffer returns any write errors or non-EOF read errors, and the amount of bytes written.

(dst io.Writer, src io.Reader, buf []byte, logger *zap.Logger)

Source from the content-addressed store, hash-verified

323// copyBuffer returns any write errors or non-EOF read errors, and the amount
324// of bytes written.
325func (h Handler) copyBuffer(dst io.Writer, src io.Reader, buf []byte, logger *zap.Logger) (int64, error) {
326 if len(buf) == 0 {
327 buf = make([]byte, defaultBufferSize)
328 }
329 var written int64
330 for {
331 logger.Debug("waiting to read from upstream")
332 nr, rerr := src.Read(buf)
333 logger := logger.With(zap.Int("read", nr))
334 if c := logger.Check(zapcore.DebugLevel, "read from upstream"); c != nil {
335 c.Write(zap.Error(rerr))
336 }
337 if rerr != nil && rerr != io.EOF && rerr != context.Canceled {
338 // TODO: this could be useful to know (indeed, it revealed an error in our
339 // fastcgi PoC earlier; but it's this single error report here that necessitates
340 // a function separate from io.CopyBuffer, since io.CopyBuffer does not distinguish
341 // between read or write errors; in a reverse proxy situation, write errors are not
342 // something we need to report to the client, but read errors are a problem on our
343 // end for sure. so we need to decide what we want.)
344 // p.logf("copyBuffer: ReverseProxy read error during body copy: %v", rerr)
345 if c := logger.Check(zapcore.ErrorLevel, "reading from backend"); c != nil {
346 c.Write(zap.Error(rerr))
347 }
348 }
349 if nr > 0 {
350 logger.Debug("writing to downstream")
351 nw, werr := dst.Write(buf[:nr])
352 if nw > 0 {
353 written += int64(nw)
354 }
355 if c := logger.Check(zapcore.DebugLevel, "wrote to downstream"); c != nil {
356 c.Write(
357 zap.Int("written", nw),
358 zap.Int64("written_total", written),
359 zap.Error(werr),
360 )
361 }
362 if werr != nil {
363 return written, fmt.Errorf("writing: %w", werr)
364 }
365 if nr != nw {
366 return written, io.ErrShortWrite
367 }
368 }
369 if rerr != nil {
370 if rerr == io.EOF {
371 return written, nil
372 }
373 return written, fmt.Errorf("reading: %w", rerr)
374 }
375 }
376}
377
378// registerConnection holds onto conn so it can be closed in the event
379// of a server shutdown. This is useful because hijacked connections or

Callers 1

copyResponseMethod · 0.95

Calls 6

ReadMethod · 0.45
WithMethod · 0.45
IntMethod · 0.45
CheckMethod · 0.45
WriteMethod · 0.45
ErrorMethod · 0.45

Tested by

no test coverage detected