18874: Merge branch 'main' from arvados-workbench2.git
[arvados.git] / sdk / go / arvadostest / proxy.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package arvadostest
6
7 import (
8         "crypto/tls"
9         "net"
10         "net/http"
11         "net/http/httptest"
12         "net/http/httputil"
13         "net/url"
14         "time"
15
16         "git.arvados.org/arvados.git/sdk/go/arvados"
17         "gopkg.in/check.v1"
18 )
19
20 type Proxy struct {
21         *httptest.Server
22
23         // URL where the proxy is listening. Same as Server.URL, but
24         // with parsing already done for you.
25         URL *url.URL
26
27         // A dump of each request that has been proxied.
28         RequestDumps [][]byte
29
30         // If non-nil, func will be called on each incoming request
31         // before proxying it.
32         Director func(*http.Request)
33 }
34
35 // NewProxy returns a new Proxy that saves a dump of each reqeust
36 // before forwarding to the indicated service.
37 func NewProxy(c *check.C, svc arvados.Service) *Proxy {
38         var target url.URL
39         c.Assert(svc.InternalURLs, check.HasLen, 1)
40         for u := range svc.InternalURLs {
41                 target = url.URL(u)
42                 break
43         }
44         rp := httputil.NewSingleHostReverseProxy(&target)
45         rp.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
46                 dump, _ := httputil.DumpRequest(r, false)
47                 c.Logf("arvadostest.Proxy ErrorHandler(%s): %s\n%s", r.URL, err, dump)
48                 http.Error(w, err.Error(), http.StatusBadGateway)
49         }
50         rp.Transport = &http.Transport{
51                 DialContext: (&net.Dialer{
52                         Timeout:   30 * time.Second,
53                         KeepAlive: 30 * time.Second,
54                         DualStack: true,
55                 }).DialContext,
56                 MaxIdleConns:          100,
57                 IdleConnTimeout:       90 * time.Second,
58                 TLSHandshakeTimeout:   10 * time.Second,
59                 ExpectContinueTimeout: 1 * time.Second,
60                 TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
61         }
62         srv := httptest.NewServer(rp)
63         u, err := url.Parse(srv.URL)
64         c.Assert(err, check.IsNil)
65         proxy := &Proxy{
66                 Server: srv,
67                 URL:    u,
68         }
69         rp.Director = func(r *http.Request) {
70                 if proxy.Director != nil {
71                         proxy.Director(r)
72                 }
73                 dump, _ := httputil.DumpRequest(r, true)
74                 proxy.RequestDumps = append(proxy.RequestDumps, dump)
75                 r.URL.Scheme = target.Scheme
76                 r.URL.Host = target.Host
77         }
78         return proxy
79 }