package http3

import (
	
	
	
	

	
)

// A Hijacker allows hijacking of the stream creating part of a quic.Connection from a http.ResponseWriter.
// It is used by WebTransport to create WebTransport streams after a session has been established.
type Hijacker interface {
	Connection() Connection
}

var errTooMuchData = errors.New("peer sent too much data")

// The body is used in the requestBody (for a http.Request) and the responseBody (for a http.Response).
type body struct {
	str *stream

	remainingContentLength int64
	violatedContentLength  bool
	hasContentLength       bool
}

func newBody( *stream,  int64) *body {
	 := &body{str: }
	if  >= 0 {
		.hasContentLength = true
		.remainingContentLength = 
	}
	return 
}

func ( *body) () quic.StreamID { return .str.StreamID() }

func ( *body) () error {
	if !.hasContentLength {
		return nil
	}
	if .remainingContentLength < 0 || .remainingContentLength == 0 && .str.hasMoreData() {
		if !.violatedContentLength {
			.str.CancelRead(quic.StreamErrorCode(ErrCodeMessageError))
			.str.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError))
			.violatedContentLength = true
		}
		return errTooMuchData
	}
	return nil
}

func ( *body) ( []byte) (int, error) {
	if  := .checkContentLengthViolation();  != nil {
		return 0, 
	}
	if .hasContentLength {
		 = [:min(int64(len()), .remainingContentLength)]
	}
	,  := .str.Read()
	.remainingContentLength -= int64()
	if  := .checkContentLengthViolation();  != nil {
		return , 
	}
	return , maybeReplaceError()
}

func ( *body) () error {
	.str.CancelRead(quic.StreamErrorCode(ErrCodeRequestCanceled))
	return nil
}

type requestBody struct {
	body
	connCtx      context.Context
	rcvdSettings <-chan struct{}
	getSettings  func() *Settings
}

var _ io.ReadCloser = &requestBody{}

func newRequestBody( *stream,  int64,  context.Context,  <-chan struct{},  func() *Settings) *requestBody {
	return &requestBody{
		body:         *newBody(, ),
		connCtx:      ,
		rcvdSettings: ,
		getSettings:  ,
	}
}

type hijackableBody struct {
	body body

	// only set for the http.Response
	// The channel is closed when the user is done with this response:
	// either when Read() errors, or when Close() is called.
	reqDone     chan<- struct{}
	reqDoneOnce sync.Once
}

var _ io.ReadCloser = &hijackableBody{}

func newResponseBody( *stream,  int64,  chan<- struct{}) *hijackableBody {
	return &hijackableBody{
		body:    *newBody(, ),
		reqDone: ,
	}
}

func ( *hijackableBody) ( []byte) (int, error) {
	,  := .body.Read()
	if  != nil {
		.requestDone()
	}
	return , maybeReplaceError()
}

func ( *hijackableBody) () {
	if .reqDone != nil {
		.reqDoneOnce.Do(func() {
			close(.reqDone)
		})
	}
}

func ( *hijackableBody) () error {
	.requestDone()
	// If the EOF was read, CancelRead() is a no-op.
	.body.str.CancelRead(quic.StreamErrorCode(ErrCodeRequestCanceled))
	return nil
}