-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.go
More file actions
64 lines (55 loc) · 2.14 KB
/
Copy pathutils.go
File metadata and controls
64 lines (55 loc) · 2.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package dhttp
import (
"context"
"fmt"
"io"
"net/http"
"regexp"
"strings"
)
var portSuffixRegex = regexp.MustCompile(`:[0-9]{2,5}$`)
// RealIP tries to determine the actual client remote IP that initiated the connection.
// This method is aware of Google Cloud Load Balancer and if the `X-Forwarded-For` exists
// and has 2 or more addresses, it will assume it's coming from Google Cloud Load Balancer.
//
// When behind a Google Load Balancer, the only two values that we can
// be sure about are the `n - 2` and `n - 1` (so the last two values
// in the array). The very last value (`n - 1`) is the Google IP and the
// `n - 2` value is the actual remote IP that reached the load balancer.
//
// When there is more than 2 IPs, all other values prior `n - 2` are
// those coming from the `X-Forwarded-For` HTTP header received by the load
// balancer directly, so something a client might have added manually. Since
// they are coming from an HTTP header and not from Google directly, they
// can be forged and cannot be trusted.
//
// @see https://cloud.google.com/load-balancing/docs/https#x-forwarded-for_header
func RealIP(r *http.Request) string {
xForwardedFor := strings.TrimSpace(r.Header.Get("X-Forwarded-For"))
if xForwardedFor != "" {
addresses := strings.Split(xForwardedFor, ",")
if len(addresses) >= 2 {
return addresses[len(addresses)-2]
}
}
if r.RemoteAddr != "" {
// The RemoteAddr actually has a format of the form `<ip>:<port>`, we remove the port suffix part
return portSuffixRegex.ReplaceAllString(r.RemoteAddr, "")
}
return ""
}
// Deprecated: Use [ForwardResponse] instead.
var FowardResponse = ForwardResponse
func ForwardResponse(ctx context.Context, w http.ResponseWriter, response *http.Response) {
// FIXME: Implement using a Pipe stream instead of reading the full content in memory
content, err := io.ReadAll(response.Body)
defer response.Body.Close()
if err != nil {
WriteError(ctx, w, fmt.Errorf("unable to read response body while forwarding response: %w", err))
}
w.WriteHeader(response.StatusCode)
_, err = w.Write(content)
if err != nil {
logWriteResponseErrorCtx(ctx, "failed forwarding response", err)
}
}