dgrr / http2

HTTP/2 implementation for fasthttp
Apache License 2.0
208 stars 35 forks source link

Does not work using net.Listener with TLS #24

Closed gitfury closed 2 years ago

gitfury commented 2 years ago

It seems as if using fasthttp2.ConfigureServer(server) does not work, even when the server is serving on a TLS listener. Am I doing something incorrect or is there no support for this?

    listener, err := net.Listen("tcp4", "0.0.0.0:443")
    if err != nil {
        panic(err)
    }

    tlsListener := tls.NewListener(listener, tlsConfig)

    server := &fasthttp.Server {
        Handler: ServeHTTP,
    }

    fasthttp2.ConfigureServer(server)

    go server.Serve(tlsListener)
dgrr commented 2 years ago

Oh yes! So you doing something wrong, and I am doing it too! ConfigureServer actually configures the TLSConfig of fasthttp.Server. In that sense, if you are going to use your own tls.Config then http2 is not going to work. I'll write a fix for that.

dgrr commented 2 years ago

@gitfury You can use ConfigureServerAndConfig(fasthttpServer, tlsConfig)

gitfury commented 2 years ago

Hi, Thank you for the response! Maybe I am still doing something wrong, but I am using AutoCert to manage certificates for me dynamically, as such, I cannot set a "start" certificate like in server.ListenAndServeTLS so I used the net.Listener (https://github.com/valyala/fasthttp/issues/431) It looks something like this:

    autoCert := &autocert.Manager{
        Prompt: autocert.AcceptTOS,
        Cache:  autocert.DirCache("/var/certs/"),
    }

    tlsConfig := &tls.Config{
        GetCertificate:           autoCert.GetCertificate,
        PreferServerCipherSuites: true,
        CurvePreferences: []tls.CurveID{
            tls.CurveP256,
            tls.X25519, // Go 1.8 only
        },
    }

    listener, err := net.Listen("tcp4", "0.0.0.0:443")
    if err != nil {
        panic(err)
    }

    tlsListener := tls.NewListener(listener, tlsConfig)

    server := &fasthttp.Server {
        Handler: ServeHTTP,
    }

    fasthttp2.ConfigureServerAndConfig(server, tlsConfig)

    go server.Serve(tlsListener)
    server.ListenAndServe(":80")

I tried the same code, and used ConfigureServerAndConfig but it still does not work.

erikdubbelboer commented 2 years ago

fasthttp2.ConfigureServerAndConfig(server, tlsConfig) needs to be called before tls.NewListener(listener, tlsConfig) as it makes changes to the tlsConfig that tls.NewListener needs.

gitfury commented 2 years ago

Works, thank you! One suggestion, let us be able to intercept the request before is redirected to HTTPS.

dgrr commented 2 years ago

You can already do it by yourself, notice that fasthttp2 is like a third-party package to http2. You can already use your own handler like here. For example:

func ConfigureOwnServer(s *fasthttp.Server) *http2.Server {
    s2 := &http2.Server{
        Adaptor: fasthttp2.NewServerAdaptor(s),
    }

    s.NextProto(http2.H2TLSProto, func(c net.Conn) error {
          if c.RemoteAddr().String() != "127.0.0.1:8443" {
            c.Close()
            return errors.New("Not allowed")
          }
          return s2.ServeConn(c)
        })

    return s2
}
gitfury commented 2 years ago

Ah I see thank you! One more thing, on IOS Safari fasthttp2 does not seem to work, output doesn't seem to say anything but Safari cay "cannot parse response". Is this something you can replicate on your own end or am I doing something wrong again?

dgrr commented 2 years ago

Weird. I am able to access http2.gofiber.io from Safari on an iPhone. I'd say is something on your end? Can you enter http2.gofiber.io from there or it happens only on your own website?

gitfury commented 2 years ago

Ah it works, it was something on my end, I was connecting via http instead of https. Also, is there a way to handle new connections before they get parsed by fasthttp? I see the ConnState hook is similar to I'm looking for, but I also need to be able to close those connections and I cannot close the connection inside ConnState without getting a panic for "use of closed network connection". Or maybe there's a way I can use my TCP listener to accept the connection, then send it to fasthttp to handle it after?

dgrr commented 2 years ago

You can try to make your own net.Listener that wraps the original net.Listener. But, why do you want that? Can I know about your use case?

gitfury commented 2 years ago

To gather data about an IP making a connection and to be able to block or accept them before my server spends CPU time parsing their request, etc.

dgrr commented 2 years ago

Then you can use the example I gave you before in this comment.

NextProto gets called after the TLS handshake, so fasthttp nor fasthttp2 will spend any time parsing any request on the NextProto callback.

gitfury commented 2 years ago

Yes, this works for http2. But I also want it to work for HTTP/1.1.

EDIT: I found what I was looking for. Something like this: I can just do

    for {
        conn, err := tlsListener.Accept()

        if err == nil {
            go func(c net.Conn) {
                          ... processing stuff
                          server.ServeConn(c)
            }(conn)
        }
    }

I assume this has downsides though? Because fasthttp uses worker pools instead of goroutines, this shouldn't hurt the original performance too much right? or is there a way I can implement the worker pool myself, it seems unexported