mirror of https://github.com/gin-gonic/gin.git
138 lines
4.0 KiB
Go
138 lines
4.0 KiB
Go
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
|
// Use of this source code is governed by a MIT style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gin
|
|
|
|
import (
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin/binding"
|
|
)
|
|
|
|
const (
|
|
MIMEJSON = binding.MIMEJSON
|
|
MIMEHTML = binding.MIMEHTML
|
|
MIMEXML = binding.MIMEXML
|
|
MIMEXML2 = binding.MIMEXML2
|
|
MIMEPlain = binding.MIMEPlain
|
|
MIMEPOSTForm = binding.MIMEPOSTForm
|
|
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
|
|
)
|
|
|
|
// DEPRECATED, use Bind() instead.
|
|
// Like ParseBody() but this method also writes a 400 error if the json is not valid.
|
|
func (c *Context) EnsureBody(item interface{}) bool {
|
|
return c.Bind(item)
|
|
}
|
|
|
|
// DEPRECATED use bindings directly
|
|
// Parses the body content as a JSON input. It decodes the json payload into the struct specified as a pointer.
|
|
func (c *Context) ParseBody(item interface{}) error {
|
|
return binding.JSON.Bind(c.Request, item)
|
|
}
|
|
|
|
// DEPRECATED use gin.Static() instead
|
|
// ServeFiles serves files from the given file system root.
|
|
// The path must end with "/*filepath", files are then served from the local
|
|
// path /defined/root/dir/*filepath.
|
|
// For example if root is "/etc" and *filepath is "passwd", the local file
|
|
// "/etc/passwd" would be served.
|
|
// Internally a http.FileServer is used, therefore http.NotFound is used instead
|
|
// of the Router's NotFound handler.
|
|
// To use the operating system's file system implementation,
|
|
// use http.Dir:
|
|
// router.ServeFiles("/src/*filepath", http.Dir("/var/www"))
|
|
func (engine *Engine) ServeFiles(path string, root http.FileSystem) {
|
|
engine.router.ServeFiles(path, root)
|
|
}
|
|
|
|
// DEPRECATED use gin.LoadHTMLGlob() or gin.LoadHTMLFiles() instead
|
|
func (engine *Engine) LoadHTMLTemplates(pattern string) {
|
|
engine.LoadHTMLGlob(pattern)
|
|
}
|
|
|
|
// DEPRECATED. Use NoRoute() instead
|
|
func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
|
|
engine.NoRoute(handlers...)
|
|
}
|
|
|
|
// the ForwardedFor middleware unwraps the X-Forwarded-For headers, be careful to only use this
|
|
// middleware if you've got servers in front of this server. The list with (known) proxies and
|
|
// local ips are being filtered out of the forwarded for list, giving the last not local ip being
|
|
// the real client ip.
|
|
func ForwardedFor(proxies ...interface{}) HandlerFunc {
|
|
if len(proxies) == 0 {
|
|
// default to local ips
|
|
var reservedLocalIps = []string{"10.0.0.0/8", "127.0.0.1/32", "172.16.0.0/12", "192.168.0.0/16"}
|
|
|
|
proxies = make([]interface{}, len(reservedLocalIps))
|
|
|
|
for i, v := range reservedLocalIps {
|
|
proxies[i] = v
|
|
}
|
|
}
|
|
|
|
return func(c *Context) {
|
|
// the X-Forwarded-For header contains an array with left most the client ip, then
|
|
// comma separated, all proxies the request passed. The last proxy appears
|
|
// as the remote address of the request. Returning the client
|
|
// ip to comply with default RemoteAddr response.
|
|
|
|
// check if remoteaddr is local ip or in list of defined proxies
|
|
remoteIp := net.ParseIP(strings.Split(c.Request.RemoteAddr, ":")[0])
|
|
|
|
if !ipInMasks(remoteIp, proxies) {
|
|
return
|
|
}
|
|
|
|
if forwardedFor := c.Request.Header.Get("X-Forwarded-For"); forwardedFor != "" {
|
|
parts := strings.Split(forwardedFor, ",")
|
|
|
|
for i := len(parts) - 1; i >= 0; i-- {
|
|
part := parts[i]
|
|
|
|
ip := net.ParseIP(strings.TrimSpace(part))
|
|
|
|
if ipInMasks(ip, proxies) {
|
|
continue
|
|
}
|
|
|
|
// returning remote addr conform the original remote addr format
|
|
c.Request.RemoteAddr = ip.String() + ":0"
|
|
|
|
// remove forwarded for address
|
|
c.Request.Header.Set("X-Forwarded-For", "")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func ipInMasks(ip net.IP, masks []interface{}) bool {
|
|
for _, proxy := range masks {
|
|
var mask *net.IPNet
|
|
var err error
|
|
|
|
switch t := proxy.(type) {
|
|
case string:
|
|
if _, mask, err = net.ParseCIDR(t); err != nil {
|
|
log.Panic(err)
|
|
}
|
|
case net.IP:
|
|
mask = &net.IPNet{IP: t, Mask: net.CIDRMask(len(t)*8, len(t)*8)}
|
|
case net.IPNet:
|
|
mask = &t
|
|
}
|
|
|
|
if mask.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|