write.go raw

   1  // Copyright 2014 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package http2
   6  
   7  import (
   8  	"bytes"
   9  	"fmt"
  10  	"log"
  11  	"net/http"
  12  	"net/url"
  13  
  14  	"golang.org/x/net/http/httpguts"
  15  	"golang.org/x/net/http2/hpack"
  16  	"golang.org/x/net/internal/httpcommon"
  17  )
  18  
  19  // writeFramer is implemented by any type that is used to write frames.
  20  type writeFramer interface {
  21  	writeFrame(writeContext) error
  22  
  23  	// staysWithinBuffer reports whether this writer promises that
  24  	// it will only write less than or equal to size bytes, and it
  25  	// won't Flush the write context.
  26  	staysWithinBuffer(size int) bool
  27  }
  28  
  29  // writeContext is the interface needed by the various frame writer
  30  // types below. All the writeFrame methods below are scheduled via the
  31  // frame writing scheduler (see writeScheduler in writesched.go).
  32  //
  33  // This interface is implemented by *serverConn.
  34  //
  35  // TODO: decide whether to a) use this in the client code (which didn't
  36  // end up using this yet, because it has a simpler design, not
  37  // currently implementing priorities), or b) delete this and
  38  // make the server code a bit more concrete.
  39  type writeContext interface {
  40  	Framer() *Framer
  41  	Flush() error
  42  	CloseConn() error
  43  	// HeaderEncoder returns an HPACK encoder that writes to the
  44  	// returned buffer.
  45  	HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
  46  }
  47  
  48  // writeEndsStream reports whether w writes a frame that will transition
  49  // the stream to a half-closed local state. This returns false for RST_STREAM,
  50  // which closes the entire stream (not just the local half).
  51  func writeEndsStream(w writeFramer) bool {
  52  	switch v := w.(type) {
  53  	case *writeData:
  54  		return v.endStream
  55  	case *writeResHeaders:
  56  		return v.endStream
  57  	case nil:
  58  		// This can only happen if the caller reuses w after it's
  59  		// been intentionally nil'ed out to prevent use. Keep this
  60  		// here to catch future refactoring breaking it.
  61  		panic("writeEndsStream called on nil writeFramer")
  62  	}
  63  	return false
  64  }
  65  
  66  type flushFrameWriter struct{}
  67  
  68  func (flushFrameWriter) writeFrame(ctx writeContext) error {
  69  	return ctx.Flush()
  70  }
  71  
  72  func (flushFrameWriter) staysWithinBuffer(max int) bool { return false }
  73  
  74  type writeSettings []Setting
  75  
  76  func (s writeSettings) staysWithinBuffer(max int) bool {
  77  	const settingSize = 6 // uint16 + uint32
  78  	return frameHeaderLen+settingSize*len(s) <= max
  79  
  80  }
  81  
  82  func (s writeSettings) writeFrame(ctx writeContext) error {
  83  	return ctx.Framer().WriteSettings([]Setting(s)...)
  84  }
  85  
  86  type writeGoAway struct {
  87  	maxStreamID uint32
  88  	code        ErrCode
  89  }
  90  
  91  func (p *writeGoAway) writeFrame(ctx writeContext) error {
  92  	err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
  93  	ctx.Flush() // ignore error: we're hanging up on them anyway
  94  	return err
  95  }
  96  
  97  func (*writeGoAway) staysWithinBuffer(max int) bool { return false } // flushes
  98  
  99  type writeData struct {
 100  	streamID  uint32
 101  	p         []byte
 102  	endStream bool
 103  }
 104  
 105  func (w *writeData) String() string {
 106  	return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
 107  }
 108  
 109  func (w *writeData) writeFrame(ctx writeContext) error {
 110  	return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
 111  }
 112  
 113  func (w *writeData) staysWithinBuffer(max int) bool {
 114  	return frameHeaderLen+len(w.p) <= max
 115  }
 116  
 117  // handlerPanicRST is the message sent from handler goroutines when
 118  // the handler panics.
 119  type handlerPanicRST struct {
 120  	StreamID uint32
 121  }
 122  
 123  func (hp handlerPanicRST) writeFrame(ctx writeContext) error {
 124  	return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal)
 125  }
 126  
 127  func (hp handlerPanicRST) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
 128  
 129  func (se StreamError) writeFrame(ctx writeContext) error {
 130  	return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
 131  }
 132  
 133  func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
 134  
 135  type writePing struct {
 136  	data [8]byte
 137  }
 138  
 139  func (w writePing) writeFrame(ctx writeContext) error {
 140  	return ctx.Framer().WritePing(false, w.data)
 141  }
 142  
 143  func (w writePing) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.data) <= max }
 144  
 145  type writePingAck struct{ pf *PingFrame }
 146  
 147  func (w writePingAck) writeFrame(ctx writeContext) error {
 148  	return ctx.Framer().WritePing(true, w.pf.Data)
 149  }
 150  
 151  func (w writePingAck) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.pf.Data) <= max }
 152  
 153  type writeSettingsAck struct{}
 154  
 155  func (writeSettingsAck) writeFrame(ctx writeContext) error {
 156  	return ctx.Framer().WriteSettingsAck()
 157  }
 158  
 159  func (writeSettingsAck) staysWithinBuffer(max int) bool { return frameHeaderLen <= max }
 160  
 161  // splitHeaderBlock splits headerBlock into fragments so that each fragment fits
 162  // in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
 163  // for the first/last fragment, respectively.
 164  func splitHeaderBlock(ctx writeContext, headerBlock []byte, fn func(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
 165  	// For now we're lazy and just pick the minimum MAX_FRAME_SIZE
 166  	// that all peers must support (16KB). Later we could care
 167  	// more and send larger frames if the peer advertised it, but
 168  	// there's little point. Most headers are small anyway (so we
 169  	// generally won't have CONTINUATION frames), and extra frames
 170  	// only waste 9 bytes anyway.
 171  	const maxFrameSize = 16384
 172  
 173  	first := true
 174  	for len(headerBlock) > 0 {
 175  		frag := headerBlock
 176  		if len(frag) > maxFrameSize {
 177  			frag = frag[:maxFrameSize]
 178  		}
 179  		headerBlock = headerBlock[len(frag):]
 180  		if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
 181  			return err
 182  		}
 183  		first = false
 184  	}
 185  	return nil
 186  }
 187  
 188  // writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
 189  // for HTTP response headers or trailers from a server handler.
 190  type writeResHeaders struct {
 191  	streamID    uint32
 192  	httpResCode int         // 0 means no ":status" line
 193  	h           http.Header // may be nil
 194  	trailers    []string    // if non-nil, which keys of h to write. nil means all.
 195  	endStream   bool
 196  
 197  	date          string
 198  	contentType   string
 199  	contentLength string
 200  }
 201  
 202  func encKV(enc *hpack.Encoder, k, v string) {
 203  	if VerboseLogs {
 204  		log.Printf("http2: server encoding header %q = %q", k, v)
 205  	}
 206  	enc.WriteField(hpack.HeaderField{Name: k, Value: v})
 207  }
 208  
 209  func (w *writeResHeaders) staysWithinBuffer(max int) bool {
 210  	// TODO: this is a common one. It'd be nice to return true
 211  	// here and get into the fast path if we could be clever and
 212  	// calculate the size fast enough, or at least a conservative
 213  	// upper bound that usually fires. (Maybe if w.h and
 214  	// w.trailers are nil, so we don't need to enumerate it.)
 215  	// Otherwise I'm afraid that just calculating the length to
 216  	// answer this question would be slower than the ~2µs benefit.
 217  	return false
 218  }
 219  
 220  func (w *writeResHeaders) writeFrame(ctx writeContext) error {
 221  	enc, buf := ctx.HeaderEncoder()
 222  	buf.Reset()
 223  
 224  	if w.httpResCode != 0 {
 225  		encKV(enc, ":status", httpCodeString(w.httpResCode))
 226  	}
 227  
 228  	encodeHeaders(enc, w.h, w.trailers)
 229  
 230  	if w.contentType != "" {
 231  		encKV(enc, "content-type", w.contentType)
 232  	}
 233  	if w.contentLength != "" {
 234  		encKV(enc, "content-length", w.contentLength)
 235  	}
 236  	if w.date != "" {
 237  		encKV(enc, "date", w.date)
 238  	}
 239  
 240  	headerBlock := buf.Bytes()
 241  	if len(headerBlock) == 0 && w.trailers == nil {
 242  		panic("unexpected empty hpack")
 243  	}
 244  
 245  	return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
 246  }
 247  
 248  func (w *writeResHeaders) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
 249  	if firstFrag {
 250  		return ctx.Framer().WriteHeaders(HeadersFrameParam{
 251  			StreamID:      w.streamID,
 252  			BlockFragment: frag,
 253  			EndStream:     w.endStream,
 254  			EndHeaders:    lastFrag,
 255  		})
 256  	} else {
 257  		return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
 258  	}
 259  }
 260  
 261  // writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
 262  type writePushPromise struct {
 263  	streamID uint32   // pusher stream
 264  	method   string   // for :method
 265  	url      *url.URL // for :scheme, :authority, :path
 266  	h        http.Header
 267  
 268  	// Creates an ID for a pushed stream. This runs on serveG just before
 269  	// the frame is written. The returned ID is copied to promisedID.
 270  	allocatePromisedID func() (uint32, error)
 271  	promisedID         uint32
 272  }
 273  
 274  func (w *writePushPromise) staysWithinBuffer(max int) bool {
 275  	// TODO: see writeResHeaders.staysWithinBuffer
 276  	return false
 277  }
 278  
 279  func (w *writePushPromise) writeFrame(ctx writeContext) error {
 280  	enc, buf := ctx.HeaderEncoder()
 281  	buf.Reset()
 282  
 283  	encKV(enc, ":method", w.method)
 284  	encKV(enc, ":scheme", w.url.Scheme)
 285  	encKV(enc, ":authority", w.url.Host)
 286  	encKV(enc, ":path", w.url.RequestURI())
 287  	encodeHeaders(enc, w.h, nil)
 288  
 289  	headerBlock := buf.Bytes()
 290  	if len(headerBlock) == 0 {
 291  		panic("unexpected empty hpack")
 292  	}
 293  
 294  	return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
 295  }
 296  
 297  func (w *writePushPromise) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
 298  	if firstFrag {
 299  		return ctx.Framer().WritePushPromise(PushPromiseParam{
 300  			StreamID:      w.streamID,
 301  			PromiseID:     w.promisedID,
 302  			BlockFragment: frag,
 303  			EndHeaders:    lastFrag,
 304  		})
 305  	} else {
 306  		return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
 307  	}
 308  }
 309  
 310  type write100ContinueHeadersFrame struct {
 311  	streamID uint32
 312  }
 313  
 314  func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
 315  	enc, buf := ctx.HeaderEncoder()
 316  	buf.Reset()
 317  	encKV(enc, ":status", "100")
 318  	return ctx.Framer().WriteHeaders(HeadersFrameParam{
 319  		StreamID:      w.streamID,
 320  		BlockFragment: buf.Bytes(),
 321  		EndStream:     false,
 322  		EndHeaders:    true,
 323  	})
 324  }
 325  
 326  func (w write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
 327  	// Sloppy but conservative:
 328  	return 9+2*(len(":status")+len("100")) <= max
 329  }
 330  
 331  type writeWindowUpdate struct {
 332  	streamID uint32 // or 0 for conn-level
 333  	n        uint32
 334  }
 335  
 336  func (wu writeWindowUpdate) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
 337  
 338  func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
 339  	return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
 340  }
 341  
 342  // encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
 343  // is encoded only if k is in keys.
 344  func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
 345  	if keys == nil {
 346  		sorter := sorterPool.Get().(*sorter)
 347  		// Using defer here, since the returned keys from the
 348  		// sorter.Keys method is only valid until the sorter
 349  		// is returned:
 350  		defer sorterPool.Put(sorter)
 351  		keys = sorter.Keys(h)
 352  	}
 353  	for _, k := range keys {
 354  		vv := h[k]
 355  		k, ascii := httpcommon.LowerHeader(k)
 356  		if !ascii {
 357  			// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
 358  			// field names have to be ASCII characters (just as in HTTP/1.x).
 359  			continue
 360  		}
 361  		if !validWireHeaderFieldName(k) {
 362  			// Skip it as backup paranoia. Per
 363  			// golang.org/issue/14048, these should
 364  			// already be rejected at a higher level.
 365  			continue
 366  		}
 367  		isTE := k == "transfer-encoding"
 368  		for _, v := range vv {
 369  			if !httpguts.ValidHeaderFieldValue(v) {
 370  				// TODO: return an error? golang.org/issue/14048
 371  				// For now just omit it.
 372  				continue
 373  			}
 374  			// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
 375  			if isTE && v != "trailers" {
 376  				continue
 377  			}
 378  			encKV(enc, k, v)
 379  		}
 380  	}
 381  }
 382