Пример #1
0
// handler を受け取って、将来 stream が渡されたら
// その Bucket につめられた Headers/Data フレームから
// req/res を作って handler を実行する関数を生成
func HandlerCallBack(handler http.Handler) CallBack {
	return func(stream *Stream) {
		header := stream.Bucket.Headers
		body := stream.Bucket.Body

		authority := header.Get(":authority")
		method := header.Get(":method")
		path := header.Get(":path")
		scheme := header.Get(":scheme")

		header.Del(":authority")
		header.Del(":method")
		header.Del(":path")
		header.Del(":scheme")

		rawurl := fmt.Sprintf("%s://%s%s", scheme, authority, path)
		url, err := neturl.ParseRequestURI(rawurl)
		if err != nil {
			Fatal("%v", err)
		}

		req := &http.Request{
			Method:           method,
			URL:              url,
			Proto:            "HTTP/1.1",
			ProtoMajor:       1,
			ProtoMinor:       1,
			Header:           header,
			Body:             body,
			ContentLength:    int64(body.Buffer.Len()),
			TransferEncoding: []string{}, // TODO:
			Close:            false,
			Host:             authority,
		}

		Info("\n%s", Lime(util.RequestString(req)))

		// Handle HTTP using handler
		res := NewResponseWriter()
		handler.ServeHTTP(res, req)
		responseHeader := res.Header()
		responseHeader.Add(":status", strconv.Itoa(res.status))

		Info("\n%s", Aqua((res.String())))

		// Send response headers as HEADERS Frame
		headerList := hpack.ToHeaderList(responseHeader)
		headerBlockFragment := stream.HpackContext.Encode(*headerList)
		Debug("%v", headerList)

		headersFrame := NewHeadersFrame(END_HEADERS, stream.ID, nil, headerBlockFragment, nil)
		headersFrame.Headers = responseHeader

		stream.Write(headersFrame)

		// Send response body as DATA Frame
		// each DataFrame has data in window size
		data := res.body.Bytes()
		maxFrameSize := stream.PeerSettings[SETTINGS_MAX_FRAME_SIZE]
		rest := int32(len(data))
		frameSize := rest

		// MaxFrameSize を基準に考え、そこから送れるサイズまで減らして行く
		for {
			Debug("rest data size(%v), current peer(%v) window(%v)", rest, stream.ID, stream.Window)

			// 送り終わってれば終わり
			if rest == 0 {
				break
			}

			frameSize = stream.Window.Consumable(rest)

			if frameSize <= 0 {
				continue
			}

			// MaxFrameSize より大きいなら切り詰める
			if frameSize > maxFrameSize {
				frameSize = maxFrameSize
			}

			Debug("send %v/%v data", frameSize, rest)

			// ここまでに算出した frameSize 分のデータを DATA Frame を作って送る
			dataToSend := make([]byte, frameSize)
			copy(dataToSend, data[:frameSize])
			dataFrame := NewDataFrame(UNSET, stream.ID, dataToSend, nil)
			stream.Write(dataFrame)

			// 送った分を削る
			rest -= frameSize
			copy(data, data[frameSize:])
			data = data[:rest]

			// Peer の Window Size を減らす
			stream.Window.ConsumePeer(frameSize)
		}

		// End Stream in empty DATA Frame
		endDataFrame := NewDataFrame(END_STREAM, stream.ID, nil, nil)
		stream.Write(endDataFrame)
	}
}
Пример #2
0
// Encode Header using HPACK
func (stream *Stream) EncodeHeader(header http.Header) []byte {
	headerList := hpack.ToHeaderList(header)
	Trace("sending header list %s", headerList)
	return stream.HpackContext.Encode(*headerList)
}