package main import ( "encoding/json" "errors" "fmt" "io" "log" "net/http" "strings" ) type DispatchFunction func([]string, []byte) (interface{}, error) var apiRoutes = map[string]*(map[string]DispatchFunction){ "version": &ApiVersionRouting, "themes": &ApiThemesRouting, "teams": &ApiTeamsRouting, } type apiRouting struct{} func ApiHandler() http.Handler { return apiRouting{} } func (a apiRouting) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) // Extract URL arguments var sURL = strings.Split(r.URL.Path, "/")[1:] if len(sURL) > 1 && sURL[len(sURL)-1] == "" { // Remove trailing / sURL = sURL[:len(sURL)-1] } w.Header().Set("Content-Type", "application/json") var ret interface{} var err error = nil // Read the body if r.ContentLength < 0 || r.ContentLength > 6553600 { http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}", err), http.StatusRequestEntityTooLarge) return } var body []byte if r.ContentLength > 0 { tmp := make([]byte, 1024) for { n, err := r.Body.Read(tmp) for j := 0; j < n; j++ { body = append(body, tmp[j]) } if err != nil || n <= 0 { break } } } // Route request if len(sURL) > 0 { if h, ok := apiRoutes[sURL[0]]; ok { if f, ok := (*h)[r.Method]; ok { ret, err = f(sURL[1:], body) } else { err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[0])) } } } else { err = errors.New("No action provided.") } // Format response resStatus := http.StatusOK if err != nil { ret = map[string]string{"errmsg": err.Error()} resStatus = http.StatusBadRequest log.Println(r.RemoteAddr, resStatus, err.Error()) } if ret == nil { ret = map[string]string{"errmsg": "Page not found"} resStatus = http.StatusNotFound } if str, found := ret.(string); found { w.WriteHeader(resStatus) io.WriteString(w, str) } else if j, err := json.Marshal(ret); err != nil { http.Error(w, fmt.Sprintf("{\"errmsg\":\"%q\"}", err), http.StatusInternalServerError) } else { w.WriteHeader(resStatus) w.Write(j) } }