package main import ( "bytes" "crypto/tls" "encoding/json" "fmt" "html/template" "io/ioutil" "net" "net/http" "os" "time" "github.com/gorilla/websocket" "gopkg.in/urfave/cli.v2" "github.com/cloudflare/cloudflare-warp/tlsconfig" ) type templateData struct { ServerName string Request *http.Request Body string } type OriginUpTime struct { StartTime time.Time `json:"startTime"` UpTime string `json:"uptime"` } const defaultServerName = "the Cloudflare Warp test server" const indexTemplate = ` Cloudflare Warp Connection

Congrats! You created your first tunnel!

Cloudflare Warp exposes locally running applications to the internet by running an encrypted, virtual tunnel from your laptop or server to Cloudflare's edge network.

Ready for the next step?

Get started here

Request

Method: {{.Request.Method}}
Protocol: {{.Request.Proto}}
Request URL: {{.Request.URL}}
Transfer encoding: {{.Request.TransferEncoding}}
Host: {{.Request.Host}}
Remote address: {{.Request.RemoteAddr}}
Request URI: {{.Request.RequestURI}}
{{range $key, $value := .Request.Header}}
Header: {{$key}}, Value: {{$value}}
{{end}}
Body: {{.Body}}
` func hello(c *cli.Context) error { address := fmt.Sprintf(":%d", c.Int("port")) listener, err := createListener(address) if err != nil { return err } defer listener.Close() err = startHelloWorldServer(listener, nil) return err } func startHelloWorldServer(listener net.Listener, shutdownC <-chan struct{}) error { Log.Infof("Starting Hello World server at %s", listener.Addr()) serverName := defaultServerName if hostname, err := os.Hostname(); err == nil { serverName = hostname } upgrader := websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } httpServer := &http.Server{Addr: listener.Addr().String(), Handler: nil} go func() { <-shutdownC httpServer.Close() }() http.HandleFunc("/uptime", uptimeHandler(time.Now())) http.HandleFunc("/ws", websocketHandler(upgrader)) http.HandleFunc("/", rootHandler(serverName)) err := httpServer.Serve(listener) return err } func createListener(address string) (net.Listener, error) { certificate, err := tlsconfig.GetHelloCertificate() if err != nil { return nil, err } // If the port in address is empty, a port number is automatically chosen listener, err := tls.Listen( "tcp", address, &tls.Config{Certificates: []tls.Certificate{certificate}}) return listener, err } func uptimeHandler(startTime time.Time) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Note that if autoupdate is enabled, the uptime is reset when a new client // release is available resp := &OriginUpTime{StartTime: startTime, UpTime: time.Now().Sub(startTime).String()} respJson, err := json.Marshal(resp) if err != nil { w.WriteHeader(http.StatusInternalServerError) } else { w.Header().Set("Content-Type", "application/json") w.Write(respJson) } } } func websocketHandler(upgrader websocket.Upgrader) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { return } defer conn.Close() for { mt, message, err := conn.ReadMessage() if err != nil { break } if err := conn.WriteMessage(mt, message); err != nil { break } } } } func rootHandler(serverName string) http.HandlerFunc { responseTemplate := template.Must(template.New("index").Parse(indexTemplate)) return func(w http.ResponseWriter, r *http.Request) { Log.WithField("client", r.RemoteAddr).Infof("%s %s %s", r.Method, r.URL, r.Proto) var buffer bytes.Buffer var body string rawBody, err := ioutil.ReadAll(r.Body) if err == nil { body = string(rawBody) } else { body = "" } err = responseTemplate.Execute(&buffer, &templateData{ ServerName: serverName, Request: r, Body: body, }) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "error: %v", err) } else { buffer.WriteTo(w) } } }