edge/pkg/module/fetch/http.go

128 lines
2.8 KiB
Go
Raw Normal View History

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
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 {
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",
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)
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",
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",
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))
}
}