http.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package proxy
  2. import (
  3. "net/http"
  4. "net/http/httputil"
  5. "net/url"
  6. "nginx-ui/server/models"
  7. "strings"
  8. )
  9. type HttpProxy struct {
  10. *httputil.ReverseProxy
  11. data *Data
  12. }
  13. func NewSingleHostReverseProxy(target *url.URL, data *models.ProxyEntity) *HttpProxy {
  14. director := func(req *http.Request) {
  15. rewriteRequestURL(req, target, data)
  16. }
  17. return &HttpProxy{
  18. ReverseProxy: &httputil.ReverseProxy{Director: director},
  19. }
  20. }
  21. func rewriteRequestURL(req *http.Request, target *url.URL, data *models.ProxyEntity) {
  22. targetQuery := target.RawQuery
  23. req.URL.Scheme = target.Scheme
  24. req.URL.Host = target.Host
  25. req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL)
  26. if data.StripPrefix != "" {
  27. req.URL.Path = strings.TrimPrefix(req.URL.Path, data.StripPrefix)
  28. req.URL.RawPath = strings.TrimPrefix(req.URL.RawPath, data.StripPrefix)
  29. }
  30. if targetQuery == "" || req.URL.RawQuery == "" {
  31. req.URL.RawQuery = targetQuery + req.URL.RawQuery
  32. } else {
  33. req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
  34. }
  35. }
  36. func joinURLPath(a, b *url.URL) (path, rawpath string) {
  37. if a.RawPath == "" && b.RawPath == "" {
  38. return singleJoiningSlash(a.Path, b.Path), ""
  39. }
  40. // Same as singleJoiningSlash, but uses EscapedPath to determine
  41. // whether a slash should be added
  42. apath := a.EscapedPath()
  43. bpath := b.EscapedPath()
  44. aslash := strings.HasSuffix(apath, "/")
  45. bslash := strings.HasPrefix(bpath, "/")
  46. switch {
  47. case aslash && bslash:
  48. return a.Path + b.Path[1:], apath + bpath[1:]
  49. case !aslash && !bslash:
  50. return a.Path + "/" + b.Path, apath + "/" + bpath
  51. }
  52. return a.Path + b.Path, apath + bpath
  53. }
  54. func singleJoiningSlash(a, b string) string {
  55. aslash := strings.HasSuffix(a, "/")
  56. bslash := strings.HasPrefix(b, "/")
  57. switch {
  58. case aslash && bslash:
  59. return a + b[1:]
  60. case !aslash && !bslash:
  61. return a + "/" + b
  62. }
  63. return a + b
  64. }