package main
import (
"bytes"
"fmt"
"html/template"
"net"
"net/http"
"os"
"strings"
"github.com/pkg/errors"
log "github.com/Sirupsen/logrus"
"github.com/cloudflare/cloudflare-warp/origin"
tunnelpogs "github.com/cloudflare/cloudflare-warp/tunnelrpc/pogs"
cli "gopkg.in/urfave/cli.v2"
)
type templateData struct {
ServerName string
Request *http.Request
Tags []tunnelpogs.Tag
}
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
{{if .Tags}}
Connection
{{range .Tags}} {{.Name}}
{{.Value}}
{{end}}
{{end}}
`
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
err := s.responseTemplate.Execute(&buffer, &templateData{
ServerName: s.serverName,
Request: r,
Tags: tagsFromHeaders(r.Header),
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "error: %v", err)
} else {
buffer.WriteTo(w)
}
}
func tagsFromHeaders(header http.Header) []tunnelpogs.Tag {
var tags []tunnelpogs.Tag
for headerName, headerValues := range header {
trimmed := strings.TrimPrefix(headerName, origin.TagHeaderNamePrefix)
if trimmed == headerName {
continue
}
for _, value := range headerValues {
tags = append(tags, tunnelpogs.Tag{Name: trimmed, Value: value})
}
}
return tags
}