// APIHandler is responsible for receiving API commands over HTTP. func (app *Application) APIHandler(w http.ResponseWriter, r *http.Request) { pk := ProjectKey(r.URL.Path[len("/api/"):]) contentType := r.Header.Get("Content-Type") var sign string var data []byte var err error if strings.HasPrefix(strings.ToLower(contentType), "application/json") { // json request sign = r.Header.Get("X-API-Sign") defer r.Body.Close() data, err = ioutil.ReadAll(r.Body) if err != nil { logger.ERROR.Println(err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } else { // application/x-www-form-urlencoded request sign = r.FormValue("sign") data = []byte(r.FormValue("data")) } if sign == "" { logger.ERROR.Println("no sign found in API request") http.Error(w, "Bad Request", http.StatusBadRequest) return } if len(data) == 0 { logger.ERROR.Println("no data found in API request") http.Error(w, "Bad Request", http.StatusBadRequest) return } project, exists := app.projectByKey(pk) if !exists { logger.ERROR.Println("no project found with key", pk) http.Error(w, "Project not found", http.StatusNotFound) return } secret := project.Secret isValid := auth.CheckApiSign(secret, string(pk), data, sign) if !isValid { logger.ERROR.Println("invalid sign") http.Error(w, "Unauthorized", http.StatusUnauthorized) return } commands, err := cmdFromAPIMsg(data) if err != nil { logger.ERROR.Println(err) http.Error(w, "Bad Request", http.StatusBadRequest) return } var mr multiResponse for _, command := range commands { resp, err := app.apiCmd(project, command) if err != nil { logger.ERROR.Println(err) http.Error(w, "Bad Request", http.StatusBadRequest) return } mr = append(mr, resp) } jsonResp, err := json.Marshal(mr) if err != nil { logger.ERROR.Println(err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(jsonResp) }
// APIHandler is responsible for receiving API commands over HTTP. func (app *Application) APIHandler(w http.ResponseWriter, r *http.Request) { app.metrics.numAPIRequests.Inc(1) defer app.metrics.timeAPI.UpdateSince(time.Now()) contentType := r.Header.Get("Content-Type") var sign string var data []byte var err error if strings.HasPrefix(strings.ToLower(contentType), "application/json") { // json request sign = r.Header.Get("X-API-Sign") defer r.Body.Close() data, err = ioutil.ReadAll(r.Body) if err != nil { logger.ERROR.Println(err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } else { // application/x-www-form-urlencoded request sign = r.FormValue("sign") data = []byte(r.FormValue("data")) } app.RLock() secret := app.config.Secret insecure := app.config.InsecureAPI app.RUnlock() if sign == "" && !insecure { logger.ERROR.Println("no sign found in API request") http.Error(w, "Bad Request", http.StatusBadRequest) return } if len(data) == 0 { logger.ERROR.Println("no data found in API request") http.Error(w, "Bad Request", http.StatusBadRequest) return } if !insecure { if secret == "" { logger.ERROR.Println("no secret set in config") http.Error(w, "Bad Request", http.StatusBadRequest) return } isValid := auth.CheckApiSign(secret, data, sign) if !isValid { logger.ERROR.Println("invalid sign") http.Error(w, "Unauthorized", http.StatusUnauthorized) return } } commands, err := cmdFromAPIMsg(data) if err != nil { logger.ERROR.Println(err) http.Error(w, "Bad Request", http.StatusBadRequest) return } var mr multiResponse for _, command := range commands { resp, err := app.apiCmd(command) if err != nil { logger.ERROR.Println(err) http.Error(w, "Bad Request", http.StatusBadRequest) return } mr = append(mr, resp) } jsonResp, err := json.Marshal(mr) if err != nil { logger.ERROR.Println(err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(jsonResp) }