mirror of
https://github.com/cnrancher/kube-explorer.git
synced 2025-04-28 19:24:43 +00:00
The index page will be handled correctly if the `XFF` and `X-API-URL-PREFIX` are set properly.
117 lines
2.8 KiB
Go
117 lines
2.8 KiB
Go
package ui
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/rancher/apiserver/pkg/urlbuilder"
|
|
"k8s.io/apimachinery/pkg/util/proxy"
|
|
)
|
|
|
|
type RoundTripFunc func(*http.Request) (*http.Response, error)
|
|
|
|
func (r RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return r(req)
|
|
}
|
|
|
|
func proxyMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
scheme := urlbuilder.GetScheme(r)
|
|
host := urlbuilder.GetHost(r, scheme)
|
|
pathPrepend := r.Header.Get(urlbuilder.PrefixHeader)
|
|
|
|
if scheme == r.URL.Scheme && host == r.URL.Host && pathPrepend == "" {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
proxyRoundtrip := proxy.Transport{
|
|
Scheme: scheme,
|
|
Host: host,
|
|
PathPrepend: pathPrepend,
|
|
RoundTripper: RoundTripFunc(func(r *http.Request) (*http.Response, error) {
|
|
rw := &dummyResponseWriter{
|
|
next: w,
|
|
header: make(http.Header),
|
|
}
|
|
next.ServeHTTP(rw, r)
|
|
return rw.getResponse(r), nil
|
|
}),
|
|
}
|
|
//proxyRoundtripper will write the response in RoundTrip func
|
|
resp, _ := proxyRoundtrip.RoundTrip(r)
|
|
responseToWriter(resp, w)
|
|
})
|
|
|
|
}
|
|
|
|
var _ http.ResponseWriter = &dummyResponseWriter{}
|
|
var _ http.Hijacker = &dummyResponseWriter{}
|
|
|
|
type dummyResponseWriter struct {
|
|
next http.ResponseWriter
|
|
|
|
header http.Header
|
|
body bytes.Buffer
|
|
statusCode int
|
|
}
|
|
|
|
// Hijack implements http.Hijacker.
|
|
func (drw *dummyResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
if h, ok := drw.next.(http.Hijacker); ok {
|
|
return h.Hijack()
|
|
}
|
|
return nil, nil, fmt.Errorf("")
|
|
}
|
|
|
|
// Header implements the http.ResponseWriter interface.
|
|
func (drw *dummyResponseWriter) Header() http.Header {
|
|
return drw.header
|
|
}
|
|
|
|
// Write implements the http.ResponseWriter interface.
|
|
func (drw *dummyResponseWriter) Write(b []byte) (int, error) {
|
|
return drw.body.Write(b)
|
|
}
|
|
|
|
// WriteHeader implements the http.ResponseWriter interface.
|
|
func (drw *dummyResponseWriter) WriteHeader(statusCode int) {
|
|
drw.statusCode = statusCode
|
|
}
|
|
|
|
// GetStatusCode returns the status code written to the response.
|
|
func (drw *dummyResponseWriter) GetStatusCode() int {
|
|
if drw.statusCode == 0 {
|
|
return 200
|
|
}
|
|
return drw.statusCode
|
|
}
|
|
|
|
func (drw *dummyResponseWriter) getResponse(req *http.Request) *http.Response {
|
|
return &http.Response{
|
|
Status: strconv.Itoa(drw.GetStatusCode()),
|
|
StatusCode: drw.GetStatusCode(),
|
|
Proto: "HTTP/1.1",
|
|
ProtoMajor: 1,
|
|
ProtoMinor: 1,
|
|
Request: req,
|
|
Header: drw.header,
|
|
Body: io.NopCloser(&drw.body),
|
|
}
|
|
}
|
|
|
|
func responseToWriter(resp *http.Response, writer http.ResponseWriter) {
|
|
for k, v := range resp.Header {
|
|
writer.Header()[k] = v
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
writer.WriteHeader(resp.StatusCode)
|
|
}
|
|
_, _ = io.Copy(writer, resp.Body)
|
|
}
|