Spaces:
Running
Running
// _ _ | |
// __ _____ __ ___ ___ __ _| |_ ___ | |
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
// \ V V / __/ (_| |\ V /| | (_| | || __/ | |
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
// | |
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
// | |
// CONTACT: [email protected] | |
// | |
package extensions | |
import ( | |
"context" | |
"io" | |
"net/http" | |
"github.com/weaviate/weaviate/entities/models" | |
) | |
type RESTUserFacingHandlers struct { | |
proxy Proxy | |
} | |
func newRESTUserFacingHandlers(proxy Proxy) *RESTUserFacingHandlers { | |
return &RESTUserFacingHandlers{ | |
proxy: proxy, | |
} | |
} | |
func (h *RESTHandlers) UserFacingHandler() http.Handler { | |
return newRESTUserFacingHandlers(h.proxy).Handler() | |
} | |
func (h *RESTUserFacingHandlers) Handler() http.Handler { | |
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
switch r.Method { | |
case http.MethodPost: | |
h.post(w, r) | |
default: | |
w.WriteHeader(http.StatusMethodNotAllowed) | |
} | |
}) | |
} | |
func (h *RESTUserFacingHandlers) post(w http.ResponseWriter, r *http.Request) { | |
ct := r.Header.Get("content-type") | |
if ct != "application/json" { | |
w.WriteHeader(http.StatusUnsupportedMediaType) | |
return | |
} | |
defer r.Body.Close() | |
body, err := io.ReadAll(r.Body) | |
if err != nil { | |
h.writeError(w, err, http.StatusInternalServerError) | |
return | |
} | |
var ext models.C11yExtension | |
if err := (&ext).UnmarshalBinary(body); err != nil { | |
h.writeError(w, err, http.StatusUnprocessableEntity) | |
return | |
} | |
if err := h.proxy.AddExtension(r.Context(), &ext); err != nil { | |
h.writeError(w, err, http.StatusBadRequest) | |
return | |
} | |
resBody, err := ext.MarshalBinary() | |
if err != nil { | |
h.writeError(w, err, http.StatusInternalServerError) | |
return | |
} | |
w.Header().Add("content-type", "application/json") | |
w.WriteHeader(http.StatusOK) | |
w.Write(resBody) | |
} | |
// C11yProxy proxies the request through the separate container, only for it to | |
// come back here for the storage. This is legacy from the pre-module times. | |
// TODO: cleanup, there does not need to be a separation between user-facing | |
// and internal storage endpoint in the long-term | |
type Proxy interface { | |
AddExtension(ctx context.Context, extension *models.C11yExtension) error | |
} | |
func (h *RESTUserFacingHandlers) writeError(w http.ResponseWriter, err error, code int) { | |
res := &models.ErrorResponse{Error: []*models.ErrorResponseErrorItems0{{ | |
Message: err.Error(), | |
}}} | |
json, mErr := res.MarshalBinary() | |
if mErr != nil { | |
// fallback to text | |
w.Header().Add("content-type", "text/plain") | |
w.WriteHeader(code) | |
w.Write([]byte(err.Error())) | |
} | |
w.Header().Add("content-type", "application/json") | |
w.WriteHeader(code) | |
w.Write(json) | |
} | |