http: allow for customized routes
Update to allow arrays of routes to be passed to the http frontend. This also supports named parameters as permitted by the router. To avoid external dependencies in the middleware, a RouteParam and RouteParams type was added to the bittorrent package. Note: this eliminates the need for "enable_legacy_php_urls", as the the additional route could be added to the route array. However, this may be considered a breaking change.
This commit is contained in:
parent
89cdaa8c6d
commit
77a52f9f30
3 changed files with 62 additions and 23 deletions
|
@ -54,6 +54,22 @@ type QueryParams struct {
|
||||||
infoHashes []InfoHash
|
infoHashes []InfoHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type routeParamsKey struct{}
|
||||||
|
|
||||||
|
// RouteParamsKey is a key for the context of a request that
|
||||||
|
// contains the named parameters from the http router
|
||||||
|
var RouteParamsKey = routeParamsKey{}
|
||||||
|
|
||||||
|
// RouteParam is a type that contains the values from the named parameters
|
||||||
|
// on the route
|
||||||
|
type RouteParam struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouteParams is a collection of RouteParam instances
|
||||||
|
type RouteParams []RouteParam
|
||||||
|
|
||||||
// ParseURLData parses a request URL or UDP URLData as defined in BEP41.
|
// ParseURLData parses a request URL or UDP URLData as defined in BEP41.
|
||||||
// It expects a concatenated string of the request's path and query parts as
|
// It expects a concatenated string of the request's path and query parts as
|
||||||
// defined in RFC 3986. As both the udp: and http: scheme used by BitTorrent
|
// defined in RFC 3986. As both the udp: and http: scheme used by BitTorrent
|
||||||
|
|
28
dist/example_config.yaml
vendored
28
dist/example_config.yaml
vendored
|
@ -41,15 +41,25 @@ chihaya:
|
||||||
# Disabling this should increase performance/decrease load.
|
# Disabling this should increase performance/decrease load.
|
||||||
enable_request_timing: false
|
enable_request_timing: false
|
||||||
|
|
||||||
# Whether to listen on /announce.php and /scrape.php in addition to their
|
# An array of routes to listen on for announce requests. This is an option
|
||||||
# non-.php counterparts.
|
# to support trackers that do not listen for /announce or need to listen
|
||||||
# This is an option for compatibility with (very) old clients or otherwise
|
# on multiple routes.
|
||||||
# outdated systems.
|
#
|
||||||
# This might be useful to retracker.local users, for more information see
|
# This supports named parameters and catch-all parameters as described at
|
||||||
# http://rutracker.wiki/Оптимизация_обмена_битторрент_траффиком_в_локальных_сетях
|
# https://github.com/julienschmidt/httprouter#named-parameters
|
||||||
# and
|
announce_routes:
|
||||||
# http://rutracker.wiki/Retracker.local
|
- "/announce"
|
||||||
enable_legacy_php_urls: false
|
# - "/announce.php"
|
||||||
|
|
||||||
|
# An array of routes to listen on for scrape requests. This is an option
|
||||||
|
# to support trackers that do not listen for /scrape or need to listen
|
||||||
|
# on multiple routes.
|
||||||
|
#
|
||||||
|
# This supports named parameters and catch-all parameters as described at
|
||||||
|
# https://github.com/julienschmidt/httprouter#named-parameters
|
||||||
|
scrape_routes:
|
||||||
|
- "/scrape"
|
||||||
|
# - "/scrape.php"
|
||||||
|
|
||||||
# When enabled, the IP address used to connect to the tracker will not
|
# When enabled, the IP address used to connect to the tracker will not
|
||||||
# override the value clients advertise as their IP address.
|
# override the value clients advertise as their IP address.
|
||||||
|
|
|
@ -29,7 +29,8 @@ type Config struct {
|
||||||
EnableKeepAlive bool `yaml:"enable_keepalive"`
|
EnableKeepAlive bool `yaml:"enable_keepalive"`
|
||||||
TLSCertPath string `yaml:"tls_cert_path"`
|
TLSCertPath string `yaml:"tls_cert_path"`
|
||||||
TLSKeyPath string `yaml:"tls_key_path"`
|
TLSKeyPath string `yaml:"tls_key_path"`
|
||||||
EnableLegacyPHPURLs bool `yaml:"enable_legacy_php_urls"`
|
AnnounceRoutes []string `yaml:"announce_routes"`
|
||||||
|
ScrapeRoutes []string `yaml:"scrape_routes"`
|
||||||
EnableRequestTiming bool `yaml:"enable_request_timing"`
|
EnableRequestTiming bool `yaml:"enable_request_timing"`
|
||||||
ParseOptions `yaml:",inline"`
|
ParseOptions `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
@ -45,7 +46,8 @@ func (cfg Config) LogFields() log.Fields {
|
||||||
"enableKeepAlive": cfg.EnableKeepAlive,
|
"enableKeepAlive": cfg.EnableKeepAlive,
|
||||||
"tlsCertPath": cfg.TLSCertPath,
|
"tlsCertPath": cfg.TLSCertPath,
|
||||||
"tlsKeyPath": cfg.TLSKeyPath,
|
"tlsKeyPath": cfg.TLSKeyPath,
|
||||||
"enableLegacyPHPURLs": cfg.EnableLegacyPHPURLs,
|
"announceRoutes": cfg.AnnounceRoutes,
|
||||||
|
"scrapeRoutes": cfg.ScrapeRoutes,
|
||||||
"enableRequestTiming": cfg.EnableRequestTiming,
|
"enableRequestTiming": cfg.EnableRequestTiming,
|
||||||
"allowIPSpoofing": cfg.AllowIPSpoofing,
|
"allowIPSpoofing": cfg.AllowIPSpoofing,
|
||||||
"realIPHeader": cfg.RealIPHeader,
|
"realIPHeader": cfg.RealIPHeader,
|
||||||
|
@ -154,6 +156,10 @@ func NewFrontend(logic frontend.TrackerLogic, provided Config) (*Frontend, error
|
||||||
return nil, errors.New("must specify addr or https_addr or both")
|
return nil, errors.New("must specify addr or https_addr or both")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(cfg.AnnounceRoutes) < 1 || len(cfg.ScrapeRoutes) < 1 {
|
||||||
|
return nil, errors.New("must specify routes")
|
||||||
|
}
|
||||||
|
|
||||||
// If TLS is enabled, create a key pair.
|
// If TLS is enabled, create a key pair.
|
||||||
if cfg.TLSCertPath != "" && cfg.TLSKeyPath != "" {
|
if cfg.TLSCertPath != "" && cfg.TLSKeyPath != "" {
|
||||||
var err error
|
var err error
|
||||||
|
@ -236,15 +242,12 @@ func (f *Frontend) makeStopFunc(stopSrv *http.Server) stop.Func {
|
||||||
|
|
||||||
func (f *Frontend) handler() http.Handler {
|
func (f *Frontend) handler() http.Handler {
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
router.GET("/announce", f.announceRoute)
|
for _, route := range f.AnnounceRoutes {
|
||||||
router.GET("/scrape", f.scrapeRoute)
|
router.GET(route, f.announceRoute)
|
||||||
|
}
|
||||||
if f.EnableLegacyPHPURLs {
|
for _, route := range f.ScrapeRoutes {
|
||||||
log.Info("http: enabling legacy PHP URLs")
|
router.GET(route, f.scrapeRoute)
|
||||||
router.GET("/announce.php", f.announceRoute)
|
|
||||||
router.GET("/scrape.php", f.scrapeRoute)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +291,16 @@ func (f *Frontend) serveHTTPS(l net.Listener) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func injectRouteParamsToContext(ctx context.Context, ps httprouter.Params) context.Context {
|
||||||
|
rp := bittorrent.RouteParams{}
|
||||||
|
for _, p := range ps {
|
||||||
|
rp = append(rp, bittorrent.RouteParam{Key: p.Key, Value: p.Value})
|
||||||
|
}
|
||||||
|
return context.WithValue(ctx, bittorrent.RouteParamsKey, rp)
|
||||||
|
}
|
||||||
|
|
||||||
// announceRoute parses and responds to an Announce.
|
// announceRoute parses and responds to an Announce.
|
||||||
func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
var err error
|
var err error
|
||||||
var start time.Time
|
var start time.Time
|
||||||
if f.EnableRequestTiming {
|
if f.EnableRequestTiming {
|
||||||
|
@ -312,7 +323,8 @@ func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httpr
|
||||||
af = new(bittorrent.AddressFamily)
|
af = new(bittorrent.AddressFamily)
|
||||||
*af = req.IP.AddressFamily
|
*af = req.IP.AddressFamily
|
||||||
|
|
||||||
ctx, resp, err := f.logic.HandleAnnounce(context.Background(), req)
|
ctx := injectRouteParamsToContext(context.Background(), ps)
|
||||||
|
ctx, resp, err := f.logic.HandleAnnounce(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteError(w, err)
|
WriteError(w, err)
|
||||||
return
|
return
|
||||||
|
@ -329,7 +341,7 @@ func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httpr
|
||||||
}
|
}
|
||||||
|
|
||||||
// scrapeRoute parses and responds to a Scrape.
|
// scrapeRoute parses and responds to a Scrape.
|
||||||
func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
var err error
|
var err error
|
||||||
var start time.Time
|
var start time.Time
|
||||||
if f.EnableRequestTiming {
|
if f.EnableRequestTiming {
|
||||||
|
@ -370,7 +382,8 @@ func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprou
|
||||||
af = new(bittorrent.AddressFamily)
|
af = new(bittorrent.AddressFamily)
|
||||||
*af = req.AddressFamily
|
*af = req.AddressFamily
|
||||||
|
|
||||||
ctx, resp, err := f.logic.HandleScrape(context.Background(), req)
|
ctx := injectRouteParamsToContext(context.Background(), ps)
|
||||||
|
ctx, resp, err := f.logic.HandleScrape(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteError(w, err)
|
WriteError(w, err)
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue