a73x

internal/server/mcphttp/inproc.go

Ref:   Size: 1.6 KiB   History

package mcphttp

import (
	"bytes"
	"io"
	"net/http"
)

// inproc dispatches a client request into the server's own handler. The caller's
// PAT rides the Authorization header exactly as a remote client's would, so the
// request re-authenticates through the same middleware and lands on the same
// Principal — there is no second authorization path to keep in step with the
// first, and no socket in between.
type inproc struct{ h http.Handler }

func (t inproc) RoundTrip(r *http.Request) (*http.Response, error) {
	rec := &recorder{header: http.Header{}, status: http.StatusOK}
	t.h.ServeHTTP(rec, r)
	resp := &http.Response{
		StatusCode:    rec.status,
		Status:        http.StatusText(rec.status),
		Header:        rec.header,
		Body:          io.NopCloser(bytes.NewReader(rec.body.Bytes())),
		ContentLength: int64(rec.body.Len()),
		Request:       r,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
	}
	return resp, nil
}

// recorder is the minimal http.ResponseWriter the in-process round trip needs.
// It is written out by hand rather than importing net/http/httptest, which is a
// testing package and has no business in a serving path.
type recorder struct {
	header      http.Header
	body        bytes.Buffer
	status      int
	wroteHeader bool
}

func (r *recorder) Header() http.Header { return r.header }

func (r *recorder) Write(p []byte) (int, error) {
	if !r.wroteHeader {
		r.WriteHeader(http.StatusOK)
	}
	return r.body.Write(p)
}

func (r *recorder) WriteHeader(status int) {
	if r.wroteHeader {
		return
	}
	r.wroteHeader = true
	r.status = status
}