2016-06-22 21:24:57 +00:00
|
|
|
package http_listener
|
|
|
|
|
|
|
|
import (
|
2016-09-29 11:09:02 +00:00
|
|
|
"bytes"
|
2016-10-18 11:22:23 +00:00
|
|
|
"compress/gzip"
|
2018-03-23 18:56:49 +00:00
|
|
|
"crypto/subtle"
|
2017-09-08 23:01:16 +00:00
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
2016-10-18 11:22:23 +00:00
|
|
|
"io"
|
2017-09-08 23:01:16 +00:00
|
|
|
"io/ioutil"
|
2016-06-22 21:24:57 +00:00
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/influxdata/telegraf"
|
|
|
|
"github.com/influxdata/telegraf/internal"
|
|
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
2016-10-18 11:22:23 +00:00
|
|
|
"github.com/influxdata/telegraf/plugins/parsers/influx"
|
2016-11-07 08:34:46 +00:00
|
|
|
"github.com/influxdata/telegraf/selfstat"
|
2016-10-18 11:22:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// DEFAULT_MAX_BODY_SIZE is the default maximum request body size, in bytes.
|
|
|
|
// if the request body is over this size, we will return an HTTP 413 error.
|
|
|
|
// 500 MB
|
|
|
|
DEFAULT_MAX_BODY_SIZE = 500 * 1024 * 1024
|
|
|
|
|
|
|
|
// MAX_LINE_SIZE is the maximum size, in bytes, that can be allocated for
|
|
|
|
// a single InfluxDB point.
|
|
|
|
// 64 KB
|
|
|
|
DEFAULT_MAX_LINE_SIZE = 64 * 1024
|
2016-06-22 21:24:57 +00:00
|
|
|
)
|
|
|
|
|
2018-04-02 21:32:33 +00:00
|
|
|
type TimeFunc func() time.Time
|
|
|
|
|
2016-10-24 15:15:46 +00:00
|
|
|
type HTTPListener struct {
|
2016-06-22 21:24:57 +00:00
|
|
|
ServiceAddress string
|
|
|
|
ReadTimeout internal.Duration
|
|
|
|
WriteTimeout internal.Duration
|
2016-10-18 11:22:23 +00:00
|
|
|
MaxBodySize int64
|
|
|
|
MaxLineSize int
|
2017-04-10 21:33:17 +00:00
|
|
|
Port int
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2017-09-08 23:01:16 +00:00
|
|
|
TlsAllowedCacerts []string
|
|
|
|
TlsCert string
|
|
|
|
TlsKey string
|
|
|
|
|
2018-03-23 18:56:49 +00:00
|
|
|
BasicUsername string
|
|
|
|
BasicPassword string
|
|
|
|
|
2018-04-02 21:32:33 +00:00
|
|
|
TimeFunc
|
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
mu sync.Mutex
|
2016-09-06 14:09:37 +00:00
|
|
|
wg sync.WaitGroup
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
listener net.Listener
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2018-03-28 00:30:51 +00:00
|
|
|
handler *influx.MetricHandler
|
|
|
|
parser *influx.Parser
|
|
|
|
acc telegraf.Accumulator
|
|
|
|
pool *pool
|
2016-11-07 08:34:46 +00:00
|
|
|
|
|
|
|
BytesRecv selfstat.Stat
|
|
|
|
RequestsServed selfstat.Stat
|
|
|
|
WritesServed selfstat.Stat
|
|
|
|
QueriesServed selfstat.Stat
|
|
|
|
PingsServed selfstat.Stat
|
|
|
|
RequestsRecv selfstat.Stat
|
|
|
|
WritesRecv selfstat.Stat
|
|
|
|
QueriesRecv selfstat.Stat
|
|
|
|
PingsRecv selfstat.Stat
|
|
|
|
NotFoundsServed selfstat.Stat
|
|
|
|
BuffersCreated selfstat.Stat
|
2018-03-23 18:56:49 +00:00
|
|
|
AuthFailures selfstat.Stat
|
2016-06-22 21:24:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const sampleConfig = `
|
|
|
|
## Address and port to host HTTP listener on
|
|
|
|
service_address = ":8186"
|
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
## maximum duration before timing out read of the request
|
2016-06-22 21:24:57 +00:00
|
|
|
read_timeout = "10s"
|
2016-10-18 11:22:23 +00:00
|
|
|
## maximum duration before timing out write of the response
|
2016-06-22 21:24:57 +00:00
|
|
|
write_timeout = "10s"
|
2016-10-18 11:22:23 +00:00
|
|
|
|
|
|
|
## Maximum allowed http request body size in bytes.
|
|
|
|
## 0 means to use the default of 536,870,912 bytes (500 mebibytes)
|
|
|
|
max_body_size = 0
|
|
|
|
|
|
|
|
## Maximum line size allowed to be sent in bytes.
|
|
|
|
## 0 means to use the default of 65536 bytes (64 kibibytes)
|
|
|
|
max_line_size = 0
|
2017-09-08 23:01:16 +00:00
|
|
|
|
|
|
|
## Set one or more allowed client CA certificate file names to
|
|
|
|
## enable mutually authenticated TLS connections
|
|
|
|
tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"]
|
|
|
|
|
|
|
|
## Add service certificate and key
|
|
|
|
tls_cert = "/etc/telegraf/cert.pem"
|
|
|
|
tls_key = "/etc/telegraf/key.pem"
|
2018-03-23 18:56:49 +00:00
|
|
|
|
|
|
|
## Optional username and password to accept for HTTP basic authentication.
|
|
|
|
## You probably want to make sure you have TLS configured above for this.
|
|
|
|
# basic_username = "foobar"
|
|
|
|
# basic_password = "barfoo"
|
2016-06-22 21:24:57 +00:00
|
|
|
`
|
|
|
|
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) SampleConfig() string {
|
2016-06-22 21:24:57 +00:00
|
|
|
return sampleConfig
|
|
|
|
}
|
|
|
|
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) Description() string {
|
2016-06-22 21:24:57 +00:00
|
|
|
return "Influx HTTP write listener"
|
|
|
|
}
|
|
|
|
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) Gather(_ telegraf.Accumulator) error {
|
2016-11-07 08:34:46 +00:00
|
|
|
h.BuffersCreated.Set(h.pool.ncreated())
|
2016-06-22 21:24:57 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start starts the http listener service.
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) Start(acc telegraf.Accumulator) error {
|
2016-10-18 11:22:23 +00:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2016-11-07 08:34:46 +00:00
|
|
|
tags := map[string]string{
|
|
|
|
"address": h.ServiceAddress,
|
|
|
|
}
|
|
|
|
h.BytesRecv = selfstat.Register("http_listener", "bytes_received", tags)
|
|
|
|
h.RequestsServed = selfstat.Register("http_listener", "requests_served", tags)
|
|
|
|
h.WritesServed = selfstat.Register("http_listener", "writes_served", tags)
|
|
|
|
h.QueriesServed = selfstat.Register("http_listener", "queries_served", tags)
|
|
|
|
h.PingsServed = selfstat.Register("http_listener", "pings_served", tags)
|
|
|
|
h.RequestsRecv = selfstat.Register("http_listener", "requests_received", tags)
|
|
|
|
h.WritesRecv = selfstat.Register("http_listener", "writes_received", tags)
|
|
|
|
h.QueriesRecv = selfstat.Register("http_listener", "queries_received", tags)
|
|
|
|
h.PingsRecv = selfstat.Register("http_listener", "pings_received", tags)
|
|
|
|
h.NotFoundsServed = selfstat.Register("http_listener", "not_founds_served", tags)
|
|
|
|
h.BuffersCreated = selfstat.Register("http_listener", "buffers_created", tags)
|
2018-03-23 18:56:49 +00:00
|
|
|
h.AuthFailures = selfstat.Register("http_listener", "auth_failures", tags)
|
2016-11-07 08:34:46 +00:00
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
if h.MaxBodySize == 0 {
|
|
|
|
h.MaxBodySize = DEFAULT_MAX_BODY_SIZE
|
|
|
|
}
|
|
|
|
if h.MaxLineSize == 0 {
|
|
|
|
h.MaxLineSize = DEFAULT_MAX_LINE_SIZE
|
2016-06-22 21:24:57 +00:00
|
|
|
}
|
2016-10-18 11:22:23 +00:00
|
|
|
|
2017-09-08 23:01:16 +00:00
|
|
|
if h.ReadTimeout.Duration < time.Second {
|
|
|
|
h.ReadTimeout.Duration = time.Second * 10
|
|
|
|
}
|
|
|
|
if h.WriteTimeout.Duration < time.Second {
|
|
|
|
h.WriteTimeout.Duration = time.Second * 10
|
|
|
|
}
|
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
h.acc = acc
|
|
|
|
h.pool = NewPool(200, h.MaxLineSize)
|
|
|
|
|
2017-09-08 23:01:16 +00:00
|
|
|
tlsConf := h.getTLSConfig()
|
|
|
|
|
|
|
|
server := &http.Server{
|
|
|
|
Addr: h.ServiceAddress,
|
|
|
|
Handler: h,
|
|
|
|
ReadTimeout: h.ReadTimeout.Duration,
|
|
|
|
WriteTimeout: h.WriteTimeout.Duration,
|
|
|
|
TLSConfig: tlsConf,
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
var listener net.Listener
|
|
|
|
if tlsConf != nil {
|
|
|
|
listener, err = tls.Listen("tcp", h.ServiceAddress, tlsConf)
|
|
|
|
} else {
|
|
|
|
listener, err = net.Listen("tcp", h.ServiceAddress)
|
|
|
|
}
|
2016-06-22 21:24:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-10-18 11:22:23 +00:00
|
|
|
h.listener = listener
|
2017-04-10 21:33:17 +00:00
|
|
|
h.Port = listener.Addr().(*net.TCPAddr).Port
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2018-03-28 00:30:51 +00:00
|
|
|
h.handler = influx.NewMetricHandler()
|
|
|
|
h.parser = influx.NewParser(h.handler)
|
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
h.wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer h.wg.Done()
|
2017-09-08 23:01:16 +00:00
|
|
|
server.Serve(h.listener)
|
2016-10-18 11:22:23 +00:00
|
|
|
}()
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
log.Printf("I! Started HTTP listener service on %s\n", h.ServiceAddress)
|
2016-06-22 21:24:57 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop cleans up all resources
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) Stop() {
|
2016-10-18 11:22:23 +00:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2016-06-22 21:24:57 +00:00
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
h.listener.Close()
|
|
|
|
h.wg.Wait()
|
2016-09-06 14:09:37 +00:00
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
log.Println("I! Stopped HTTP listener service on ", h.ServiceAddress)
|
2016-06-22 21:24:57 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
2016-11-07 08:34:46 +00:00
|
|
|
h.RequestsRecv.Incr(1)
|
|
|
|
defer h.RequestsServed.Incr(1)
|
2016-09-06 14:09:37 +00:00
|
|
|
switch req.URL.Path {
|
|
|
|
case "/write":
|
2016-11-07 08:34:46 +00:00
|
|
|
h.WritesRecv.Incr(1)
|
|
|
|
defer h.WritesServed.Incr(1)
|
2018-03-23 18:56:49 +00:00
|
|
|
h.AuthenticateIfSet(h.serveWrite, res, req)
|
2016-09-06 14:09:37 +00:00
|
|
|
case "/query":
|
2016-11-07 08:34:46 +00:00
|
|
|
h.QueriesRecv.Incr(1)
|
|
|
|
defer h.QueriesServed.Incr(1)
|
2016-09-06 14:09:37 +00:00
|
|
|
// Deliver a dummy response to the query endpoint, as some InfluxDB
|
|
|
|
// clients test endpoint availability with a query
|
2018-03-23 18:56:49 +00:00
|
|
|
h.AuthenticateIfSet(func(res http.ResponseWriter, req *http.Request) {
|
|
|
|
res.Header().Set("Content-Type", "application/json")
|
|
|
|
res.Header().Set("X-Influxdb-Version", "1.0")
|
|
|
|
res.WriteHeader(http.StatusOK)
|
|
|
|
res.Write([]byte("{\"results\":[]}"))
|
|
|
|
}, res, req)
|
2016-09-06 14:09:37 +00:00
|
|
|
case "/ping":
|
2016-11-07 08:34:46 +00:00
|
|
|
h.PingsRecv.Incr(1)
|
|
|
|
defer h.PingsServed.Incr(1)
|
2016-09-06 14:09:37 +00:00
|
|
|
// respond to ping requests
|
2018-03-23 18:56:49 +00:00
|
|
|
h.AuthenticateIfSet(func(res http.ResponseWriter, req *http.Request) {
|
|
|
|
res.WriteHeader(http.StatusNoContent)
|
|
|
|
}, res, req)
|
2016-09-06 14:09:37 +00:00
|
|
|
default:
|
2016-11-07 08:34:46 +00:00
|
|
|
defer h.NotFoundsServed.Incr(1)
|
2016-06-22 21:24:57 +00:00
|
|
|
// Don't know how to respond to calls to other endpoints
|
2018-03-23 18:56:49 +00:00
|
|
|
h.AuthenticateIfSet(http.NotFound, res, req)
|
2016-06-22 21:24:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-24 15:15:46 +00:00
|
|
|
func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
|
2016-10-18 11:22:23 +00:00
|
|
|
// Check that the content length is not too large for us to handle.
|
|
|
|
if req.ContentLength > h.MaxBodySize {
|
|
|
|
tooLarge(res)
|
|
|
|
return
|
|
|
|
}
|
2018-04-02 21:32:33 +00:00
|
|
|
now := h.TimeFunc()
|
2016-10-18 11:22:23 +00:00
|
|
|
|
2017-04-10 23:39:40 +00:00
|
|
|
precision := req.URL.Query().Get("precision")
|
|
|
|
|
2016-10-18 11:22:23 +00:00
|
|
|
// Handle gzip request bodies
|
|
|
|
body := req.Body
|
|
|
|
if req.Header.Get("Content-Encoding") == "gzip" {
|
2017-04-10 23:39:40 +00:00
|
|
|
var err error
|
2016-10-24 15:15:46 +00:00
|
|
|
body, err = gzip.NewReader(req.Body)
|
2016-10-18 11:22:23 +00:00
|
|
|
defer body.Close()
|
|
|
|
if err != nil {
|
|
|
|
log.Println("E! " + err.Error())
|
|
|
|
badRequest(res)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
body = http.MaxBytesReader(res, body, h.MaxBodySize)
|
|
|
|
|
|
|
|
var return400 bool
|
|
|
|
var hangingBytes bool
|
|
|
|
buf := h.pool.get()
|
2016-10-24 15:15:46 +00:00
|
|
|
defer h.pool.put(buf)
|
2016-10-18 11:22:23 +00:00
|
|
|
bufStart := 0
|
|
|
|
for {
|
|
|
|
n, err := io.ReadFull(body, buf[bufStart:])
|
|
|
|
if err != nil && err != io.ErrUnexpectedEOF && err != io.EOF {
|
|
|
|
log.Println("E! " + err.Error())
|
|
|
|
// problem reading the request body
|
|
|
|
badRequest(res)
|
|
|
|
return
|
|
|
|
}
|
2016-11-07 08:34:46 +00:00
|
|
|
h.BytesRecv.Incr(int64(n))
|
2016-10-18 11:22:23 +00:00
|
|
|
|
|
|
|
if err == io.EOF {
|
|
|
|
if return400 {
|
|
|
|
badRequest(res)
|
|
|
|
} else {
|
|
|
|
res.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if hangingBytes {
|
|
|
|
i := bytes.IndexByte(buf, '\n')
|
|
|
|
if i == -1 {
|
|
|
|
// still didn't find a newline, keep scanning
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// rotate the bit remaining after the first newline to the front of the buffer
|
|
|
|
i++ // start copying after the newline
|
|
|
|
bufStart = len(buf) - i
|
|
|
|
if bufStart > 0 {
|
|
|
|
copy(buf, buf[i:])
|
|
|
|
}
|
|
|
|
hangingBytes = false
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == io.ErrUnexpectedEOF {
|
|
|
|
// finished reading the request body
|
2017-04-10 23:39:40 +00:00
|
|
|
if err := h.parse(buf[:n+bufStart], now, precision); err != nil {
|
2016-10-18 11:22:23 +00:00
|
|
|
log.Println("E! " + err.Error())
|
|
|
|
return400 = true
|
|
|
|
}
|
|
|
|
if return400 {
|
|
|
|
badRequest(res)
|
|
|
|
} else {
|
|
|
|
res.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we got down here it means that we filled our buffer, and there
|
|
|
|
// are still bytes remaining to be read. So we will parse up until the
|
|
|
|
// final newline, then push the rest of the bytes into the next buffer.
|
|
|
|
i := bytes.LastIndexByte(buf, '\n')
|
|
|
|
if i == -1 {
|
|
|
|
// drop any line longer than the max buffer size
|
|
|
|
log.Printf("E! http_listener received a single line longer than the maximum of %d bytes",
|
|
|
|
len(buf))
|
|
|
|
hangingBytes = true
|
|
|
|
return400 = true
|
|
|
|
bufStart = 0
|
|
|
|
continue
|
|
|
|
}
|
2017-04-10 23:39:40 +00:00
|
|
|
if err := h.parse(buf[:i+1], now, precision); err != nil {
|
2016-10-18 11:22:23 +00:00
|
|
|
log.Println("E! " + err.Error())
|
|
|
|
return400 = true
|
|
|
|
}
|
|
|
|
// rotate the bit remaining after the last newline to the front of the buffer
|
|
|
|
i++ // start copying after the newline
|
|
|
|
bufStart = len(buf) - i
|
|
|
|
if bufStart > 0 {
|
|
|
|
copy(buf, buf[i:])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-10 23:39:40 +00:00
|
|
|
func (h *HTTPListener) parse(b []byte, t time.Time, precision string) error {
|
2018-04-02 21:32:33 +00:00
|
|
|
h.handler.SetTimePrecision(getPrecisionMultiplier(precision))
|
|
|
|
h.handler.SetTimeFunc(func() time.Time { return t })
|
2018-03-28 00:30:51 +00:00
|
|
|
metrics, err := h.parser.Parse(b)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-10-18 11:22:23 +00:00
|
|
|
|
|
|
|
for _, m := range metrics {
|
|
|
|
h.acc.AddFields(m.Name(), m.Fields(), m.Tags(), m.Time())
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func tooLarge(res http.ResponseWriter) {
|
|
|
|
res.Header().Set("Content-Type", "application/json")
|
|
|
|
res.Header().Set("X-Influxdb-Version", "1.0")
|
|
|
|
res.WriteHeader(http.StatusRequestEntityTooLarge)
|
|
|
|
res.Write([]byte(`{"error":"http: request body too large"}`))
|
|
|
|
}
|
|
|
|
|
|
|
|
func badRequest(res http.ResponseWriter) {
|
|
|
|
res.Header().Set("Content-Type", "application/json")
|
|
|
|
res.Header().Set("X-Influxdb-Version", "1.0")
|
|
|
|
res.WriteHeader(http.StatusBadRequest)
|
|
|
|
res.Write([]byte(`{"error":"http: bad request"}`))
|
|
|
|
}
|
|
|
|
|
2017-09-08 23:01:16 +00:00
|
|
|
func (h *HTTPListener) getTLSConfig() *tls.Config {
|
|
|
|
tlsConf := &tls.Config{
|
|
|
|
InsecureSkipVerify: false,
|
|
|
|
Renegotiation: tls.RenegotiateNever,
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(h.TlsCert) == 0 || len(h.TlsKey) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
cert, err := tls.LoadX509KeyPair(h.TlsCert, h.TlsKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
tlsConf.Certificates = []tls.Certificate{cert}
|
|
|
|
|
|
|
|
if h.TlsAllowedCacerts != nil {
|
|
|
|
tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
|
|
|
|
clientPool := x509.NewCertPool()
|
|
|
|
for _, ca := range h.TlsAllowedCacerts {
|
|
|
|
c, err := ioutil.ReadFile(ca)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
clientPool.AppendCertsFromPEM(c)
|
|
|
|
}
|
|
|
|
tlsConf.ClientCAs = clientPool
|
|
|
|
}
|
|
|
|
|
|
|
|
return tlsConf
|
|
|
|
}
|
|
|
|
|
2018-03-23 18:56:49 +00:00
|
|
|
func (h *HTTPListener) AuthenticateIfSet(handler http.HandlerFunc, res http.ResponseWriter, req *http.Request) {
|
|
|
|
if h.BasicUsername != "" && h.BasicPassword != "" {
|
|
|
|
reqUsername, reqPassword, ok := req.BasicAuth()
|
|
|
|
if !ok ||
|
|
|
|
subtle.ConstantTimeCompare([]byte(reqUsername), []byte(h.BasicUsername)) != 1 ||
|
|
|
|
subtle.ConstantTimeCompare([]byte(reqPassword), []byte(h.BasicPassword)) != 1 {
|
|
|
|
|
|
|
|
h.AuthFailures.Incr(1)
|
|
|
|
http.Error(res, "Unauthorized.", http.StatusUnauthorized)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
handler(res, req)
|
|
|
|
} else {
|
|
|
|
handler(res, req)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-28 00:30:51 +00:00
|
|
|
func getPrecisionMultiplier(precision string) time.Duration {
|
|
|
|
d := time.Nanosecond
|
|
|
|
switch precision {
|
|
|
|
case "u":
|
|
|
|
d = time.Microsecond
|
|
|
|
case "ms":
|
|
|
|
d = time.Millisecond
|
|
|
|
case "s":
|
|
|
|
d = time.Second
|
|
|
|
case "m":
|
|
|
|
d = time.Minute
|
|
|
|
case "h":
|
|
|
|
d = time.Hour
|
|
|
|
}
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
2016-06-22 21:24:57 +00:00
|
|
|
func init() {
|
|
|
|
inputs.Add("http_listener", func() telegraf.Input {
|
2016-10-24 15:15:46 +00:00
|
|
|
return &HTTPListener{
|
2016-10-18 11:22:23 +00:00
|
|
|
ServiceAddress: ":8186",
|
2018-04-02 21:32:33 +00:00
|
|
|
TimeFunc: time.Now,
|
2016-10-18 11:22:23 +00:00
|
|
|
}
|
2016-06-22 21:24:57 +00:00
|
|
|
})
|
|
|
|
}
|