Last active
October 8, 2022 16:30
-
-
Save ilyaigpetrov/c9df309f16a7bea6834b1755ebf69985 to your computer and use it in GitHub Desktop.
How To Use Golang Framer? https://git.io/how-to-use-golang-framer | by https://git.io/ilyaigpetrov
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// It doesn't work well, I just want to save this imperfect note for myself in case I need it in the future. | |
// It's a modified version of code on https://stackoverflow.com/a/43900205/521957 | |
// If want to know how http2 session is initiated also look at https://github.com/golang/net/blob/master/http2/transport.go#L532 | |
package main | |
import ( | |
"crypto/tls" | |
"io" | |
"log" | |
"os" | |
"bytes" | |
"golang.org/x/net/http2" | |
"golang.org/x/net/http2/hpack" | |
) | |
var infolog = log.New(os.Stdout, | |
"", 0) | |
type proxyConn struct { | |
tls.Conn | |
} | |
func (w *proxyConn) Read(b []byte) (n int, err error) { | |
n, err = w.Conn.Read(b) | |
infolog.Println("READ:", string(b)) | |
return | |
} | |
func (w *proxyConn) Write(b []byte) (n int, err error) { | |
n, err = w.Conn.Write(b) | |
infolog.Println("WRITE:", string(b)) | |
return | |
} | |
func main() { | |
cfg := new(tls.Config) | |
cfg.NextProtos = append([]string{"h2"}, cfg.NextProtos...) | |
front := "google.com:443" | |
tlsConn, err := tls.Dial("tcp", front, cfg) | |
if err != nil { | |
panic(err) | |
} | |
sniffedTls := &proxyConn{*tlsConn} | |
transport := &http2.Transport{} | |
clientConn, err := transport.NewClientConn(sniffedTls) | |
_ = clientConn // not used | |
if err != nil { | |
panic(err) | |
} | |
framer := http2.NewFramer(sniffedTls, sniffedTls) | |
err = framer.WriteSettings() | |
if err != nil { | |
panic(err) | |
} | |
// clientConn.RoundTrip(req) is a way too. | |
var headers bytes.Buffer | |
enc := hpack.NewEncoder(&headers) | |
enc.WriteField(hpack.HeaderField{Name: ":authority", Value: "google.com"}) | |
enc.WriteField(hpack.HeaderField{Name: ":method", Value: "GET"}) | |
enc.WriteField(hpack.HeaderField{Name: ":path", Value: "/"}) | |
enc.WriteField(hpack.HeaderField{Name: ":scheme", Value: "https"}) | |
err = framer.WriteHeaders(http2.HeadersFrameParam{ | |
EndHeaders: true, | |
BlockFragment: headers.Bytes(), | |
StreamID: 13, | |
}) | |
if err != nil { | |
panic(err) | |
} | |
LOOP: | |
for { | |
infolog.Println("Reading frame...") | |
f, err := framer.ReadFrame() | |
if err == io.EOF || err == io.ErrUnexpectedEOF { | |
break | |
} | |
switch err.(type) { | |
case nil: | |
infolog.Printf("FRAME: %v", f) | |
setfr, ok := f.(*http2.SettingsFrame) | |
if ok && !setfr.IsAck() { | |
infolog.Println("Writing Settings ACK") | |
err = framer.WriteSettingsAck() | |
if err != nil { | |
infolog.Println(err) | |
panic(err) | |
} | |
} | |
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. | |
infolog.Println("CON ERR:", err) | |
default: | |
infolog.Println(err, framer.ErrorDetail()) | |
break LOOP | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I've forked this with some code I found on the net, my fork doesn't seem to do POST's but GET's as in this example work.