Merge pull request from chihaya/http-and-https

Add https_addr config, required to run HTTPS
This commit is contained in:
Justin Li 2018-09-12 00:49:08 -04:00 committed by GitHub
commit 862b452cef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 24 deletions

View file

@ -25,9 +25,13 @@ chihaya:
# If you do not wish to run this, delete this section. # If you do not wish to run this, delete this section.
http: http:
# The network interface that will bind to an HTTP server for serving # The network interface that will bind to an HTTP server for serving
# BitTorrent traffic. # BitTorrent traffic. Remove this to disable the non-TLS listener.
addr: "0.0.0.0:6969" addr: "0.0.0.0:6969"
# The network interface that will bind to an HTTPS server for serving
# BitTorrent traffic. If set, tls_cert_path and tls_key_path are required.
https_addr: ""
# The path to the required files to listen via HTTPS. # The path to the required files to listen via HTTPS.
tls_cert_path: "" tls_cert_path: ""
tls_key_path: "" tls_key_path: ""

View file

@ -5,6 +5,7 @@ package http
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors"
"net" "net"
"net/http" "net/http"
"time" "time"
@ -21,6 +22,7 @@ import (
// Frontend. // Frontend.
type Config struct { type Config struct {
Addr string `yaml:"addr"` Addr string `yaml:"addr"`
HTTPSAddr string `yaml:"https_addr"`
ReadTimeout time.Duration `yaml:"read_timeout"` ReadTimeout time.Duration `yaml:"read_timeout"`
WriteTimeout time.Duration `yaml:"write_timeout"` WriteTimeout time.Duration `yaml:"write_timeout"`
IdleTimeout time.Duration `yaml:"idle_timeout"` IdleTimeout time.Duration `yaml:"idle_timeout"`
@ -36,6 +38,7 @@ type Config struct {
func (cfg Config) LogFields() log.Fields { func (cfg Config) LogFields() log.Fields {
return log.Fields{ return log.Fields{
"addr": cfg.Addr, "addr": cfg.Addr,
"httpsAddr": cfg.HTTPSAddr,
"readTimeout": cfg.ReadTimeout, "readTimeout": cfg.ReadTimeout,
"writeTimeout": cfg.WriteTimeout, "writeTimeout": cfg.WriteTimeout,
"idleTimeout": cfg.IdleTimeout, "idleTimeout": cfg.IdleTimeout,
@ -103,6 +106,7 @@ func (cfg Config) Validate() Config {
// Frontend represents the state of an HTTP BitTorrent Frontend. // Frontend represents the state of an HTTP BitTorrent Frontend.
type Frontend struct { type Frontend struct {
srv *http.Server srv *http.Server
tlsSrv *http.Server
tlsCfg *tls.Config tlsCfg *tls.Config
logic frontend.TrackerLogic logic frontend.TrackerLogic
@ -119,6 +123,10 @@ func NewFrontend(logic frontend.TrackerLogic, provided Config) (*Frontend, error
Config: cfg, Config: cfg,
} }
if cfg.Addr == "" && cfg.HTTPSAddr == "" {
return nil, errors.New("must specify addr or https_addr or both")
}
// 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
@ -131,23 +139,54 @@ func NewFrontend(logic frontend.TrackerLogic, provided Config) (*Frontend, error
} }
} }
go func() { if cfg.HTTPSAddr != "" && f.tlsCfg == nil {
if err := f.listenAndServe(); err != nil { return nil, errors.New("must specify tls_cert_path and tls_key_path when using https_addr")
log.Fatal("failed while serving http", log.Err(err)) }
} if cfg.HTTPSAddr == "" && f.tlsCfg != nil {
}() return nil, errors.New("must specify https_addr when using tls_cert_path and tls_key_path")
}
if cfg.Addr != "" {
go func() {
if err := f.listenAndServe(); err != nil {
log.Fatal("failed while serving http", log.Err(err))
}
}()
}
if cfg.HTTPSAddr != "" {
go func() {
if err := f.listenAndServeTLS(); err != nil {
log.Fatal("failed while serving https", log.Err(err))
}
}()
}
return f, nil return f, nil
} }
// Stop provides a thread-safe way to shutdown a currently running Frontend. // Stop provides a thread-safe way to shutdown a currently running Frontend.
func (f *Frontend) Stop() stop.Result { func (f *Frontend) Stop() stop.Result {
c := make(stop.Channel) stopGroup := stop.NewGroup()
go func() {
c.Done(f.srv.Shutdown(context.Background()))
}()
return c.Result() if f.srv != nil {
stopGroup.AddFunc(f.makeStopFunc(f.srv))
}
if f.tlsSrv != nil {
stopGroup.AddFunc(f.makeStopFunc(f.tlsSrv))
}
return stopGroup.Stop()
}
func (f *Frontend) makeStopFunc(stopSrv *http.Server) stop.Func {
return func() stop.Result {
c := make(stop.Channel)
go func() {
c.Done(stopSrv.Shutdown(context.Background()))
}()
return c.Result()
}
} }
func (f *Frontend) handler() http.Handler { func (f *Frontend) handler() http.Handler {
@ -164,12 +203,11 @@ func (f *Frontend) handler() http.Handler {
return router return router
} }
// listenAndServe blocks while listening and serving HTTP BitTorrent requests // listenAndServe blocks while listening and serving non-TLS HTTP BitTorrent
// until Stop() is called or an error is returned. // requests until Stop() is called or an error is returned.
func (f *Frontend) listenAndServe() error { func (f *Frontend) listenAndServe() error {
f.srv = &http.Server{ f.srv = &http.Server{
Addr: f.Addr, Addr: f.Addr,
TLSConfig: f.tlsCfg,
Handler: f.handler(), Handler: f.handler(),
ReadTimeout: f.ReadTimeout, ReadTimeout: f.ReadTimeout,
WriteTimeout: f.WriteTimeout, WriteTimeout: f.WriteTimeout,
@ -179,18 +217,30 @@ func (f *Frontend) listenAndServe() error {
f.srv.SetKeepAlivesEnabled(f.EnableKeepAlive) f.srv.SetKeepAlivesEnabled(f.EnableKeepAlive)
// Start the HTTP server. // Start the HTTP server.
if f.tlsCfg != nil { if err := f.srv.ListenAndServe(); err != http.ErrServerClosed {
// ... using TLS. return err
if err := f.srv.ListenAndServeTLS("", ""); err != http.ErrServerClosed { }
return err return nil
} }
} else {
// ... using plain TCP. // listenAndServeTLS blocks while listening and serving TLS HTTP BitTorrent
if err := f.srv.ListenAndServe(); err != http.ErrServerClosed { // requests until Stop() is called or an error is returned.
return err func (f *Frontend) listenAndServeTLS() error {
} f.tlsSrv = &http.Server{
Addr: f.HTTPSAddr,
TLSConfig: f.tlsCfg,
Handler: f.handler(),
ReadTimeout: f.ReadTimeout,
WriteTimeout: f.WriteTimeout,
} }
// Disable KeepAlives.
f.tlsSrv.SetKeepAlivesEnabled(f.EnableKeepAlive)
// Start the HTTP server.
if err := f.tlsSrv.ListenAndServeTLS("", ""); err != http.ErrServerClosed {
return err
}
return nil return nil
} }