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