package main import ( "fmt" "io/ioutil" "net/http" "net/http/httputil" "os" "strconv" "time" ) type ServerCommand struct { Body string `short:"b" long:"body" description:"Body message to respond with."` Port int `short:"p" long:"port" description:"Port to listen on." default:"8080"` Status int `short:"s" long:"status" description:"Status code to respond with." default:"204"` Cors bool `shot:"c" long:"cors" description:"Enable Cross Origin Resource Sharing (CORS)."` } var ( serverOptions *ServerCommand ) func (c *ServerCommand) Execute(args []string) error { fmt.Println("HTTP server listening on port " + strconv.Itoa(c.Port) + "\n") http.HandleFunc("/", serverRequestHandler) serverOptions = c if err := http.ListenAndServe(":"+strconv.Itoa(c.Port), nil); err != nil { fmt.Fprintf(os.Stderr, "Could not start server. Is port %d available?\n", c.Port) os.Exit(1) } return nil } func serverRequestHandler(rsp http.ResponseWriter, req *http.Request) { if globalOptions.Verbose { fmt.Printf("Received a %s request to %s\n", req.Method, req.RequestURI) } fmt.Println(time.Now().Format(time.StampMilli)) if globalOptions.BodiesOnly { body, _ := ioutil.ReadAll(req.Body) fmt.Println(string(body[:])) } else if globalOptions.HeadersOnly { fmt.Println(req.Method + " " + req.URL.Path + " " + req.Proto) for k := range req.Header { fmt.Println(k + ": " + req.Header[k][0]) } // TODO } else { // dump entire request dump, _ := httputil.DumpRequest(req, true) fmt.Println(string(dump[:])) } // cors if serverOptions.Cors && req.Method == http.MethodOptions { if globalOptions.Verbose { fmt.Println("CORS preflight") } if origin := req.Header.Get("Origin"); origin != "" { rsp.Header().Set("Access-Control-Allow-Origin", origin) if headers := req.Header.Get("Access-Control-Request-Headers"); headers != "" { rsp.Header().Set("Access-Control-Allow-Headers", headers) } if method := req.Header.Get("Access-Control-Request-Method"); method != "" { rsp.Header().Set("Access-Control-Allow-Method", method) } rsp.WriteHeader(200) return } else { if globalOptions.Verbose { fmt.Println("Preflight did not contain 'Origin' header!") } } } // send response if serverOptions.Body != "" { if serverOptions.Status == 204 { // body exists, so send a 200 response instead of 204 serverOptions.Status = 200 } rsp.WriteHeader(serverOptions.Status) fmt.Fprintf(rsp, serverOptions.Body) } else { // no body, so just write status header rsp.WriteHeader(serverOptions.Status) } }