Raw
 1package oidcrp
 2
 3import (
 4	"bytes"
 5	"fmt"
 6	"io"
 7	"net/http"
 8	"net/url"
 9	"strconv"
10)
11
12type inProcess struct {
13	host string
14	h    http.Handler
15}
16
17func InProcess(host string, h http.Handler) http.RoundTripper {
18	return inProcess{host: host, h: h}
19}
20
21func (t inProcess) RoundTrip(req *http.Request) (*http.Response, error) {
22	if req.URL.Host != t.host {
23		if req.Body != nil {
24			req.Body.Close()
25		}
26		return nil, fmt.Errorf("oidcrp: %s is not served in process", req.URL.Host)
27	}
28	body := req.Body
29	if body == nil {
30		body = http.NoBody
31	}
32	defer body.Close()
33	sreq := req.Clone(req.Context())
34	sreq.Host = req.URL.Host
35	sreq.URL = &url.URL{Path: req.URL.Path, RawPath: req.URL.RawPath, RawQuery: req.URL.RawQuery}
36	sreq.RequestURI = req.URL.RequestURI()
37	sreq.Proto, sreq.ProtoMajor, sreq.ProtoMinor = "HTTP/1.1", 1, 1
38	sreq.Body = body
39	rec := &recorder{header: http.Header{}}
40	t.h.ServeHTTP(rec, sreq)
41	return rec.response(req), nil
42}
43
44type recorder struct {
45	header  http.Header
46	written http.Header
47	status  int
48	body    bytes.Buffer
49}
50
51func (r *recorder) Header() http.Header { return r.header }
52
53func (r *recorder) WriteHeader(status int) {
54	if r.status != 0 {
55		return
56	}
57	r.status = status
58	r.written = r.header.Clone()
59}
60
61func (r *recorder) Write(b []byte) (int, error) {
62	if r.status == 0 {
63		r.WriteHeader(http.StatusOK)
64	}
65	return r.body.Write(b)
66}
67
68func (r *recorder) response(req *http.Request) *http.Response {
69	if r.status == 0 {
70		r.WriteHeader(http.StatusOK)
71	}
72	h := r.written
73	h.Del("Content-Length")
74	h.Set("Content-Length", strconv.Itoa(r.body.Len()))
75	return &http.Response{
76		Status:        strconv.Itoa(r.status) + " " + http.StatusText(r.status),
77		StatusCode:    r.status,
78		Proto:         "HTTP/1.1",
79		ProtoMajor:    1,
80		ProtoMinor:    1,
81		Header:        h,
82		Body:          io.NopCloser(bytes.NewReader(r.body.Bytes())),
83		ContentLength: int64(r.body.Len()),
84		Request:       req,
85	}
86}