github.com/webdestroya/awsmocker@v0.2.6/https.go (about)

     1  package awsmocker
     2  
     3  import (
     4  	"bufio"
     5  	"crypto/tls"
     6  	"errors"
     7  	"io"
     8  	"net"
     9  	"net/http"
    10  	"net/url"
    11  	"regexp"
    12  )
    13  
    14  const (
    15  	imdsHost4 = "169.254.169.254"
    16  	imdsHost6 = "fd00:ec2::254"
    17  )
    18  
    19  var (
    20  	httpsRegexp = regexp.MustCompile(`^https:\/\/`)
    21  
    22  	globalTlsConfig = &tls.Config{
    23  		InsecureSkipVerify: true,
    24  		GetCertificate: func(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
    25  			return globalCertStore.Fetch(chi.ServerName), nil
    26  		},
    27  	}
    28  )
    29  
    30  func (m *mocker) handleHttps(w http.ResponseWriter, r *http.Request) {
    31  	hij, ok := w.(http.Hijacker)
    32  	if !ok {
    33  		panic("httpserver does not support hijacking")
    34  	}
    35  
    36  	proxyClient, _, e := hij.Hijack()
    37  	if e != nil {
    38  		panic("Cannot hijack connection " + e.Error())
    39  	}
    40  
    41  	// respond with success to acknowledge the proxy request
    42  	_, _ = proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
    43  
    44  	// handle the request
    45  	go m.handleAwsRequestHttps(proxyClient, r)
    46  
    47  }
    48  
    49  func (m *mocker) handleAwsRequestHttps(proxyClient net.Conn, r *http.Request) {
    50  	rawClientTls := tls.Server(proxyClient, globalTlsConfig)
    51  	if err := rawClientTls.Handshake(); err != nil {
    52  		m.Warnf("Cannot handshake client %v %v", r.Host, err)
    53  		return
    54  	}
    55  	defer rawClientTls.Close()
    56  
    57  	clientTlsReader := bufio.NewReader(rawClientTls)
    58  	for !isEof(clientTlsReader) {
    59  		req, err := http.ReadRequest(clientTlsReader)
    60  		if err != nil && !errors.Is(err, io.EOF) {
    61  			return
    62  		}
    63  		if err != nil {
    64  			m.Warnf("Cannot read TLS request from mitm'd client %v %v", r.Host, err)
    65  			return
    66  		}
    67  		req.RemoteAddr = r.RemoteAddr
    68  
    69  		if !httpsRegexp.MatchString(req.URL.String()) {
    70  			req.URL, _ = url.Parse("https://" + r.Host + req.URL.String())
    71  		}
    72  
    73  		_, resp := m.handleRequest(req)
    74  		origBody := resp.Body
    75  		defer origBody.Close()
    76  
    77  		// defer resp.Body.Close()
    78  
    79  		resp.Header.Set("Connection", "close")
    80  
    81  		if err := resp.Write(rawClientTls); err != nil {
    82  			m.Warnf("Failed to write response: %s", err)
    83  		}
    84  	}
    85  }