From 43c39dc36ce12c9edf017ffd184535a7ac92ef37 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Wed, 29 Apr 2020 16:20:23 +0300 Subject: [PATCH] vendor: use github.com/VictoriaMetrics/fasthttp instead of github.com/fasthttp/fasthttp The upstream fasthttp may contain issues like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b , plus a code that isn't used by VictoriaMetrics. So let's use a private copy under our control instead. --- app/vmagent/remotewrite/client.go | 2 +- app/vmagent/remotewrite/statconn.go | 2 +- go.mod | 8 +- go.sum | 37 +- lib/promscrape/client.go | 24 +- lib/promscrape/discovery/kubernetes/api.go | 2 +- lib/promscrape/statconn.go | 2 +- .../fasthttp/.gitignore | 0 .../VictoriaMetrics/fasthttp/.travis.yml | 16 + .../fasthttp/LICENSE | 5 +- .../VictoriaMetrics/fasthttp/README.md | 5 + .../fasthttp/TODO | 0 .../fasthttp/args.go | 129 +--- .../VictoriaMetrics/fasthttp/bytebuffer.go | 64 ++ .../fasthttp/bytesconv.go | 36 +- .../fasthttp/bytesconv_32.go | 1 + .../fasthttp/bytesconv_64.go | 1 + .../fasthttp/client.go | 380 ++++------ .../VictoriaMetrics/fasthttp/coarseTime.go | 28 + .../fasthttp/compress.go | 8 +- .../fasthttp/cookie.go | 182 +---- .../fasthttp/doc.go | 3 + .../fasthttp/fasthttputil/doc.go | 0 .../fasthttp/fasthttputil/ecdsa.key | 0 .../fasthttp/fasthttputil/ecdsa.pem | 0 .../fasthttputil/inmemory_listener.go | 24 +- .../fasthttp/fasthttputil/pipeconns.go | 2 +- .../fasthttp/fasthttputil/rsa.key | 0 .../fasthttp/fasthttputil/rsa.pem | 0 .../fasthttp/fs.go | 37 +- .../VictoriaMetrics/fasthttp/go.mod | 9 + .../VictoriaMetrics/fasthttp/go.sum | 6 + .../fasthttp/header.go | 453 ++++-------- .../fasthttp/http.go | 104 +-- .../fasthttp/lbclient.go | 2 +- .../fasthttp/nocopy.go | 4 +- .../fasthttp/peripconn.go | 0 .../fasthttp/server.go | 671 ++---------------- .../fasthttp/ssl-cert-snakeoil.key | 0 .../fasthttp/ssl-cert-snakeoil.pem | 0 .../fasthttp/stackless/doc.go | 0 .../fasthttp/stackless/func.go | 0 .../fasthttp/stackless/writer.go | 3 +- .../fasthttp/status.go | 0 .../fasthttp/stream.go | 2 +- .../fasthttp/strings.go | 29 +- .../fasthttp/tcpdialer.go | 251 +++---- .../fasthttp/timer.go | 14 +- .../fasthttp/uri.go | 2 +- .../fasthttp/uri_unix.go | 0 .../fasthttp/uri_windows.go | 0 .../fasthttp/userdata.go | 0 .../fasthttp/workerpool.go | 12 +- .../github.com/valyala/fasthttp/.travis.yml | 36 - vendor/github.com/valyala/fasthttp/README.md | 585 --------------- .../github.com/valyala/fasthttp/coarseTime.go | 13 - vendor/github.com/valyala/fasthttp/go.mod | 9 - vendor/github.com/valyala/fasthttp/go.sum | 10 - vendor/modules.txt | 8 +- 59 files changed, 738 insertions(+), 2483 deletions(-) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/.gitignore (100%) create mode 100644 vendor/github.com/VictoriaMetrics/fasthttp/.travis.yml rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/LICENSE (84%) create mode 100644 vendor/github.com/VictoriaMetrics/fasthttp/README.md rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/TODO (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/args.go (75%) create mode 100644 vendor/github.com/VictoriaMetrics/fasthttp/bytebuffer.go rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/bytesconv.go (91%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/bytesconv_32.go (80%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/bytesconv_64.go (78%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/client.go (83%) create mode 100644 vendor/github.com/VictoriaMetrics/fasthttp/coarseTime.go rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/compress.go (98%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/cookie.go (63%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/doc.go (85%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/doc.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/ecdsa.key (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/ecdsa.pem (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/inmemory_listener.go (78%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/pipeconns.go (98%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/rsa.key (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fasthttputil/rsa.pem (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/fs.go (97%) create mode 100644 vendor/github.com/VictoriaMetrics/fasthttp/go.mod create mode 100644 vendor/github.com/VictoriaMetrics/fasthttp/go.sum rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/header.go (82%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/http.go (94%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/lbclient.go (98%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/nocopy.go (64%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/peripconn.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/server.go (72%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/ssl-cert-snakeoil.key (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/ssl-cert-snakeoil.pem (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/stackless/doc.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/stackless/func.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/stackless/writer.go (99%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/status.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/stream.go (95%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/strings.go (77%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/tcpdialer.go (55%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/timer.go (53%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/uri.go (99%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/uri_unix.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/uri_windows.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/userdata.go (100%) rename vendor/github.com/{valyala => VictoriaMetrics}/fasthttp/workerpool.go (94%) delete mode 100644 vendor/github.com/valyala/fasthttp/.travis.yml delete mode 100644 vendor/github.com/valyala/fasthttp/README.md delete mode 100644 vendor/github.com/valyala/fasthttp/coarseTime.go delete mode 100644 vendor/github.com/valyala/fasthttp/go.mod delete mode 100644 vendor/github.com/valyala/fasthttp/go.sum diff --git a/app/vmagent/remotewrite/client.go b/app/vmagent/remotewrite/client.go index 44bc8152f..597067007 100644 --- a/app/vmagent/remotewrite/client.go +++ b/app/vmagent/remotewrite/client.go @@ -14,8 +14,8 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/persistentqueue" + "github.com/VictoriaMetrics/fasthttp" "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fasthttp" ) var ( diff --git a/app/vmagent/remotewrite/statconn.go b/app/vmagent/remotewrite/statconn.go index 19ee1e9b5..6507774ef 100644 --- a/app/vmagent/remotewrite/statconn.go +++ b/app/vmagent/remotewrite/statconn.go @@ -4,8 +4,8 @@ import ( "net" "sync/atomic" + "github.com/VictoriaMetrics/fasthttp" "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fasthttp" ) func statDial(addr string) (net.Conn, error) { diff --git a/go.mod b/go.mod index f3fe332e7..b2479111b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,10 @@ require ( cloud.google.com/go v0.56.0 // indirect cloud.google.com/go/storage v1.6.0 github.com/VictoriaMetrics/fastcache v1.5.7 + + // Do not use the original github.com/valyala/fasthttp because of issues + // like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b + github.com/VictoriaMetrics/fasthttp v1.0.1 github.com/VictoriaMetrics/metrics v1.11.2 github.com/VictoriaMetrics/metricsql v0.1.0 github.com/aws/aws-sdk-go v1.30.13 @@ -11,10 +15,6 @@ require ( github.com/golang/protobuf v1.4.0 // indirect github.com/golang/snappy v0.0.1 github.com/klauspost/compress v1.10.5 - - // do not update fasthttp releases because of issues like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b - // in the new code. - github.com/valyala/fasthttp v1.2.0 github.com/valyala/fastjson v1.5.1 github.com/valyala/fastrand v1.0.0 github.com/valyala/gozstd v1.7.0 diff --git a/go.sum b/go.sum index 2bcb0ef63..50f118d0b 100644 --- a/go.sum +++ b/go.sum @@ -7,26 +7,21 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0 h1:RPUcBvDeYgQFMfQu1eBMq6piD1SXmLH+vK3qjewZPus= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= @@ -36,6 +31,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VictoriaMetrics/fasthttp v1.0.1 h1:I7YdbswTIW63WxoFoUOSNxeOEGB46rdKULQhn+jt+AY= +github.com/VictoriaMetrics/fasthttp v1.0.1/go.mod h1:BqgsieH90PR7x97c89j+eqZDloKkDhAEQTwhLw6jw/4= github.com/VictoriaMetrics/metrics v1.11.2 h1:t/ceLP6SvagUqypCKU7cI7+tQn54+TIV/tGoxihHvx8= github.com/VictoriaMetrics/metrics v1.11.2/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= github.com/VictoriaMetrics/metricsql v0.1.0 h1:IoyG84PCwFY15rNuxpr2nQ+YZBYIhnd7zTiaGo5BNpc= @@ -63,10 +60,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -77,11 +72,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -95,7 +87,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -137,13 +128,11 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.2.0 h1:dzZJf2IuMiclVjdw0kkT+f9u4YdrapbNyGAN47E/qnk= github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= github.com/valyala/fastjson v1.5.1 h1:SXaQZVSwLjZOVhDEhjiCcDtnX0Feu7Z7A1+C5atpoHM= github.com/valyala/fastjson v1.5.1/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= @@ -160,7 +149,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -176,9 +164,7 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd h1:zkO/Lhoka23X63N9OSzpSeROEUQ5ODw47tM3YWjygbs= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -189,9 +175,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -199,7 +183,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= @@ -218,12 +201,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -238,7 +218,6 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -257,9 +236,7 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -315,12 +292,9 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0 h1:0q95w+VuFtv4PAx4PZVQdBMmYbaCHbnfKaEiDIcVyag= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0 h1:J1Pl9P2lnmYFSJvgs70DKELqHNh8CNWXPbud4njEE2s= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= @@ -328,7 +302,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -347,7 +320,6 @@ google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce h1:1mbrb1tUU+Zmt5C94IGKADBTJZjZXAd+BubWi7r9EiI= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -358,12 +330,9 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= @@ -377,7 +346,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -385,7 +353,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= diff --git a/lib/promscrape/client.go b/lib/promscrape/client.go index 0cfb34287..be665ccdc 100644 --- a/lib/promscrape/client.go +++ b/lib/promscrape/client.go @@ -8,8 +8,8 @@ import ( "time" "github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil" + "github.com/VictoriaMetrics/fasthttp" "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fasthttp" ) var ( @@ -46,17 +46,17 @@ func newClient(sw *ScrapeWork) *client { } } hc := &fasthttp.HostClient{ - Addr: host, - Name: "vm_promscrape", - Dial: statDial, - DialDualStack: netutil.TCP6Enabled(), - IsTLS: isTLS, - TLSConfig: tlsCfg, - MaxIdleConnDuration: 2 * sw.ScrapeInterval, - ReadTimeout: sw.ScrapeTimeout, - WriteTimeout: 10 * time.Second, - MaxResponseBodySize: *maxScrapeSize, - MaxIdemponentCallAttempts: 1, + Addr: host, + Name: "vm_promscrape", + Dial: statDial, + DialDualStack: netutil.TCP6Enabled(), + IsTLS: isTLS, + TLSConfig: tlsCfg, + MaxIdleConnDuration: 2 * sw.ScrapeInterval, + ReadTimeout: sw.ScrapeTimeout, + WriteTimeout: 10 * time.Second, + MaxResponseBodySize: *maxScrapeSize, + MaxIdempotentRequestAttempts: 1, } return &client{ hc: hc, diff --git a/lib/promscrape/discovery/kubernetes/api.go b/lib/promscrape/discovery/kubernetes/api.go index f32952a5f..9f6ae7db6 100644 --- a/lib/promscrape/discovery/kubernetes/api.go +++ b/lib/promscrape/discovery/kubernetes/api.go @@ -11,7 +11,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth" - "github.com/valyala/fasthttp" + "github.com/VictoriaMetrics/fasthttp" ) // apiConfig contains config for API server diff --git a/lib/promscrape/statconn.go b/lib/promscrape/statconn.go index 7909899c0..eaf44a54b 100644 --- a/lib/promscrape/statconn.go +++ b/lib/promscrape/statconn.go @@ -4,8 +4,8 @@ import ( "net" "sync/atomic" + "github.com/VictoriaMetrics/fasthttp" "github.com/VictoriaMetrics/metrics" - "github.com/valyala/fasthttp" ) func statDial(addr string) (net.Conn, error) { diff --git a/vendor/github.com/valyala/fasthttp/.gitignore b/vendor/github.com/VictoriaMetrics/fasthttp/.gitignore similarity index 100% rename from vendor/github.com/valyala/fasthttp/.gitignore rename to vendor/github.com/VictoriaMetrics/fasthttp/.gitignore diff --git a/vendor/github.com/VictoriaMetrics/fasthttp/.travis.yml b/vendor/github.com/VictoriaMetrics/fasthttp/.travis.yml new file mode 100644 index 000000000..3ed568b14 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/fasthttp/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - 1.9.x + - 1.8.x + +script: + # build test for supported platforms + - GOOS=linux go build + - GOOS=darwin go build + - GOOS=freebsd go build + - GOOS=windows go build + - GOARCH=386 go build + + # run tests on a standard platform + - go test -v ./... diff --git a/vendor/github.com/valyala/fasthttp/LICENSE b/vendor/github.com/VictoriaMetrics/fasthttp/LICENSE similarity index 84% rename from vendor/github.com/valyala/fasthttp/LICENSE rename to vendor/github.com/VictoriaMetrics/fasthttp/LICENSE index b098914af..22bf00cb4 100644 --- a/vendor/github.com/valyala/fasthttp/LICENSE +++ b/vendor/github.com/VictoriaMetrics/fasthttp/LICENSE @@ -1,9 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia -Copyright (c) 2018-present Kirill Danshin -Copyright (c) 2018-present Erik Dubbelboer -Copyright (c) 2018-present FastHTTP Authors +Copyright (c) 2015-2016 Aliaksandr Valialkin, VertaMedia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/VictoriaMetrics/fasthttp/README.md b/vendor/github.com/VictoriaMetrics/fasthttp/README.md new file mode 100644 index 000000000..2fe7f4074 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/fasthttp/README.md @@ -0,0 +1,5 @@ +Private copy of [fasthttp](https://github.com/valyala/fasthttp) for VictoriaMetrics usage. + +It contains only the functionality required for [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics). + +Do not use it in your own projects! diff --git a/vendor/github.com/valyala/fasthttp/TODO b/vendor/github.com/VictoriaMetrics/fasthttp/TODO similarity index 100% rename from vendor/github.com/valyala/fasthttp/TODO rename to vendor/github.com/VictoriaMetrics/fasthttp/TODO diff --git a/vendor/github.com/valyala/fasthttp/args.go b/vendor/github.com/VictoriaMetrics/fasthttp/args.go similarity index 75% rename from vendor/github.com/valyala/fasthttp/args.go rename to vendor/github.com/VictoriaMetrics/fasthttp/args.go index e5865cd2c..5d432f5f9 100644 --- a/vendor/github.com/valyala/fasthttp/args.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/args.go @@ -4,15 +4,7 @@ import ( "bytes" "errors" "io" - "sort" "sync" - - "github.com/valyala/bytebufferpool" -) - -const ( - argsNoValue = true - argsHasValue = false ) // AcquireArgs returns an empty Args object from the pool. @@ -23,7 +15,7 @@ func AcquireArgs() *Args { return argsPool.Get().(*Args) } -// ReleaseArgs returns the object acquired via AcquireArgs to the pool. +// ReleaseArgs returns the object acquired via AquireArgs to the pool. // // Do not access the released Args object, otherwise data races may occur. func ReleaseArgs(a *Args) { @@ -51,9 +43,8 @@ type Args struct { } type argsKV struct { - key []byte - value []byte - noValue bool + key []byte + value []byte } // Reset clears query args. @@ -116,29 +107,14 @@ func (a *Args) QueryString() []byte { return a.buf } -// Sort sorts Args by key and then value using 'f' as comparison function. -// -// For example args.Sort(bytes.Compare) -func (a *Args) Sort(f func(x, y []byte) int) { - sort.SliceStable(a.args, func(i, j int) bool { - n := f(a.args[i].key, a.args[j].key) - if n == 0 { - return f(a.args[i].value, a.args[j].value) == -1 - } - return n == -1 - }) -} - // AppendBytes appends query string to dst and returns the extended dst. func (a *Args) AppendBytes(dst []byte) []byte { for i, n := 0, len(a.args); i < n; i++ { kv := &a.args[i] dst = AppendQuotedArg(dst, kv.key) - if !kv.noValue { + if len(kv.value) > 0 { dst = append(dst, '=') - if len(kv.value) > 0 { - dst = AppendQuotedArg(dst, kv.value) - } + dst = AppendQuotedArg(dst, kv.value) } if i+1 < n { dst = append(dst, '&') @@ -169,74 +145,48 @@ func (a *Args) DelBytes(key []byte) { // // Multiple values for the same key may be added. func (a *Args) Add(key, value string) { - a.args = appendArg(a.args, key, value, argsHasValue) + a.args = appendArg(a.args, key, value) } // AddBytesK adds 'key=value' argument. // // Multiple values for the same key may be added. func (a *Args) AddBytesK(key []byte, value string) { - a.args = appendArg(a.args, b2s(key), value, argsHasValue) + a.args = appendArg(a.args, b2s(key), value) } // AddBytesV adds 'key=value' argument. // // Multiple values for the same key may be added. func (a *Args) AddBytesV(key string, value []byte) { - a.args = appendArg(a.args, key, b2s(value), argsHasValue) + a.args = appendArg(a.args, key, b2s(value)) } // AddBytesKV adds 'key=value' argument. // // Multiple values for the same key may be added. func (a *Args) AddBytesKV(key, value []byte) { - a.args = appendArg(a.args, b2s(key), b2s(value), argsHasValue) -} - -// AddNoValue adds only 'key' as argument without the '='. -// -// Multiple values for the same key may be added. -func (a *Args) AddNoValue(key string) { - a.args = appendArg(a.args, key, "", argsNoValue) -} - -// AddBytesKNoValue adds only 'key' as argument without the '='. -// -// Multiple values for the same key may be added. -func (a *Args) AddBytesKNoValue(key []byte) { - a.args = appendArg(a.args, b2s(key), "", argsNoValue) + a.args = appendArg(a.args, b2s(key), b2s(value)) } // Set sets 'key=value' argument. func (a *Args) Set(key, value string) { - a.args = setArg(a.args, key, value, argsHasValue) + a.args = setArg(a.args, key, value) } // SetBytesK sets 'key=value' argument. func (a *Args) SetBytesK(key []byte, value string) { - a.args = setArg(a.args, b2s(key), value, argsHasValue) + a.args = setArg(a.args, b2s(key), value) } // SetBytesV sets 'key=value' argument. func (a *Args) SetBytesV(key string, value []byte) { - a.args = setArg(a.args, key, b2s(value), argsHasValue) + a.args = setArg(a.args, key, b2s(value)) } // SetBytesKV sets 'key=value' argument. func (a *Args) SetBytesKV(key, value []byte) { - a.args = setArgBytes(a.args, key, value, argsHasValue) -} - -// SetNoValue sets only 'key' as argument without the '='. -// -// Only key in argumemt, like key1&key2 -func (a *Args) SetNoValue(key string) { - a.args = setArg(a.args, key, "", argsNoValue) -} - -// SetBytesKNoValue sets 'key' argument. -func (a *Args) SetBytesKNoValue(key []byte) { - a.args = setArg(a.args, b2s(key), "", argsNoValue) + a.args = setArgBytes(a.args, key, value) } // Peek returns query arg value for the given key. @@ -293,10 +243,10 @@ func (a *Args) GetUint(key string) (int, error) { // SetUint sets uint value for the given key. func (a *Args) SetUint(key string, value int) { - bb := bytebufferpool.Get() + bb := AcquireByteBuffer() bb.B = AppendUint(bb.B[:0], value) a.SetBytesV(key, bb.B) - bytebufferpool.Put(bb) + ReleaseByteBuffer(bb) } // SetUintBytes sets uint value for the given key. @@ -337,14 +287,11 @@ func (a *Args) GetUfloatOrZero(key string) float64 { // GetBool returns boolean value for the given key. // -// true is returned for "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes", +// true is returned for '1', 'y' and 'yes' values, // otherwise false is returned. func (a *Args) GetBool(key string) bool { - switch b2s(a.Peek(key)) { - // Support the same true cases as strconv.ParseBool - // See: https://github.com/golang/go/blob/4e1b11e2c9bdb0ddea1141eed487be1a626ff5be/src/strconv/atob.go#L12 - // and Y and Yes versions. - case "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes": + switch string(a.Peek(key)) { + case "1", "y", "yes": return true default: return false @@ -370,12 +317,7 @@ func copyArgs(dst, src []argsKV) []argsKV { dstKV := &dst[i] srcKV := &src[i] dstKV.key = append(dstKV.key[:0], srcKV.key...) - if srcKV.noValue { - dstKV.value = dstKV.value[:0] - } else { - dstKV.value = append(dstKV.value[:0], srcKV.value...) - } - dstKV.noValue = srcKV.noValue + dstKV.value = append(dstKV.value[:0], srcKV.value...) } return dst } @@ -398,41 +340,31 @@ func delAllArgs(args []argsKV, key string) []argsKV { return args } -func setArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV { - return setArg(h, b2s(key), b2s(value), noValue) +func setArgBytes(h []argsKV, key, value []byte) []argsKV { + return setArg(h, b2s(key), b2s(value)) } -func setArg(h []argsKV, key, value string, noValue bool) []argsKV { +func setArg(h []argsKV, key, value string) []argsKV { n := len(h) for i := 0; i < n; i++ { kv := &h[i] if key == string(kv.key) { - if noValue { - kv.value = kv.value[:0] - } else { - kv.value = append(kv.value[:0], value...) - } - kv.noValue = noValue + kv.value = append(kv.value[:0], value...) return h } } - return appendArg(h, key, value, noValue) + return appendArg(h, key, value) } -func appendArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV { - return appendArg(h, b2s(key), b2s(value), noValue) +func appendArgBytes(h []argsKV, key, value []byte) []argsKV { + return appendArg(h, b2s(key), b2s(value)) } -func appendArg(args []argsKV, key, value string, noValue bool) []argsKV { +func appendArg(args []argsKV, key, value string) []argsKV { var kv *argsKV args, kv = allocArg(args) kv.key = append(kv.key[:0], key...) - if noValue { - kv.value = kv.value[:0] - } else { - kv.value = append(kv.value[:0], value...) - } - kv.noValue = noValue + kv.value = append(kv.value[:0], value...) return args } @@ -488,7 +420,6 @@ func (s *argsScanner) next(kv *argsKV) bool { if len(s.b) == 0 { return false } - kv.noValue = argsHasValue isKey := true k := 0 @@ -504,7 +435,6 @@ func (s *argsScanner) next(kv *argsKV) bool { if isKey { kv.key = decodeArgAppend(kv.key[:0], s.b[:i]) kv.value = kv.value[:0] - kv.noValue = argsNoValue } else { kv.value = decodeArgAppend(kv.value[:0], s.b[k:i]) } @@ -516,7 +446,6 @@ func (s *argsScanner) next(kv *argsKV) bool { if isKey { kv.key = decodeArgAppend(kv.key[:0], s.b) kv.value = kv.value[:0] - kv.noValue = argsNoValue } else { kv.value = decodeArgAppend(kv.value[:0], s.b[k:]) } @@ -557,7 +486,7 @@ func decodeArgAppend(dst, src []byte) []byte { // decodeArgAppendNoPlus is almost identical to decodeArgAppend, but it doesn't // substitute '+' with ' '. // -// The function is copy-pasted from decodeArgAppend due to the performance +// The function is copy-pasted from decodeArgAppend due to the preformance // reasons only. func decodeArgAppendNoPlus(dst, src []byte) []byte { if bytes.IndexByte(src, '%') < 0 { diff --git a/vendor/github.com/VictoriaMetrics/fasthttp/bytebuffer.go b/vendor/github.com/VictoriaMetrics/fasthttp/bytebuffer.go new file mode 100644 index 000000000..f9651722d --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/fasthttp/bytebuffer.go @@ -0,0 +1,64 @@ +package fasthttp + +import ( + "github.com/valyala/bytebufferpool" +) + +// ByteBuffer provides byte buffer, which can be used with fasthttp API +// in order to minimize memory allocations. +// +// ByteBuffer may be used with functions appending data to the given []byte +// slice. See example code for details. +// +// Use AcquireByteBuffer for obtaining an empty byte buffer. +// +// ByteBuffer is deprecated. Use github.com/valyala/bytebufferpool instead. +type ByteBuffer bytebufferpool.ByteBuffer + +// Write implements io.Writer - it appends p to ByteBuffer.B +func (b *ByteBuffer) Write(p []byte) (int, error) { + return bb(b).Write(p) +} + +// WriteString appends s to ByteBuffer.B +func (b *ByteBuffer) WriteString(s string) (int, error) { + return bb(b).WriteString(s) +} + +// Set sets ByteBuffer.B to p +func (b *ByteBuffer) Set(p []byte) { + bb(b).Set(p) +} + +// SetString sets ByteBuffer.B to s +func (b *ByteBuffer) SetString(s string) { + bb(b).SetString(s) +} + +// Reset makes ByteBuffer.B empty. +func (b *ByteBuffer) Reset() { + bb(b).Reset() +} + +// AcquireByteBuffer returns an empty byte buffer from the pool. +// +// Acquired byte buffer may be returned to the pool via ReleaseByteBuffer call. +// This reduces the number of memory allocations required for byte buffer +// management. +func AcquireByteBuffer() *ByteBuffer { + return (*ByteBuffer)(defaultByteBufferPool.Get()) +} + +// ReleaseByteBuffer returns byte buffer to the pool. +// +// ByteBuffer.B mustn't be touched after returning it to the pool. +// Otherwise data races occur. +func ReleaseByteBuffer(b *ByteBuffer) { + defaultByteBufferPool.Put(bb(b)) +} + +func bb(b *ByteBuffer) *bytebufferpool.ByteBuffer { + return (*bytebufferpool.ByteBuffer)(b) +} + +var defaultByteBufferPool bytebufferpool.Pool diff --git a/vendor/github.com/valyala/fasthttp/bytesconv.go b/vendor/github.com/VictoriaMetrics/fasthttp/bytesconv.go similarity index 91% rename from vendor/github.com/valyala/fasthttp/bytesconv.go rename to vendor/github.com/VictoriaMetrics/fasthttp/bytesconv.go index 8c0e1545d..004d28dc2 100644 --- a/vendor/github.com/valyala/fasthttp/bytesconv.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/bytesconv.go @@ -164,7 +164,7 @@ func ParseUint(buf []byte) (int, error) { var ( errEmptyInt = errors.New("empty integer") errUnexpectedFirstChar = errors.New("unexpected first char found. Expecting 0-9") - errUnexpectedTrailingChar = errors.New("unexpected trailing char found. Expecting 0-9") + errUnexpectedTrailingChar = errors.New("unexpected traling char found. Expecting 0-9") errTooLongInt = errors.New("too long int") ) @@ -183,8 +183,7 @@ func parseUintBuf(b []byte) (int, int, error) { } return v, i, nil } - // Test for overflow. - if v*10 < v { + if i >= maxIntChars { return -1, i, errTooLongInt } v = 10*v + int(k) @@ -417,17 +416,8 @@ func AppendQuotedArg(dst, src []byte) []byte { func appendQuotedPath(dst, src []byte) []byte { for _, c := range src { - // From the spec: http://tools.ietf.org/html/rfc3986#section-3.3 - // an path can contain zero or more of pchar that is defined as follows: - // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - // pct-encoded = "%" HEXDIG HEXDIG - // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - // / "*" / "+" / "," / ";" / "=" if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || - c == '-' || c == '.' || c == '_' || c == '~' || c == '!' || c == '$' || - c == '&' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || - c == ',' || c == ';' || c == '=' || c == ':' || c == '@' || c == '/' { + c == '/' || c == '.' || c == ',' || c == '=' || c == ':' || c == '&' || c == '~' || c == '-' || c == '_' { dst = append(dst, c) } else { dst = append(dst, '%', hexCharUpper(c>>4), hexCharUpper(c&15)) @@ -435,3 +425,23 @@ func appendQuotedPath(dst, src []byte) []byte { } return dst } + +// EqualBytesStr returns true if string(b) == s. +// +// This function has no performance benefits comparing to string(b) == s. +// It is left here for backwards compatibility only. +// +// This function is deperecated and may be deleted soon. +func EqualBytesStr(b []byte, s string) bool { + return string(b) == s +} + +// AppendBytesStr appends src to dst and returns the extended dst. +// +// This function has no performance benefits comparing to append(dst, src...). +// It is left here for backwards compatibility only. +// +// This function is deprecated and may be deleted soon. +func AppendBytesStr(dst []byte, src string) []byte { + return append(dst, src...) +} diff --git a/vendor/github.com/valyala/fasthttp/bytesconv_32.go b/vendor/github.com/VictoriaMetrics/fasthttp/bytesconv_32.go similarity index 80% rename from vendor/github.com/valyala/fasthttp/bytesconv_32.go rename to vendor/github.com/VictoriaMetrics/fasthttp/bytesconv_32.go index 7fd6f5f12..143775474 100644 --- a/vendor/github.com/valyala/fasthttp/bytesconv_32.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/bytesconv_32.go @@ -3,5 +3,6 @@ package fasthttp const ( + maxIntChars = 9 maxHexIntChars = 7 ) diff --git a/vendor/github.com/valyala/fasthttp/bytesconv_64.go b/vendor/github.com/VictoriaMetrics/fasthttp/bytesconv_64.go similarity index 78% rename from vendor/github.com/valyala/fasthttp/bytesconv_64.go rename to vendor/github.com/VictoriaMetrics/fasthttp/bytesconv_64.go index edf7309c2..09d07ef10 100644 --- a/vendor/github.com/valyala/fasthttp/bytesconv_64.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/bytesconv_64.go @@ -3,5 +3,6 @@ package fasthttp const ( + maxIntChars = 18 maxHexIntChars = 15 ) diff --git a/vendor/github.com/valyala/fasthttp/client.go b/vendor/github.com/VictoriaMetrics/fasthttp/client.go similarity index 83% rename from vendor/github.com/valyala/fasthttp/client.go rename to vendor/github.com/VictoriaMetrics/fasthttp/client.go index 89e98082d..3070c5744 100644 --- a/vendor/github.com/valyala/fasthttp/client.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/client.go @@ -60,11 +60,6 @@ func Do(req *Request, resp *Response) error { // // It is recommended obtaining req and resp via AcquireRequest // and AcquireResponse in performance-critical code. -// -// Warning: DoTimeout does not terminate the request itself. The request will -// continue in the background and the response will be discarded. -// If requests take too long and the connection pool gets filled up please -// try using a Client and setting a ReadTimeout. func DoTimeout(req *Request, resp *Response, timeout time.Duration) error { return defaultClient.DoTimeout(req, resp, timeout) } @@ -96,36 +91,33 @@ func DoDeadline(req *Request, resp *Response, deadline time.Time) error { return defaultClient.DoDeadline(req, resp, deadline) } -// Get returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// Get appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. +// +// New body buffer is allocated if dst is nil. func Get(dst []byte, url string) (statusCode int, body []byte, err error) { return defaultClient.Get(dst, url) } -// GetTimeout returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// GetTimeout appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // ErrTimeout error is returned if url contents couldn't be fetched // during the given timeout. func GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) { return defaultClient.GetTimeout(dst, url, timeout) } -// GetDeadline returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// GetDeadline appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // ErrTimeout error is returned if url contents couldn't be fetched // until the given deadline. func GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) { @@ -134,11 +126,12 @@ func GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, bo // Post sends POST request to the given url with the given POST arguments. // -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// Response body is appended to dst, which is returned as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // Empty POST body is sent if postArgs is nil. func Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) { return defaultClient.Post(dst, url, postArgs) @@ -159,10 +152,6 @@ type Client struct { // Default client name is used if not set. Name string - // NoDefaultUserAgentHeader when set to true, causes the default - // User-Agent header to be excluded from the Request. - NoDefaultUserAgentHeader bool - // Callback for establishing new connections to hosts. // // Default Dial is used if not set. @@ -193,11 +182,6 @@ type Client struct { // after DefaultMaxIdleConnDuration. MaxIdleConnDuration time.Duration - // Maximum number of attempts for idempotent calls - // - // DefaultMaxIdemponentCallAttempts is used if not set. - MaxIdemponentCallAttempts int - // Per-connection buffer size for responses' reading. // This also limits the maximum header size. // @@ -227,59 +211,41 @@ type Client struct { // By default response body size is unlimited. MaxResponseBodySize int - // Header names are passed as-is without normalization - // if this option is set. - // - // Disabled header names' normalization may be useful only for proxying - // responses to other clients expecting case-sensitive - // header names. See https://github.com/valyala/fasthttp/issues/57 - // for details. - // - // By default request and response header names are normalized, i.e. - // The first letter and the first letters following dashes - // are uppercased, while all the other letters are lowercased. - // Examples: - // - // * HOST -> Host - // * content-type -> Content-Type - // * cONTENT-lenGTH -> Content-Length - DisableHeaderNamesNormalizing bool + // The maximum number of idempotent requests the client can make. + MaxIdempotentRequestAttempts int mLock sync.Mutex m map[string]*HostClient ms map[string]*HostClient } -// Get returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// Get appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. +// +// New body buffer is allocated if dst is nil. func (c *Client) Get(dst []byte, url string) (statusCode int, body []byte, err error) { return clientGetURL(dst, url, c) } -// GetTimeout returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// GetTimeout appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // ErrTimeout error is returned if url contents couldn't be fetched // during the given timeout. func (c *Client) GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) { return clientGetURLTimeout(dst, url, timeout, c) } -// GetDeadline returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// GetDeadline appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // ErrTimeout error is returned if url contents couldn't be fetched // until the given deadline. func (c *Client) GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) { @@ -288,11 +254,12 @@ func (c *Client) GetDeadline(dst []byte, url string, deadline time.Time) (status // Post sends POST request to the given url with the given POST arguments. // -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// Response body is appended to dst, which is returned as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // Empty POST body is sent if postArgs is nil. func (c *Client) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) { return clientPostURL(dst, url, postArgs, c) @@ -321,11 +288,6 @@ func (c *Client) Post(dst []byte, url string, postArgs *Args) (statusCode int, b // // It is recommended obtaining req and resp via AcquireRequest // and AcquireResponse in performance-critical code. -// -// Warning: DoTimeout does not terminate the request itself. The request will -// continue in the background and the response will be discarded. -// If requests take too long and the connection pool gets filled up please -// try setting a ReadTimeout. func (c *Client) DoTimeout(req *Request, resp *Response, timeout time.Duration) error { return clientDoTimeout(req, resp, timeout, c) } @@ -406,22 +368,20 @@ func (c *Client) Do(req *Request, resp *Response) error { hc := m[string(host)] if hc == nil { hc = &HostClient{ - Addr: addMissingPort(string(host), isTLS), - Name: c.Name, - NoDefaultUserAgentHeader: c.NoDefaultUserAgentHeader, - Dial: c.Dial, - DialDualStack: c.DialDualStack, - IsTLS: isTLS, - TLSConfig: c.TLSConfig, - MaxConns: c.MaxConnsPerHost, - MaxIdleConnDuration: c.MaxIdleConnDuration, - MaxIdemponentCallAttempts: c.MaxIdemponentCallAttempts, - ReadBufferSize: c.ReadBufferSize, - WriteBufferSize: c.WriteBufferSize, - ReadTimeout: c.ReadTimeout, - WriteTimeout: c.WriteTimeout, - MaxResponseBodySize: c.MaxResponseBodySize, - DisableHeaderNamesNormalizing: c.DisableHeaderNamesNormalizing, + Addr: addMissingPort(string(host), isTLS), + Name: c.Name, + Dial: c.Dial, + DialDualStack: c.DialDualStack, + IsTLS: isTLS, + TLSConfig: c.TLSConfig, + MaxConns: c.MaxConnsPerHost, + MaxIdleConnDuration: c.MaxIdleConnDuration, + ReadBufferSize: c.ReadBufferSize, + WriteBufferSize: c.WriteBufferSize, + ReadTimeout: c.ReadTimeout, + WriteTimeout: c.WriteTimeout, + MaxResponseBodySize: c.MaxResponseBodySize, + MaxIdempotentRequestAttempts: c.MaxIdempotentRequestAttempts, } m[string(host)] = hc if len(m) == 1 { @@ -439,15 +399,11 @@ func (c *Client) Do(req *Request, resp *Response) error { func (c *Client) mCleaner(m map[string]*HostClient) { mustStop := false - for { + t := time.Now() c.mLock.Lock() for k, v := range m { - v.connsLock.Lock() - shouldRemove := v.connsCount == 0 - v.connsLock.Unlock() - - if shouldRemove { + if t.Sub(v.LastUseTime()) > time.Minute { delete(m, k) } } @@ -472,9 +428,6 @@ const DefaultMaxConnsPerHost = 512 // connection is closed. const DefaultMaxIdleConnDuration = 10 * time.Second -// DefaultMaxIdemponentCallAttempts is the default idempotent calls attempts count. -const DefaultMaxIdemponentCallAttempts = 5 - // DialFunc must establish connection to addr. // // There is no need in establishing TLS (SSL) connection for https. @@ -516,10 +469,6 @@ type HostClient struct { // Client name. Used in User-Agent request header. Name string - // NoDefaultUserAgentHeader when set to true, causes the default - // User-Agent header to be excluded from the Request. - NoDefaultUserAgentHeader bool - // Callback for establishing new connection to the host. // // Default Dial is used if not set. @@ -544,9 +493,6 @@ type HostClient struct { // Maximum number of connections which may be established to all hosts // listed in Addr. // - // You can change this value while the HostClient is being used - // using HostClient.SetMaxConns(value) - // // DefaultMaxConnsPerHost is used if not set. MaxConns int @@ -561,11 +507,6 @@ type HostClient struct { // after DefaultMaxIdleConnDuration. MaxIdleConnDuration time.Duration - // Maximum number of attempts for idempotent calls - // - // DefaultMaxIdemponentCallAttempts is used if not set. - MaxIdemponentCallAttempts int - // Per-connection buffer size for responses' reading. // This also limits the maximum header size. // @@ -595,23 +536,8 @@ type HostClient struct { // By default response body size is unlimited. MaxResponseBodySize int - // Header names are passed as-is without normalization - // if this option is set. - // - // Disabled header names' normalization may be useful only for proxying - // responses to other clients expecting case-sensitive - // header names. See https://github.com/valyala/fasthttp/issues/57 - // for details. - // - // By default request and response header names are normalized, i.e. - // The first letter and the first letters following dashes - // are uppercased, while all the other letters are lowercased. - // Examples: - // - // * HOST -> Host - // * content-type -> Content-Type - // * cONTENT-lenGTH -> Content-Length - DisableHeaderNamesNormalizing bool + // The maximum number of idempotent requests the client can make. + MaxIdempotentRequestAttempts int clientName atomic.Value lastUseTime uint32 @@ -630,7 +556,7 @@ type HostClient struct { readerPool sync.Pool writerPool sync.Pool - pendingRequests int32 + pendingRequests uint64 connsCleanerRun bool } @@ -640,6 +566,9 @@ type clientConn struct { createdTime time.Time lastUseTime time.Time + + lastReadDeadlineTime time.Time + lastWriteDeadlineTime time.Time } var startTimeUnix = time.Now().Unix() @@ -650,36 +579,33 @@ func (c *HostClient) LastUseTime() time.Time { return time.Unix(startTimeUnix+int64(n), 0) } -// Get returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// Get appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. +// +// New body buffer is allocated if dst is nil. func (c *HostClient) Get(dst []byte, url string) (statusCode int, body []byte, err error) { return clientGetURL(dst, url, c) } -// GetTimeout returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// GetTimeout appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // ErrTimeout error is returned if url contents couldn't be fetched // during the given timeout. func (c *HostClient) GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) { return clientGetURLTimeout(dst, url, timeout, c) } -// GetDeadline returns the status code and body of url. -// -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// GetDeadline appends url contents to dst and returns it as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // ErrTimeout error is returned if url contents couldn't be fetched // until the given deadline. func (c *HostClient) GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) { @@ -688,11 +614,12 @@ func (c *HostClient) GetDeadline(dst []byte, url string, deadline time.Time) (st // Post sends POST request to the given url with the given POST arguments. // -// The contents of dst will be replaced by the body and returned, if the dst -// is too small a new slice will be allocated. +// Response body is appended to dst, which is returned as body. // // The function follows redirects. Use Do* for manually handling redirects. // +// New body buffer is allocated if dst is nil. +// // Empty POST body is sent if postArgs is nil. func (c *HostClient) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) { return clientPostURL(dst, url, postArgs, c) @@ -753,7 +680,7 @@ func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c clientDo } }() - tc := AcquireTimer(timeout) + tc := acquireTimer(timeout) select { case resp := <-ch: ReleaseRequest(req) @@ -765,7 +692,7 @@ func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c clientDo body = dst err = ErrTimeout } - ReleaseTimer(tc) + releaseTimer(tc) return statusCode, body, err } @@ -799,24 +726,9 @@ func doRequestFollowRedirects(req *Request, dst []byte, url string, c clientDoer resp.keepBodyBuffer = true oldBody := bodyBuf.B bodyBuf.B = dst - scheme := req.uri.Scheme() - req.schemaUpdate = false redirectsCount := 0 for { - // In case redirect to different scheme - if redirectsCount > 0 && !bytes.Equal(scheme, req.uri.Scheme()) { - if strings.HasPrefix(url, string(strHTTPS)) { - req.isTLS = true - req.uri.SetSchemeBytes(strHTTPS) - } else { - req.isTLS = false - req.uri.SetSchemeBytes(strHTTP) - } - scheme = req.uri.Scheme() - req.schemaUpdate = true - } - req.parsedURI = false req.Header.host = req.Header.host[:0] req.SetRequestURI(url) @@ -825,11 +737,7 @@ func doRequestFollowRedirects(req *Request, dst []byte, url string, c clientDoer break } statusCode = resp.Header.StatusCode() - if statusCode != StatusMovedPermanently && - statusCode != StatusFound && - statusCode != StatusSeeOther && - statusCode != StatusTemporaryRedirect && - statusCode != StatusPermanentRedirect { + if statusCode != StatusMovedPermanently && statusCode != StatusFound && statusCode != StatusSeeOther { break } @@ -930,11 +838,6 @@ func ReleaseResponse(resp *Response) { // // It is recommended obtaining req and resp via AcquireRequest // and AcquireResponse in performance-critical code. -// -// Warning: DoTimeout does not terminate the request itself. The request will -// continue in the background and the response will be discarded. -// If requests take too long and the connection pool gets filled up please -// try setting a ReadTimeout. func (c *HostClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error { return clientDoTimeout(req, resp, timeout, c) } @@ -985,9 +888,6 @@ func clientDoDeadline(req *Request, resp *Response, deadline time.Time, c client req.copyToSkipBody(reqCopy) swapRequestBody(req, reqCopy) respCopy := AcquireResponse() - // Not calling resp.copyToSkipBody(respCopy) here to avoid - // unexpected messing with headers - respCopy.SkipBody = resp.SkipBody // Note that the request continues execution on ErrTimeout until // client-specific ReadTimeout exceeds. This helps limiting load @@ -996,20 +896,11 @@ func clientDoDeadline(req *Request, resp *Response, deadline time.Time, c client // Without this 'hack' the load on slow host could exceed MaxConns* // concurrent requests, since timed out requests on client side // usually continue execution on the host. - - var cleanup int32 go func() { - errDo := c.Do(reqCopy, respCopy) - if atomic.LoadInt32(&cleanup) == 1 { - ReleaseResponse(respCopy) - ReleaseRequest(reqCopy) - errorChPool.Put(chv) - } else { - ch <- errDo - } + ch <- c.Do(reqCopy, respCopy) }() - tc := AcquireTimer(timeout) + tc := acquireTimer(timeout) var err error select { case err = <-ch: @@ -1022,10 +913,9 @@ func clientDoDeadline(req *Request, resp *Response, deadline time.Time, c client ReleaseRequest(reqCopy) errorChPool.Put(chv) case <-tc.C: - atomic.StoreInt32(&cleanup, 1) err = ErrTimeout } - ReleaseTimer(tc) + releaseTimer(tc) return err } @@ -1049,13 +939,13 @@ var errorChPool sync.Pool func (c *HostClient) Do(req *Request, resp *Response) error { var err error var retry bool - maxAttempts := c.MaxIdemponentCallAttempts + maxAttempts := c.MaxIdempotentRequestAttempts if maxAttempts <= 0 { - maxAttempts = DefaultMaxIdemponentCallAttempts + maxAttempts = 5 } attempts := 0 - atomic.AddInt32(&c.pendingRequests, 1) + atomic.AddUint64(&c.pendingRequests, 1) for { retry, err = c.do(req, resp) if err == nil || !retry { @@ -1079,7 +969,7 @@ func (c *HostClient) Do(req *Request, resp *Response) error { break } } - atomic.AddInt32(&c.pendingRequests, -1) + atomic.AddUint64(&c.pendingRequests, ^uint64(0)) if err == io.EOF { err = ErrConnectionClosed @@ -1093,7 +983,7 @@ func (c *HostClient) Do(req *Request, resp *Response) error { // This function may be used for balancing load among multiple HostClient // instances. func (c *HostClient) PendingRequests() int { - return int(atomic.LoadInt32(&c.pendingRequests)) + return int(atomic.LoadUint64(&c.pendingRequests)) } func isIdempotent(req *Request) bool { @@ -1124,37 +1014,29 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) panic("BUG: resp cannot be nil") } - atomic.StoreUint32(&c.lastUseTime, uint32(time.Now().Unix()-startTimeUnix)) + atomic.StoreUint32(&c.lastUseTime, uint32(CoarseTimeNow().Unix()-startTimeUnix)) // Free up resources occupied by response before sending the request, // so the GC may reclaim these resources (e.g. response body). resp.Reset() - // If we detected a redirect to another schema - if req.schemaUpdate { - c.IsTLS = bytes.Equal(req.URI().Scheme(), strHTTPS) - c.Addr = addMissingPort(string(req.Host()), c.IsTLS) - c.addrIdx = 0 - c.addrs = nil - req.schemaUpdate = false - req.SetConnectionClose() - } - cc, err := c.acquireConn() if err != nil { return false, err } conn := cc.c - resp.parseNetConn(conn) - if c.WriteTimeout > 0 { - // Set Deadline every time, since golang has fixed the performance issue - // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details - currentTime := time.Now() - if err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)); err != nil { - c.closeConn(cc) - return true, err + // Optimization: update write deadline only if more than 25% + // of the last write deadline exceeded. + // See https://github.com/golang/go/issues/15133 for details. + currentTime := CoarseTimeNow() + if currentTime.Sub(cc.lastWriteDeadlineTime) > (c.WriteTimeout >> 2) { + if err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)); err != nil { + c.closeConn(cc) + return true, err + } + cc.lastWriteDeadlineTime = currentTime } } @@ -1170,6 +1052,9 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) } bw := c.acquireWriter(conn) err = req.Write(bw) + if len(userAgentOld) == 0 { + req.Header.userAgent = userAgentOld + } if resetConnection { req.Header.ResetConnectionClose() @@ -1186,29 +1071,28 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) c.releaseWriter(bw) if c.ReadTimeout > 0 { - // Set Deadline every time, since golang has fixed the performance issue - // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details - currentTime := time.Now() - if err = conn.SetReadDeadline(currentTime.Add(c.ReadTimeout)); err != nil { - c.closeConn(cc) - return true, err + // Optimization: update read deadline only if more than 25% + // of the last read deadline exceeded. + // See https://github.com/golang/go/issues/15133 for details. + currentTime := CoarseTimeNow() + if currentTime.Sub(cc.lastReadDeadlineTime) > (c.ReadTimeout >> 2) { + if err = conn.SetReadDeadline(currentTime.Add(c.ReadTimeout)); err != nil { + c.closeConn(cc) + return true, err + } + cc.lastReadDeadlineTime = currentTime } } if !req.Header.IsGet() && req.Header.IsHead() { resp.SkipBody = true } - if c.DisableHeaderNamesNormalizing { - resp.Header.DisableNormalizing() - } br := c.acquireReader(conn) if err = resp.ReadLimitBody(br, c.MaxResponseBodySize); err != nil { c.releaseReader(br) c.closeConn(cc) - // Don't retry in case of ErrBodyTooLarge since we will just get the same again. - retry := err != ErrBodyTooLarge - return retry, err + return true, err } c.releaseReader(br) @@ -1243,12 +1127,6 @@ var ( "Make sure the server returns 'Connection: close' response header before closing the connection") ) -func (c *HostClient) SetMaxConns(newMaxConns int) { - c.connsLock.Lock() - c.MaxConns = newMaxConns - c.connsLock.Unlock() -} - func (c *HostClient) acquireConn() (*clientConn, error) { var cc *clientConn createConn := false @@ -1318,12 +1196,6 @@ func (c *HostClient) connsCleaner() { for i < n && currentTime.Sub(conns[i].lastUseTime) > maxIdleConnDuration { i++ } - sleepFor := maxIdleConnDuration - if i < n { - // + 1 so we actually sleep past the expiration time and not up to it. - // Otherwise the > check above would still fail. - sleepFor = maxIdleConnDuration - currentTime.Sub(conns[i].lastUseTime) + 1 - } scratch = append(scratch[:0], conns[:i]...) if i > 0 { m := copy(conns, conns[i:]) @@ -1351,7 +1223,7 @@ func (c *HostClient) connsCleaner() { break } - time.Sleep(sleepFor) + time.Sleep(maxIdleConnDuration) } } @@ -1374,20 +1246,19 @@ func acquireClientConn(conn net.Conn) *clientConn { } cc := v.(*clientConn) cc.c = conn - cc.createdTime = time.Now() + cc.createdTime = CoarseTimeNow() return cc } func releaseClientConn(cc *clientConn) { - // Reset all fields. - *cc = clientConn{} + cc.c = nil clientConnPool.Put(cc) } var clientConnPool sync.Pool func (c *HostClient) releaseConn(cc *clientConn) { - cc.lastUseTime = time.Now() + cc.lastUseTime = CoarseTimeNow() c.connsLock.Lock() c.conns = append(c.conns, cc) c.connsLock.Unlock() @@ -1581,7 +1452,7 @@ func (c *HostClient) getClientName() []byte { var clientName []byte if v == nil { clientName = []byte(c.Name) - if len(clientName) == 0 && !c.NoDefaultUserAgentHeader { + if len(clientName) == 0 { clientName = defaultUserAgent } c.clientName.Store(clientName) @@ -1623,7 +1494,7 @@ type PipelineClient struct { // The maximum number of concurrent connections to the Addr. // - // A single connection is used by default. + // A sinle connection is used by default. MaxConns int // The maximum number of pending pipelined requests over @@ -1748,11 +1619,6 @@ type pipelineWork struct { // // It is recommended obtaining req and resp via AcquireRequest // and AcquireResponse in performance-critical code. -// -// Warning: DoTimeout does not terminate the request itself. The request will -// continue in the background and the response will be discarded. -// If requests take too long and the connection pool gets filled up please -// try setting a ReadTimeout. func (c *PipelineClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error { return c.DoDeadline(req, resp, time.Now().Add(timeout)) } @@ -2058,6 +1924,8 @@ func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error w *pipelineWork err error + + lastWriteDeadlineTime time.Time ) close(instantTimerCh) for { @@ -2089,16 +1957,18 @@ func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error continue } - w.resp.parseNetConn(conn) - if writeTimeout > 0 { - // Set Deadline every time, since golang has fixed the performance issue - // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details - currentTime := time.Now() - if err = conn.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil { - w.err = err - w.done <- struct{}{} - return err + // Optimization: update write deadline only if more than 25% + // of the last write deadline exceeded. + // See https://github.com/golang/go/issues/15133 for details. + currentTime := CoarseTimeNow() + if currentTime.Sub(lastWriteDeadlineTime) > (writeTimeout >> 2) { + if err = conn.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil { + w.err = err + w.done <- struct{}{} + return err + } + lastWriteDeadlineTime = currentTime } } if err = w.req.Write(bw); err != nil { @@ -2152,6 +2022,8 @@ func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error var ( w *pipelineWork err error + + lastReadDeadlineTime time.Time ) for { select { @@ -2167,13 +2039,17 @@ func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error } if readTimeout > 0 { - // Set Deadline every time, since golang has fixed the performance issue - // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details - currentTime := time.Now() - if err = conn.SetReadDeadline(currentTime.Add(readTimeout)); err != nil { - w.err = err - w.done <- struct{}{} - return err + // Optimization: update read deadline only if more than 25% + // of the last read deadline exceeded. + // See https://github.com/golang/go/issues/15133 for details. + currentTime := CoarseTimeNow() + if currentTime.Sub(lastReadDeadlineTime) > (readTimeout >> 2) { + if err = conn.SetReadDeadline(currentTime.Add(readTimeout)); err != nil { + w.err = err + w.done <- struct{}{} + return err + } + lastReadDeadlineTime = currentTime } } if err = w.resp.Read(br); err != nil { diff --git a/vendor/github.com/VictoriaMetrics/fasthttp/coarseTime.go b/vendor/github.com/VictoriaMetrics/fasthttp/coarseTime.go new file mode 100644 index 000000000..03c14f39a --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/fasthttp/coarseTime.go @@ -0,0 +1,28 @@ +package fasthttp + +import ( + "sync/atomic" + "time" +) + +// CoarseTimeNow returns the current time truncated to the nearest second. +// +// This is a faster alternative to time.Now(). +func CoarseTimeNow() time.Time { + tp := coarseTime.Load().(*time.Time) + return *tp +} + +func init() { + t := time.Now().Truncate(time.Second) + coarseTime.Store(&t) + go func() { + for { + time.Sleep(time.Second) + t := time.Now().Truncate(time.Second) + coarseTime.Store(&t) + } + }() +} + +var coarseTime atomic.Value diff --git a/vendor/github.com/valyala/fasthttp/compress.go b/vendor/github.com/VictoriaMetrics/fasthttp/compress.go similarity index 98% rename from vendor/github.com/valyala/fasthttp/compress.go rename to vendor/github.com/VictoriaMetrics/fasthttp/compress.go index 73a40d3bd..ed2e0ad33 100644 --- a/vendor/github.com/valyala/fasthttp/compress.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/compress.go @@ -7,11 +7,11 @@ import ( "os" "sync" + "github.com/VictoriaMetrics/fasthttp/stackless" "github.com/klauspost/compress/flate" "github.com/klauspost/compress/gzip" "github.com/klauspost/compress/zlib" "github.com/valyala/bytebufferpool" - "github.com/valyala/fasthttp/stackless" ) // Supported compression levels. @@ -152,6 +152,7 @@ func WriteGzipLevel(w io.Writer, p []byte, level int) (int, error) { switch w.(type) { case *byteSliceWriter, *bytes.Buffer, + *ByteBuffer, *bytebufferpool.ByteBuffer: // These writers don't block, so we can just use stacklessWriteGzip ctx := &compressCtx{ @@ -248,6 +249,7 @@ func WriteDeflateLevel(w io.Writer, p []byte, level int) (int, error) { switch w.(type) { case *byteSliceWriter, *bytes.Buffer, + *ByteBuffer, *bytebufferpool.ByteBuffer: // These writers don't block, so we can just use stacklessWriteDeflate ctx := &compressCtx{ @@ -407,7 +409,7 @@ func isFileCompressible(f *os.File, minCompressRatio float64) bool { // Try compressing the first 4kb of of the file // and see if it can be compressed by more than // the given minCompressRatio. - b := bytebufferpool.Get() + b := AcquireByteBuffer() zw := acquireStacklessGzipWriter(b, CompressDefaultCompression) lr := &io.LimitedReader{ R: f, @@ -422,7 +424,7 @@ func isFileCompressible(f *os.File, minCompressRatio float64) bool { n := 4096 - lr.N zn := len(b.B) - bytebufferpool.Put(b) + ReleaseByteBuffer(b) return float64(zn) < float64(n)*minCompressRatio } diff --git a/vendor/github.com/valyala/fasthttp/cookie.go b/vendor/github.com/VictoriaMetrics/fasthttp/cookie.go similarity index 63% rename from vendor/github.com/valyala/fasthttp/cookie.go rename to vendor/github.com/VictoriaMetrics/fasthttp/cookie.go index 8137643c2..17ecc626d 100644 --- a/vendor/github.com/valyala/fasthttp/cookie.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/cookie.go @@ -18,21 +18,6 @@ var ( CookieExpireUnlimited = zeroTime ) -// CookieSameSite is an enum for the mode in which the SameSite flag should be set for the given cookie. -// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details. -type CookieSameSite int - -const ( - // CookieSameSiteDisabled removes the SameSite flag - CookieSameSiteDisabled CookieSameSite = iota - // CookieSameSiteDefaultMode sets the SameSite flag - CookieSameSiteDefaultMode - // CookieSameSiteLaxMode sets the SameSite flag with the "Lax" parameter - CookieSameSiteLaxMode - // CookieSameSiteStrictMode sets the SameSite flag with the "Strict" parameter - CookieSameSiteStrictMode -) - // AcquireCookie returns an empty Cookie object from the pool. // // The returned object may be returned back to the pool with ReleaseCookie. @@ -67,13 +52,11 @@ type Cookie struct { key []byte value []byte expire time.Time - maxAge int domain []byte path []byte httpOnly bool secure bool - sameSite CookieSameSite bufKV argsKV buf []byte @@ -85,12 +68,10 @@ func (c *Cookie) CopyTo(src *Cookie) { c.key = append(c.key[:0], src.key...) c.value = append(c.value[:0], src.value...) c.expire = src.expire - c.maxAge = src.maxAge c.domain = append(c.domain[:0], src.domain...) c.path = append(c.path[:0], src.path...) c.httpOnly = src.httpOnly c.secure = src.secure - c.sameSite = src.sameSite } // HTTPOnly returns true if the cookie is http only. @@ -113,16 +94,6 @@ func (c *Cookie) SetSecure(secure bool) { c.secure = secure } -// SameSite returns the SameSite mode. -func (c *Cookie) SameSite() CookieSameSite { - return c.sameSite -} - -// SetSameSite sets the cookie's SameSite flag to the given value. -func (c *Cookie) SetSameSite(mode CookieSameSite) { - c.sameSite = mode -} - // Path returns cookie path. func (c *Cookie) Path() []byte { return c.path @@ -157,20 +128,6 @@ func (c *Cookie) SetDomainBytes(domain []byte) { c.domain = append(c.domain[:0], domain...) } -// MaxAge returns the seconds until the cookie is meant to expire or 0 -// if no max age. -func (c *Cookie) MaxAge() int { - return c.maxAge -} - -// SetMaxAge sets cookie expiration time based on seconds. This takes precedence -// over any absolute expiry set on the cookie -// -// Set max age to 0 to unset -func (c *Cookie) SetMaxAge(seconds int) { - c.maxAge = seconds -} - // Expire returns cookie expiration time. // // CookieExpireUnlimited is returned if cookie doesn't expire @@ -231,12 +188,10 @@ func (c *Cookie) Reset() { c.key = c.key[:0] c.value = c.value[:0] c.expire = zeroTime - c.maxAge = 0 c.domain = c.domain[:0] c.path = c.path[:0] c.httpOnly = false c.secure = false - c.sameSite = CookieSameSiteDisabled } // AppendBytes appends cookie representation to dst and returns @@ -248,12 +203,7 @@ func (c *Cookie) AppendBytes(dst []byte) []byte { } dst = append(dst, c.value...) - if c.maxAge > 0 { - dst = append(dst, ';', ' ') - dst = append(dst, strCookieMaxAge...) - dst = append(dst, '=') - dst = AppendUint(dst, c.maxAge) - } else if !c.expire.IsZero() { + if !c.expire.IsZero() { c.bufKV.value = AppendHTTPDate(c.bufKV.value[:0], c.expire) dst = append(dst, ';', ' ') dst = append(dst, strCookieExpires...) @@ -274,21 +224,6 @@ func (c *Cookie) AppendBytes(dst []byte) []byte { dst = append(dst, ';', ' ') dst = append(dst, strCookieSecure...) } - switch c.sameSite { - case CookieSameSiteDefaultMode: - dst = append(dst, ';', ' ') - dst = append(dst, strCookieSameSite...) - case CookieSameSiteLaxMode: - dst = append(dst, ';', ' ') - dst = append(dst, strCookieSameSite...) - dst = append(dst, '=') - dst = append(dst, strCookieSameSiteLax...) - case CookieSameSiteStrictMode: - dst = append(dst, ';', ' ') - dst = append(dst, strCookieSameSite...) - dst = append(dst, '=') - dst = append(dst, strCookieSameSiteStrict...) - } return dst } @@ -337,75 +272,29 @@ func (c *Cookie) ParseBytes(src []byte) error { c.value = append(c.value[:0], kv.value...) for s.next(kv) { - if len(kv.key) != 0 { - // Case insensitive switch on first char - switch kv.key[0] | 0x20 { - case 'm': - if caseInsensitiveCompare(strCookieMaxAge, kv.key) { - maxAge, err := ParseUint(kv.value) - if err != nil { - return err - } - c.maxAge = maxAge - } - - case 'e': // "expires" - if caseInsensitiveCompare(strCookieExpires, kv.key) { - v := b2s(kv.value) - // Try the same two formats as net/http - // See: https://github.com/golang/go/blob/00379be17e63a5b75b3237819392d2dc3b313a27/src/net/http/cookie.go#L133-L135 - exptime, err := time.ParseInLocation(time.RFC1123, v, time.UTC) - if err != nil { - exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", v) - if err != nil { - return err - } - } - c.expire = exptime - } - - case 'd': // "domain" - if caseInsensitiveCompare(strCookieDomain, kv.key) { - c.domain = append(c.domain[:0], kv.value...) - } - - case 'p': // "path" - if caseInsensitiveCompare(strCookiePath, kv.key) { - c.path = append(c.path[:0], kv.value...) - } - - case 's': // "samesite" - if caseInsensitiveCompare(strCookieSameSite, kv.key) { - // Case insensitive switch on first char - switch kv.value[0] | 0x20 { - case 'l': // "lax" - if caseInsensitiveCompare(strCookieSameSiteLax, kv.value) { - c.sameSite = CookieSameSiteLaxMode - } - case 's': // "strict" - if caseInsensitiveCompare(strCookieSameSiteStrict, kv.value) { - c.sameSite = CookieSameSiteStrictMode - } - } - } + if len(kv.key) == 0 && len(kv.value) == 0 { + continue + } + switch string(kv.key) { + case "expires": + v := b2s(kv.value) + exptime, err := time.ParseInLocation(time.RFC1123, v, time.UTC) + if err != nil { + return err } - - } else if len(kv.value) != 0 { - // Case insensitive switch on first char - switch kv.value[0] | 0x20 { - case 'h': // "httponly" - if caseInsensitiveCompare(strCookieHTTPOnly, kv.value) { - c.httpOnly = true - } - - case 's': // "secure" - if caseInsensitiveCompare(strCookieSecure, kv.value) { - c.secure = true - } else if caseInsensitiveCompare(strCookieSameSite, kv.value) { - c.sameSite = CookieSameSiteDefaultMode - } + c.expire = exptime + case "domain": + c.domain = append(c.domain[:0], kv.value...) + case "path": + c.path = append(c.path[:0], kv.value...) + case "": + switch string(kv.value) { + case "HttpOnly": + c.httpOnly = true + case "secure": + c.secure = true } - } // else empty or no match + } } return nil } @@ -440,19 +329,6 @@ func appendRequestCookieBytes(dst []byte, cookies []argsKV) []byte { return dst } -// For Response we can not use the above function as response cookies -// already contain the key= in the value. -func appendResponseCookieBytes(dst []byte, cookies []argsKV) []byte { - for i, n := 0, len(cookies); i < n; i++ { - kv := &cookies[i] - dst = append(dst, kv.value...) - if i+1 < n { - dst = append(dst, ';', ' ') - } - } - return dst -} - func parseRequestCookies(cookies []argsKV, src []byte) []argsKV { var s cookieScanner s.b = src @@ -518,17 +394,3 @@ func decodeCookieArg(dst, src []byte, skipQuotes bool) []byte { } return append(dst[:0], src...) } - -// caseInsensitiveCompare does a case insensitive equality comparison of -// two []byte. Assumes only letters need to be matched. -func caseInsensitiveCompare(a, b []byte) bool { - if len(a) != len(b) { - return false - } - for i := 0; i < len(a); i++ { - if a[i]|0x20 != b[i]|0x20 { - return false - } - } - return true -} diff --git a/vendor/github.com/valyala/fasthttp/doc.go b/vendor/github.com/VictoriaMetrics/fasthttp/doc.go similarity index 85% rename from vendor/github.com/valyala/fasthttp/doc.go rename to vendor/github.com/VictoriaMetrics/fasthttp/doc.go index efcd4a033..501eff6f1 100644 --- a/vendor/github.com/valyala/fasthttp/doc.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/doc.go @@ -7,6 +7,9 @@ Fasthttp provides the following features: concurrent keep-alive connections on modern hardware. * Optimized for low memory usage. * Easy 'Connection: Upgrade' support via RequestCtx.Hijack. + * Server supports requests' pipelining. Multiple requests may be read from + a single network packet and multiple responses may be sent in a single + network packet. This may be useful for highly loaded REST services. * Server provides the following anti-DoS limits: * The number of concurrent connections. diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/doc.go b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/doc.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/fasthttputil/doc.go rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/doc.go diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/ecdsa.key b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/ecdsa.key similarity index 100% rename from vendor/github.com/valyala/fasthttp/fasthttputil/ecdsa.key rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/ecdsa.key diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/ecdsa.pem b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/ecdsa.pem similarity index 100% rename from vendor/github.com/valyala/fasthttp/fasthttputil/ecdsa.pem rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/ecdsa.pem diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/inmemory_listener.go b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/inmemory_listener.go similarity index 78% rename from vendor/github.com/valyala/fasthttp/fasthttputil/inmemory_listener.go rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/inmemory_listener.go index 1b1a5f366..d6bcca435 100644 --- a/vendor/github.com/valyala/fasthttp/fasthttputil/inmemory_listener.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/inmemory_listener.go @@ -8,23 +8,18 @@ import ( // InmemoryListener provides in-memory dialer<->net.Listener implementation. // -// It may be used either for fast in-process client<->server communications +// It may be used either for fast in-process client<->server communcations // without network stack overhead or for client<->server tests. type InmemoryListener struct { lock sync.Mutex closed bool - conns chan acceptConn -} - -type acceptConn struct { - conn net.Conn - accepted chan struct{} + conns chan net.Conn } // NewInmemoryListener returns new in-memory dialer<->net.Listener. func NewInmemoryListener() *InmemoryListener { return &InmemoryListener{ - conns: make(chan acceptConn, 1024), + conns: make(chan net.Conn, 1024), } } @@ -38,8 +33,7 @@ func (ln *InmemoryListener) Accept() (net.Conn, error) { if !ok { return nil, fmt.Errorf("InmemoryListener is already closed: use of closed network connection") } - close(c.accepted) - return c.conn, nil + return c, nil } // Close implements net.Listener's Close. @@ -65,9 +59,8 @@ func (ln *InmemoryListener) Addr() net.Addr { } } -// Dial creates new client<->server connection. -// Just like a real Dial it only returns once the server -// has accepted the connection. +// Dial creates new client<->server connection, enqueues server side +// of the connection to Accept and returns client side of the connection. // // It is safe calling Dial from concurrently running goroutines. func (ln *InmemoryListener) Dial() (net.Conn, error) { @@ -75,11 +68,8 @@ func (ln *InmemoryListener) Dial() (net.Conn, error) { cConn := pc.Conn1() sConn := pc.Conn2() ln.lock.Lock() - accepted := make(chan struct{}) if !ln.closed { - ln.conns <- acceptConn{sConn, accepted} - // Wait until the connection has been accepted. - <-accepted + ln.conns <- sConn } else { sConn.Close() cConn.Close() diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/pipeconns.go b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/pipeconns.go similarity index 98% rename from vendor/github.com/valyala/fasthttp/fasthttputil/pipeconns.go rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/pipeconns.go index aa92b6ff8..e5a02351c 100644 --- a/vendor/github.com/valyala/fasthttp/fasthttputil/pipeconns.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/pipeconns.go @@ -8,7 +8,7 @@ import ( "time" ) -// NewPipeConns returns new bi-directional connection pipe. +// NewPipeConns returns new bi-directonal connection pipe. func NewPipeConns() *PipeConns { ch1 := make(chan *byteBuffer, 4) ch2 := make(chan *byteBuffer, 4) diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/rsa.key b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/rsa.key similarity index 100% rename from vendor/github.com/valyala/fasthttp/fasthttputil/rsa.key rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/rsa.key diff --git a/vendor/github.com/valyala/fasthttp/fasthttputil/rsa.pem b/vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/rsa.pem similarity index 100% rename from vendor/github.com/valyala/fasthttp/fasthttputil/rsa.pem rename to vendor/github.com/VictoriaMetrics/fasthttp/fasthttputil/rsa.pem diff --git a/vendor/github.com/valyala/fasthttp/fs.go b/vendor/github.com/VictoriaMetrics/fasthttp/fs.go similarity index 97% rename from vendor/github.com/valyala/fasthttp/fs.go rename to vendor/github.com/VictoriaMetrics/fasthttp/fs.go index 1e9b4ab19..0d83b6090 100644 --- a/vendor/github.com/valyala/fasthttp/fs.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/fs.go @@ -17,7 +17,6 @@ import ( "time" "github.com/klauspost/compress/gzip" - "github.com/valyala/bytebufferpool" ) // ServeFileBytesUncompressed returns HTTP response containing file contents @@ -140,12 +139,12 @@ func NewVHostPathRewriter(slashesCount int) PathRewriteFunc { if len(host) == 0 { host = strInvalidHost } - b := bytebufferpool.Get() + b := AcquireByteBuffer() b.B = append(b.B, '/') b.B = append(b.B, host...) b.B = append(b.B, path...) ctx.URI().SetPathBytes(b.B) - bytebufferpool.Put(b) + ReleaseByteBuffer(b) return ctx.Path() } @@ -226,7 +225,7 @@ type FS struct { // It adds CompressedFileSuffix suffix to the original file name and // tries saving the resulting compressed file under the new file name. // So it is advisable to give the server write access to Root - // and to all inner folders in order to minimize CPU usage when serving + // and to all inner folders in order to minimze CPU usage when serving // compressed responses. // // Transparent compression is disabled by default. @@ -242,14 +241,6 @@ type FS struct { // By default request path is not modified. PathRewrite PathRewriteFunc - // PathNotFound fires when file is not found in filesystem - // this functions tries to replace "Cannot open requested path" - // server response giving to the programmer the control of server flow. - // - // By default PathNotFound returns - // "Cannot open requested path" - PathNotFound RequestHandler - // Expiration duration for inactive file handlers. // // FSHandlerCacheDuration is used by default. @@ -352,7 +343,6 @@ func (fs *FS) initRequestHandler() { pathRewrite: fs.PathRewrite, generateIndexPages: fs.GenerateIndexPages, compress: fs.Compress, - pathNotFound: fs.PathNotFound, acceptByteRange: fs.AcceptByteRange, cacheDuration: cacheDuration, compressedFileSuffix: compressedFileSuffix, @@ -375,7 +365,6 @@ type fsHandler struct { root string indexNames []string pathRewrite PathRewriteFunc - pathNotFound RequestHandler generateIndexPages bool compress bool acceptByteRange bool @@ -737,12 +726,7 @@ func (h *fsHandler) handleRequest(ctx *RequestCtx) { } } else if err != nil { ctx.Logger().Printf("cannot open file %q: %s", filePath, err) - if h.pathNotFound == nil { - ctx.Error("Cannot open requested path", StatusNotFound) - } else { - ctx.SetStatusCode(StatusNotFound) - h.pathNotFound(ctx) - } + ctx.Error("Cannot open requested path", StatusNotFound) return } @@ -824,10 +808,7 @@ func (h *fsHandler) handleRequest(ctx *RequestCtx) { } } } - hdr.noDefaultContentType = true - if len(hdr.ContentType()) == 0 { - ctx.SetContentType(ff.contentType) - } + ctx.SetContentType(ff.contentType) ctx.SetStatusCode(statusCode) } @@ -916,7 +897,7 @@ var ( ) func (h *fsHandler) createDirIndex(base *URI, dirPath string, mustCompress bool) (*fsFile, error) { - w := &bytebufferpool.ByteBuffer{} + w := &ByteBuffer{} basePathEscaped := html.EscapeString(string(base.Path())) fmt.Fprintf(w, "%s", basePathEscaped) @@ -943,7 +924,7 @@ func (h *fsHandler) createDirIndex(base *URI, dirPath string, mustCompress bool) } fm := make(map[string]os.FileInfo, len(fileinfos)) - filenames := make([]string, 0, len(fileinfos)) + var filenames []string for _, fi := range fileinfos { name := fi.Name() if strings.HasSuffix(name, h.compressedFileSuffix) { @@ -958,7 +939,7 @@ func (h *fsHandler) createDirIndex(base *URI, dirPath string, mustCompress bool) base.CopyTo(&u) u.Update(string(u.Path()) + "/") - sort.Strings(filenames) + sort.Sort(sort.StringSlice(filenames)) for _, name := range filenames { u.Update(name) pathEscaped := html.EscapeString(string(u.Path())) @@ -976,7 +957,7 @@ func (h *fsHandler) createDirIndex(base *URI, dirPath string, mustCompress bool) fmt.Fprintf(w, "") if mustCompress { - var zbuf bytebufferpool.ByteBuffer + var zbuf ByteBuffer zbuf.B = AppendGzipBytesLevel(zbuf.B, w.B, CompressDefaultCompression) w = &zbuf } diff --git a/vendor/github.com/VictoriaMetrics/fasthttp/go.mod b/vendor/github.com/VictoriaMetrics/fasthttp/go.mod new file mode 100644 index 000000000..d8c90d78e --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/fasthttp/go.mod @@ -0,0 +1,9 @@ +module github.com/VictoriaMetrics/fasthttp + +go 1.13 + +require ( + github.com/klauspost/compress v1.10.5 + github.com/valyala/bytebufferpool v1.0.0 + github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a +) diff --git a/vendor/github.com/VictoriaMetrics/fasthttp/go.sum b/vendor/github.com/VictoriaMetrics/fasthttp/go.sum new file mode 100644 index 000000000..1ac553811 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/fasthttp/go.sum @@ -0,0 +1,6 @@ +github.com/klauspost/compress v1.10.5 h1:7q6vHIqubShURwQz8cQK6yIe/xC3IF0Vm7TGfqjewrc= +github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= diff --git a/vendor/github.com/valyala/fasthttp/header.go b/vendor/github.com/VictoriaMetrics/fasthttp/header.go similarity index 82% rename from vendor/github.com/valyala/fasthttp/header.go rename to vendor/github.com/VictoriaMetrics/fasthttp/header.go index 190ac3238..f374c2b59 100644 --- a/vendor/github.com/valyala/fasthttp/header.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/header.go @@ -20,10 +20,8 @@ import ( type ResponseHeader struct { noCopy noCopy - disableNormalizing bool - noHTTP11 bool - connectionClose bool - noDefaultContentType bool + noHTTP11 bool + connectionClose bool statusCode int contentLength int @@ -48,9 +46,9 @@ type ResponseHeader struct { type RequestHeader struct { noCopy noCopy - disableNormalizing bool - noHTTP11 bool - connectionClose bool + noHTTP11 bool + connectionClose bool + isGet bool // These two fields have been moved close to other bool fields // for reducing RequestHeader object size. @@ -72,10 +70,6 @@ type RequestHeader struct { cookies []argsKV rawHeaders []byte - - // stores an immutable copy of headers as they were received from the - // wire. - rawHeadersCopy []byte } // SetContentRange sets 'Content-Range: bytes startPos-endPos/contentLength' @@ -161,6 +155,12 @@ func (h *RequestHeader) ConnectionClose() bool { return h.connectionClose } +func (h *RequestHeader) connectionCloseFast() bool { + // h.parseRawHeaders() isn't called for performance reasons. + // Use ConnectionClose for triggering raw headers parsing. + return h.connectionClose +} + // SetConnectionClose sets 'Connection: close' header. func (h *RequestHeader) SetConnectionClose() { // h.parseRawHeaders() isn't called for performance reasons. @@ -187,11 +187,6 @@ func (h *RequestHeader) ConnectionUpgrade() bool { return hasHeaderValue(h.Peek("Connection"), strUpgrade) } -// PeekCookie is able to returns cookie by a given key from response. -func (h *ResponseHeader) PeekCookie(key string) []byte { - return peekArgStr(h.cookies, key) -} - // ContentLength returns Content-Length header value. // // It may be negative: @@ -221,7 +216,7 @@ func (h *ResponseHeader) SetContentLength(contentLength int) { h.SetConnectionClose() value = strIdentity } - h.h = setArgBytes(h.h, strTransferEncoding, value, argsHasValue) + h.h = setArgBytes(h.h, strTransferEncoding, value) } } @@ -244,15 +239,9 @@ func (h *ResponseHeader) mustSkipContentLength() bool { // It may be negative: // -1 means Transfer-Encoding: chunked. func (h *RequestHeader) ContentLength() int { - if h.ignoreBody() { + if h.noBody() { return 0 } - return h.realContentLength() -} - -// realContentLength returns the actual Content-Length set in the request, -// including positive lengths for GET/HEAD requests. -func (h *RequestHeader) realContentLength() int { h.parseRawHeaders() return h.contentLength } @@ -268,7 +257,7 @@ func (h *RequestHeader) SetContentLength(contentLength int) { h.h = delAllArgsBytes(h.h, strTransferEncoding) } else { h.contentLengthBytes = h.contentLengthBytes[:0] - h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue) + h.h = setArgBytes(h.h, strTransferEncoding, strChunked) } } @@ -281,7 +270,7 @@ func (h *ResponseHeader) isCompressibleContentType() bool { // ContentType returns Content-Type header value. func (h *ResponseHeader) ContentType() []byte { contentType := h.contentType - if !h.noDefaultContentType && len(h.contentType) == 0 { + if len(h.contentType) == 0 { contentType = defaultContentType } return contentType @@ -513,10 +502,14 @@ func (h *RequestHeader) SetRequestURIBytes(requestURI []byte) { // IsGet returns true if request method is GET. func (h *RequestHeader) IsGet() bool { - return bytes.Equal(h.Method(), strGet) + // Optimize fast path for GET requests. + if !h.isGet { + h.isGet = bytes.Equal(h.Method(), strGet) + } + return h.isGet } -// IsPost returns true if request method is POST. +// IsPost returns true if request methos is POST. func (h *RequestHeader) IsPost() bool { return bytes.Equal(h.Method(), strPost) } @@ -528,6 +521,10 @@ func (h *RequestHeader) IsPut() bool { // IsHead returns true if request method is HEAD. func (h *RequestHeader) IsHead() bool { + // Fast path + if h.isGet { + return false + } return bytes.Equal(h.Method(), strHead) } @@ -536,26 +533,6 @@ func (h *RequestHeader) IsDelete() bool { return bytes.Equal(h.Method(), strDelete) } -// IsConnect returns true if request method is CONNECT. -func (h *RequestHeader) IsConnect() bool { - return bytes.Equal(h.Method(), strConnect) -} - -// IsOptions returns true if request method is OPTIONS. -func (h *RequestHeader) IsOptions() bool { - return bytes.Equal(h.Method(), strOptions) -} - -// IsTrace returns true if request method is TRACE. -func (h *RequestHeader) IsTrace() bool { - return bytes.Equal(h.Method(), strTrace) -} - -// IsPatch returns true if request method is PATCH. -func (h *RequestHeader) IsPatch() bool { - return bytes.Equal(h.Method(), strPatch) -} - // IsHTTP11 returns true if the request is HTTP/1.1. func (h *RequestHeader) IsHTTP11() bool { return !h.noHTTP11 @@ -607,46 +584,8 @@ func (h *RequestHeader) Len() int { return n } -// DisableNormalizing disables header names' normalization. -// -// By default all the header names are normalized by uppercasing -// the first letter and all the first letters following dashes, -// while lowercasing all the other letters. -// Examples: -// -// * CONNECTION -> Connection -// * conteNT-tYPE -> Content-Type -// * foo-bar-baz -> Foo-Bar-Baz -// -// Disable header names' normalization only if know what are you doing. -func (h *RequestHeader) DisableNormalizing() { - h.disableNormalizing = true -} - -// DisableNormalizing disables header names' normalization. -// -// By default all the header names are normalized by uppercasing -// the first letter and all the first letters following dashes, -// while lowercasing all the other letters. -// Examples: -// -// * CONNECTION -> Connection -// * conteNT-tYPE -> Content-Type -// * foo-bar-baz -> Foo-Bar-Baz -// -// Disable header names' normalization only if know what are you doing. -func (h *ResponseHeader) DisableNormalizing() { - h.disableNormalizing = true -} - // Reset clears response header. func (h *ResponseHeader) Reset() { - h.disableNormalizing = false - h.noDefaultContentType = false - h.resetSkipNormalize() -} - -func (h *ResponseHeader) resetSkipNormalize() { h.noHTTP11 = false h.connectionClose = false @@ -663,13 +602,9 @@ func (h *ResponseHeader) resetSkipNormalize() { // Reset clears request header. func (h *RequestHeader) Reset() { - h.disableNormalizing = false - h.resetSkipNormalize() -} - -func (h *RequestHeader) resetSkipNormalize() { h.noHTTP11 = false h.connectionClose = false + h.isGet = false h.contentLength = 0 h.contentLengthBytes = h.contentLengthBytes[:0] @@ -692,10 +627,8 @@ func (h *RequestHeader) resetSkipNormalize() { func (h *ResponseHeader) CopyTo(dst *ResponseHeader) { dst.Reset() - dst.disableNormalizing = h.disableNormalizing dst.noHTTP11 = h.noHTTP11 dst.connectionClose = h.connectionClose - dst.noDefaultContentType = h.noDefaultContentType dst.statusCode = h.statusCode dst.contentLength = h.contentLength @@ -710,9 +643,9 @@ func (h *ResponseHeader) CopyTo(dst *ResponseHeader) { func (h *RequestHeader) CopyTo(dst *RequestHeader) { dst.Reset() - dst.disableNormalizing = h.disableNormalizing dst.noHTTP11 = h.noHTTP11 dst.connectionClose = h.connectionClose + dst.isGet = h.isGet dst.contentLength = h.contentLength dst.contentLengthBytes = append(dst.contentLengthBytes[:0], h.contentLengthBytes...) @@ -726,7 +659,6 @@ func (h *RequestHeader) CopyTo(dst *RequestHeader) { dst.cookiesCollected = h.cookiesCollected dst.rawHeaders = append(dst.rawHeaders[:0], h.rawHeaders...) dst.rawHeadersParsed = h.rawHeadersParsed - dst.rawHeadersCopy = append(dst.rawHeadersCopy[:0], h.rawHeadersCopy...) } // VisitAll calls f for each header. @@ -780,8 +712,6 @@ func (h *RequestHeader) VisitAllCookie(f func(key, value []byte)) { // // f must not retain references to key and/or value after returning. // Copy key and/or value contents before returning if you need retaining them. -// -// To get the headers in order they were received use VisitAllInOrder. func (h *RequestHeader) VisitAll(f func(key, value []byte)) { h.parseRawHeaders() host := h.Host() @@ -811,35 +741,16 @@ func (h *RequestHeader) VisitAll(f func(key, value []byte)) { } } -// VisitAllInOrder calls f for each header in the order they were received. -// -// f must not retain references to key and/or value after returning. -// Copy key and/or value contents before returning if you need retaining them. -// -// This function is slightly slower than VisitAll because it has to reparse the -// raw headers to get the order. -func (h *RequestHeader) VisitAllInOrder(f func(key, value []byte)) { - h.parseRawHeaders() - var s headerScanner - s.b = h.rawHeaders - s.disableNormalizing = h.disableNormalizing - for s.next() { - if len(s.key) > 0 { - f(s.key, s.value) - } - } -} - // Del deletes header with the given key. func (h *ResponseHeader) Del(key string) { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) + k := getHeaderKeyBytes(&h.bufKV, key) h.del(k) } // DelBytes deletes header with the given key. func (h *ResponseHeader) DelBytes(key []byte) { h.bufKV.key = append(h.bufKV.key[:0], key...) - normalizeHeaderKey(h.bufKV.key, h.disableNormalizing) + normalizeHeaderKey(h.bufKV.key) h.del(h.bufKV.key) } @@ -863,7 +774,7 @@ func (h *ResponseHeader) del(key []byte) { // Del deletes header with the given key. func (h *RequestHeader) Del(key string) { h.parseRawHeaders() - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) + k := getHeaderKeyBytes(&h.bufKV, key) h.del(k) } @@ -871,7 +782,7 @@ func (h *RequestHeader) Del(key string) { func (h *RequestHeader) DelBytes(key []byte) { h.parseRawHeaders() h.bufKV.key = append(h.bufKV.key[:0], key...) - normalizeHeaderKey(h.bufKV.key, h.disableNormalizing) + normalizeHeaderKey(h.bufKV.key) h.del(h.bufKV.key) } @@ -899,8 +810,8 @@ func (h *RequestHeader) del(key []byte) { // Multiple headers with the same key may be added with this function. // Use Set for setting a single header for the given key. func (h *ResponseHeader) Add(key, value string) { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) - h.h = appendArg(h.h, b2s(k), value, argsHasValue) + k := getHeaderKeyBytes(&h.bufKV, key) + h.h = appendArg(h.h, b2s(k), value) } // AddBytesK adds the given 'key: value' header. @@ -931,7 +842,7 @@ func (h *ResponseHeader) AddBytesKV(key, value []byte) { // // Use Add for setting multiple header values under the same key. func (h *ResponseHeader) Set(key, value string) { - initHeaderKV(&h.bufKV, key, value, h.disableNormalizing) + initHeaderKV(&h.bufKV, key, value) h.SetCanonical(h.bufKV.key, h.bufKV.value) } @@ -947,7 +858,7 @@ func (h *ResponseHeader) SetBytesK(key []byte, value string) { // // Use AddBytesV for setting multiple header values under the same key. func (h *ResponseHeader) SetBytesV(key string, value []byte) { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) + k := getHeaderKeyBytes(&h.bufKV, key) h.SetCanonical(k, value) } @@ -956,7 +867,7 @@ func (h *ResponseHeader) SetBytesV(key string, value []byte) { // Use AddBytesKV for setting multiple header values under the same key. func (h *ResponseHeader) SetBytesKV(key, value []byte) { h.bufKV.key = append(h.bufKV.key[:0], key...) - normalizeHeaderKey(h.bufKV.key, h.disableNormalizing) + normalizeHeaderKey(h.bufKV.key) h.SetCanonical(h.bufKV.key, value) } @@ -983,14 +894,14 @@ func (h *ResponseHeader) SetCanonical(key, value []byte) { h.SetConnectionClose() } else { h.ResetConnectionClose() - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.h = setArgBytes(h.h, key, value) } case "Transfer-Encoding": // Transfer-Encoding is managed automatically. case "Date": // Date is managed automatically. default: - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.h = setArgBytes(h.h, key, value) } } @@ -998,14 +909,14 @@ func (h *ResponseHeader) SetCanonical(key, value []byte) { // // It is save re-using the cookie after the function returns. func (h *ResponseHeader) SetCookie(cookie *Cookie) { - h.cookies = setArgBytes(h.cookies, cookie.Key(), cookie.Cookie(), argsHasValue) + h.cookies = setArgBytes(h.cookies, cookie.Key(), cookie.Cookie()) } // SetCookie sets 'key: value' cookies. func (h *RequestHeader) SetCookie(key, value string) { h.parseRawHeaders() h.collectCookies() - h.cookies = setArg(h.cookies, key, value, argsHasValue) + h.cookies = setArg(h.cookies, key, value) } // SetCookieBytesK sets 'key: value' cookies. @@ -1083,8 +994,8 @@ func (h *RequestHeader) DelAllCookies() { // Multiple headers with the same key may be added with this function. // Use Set for setting a single header for the given key. func (h *RequestHeader) Add(key, value string) { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) - h.h = appendArg(h.h, b2s(k), value, argsHasValue) + k := getHeaderKeyBytes(&h.bufKV, key) + h.h = appendArg(h.h, b2s(k), value) } // AddBytesK adds the given 'key: value' header. @@ -1115,7 +1026,7 @@ func (h *RequestHeader) AddBytesKV(key, value []byte) { // // Use Add for setting multiple header values under the same key. func (h *RequestHeader) Set(key, value string) { - initHeaderKV(&h.bufKV, key, value, h.disableNormalizing) + initHeaderKV(&h.bufKV, key, value) h.SetCanonical(h.bufKV.key, h.bufKV.value) } @@ -1131,7 +1042,7 @@ func (h *RequestHeader) SetBytesK(key []byte, value string) { // // Use AddBytesV for setting multiple header values under the same key. func (h *RequestHeader) SetBytesV(key string, value []byte) { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) + k := getHeaderKeyBytes(&h.bufKV, key) h.SetCanonical(k, value) } @@ -1140,7 +1051,7 @@ func (h *RequestHeader) SetBytesV(key string, value []byte) { // Use AddBytesKV for setting multiple header values under the same key. func (h *RequestHeader) SetBytesKV(key, value []byte) { h.bufKV.key = append(h.bufKV.key[:0], key...) - normalizeHeaderKey(h.bufKV.key, h.disableNormalizing) + normalizeHeaderKey(h.bufKV.key) h.SetCanonical(h.bufKV.key, value) } @@ -1168,12 +1079,12 @@ func (h *RequestHeader) SetCanonical(key, value []byte) { h.SetConnectionClose() } else { h.ResetConnectionClose() - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.h = setArgBytes(h.h, key, value) } case "Transfer-Encoding": // Transfer-Encoding is managed automatically. default: - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.h = setArgBytes(h.h, key, value) } } @@ -1182,7 +1093,7 @@ func (h *RequestHeader) SetCanonical(key, value []byte) { // Returned value is valid until the next call to ResponseHeader. // Do not store references to returned value. Make copies instead. func (h *ResponseHeader) Peek(key string) []byte { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) + k := getHeaderKeyBytes(&h.bufKV, key) return h.peek(k) } @@ -1192,7 +1103,7 @@ func (h *ResponseHeader) Peek(key string) []byte { // Do not store references to returned value. Make copies instead. func (h *ResponseHeader) PeekBytes(key []byte) []byte { h.bufKV.key = append(h.bufKV.key[:0], key...) - normalizeHeaderKey(h.bufKV.key, h.disableNormalizing) + normalizeHeaderKey(h.bufKV.key) return h.peek(h.bufKV.key) } @@ -1201,7 +1112,7 @@ func (h *ResponseHeader) PeekBytes(key []byte) []byte { // Returned value is valid until the next call to RequestHeader. // Do not store references to returned value. Make copies instead. func (h *RequestHeader) Peek(key string) []byte { - k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing) + k := getHeaderKeyBytes(&h.bufKV, key) return h.peek(k) } @@ -1211,7 +1122,7 @@ func (h *RequestHeader) Peek(key string) []byte { // Do not store references to returned value. Make copies instead. func (h *RequestHeader) PeekBytes(key []byte) []byte { h.bufKV.key = append(h.bufKV.key[:0], key...) - normalizeHeaderKey(h.bufKV.key, h.disableNormalizing) + normalizeHeaderKey(h.bufKV.key) return h.peek(h.bufKV.key) } @@ -1228,8 +1139,6 @@ func (h *ResponseHeader) peek(key []byte) []byte { return peekArgBytes(h.h, key) case "Content-Length": return h.contentLengthBytes - case "Set-Cookie": - return appendResponseCookieBytes(nil, h.cookies) default: return peekArgBytes(h.h, key) } @@ -1251,12 +1160,6 @@ func (h *RequestHeader) peek(key []byte) []byte { return peekArgBytes(h.h, key) case "Content-Length": return h.contentLengthBytes - case "Cookie": - if h.cookiesCollected { - return appendRequestCookieBytes(nil, h.cookies) - } else { - return peekArgBytes(h.h, key) - } default: return peekArgBytes(h.h, key) } @@ -1299,7 +1202,7 @@ func (h *ResponseHeader) Read(r *bufio.Reader) error { return nil } if err != errNeedMore { - h.resetSkipNormalize() + h.Reset() return err } n = r.Buffered() + 1 @@ -1307,7 +1210,7 @@ func (h *ResponseHeader) Read(r *bufio.Reader) error { } func (h *ResponseHeader) tryRead(r *bufio.Reader, n int) error { - h.resetSkipNormalize() + h.Reset() b, err := r.Peek(n) if len(b) == 0 { // treat all errors on the first byte read as EOF @@ -1370,7 +1273,7 @@ func (h *RequestHeader) Read(r *bufio.Reader) error { return nil } if err != errNeedMore { - h.resetSkipNormalize() + h.Reset() return err } n = r.Buffered() + 1 @@ -1378,15 +1281,12 @@ func (h *RequestHeader) Read(r *bufio.Reader) error { } func (h *RequestHeader) tryRead(r *bufio.Reader, n int) error { - h.resetSkipNormalize() + h.Reset() b, err := r.Peek(n) if len(b) == 0 { - if err == io.EOF { - return err - } - - if err == nil { - panic("bufio.Reader.Peek() returned nil, nil") + // treat all errors on the first byte read as EOF + if n == 1 || err == io.EOF { + return io.EOF } // This is for go 1.6 bug. See https://github.com/golang/go/issues/14121 . @@ -1396,11 +1296,6 @@ func (h *RequestHeader) tryRead(r *bufio.Reader, n int) error { } } - if n == 1 { - // We didn't read a single byte. - return errNothingRead - } - return fmt.Errorf("error when reading request headers: %s", err) } b = mustPeekBuffered(r) @@ -1490,9 +1385,10 @@ func (h *ResponseHeader) AppendBytes(dst []byte) []byte { dst = append(dst, statusLine(statusCode)...) server := h.Server() - if len(server) != 0 { - dst = appendHeaderLine(dst, strServer, server) + if len(server) == 0 { + server = defaultServerName } + dst = appendHeaderLine(dst, strServer, server) dst = appendHeaderLine(dst, strDate, serverDate.Load().([]byte)) // Append Content-Type only for non-zero responses @@ -1550,20 +1446,6 @@ func (h *RequestHeader) Header() []byte { return h.bufKV.value } -// RawHeaders returns raw header key/value bytes. -// -// Depending on server configuration, header keys may be normalized to -// capital-case in place. -// -// This copy is set aside during parsing, so empty slice is returned for all -// cases where parsing did not happen. Similarly, request line is not stored -// during parsing and can not be returned. -// -// The slice is not safe to use after the handler returns. -func (h *RequestHeader) RawHeaders() []byte { - return h.rawHeadersCopy -} - // String returns request header representation. func (h *RequestHeader) String() string { return string(h.Header()) @@ -1585,9 +1467,10 @@ func (h *RequestHeader) AppendBytes(dst []byte) []byte { } userAgent := h.UserAgent() - if len(userAgent) > 0 { - dst = appendHeaderLine(dst, strUserAgent, userAgent) + if len(userAgent) == 0 { + userAgent = defaultUserAgent } + dst = appendHeaderLine(dst, strUserAgent, userAgent) host := h.Host() if len(host) > 0 { @@ -1595,7 +1478,7 @@ func (h *RequestHeader) AppendBytes(dst []byte) []byte { } contentType := h.ContentType() - if !h.ignoreBody() { + if !h.noBody() { if len(contentType) == 0 { contentType = strPostArgsContentType } @@ -1649,7 +1532,7 @@ func (h *ResponseHeader) parse(buf []byte) (int, error) { return m + n, nil } -func (h *RequestHeader) ignoreBody() bool { +func (h *RequestHeader) noBody() bool { return h.IsGet() || h.IsHead() } @@ -1660,20 +1543,18 @@ func (h *RequestHeader) parse(buf []byte) (int, error) { } var n int - var rawHeaders []byte - rawHeaders, n, err = readRawHeaders(h.rawHeaders[:0], buf[m:]) - if err != nil { - return 0, err - } - h.rawHeadersCopy = append(h.rawHeadersCopy[:0], rawHeaders...) - if !h.ignoreBody() || h.noHTTP11 { + if !h.noBody() || h.noHTTP11 { n, err = h.parseHeaders(buf[m:]) if err != nil { return 0, err } - h.rawHeaders = append(h.rawHeaders[:0], buf[m:m+n]...) h.rawHeadersParsed = true } else { + var rawHeaders []byte + rawHeaders, n, err = readRawHeaders(h.rawHeaders[:0], buf[m:]) + if err != nil { + return 0, err + } h.rawHeaders = rawHeaders } return m + n, nil @@ -1807,57 +1688,40 @@ func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) { var s headerScanner s.b = buf - s.disableNormalizing = h.disableNormalizing var err error var kv *argsKV for s.next() { - if len(s.key) > 0 { - switch s.key[0] | 0x20 { - case 'c': - if caseInsensitiveCompare(s.key, strContentType) { - h.contentType = append(h.contentType[:0], s.value...) - continue - } - if caseInsensitiveCompare(s.key, strContentLength) { - if h.contentLength != -1 { - if h.contentLength, err = parseContentLength(s.value); err != nil { - h.contentLength = -2 - } else { - h.contentLengthBytes = append(h.contentLengthBytes[:0], s.value...) - } - } - continue - } - if caseInsensitiveCompare(s.key, strConnection) { - if bytes.Equal(s.value, strClose) { - h.connectionClose = true - } else { - h.connectionClose = false - h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue) - } - continue - } - case 's': - if caseInsensitiveCompare(s.key, strServer) { - h.server = append(h.server[:0], s.value...) - continue - } - if caseInsensitiveCompare(s.key, strSetCookie) { - h.cookies, kv = allocArg(h.cookies) - kv.key = getCookieKey(kv.key, s.value) - kv.value = append(kv.value[:0], s.value...) - continue - } - case 't': - if caseInsensitiveCompare(s.key, strTransferEncoding) { - if !bytes.Equal(s.value, strIdentity) { - h.contentLength = -1 - h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue) - } - continue + switch string(s.key) { + case "Content-Type": + h.contentType = append(h.contentType[:0], s.value...) + case "Server": + h.server = append(h.server[:0], s.value...) + case "Content-Length": + if h.contentLength != -1 { + if h.contentLength, err = parseContentLength(s.value); err != nil { + h.contentLength = -2 + } else { + h.contentLengthBytes = append(h.contentLengthBytes[:0], s.value...) } } - h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue) + case "Transfer-Encoding": + if !bytes.Equal(s.value, strIdentity) { + h.contentLength = -1 + h.h = setArgBytes(h.h, strTransferEncoding, strChunked) + } + case "Set-Cookie": + h.cookies, kv = allocArg(h.cookies) + kv.key = getCookieKey(kv.key, s.value) + kv.value = append(kv.value[:0], s.value...) + case "Connection": + if bytes.Equal(s.value, strClose) { + h.connectionClose = true + } else { + h.connectionClose = false + h.h = appendArgBytes(h.h, s.key, s.value) + } + default: + h.h = appendArgBytes(h.h, s.key, s.value) } } if s.err != nil { @@ -1869,13 +1733,13 @@ func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) { h.contentLengthBytes = h.contentLengthBytes[:0] } if h.contentLength == -2 && !h.ConnectionUpgrade() && !h.mustSkipContentLength() { - h.h = setArgBytes(h.h, strTransferEncoding, strIdentity, argsHasValue) + h.h = setArgBytes(h.h, strTransferEncoding, strIdentity) h.connectionClose = true } if h.noHTTP11 && !h.connectionClose { // close connection for non-http/1.1 response unless 'Connection: keep-alive' is set. v := peekArgBytes(h.h, strConnection) - h.connectionClose = !hasHeaderValue(v, strKeepAlive) + h.connectionClose = !hasHeaderValue(v, strKeepAlive) && !hasHeaderValue(v, strKeepAliveCamelCase) } return len(buf) - len(s.b), nil @@ -1886,56 +1750,38 @@ func (h *RequestHeader) parseHeaders(buf []byte) (int, error) { var s headerScanner s.b = buf - s.disableNormalizing = h.disableNormalizing var err error for s.next() { - if len(s.key) > 0 { - switch s.key[0] | 0x20 { - case 'h': - if caseInsensitiveCompare(s.key, strHost) { - h.host = append(h.host[:0], s.value...) - continue - } - case 'u': - if caseInsensitiveCompare(s.key, strUserAgent) { - h.userAgent = append(h.userAgent[:0], s.value...) - continue - } - case 'c': - if caseInsensitiveCompare(s.key, strContentType) { - h.contentType = append(h.contentType[:0], s.value...) - continue - } - if caseInsensitiveCompare(s.key, strContentLength) { - if h.contentLength != -1 { - if h.contentLength, err = parseContentLength(s.value); err != nil { - h.contentLength = -2 - } else { - h.contentLengthBytes = append(h.contentLengthBytes[:0], s.value...) - } - } - continue - } - if caseInsensitiveCompare(s.key, strConnection) { - if bytes.Equal(s.value, strClose) { - h.connectionClose = true - } else { - h.connectionClose = false - h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue) - } - continue - } - case 't': - if caseInsensitiveCompare(s.key, strTransferEncoding) { - if !bytes.Equal(s.value, strIdentity) { - h.contentLength = -1 - h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue) - } - continue + switch string(s.key) { + case "Host": + h.host = append(h.host[:0], s.value...) + case "User-Agent": + h.userAgent = append(h.userAgent[:0], s.value...) + case "Content-Type": + h.contentType = append(h.contentType[:0], s.value...) + case "Content-Length": + if h.contentLength != -1 { + if h.contentLength, err = parseContentLength(s.value); err != nil { + h.contentLength = -2 + } else { + h.contentLengthBytes = append(h.contentLengthBytes[:0], s.value...) } } + case "Transfer-Encoding": + if !bytes.Equal(s.value, strIdentity) { + h.contentLength = -1 + h.h = setArgBytes(h.h, strTransferEncoding, strChunked) + } + case "Connection": + if bytes.Equal(s.value, strClose) { + h.connectionClose = true + } else { + h.connectionClose = false + h.h = appendArgBytes(h.h, s.key, s.value) + } + default: + h.h = appendArgBytes(h.h, s.key, s.value) } - h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue) } if s.err != nil { h.connectionClose = true @@ -1945,12 +1791,17 @@ func (h *RequestHeader) parseHeaders(buf []byte) (int, error) { if h.contentLength < 0 { h.contentLengthBytes = h.contentLengthBytes[:0] } + if h.noBody() { + h.contentLength = 0 + h.contentLengthBytes = h.contentLengthBytes[:0] + } if h.noHTTP11 && !h.connectionClose { // close connection for non-http/1.1 request unless 'Connection: keep-alive' is set. v := peekArgBytes(h.h, strConnection) - h.connectionClose = !hasHeaderValue(v, strKeepAlive) + h.connectionClose = !hasHeaderValue(v, strKeepAlive) && !hasHeaderValue(v, strKeepAliveCamelCase) } - return s.hLen, nil + + return len(buf) - len(s.b), nil } func (h *RequestHeader) parseRawHeaders() { @@ -2000,23 +1851,16 @@ type headerScanner struct { key []byte value []byte err error - - // hLen stores header subslice len - hLen int - - disableNormalizing bool } func (s *headerScanner) next() bool { bLen := len(s.b) if bLen >= 2 && s.b[0] == '\r' && s.b[1] == '\n' { s.b = s.b[2:] - s.hLen += 2 return false } if bLen >= 1 && s.b[0] == '\n' { s.b = s.b[1:] - s.hLen++ return false } n := bytes.IndexByte(s.b, ':') @@ -2025,12 +1869,11 @@ func (s *headerScanner) next() bool { return false } s.key = s.b[:n] - normalizeHeaderKey(s.key, s.disableNormalizing) + normalizeHeaderKey(s.key) n++ for len(s.b) > n && s.b[n] == ' ' { n++ } - s.hLen += n s.b = s.b[n:] n = bytes.IndexByte(s.b, '\n') if n < 0 { @@ -2038,7 +1881,6 @@ func (s *headerScanner) next() bool { return false } s.value = s.b[:n] - s.hLen += n + 1 s.b = s.b[n+1:] if n > 0 && s.value[n-1] == '\r' { @@ -2086,7 +1928,7 @@ func hasHeaderValue(s, value []byte) bool { var vs headerValueScanner vs.b = s for vs.next() { - if caseInsensitiveCompare(vs.value, value) { + if bytes.Equal(vs.value, value) { return true } } @@ -2105,22 +1947,18 @@ func nextLine(b []byte) ([]byte, []byte, error) { return b[:n], b[nNext+1:], nil } -func initHeaderKV(kv *argsKV, key, value string, disableNormalizing bool) { - kv.key = getHeaderKeyBytes(kv, key, disableNormalizing) +func initHeaderKV(kv *argsKV, key, value string) { + kv.key = getHeaderKeyBytes(kv, key) kv.value = append(kv.value[:0], value...) } -func getHeaderKeyBytes(kv *argsKV, key string, disableNormalizing bool) []byte { +func getHeaderKeyBytes(kv *argsKV, key string) []byte { kv.key = append(kv.key[:0], key...) - normalizeHeaderKey(kv.key, disableNormalizing) + normalizeHeaderKey(kv.key) return kv.key } -func normalizeHeaderKey(b []byte, disableNormalizing bool) { - if disableNormalizing { - return - } - +func normalizeHeaderKey(b []byte) { n := len(b) if n == 0 { return @@ -2152,7 +1990,7 @@ func normalizeHeaderKey(b []byte, disableNormalizing bool) { // * foo-bar-baz -> Foo-Bar-Baz func AppendNormalizedHeaderKey(dst []byte, key string) []byte { dst = append(dst, key...) - normalizeHeaderKey(dst[len(dst)-len(key):], false) + normalizeHeaderKey(dst[len(dst)-len(key):]) return dst } @@ -2173,7 +2011,6 @@ func AppendNormalizedHeaderKeyBytes(dst, key []byte) []byte { var ( errNeedMore = errors.New("need more data: cannot find trailing lf") errSmallBuffer = errors.New("small read buffer. Increase ReadBufferSize") - errNothingRead = errors.New("read timeout with nothing read") ) // ErrSmallBuffer is returned when the provided buffer size is too small diff --git a/vendor/github.com/valyala/fasthttp/http.go b/vendor/github.com/VictoriaMetrics/fasthttp/http.go similarity index 94% rename from vendor/github.com/valyala/fasthttp/http.go rename to vendor/github.com/VictoriaMetrics/fasthttp/http.go index 10dc4654e..5fc3bee11 100644 --- a/vendor/github.com/valyala/fasthttp/http.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/http.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "mime/multipart" - "net" "os" "sync" @@ -45,9 +44,6 @@ type Request struct { keepBodyBuffer bool isTLS bool - - // To detect scheme changes in redirects - schemaUpdate bool } // Response represents HTTP response. @@ -76,11 +72,6 @@ type Response struct { SkipBody bool keepBodyBuffer bool - - // Remote TCPAddr from concurrently net.Conn - raddr net.Addr - // Local TCPAddr from concurrently net.Conn - laddr net.Addr } // SetHost sets host for the request. @@ -287,23 +278,6 @@ func (w *requestBodyWriter) Write(p []byte) (int, error) { return len(p), nil } -func (resp *Response) parseNetConn(conn net.Conn) { - resp.raddr = conn.RemoteAddr() - resp.laddr = conn.LocalAddr() -} - -// RemoteAddr returns the remote network address. The Addr returned is shared -// by all invocations of RemoteAddr, so do not modify it. -func (resp *Response) RemoteAddr() net.Addr { - return resp.raddr -} - -// LocalAddr returns the local network address. The Addr returned is shared -// by all invocations of LocalAddr, so do not modify it. -func (resp *Response) LocalAddr() net.Addr { - return resp.laddr -} - // Body returns response body. // // The returned body is valid until the response modification. @@ -372,7 +346,7 @@ func (resp *Response) BodyGunzip() ([]byte, error) { } func gunzipData(p []byte) ([]byte, error) { - var bb bytebufferpool.ByteBuffer + var bb ByteBuffer _, err := WriteGunzip(&bb, p) if err != nil { return nil, err @@ -399,7 +373,7 @@ func (resp *Response) BodyInflate() ([]byte, error) { } func inflateData(p []byte) ([]byte, error) { - var bb bytebufferpool.ByteBuffer + var bb ByteBuffer _, err := WriteInflate(&bb, p) if err != nil { return nil, err @@ -650,8 +624,6 @@ func (resp *Response) copyToSkipBody(dst *Response) { dst.Reset() resp.Header.CopyTo(&dst.Header) dst.SkipBody = resp.SkipBody - dst.raddr = resp.raddr - dst.laddr = resp.laddr } func swapRequestBody(a, b *Request) { @@ -739,7 +711,7 @@ func (req *Request) MultipartForm() (*multipart.Form, error) { } func marshalMultipartForm(f *multipart.Form, boundary string) ([]byte, error) { - var buf bytebufferpool.ByteBuffer + var buf ByteBuffer if err := WriteMultipartForm(&buf, f, boundary); err != nil { return nil, err } @@ -750,7 +722,7 @@ func marshalMultipartForm(f *multipart.Form, boundary string) ([]byte, error) { // boundary to w. func WriteMultipartForm(w io.Writer, f *multipart.Form, boundary string) error { // Do not care about memory allocations here, since multipart - // form processing is slow. + // form processing is slooow. if len(boundary) == 0 { panic("BUG: form boundary cannot be empty") } @@ -772,7 +744,7 @@ func WriteMultipartForm(w io.Writer, f *multipart.Form, boundary string) error { // marshal files for k, fvv := range f.File { for _, fv := range fvv { - vw, err := mw.CreatePart(fv.Header) + vw, err := mw.CreateFormFile(k, fv.Filename) if err != nil { return fmt.Errorf("cannot create form file %q (%q): %s", k, fv.Filename, err) } @@ -845,8 +817,6 @@ func (resp *Response) Reset() { resp.Header.Reset() resp.resetSkipHeader() resp.SkipBody = false - resp.raddr = nil - resp.laddr = nil } func (resp *Response) resetSkipHeader() { @@ -874,9 +844,7 @@ func (req *Request) Read(r *bufio.Reader) error { const defaultMaxInMemoryFileSize = 16 * 1024 * 1024 -// ErrGetOnly is returned when server expects only GET requests, -// but some other type of request came (Server.GetOnly option is true). -var ErrGetOnly = errors.New("non-GET request received") +var errGetOnly = errors.New("non-GET request received") // ReadLimitBody reads request from the given r, limiting the body size. // @@ -910,7 +878,11 @@ func (req *Request) readLimitBody(r *bufio.Reader, maxBodySize int, getOnly bool return err } if getOnly && !req.Header.IsGet() { - return ErrGetOnly + return errGetOnly + } + + if req.Header.noBody() { + return nil } if req.MayContinue() { @@ -946,7 +918,7 @@ func (req *Request) MayContinue() bool { // then ErrBodyTooLarge is returned. func (req *Request) ContinueReadBody(r *bufio.Reader, maxBodySize int) error { var err error - contentLength := req.Header.realContentLength() + contentLength := req.Header.ContentLength() if contentLength > 0 { if maxBodySize > 0 && contentLength > maxBodySize { return ErrBodyTooLarge @@ -1016,6 +988,7 @@ func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) error { bodyBuf.Reset() bodyBuf.B, err = readBody(r, resp.Header.ContentLength(), maxBodySize, bodyBuf.B) if err != nil { + resp.Reset() return err } resp.Header.SetContentLength(len(bodyBuf.B)) @@ -1136,11 +1109,8 @@ func (req *Request) Write(w *bufio.Writer) error { req.Header.SetMultipartFormBoundary(req.multipartFormBoundary) } - hasBody := !req.Header.ignoreBody() + hasBody := !req.Header.noBody() if hasBody { - if len(body) == 0 { - body = req.postArgs.QueryString() - } req.Header.SetContentLength(len(body)) } if err = req.Header.Write(w); err != nil { @@ -1488,7 +1458,7 @@ func (resp *Response) String() string { } func getHTTPString(hw httpWriter) string { - w := bytebufferpool.Get() + w := AcquireByteBuffer() bw := bufio.NewWriter(w) if err := hw.Write(bw); err != nil { return err.Error() @@ -1497,7 +1467,7 @@ func getHTTPString(hw httpWriter) string { return err.Error() } s := string(w.B) - bytebufferpool.Put(w) + ReleaseByteBuffer(w) return s } @@ -1680,11 +1650,6 @@ func appendBodyFixedSize(r *bufio.Reader, dst []byte, n int) ([]byte, error) { } } -// ErrBrokenChunk is returned when server receives a broken chunked body (Transfer-Encoding: chunked). -type ErrBrokenChunk struct { - error -} - func readBodyChunked(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, error) { if len(dst) > 0 { panic("BUG: expected zero-length buffer") @@ -1704,9 +1669,7 @@ func readBodyChunked(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, erro return dst, err } if !bytes.Equal(dst[len(dst)-strCRLFLen:], strCRLF) { - return dst, ErrBrokenChunk{ - error: fmt.Errorf("cannot find crlf at the end of chunk"), - } + return dst, fmt.Errorf("cannot find crlf at the end of chunk") } dst = dst[:len(dst)-strCRLFLen] if chunkSize == 0 { @@ -1720,34 +1683,19 @@ func parseChunkSize(r *bufio.Reader) (int, error) { if err != nil { return -1, err } - for { - c, err := r.ReadByte() - if err != nil { - return -1, ErrBrokenChunk{ - error: fmt.Errorf("cannot read '\r' char at the end of chunk size: %s", err), - } - } - // Skip any trailing whitespace after chunk size. - if c == ' ' { - continue - } - if c != '\r' { - return -1, ErrBrokenChunk{ - error: fmt.Errorf("unexpected char %q at the end of chunk size. Expected %q", c, '\r'), - } - } - break - } c, err := r.ReadByte() if err != nil { - return -1, ErrBrokenChunk{ - error: fmt.Errorf("cannot read '\n' char at the end of chunk size: %s", err), - } + return -1, fmt.Errorf("cannot read '\r' char at the end of chunk size: %s", err) + } + if c != '\r' { + return -1, fmt.Errorf("unexpected char %q at the end of chunk size. Expected %q", c, '\r') + } + c, err = r.ReadByte() + if err != nil { + return -1, fmt.Errorf("cannot read '\n' char at the end of chunk size: %s", err) } if c != '\n' { - return -1, ErrBrokenChunk{ - error: fmt.Errorf("unexpected char %q at the end of chunk size. Expected %q", c, '\n'), - } + return -1, fmt.Errorf("unexpected char %q at the end of chunk size. Expected %q", c, '\n') } return n, nil } diff --git a/vendor/github.com/valyala/fasthttp/lbclient.go b/vendor/github.com/VictoriaMetrics/fasthttp/lbclient.go similarity index 98% rename from vendor/github.com/valyala/fasthttp/lbclient.go rename to vendor/github.com/VictoriaMetrics/fasthttp/lbclient.go index 12418b6b6..41fe727f9 100644 --- a/vendor/github.com/valyala/fasthttp/lbclient.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/lbclient.go @@ -59,7 +59,7 @@ type LBClient struct { // DefaultLBClientTimeout is the default request timeout used by LBClient // when calling LBClient.Do. // -// The timeout may be overridden via LBClient.Timeout. +// The timeout may be overriden via LBClient.Timeout. const DefaultLBClientTimeout = time.Second // DoDeadline calls DoDeadline on the least loaded client diff --git a/vendor/github.com/valyala/fasthttp/nocopy.go b/vendor/github.com/VictoriaMetrics/fasthttp/nocopy.go similarity index 64% rename from vendor/github.com/valyala/fasthttp/nocopy.go rename to vendor/github.com/VictoriaMetrics/fasthttp/nocopy.go index 8e9b89a41..32af52e43 100644 --- a/vendor/github.com/valyala/fasthttp/nocopy.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/nocopy.go @@ -4,8 +4,6 @@ package fasthttp // so `go vet` gives a warning if this struct is copied. // // See https://github.com/golang/go/issues/8005#issuecomment-190753527 for details. -// and also: https://stackoverflow.com/questions/52494458/nocopy-minimal-example type noCopy struct{} -func (*noCopy) Lock() {} -func (*noCopy) Unlock() {} +func (*noCopy) Lock() {} diff --git a/vendor/github.com/valyala/fasthttp/peripconn.go b/vendor/github.com/VictoriaMetrics/fasthttp/peripconn.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/peripconn.go rename to vendor/github.com/VictoriaMetrics/fasthttp/peripconn.go diff --git a/vendor/github.com/valyala/fasthttp/server.go b/vendor/github.com/VictoriaMetrics/fasthttp/server.go similarity index 72% rename from vendor/github.com/valyala/fasthttp/server.go rename to vendor/github.com/VictoriaMetrics/fasthttp/server.go index 5fcf20f5f..3e74369e7 100644 --- a/vendor/github.com/valyala/fasthttp/server.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/server.go @@ -2,7 +2,6 @@ package fasthttp import ( "bufio" - "context" "crypto/tls" "errors" "fmt" @@ -17,14 +16,6 @@ import ( "time" ) -var errNoCertOrKeyProvided = errors.New("Cert or key has not provided") - -var ( - // ErrAlreadyServing is returned when calling Serve on a Server - // that is already serving connections. - ErrAlreadyServing = errors.New("Server is already serving connections") -) - // ServeConn serves HTTP requests from the given connection // using the given handler. // @@ -135,9 +126,6 @@ func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handler Reque // must be limited. type RequestHandler func(ctx *RequestCtx) -// ServeHandler must process tls.Config.NextProto negotiated requests. -type ServeHandler func(c net.Conn) error - // Server implements HTTP server. // // Default Server settings should satisfy the majority of Server users. @@ -151,22 +139,8 @@ type Server struct { noCopy noCopy // Handler for processing incoming requests. - // - // Take into account that no `panic` recovery is done by `fasthttp` (thus any `panic` will take down the entire server). - // Instead the user should use `recover` to handle these situations. Handler RequestHandler - // ErrorHandler for returning a response in case of an error while receiving or parsing the request. - // - // The following is a non-exhaustive list of errors that can be expected as argument: - // * io.EOF - // * io.ErrUnexpectedEOF - // * ErrGetOnly - // * ErrSmallBuffer - // * ErrBodyTooLarge - // * ErrBrokenChunks - ErrorHandler func(ctx *RequestCtx, err error) - // Server name for sending in response headers. // // Default server name is used if left blank. @@ -237,18 +211,6 @@ type Server struct { // By default keep-alive connection lifetime is unlimited. MaxKeepaliveDuration time.Duration - // Whether to enable tcp keep-alive connections. - // - // Whether the operating system should send tcp keep-alive messages on the tcp connection. - // - // By default tcp keep-alive connections are disabled. - TCPKeepalive bool - - // Period between tcp keep-alive messages. - // - // TCP keep-alive period is determined by operation system by default. - TCPKeepalivePeriod time.Duration - // Maximum request body size. // // The server rejects requests with bodies exceeding this limit. @@ -285,58 +247,11 @@ type Server struct { // are suppressed in order to limit output log traffic. LogAllErrors bool - // Header names are passed as-is without normalization - // if this option is set. - // - // Disabled header names' normalization may be useful only for proxying - // incoming requests to other servers expecting case-sensitive - // header names. See https://github.com/valyala/fasthttp/issues/57 - // for details. - // - // By default request and response header names are normalized, i.e. - // The first letter and the first letters following dashes - // are uppercased, while all the other letters are lowercased. - // Examples: - // - // * HOST -> Host - // * content-type -> Content-Type - // * cONTENT-lenGTH -> Content-Length - DisableHeaderNamesNormalizing bool - - // SleepWhenConcurrencyLimitsExceeded is a duration to be slept of if - // the concurrency limit in exceeded (default [when is 0]: don't sleep - // and accept new connections immidiatelly). - SleepWhenConcurrencyLimitsExceeded time.Duration - - // NoDefaultServerHeader, when set to true, causes the default Server header - // to be excluded from the Response. - // - // The default Server header value is the value of the Name field or an - // internal default value in its absence. With this option set to true, - // the only time a Server header will be sent is if a non-zero length - // value is explicitly provided during a request. - NoDefaultServerHeader bool - - // NoDefaultContentType, when set to true, causes the default Content-Type - // header to be excluded from the Response. - // - // The default Content-Type header value is the internal default value. When - // set to true, the Content-Type will not be present. - NoDefaultContentType bool - - // ConnState specifies an optional callback function that is - // called when a client connection changes state. See the - // ConnState type and associated constants for details. - ConnState func(net.Conn, ConnState) - // Logger, which is used by RequestCtx.Logger(). // // By default standard logger from log package is used. Logger Logger - tlsConfig *tls.Config - nextProtos map[string]ServeHandler - concurrency uint32 concurrencyCh chan struct{} perIPConnCounter perIPConnCounter @@ -347,14 +262,6 @@ type Server struct { writerPool sync.Pool hijackConnPool sync.Pool bytePool sync.Pool - - // We need to know our listener so we can close it in Shutdown(). - ln net.Listener - - mu sync.Mutex - open int32 - stop int32 - done chan struct{} } // TimeoutHandler creates RequestHandler, which returns StatusRequestTimeout @@ -419,6 +326,12 @@ func CompressHandler(h RequestHandler) RequestHandler { func CompressHandlerLevel(h RequestHandler, level int) RequestHandler { return func(ctx *RequestCtx) { h(ctx) + ce := ctx.Response.Header.PeekBytes(strContentEncoding) + if len(ce) > 0 { + // Do not compress responses with non-empty + // Content-Encoding. + return + } if ctx.Request.Header.HasAcceptEncodingBytes(strGzip) { ctx.Response.gzipBody(level) } else if ctx.Request.Header.HasAcceptEncodingBytes(strDeflate) { @@ -567,7 +480,6 @@ func (ctx *RequestCtx) VisitUserValues(visitor func([]byte, interface{})) { } type connTLSer interface { - Handshake() error ConnectionState() tls.ConnectionState } @@ -602,15 +514,6 @@ func (ctx *RequestCtx) TLSConnectionState() *tls.ConnectionState { return &state } -// Conn returns a reference to the underlying net.Conn. -// -// WARNING: Only use this method if you know what you are doing! -// -// Reading from or writing to the returned connection will end badly! -func (ctx *RequestCtx) Conn() net.Conn { - return ctx.c -} - type firstByteReader struct { c net.Conn ch byte @@ -677,13 +580,18 @@ func (ctx *RequestCtx) ConnID() uint64 { return ctx.connID } -// Time returns RequestHandler call time. +// Time returns RequestHandler call time truncated to the nearest second. +// +// Call time.Now() at the beginning of RequestHandler in order to obtain +// percise RequestHandler call time. func (ctx *RequestCtx) Time() time.Time { return ctx.time } -// ConnTime returns the time the server started serving the connection +// ConnTime returns the time server starts serving the connection // the current request came from. +// +// The returned time is truncated to the nearest second. func (ctx *RequestCtx) ConnTime() time.Time { return ctx.connTime } @@ -832,28 +740,12 @@ func SaveMultipartFile(fh *multipart.FileHeader, path string) error { if err != nil { return err } + defer f.Close() if ff, ok := f.(*os.File); ok { - // Windows can't rename files that are opened. - if err := f.Close(); err != nil { - return err - } - - // If renaming fails we try the normal copying method. - // Renaming could fail if the files are on different devices. - if os.Rename(ff.Name(), path) == nil { - return nil - } - - // Reopen f for the code below. - f, err = fh.Open() - if err != nil { - return err - } + return os.Rename(ff.Name(), path) } - defer f.Close() - ff, err := os.Create(path) if err != nil { return err @@ -917,26 +809,6 @@ func (ctx *RequestCtx) IsDelete() bool { return ctx.Request.Header.IsDelete() } -// IsConnect returns true if request method is CONNECT. -func (ctx *RequestCtx) IsConnect() bool { - return ctx.Request.Header.IsConnect() -} - -// IsOptions returns true if request method is OPTIONS. -func (ctx *RequestCtx) IsOptions() bool { - return ctx.Request.Header.IsOptions() -} - -// IsTrace returns true if request method is TRACE. -func (ctx *RequestCtx) IsTrace() bool { - return ctx.Request.Header.IsTrace() -} - -// IsPatch returns true if request method is PATCH. -func (ctx *RequestCtx) IsPatch() bool { - return ctx.Request.Header.IsPatch() -} - // Method return request method. // // Returned value is valid until returning from RequestHandler. @@ -1028,18 +900,11 @@ func (ctx *RequestCtx) SuccessString(contentType, body string) { // * StatusFound (302) // * StatusSeeOther (303) // * StatusTemporaryRedirect (307) -// * StatusPermanentRedirect (308) // // All other statusCode values are replaced by StatusFound (302). // // The redirect uri may be either absolute or relative to the current -// request uri. Fasthttp will always send an absolute uri back to the client. -// To send a relative uri you can use the following code: -// -// strLocation = []byte("Location") // Put this with your top level var () declarations. -// ctx.Response.Header.SetCanonical(strLocation, "/relative?uri") -// ctx.Response.SetStatusCode(fasthttp.StatusMovedPermanently) -// +// request uri. func (ctx *RequestCtx) Redirect(uri string, statusCode int) { u := AcquireURI() ctx.URI().CopyTo(u) @@ -1057,18 +922,11 @@ func (ctx *RequestCtx) Redirect(uri string, statusCode int) { // * StatusFound (302) // * StatusSeeOther (303) // * StatusTemporaryRedirect (307) -// * StatusPermanentRedirect (308) // // All other statusCode values are replaced by StatusFound (302). // // The redirect uri may be either absolute or relative to the current -// request uri. Fasthttp will always send an absolute uri back to the client. -// To send a relative uri you can use the following code: -// -// strLocation = []byte("Location") // Put this with your top level var () declarations. -// ctx.Response.Header.SetCanonical(strLocation, "/relative?uri") -// ctx.Response.SetStatusCode(fasthttp.StatusMovedPermanently) -// +// request uri. func (ctx *RequestCtx) RedirectBytes(uri []byte, statusCode int) { s := b2s(uri) ctx.Redirect(s, statusCode) @@ -1082,8 +940,7 @@ func (ctx *RequestCtx) redirect(uri []byte, statusCode int) { func getRedirectStatusCode(statusCode int) int { if statusCode == StatusMovedPermanently || statusCode == StatusFound || - statusCode == StatusSeeOther || statusCode == StatusTemporaryRedirect || - statusCode == StatusPermanentRedirect { + statusCode == StatusSeeOther || statusCode == StatusTemporaryRedirect { return statusCode } return StatusFound @@ -1280,69 +1137,15 @@ func (ctx *RequestCtx) TimeoutErrorWithResponse(resp *Response) { ctx.timeoutResponse = respCopy } -// NextProto adds nph to be processed when key is negotiated when TLS -// connection is established. -// -// This function can only be called before the server is started. -func (s *Server) NextProto(key string, nph ServeHandler) { - if s.nextProtos == nil { - s.nextProtos = make(map[string]ServeHandler) - } - s.configTLS() - s.tlsConfig.NextProtos = append(s.tlsConfig.NextProtos, key) - s.nextProtos[key] = nph -} - -func (s *Server) getNextProto(c net.Conn) (proto string, err error) { - if tlsConn, ok := c.(connTLSer); ok { - err = tlsConn.Handshake() - if err == nil { - proto = tlsConn.ConnectionState().NegotiatedProtocol - } - } - return -} - -// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted -// connections. It's used by ListenAndServe, ListenAndServeTLS and -// ListenAndServeTLSEmbed so dead TCP connections (e.g. closing laptop mid-download) -// eventually go away. -type tcpKeepaliveListener struct { - *net.TCPListener - keepalivePeriod time.Duration -} - -func (ln tcpKeepaliveListener) Accept() (net.Conn, error) { - tc, err := ln.AcceptTCP() - if err != nil { - return nil, err - } - tc.SetKeepAlive(true) - if ln.keepalivePeriod > 0 { - tc.SetKeepAlivePeriod(ln.keepalivePeriod) - } - return tc, nil -} - // ListenAndServe serves HTTP requests from the given TCP4 addr. // // Pass custom listener to Serve if you need listening on non-TCP4 media // such as IPv6. -// -// Accepted connections are configured to enable TCP keep-alives. func (s *Server) ListenAndServe(addr string) error { ln, err := net.Listen("tcp4", addr) if err != nil { return err } - if s.TCPKeepalive { - if tcpln, ok := ln.(*net.TCPListener); ok { - return s.Serve(tcpKeepaliveListener{ - TCPListener: tcpln, - keepalivePeriod: s.TCPKeepalivePeriod, - }) - } - } return s.Serve(ln) } @@ -1371,24 +1174,11 @@ func (s *Server) ListenAndServeUNIX(addr string, mode os.FileMode) error { // // Pass custom listener to Serve if you need listening on non-TCP4 media // such as IPv6. -// -// If the certFile or keyFile has not been provided to the server structure, -// the function will use the previously added TLS configuration. -// -// Accepted connections are configured to enable TCP keep-alives. func (s *Server) ListenAndServeTLS(addr, certFile, keyFile string) error { ln, err := net.Listen("tcp4", addr) if err != nil { return err } - if s.TCPKeepalive { - if tcpln, ok := ln.(*net.TCPListener); ok { - return s.ServeTLS(tcpKeepaliveListener{ - TCPListener: tcpln, - keepalivePeriod: s.TCPKeepalivePeriod, - }, certFile, keyFile) - } - } return s.ServeTLS(ln, certFile, keyFile) } @@ -1398,113 +1188,59 @@ func (s *Server) ListenAndServeTLS(addr, certFile, keyFile string) error { // // Pass custom listener to Serve if you need listening on arbitrary media // such as IPv6. -// -// If the certFile or keyFile has not been provided the server structure, -// the function will use previously added TLS configuration. -// -// Accepted connections are configured to enable TCP keep-alives. func (s *Server) ListenAndServeTLSEmbed(addr string, certData, keyData []byte) error { ln, err := net.Listen("tcp4", addr) if err != nil { return err } - if s.TCPKeepalive { - if tcpln, ok := ln.(*net.TCPListener); ok { - return s.ServeTLSEmbed(tcpKeepaliveListener{ - TCPListener: tcpln, - keepalivePeriod: s.TCPKeepalivePeriod, - }, certData, keyData) - } - } return s.ServeTLSEmbed(ln, certData, keyData) } // ServeTLS serves HTTPS requests from the given listener. // // certFile and keyFile are paths to TLS certificate and key files. -// -// If the certFile or keyFile has not been provided the server structure, -// the function will use previously added TLS configuration. func (s *Server) ServeTLS(ln net.Listener, certFile, keyFile string) error { - err := s.AppendCert(certFile, keyFile) - if err != nil && err != errNoCertOrKeyProvided { + lnTLS, err := newTLSListener(ln, certFile, keyFile) + if err != nil { return err } - if s.tlsConfig == nil { - return errNoCertOrKeyProvided - } - s.tlsConfig.BuildNameToCertificate() - - return s.Serve( - tls.NewListener(ln, s.tlsConfig), - ) + return s.Serve(lnTLS) } // ServeTLSEmbed serves HTTPS requests from the given listener. // // certData and keyData must contain valid TLS certificate and key data. -// -// If the certFile or keyFile has not been provided the server structure, -// the function will use previously added TLS configuration. func (s *Server) ServeTLSEmbed(ln net.Listener, certData, keyData []byte) error { - err := s.AppendCertEmbed(certData, keyData) - if err != nil && err != errNoCertOrKeyProvided { + lnTLS, err := newTLSListenerEmbed(ln, certData, keyData) + if err != nil { return err } - if s.tlsConfig == nil { - return errNoCertOrKeyProvided - } - s.tlsConfig.BuildNameToCertificate() - - return s.Serve( - tls.NewListener(ln, s.tlsConfig), - ) + return s.Serve(lnTLS) } -// AppendCert appends certificate and keyfile to TLS Configuration. -// -// This function allows programmer to handle multiple domains -// in one server structure. See examples/multidomain -func (s *Server) AppendCert(certFile, keyFile string) error { - if len(certFile) == 0 && len(keyFile) == 0 { - return errNoCertOrKeyProvided - } - +func newTLSListener(ln net.Listener, certFile, keyFile string) (net.Listener, error) { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { - return fmt.Errorf("cannot load TLS key pair from certFile=%q and keyFile=%q: %s", certFile, keyFile, err) + return nil, fmt.Errorf("cannot load TLS key pair from certFile=%q and keyFile=%q: %s", certFile, keyFile, err) } - - s.configTLS() - - s.tlsConfig.Certificates = append(s.tlsConfig.Certificates, cert) - return nil + return newCertListener(ln, &cert), nil } -// AppendCertEmbed does the same as AppendCert but using in-memory data. -func (s *Server) AppendCertEmbed(certData, keyData []byte) error { - if len(certData) == 0 && len(keyData) == 0 { - return errNoCertOrKeyProvided - } - +func newTLSListenerEmbed(ln net.Listener, certData, keyData []byte) (net.Listener, error) { cert, err := tls.X509KeyPair(certData, keyData) if err != nil { - return fmt.Errorf("cannot load TLS key pair from the provided certData(%d) and keyData(%d): %s", + return nil, fmt.Errorf("cannot load TLS key pair from the provided certData(%d) and keyData(%d): %s", len(certData), len(keyData), err) } - - s.configTLS() - - s.tlsConfig.Certificates = append(s.tlsConfig.Certificates, cert) - return nil + return newCertListener(ln, &cert), nil } -func (s *Server) configTLS() { - if s.tlsConfig == nil { - s.tlsConfig = &tls.Config{ - PreferServerCipherSuites: true, - } +func newCertListener(ln net.Listener, cert *tls.Certificate) net.Listener { + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{*cert}, + PreferServerCipherSuites: true, } + return tls.NewListener(ln, tlsConfig) } // DefaultConcurrency is the maximum number of concurrent connections @@ -1520,18 +1256,6 @@ func (s *Server) Serve(ln net.Listener) error { var c net.Conn var err error - s.mu.Lock() - { - if s.ln != nil { - s.mu.Unlock() - return ErrAlreadyServing - } - - s.ln = ln - s.done = make(chan struct{}) - } - s.mu.Unlock() - maxWorkersCount := s.getConcurrency() s.concurrencyCh = make(chan struct{}, maxWorkersCount) wp := &workerPool{ @@ -1539,17 +1263,9 @@ func (s *Server) Serve(ln net.Listener) error { MaxWorkersCount: maxWorkersCount, LogAllErrors: s.LogAllErrors, Logger: s.logger(), - connState: s.setState, } wp.Start() - // Count our waiting to accept a connection as an open connection. - // This way we can't get into any weird state where just after accepting - // a connection Shutdown is called which reads open as 0 because it isn't - // incremented yet. - atomic.AddInt32(&s.open, 1) - defer atomic.AddInt32(&s.open, -1) - for { if c, err = acceptConn(s, ln, &lastPerIPErrorTime); err != nil { wp.Stop() @@ -1558,18 +1274,14 @@ func (s *Server) Serve(ln net.Listener) error { } return err } - s.setState(c, StateNew) - atomic.AddInt32(&s.open, 1) if !wp.Serve(c) { - atomic.AddInt32(&s.open, -1) s.writeFastError(c, StatusServiceUnavailable, "The connection cannot be served because Server.Concurrency limit exceeded") c.Close() - s.setState(c, StateClosed) if time.Since(lastOverflowErrorTime) > time.Minute { s.logger().Printf("The incoming connection cannot be served, because %d concurrent connections are served. "+ "Try increasing Server.Concurrency", maxWorkersCount) - lastOverflowErrorTime = time.Now() + lastOverflowErrorTime = CoarseTimeNow() } // The current server reached concurrency limit, @@ -1578,59 +1290,12 @@ func (s *Server) Serve(ln net.Listener) error { // // There is a hope other servers didn't reach their // concurrency limits yet :) - // - // See also: https://github.com/valyala/fasthttp/pull/485#discussion_r239994990 - if s.SleepWhenConcurrencyLimitsExceeded > 0 { - time.Sleep(s.SleepWhenConcurrencyLimitsExceeded) - } + time.Sleep(100 * time.Millisecond) } c = nil } } -// Shutdown gracefully shuts down the server without interrupting any active connections. -// Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle and then shut down. -// -// When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil. -// Make sure the program doesn't exit and waits instead for Shutdown to return. -// -// Shutdown does not close keepalive connections so its recommended to set ReadTimeout to something else than 0. -func (s *Server) Shutdown() error { - s.mu.Lock() - defer s.mu.Unlock() - - atomic.StoreInt32(&s.stop, 1) - defer atomic.StoreInt32(&s.stop, 0) - - if s.ln == nil { - return nil - } - - if err := s.ln.Close(); err != nil { - return err - } - - if s.done != nil { - close(s.done) - } - - // Closing the listener will make Serve() call Stop on the worker pool. - // Setting .stop to 1 will make serveConn() break out of its loop. - // Now we just have to wait until all workers are done. - for { - if open := atomic.LoadInt32(&s.open); open == 0 { - break - } - // This is not an optimal solution but using a sync.WaitGroup - // here causes data races as it's hard to prevent Add() to be called - // while Wait() is waiting. - time.Sleep(time.Millisecond * 100) - } - - s.ln = nil - return nil -} - func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net.Conn, error) { for { c, err := ln.Accept() @@ -1658,7 +1323,7 @@ func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net. if time.Since(*lastPerIPErrorTime) > time.Minute { s.logger().Printf("The number of connections from %s exceeds MaxConnsPerIP=%d", getConnIP4(c), s.MaxConnsPerIP) - *lastPerIPErrorTime = time.Now() + *lastPerIPErrorTime = CoarseTimeNow() } continue } @@ -1698,8 +1363,8 @@ var ( ErrPerIPConnLimit = errors.New("too many connections per ip") // ErrConcurrencyLimit may be returned from ServeConn if the number - // of concurrently served connections exceeds Server.Concurrency. - ErrConcurrencyLimit = errors.New("cannot serve the connection because Server.Concurrency concurrent connections are served") + // of concurrenty served connections exceeds Server.Concurrency. + ErrConcurrencyLimit = errors.New("canot serve the connection because Server.Concurrency concurrent connections are served") // ErrKeepaliveTimeout is returned from ServeConn // if the connection lifetime exceeds MaxKeepaliveDuration. @@ -1732,42 +1397,23 @@ func (s *Server) ServeConn(c net.Conn) error { return ErrConcurrencyLimit } - atomic.AddInt32(&s.open, 1) - err := s.serveConn(c) atomic.AddUint32(&s.concurrency, ^uint32(0)) if err != errHijacked { err1 := c.Close() - s.setState(c, StateClosed) if err == nil { err = err1 } } else { err = nil - s.setState(c, StateHijacked) } return err } var errHijacked = errors.New("connection has been hijacked") -// GetCurrentConcurrency returns a number of currently served -// connections. -// -// This function is intended be used by monitoring systems -func (s *Server) GetCurrentConcurrency() uint32 { - return atomic.LoadUint32(&s.concurrency) -} - -// GetOpenConnectionsCount returns a number of opened connections. -// -// This function is intended be used by monitoring systems -func (s *Server) GetOpenConnectionsCount() int32 { - return atomic.LoadInt32(&s.open) - 1 -} - func (s *Server) getConcurrency() int { n := s.Concurrency if n <= 0 { @@ -1789,24 +1435,10 @@ func nextConnID() uint64 { const DefaultMaxRequestBodySize = 4 * 1024 * 1024 func (s *Server) serveConn(c net.Conn) error { - defer atomic.AddInt32(&s.open, -1) - - if proto, err := s.getNextProto(c); err != nil { - return err - } else { - handler, ok := s.nextProtos[proto] - if ok { - return handler(c) - } - } - - var serverName []byte - if !s.NoDefaultServerHeader { - serverName = s.getServerName() - } + serverName := s.getServerName() connRequestNum := uint64(0) connID := nextConnID() - currentTime := time.Now() + currentTime := CoarseTimeNow() connTime := currentTime maxRequestBodySize := s.MaxRequestBodySize if maxRequestBodySize <= 0 { @@ -1850,84 +1482,64 @@ func (s *Server) serveConn(c net.Conn) error { br, err = acquireByteReader(&ctx) } ctx.Request.isTLS = isTLS - ctx.Response.Header.noDefaultContentType = s.NoDefaultContentType if err == nil { - if s.DisableHeaderNamesNormalizing { - ctx.Request.Header.DisableNormalizing() - ctx.Response.Header.DisableNormalizing() - } - // reading Headers and Body err = ctx.Request.readLimitBody(br, maxRequestBodySize, s.GetOnly) - if err == nil { - // If we read any bytes off the wire, we're active. - s.setState(c, StateActive) - } - if (s.ReduceMemoryUsage && br.Buffered() == 0) || err != nil { + if br.Buffered() == 0 || err != nil { releaseReader(s, br) br = nil } } - currentTime = time.Now() + currentTime = CoarseTimeNow() ctx.lastReadDuration = currentTime.Sub(ctx.time) if err != nil { if err == io.EOF { err = nil - } else if connRequestNum > 1 && err == errNothingRead { - // This is not the first request and we haven't read a single byte - // of a new request yet. This means it's just a keep-alive connection - // closing down either because the remote closed it or because - // or a read timeout on our side. Either way just close the connection - // and don't return any error response. - err = nil } else { - bw = s.writeErrorResponse(bw, ctx, serverName, err) + bw = writeErrorResponse(bw, ctx, err) } break } // 'Expect: 100-continue' request handling. // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html for details. - if !ctx.Request.Header.ignoreBody() && ctx.Request.MayContinue() { + if !ctx.Request.Header.noBody() && ctx.Request.MayContinue() { // Send 'HTTP/1.1 100 Continue' response. if bw == nil { bw = acquireWriter(ctx) } bw.Write(strResponseContinue) err = bw.Flush() + releaseWriter(s, bw) + bw = nil if err != nil { break } - if s.ReduceMemoryUsage { - releaseWriter(s, bw) - bw = nil - } // Read request body. if br == nil { br = acquireReader(ctx) } err = ctx.Request.ContinueReadBody(br, maxRequestBodySize) - if (s.ReduceMemoryUsage && br.Buffered() == 0) || err != nil { + if br.Buffered() == 0 || err != nil { releaseReader(s, br) br = nil } if err != nil { - bw = s.writeErrorResponse(bw, ctx, serverName, err) + bw = writeErrorResponse(bw, ctx, err) break } } - connectionClose = s.DisableKeepalive || ctx.Request.Header.ConnectionClose() + connectionClose = s.DisableKeepalive || ctx.Request.Header.connectionCloseFast() isHTTP11 = ctx.Request.Header.IsHTTP11() - if serverName != nil { - ctx.Response.Header.SetServerBytes(serverName) - } + ctx.Response.Header.SetServerBytes(serverName) ctx.connID = connID ctx.connRequestNum = connRequestNum + ctx.connTime = connTime ctx.time = currentTime s.Handler(ctx) @@ -1959,7 +1571,9 @@ func (s *Server) serveConn(c net.Conn) error { lastWriteDeadlineTime = s.updateWriteDeadline(c, ctx, lastWriteDeadlineTime) } - connectionClose = connectionClose || ctx.Response.ConnectionClose() + // Verify Request.Header.connectionCloseFast() again, + // since request handler might trigger full headers' parsing. + connectionClose = connectionClose || ctx.Request.Header.connectionCloseFast() || ctx.Response.ConnectionClose() if connectionClose { ctx.Response.Header.SetCanonical(strConnection, strClose) } else if !isHTTP11 { @@ -1969,7 +1583,7 @@ func (s *Server) serveConn(c net.Conn) error { ctx.Response.Header.SetCanonical(strConnection, strKeepAlive) } - if serverName != nil && len(ctx.Response.Header.Server()) == 0 { + if len(ctx.Response.Header.Server()) == 0 { ctx.Response.Header.SetServerBytes(serverName) } @@ -1980,27 +1594,21 @@ func (s *Server) serveConn(c net.Conn) error { break } - // Only flush the writer if we don't have another request in the pipeline. - // This is a big of an ugly optimization for https://www.techempower.com/benchmarks/ - // This benchmark will send 16 pipelined requests. It is faster to pack as many responses - // in a TCP packet and send it back at once than waiting for a flush every request. - // In real world circumstances this behaviour could be argued as being wrong. - if br == nil || br.Buffered() == 0 || connectionClose { + if br == nil || connectionClose { err = bw.Flush() + releaseWriter(s, bw) + bw = nil if err != nil { break } - } - if connectionClose { - break - } - if s.ReduceMemoryUsage { - releaseWriter(s, bw) - bw = nil + if connectionClose { + break + } } if hijackHandler != nil { - var hjr io.Reader = c + var hjr io.Reader + hjr = c if br != nil { hjr = br br = nil @@ -2010,11 +1618,11 @@ func (s *Server) serveConn(c net.Conn) error { } if bw != nil { err = bw.Flush() + releaseWriter(s, bw) + bw = nil if err != nil { break } - releaseWriter(s, bw) - bw = nil } c.SetReadDeadline(zeroTime) c.SetWriteDeadline(zeroTime) @@ -2024,13 +1632,7 @@ func (s *Server) serveConn(c net.Conn) error { break } - currentTime = time.Now() - s.setState(c, StateIdle) - - if atomic.LoadInt32(&s.stop) == 1 { - err = nil - break - } + currentTime = CoarseTimeNow() } if br != nil { @@ -2043,12 +1645,6 @@ func (s *Server) serveConn(c net.Conn) error { return err } -func (s *Server) setState(nc net.Conn, state ConnState) { - if hook := s.ConnState; hook != nil { - hook(nc, state) - } -} - func (s *Server) updateReadDeadline(c net.Conn, ctx *RequestCtx, lastDeadlineTime time.Time) time.Time { readTimeout := s.ReadTimeout currentTime := ctx.time @@ -2092,7 +1688,7 @@ func (s *Server) updateWriteDeadline(c net.Conn, ctx *RequestCtx, lastDeadlineTi // Optimization: update write deadline only if more than 25% // of the last write deadline exceeded. // See https://github.com/golang/go/issues/15133 for details. - currentTime := time.Now() + currentTime := CoarseTimeNow() if currentTime.Sub(lastDeadlineTime) > (writeTimeout >> 2) { if err := c.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil { panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%s): %s", writeTimeout, err)) @@ -2246,8 +1842,9 @@ func releaseWriter(s *Server, w *bufio.Writer) { s.writerPool.Put(w) } -func (s *Server) acquireCtx(c net.Conn) (ctx *RequestCtx) { +func (s *Server) acquireCtx(c net.Conn) *RequestCtx { v := s.ctxPool.Get() + var ctx *RequestCtx if v == nil { ctx = &RequestCtx{ s: s, @@ -2259,7 +1856,7 @@ func (s *Server) acquireCtx(c net.Conn) (ctx *RequestCtx) { ctx = v.(*RequestCtx) } ctx.c = c - return + return ctx } // Init2 prepares ctx for passing to RequestHandler. @@ -2274,7 +1871,7 @@ func (ctx *RequestCtx) Init2(conn net.Conn, logger Logger, reduceMemoryUsage boo ctx.connID = nextConnID() ctx.s = fakeServer ctx.connRequestNum = 0 - ctx.connTime = time.Now() + ctx.connTime = CoarseTimeNow() ctx.time = ctx.connTime keepBodyBuffer := !reduceMemoryUsage @@ -2302,51 +1899,6 @@ func (ctx *RequestCtx) Init(req *Request, remoteAddr net.Addr, logger Logger) { req.CopyTo(&ctx.Request) } -// Deadline returns the time when work done on behalf of this context -// should be canceled. Deadline returns ok==false when no deadline is -// set. Successive calls to Deadline return the same results. -// -// This method always returns 0, false and is only present to make -// RequestCtx implement the context interface. -func (ctx *RequestCtx) Deadline() (deadline time.Time, ok bool) { - return -} - -// Done returns a channel that's closed when work done on behalf of this -// context should be canceled. Done may return nil if this context can -// never be canceled. Successive calls to Done return the same value. -func (ctx *RequestCtx) Done() <-chan struct{} { - return ctx.s.done -} - -// Err returns a non-nil error value after Done is closed, -// successive calls to Err return the same error. -// If Done is not yet closed, Err returns nil. -// If Done is closed, Err returns a non-nil error explaining why: -// Canceled if the context was canceled (via server Shutdown) -// or DeadlineExceeded if the context's deadline passed. -func (ctx *RequestCtx) Err() error { - select { - case <-ctx.s.done: - return context.Canceled - default: - return nil - } -} - -// Value returns the value associated with this context for key, or nil -// if no value is associated with key. Successive calls to Value with -// the same key returns the same result. -// -// This method is present to make RequestCtx implement the context interface. -// This method is the same as calling ctx.UserValue(key) -func (ctx *RequestCtx) Value(key interface{}) interface{} { - if keyString, ok := key.(string); ok { - return ctx.UserValue(keyString) - } - return nil -} - var fakeServer = &Server{ // Initialize concurrencyCh for TimeoutHandler concurrencyCh: make(chan struct{}, DefaultConcurrency), @@ -2404,41 +1956,22 @@ func (s *Server) getServerName() []byte { func (s *Server) writeFastError(w io.Writer, statusCode int, msg string) { w.Write(statusLine(statusCode)) - - server := "" - if !s.NoDefaultServerHeader { - server = fmt.Sprintf("Server: %s\r\n", s.getServerName()) - } - fmt.Fprintf(w, "Connection: close\r\n"+ - server+ + "Server: %s\r\n"+ "Date: %s\r\n"+ "Content-Type: text/plain\r\n"+ "Content-Length: %d\r\n"+ "\r\n"+ "%s", - serverDate.Load(), len(msg), msg) + s.getServerName(), serverDate.Load(), len(msg), msg) } -func defaultErrorHandler(ctx *RequestCtx, err error) { +func writeErrorResponse(bw *bufio.Writer, ctx *RequestCtx, err error) *bufio.Writer { if _, ok := err.(*ErrSmallBuffer); ok { ctx.Error("Too big request header", StatusRequestHeaderFieldsTooLarge) } else { ctx.Error("Error when parsing request", StatusBadRequest) } -} - -func (s *Server) writeErrorResponse(bw *bufio.Writer, ctx *RequestCtx, serverName []byte, err error) *bufio.Writer { - errorHandler := defaultErrorHandler - if s.ErrorHandler != nil { - errorHandler = s.ErrorHandler - } - - errorHandler(ctx, err) - - if serverName != nil { - ctx.Response.Header.SetServerBytes(serverName) - } ctx.SetConnectionClose() if bw == nil { bw = acquireWriter(ctx) @@ -2447,55 +1980,3 @@ func (s *Server) writeErrorResponse(bw *bufio.Writer, ctx *RequestCtx, serverNam bw.Flush() return bw } - -// A ConnState represents the state of a client connection to a server. -// It's used by the optional Server.ConnState hook. -type ConnState int - -const ( - // StateNew represents a new connection that is expected to - // send a request immediately. Connections begin at this - // state and then transition to either StateActive or - // StateClosed. - StateNew ConnState = iota - - // StateActive represents a connection that has read 1 or more - // bytes of a request. The Server.ConnState hook for - // StateActive fires before the request has entered a handler - // and doesn't fire again until the request has been - // handled. After the request is handled, the state - // transitions to StateClosed, StateHijacked, or StateIdle. - // For HTTP/2, StateActive fires on the transition from zero - // to one active request, and only transitions away once all - // active requests are complete. That means that ConnState - // cannot be used to do per-request work; ConnState only notes - // the overall state of the connection. - StateActive - - // StateIdle represents a connection that has finished - // handling a request and is in the keep-alive state, waiting - // for a new request. Connections transition from StateIdle - // to either StateActive or StateClosed. - StateIdle - - // StateHijacked represents a hijacked connection. - // This is a terminal state. It does not transition to StateClosed. - StateHijacked - - // StateClosed represents a closed connection. - // This is a terminal state. Hijacked connections do not - // transition to StateClosed. - StateClosed -) - -var stateName = map[ConnState]string{ - StateNew: "new", - StateActive: "active", - StateIdle: "idle", - StateHijacked: "hijacked", - StateClosed: "closed", -} - -func (c ConnState) String() string { - return stateName[c] -} diff --git a/vendor/github.com/valyala/fasthttp/ssl-cert-snakeoil.key b/vendor/github.com/VictoriaMetrics/fasthttp/ssl-cert-snakeoil.key similarity index 100% rename from vendor/github.com/valyala/fasthttp/ssl-cert-snakeoil.key rename to vendor/github.com/VictoriaMetrics/fasthttp/ssl-cert-snakeoil.key diff --git a/vendor/github.com/valyala/fasthttp/ssl-cert-snakeoil.pem b/vendor/github.com/VictoriaMetrics/fasthttp/ssl-cert-snakeoil.pem similarity index 100% rename from vendor/github.com/valyala/fasthttp/ssl-cert-snakeoil.pem rename to vendor/github.com/VictoriaMetrics/fasthttp/ssl-cert-snakeoil.pem diff --git a/vendor/github.com/valyala/fasthttp/stackless/doc.go b/vendor/github.com/VictoriaMetrics/fasthttp/stackless/doc.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/stackless/doc.go rename to vendor/github.com/VictoriaMetrics/fasthttp/stackless/doc.go diff --git a/vendor/github.com/valyala/fasthttp/stackless/func.go b/vendor/github.com/VictoriaMetrics/fasthttp/stackless/func.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/stackless/func.go rename to vendor/github.com/VictoriaMetrics/fasthttp/stackless/func.go diff --git a/vendor/github.com/valyala/fasthttp/stackless/writer.go b/vendor/github.com/VictoriaMetrics/fasthttp/stackless/writer.go similarity index 99% rename from vendor/github.com/valyala/fasthttp/stackless/writer.go rename to vendor/github.com/VictoriaMetrics/fasthttp/stackless/writer.go index c2053f9a1..9b9ff09d5 100644 --- a/vendor/github.com/valyala/fasthttp/stackless/writer.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/stackless/writer.go @@ -3,9 +3,8 @@ package stackless import ( "errors" "fmt" - "io" - "github.com/valyala/bytebufferpool" + "io" ) // Writer is an interface stackless writer must conform to. diff --git a/vendor/github.com/valyala/fasthttp/status.go b/vendor/github.com/VictoriaMetrics/fasthttp/status.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/status.go rename to vendor/github.com/VictoriaMetrics/fasthttp/status.go diff --git a/vendor/github.com/valyala/fasthttp/stream.go b/vendor/github.com/VictoriaMetrics/fasthttp/stream.go similarity index 95% rename from vendor/github.com/valyala/fasthttp/stream.go rename to vendor/github.com/VictoriaMetrics/fasthttp/stream.go index aa23b1af7..0b2ccc881 100644 --- a/vendor/github.com/valyala/fasthttp/stream.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/stream.go @@ -5,7 +5,7 @@ import ( "io" "sync" - "github.com/valyala/fasthttp/fasthttputil" + "github.com/VictoriaMetrics/fasthttp/fasthttputil" ) // StreamWriter must write data to w. diff --git a/vendor/github.com/valyala/fasthttp/strings.go b/vendor/github.com/VictoriaMetrics/fasthttp/strings.go similarity index 77% rename from vendor/github.com/valyala/fasthttp/strings.go rename to vendor/github.com/VictoriaMetrics/fasthttp/strings.go index 6d832310d..ebfa3edb2 100644 --- a/vendor/github.com/valyala/fasthttp/strings.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/strings.go @@ -22,15 +22,11 @@ var ( strResponseContinue = []byte("HTTP/1.1 100 Continue\r\n\r\n") - strGet = []byte("GET") - strHead = []byte("HEAD") - strPost = []byte("POST") - strPut = []byte("PUT") - strDelete = []byte("DELETE") - strConnect = []byte("CONNECT") - strOptions = []byte("OPTIONS") - strTrace = []byte("TRACE") - strPatch = []byte("PATCH") + strGet = []byte("GET") + strHead = []byte("HEAD") + strPost = []byte("POST") + strPut = []byte("PUT") + strDelete = []byte("DELETE") strExpect = []byte("Expect") strConnection = []byte("Connection") @@ -53,20 +49,17 @@ var ( strRange = []byte("Range") strContentRange = []byte("Content-Range") - strCookieExpires = []byte("expires") - strCookieDomain = []byte("domain") - strCookiePath = []byte("path") - strCookieHTTPOnly = []byte("HttpOnly") - strCookieSecure = []byte("secure") - strCookieMaxAge = []byte("max-age") - strCookieSameSite = []byte("SameSite") - strCookieSameSiteLax = []byte("Lax") - strCookieSameSiteStrict = []byte("Strict") + strCookieExpires = []byte("expires") + strCookieDomain = []byte("domain") + strCookiePath = []byte("path") + strCookieHTTPOnly = []byte("HttpOnly") + strCookieSecure = []byte("secure") strClose = []byte("close") strGzip = []byte("gzip") strDeflate = []byte("deflate") strKeepAlive = []byte("keep-alive") + strKeepAliveCamelCase = []byte("Keep-Alive") strUpgrade = []byte("Upgrade") strChunked = []byte("chunked") strIdentity = []byte("identity") diff --git a/vendor/github.com/valyala/fasthttp/tcpdialer.go b/vendor/github.com/VictoriaMetrics/fasthttp/tcpdialer.go similarity index 55% rename from vendor/github.com/valyala/fasthttp/tcpdialer.go rename to vendor/github.com/VictoriaMetrics/fasthttp/tcpdialer.go index 6a5cd3a1f..e31fd7585 100644 --- a/vendor/github.com/valyala/fasthttp/tcpdialer.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/tcpdialer.go @@ -33,7 +33,7 @@ import ( // * foo.bar:80 // * aaa.com:8080 func Dial(addr string) (net.Conn, error) { - return defaultDialer.Dial(addr) + return getDialer(DefaultDialTimeout, false)(addr) } // DialTimeout dials the given TCP addr using tcp4 using the given timeout. @@ -58,7 +58,7 @@ func Dial(addr string) (net.Conn, error) { // * foo.bar:80 // * aaa.com:8080 func DialTimeout(addr string, timeout time.Duration) (net.Conn, error) { - return defaultDialer.DialTimeout(addr, timeout) + return getDialer(timeout, false)(addr) } // DialDualStack dials the given TCP addr using both tcp4 and tcp6. @@ -86,7 +86,7 @@ func DialTimeout(addr string, timeout time.Duration) (net.Conn, error) { // * foo.bar:80 // * aaa.com:8080 func DialDualStack(addr string) (net.Conn, error) { - return defaultDialer.DialDualStack(addr) + return getDialer(DefaultDialTimeout, true)(addr) } // DialDualStackTimeout dials the given TCP addr using both tcp4 and tcp6 @@ -112,22 +112,45 @@ func DialDualStack(addr string) (net.Conn, error) { // * foo.bar:80 // * aaa.com:8080 func DialDualStackTimeout(addr string, timeout time.Duration) (net.Conn, error) { - return defaultDialer.DialDualStackTimeout(addr, timeout) + return getDialer(timeout, true)(addr) +} + +func getDialer(timeout time.Duration, dualStack bool) DialFunc { + if timeout <= 0 { + timeout = DefaultDialTimeout + } + timeoutRounded := int(timeout.Seconds()*10 + 9) + + m := dialMap + if dualStack { + m = dialDualStackMap + } + + dialMapLock.Lock() + d := m[timeoutRounded] + if d == nil { + dialer := dialerStd + if dualStack { + dialer = dialerDualStack + } + d = dialer.NewDial(timeout) + m[timeoutRounded] = d + } + dialMapLock.Unlock() + return d } var ( - defaultDialer = &TCPDialer{Concurrency: 1000} + dialerStd = &tcpDialer{} + dialerDualStack = &tcpDialer{DualStack: true} + + dialMap = make(map[int]DialFunc) + dialDualStackMap = make(map[int]DialFunc) + dialMapLock sync.Mutex ) -// TCPDialer contains options to control a group of Dial calls. -type TCPDialer struct { - // Concurrency controls the maximum number of concurrent Dails - // that can be performed using this object. - // Setting this to 0 means unlimited. - // - // WARNING: This can only be changed before the first Dial. - // Changes made after the first Dial will not affect anything. - Concurrency int +type tcpDialer struct { + DualStack bool tcpAddrsLock sync.Mutex tcpAddrsMap map[string]*tcpAddrEntry @@ -137,145 +160,41 @@ type TCPDialer struct { once sync.Once } -// Dial dials the given TCP addr using tcp4. -// -// This function has the following additional features comparing to net.Dial: -// -// * It reduces load on DNS resolver by caching resolved TCP addressed -// for DefaultDNSCacheDuration. -// * It dials all the resolved TCP addresses in round-robin manner until -// connection is established. This may be useful if certain addresses -// are temporarily unreachable. -// * It returns ErrDialTimeout if connection cannot be established during -// DefaultDialTimeout seconds. Use DialTimeout for customizing dial timeout. -// -// This dialer is intended for custom code wrapping before passing -// to Client.Dial or HostClient.Dial. -// -// For instance, per-host counters and/or limits may be implemented -// by such wrappers. -// -// The addr passed to the function must contain port. Example addr values: -// -// * foobar.baz:443 -// * foo.bar:80 -// * aaa.com:8080 -func (d *TCPDialer) Dial(addr string) (net.Conn, error) { - return d.dial(addr, false, DefaultDialTimeout) -} +const maxDialConcurrency = 1000 -// DialTimeout dials the given TCP addr using tcp4 using the given timeout. -// -// This function has the following additional features comparing to net.Dial: -// -// * It reduces load on DNS resolver by caching resolved TCP addressed -// for DefaultDNSCacheDuration. -// * It dials all the resolved TCP addresses in round-robin manner until -// connection is established. This may be useful if certain addresses -// are temporarily unreachable. -// -// This dialer is intended for custom code wrapping before passing -// to Client.Dial or HostClient.Dial. -// -// For instance, per-host counters and/or limits may be implemented -// by such wrappers. -// -// The addr passed to the function must contain port. Example addr values: -// -// * foobar.baz:443 -// * foo.bar:80 -// * aaa.com:8080 -func (d *TCPDialer) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) { - return d.dial(addr, false, timeout) -} - -// DialDualStack dials the given TCP addr using both tcp4 and tcp6. -// -// This function has the following additional features comparing to net.Dial: -// -// * It reduces load on DNS resolver by caching resolved TCP addressed -// for DefaultDNSCacheDuration. -// * It dials all the resolved TCP addresses in round-robin manner until -// connection is established. This may be useful if certain addresses -// are temporarily unreachable. -// * It returns ErrDialTimeout if connection cannot be established during -// DefaultDialTimeout seconds. Use DialDualStackTimeout for custom dial -// timeout. -// -// This dialer is intended for custom code wrapping before passing -// to Client.Dial or HostClient.Dial. -// -// For instance, per-host counters and/or limits may be implemented -// by such wrappers. -// -// The addr passed to the function must contain port. Example addr values: -// -// * foobar.baz:443 -// * foo.bar:80 -// * aaa.com:8080 -func (d *TCPDialer) DialDualStack(addr string) (net.Conn, error) { - return d.dial(addr, true, DefaultDialTimeout) -} - -// DialDualStackTimeout dials the given TCP addr using both tcp4 and tcp6 -// using the given timeout. -// -// This function has the following additional features comparing to net.Dial: -// -// * It reduces load on DNS resolver by caching resolved TCP addressed -// for DefaultDNSCacheDuration. -// * It dials all the resolved TCP addresses in round-robin manner until -// connection is established. This may be useful if certain addresses -// are temporarily unreachable. -// -// This dialer is intended for custom code wrapping before passing -// to Client.Dial or HostClient.Dial. -// -// For instance, per-host counters and/or limits may be implemented -// by such wrappers. -// -// The addr passed to the function must contain port. Example addr values: -// -// * foobar.baz:443 -// * foo.bar:80 -// * aaa.com:8080 -func (d *TCPDialer) DialDualStackTimeout(addr string, timeout time.Duration) (net.Conn, error) { - return d.dial(addr, true, timeout) -} - -func (d *TCPDialer) dial(addr string, dualStack bool, timeout time.Duration) (net.Conn, error) { +func (d *tcpDialer) NewDial(timeout time.Duration) DialFunc { d.once.Do(func() { - if d.Concurrency > 0 { - d.concurrencyCh = make(chan struct{}, d.Concurrency) - } + d.concurrencyCh = make(chan struct{}, maxDialConcurrency) d.tcpAddrsMap = make(map[string]*tcpAddrEntry) go d.tcpAddrsClean() }) - addrs, idx, err := d.getTCPAddrs(addr, dualStack) - if err != nil { - return nil, err - } - network := "tcp4" - if dualStack { - network = "tcp" - } - - var conn net.Conn - n := uint32(len(addrs)) - deadline := time.Now().Add(timeout) - for n > 0 { - conn, err = tryDial(network, &addrs[idx%n], deadline, d.concurrencyCh) - if err == nil { - return conn, nil - } - if err == ErrDialTimeout { + return func(addr string) (net.Conn, error) { + addrs, idx, err := d.getTCPAddrs(addr) + if err != nil { return nil, err } - idx++ - n-- + network := "tcp4" + if d.DualStack { + network = "tcp" + } + + var conn net.Conn + n := uint32(len(addrs)) + deadline := time.Now().Add(timeout) + for n > 0 { + conn, err = tryDial(network, &addrs[idx%n], deadline, d.concurrencyCh) + if err == nil { + return conn, nil + } + if err == ErrDialTimeout { + return nil, err + } + idx++ + n-- + } + return nil, err } - return nil, err } func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyCh chan struct{}) (net.Conn, error) { @@ -284,22 +203,26 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC return nil, ErrDialTimeout } - if concurrencyCh != nil { + select { + case concurrencyCh <- struct{}{}: + default: + tc := acquireTimer(timeout) + isTimeout := false select { case concurrencyCh <- struct{}{}: - default: - tc := AcquireTimer(timeout) - isTimeout := false - select { - case concurrencyCh <- struct{}{}: - case <-tc.C: - isTimeout = true - } - ReleaseTimer(tc) - if isTimeout { - return nil, ErrDialTimeout - } + case <-tc.C: + isTimeout = true } + releaseTimer(tc) + if isTimeout { + return nil, ErrDialTimeout + } + } + + timeout = -time.Since(deadline) + if timeout <= 0 { + <-concurrencyCh + return nil, ErrDialTimeout } chv := dialResultChanPool.Get() @@ -311,9 +234,7 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC var dr dialResult dr.conn, dr.err = net.DialTCP(network, nil, addr) ch <- dr - if concurrencyCh != nil { - <-concurrencyCh - } + <-concurrencyCh }() var ( @@ -321,7 +242,7 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC err error ) - tc := AcquireTimer(timeout) + tc := acquireTimer(timeout) select { case dr := <-ch: conn = dr.conn @@ -330,7 +251,7 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC case <-tc.C: err = ErrDialTimeout } - ReleaseTimer(tc) + releaseTimer(tc) return conn, err } @@ -361,7 +282,7 @@ type tcpAddrEntry struct { // by Dial* functions. const DefaultDNSCacheDuration = time.Minute -func (d *TCPDialer) tcpAddrsClean() { +func (d *tcpDialer) tcpAddrsClean() { expireDuration := 2 * DefaultDNSCacheDuration for { time.Sleep(time.Second) @@ -377,7 +298,7 @@ func (d *TCPDialer) tcpAddrsClean() { } } -func (d *TCPDialer) getTCPAddrs(addr string, dualStack bool) ([]net.TCPAddr, uint32, error) { +func (d *tcpDialer) getTCPAddrs(addr string) ([]net.TCPAddr, uint32, error) { d.tcpAddrsLock.Lock() e := d.tcpAddrsMap[addr] if e != nil && !e.pending && time.Since(e.resolveTime) > DefaultDNSCacheDuration { @@ -387,7 +308,7 @@ func (d *TCPDialer) getTCPAddrs(addr string, dualStack bool) ([]net.TCPAddr, uin d.tcpAddrsLock.Unlock() if e == nil { - addrs, err := resolveTCPAddrs(addr, dualStack) + addrs, err := resolveTCPAddrs(addr, d.DualStack) if err != nil { d.tcpAddrsLock.Lock() e = d.tcpAddrsMap[addr] diff --git a/vendor/github.com/valyala/fasthttp/timer.go b/vendor/github.com/VictoriaMetrics/fasthttp/timer.go similarity index 53% rename from vendor/github.com/valyala/fasthttp/timer.go rename to vendor/github.com/VictoriaMetrics/fasthttp/timer.go index 4e919384e..bb12acb7e 100644 --- a/vendor/github.com/valyala/fasthttp/timer.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/timer.go @@ -26,12 +26,7 @@ func stopTimer(t *time.Timer) { } } -// AcquireTimer returns a time.Timer from the pool and updates it to -// send the current time on its channel after at least timeout. -// -// The returned Timer may be returned to the pool with ReleaseTimer -// when no longer needed. This allows reducing GC load. -func AcquireTimer(timeout time.Duration) *time.Timer { +func acquireTimer(timeout time.Duration) *time.Timer { v := timerPool.Get() if v == nil { return time.NewTimer(timeout) @@ -41,12 +36,7 @@ func AcquireTimer(timeout time.Duration) *time.Timer { return t } -// ReleaseTimer returns the time.Timer acquired via AcquireTimer to the pool -// and prevents the Timer from firing. -// -// Do not access the released time.Timer or read from it's channel otherwise -// data races may occur. -func ReleaseTimer(t *time.Timer) { +func releaseTimer(t *time.Timer) { stopTimer(t) timerPool.Put(t) } diff --git a/vendor/github.com/valyala/fasthttp/uri.go b/vendor/github.com/VictoriaMetrics/fasthttp/uri.go similarity index 99% rename from vendor/github.com/valyala/fasthttp/uri.go rename to vendor/github.com/VictoriaMetrics/fasthttp/uri.go index d536f5934..37572f5d1 100644 --- a/vendor/github.com/valyala/fasthttp/uri.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/uri.go @@ -180,7 +180,7 @@ func (u *URI) Reset() { u.parsedQueryArgs = false // There is no need in u.fullURI = u.fullURI[:0], since full uri - // is calculated on each call to FullURI(). + // is calucalted on each call to FullURI(). // There is no need in u.requestURI = u.requestURI[:0], since requestURI // is calculated on each call to RequestURI(). diff --git a/vendor/github.com/valyala/fasthttp/uri_unix.go b/vendor/github.com/VictoriaMetrics/fasthttp/uri_unix.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/uri_unix.go rename to vendor/github.com/VictoriaMetrics/fasthttp/uri_unix.go diff --git a/vendor/github.com/valyala/fasthttp/uri_windows.go b/vendor/github.com/VictoriaMetrics/fasthttp/uri_windows.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/uri_windows.go rename to vendor/github.com/VictoriaMetrics/fasthttp/uri_windows.go diff --git a/vendor/github.com/valyala/fasthttp/userdata.go b/vendor/github.com/VictoriaMetrics/fasthttp/userdata.go similarity index 100% rename from vendor/github.com/valyala/fasthttp/userdata.go rename to vendor/github.com/VictoriaMetrics/fasthttp/userdata.go diff --git a/vendor/github.com/valyala/fasthttp/workerpool.go b/vendor/github.com/VictoriaMetrics/fasthttp/workerpool.go similarity index 94% rename from vendor/github.com/valyala/fasthttp/workerpool.go rename to vendor/github.com/VictoriaMetrics/fasthttp/workerpool.go index bfd297c31..cf602e050 100644 --- a/vendor/github.com/valyala/fasthttp/workerpool.go +++ b/vendor/github.com/VictoriaMetrics/fasthttp/workerpool.go @@ -16,7 +16,7 @@ import ( type workerPool struct { // Function for serving server connections. // It must leave c unclosed. - WorkerFunc ServeHandler + WorkerFunc func(c net.Conn) error MaxWorkersCount int @@ -35,8 +35,6 @@ type workerPool struct { stopCh chan struct{} workerChanPool sync.Pool - - connState func(net.Conn, ConnState) } type workerChan struct { @@ -189,7 +187,7 @@ func (wp *workerPool) getCh() *workerChan { } func (wp *workerPool) release(ch *workerChan) bool { - ch.lastUseTime = time.Now() + ch.lastUseTime = CoarseTimeNow() wp.lock.Lock() if wp.mustStop { wp.lock.Unlock() @@ -213,16 +211,12 @@ func (wp *workerPool) workerFunc(ch *workerChan) { errStr := err.Error() if wp.LogAllErrors || !(strings.Contains(errStr, "broken pipe") || strings.Contains(errStr, "reset by peer") || - strings.Contains(errStr, "request headers: small read buffer") || strings.Contains(errStr, "i/o timeout")) { wp.Logger.Printf("error when serving connection %q<->%q: %s", c.LocalAddr(), c.RemoteAddr(), err) } } - if err == errHijacked { - wp.connState(c, StateHijacked) - } else { + if err != errHijacked { c.Close() - wp.connState(c, StateClosed) } c = nil diff --git a/vendor/github.com/valyala/fasthttp/.travis.yml b/vendor/github.com/valyala/fasthttp/.travis.yml deleted file mode 100644 index 104ead045..000000000 --- a/vendor/github.com/valyala/fasthttp/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: go - -go: - - tip - - 1.11.x - - 1.10.x - - 1.9.x - -os: - - linux - - osx - -matrix: - allow_failures: - - tip - fast_finish: true - -before_install: - - go get -t -v ./... - # - go get -v golang.org/x/tools/cmd/goimports - -script: - # TODO(@kirilldanshin) - # - test -z "$(goimports -d $(find . -type f -name '*.go' -not -path "./vendor/*"))" - # build test for supported platforms - - GOOS=linux go build - - GOOS=darwin go build - - GOOS=freebsd go build - - GOOS=windows go build - - GOARCH=386 go build - - # run tests on a standard platform - - go test -v ./... - - # run tests with the race detector as well - - go test -race -v ./... diff --git a/vendor/github.com/valyala/fasthttp/README.md b/vendor/github.com/valyala/fasthttp/README.md deleted file mode 100644 index 5fcb6398d..000000000 --- a/vendor/github.com/valyala/fasthttp/README.md +++ /dev/null @@ -1,585 +0,0 @@ -[![Build Status](https://travis-ci.org/valyala/fasthttp.svg)](https://travis-ci.org/valyala/fasthttp) -[![GoDoc](https://godoc.org/github.com/valyala/fasthttp?status.svg)](http://godoc.org/github.com/valyala/fasthttp) -[![Go Report](https://goreportcard.com/badge/github.com/valyala/fasthttp)](https://goreportcard.com/report/github.com/valyala/fasthttp) - -# fasthttp -Fast HTTP implementation for Go. - -Currently fasthttp is successfully used by [VertaMedia](https://vertamedia.com/) -in a production serving up to 200K rps from more than 1.5M concurrent keep-alive -connections per physical server. - -[TechEmpower Benchmark round 12 results](https://www.techempower.com/benchmarks/#section=data-r12&hw=peak&test=plaintext) - -[Server Benchmarks](#http-server-performance-comparison-with-nethttp) - -[Client Benchmarks](#http-client-comparison-with-nethttp) - -[Install](#install) - -[Documentation](https://godoc.org/github.com/valyala/fasthttp) - -[Examples from docs](https://godoc.org/github.com/valyala/fasthttp#pkg-examples) - -[Code examples](examples) - -[Awesome fasthttp tools](https://github.com/fasthttp) - -[Switching from net/http to fasthttp](#switching-from-nethttp-to-fasthttp) - -[Fasthttp best practices](#fasthttp-best-practices) - -[Tricks with byte buffers](#tricks-with-byte-buffers) - -[Related projects](#related-projects) - -[FAQ](#faq) - -# HTTP server performance comparison with [net/http](https://golang.org/pkg/net/http/) - -In short, fasthttp server is up to 10 times faster than net/http. -Below are benchmark results. - -*GOMAXPROCS=1* - -net/http server: -``` -$ GOMAXPROCS=1 go test -bench=NetHTTPServerGet -benchmem -benchtime=10s -BenchmarkNetHTTPServerGet1ReqPerConn 1000000 12052 ns/op 2297 B/op 29 allocs/op -BenchmarkNetHTTPServerGet2ReqPerConn 1000000 12278 ns/op 2327 B/op 24 allocs/op -BenchmarkNetHTTPServerGet10ReqPerConn 2000000 8903 ns/op 2112 B/op 19 allocs/op -BenchmarkNetHTTPServerGet10KReqPerConn 2000000 8451 ns/op 2058 B/op 18 allocs/op -BenchmarkNetHTTPServerGet1ReqPerConn10KClients 500000 26733 ns/op 3229 B/op 29 allocs/op -BenchmarkNetHTTPServerGet2ReqPerConn10KClients 1000000 23351 ns/op 3211 B/op 24 allocs/op -BenchmarkNetHTTPServerGet10ReqPerConn10KClients 1000000 13390 ns/op 2483 B/op 19 allocs/op -BenchmarkNetHTTPServerGet100ReqPerConn10KClients 1000000 13484 ns/op 2171 B/op 18 allocs/op -``` - -fasthttp server: -``` -$ GOMAXPROCS=1 go test -bench=kServerGet -benchmem -benchtime=10s -BenchmarkServerGet1ReqPerConn 10000000 1559 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet2ReqPerConn 10000000 1248 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet10ReqPerConn 20000000 797 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet10KReqPerConn 20000000 716 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet1ReqPerConn10KClients 10000000 1974 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet2ReqPerConn10KClients 10000000 1352 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet10ReqPerConn10KClients 20000000 789 ns/op 2 B/op 0 allocs/op -BenchmarkServerGet100ReqPerConn10KClients 20000000 604 ns/op 0 B/op 0 allocs/op -``` - -*GOMAXPROCS=4* - -net/http server: -``` -$ GOMAXPROCS=4 go test -bench=NetHTTPServerGet -benchmem -benchtime=10s -BenchmarkNetHTTPServerGet1ReqPerConn-4 3000000 4529 ns/op 2389 B/op 29 allocs/op -BenchmarkNetHTTPServerGet2ReqPerConn-4 5000000 3896 ns/op 2418 B/op 24 allocs/op -BenchmarkNetHTTPServerGet10ReqPerConn-4 5000000 3145 ns/op 2160 B/op 19 allocs/op -BenchmarkNetHTTPServerGet10KReqPerConn-4 5000000 3054 ns/op 2065 B/op 18 allocs/op -BenchmarkNetHTTPServerGet1ReqPerConn10KClients-4 1000000 10321 ns/op 3710 B/op 30 allocs/op -BenchmarkNetHTTPServerGet2ReqPerConn10KClients-4 2000000 7556 ns/op 3296 B/op 24 allocs/op -BenchmarkNetHTTPServerGet10ReqPerConn10KClients-4 5000000 3905 ns/op 2349 B/op 19 allocs/op -BenchmarkNetHTTPServerGet100ReqPerConn10KClients-4 5000000 3435 ns/op 2130 B/op 18 allocs/op -``` - -fasthttp server: -``` -$ GOMAXPROCS=4 go test -bench=kServerGet -benchmem -benchtime=10s -BenchmarkServerGet1ReqPerConn-4 10000000 1141 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet2ReqPerConn-4 20000000 707 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet10ReqPerConn-4 30000000 341 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet10KReqPerConn-4 50000000 310 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet1ReqPerConn10KClients-4 10000000 1119 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet2ReqPerConn10KClients-4 20000000 644 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet10ReqPerConn10KClients-4 30000000 346 ns/op 0 B/op 0 allocs/op -BenchmarkServerGet100ReqPerConn10KClients-4 50000000 282 ns/op 0 B/op 0 allocs/op -``` - -# HTTP client comparison with net/http - -In short, fasthttp client is up to 10 times faster than net/http. -Below are benchmark results. - -*GOMAXPROCS=1* - -net/http client: -``` -$ GOMAXPROCS=1 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s -BenchmarkNetHTTPClientDoFastServer 1000000 12567 ns/op 2616 B/op 35 allocs/op -BenchmarkNetHTTPClientGetEndToEnd1TCP 200000 67030 ns/op 5028 B/op 56 allocs/op -BenchmarkNetHTTPClientGetEndToEnd10TCP 300000 51098 ns/op 5031 B/op 56 allocs/op -BenchmarkNetHTTPClientGetEndToEnd100TCP 300000 45096 ns/op 5026 B/op 55 allocs/op -BenchmarkNetHTTPClientGetEndToEnd1Inmemory 500000 24779 ns/op 5035 B/op 57 allocs/op -BenchmarkNetHTTPClientGetEndToEnd10Inmemory 1000000 26425 ns/op 5035 B/op 57 allocs/op -BenchmarkNetHTTPClientGetEndToEnd100Inmemory 500000 28515 ns/op 5045 B/op 57 allocs/op -BenchmarkNetHTTPClientGetEndToEnd1000Inmemory 500000 39511 ns/op 5096 B/op 56 allocs/op -``` - -fasthttp client: -``` -$ GOMAXPROCS=1 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s -BenchmarkClientDoFastServer 20000000 865 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd1TCP 1000000 18711 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd10TCP 1000000 14664 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd100TCP 1000000 14043 ns/op 1 B/op 0 allocs/op -BenchmarkClientGetEndToEnd1Inmemory 5000000 3965 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd10Inmemory 3000000 4060 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd100Inmemory 5000000 3396 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd1000Inmemory 5000000 3306 ns/op 2 B/op 0 allocs/op -``` - -*GOMAXPROCS=4* - -net/http client: -``` -$ GOMAXPROCS=4 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s -BenchmarkNetHTTPClientDoFastServer-4 2000000 8774 ns/op 2619 B/op 35 allocs/op -BenchmarkNetHTTPClientGetEndToEnd1TCP-4 500000 22951 ns/op 5047 B/op 56 allocs/op -BenchmarkNetHTTPClientGetEndToEnd10TCP-4 1000000 19182 ns/op 5037 B/op 55 allocs/op -BenchmarkNetHTTPClientGetEndToEnd100TCP-4 1000000 16535 ns/op 5031 B/op 55 allocs/op -BenchmarkNetHTTPClientGetEndToEnd1Inmemory-4 1000000 14495 ns/op 5038 B/op 56 allocs/op -BenchmarkNetHTTPClientGetEndToEnd10Inmemory-4 1000000 10237 ns/op 5034 B/op 56 allocs/op -BenchmarkNetHTTPClientGetEndToEnd100Inmemory-4 1000000 10125 ns/op 5045 B/op 56 allocs/op -BenchmarkNetHTTPClientGetEndToEnd1000Inmemory-4 1000000 11132 ns/op 5136 B/op 56 allocs/op -``` - -fasthttp client: -``` -$ GOMAXPROCS=4 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s -BenchmarkClientDoFastServer-4 50000000 397 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd1TCP-4 2000000 7388 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd10TCP-4 2000000 6689 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd100TCP-4 3000000 4927 ns/op 1 B/op 0 allocs/op -BenchmarkClientGetEndToEnd1Inmemory-4 10000000 1604 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd10Inmemory-4 10000000 1458 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd100Inmemory-4 10000000 1329 ns/op 0 B/op 0 allocs/op -BenchmarkClientGetEndToEnd1000Inmemory-4 10000000 1316 ns/op 5 B/op 0 allocs/op -``` - - -# Install - -``` -go get -u github.com/valyala/fasthttp -``` - - -# Switching from net/http to fasthttp - -Unfortunately, fasthttp doesn't provide API identical to net/http. -See the [FAQ](#faq) for details. -There is [net/http -> fasthttp handler converter](https://godoc.org/github.com/valyala/fasthttp/fasthttpadaptor), -but it is better to write fasthttp request handlers by hand in order to use -all of the fasthttp advantages (especially high performance :) ). - -Important points: - -* Fasthttp works with [RequestHandler functions](https://godoc.org/github.com/valyala/fasthttp#RequestHandler) -instead of objects implementing [Handler interface](https://golang.org/pkg/net/http/#Handler). -Fortunately, it is easy to pass bound struct methods to fasthttp: - - ```go - type MyHandler struct { - foobar string - } - - // request handler in net/http style, i.e. method bound to MyHandler struct. - func (h *MyHandler) HandleFastHTTP(ctx *fasthttp.RequestCtx) { - // notice that we may access MyHandler properties here - see h.foobar. - fmt.Fprintf(ctx, "Hello, world! Requested path is %q. Foobar is %q", - ctx.Path(), h.foobar) - } - - // request handler in fasthttp style, i.e. just plain function. - func fastHTTPHandler(ctx *fasthttp.RequestCtx) { - fmt.Fprintf(ctx, "Hi there! RequestURI is %q", ctx.RequestURI()) - } - - // pass bound struct method to fasthttp - myHandler := &MyHandler{ - foobar: "foobar", - } - fasthttp.ListenAndServe(":8080", myHandler.HandleFastHTTP) - - // pass plain function to fasthttp - fasthttp.ListenAndServe(":8081", fastHTTPHandler) - ``` - -* The [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler) -accepts only one argument - [RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx). -It contains all the functionality required for http request processing -and response writing. Below is an example of a simple request handler conversion -from net/http to fasthttp. - - ```go - // net/http request handler - requestHandler := func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/foo": - fooHandler(w, r) - case "/bar": - barHandler(w, r) - default: - http.Error(w, "Unsupported path", http.StatusNotFound) - } - } - ``` - - ```go - // the corresponding fasthttp request handler - requestHandler := func(ctx *fasthttp.RequestCtx) { - switch string(ctx.Path()) { - case "/foo": - fooHandler(ctx) - case "/bar": - barHandler(ctx) - default: - ctx.Error("Unsupported path", fasthttp.StatusNotFound) - } - } - ``` - -* Fasthttp allows setting response headers and writing response body -in an arbitrary order. There is no 'headers first, then body' restriction -like in net/http. The following code is valid for fasthttp: - - ```go - requestHandler := func(ctx *fasthttp.RequestCtx) { - // set some headers and status code first - ctx.SetContentType("foo/bar") - ctx.SetStatusCode(fasthttp.StatusOK) - - // then write the first part of body - fmt.Fprintf(ctx, "this is the first part of body\n") - - // then set more headers - ctx.Response.Header.Set("Foo-Bar", "baz") - - // then write more body - fmt.Fprintf(ctx, "this is the second part of body\n") - - // then override already written body - ctx.SetBody([]byte("this is completely new body contents")) - - // then update status code - ctx.SetStatusCode(fasthttp.StatusNotFound) - - // basically, anything may be updated many times before - // returning from RequestHandler. - // - // Unlike net/http fasthttp doesn't put response to the wire until - // returning from RequestHandler. - } - ``` - -* Fasthttp doesn't provide [ServeMux](https://golang.org/pkg/net/http/#ServeMux), -but there are more powerful third-party routers and web frameworks -with fasthttp support: - - * [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing) - * [fasthttprouter](https://github.com/buaazp/fasthttprouter) - * [lu](https://github.com/vincentLiuxiang/lu) - * [atreugo](https://github.com/savsgio/atreugo) - - Net/http code with simple ServeMux is trivially converted to fasthttp code: - - ```go - // net/http code - - m := &http.ServeMux{} - m.HandleFunc("/foo", fooHandlerFunc) - m.HandleFunc("/bar", barHandlerFunc) - m.Handle("/baz", bazHandler) - - http.ListenAndServe(":80", m) - ``` - - ```go - // the corresponding fasthttp code - m := func(ctx *fasthttp.RequestCtx) { - switch string(ctx.Path()) { - case "/foo": - fooHandlerFunc(ctx) - case "/bar": - barHandlerFunc(ctx) - case "/baz": - bazHandler.HandlerFunc(ctx) - default: - ctx.Error("not found", fasthttp.StatusNotFound) - } - } - - fasthttp.ListenAndServe(":80", m) - ``` - -* net/http -> fasthttp conversion table: - - * All the pseudocode below assumes w, r and ctx have these types: - ```go - var ( - w http.ResponseWriter - r *http.Request - ctx *fasthttp.RequestCtx - ) - ``` - * r.Body -> [ctx.PostBody()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.PostBody) - * r.URL.Path -> [ctx.Path()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Path) - * r.URL -> [ctx.URI()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.URI) - * r.Method -> [ctx.Method()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Method) - * r.Header -> [ctx.Request.Header](https://godoc.org/github.com/valyala/fasthttp#RequestHeader) - * r.Header.Get() -> [ctx.Request.Header.Peek()](https://godoc.org/github.com/valyala/fasthttp#RequestHeader.Peek) - * r.Host -> [ctx.Host()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Host) - * r.Form -> [ctx.QueryArgs()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.QueryArgs) + - [ctx.PostArgs()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.PostArgs) - * r.PostForm -> [ctx.PostArgs()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.PostArgs) - * r.FormValue() -> [ctx.FormValue()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.FormValue) - * r.FormFile() -> [ctx.FormFile()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.FormFile) - * r.MultipartForm -> [ctx.MultipartForm()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.MultipartForm) - * r.RemoteAddr -> [ctx.RemoteAddr()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.RemoteAddr) - * r.RequestURI -> [ctx.RequestURI()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.RequestURI) - * r.TLS -> [ctx.IsTLS()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.IsTLS) - * r.Cookie() -> [ctx.Request.Header.Cookie()](https://godoc.org/github.com/valyala/fasthttp#RequestHeader.Cookie) - * r.Referer() -> [ctx.Referer()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Referer) - * r.UserAgent() -> [ctx.UserAgent()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.UserAgent) - * w.Header() -> [ctx.Response.Header](https://godoc.org/github.com/valyala/fasthttp#ResponseHeader) - * w.Header().Set() -> [ctx.Response.Header.Set()](https://godoc.org/github.com/valyala/fasthttp#ResponseHeader.Set) - * w.Header().Set("Content-Type") -> [ctx.SetContentType()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.SetContentType) - * w.Header().Set("Set-Cookie") -> [ctx.Response.Header.SetCookie()](https://godoc.org/github.com/valyala/fasthttp#ResponseHeader.SetCookie) - * w.Write() -> [ctx.Write()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Write), - [ctx.SetBody()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.SetBody), - [ctx.SetBodyStream()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.SetBodyStream), - [ctx.SetBodyStreamWriter()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.SetBodyStreamWriter) - * w.WriteHeader() -> [ctx.SetStatusCode()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.SetStatusCode) - * w.(http.Hijacker).Hijack() -> [ctx.Hijack()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Hijack) - * http.Error() -> [ctx.Error()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Error) - * http.FileServer() -> [fasthttp.FSHandler()](https://godoc.org/github.com/valyala/fasthttp#FSHandler), - [fasthttp.FS](https://godoc.org/github.com/valyala/fasthttp#FS) - * http.ServeFile() -> [fasthttp.ServeFile()](https://godoc.org/github.com/valyala/fasthttp#ServeFile) - * http.Redirect() -> [ctx.Redirect()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Redirect) - * http.NotFound() -> [ctx.NotFound()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.NotFound) - * http.StripPrefix() -> [fasthttp.PathRewriteFunc](https://godoc.org/github.com/valyala/fasthttp#PathRewriteFunc) - -* *VERY IMPORTANT!* Fasthttp disallows holding references -to [RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) or to its' -members after returning from [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler). -Otherwise [data races](http://blog.golang.org/race-detector) are inevitable. -Carefully inspect all the net/http request handlers converted to fasthttp whether -they retain references to RequestCtx or to its' members after returning. -RequestCtx provides the following _band aids_ for this case: - - * Wrap RequestHandler into [TimeoutHandler](https://godoc.org/github.com/valyala/fasthttp#TimeoutHandler). - * Call [TimeoutError](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.TimeoutError) - before returning from RequestHandler if there are references to RequestCtx or to its' members. - See [the example](https://godoc.org/github.com/valyala/fasthttp#example-RequestCtx-TimeoutError) - for more details. - -Use this brilliant tool - [race detector](http://blog.golang.org/race-detector) - -for detecting and eliminating data races in your program. If you detected -data race related to fasthttp in your program, then there is high probability -you forgot calling [TimeoutError](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.TimeoutError) -before returning from [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler). - -* Blind switching from net/http to fasthttp won't give you performance boost. -While fasthttp is optimized for speed, its' performance may be easily saturated -by slow [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler). -So [profile](http://blog.golang.org/profiling-go-programs) and optimize your -code after switching to fasthttp. For instance, use [quicktemplate](https://github.com/valyala/quicktemplate) -instead of [html/template](https://golang.org/pkg/html/template/). - -* See also [fasthttputil](https://godoc.org/github.com/valyala/fasthttp/fasthttputil), -[fasthttpadaptor](https://godoc.org/github.com/valyala/fasthttp/fasthttpadaptor) and -[expvarhandler](https://godoc.org/github.com/valyala/fasthttp/expvarhandler). - - -# Performance optimization tips for multi-core systems - -* Use [reuseport](https://godoc.org/github.com/valyala/fasthttp/reuseport) listener. -* Run a separate server instance per CPU core with GOMAXPROCS=1. -* Pin each server instance to a separate CPU core using [taskset](http://linux.die.net/man/1/taskset). -* Ensure the interrupts of multiqueue network card are evenly distributed between CPU cores. - See [this article](https://blog.cloudflare.com/how-to-achieve-low-latency/) for details. -* Use Go 1.6 as it provides some considerable performance improvements. - - -# Fasthttp best practices - -* Do not allocate objects and `[]byte` buffers - just reuse them as much - as possible. Fasthttp API design encourages this. -* [sync.Pool](https://golang.org/pkg/sync/#Pool) is your best friend. -* [Profile your program](http://blog.golang.org/profiling-go-programs) - in production. - `go tool pprof --alloc_objects your-program mem.pprof` usually gives better - insights for optimization opportunities than `go tool pprof your-program cpu.pprof`. -* Write [tests and benchmarks](https://golang.org/pkg/testing/) for hot paths. -* Avoid conversion between `[]byte` and `string`, since this may result in memory - allocation+copy. Fasthttp API provides functions for both `[]byte` and `string` - - use these functions instead of converting manually between `[]byte` and `string`. - There are some exceptions - see [this wiki page](https://github.com/golang/go/wiki/CompilerOptimizations#string-and-byte) - for more details. -* Verify your tests and production code under - [race detector](https://golang.org/doc/articles/race_detector.html) on a regular basis. -* Prefer [quicktemplate](https://github.com/valyala/quicktemplate) instead of - [html/template](https://golang.org/pkg/html/template/) in your webserver. - - -# Tricks with `[]byte` buffers - -The following tricks are used by fasthttp. Use them in your code too. - -* Standard Go functions accept nil buffers -```go -var ( - // both buffers are uninitialized - dst []byte - src []byte -) -dst = append(dst, src...) // is legal if dst is nil and/or src is nil -copy(dst, src) // is legal if dst is nil and/or src is nil -(string(src) == "") // is true if src is nil -(len(src) == 0) // is true if src is nil -src = src[:0] // works like a charm with nil src - -// this for loop doesn't panic if src is nil -for i, ch := range src { - doSomething(i, ch) -} -``` - -So throw away nil checks for `[]byte` buffers from you code. For example, -```go -srcLen := 0 -if src != nil { - srcLen = len(src) -} -``` - -becomes - -```go -srcLen := len(src) -``` - -* String may be appended to `[]byte` buffer with `append` -```go -dst = append(dst, "foobar"...) -``` - -* `[]byte` buffer may be extended to its' capacity. -```go -buf := make([]byte, 100) -a := buf[:10] // len(a) == 10, cap(a) == 100. -b := a[:100] // is valid, since cap(a) == 100. -``` - -* All fasthttp functions accept nil `[]byte` buffer -```go -statusCode, body, err := fasthttp.Get(nil, "http://google.com/") -uintBuf := fasthttp.AppendUint(nil, 1234) -``` - -# Related projects - - * [fasthttp](https://github.com/fasthttp) - various useful - helpers for projects based on fasthttp. - * [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing) - fast and - powerful routing package for fasthttp servers. - * [fasthttprouter](https://github.com/buaazp/fasthttprouter) - a high - performance fasthttp request router that scales well. - * [gramework](https://github.com/gramework/gramework) - a web framework made by one of fasthttp maintainers - * [lu](https://github.com/vincentLiuxiang/lu) - a high performance - go middleware web framework which is based on fasthttp. - * [websocket](https://github.com/fasthttp/websocket) - Gorilla-based - websocket implementation for fasthttp. - * [fasthttpsession](https://github.com/phachon/fasthttpsession) - a fast and powerful session package for fasthttp servers. - * [atreugo](https://github.com/savsgio/atreugo) - Micro-framework to make simple the use of routing and middlewares. - * [kratgo](https://github.com/savsgio/kratgo) - Simple, lightweight and ultra-fast HTTP Cache to speed up your websites. - - -# FAQ - -* *Why creating yet another http package instead of optimizing net/http?* - - Because net/http API limits many optimization opportunities. - For example: - * net/http Request object lifetime isn't limited by request handler execution - time. So the server must create a new request object per each request instead - of reusing existing objects like fasthttp does. - * net/http headers are stored in a `map[string][]string`. So the server - must parse all the headers, convert them from `[]byte` to `string` and put - them into the map before calling user-provided request handler. - This all requires unnecessary memory allocations avoided by fasthttp. - * net/http client API requires creating a new response object per each request. - -* *Why fasthttp API is incompatible with net/http?* - - Because net/http API limits many optimization opportunities. See the answer - above for more details. Also certain net/http API parts are suboptimal - for use: - * Compare [net/http connection hijacking](https://golang.org/pkg/net/http/#Hijacker) - to [fasthttp connection hijacking](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Hijack). - * Compare [net/http Request.Body reading](https://golang.org/pkg/net/http/#Request) - to [fasthttp request body reading](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.PostBody). - -* *Why fasthttp doesn't support HTTP/2.0 and WebSockets?* - - [HTTP/2.0 support](https://github.com/fasthttp/http2) is in progress. [WebSockets](https://github.com/fasthttp/websockets) has been done already. - Third parties also may use [RequestCtx.Hijack](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Hijack) - for implementing these goodies. - -* *Are there known net/http advantages comparing to fasthttp?* - - Yes: - * net/http supports [HTTP/2.0 starting from go1.6](https://http2.golang.org/). - * net/http API is stable, while fasthttp API constantly evolves. - * net/http handles more HTTP corner cases. - * net/http should contain less bugs, since it is used and tested by much - wider audience. - * net/http works on Go older than 1.5. - -* *Why fasthttp API prefers returning `[]byte` instead of `string`?* - - Because `[]byte` to `string` conversion isn't free - it requires memory - allocation and copy. Feel free wrapping returned `[]byte` result into - `string()` if you prefer working with strings instead of byte slices. - But be aware that this has non-zero overhead. - -* *Which GO versions are supported by fasthttp?* - - Go1.5+. Older versions won't be supported, since their standard package - [miss useful functions](https://github.com/valyala/fasthttp/issues/5). - - **NOTE**: Go 1.9.7 is the oldest tested version. We recommend you to update as soon as you can. As of 1.11.3 we will drop 1.9.x support. - -* *Please provide real benchmark data and server information* - - See [this issue](https://github.com/valyala/fasthttp/issues/4). - -* *Are there plans to add request routing to fasthttp?* - - There are no plans to add request routing into fasthttp. - Use third-party routers and web frameworks with fasthttp support: - - * [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing) - * [fasthttprouter](https://github.com/buaazp/fasthttprouter) - * [gramework](https://github.com/gramework/gramework) - * [lu](https://github.com/vincentLiuxiang/lu) - * [atreugo](https://github.com/savsgio/atreugo) - - See also [this issue](https://github.com/valyala/fasthttp/issues/9) for more info. - -* *I detected data race in fasthttp!* - - Cool! [File a bug](https://github.com/valyala/fasthttp/issues/new). But before - doing this check the following in your code: - - * Make sure there are no references to [RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) - or to its' members after returning from [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler). - * Make sure you call [TimeoutError](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.TimeoutError) - before returning from [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler) - if there are references to [RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) - or to its' members, which may be accessed by other goroutines. - -* *I didn't find an answer for my question here* - - Try exploring [these questions](https://github.com/valyala/fasthttp/issues?q=label%3Aquestion). diff --git a/vendor/github.com/valyala/fasthttp/coarseTime.go b/vendor/github.com/valyala/fasthttp/coarseTime.go deleted file mode 100644 index 4679df689..000000000 --- a/vendor/github.com/valyala/fasthttp/coarseTime.go +++ /dev/null @@ -1,13 +0,0 @@ -package fasthttp - -import ( - "time" -) - -// CoarseTimeNow returns the current time truncated to the nearest second. -// -// Deprecated: This is slower than calling time.Now() directly. -// This is now time.Now().Truncate(time.Second) shortcut. -func CoarseTimeNow() time.Time { - return time.Now().Truncate(time.Second) -} diff --git a/vendor/github.com/valyala/fasthttp/go.mod b/vendor/github.com/valyala/fasthttp/go.mod deleted file mode 100644 index 8434ca1ec..000000000 --- a/vendor/github.com/valyala/fasthttp/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module github.com/valyala/fasthttp - -require ( - github.com/klauspost/compress v1.4.0 - github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e // indirect - github.com/valyala/bytebufferpool v1.0.0 - github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a - golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3 -) diff --git a/vendor/github.com/valyala/fasthttp/go.sum b/vendor/github.com/valyala/fasthttp/go.sum deleted file mode 100644 index 93f38fcf2..000000000 --- a/vendor/github.com/valyala/fasthttp/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/klauspost/compress v1.4.0 h1:8nsMz3tWa9SWWPL60G1V6CUsf4lLjWLTNEtibhe8gh8= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e h1:+lIPJOWl+jSiJOc70QXJ07+2eg2Jy2EC7Mi11BWujeM= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3 h1:czFLhve3vsQetD6JOJ8NZZvGQIXlnN3/yXxbT6/awxI= -golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/vendor/modules.txt b/vendor/modules.txt index cbfbe92c3..574a1a548 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -12,6 +12,10 @@ cloud.google.com/go/storage github.com/BurntSushi/toml # github.com/VictoriaMetrics/fastcache v1.5.7 github.com/VictoriaMetrics/fastcache +# github.com/VictoriaMetrics/fasthttp v1.0.1 +github.com/VictoriaMetrics/fasthttp +github.com/VictoriaMetrics/fasthttp/fasthttputil +github.com/VictoriaMetrics/fasthttp/stackless # github.com/VictoriaMetrics/metrics v1.11.2 github.com/VictoriaMetrics/metrics # github.com/VictoriaMetrics/metricsql v0.1.0 @@ -96,10 +100,6 @@ github.com/klauspost/compress/zstd github.com/klauspost/compress/zstd/internal/xxhash # github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/bytebufferpool -# github.com/valyala/fasthttp v1.2.0 -github.com/valyala/fasthttp -github.com/valyala/fasthttp/fasthttputil -github.com/valyala/fasthttp/stackless # github.com/valyala/fastjson v1.5.1 github.com/valyala/fastjson github.com/valyala/fastjson/fastfloat