package main
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"net"
"net/http"
"os"
"github.com/pkg/errors"
log "github.com/Sirupsen/logrus"
cli "gopkg.in/urfave/cli.v2"
)
type templateData struct {
ServerName string
Request *http.Request
Body string
}
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"))
server := NewHelloWorldServer()
if hostname, err := os.Hostname(); err != nil {
server.serverName = hostname
}
err := server.ListenAndServe(address)
return errors.Wrap(err, "Fail to start Hello World Server")
}
func startHelloWorldServer(listener net.Listener, shutdownC <-chan struct{}) error {
server := NewHelloWorldServer()
if hostname, err := os.Hostname(); err != nil {
server.serverName = hostname
}
httpServer := &http.Server{Addr: listener.Addr().String(), Handler: server}
go func() {
<-shutdownC
httpServer.Close()
}()
err := httpServer.Serve(listener)
return err
}
type HelloWorldServer struct {
responseTemplate *template.Template
serverName string
}
func NewHelloWorldServer() *HelloWorldServer {
return &HelloWorldServer{
responseTemplate: template.Must(template.New("index").Parse(indexTemplate)),
serverName: defaultServerName,
}
}
func findAvailablePort() (net.Listener, error) {
// If the port in address is empty, a port number is automatically chosen.
listener, err := net.Listen("tcp", "127.0.0.1:")
return listener, err
}
func (s *HelloWorldServer) ListenAndServe(address string) error {
log.Infof("Starting Hello World server on %s", address)
err := http.ListenAndServe(address, s)
return err
}
func (s *HelloWorldServer) ServeHTTP(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 = s.responseTemplate.Execute(&buffer, &templateData{
ServerName: s.serverName,
Request: r,
Body: body,
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "error: %v", err)
} else {
buffer.WriteTo(w)
}
}