2016-06-25 17:51:24 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type DispatchFunction func(*User, []string, io.ReadCloser) (interface{}, error)
|
|
|
|
|
2018-09-18 20:16:58 +00:00
|
|
|
var apiRoutes = map[string]*(map[string]struct {
|
|
|
|
AuthFunction
|
|
|
|
DispatchFunction
|
|
|
|
}){
|
2016-06-26 09:23:29 +00:00
|
|
|
"images": &ApiImagesRouting,
|
2016-06-26 11:16:50 +00:00
|
|
|
"next": &ApiNextImagesRouting,
|
2016-06-25 17:51:24 +00:00
|
|
|
"version": &ApiVersionRouting,
|
|
|
|
}
|
|
|
|
|
|
|
|
type apiHandler struct {
|
2018-09-18 20:16:58 +00:00
|
|
|
Authenticate func(*http.Request) *User
|
2016-06-25 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
2018-09-18 20:16:58 +00:00
|
|
|
func ApiHandler(Authenticate func(*http.Request) *User) apiHandler {
|
2016-06-25 17:51:24 +00:00
|
|
|
return apiHandler{Authenticate}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
user := a.Authenticate(r)
|
|
|
|
|
|
|
|
log.Printf("Handling %s API request from %s: %s %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, user, r.UserAgent())
|
|
|
|
|
|
|
|
// Extract URL arguments
|
|
|
|
var sURL = strings.Split(r.URL.Path[1:], "/")
|
|
|
|
if sURL[len(sURL)-1] == "" && len(sURL) > 0 {
|
|
|
|
// Remove trailing /
|
|
|
|
sURL = sURL[:len(sURL)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
var ret interface{}
|
|
|
|
var err error = nil
|
|
|
|
|
|
|
|
// Refuse too large requests
|
|
|
|
if r.ContentLength < 0 || r.ContentLength > 10485760 || ((r.Method == "DELETE" || r.Method == "GET" || r.Method == "HEAD") && r.ContentLength > 0) {
|
|
|
|
http.Error(w, "{errmsg:\"Request too large or request size unknown\"}", http.StatusRequestEntityTooLarge)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Route request
|
|
|
|
if len(sURL) == 0 {
|
|
|
|
err = errors.New(fmt.Sprintf("No action provided"))
|
|
|
|
} else if h, ok := apiRoutes[sURL[0]]; ok {
|
|
|
|
if f, ok := (*h)[r.Method]; ok {
|
|
|
|
if f.AuthFunction(user, sURL[1:]) {
|
|
|
|
ret, err = f.DispatchFunction(user, sURL[1:], r.Body)
|
|
|
|
} else {
|
2018-09-18 17:46:15 +00:00
|
|
|
w.Header().Set("WWW-Authenticate", "Basic realm=\"YouP0m\"")
|
2016-06-25 17:51:24 +00:00
|
|
|
http.Error(w, "{errmsg:\"You are not allowed to do this request.\"}", http.StatusUnauthorized)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[0]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format response
|
|
|
|
resStatus := http.StatusOK
|
|
|
|
if err != nil {
|
|
|
|
ret = map[string]string{"errmsg": err.Error()}
|
|
|
|
resStatus = http.StatusBadRequest
|
|
|
|
}
|
|
|
|
|
|
|
|
if ret == nil {
|
|
|
|
ret = map[string]string{"errmsg": "Page not found"}
|
|
|
|
resStatus = http.StatusNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
if j, err := json.Marshal(ret); err != nil {
|
2017-10-26 12:17:01 +00:00
|
|
|
http.Error(w, fmt.Sprintf("{errmsg:%q}", err), http.StatusInternalServerError)
|
2016-06-25 17:51:24 +00:00
|
|
|
} else {
|
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
w.Write(j)
|
|
|
|
}
|
|
|
|
}
|