Capstan is a Golang web framework that shares some similarities with others in its segment.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
2.4KB

  1. package capstan
  2. import (
  3. "bytes"
  4. "net/http"
  5. "strings"
  6. "github.com/go-chi/chi"
  7. )
  8. // The router proxy provides an intermediary between go-chi's handler and
  9. // Capstan. This allows us to rebind or rename mount points by reinitializing
  10. // the proxy's internal pointer to the new muxer.
  11. type proxy struct {
  12. Hostname string
  13. FullHost string
  14. EnforceHost bool
  15. EnforcePort bool
  16. MaxRequestDuration int
  17. router *Router
  18. mux *chi.Mux
  19. }
  20. type proxyOptions struct {
  21. ListenAddr string
  22. Hostname string
  23. EnforceHost bool
  24. EnforcePort bool
  25. MaxRequestDuration int
  26. }
  27. // Returns a new proxy object with its router and mux unset.
  28. //
  29. // TODO: Replace or add feature for using a radix trie to determine the
  30. // appropriate muxer for a given host name. Or, optionally, implement a
  31. // different proxy type when multiple host names are configured/requested.
  32. func newProxy(options *proxyOptions) *proxy {
  33. prx := &proxy{
  34. Hostname: options.Hostname,
  35. EnforceHost: options.EnforceHost,
  36. EnforcePort: options.EnforcePort,
  37. MaxRequestDuration: options.MaxRequestDuration,
  38. }
  39. if options.EnforcePort && strings.IndexRune(options.Hostname, ':') == -1 {
  40. prx.FullHost = options.Hostname + options.ListenAddr[strings.IndexRune(options.ListenAddr, ':'):]
  41. }
  42. return prx
  43. }
  44. func (d *proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  45. // Host enforcement is not enabled.
  46. if !d.EnforceHost {
  47. d.mux.ServeHTTP(w, r)
  48. return
  49. }
  50. host := r.Host
  51. if !d.EnforcePort {
  52. if i := strings.IndexRune(host, ':'); i >= 0 {
  53. host = host[:i]
  54. }
  55. }
  56. if bytes.Compare([]byte(d.Hostname), []byte(host)) == 0 {
  57. d.mux.ServeHTTP(w, r)
  58. return
  59. }
  60. w.WriteHeader(404)
  61. }
  62. func (d *proxy) Switch(router chi.Router) {
  63. if mux, ok := router.(*chi.Mux); ok {
  64. d.mux = mux
  65. }
  66. }
  67. func (d *proxy) SwitchFunc() func(chi.Router) {
  68. return d.Switch
  69. }
  70. // Consider implementing a match function that uses radix tries similar to Chi
  71. // (or port from Chi) such that subdomains could be matches using longest path
  72. // matching or parameter matching ("{username}.example.com").
  73. //
  74. // vhostProxy will only be used and set automatically whenever a subserver is
  75. // created, otherwise `proxy` is used instead.
  76. type vhostProxy struct {
  77. }
  78. type proxyHandler interface {
  79. http.Handler
  80. Switch(chi.Router)
  81. SwitchFunc() func(chi.Router)
  82. }