Reputation: 272
Was trying out the http2 package in go, and while creating an HTTP2 connection I am getting an unexpected EOF error. Not able to figure out the exact issue.
tcpConn, err := net.Dial("tcp", "clients1.google.com:443")
if err != nil {
panic(err)
}
defer tcpConn.Close()
t := http2.Transport{}
http2ClientConn, err := t.NewClientConn(tcpConn)
if err != nil {
panic(err)
}
req, err := http.NewRequest("GET", "https://clients1.google.com/generate_204", nil)
if err != nil {
panic(err)
}
resp, err := http2ClientConn.RoundTrip(req)
if err != nil {
panic(err) // getting unexpected EOF
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
Output
panic: unexpected EOF
goroutine 1 [running]:
main.main()
/Users/rishabharya/Desktop/Projects/src/github.com/rishabh-arya95/raw_http/main.go:31 +0x217
exit status 2
Upvotes: 1
Views: 4548
Reputation: 121
You should use TLS encryption with Application-Layer Protocol Negotiation (ALPN).
The client establishes a connection to the standard HTTPS port (port number is 443), but use net.Dial() function. HTTPS protocol use TLS to secure HTTP connection over the Internet. Therefore, the client have to use tls.Dial() function to establish a connection:
tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", new(tls.Config))
However, the client cannot use an empty TLS configuration. In this particular case, the server supports both protocols: HTTP/1.1 and HTTP/2. By default, the server uses HTTP/1.1 protocol. There are two ways to request the use of HTTP/2 protocol:
The second method is not suitable. The first reason is that http2 package is not intended for this. The second reason is that the server ignores HTTP Upgrade mechanism for the given request.
In order to use the first methods, we need to add "h2" identifier to a list of supported application level protocols (a list of all registered identifiers can be found on IANA website).
conf := & tls.Config {
NextProtos: []string{"h2"},
}
tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", conf)
package main
import (
"crypto/tls"
"fmt"
"net/http"
"golang.org/x/net/http2"
)
func main() {
conf := & tls.Config {
NextProtos: []string{"h2"},
}
tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", conf)
if err != nil {
panic(err)
}
defer tcpConn.Close()
t := http2.Transport{}
http2ClientConn, err := t.NewClientConn(tcpConn)
if err != nil {
panic(err)
}
req, err := http.NewRequest("GET", "https://clients1.google.com/generate_204", nil)
if err != nil {
panic(err)
}
resp, err := http2ClientConn.RoundTrip(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
}
And a slightly modified version.
cURL is a handy tool for checking.
Make an HTTP/2 request:
$ curl -i --http2 https://clients1.google.com/generate_204
-| HTTP/2 204
Disable Application-Layer Protocol Negotiation (ALPN):
$ curl -i --http2 --no-alpn https://clients1.google.com/generate_204
-| HTTP/1.1 204 No Content
Send an HTTP/2 request without Application-Layer Protocol Negotiation (ALPN):
$ curl -i --http2-prior-knowledge --no-alpn https://clients1.google.com/generate_204
-| curl: (52) Empty reply from server
Error 52: The server did not reply anything, which here is considered an error.
Parameter | Description |
---|---|
-i | Include the HTTP response headers in the output. |
-v | Makes curl verbose during the operation. |
--no-alpn | Disable the ALPN TLS extension. |
--http2 | Tells curl to use HTTP version 2. |
--http2-prior-knowledge | Tells curl to use HTTP version 2. |
Upvotes: 1