win-t
win-t

Reputation: 187

How to completely disable HTTP/1.x support

I only want to support HTTP/2 for a new project, the client is not a browser so it's not a problem if we don't support HTTP/1.x at all.

from what I see in golang.org/x/net/http2. I can use tls.Listen and pass the net.Conn to http2.Server.ServeConn.

But I'm bit confused about how to use http2.Transport here, can anyone give me an example?

Thanks

UPDATE:

This is the server part, pretty simple, it's an echo server

package main

import (
    "fmt"
    "io"
    "net"
    "net/http"

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

func main() {
    l, err := net.Listen("tcp4", ":1234")
    panicIfNotNil(err)

    s := &http2.Server{}
    sopt := &http2.ServeConnOpts{
        BaseConfig: &http.Server{},
        Handler:    http.HandlerFunc(handler),
    }
    for {
        c, err := l.Accept()
        panicIfNotNil(err)
        go serve(s, sopt, c)
    }
}

func serve(s *http2.Server, sopt *http2.ServeConnOpts, c net.Conn) {
    defer c.Close()
    s.ServeConn(c, sopt)
}

func handler(w http.ResponseWriter, r *http.Request) {
    if r.ProtoMajor != 2 {
        w.WriteHeader(500)
        fmt.Fprintln(w, "Not HTTP/2")
        return
    }
    f, ok := w.(http.Flusher)
    if !ok {
        w.WriteHeader(500)
        fmt.Fprintln(w, "Not Flusher")
        return
    }
    w.Header().Set("Content-Type", "application/octet-stream")
    fmt.Fprintln(w, "Hello World, Echo Server")

    buf := [1024]byte{}
    for {
        n, err := r.Body.Read(buf[:])
        if err == io.EOF {
            break
        }
        panicIfNotNil(err)
        _, err = w.Write(buf[:n])
        f.Flush()
        panicIfNotNil(err)
    }
}

func panicIfNotNil(err error) {
    if err != nil {
        panic(err)
    }
}

tested with curl --http2-prior-knowledge http://127.0.0.1:1234 -d a=b -d c=d -d e=f

for the client part, I'm still trying, I will update this post again when I got something.

UPDATE:

for the sake of simplicity, I don't use TLS here

UPDATE:

This is the client part

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "net"
    "net/http"
    "net/url"
    "time"

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

func main() {
    t := &http2.Transport{
        DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
            return net.Dial(network, addr)
        },
        AllowHTTP: true,
    }
    c := &http.Client{
        Transport: t,
    }

    pr, pw := io.Pipe()
    req := &http.Request{
        Method: "POST",
        URL:    mustUrl("http://127.0.0.1:1234/"),
        Body:   pr,
    }
    resp, err := c.Do(req)
    panicIfNotNil(err)
    defer resp.Body.Close()
    if resp.StatusCode != 200 {
        panic(fmt.Errorf("Server return non 200, %d", resp.StatusCode))
    }

    wchan := make(chan struct{})
    go func() {
        buf := [1024]byte{}
        for {
            n, err := resp.Body.Read(buf[:])
            if err == io.EOF {
                break
            }
            panicIfNotNil(err)
            fmt.Printf("GOT DATA %s\n", string(buf[:n]))
        }
        close(wchan)
    }()

    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai AAA"))
    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai BBB"))
    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai CCC"))
    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai CCC"))
    time.Sleep(1 * time.Second)
    pw.Close()

    <-wchan
}

func mustUrl(s string) *url.URL {
    r, err := url.Parse(s)
    panicIfNotNil(err)
    return r
}

func panicIfNotNil(err error) {
    if err != nil {
        panic(err)
    }
}

but somehow it doesn't work You can see network traffic in https://i.sstatic.net/wnIlQ.jpg

Upvotes: 3

Views: 1180

Answers (1)

win-t
win-t

Reputation: 187

After looking into Wireshark more closely I found the problem, it happens because the server didn't send any header frame, so the client cannot continue with more data. Just printing into http.ResponseWriter doesn't ensure its written into the network, it gets buffered instead, so we need to explicitly flush it.

This fixes the problem:

--- main.go 2018-07-25 22:31:44.092823590 +0700
+++ main2.go    2018-07-25 22:32:50.586179879 +0700
@@ -43,6 +43,9 @@
        return
    }
    w.Header().Set("Content-Type", "application/octet-stream")
+   w.WriteHeader(200)
+   f.Flush()
+
    fmt.Fprintln(w, "Hello World, Echo Server")

    buf := [1024]byte{}

Upvotes: 2

Related Questions