diff --git a/README.md b/README.md index ca8659d..8462785 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,22 @@ Response behaviour is controlled via custom http headers: |X-Erised-Data|Returns the value **as is** in the response body| |X-Erised-Content-Type|Returns the value **as is** in the *Content-Type* response header| |X-Erised-Status-Code|Used to set the *http status code* value| +|X-Erised-Location|Returns the value **as is** of a new URL or path when 300 ≤ *X-Erised-Status-Code* < 310 -By design, no validation is performed on *X-Erised-Data* or *X-Erised-Content-Type*. Values are used **as is** +By design, no validation is performed on *X-Erised-Data*, *X-Erised-Content-Type* or *X-Erised-Location*. Values are returned **as is** Valid *X-Erised-Status-Code* values are as follows: ```text OK or 200 +MultipleChoices or 300 +MovedPermanently or 301 +Found or 302 +SeeOther or 303 +UseProxy or 305 +TemporaryRedirect or 307 +PermanentRedirect or 308 + BadRequest or 400 Unauthorized or 401 PaymentRequired or 402 @@ -146,15 +155,16 @@ Server refuses to brew coffee because it is, permanently, a teapot. ``` # Release History -* v0.0.1 Initial release +* v0.0.2 - Add HTTP redirection status codes (300's), startup configuration parameters and request's logging +* v0.0.1 - Initial release # Known Issues **erised** is full of bugs and "_...men have wasted away before it, not knowing if what they have seen is real, or even possible..._" so use it with caution for it gives no knowledge or truth. Of all its deficiencies, the most notable are: * There are not tests (yet) -* **erised** offers no help -* Server parameters are hardcoded +* ~~**erised** offers no help~~ +* ~~Server parameters are hardcoded~~ * Server does not shutdown gracefully. To stop, process must be terminated * https protocol is not supported * **erised** does not scale well diff --git a/cmd/erised/main.go b/cmd/erised/main.go index 3089436..e886202 100644 --- a/cmd/erised/main.go +++ b/cmd/erised/main.go @@ -1,8 +1,13 @@ package main import ( + "flag" + "fmt" "log" "net/http" + "os" + "path/filepath" + "strconv" "time" ) @@ -11,22 +16,41 @@ type server struct { cfg *http.Server } -func newServer() *server { +func newServer(port, read, write, idle int) *server { s := &server{} s.mux = &http.ServeMux{} s.cfg = &http.Server{ - Addr: ":8080", + Addr: ":" + strconv.Itoa(port), Handler: s.mux, - ReadTimeout: 5 * time.Second, - WriteTimeout: 10 * time.Second, - IdleTimeout: 120 * time.Second, + ReadTimeout: time.Duration(read) * time.Second, + WriteTimeout: time.Duration(write) * time.Second, + IdleTimeout: time.Duration(idle) * time.Second, } s.routes() + log.Printf("Server configured to listen on port %s. Timeouts: %s (read) %s (write) %s (idle)\n", + s.cfg.Addr, s.cfg.ReadTimeout.String(), s.cfg.WriteTimeout.String(), s.cfg.IdleTimeout.String()) + return s } +func setupFlags(f *flag.FlagSet) { + f.Usage = func() { + _, _ = fmt.Printf("%s: a simple http server to test arbitrary responses. Usage example at https://github.com/EAddario/erised\n", filepath.Base(os.Args[0])) + fmt.Println("\nParameters:") + flag.PrintDefaults() + } +} + func main() { - srv := newServer() + pt := flag.Int("port", 8080, "port to listen") + rt := flag.Int("read", 5, "read timeout in seconds") + wt := flag.Int("write", 10, "write timeout in seconds") + it := flag.Int("idle", 120, "idle timeout in seconds") + + setupFlags(flag.CommandLine) + flag.Parse() + + srv := newServer(*pt, *rt, *wt, *it) log.Fatal(srv.cfg.ListenAndServe()) } diff --git a/cmd/erised/serverRoutes.go b/cmd/erised/serverRoutes.go index 7f3596f..e0d2173 100644 --- a/cmd/erised/serverRoutes.go +++ b/cmd/erised/serverRoutes.go @@ -1,6 +1,7 @@ package main import ( + "log" "net/http" ) @@ -10,6 +11,9 @@ func (s *server) routes() { func (s *server) handleLanding() http.HandlerFunc { return func (res http.ResponseWriter, req *http.Request) { + log.Printf("%s from %s - %s %s%s", + req.Proto, req.RemoteAddr, req.Method, req.Host, req.RequestURI) + res.Header().Set("Content-Type", "text/plain; charset=utf-8") if ct := req.Header.Get("X-Erised-Content-Type"); ct != "" { @@ -19,7 +23,11 @@ func (s *server) handleLanding() http.HandlerFunc { res.Header().Set("Transfer-Encoding", te) } - res.WriteHeader(httpStatusCode(req.Header.Get("X-Erised-Status-Code"))) + sc := httpStatusCode(req.Header.Get("X-Erised-Status-Code")) + if sc >= 300 && sc < 310 { + res.Header().Set("Location", req.Header.Get("X-Erised-Location")) + } + res.WriteHeader(sc) data := req.Header.Get("X-Erised-Data") diff --git a/cmd/erised/serverUtil.go b/cmd/erised/serverUtil.go index ab36960..e5b59a4 100644 --- a/cmd/erised/serverUtil.go +++ b/cmd/erised/serverUtil.go @@ -21,6 +21,14 @@ func httpStatusCode(code string) int { switch code { case "OK", "200" : return 200 + case "MultipleChoices", "300": return 300 + case "MovedPermanently", "301": return 301 + case "Found", "302": return 302 + case "SeeOther", "303": return 303 + case "UseProxy", "305": return 305 + case "TemporaryRedirect", "307": return 307 + case "PermanentRedirect", "308": return 308 + case "BadRequest", "400": return 400 case "Unauthorized", "401": return 401 case "PaymentRequired", "402": return 402 @@ -76,4 +84,3 @@ func (s *server) respond(res http.ResponseWriter, encoding int, data interface{ } } } -