package http2
import (
)
type writeFramer interface {
writeFrame(writeContext) error
staysWithinBuffer(size int) bool
}
type writeContext interface {
Framer() *Framer
Flush() error
CloseConn() error
HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
}
func ( writeFramer) bool {
switch v := .(type) {
case *writeData:
return .endStream
case *writeResHeaders:
return .endStream
case nil:
panic("writeEndsStream called on nil writeFramer")
}
return false
}
type flushFrameWriter struct{}
func (flushFrameWriter) ( writeContext) error {
return .Flush()
}
func (flushFrameWriter) ( int) bool { return false }
type writeSettings []Setting
func ( writeSettings) ( int) bool {
const = 6
return frameHeaderLen+*len() <=
}
func ( writeSettings) ( writeContext) error {
return .Framer().WriteSettings([]Setting()...)
}
type writeGoAway struct {
maxStreamID uint32
code ErrCode
}
func ( *writeGoAway) ( writeContext) error {
:= .Framer().WriteGoAway(.maxStreamID, .code, nil)
.Flush()
return
}
func (*writeGoAway) ( int) bool { return false }
type writeData struct {
streamID uint32
p []byte
endStream bool
}
func ( *writeData) () string {
return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", .streamID, len(.p), .endStream)
}
func ( *writeData) ( writeContext) error {
return .Framer().WriteData(.streamID, .endStream, .p)
}
func ( *writeData) ( int) bool {
return frameHeaderLen+len(.p) <=
}
type handlerPanicRST struct {
StreamID uint32
}
func ( handlerPanicRST) ( writeContext) error {
return .Framer().WriteRSTStream(.StreamID, ErrCodeInternal)
}
func ( handlerPanicRST) ( int) bool { return frameHeaderLen+4 <= }
func ( StreamError) ( writeContext) error {
return .Framer().WriteRSTStream(.StreamID, .Code)
}
func ( StreamError) ( int) bool { return frameHeaderLen+4 <= }
type writePingAck struct{ pf *PingFrame }
func ( writePingAck) ( writeContext) error {
return .Framer().WritePing(true, .pf.Data)
}
func ( writePingAck) ( int) bool { return frameHeaderLen+len(.pf.Data) <= }
type writeSettingsAck struct{}
func (writeSettingsAck) ( writeContext) error {
return .Framer().WriteSettingsAck()
}
func (writeSettingsAck) ( int) bool { return frameHeaderLen <= }
func ( writeContext, []byte, func( writeContext, []byte, , bool) error) error {
const = 16384
:= true
for len() > 0 {
:=
if len() > {
= [:]
}
= [len():]
if := (, , , len() == 0); != nil {
return
}
= false
}
return nil
}
type writeResHeaders struct {
streamID uint32
httpResCode int
h http.Header
trailers []string
endStream bool
date string
contentType string
contentLength string
}
func ( *hpack.Encoder, , string) {
if VerboseLogs {
log.Printf("http2: server encoding header %q = %q", , )
}
.WriteField(hpack.HeaderField{Name: , Value: })
}
func ( *writeResHeaders) ( int) bool {
return false
}
func ( *writeResHeaders) ( writeContext) error {
, := .HeaderEncoder()
.Reset()
if .httpResCode != 0 {
encKV(, ":status", httpCodeString(.httpResCode))
}
encodeHeaders(, .h, .trailers)
if .contentType != "" {
encKV(, "content-type", .contentType)
}
if .contentLength != "" {
encKV(, "content-length", .contentLength)
}
if .date != "" {
encKV(, "date", .date)
}
:= .Bytes()
if len() == 0 && .trailers == nil {
panic("unexpected empty hpack")
}
return splitHeaderBlock(, , .writeHeaderBlock)
}
func ( *writeResHeaders) ( writeContext, []byte, , bool) error {
if {
return .Framer().WriteHeaders(HeadersFrameParam{
StreamID: .streamID,
BlockFragment: ,
EndStream: .endStream,
EndHeaders: ,
})
} else {
return .Framer().WriteContinuation(.streamID, , )
}
}
type writePushPromise struct {
streamID uint32
method string
url *url.URL
h http.Header
allocatePromisedID func() (uint32, error)
promisedID uint32
}
func ( *writePushPromise) ( int) bool {
return false
}
func ( *writePushPromise) ( writeContext) error {
, := .HeaderEncoder()
.Reset()
encKV(, ":method", .method)
encKV(, ":scheme", .url.Scheme)
encKV(, ":authority", .url.Host)
encKV(, ":path", .url.RequestURI())
encodeHeaders(, .h, nil)
:= .Bytes()
if len() == 0 {
panic("unexpected empty hpack")
}
return splitHeaderBlock(, , .writeHeaderBlock)
}
func ( *writePushPromise) ( writeContext, []byte, , bool) error {
if {
return .Framer().WritePushPromise(PushPromiseParam{
StreamID: .streamID,
PromiseID: .promisedID,
BlockFragment: ,
EndHeaders: ,
})
} else {
return .Framer().WriteContinuation(.streamID, , )
}
}
type write100ContinueHeadersFrame struct {
streamID uint32
}
func ( write100ContinueHeadersFrame) ( writeContext) error {
, := .HeaderEncoder()
.Reset()
encKV(, ":status", "100")
return .Framer().WriteHeaders(HeadersFrameParam{
StreamID: .streamID,
BlockFragment: .Bytes(),
EndStream: false,
EndHeaders: true,
})
}
func ( write100ContinueHeadersFrame) ( int) bool {
return 9+2*(len(":status")+len("100")) <=
}
type writeWindowUpdate struct {
streamID uint32
n uint32
}
func ( writeWindowUpdate) ( int) bool { return frameHeaderLen+4 <= }
func ( writeWindowUpdate) ( writeContext) error {
return .Framer().WriteWindowUpdate(.streamID, .n)
}
func ( *hpack.Encoder, http.Header, []string) {
if == nil {
:= sorterPool.Get().(*sorter)
defer sorterPool.Put()
= .Keys()
}
for , := range {
:= []
, := lowerHeader()
if ! {
continue
}
if !validWireHeaderFieldName() {
continue
}
:= == "transfer-encoding"
for , := range {
if !httpguts.ValidHeaderFieldValue() {
continue
}
if && != "trailers" {
continue
}
encKV(, , )
}
}
}