cloneRequest makes a semi-deep clone of origReq. Most of this code is borrowed from the Go stdlib reverse proxy, but we make a shallow-ish clone the request (deep clone only the headers and URL) so we can avoid manipulating the original request when using it to proxy upstream. This prevents request
(origReq *http.Request)
| 1503 | // request when using it to proxy upstream. This prevents request |
| 1504 | // corruption and data races. |
| 1505 | func cloneRequest(origReq *http.Request) *http.Request { |
| 1506 | req := new(http.Request) |
| 1507 | *req = *origReq |
| 1508 | if origReq.URL != nil { |
| 1509 | newURL := new(url.URL) |
| 1510 | *newURL = *origReq.URL |
| 1511 | if origReq.URL.User != nil { |
| 1512 | newURL.User = new(url.Userinfo) |
| 1513 | *newURL.User = *origReq.URL.User |
| 1514 | } |
| 1515 | // sanitize the request URL; we expect it to not contain the |
| 1516 | // scheme and host since those should be determined by r.TLS |
| 1517 | // and r.Host respectively, but some clients may include it |
| 1518 | // in the request-line, which is technically valid in HTTP, |
| 1519 | // but breaks reverseproxy behaviour, overriding how the |
| 1520 | // dialer will behave. See #4237 for context. |
| 1521 | newURL.Scheme = "" |
| 1522 | newURL.Host = "" |
| 1523 | req.URL = newURL |
| 1524 | } |
| 1525 | if origReq.Header != nil { |
| 1526 | req.Header = origReq.Header.Clone() |
| 1527 | } |
| 1528 | if origReq.Trailer != nil { |
| 1529 | req.Trailer = origReq.Trailer.Clone() |
| 1530 | } |
| 1531 | return req |
| 1532 | } |
| 1533 | |
| 1534 | func copyHeader(dst, src http.Header) { |
| 1535 | for k, vv := range src { |