93 lines
2.4 KiB
Go
93 lines
2.4 KiB
Go
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())
|
|
}
|