package oidcrp import ( "bytes" "fmt" "io" "net/http" "net/url" "strconv" ) type inProcess struct { host string h http.Handler } func InProcess(host string, h http.Handler) http.RoundTripper { return inProcess{host: host, h: h} } func (t inProcess) RoundTrip(req *http.Request) (*http.Response, error) { if req.URL.Host != t.host { if req.Body != nil { req.Body.Close() } return nil, fmt.Errorf("oidcrp: %s is not served in process", req.URL.Host) } body := req.Body if body == nil { body = http.NoBody } defer body.Close() sreq := req.Clone(req.Context()) sreq.Host = req.URL.Host sreq.URL = &url.URL{Path: req.URL.Path, RawPath: req.URL.RawPath, RawQuery: req.URL.RawQuery} sreq.RequestURI = req.URL.RequestURI() sreq.Proto, sreq.ProtoMajor, sreq.ProtoMinor = "HTTP/1.1", 1, 1 sreq.Body = body rec := &recorder{header: http.Header{}} t.h.ServeHTTP(rec, sreq) return rec.response(req), nil } type recorder struct { header http.Header written http.Header status int body bytes.Buffer } func (r *recorder) Header() http.Header { return r.header } func (r *recorder) WriteHeader(status int) { if r.status != 0 { return } r.status = status r.written = r.header.Clone() } func (r *recorder) Write(b []byte) (int, error) { if r.status == 0 { r.WriteHeader(http.StatusOK) } return r.body.Write(b) } func (r *recorder) response(req *http.Request) *http.Response { if r.status == 0 { r.WriteHeader(http.StatusOK) } h := r.written h.Del("Content-Length") h.Set("Content-Length", strconv.Itoa(r.body.Len())) return &http.Response{ Status: strconv.Itoa(r.status) + " " + http.StatusText(r.status), StatusCode: r.status, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, Header: h, Body: io.NopCloser(bytes.NewReader(r.body.Bytes())), ContentLength: int64(r.body.Len()), Request: req, } }