如何从net / http请求中读取HTTP / 2推送帧

时间:2017-05-08 16:41:27

标签: go http2

我正在尝试编写Go客户端来测试我们的http / 2基础架构。我想向https://mydomain.tld/somePage发出一个http请求,并希望收到一个html响应,以及几个推送的资源。我想确保那些推动成功,如果不成功则失败。

我不清楚标准库的任何部分是否公开了我需要的这个功能。

我可以查看响应并检查协议版本以检测http2。

我可以在发送推送的https://http2-push.appspot.com/等网站的响应中看到Link标头,但我不太清楚链接标头与实际Push Promise框架之间的关系。你可以通过http 1.1获得链接头,所以我不确定是否只能确保推送会发生。

http2 package有一个较低级Framer接口,我可以利用它来验证原始帧,但老实说,我不知道如何设置一个并发出初始请求它。

是否有任何示例说明go客户端如何验证http2推送资源的正确配置?

2 个答案:

答案 0 :(得分:3)

如果我们可以获得http.Client自然读取的字节副本,那么在golang.org/x/net/http2中使用Framer并不难。我们可以通过实现我们自己的net.Conn。

来做到这一点

我在下面的程序中取得了一些进展,但是我没有看到预期的PUSH_PROMISE帧。经过一番挖掘,我发现the Go client explicitly disables Push。在这种情况下,不允许服务器发送这些帧。我没有看到改变这种设置的明显方法(没有破解stdlib)。

以为我仍然分享我的代码。也许我错过了一些简单的东西,让它毕竟有用。

package main

import (
    "bytes"
    "crypto/tls"
    "io"
    "io/ioutil"
    "log"
    "net"
    "net/http"
    "os"

    "golang.org/x/net/http2"
)

func main() {
    buf := &bytes.Buffer{}
    transport := &http2.Transport{DialTLS: dialT(buf)}
    client := &http.Client{Transport: transport}

    res, err := client.Get("https://http2-push.appspot.com/")
    if err != nil {
            log.Fatal(err)
    }

    res.Body.Close()
    res.Write(os.Stdout)

    framer := http2.NewFramer(ioutil.Discard, buf)
    for {
            f, err := framer.ReadFrame()
            if err == io.EOF || err == io.ErrUnexpectedEOF {
                    break
            }
            switch err.(type) {
            case nil:
                    log.Println(f)
            case http2.ConnectionError:
                    // Ignore. There will be many errors of type "PROTOCOL_ERROR, DATA
                    // frame with stream ID 0". Presumably we are abusing the framer.
            default:
                    log.Println(err, framer.ErrorDetail())
            }
    }
}

// dialT returns a connection that writes everything that is read to w.
func dialT(w io.Writer) func(network, addr string, cfg *tls.Config) (net.Conn, error) {
    return func(network, addr string, cfg *tls.Config) (net.Conn, error) {
            conn, err := tls.Dial(network, addr, cfg)
            return &tConn{conn, w}, err
    }
}

type tConn struct {
    net.Conn
    T io.Writer // receives everything that is read from Conn
}

func (w *tConn) Read(b []byte) (n int, err error) {
    n, err = w.Conn.Read(b)
    w.T.Write(b)
    return
}

答案 1 :(得分:0)

提交patch进行审核。

" http2:支持在客户端消费PUSH_PROMISE流"

(github问题有里程碑" Unplanned",希望在审核队列中不会给它显着降低优先级。)