1package buildkit
2
3import (
4	"io"
5	"net/http"
6	"strings"
7	"sync"
8
9	"github.com/moby/buildkit/identity"
10	"github.com/pkg/errors"
11)
12
13const urlPrefix = "build-context-"
14
15type reqBodyHandler struct {
16	mu sync.Mutex
17	rt http.RoundTripper
18
19	requests map[string]io.ReadCloser
20}
21
22func newReqBodyHandler(rt http.RoundTripper) *reqBodyHandler {
23	return &reqBodyHandler{
24		rt:       rt,
25		requests: map[string]io.ReadCloser{},
26	}
27}
28
29func (h *reqBodyHandler) newRequest(rc io.ReadCloser) (string, func()) {
30	id := identity.NewID()
31	h.mu.Lock()
32	h.requests[id] = rc
33	h.mu.Unlock()
34	return "http://" + urlPrefix + id, func() {
35		h.mu.Lock()
36		delete(h.requests, id)
37		h.mu.Unlock()
38		rc.Close()
39	}
40}
41
42func (h *reqBodyHandler) RoundTrip(req *http.Request) (*http.Response, error) {
43	host := req.URL.Host
44	if strings.HasPrefix(host, urlPrefix) {
45		if req.Method != http.MethodGet {
46			return nil, errors.Errorf("invalid request")
47		}
48		id := strings.TrimPrefix(host, urlPrefix)
49		h.mu.Lock()
50		rc, ok := h.requests[id]
51		delete(h.requests, id)
52		h.mu.Unlock()
53
54		if !ok {
55			return nil, errors.Errorf("context not found")
56		}
57
58		resp := &http.Response{
59			Status:        "200 OK",
60			StatusCode:    http.StatusOK,
61			Body:          rc,
62			ContentLength: -1,
63		}
64
65		return resp, nil
66	}
67	return h.rt.RoundTrip(req)
68}
69