2023-11-28 16:35:49 +01:00
|
|
|
package fetch
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp "forge.cadoles.com/arcad/edge/pkg/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
2023-04-02 17:59:33 +02:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
|
|
)
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
func Mount() func(r chi.Router) {
|
|
|
|
return func(r chi.Router) {
|
|
|
|
r.Get("/api/v1/fetch", handleAppFetch)
|
|
|
|
}
|
|
|
|
}
|
2023-04-02 17:59:33 +02:00
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
func handleAppFetch(w http.ResponseWriter, r *http.Request) {
|
2023-04-02 17:59:33 +02:00
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
rawURL := r.URL.Query().Get("url")
|
|
|
|
|
|
|
|
url, err := url.Parse(rawURL)
|
|
|
|
if err != nil {
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp.JSONError(w, http.StatusBadRequest, edgehttp.ErrCodeBadRequest)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
requestMsg := NewFetchRequestEnvelope(ctx, r.RemoteAddr, url)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
2023-11-30 19:09:51 +01:00
|
|
|
bus, ok := edgehttp.ContextBus(ctx)
|
|
|
|
if !ok {
|
|
|
|
logger.Error(ctx, "could find bus on context")
|
|
|
|
edgehttp.JSONError(w, http.StatusInternalServerError, edgehttp.ErrCodeInternalError)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2023-11-28 16:35:49 +01:00
|
|
|
|
|
|
|
reply, err := bus.Request(ctx, requestMsg)
|
2023-04-02 17:59:33 +02:00
|
|
|
if err != nil {
|
2023-10-19 21:47:09 +02:00
|
|
|
logger.Error(ctx, "could not retrieve fetch request reply", logger.CapturedE(errors.WithStack(err)))
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp.JSONError(w, http.StatusInternalServerError, edgehttp.ErrCodeInternalError)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.Debug(ctx, "fetch reply", logger.F("reply", reply))
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
responseMsg, ok := reply.Message().(*FetchResponse)
|
2023-04-02 17:59:33 +02:00
|
|
|
if !ok {
|
|
|
|
logger.Error(
|
|
|
|
ctx, "unexpected fetch response message",
|
|
|
|
logger.F("message", reply),
|
|
|
|
)
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp.JSONError(w, http.StatusInternalServerError, edgehttp.ErrCodeInternalError)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !responseMsg.Allow {
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp.JSONError(w, http.StatusForbidden, edgehttp.ErrCodeForbidden)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
proxyReq, err := http.NewRequest(http.MethodGet, url.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
logger.Error(
|
|
|
|
ctx, "could not create proxy request",
|
2023-10-19 21:47:09 +02:00
|
|
|
logger.CapturedE(errors.WithStack(err)),
|
2023-04-02 17:59:33 +02:00
|
|
|
)
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp.JSONError(w, http.StatusInternalServerError, edgehttp.ErrCodeInternalError)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for header, values := range r.Header {
|
|
|
|
for _, value := range values {
|
|
|
|
proxyReq.Header.Add(header, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
proxyReq.Header.Add("X-Forwarded-From", r.RemoteAddr)
|
|
|
|
|
2023-11-30 19:09:51 +01:00
|
|
|
httpClient, ok := edgehttp.ContextHTTPClient(ctx)
|
|
|
|
if !ok {
|
|
|
|
logger.Error(ctx, "could find http client on context")
|
|
|
|
edgehttp.JSONError(w, http.StatusInternalServerError, edgehttp.ErrCodeInternalError)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2023-11-28 16:35:49 +01:00
|
|
|
|
|
|
|
res, err := httpClient.Do(proxyReq)
|
2023-04-02 17:59:33 +02:00
|
|
|
if err != nil {
|
|
|
|
logger.Error(
|
|
|
|
ctx, "could not execute proxy request",
|
2023-10-19 21:47:09 +02:00
|
|
|
logger.CapturedE(errors.WithStack(err)),
|
2023-04-02 17:59:33 +02:00
|
|
|
)
|
2023-11-28 16:35:49 +01:00
|
|
|
edgehttp.JSONError(w, http.StatusInternalServerError, edgehttp.ErrCodeInternalError)
|
2023-04-02 17:59:33 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err := res.Body.Close(); err != nil {
|
|
|
|
logger.Error(
|
|
|
|
ctx, "could not close response body",
|
2023-10-19 21:47:09 +02:00
|
|
|
logger.CapturedE(errors.WithStack(err)),
|
2023-04-02 17:59:33 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
for header, values := range res.Header {
|
|
|
|
for _, value := range values {
|
|
|
|
w.Header().Add(header, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(res.StatusCode)
|
|
|
|
|
|
|
|
if _, err := io.Copy(w, res.Body); err != nil {
|
|
|
|
panic(errors.WithStack(err))
|
|
|
|
}
|
|
|
|
}
|