gowebbuild/npmproxy/externalProxy.go

93 lines
2.4 KiB
Go
Raw Permalink Normal View History

2024-11-06 10:43:05 +01:00
package npmproxy
import (
"bytes"
"context"
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"time"
"github.com/kataras/golog"
)
func (p *Proxy) externalHTTPServer(ctx context.Context) {
mux := http.NewServeMux()
srv := &http.Server{
Addr: p.externalProxyHost,
Handler: mux,
}
go func() {
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
fmt.Printf("Failed to shutdown proxy server: %v\n", err)
}
}()
mux.HandleFunc("/", p.incomingNpmRequestHandler)
if err := srv.ListenAndServe(); err != nil {
if err != http.ErrServerClosed {
panic(err)
}
}
}
// Receives incoming requests from the npm cli and decides based on override rules what server it should forwarded to.
func (p *Proxy) incomingNpmRequestHandler(res http.ResponseWriter, req *http.Request) {
golog.Infof("Incoming NPM request for %s", req.URL.Path)
pkgPath := strings.TrimLeft(req.URL.Path, "/")
// If no matching override is found, we forward the request to the default registry.
_, ok := p.matchingOverride(pkgPath)
if !ok {
serveReverseProxy(p.DefaultRegistry, res, req)
return
}
// Process the override by forwarding the request to the internal proxy.
serveReverseProxy(p.internalProxyUrl, res, req)
// golog.Infof("Received request for url: %v", proxyUrl)
}
type ResponseWriterWrapper struct {
http.ResponseWriter
Body *bytes.Buffer
}
func (rw *ResponseWriterWrapper) Write(b []byte) (int, error) {
rw.Body.Write(b) // Capture the response body
return rw.ResponseWriter.Write(b) // Send the response to the original writer
}
func serveReverseProxy(target string, res http.ResponseWriter, req *http.Request) {
// parse the OriginalUrl
OriginalUrl, _ := url.Parse(target)
// create the reverse proxy
proxy := httputil.NewSingleHostReverseProxy(OriginalUrl)
// Update the headers to allow for SSL redirection
req.URL.Host = OriginalUrl.Host
req.URL.Scheme = OriginalUrl.Scheme
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
req.Host = OriginalUrl.Host
wrappedRes := &ResponseWriterWrapper{ResponseWriter: res, Body: new(bytes.Buffer)}
// Note that ServeHttp is non blocking and uses a go routine under the hood
proxy.ServeHTTP(wrappedRes, req)
// Print the captured response body
fmt.Println("Response body:", wrappedRes.Body.String())
}