// 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) } }
// 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) }