2016-12-18 05:21:29 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/portainer/portainer"
|
|
|
|
|
|
|
|
"encoding/json"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Handler is a collection of all the service handlers.
|
|
|
|
type Handler struct {
|
|
|
|
AuthHandler *AuthHandler
|
|
|
|
UserHandler *UserHandler
|
2016-12-25 20:34:02 +00:00
|
|
|
EndpointHandler *EndpointHandler
|
2016-12-18 05:21:29 +00:00
|
|
|
SettingsHandler *SettingsHandler
|
|
|
|
TemplatesHandler *TemplatesHandler
|
|
|
|
DockerHandler *DockerHandler
|
|
|
|
WebSocketHandler *WebSocketHandler
|
2016-12-25 20:34:02 +00:00
|
|
|
UploadHandler *UploadHandler
|
2016-12-30 23:20:38 +00:00
|
|
|
FileHandler *FileHandler
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
// ErrInvalidJSON defines an error raised the app is unable to parse request data
|
|
|
|
ErrInvalidJSON = portainer.Error("Invalid JSON")
|
|
|
|
// ErrInvalidRequestFormat defines an error raised when the format of the data sent in a request is not valid
|
|
|
|
ErrInvalidRequestFormat = portainer.Error("Invalid request data format")
|
2017-03-12 16:24:15 +00:00
|
|
|
// ErrInvalidQueryFormat defines an error raised when the data sent in the query or the URL is invalid
|
|
|
|
ErrInvalidQueryFormat = portainer.Error("Invalid query format")
|
|
|
|
// ErrEmptyResponseBody defines an error raised when portainer excepts to parse the body of a HTTP response and there is nothing to parse
|
|
|
|
ErrEmptyResponseBody = portainer.Error("Empty response body")
|
2016-12-18 05:21:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ServeHTTP delegates a request to the appropriate subhandler.
|
|
|
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if strings.HasPrefix(r.URL.Path, "/api/auth") {
|
|
|
|
http.StripPrefix("/api", h.AuthHandler).ServeHTTP(w, r)
|
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/users") {
|
|
|
|
http.StripPrefix("/api", h.UserHandler).ServeHTTP(w, r)
|
2016-12-25 20:34:02 +00:00
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/endpoints") {
|
|
|
|
http.StripPrefix("/api", h.EndpointHandler).ServeHTTP(w, r)
|
2016-12-18 05:21:29 +00:00
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/settings") {
|
|
|
|
http.StripPrefix("/api", h.SettingsHandler).ServeHTTP(w, r)
|
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/templates") {
|
|
|
|
http.StripPrefix("/api", h.TemplatesHandler).ServeHTTP(w, r)
|
2016-12-25 20:34:02 +00:00
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/upload") {
|
|
|
|
http.StripPrefix("/api", h.UploadHandler).ServeHTTP(w, r)
|
2016-12-18 05:21:29 +00:00
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/websocket") {
|
|
|
|
http.StripPrefix("/api", h.WebSocketHandler).ServeHTTP(w, r)
|
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/api/docker") {
|
|
|
|
http.StripPrefix("/api/docker", h.DockerHandler).ServeHTTP(w, r)
|
|
|
|
} else if strings.HasPrefix(r.URL.Path, "/") {
|
|
|
|
h.FileHandler.ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error writes an API error message to the response and logger.
|
|
|
|
func Error(w http.ResponseWriter, err error, code int, logger *log.Logger) {
|
|
|
|
// Log error.
|
2017-01-24 03:35:48 +00:00
|
|
|
if logger != nil {
|
|
|
|
logger.Printf("http error: %s (code=%d)", err, code)
|
|
|
|
}
|
2016-12-18 05:21:29 +00:00
|
|
|
|
|
|
|
// Write generic error response.
|
|
|
|
w.WriteHeader(code)
|
|
|
|
json.NewEncoder(w).Encode(&errorResponse{Err: err.Error()})
|
|
|
|
}
|
|
|
|
|
|
|
|
// errorResponse is a generic response for sending a error.
|
|
|
|
type errorResponse struct {
|
|
|
|
Err string `json:"err,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleNotAllowed writes an API error message to the response and sets the Allow header.
|
|
|
|
func handleNotAllowed(w http.ResponseWriter, allowedMethods []string) {
|
|
|
|
w.Header().Set("Allow", strings.Join(allowedMethods, ", "))
|
|
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
|
|
json.NewEncoder(w).Encode(&errorResponse{Err: http.StatusText(http.StatusMethodNotAllowed)})
|
|
|
|
}
|
|
|
|
|
|
|
|
// encodeJSON encodes v to w in JSON format. Error() is called if encoding fails.
|
|
|
|
func encodeJSON(w http.ResponseWriter, v interface{}, logger *log.Logger) {
|
|
|
|
if err := json.NewEncoder(w).Encode(v); err != nil {
|
|
|
|
Error(w, err, http.StatusInternalServerError, logger)
|
|
|
|
}
|
|
|
|
}
|