2016-01-25 06:41:39 +01:00
|
|
|
// Copyright 2016 The Chihaya Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by the BSD 2-Clause license,
|
|
|
|
// which can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
"github.com/tylerb/graceful"
|
|
|
|
|
2016-03-03 02:18:55 +01:00
|
|
|
"github.com/chihaya/chihaya"
|
2016-01-25 06:41:39 +01:00
|
|
|
"github.com/chihaya/chihaya/server"
|
|
|
|
"github.com/chihaya/chihaya/tracker"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
server.Register("http", constructor)
|
|
|
|
}
|
|
|
|
|
2016-03-03 02:18:55 +01:00
|
|
|
func constructor(srvcfg *chihaya.ServerConfig, tkr *tracker.Tracker) (server.Server, error) {
|
2016-01-25 06:41:39 +01:00
|
|
|
cfg, err := newHTTPConfig(srvcfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New("http: invalid config: " + err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return &httpServer{
|
|
|
|
cfg: cfg,
|
|
|
|
tkr: tkr,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type httpServer struct {
|
2016-04-07 16:22:30 +02:00
|
|
|
cfg *httpConfig
|
|
|
|
tkr *tracker.Tracker
|
|
|
|
grace *graceful.Server
|
2016-01-25 06:41:39 +01:00
|
|
|
}
|
|
|
|
|
2016-04-07 16:24:37 +02:00
|
|
|
// Start runs the server and blocks until it has exited.
|
|
|
|
//
|
|
|
|
// It panics if the server exits unexpectedly.
|
2016-01-25 06:41:39 +01:00
|
|
|
func (s *httpServer) Start() {
|
|
|
|
s.grace = &graceful.Server{
|
|
|
|
Server: &http.Server{
|
|
|
|
Addr: s.cfg.Addr,
|
|
|
|
Handler: s.routes(),
|
|
|
|
ReadTimeout: s.cfg.ReadTimeout,
|
|
|
|
WriteTimeout: s.cfg.WriteTimeout,
|
|
|
|
},
|
2016-04-07 16:22:30 +02:00
|
|
|
Timeout: s.cfg.RequestTimeout,
|
|
|
|
NoSignalHandling: true,
|
2016-01-25 06:41:39 +01:00
|
|
|
ConnState: func(conn net.Conn, state http.ConnState) {
|
|
|
|
switch state {
|
|
|
|
case http.StateNew:
|
|
|
|
//stats.RecordEvent(stats.AcceptedConnection)
|
|
|
|
|
|
|
|
case http.StateClosed:
|
|
|
|
//stats.RecordEvent(stats.ClosedConnection)
|
|
|
|
|
|
|
|
case http.StateHijacked:
|
|
|
|
panic("http: connection impossibly hijacked")
|
|
|
|
|
|
|
|
// Ignore the following cases.
|
|
|
|
case http.StateActive, http.StateIdle:
|
|
|
|
|
|
|
|
default:
|
|
|
|
panic("http: connection transitioned to unknown state")
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
s.grace.SetKeepAlivesEnabled(false)
|
|
|
|
|
|
|
|
if err := s.grace.ListenAndServe(); err != nil {
|
|
|
|
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
|
|
|
|
log.Printf("Failed to gracefully run HTTP server: %s", err.Error())
|
2016-04-07 16:22:30 +02:00
|
|
|
panic(err)
|
2016-01-25 06:41:39 +01:00
|
|
|
}
|
|
|
|
}
|
2016-03-02 22:18:34 +01:00
|
|
|
|
|
|
|
log.Println("HTTP server shut down cleanly")
|
2016-01-25 06:41:39 +01:00
|
|
|
}
|
|
|
|
|
2016-04-07 16:24:37 +02:00
|
|
|
// Stop stops the server and blocks until the server has exited.
|
2016-01-25 06:41:39 +01:00
|
|
|
func (s *httpServer) Stop() {
|
2016-04-07 16:22:30 +02:00
|
|
|
s.grace.Stop(s.grace.Timeout)
|
|
|
|
<-s.grace.StopChan()
|
2016-01-25 06:41:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) routes() *httprouter.Router {
|
|
|
|
r := httprouter.New()
|
|
|
|
r.GET("/announce", s.serveAnnounce)
|
|
|
|
r.GET("/scrape", s.serveScrape)
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) serveAnnounce(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2016-02-16 01:49:25 +01:00
|
|
|
req, err := announceRequest(r, s.cfg)
|
2016-01-25 06:41:39 +01:00
|
|
|
if err != nil {
|
2016-02-16 01:49:25 +01:00
|
|
|
writeError(w, err)
|
2016-01-25 06:41:39 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := s.tkr.HandleAnnounce(req)
|
|
|
|
if err != nil {
|
2016-02-16 01:49:25 +01:00
|
|
|
writeError(w, err)
|
2016-01-25 06:41:39 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-04-08 04:31:38 +02:00
|
|
|
err = writeAnnounceResponse(w, resp)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("error serializing response", err)
|
|
|
|
}
|
2016-01-25 06:41:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) serveScrape(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2016-02-16 01:49:25 +01:00
|
|
|
req, err := scrapeRequest(r, s.cfg)
|
2016-01-25 06:41:39 +01:00
|
|
|
if err != nil {
|
2016-02-16 01:49:25 +01:00
|
|
|
writeError(w, err)
|
2016-01-25 06:41:39 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := s.tkr.HandleScrape(req)
|
|
|
|
if err != nil {
|
2016-02-16 01:49:25 +01:00
|
|
|
writeError(w, err)
|
2016-01-25 06:41:39 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-02-16 01:49:25 +01:00
|
|
|
writeScrapeResponse(w, resp)
|
2016-01-25 06:41:39 +01:00
|
|
|
}
|