Source file blog/context/userip/userip.go
1 // +build OMIT 2 3 // Package userip provides functions for extracting a user IP address from a 4 // request and associating it with a Context. 5 // 6 // This package is an example to accompany https://blog.golang.org/context. 7 // It is not intended for use by others. 8 package userip 9 10 import ( 11 "context" 12 "fmt" 13 "net" 14 "net/http" 15 ) 16 17 // FromRequest extracts the user IP address from req, if present. 18 func FromRequest(req *http.Request) (net.IP, error) { 19 ip, _, err := net.SplitHostPort(req.RemoteAddr) 20 if err != nil { 21 return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr) 22 } 23 24 userIP := net.ParseIP(ip) 25 if userIP == nil { 26 return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr) 27 } 28 return userIP, nil 29 } 30 31 // The key type is unexported to prevent collisions with context keys defined in 32 // other packages. 33 type key int 34 35 // userIPkey is the context key for the user IP address. Its value of zero is 36 // arbitrary. If this package defined other context keys, they would have 37 // different integer values. 38 const userIPKey key = 0 39 40 // NewContext returns a new Context carrying userIP. 41 func NewContext(ctx context.Context, userIP net.IP) context.Context { 42 return context.WithValue(ctx, userIPKey, userIP) 43 } 44 45 // FromContext extracts the user IP address from ctx, if present. 46 func FromContext(ctx context.Context) (net.IP, bool) { 47 // ctx.Value returns nil if ctx has no value for the key; 48 // the net.IP type assertion returns ok=false for nil. 49 userIP, ok := ctx.Value(userIPKey).(net.IP) 50 return userIP, ok 51 } 52