From 18f4bcbbaecf2f938edb8a7119752bd1c767ef3e Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Mon, 21 May 2018 13:02:15 +0200 Subject: [PATCH] add 'controller path-finding' + 'method check' + [TODO: issue with ParseMultipartForm() that is slow] --- internal/config/types.go | 2 +- request_builder.go | 11 ++++-- router.go | 77 ++++++++++++++++++++++++++++++++++------ server.go | 2 +- types.go | 8 +++-- 5 files changed, 83 insertions(+), 17 deletions(-) diff --git a/internal/config/types.go b/internal/config/types.go index 7cf7bdd..8646585 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -23,5 +23,5 @@ type Controller struct { PUT *Method `json:"PUT"` DELETE *Method `json:"DELETE"` - Children map[string]Controller `json:"/"` + Children map[string]*Controller `json:"/"` } diff --git a/request_builder.go b/request_builder.go index bfc251a..fc5f163 100644 --- a/request_builder.go +++ b/request_builder.go @@ -2,12 +2,15 @@ package gfw import ( "encoding/json" + "fmt" "log" - "math" "net/http" "strings" + "time" ) +// buildRequest builds an interface request +// from a http.Request func buildRequest(req *http.Request) (*Request, error) { /* (1) Init request */ @@ -16,7 +19,9 @@ func buildRequest(req *http.Request) (*Request, error) { Uri: strings.Split(uri, "/"), GetData: FetchGetData(req), FormData: FetchFormData(req), + Data: make(map[string]interface{}), } + inst.ControllerUri = make([]string, 0, len(inst.Uri)) return inst, nil } @@ -91,8 +96,9 @@ func FetchFormData(req *http.Request) map[string]interface{} { } else { // form-data or anything + startn := time.Now().UnixNano() // 1. Parse form-data - if err := req.ParseMultipartForm(math.MaxInt32); err != nil { + if err := req.ParseMultipartForm(req.ContentLength + 1); err != nil { log.Printf("[read.multipart] %s\n", err) return res } @@ -101,6 +107,7 @@ func FetchFormData(req *http.Request) map[string]interface{} { for name, value := range req.PostForm { res[name] = value } + fmt.Printf("* %.3f us\n", float64(time.Now().UnixNano()-startn)/1e3) } diff --git a/router.go b/router.go index 653245c..1607217 100644 --- a/router.go +++ b/router.go @@ -2,11 +2,12 @@ package gfw import ( "fmt" + "git.xdrm.io/gfw/internal/config" "log" "net/http" ) -func route(res http.ResponseWriter, req *http.Request) { +func (s Server) route(res http.ResponseWriter, req *http.Request) { /* (1) Build request ---------------------------------------------------------*/ @@ -16,17 +17,73 @@ func route(res http.ResponseWriter, req *http.Request) { log.Fatal(req) } - fmt.Printf("Uri: %v\n", request.Uri) - fmt.Printf("GET: %v\n", request.GetData) - fmt.Printf("POST: %v\n", request.FormData) + // fmt.Printf("Uri: %v\n", request.Uri) + // fmt.Printf("GET: %v\n", request.GetData) + // fmt.Printf("POST: %v\n", request.FormData) - // 1. Query parameters - // fmt.Printf("query: %v\n", req.URL.Query()) + /* (2) Find a controller + ---------------------------------------------------------*/ + /* (1) Init browsing cursors */ + ctl := s.config + uriIndex := 0 - // 2. URI path - // fmt.Printf("uri: %v\n", req.URL.Path) + /* (2) Browse while there is uri parts */ + for uriIndex < len(request.Uri) { + uri := request.Uri[uriIndex] - // 3. Form values - // fmt.Printf("form: %v\n", req.FormValue("asa")) + child, hasKey := ctl.Children[uri] + // stop if no matchind child + if !hasKey { + break + } + + request.ControllerUri = append(request.ControllerUri, uri) + ctl = child + uriIndex++ + + } + + /* (3) Check method + ---------------------------------------------------------*/ + /* (1) Unavailable method */ + if req.Method == "GET" && ctl.GET == nil || + req.Method == "POST" && ctl.POST == nil || + req.Method == "PUT" && ctl.PUT == nil || + req.Method == "DELETE" && ctl.DELETE == nil { + + Json, _ := ErrUnknownMethod.MarshalJSON() + res.Header().Add("Content-Type", "application/json") + res.Write(Json) + log.Printf("[err] %s\n", ErrUnknownMethod.Reason) + return + + } + + /* (2) Extract method cursor */ + var method *config.Method + + if req.Method == "GET" { + method = ctl.GET + } else if req.Method == "POST" { + method = ctl.POST + } else if req.Method == "PUT" { + method = ctl.PUT + } else if req.Method == "DELETE" { + method = ctl.DELETE + } + + /* (3) Unmanaged HTTP method */ + if method == nil { // unknown method + Json, _ := ErrUnknownMethod.MarshalJSON() + res.Header().Add("Content-Type", "application/json") + res.Write(Json) + log.Printf("[err] %s\n", ErrUnknownMethod.Reason) + return + } + + /* (4) Check arguments + ---------------------------------------------------------*/ + fmt.Printf("OK\n") + return } diff --git a/server.go b/server.go index 8c11819..7949ca5 100644 --- a/server.go +++ b/server.go @@ -9,7 +9,7 @@ import ( func (s *Server) Launch(port uint16) error { /* (1) Bind router */ - http.HandleFunc("/", route) + http.HandleFunc("/", s.route) /* (2) Bind listener */ return http.ListenAndServe(fmt.Sprintf(":%d", port), nil) diff --git a/types.go b/types.go index 183722a..2256488 100644 --- a/types.go +++ b/types.go @@ -11,7 +11,9 @@ type Server struct { } type Request struct { - Uri []string - FormData map[string]interface{} - GetData map[string]interface{} + Uri []string + ControllerUri []string + FormData map[string]interface{} + GetData map[string]interface{} + Data map[string]interface{} }