diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..547730b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "go.autocompleteUnimportedPackages": true +} \ No newline at end of file diff --git a/bin/gocode.exe b/bin/gocode.exe new file mode 100644 index 0000000..de80e04 Binary files /dev/null and b/bin/gocode.exe differ diff --git a/bin/gopkgs.exe b/bin/gopkgs.exe new file mode 100644 index 0000000..dba4b1c Binary files /dev/null and b/bin/gopkgs.exe differ diff --git a/bin/goreturns.exe b/bin/goreturns.exe new file mode 100644 index 0000000..99d4c06 Binary files /dev/null and b/bin/goreturns.exe differ diff --git a/go/pythia.mk b/go/pythia.mk index e6bf75c..2574905 100644 --- a/go/pythia.mk +++ b/go/pythia.mk @@ -29,7 +29,10 @@ GO_OUT_BINARIES := $(addprefix $(OUT_DIR)/,$(GO_INSTALL_BINARIES)) $(call add_target,go,BUILD,Build go code) all: go -go: $(GO_TARGETS) $(GO_OUT_BINARIES) +go: go_deps $(GO_TARGETS) $(GO_OUT_BINARIES) + +go_deps: + go get -u github.com/gorilla/mux $(GO_TARGETS): $(GO_SOURCES) $(GO) install $(addsuffix /...,$(GO_PACKAGES)) diff --git a/go/src/github.com/gorilla/context b/go/src/github.com/gorilla/context new file mode 160000 index 0000000..08b5f42 --- /dev/null +++ b/go/src/github.com/gorilla/context @@ -0,0 +1 @@ +Subproject commit 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 diff --git a/go/src/github.com/gorilla/mux b/go/src/github.com/gorilla/mux new file mode 160000 index 0000000..e3702be --- /dev/null +++ b/go/src/github.com/gorilla/mux @@ -0,0 +1 @@ +Subproject commit e3702bed27f0d39777b0b37b664b6280e8ef8fbf diff --git a/go/src/pythia/frontend/confReader.go b/go/src/pythia/frontend/confReader.go new file mode 100644 index 0000000..09bb0bf --- /dev/null +++ b/go/src/pythia/frontend/confReader.go @@ -0,0 +1,49 @@ +package frontend + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" +) + +//Conf struct for the config.json file +type Conf struct { + IP []string +} + +var myConf Conf + +//GetConf that was or will be loaded from the config.json file +func GetConf() Conf { + //check if not initialized + if cap(myConf.IP) == 0 { + fmt.Println("ip = 0") + myConf = LoadConf() + } + fmt.Println("sending conf") + return myConf +} + +//LoadConf to retreive the data from the conf.json file +func LoadConf() Conf { + var conf Conf + //Problem with the congif.json file: it must be in the go/bin/ directory to be loaded + c, err := ioutil.ReadFile("./config.json") + if err != nil { + log.Println("Could not open conf file, default configuration loaded") + return LoadDefaultConf() + } + + if err := json.Unmarshal(c, &conf); err != nil { + log.Println("Could not retreive data from conf file default configuration loaded") + return LoadDefaultConf() + } + + return conf +} + +func LoadDefaultConf() Conf { + conf := Conf{[]string{"127.0.0.1", "::1"}} + return conf +} diff --git a/go/src/pythia/frontend/handlers.go b/go/src/pythia/frontend/handlers.go new file mode 100644 index 0000000..d40d40b --- /dev/null +++ b/go/src/pythia/frontend/handlers.go @@ -0,0 +1,91 @@ +package frontend + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "pythia" +) + +//Echo the given message in a JSON Message struct format +func Echo(rw http.ResponseWriter, r *http.Request) { + var message map[string]string + body, err := ioutil.ReadAll(r.Body) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + } + if err := json.Unmarshal(body, &message); err != nil { + Error422(rw, err) + return + } + for key := range message { + if key == "text" { + if err := json.NewEncoder(rw).Encode("Reply: " + message["text"]); err != nil { + panic(err) + } + return + } + } + Error422(rw, err) + +} + +// Task function for the server. +func Task(rw http.ResponseWriter, req *http.Request) { + log.Println("Client connected: ", req.URL) + if req.Method != "POST" { + rw.WriteHeader(http.StatusMethodNotAllowed) + return + } + // Reading the task request + body, err := ioutil.ReadAll(req.Body) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + return + } + var taskReq taskRequest + if err := json.Unmarshal([]byte(body), &taskReq); err != nil { + rw.WriteHeader(http.StatusBadRequest) + return + } + // Connection to the pool and execution of the task + conn := pythia.DialRetry(pythia.QueueAddr) + defer conn.Close() + content, err := ioutil.ReadFile("tasks/" + taskReq.Tid + ".task") + if err != nil { + Error422(rw, err) + return + } + var task pythia.Task + if err := json.Unmarshal([]byte(content), &task); err != nil { + rw.WriteHeader(http.StatusInternalServerError) + return + } + conn.Send(pythia.Message{ + Message: pythia.LaunchMsg, + Id: "test", + Task: &task, + Input: taskReq.Response, + }) + if msg, ok := <-conn.Receive(); ok { + switch msg.Status { + case "success": + fmt.Fprintf(rw, msg.Output) + } + return + } + rw.WriteHeader(http.StatusInternalServerError) +} + +//Error422 response +func Error422(w http.ResponseWriter, err error) { + //Unprocessable Entity if can't convert to struct + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(422) + w.Write([]byte("Error 422: Unprocessable Entity ")) + if err := json.NewEncoder(w).Encode(err); err != nil { + panic(err) + } +} diff --git a/go/src/pythia/frontend/routes.go b/go/src/pythia/frontend/routes.go new file mode 100644 index 0000000..32d301e --- /dev/null +++ b/go/src/pythia/frontend/routes.go @@ -0,0 +1,84 @@ +package frontend + +import ( + "net" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +//Route struct to easily add new roots +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +//Routes is a list of Route +type Routes []Route + +//NewRouter changed mux.Router func to work with the Rout struct +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + + for _, route := range routes { + router.Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(route.HandlerFunc) + } + + return router +} + +//MiddleWare check the IP of client with the list of IPs in conf.jdon +func MiddleWare(h http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + addr := GetClientIPs(r) + IPConf := GetConf().IP + + for _, ipConf := range IPConf { + for _, ipClient := range addr { + if ipConf == ipClient { + h.ServeHTTP(w, r) + return + } + } + } + http.Error(w, "Unauthorized IP address", 401) + return + }) +} + +//GetClientIPs returns the IPs address of client +func GetClientIPs(r *http.Request) []string { + //If X-FORWARDED-FOR structure is respected (first IP is the client's private IP address) + //and separate with ", " + //Header.Get will have all other IPs but not the last one used (last proxy or client if empty) + var IPs []string + if allIP := r.Header.Get("W-FORWARDED-FOR"); len(allIP) > 0 { + IPs = strings.Split(allIP, ", ") + } + ip, _, _ := net.SplitHostPort(r.RemoteAddr) + IPs = append(IPs, ip) + return IPs +} + +var routes = Routes{ + Route{ + "Echo", + "POST", + "/api/echo", + Echo, + }, + Route{ + "Task", + "POST", + "/execute", + Task, + }, +} diff --git a/go/src/pythia/frontend/server.go b/go/src/pythia/frontend/server.go index fc0d923..7cd6aac 100644 --- a/go/src/pythia/frontend/server.go +++ b/go/src/pythia/frontend/server.go @@ -16,15 +16,13 @@ package frontend import ( - "encoding/json" "flag" - "fmt" - "io/ioutil" "log" "net/http" "os" "os/signal" "pythia" + "strconv" "syscall" ) @@ -82,9 +80,14 @@ func (server *Server) Run() { os.Exit(0) }() // Start the web server - http.HandleFunc("/execute", handler) + router := NewRouter() + httpServ := &http.Server{ + Addr: ":" + strconv.Itoa(server.Port), + Handler: MiddleWare(router), + } + log.Println("Server listening on", server.Port) - if err := http.ListenAndServe(fmt.Sprint(":", server.Port), nil); err != nil { + if err := httpServ.ListenAndServe(); err != nil { log.Fatal(err) } } @@ -93,51 +96,4 @@ func (server *Server) Run() { func (server *Server) Shutdown() { } -// Handler function for the server. -func handler(rw http.ResponseWriter, req *http.Request) { - log.Println("Client connected: ", req.URL) - if req.Method != "POST" { - rw.WriteHeader(http.StatusMethodNotAllowed) - return - } - // Reading the task request - body, err := ioutil.ReadAll(req.Body) - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - return - } - var taskReq taskRequest - if err := json.Unmarshal([]byte(body), &taskReq); err != nil { - rw.WriteHeader(http.StatusBadRequest) - return - } - // Connection to the pool and execution of the task - conn := pythia.DialRetry(pythia.QueueAddr) - defer conn.Close() - content, err := ioutil.ReadFile("tasks/" + taskReq.Tid + ".task") - if err != nil { - rw.WriteHeader(422) - return - } - var task pythia.Task - if err := json.Unmarshal([]byte(content), &task); err != nil { - rw.WriteHeader(http.StatusInternalServerError) - return - } - conn.Send(pythia.Message{ - Message: pythia.LaunchMsg, - Id: "test", - Task: &task, - Input: taskReq.Response, - }) - if msg, ok := <-conn.Receive(); ok { - switch msg.Status { - case "success": - fmt.Fprintf(rw, msg.Output) - } - return - } - rw.WriteHeader(http.StatusInternalServerError) -} - // vim:set sw=4 ts=4 noet: diff --git a/src/github.com/MichaelTJones/walk b/src/github.com/MichaelTJones/walk new file mode 160000 index 0000000..4748e29 --- /dev/null +++ b/src/github.com/MichaelTJones/walk @@ -0,0 +1 @@ +Subproject commit 4748e29d5718c2df4028a6543edf86fd8cc0f881 diff --git a/src/github.com/nsf/gocode b/src/github.com/nsf/gocode new file mode 160000 index 0000000..9d1e037 --- /dev/null +++ b/src/github.com/nsf/gocode @@ -0,0 +1 @@ +Subproject commit 9d1e0378d35b0527c9aef0d17c0913fc38d88b81 diff --git a/src/github.com/sqs/goreturns b/src/github.com/sqs/goreturns new file mode 160000 index 0000000..83e0287 --- /dev/null +++ b/src/github.com/sqs/goreturns @@ -0,0 +1 @@ +Subproject commit 83e02874ec120f73d5f7dd382d62449dc8abe9c6 diff --git a/src/github.com/uudashr/gopkgs b/src/github.com/uudashr/gopkgs new file mode 160000 index 0000000..1c62af7 --- /dev/null +++ b/src/github.com/uudashr/gopkgs @@ -0,0 +1 @@ +Subproject commit 1c62af71702179cbb9b6fb1b9acb7ed30bc32759 diff --git a/src/golang.org/x/tools b/src/golang.org/x/tools new file mode 160000 index 0000000..48418e5 --- /dev/null +++ b/src/golang.org/x/tools @@ -0,0 +1 @@ +Subproject commit 48418e5732e1b1e2a10207c8007a5f959e422f20