Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
e72aa1c853 | |||
3c02969ffd | |||
7a3fd4e400 | |||
d10f31109b | |||
eb5d136207 | |||
32ddcdc269 | |||
bb2a195007 | |||
3c797f0850 | |||
715eedf4bf | |||
fa74f7ad4c | |||
d7738f79e1 | |||
1a1a8e0f98 | |||
5b0f744a75 | |||
f79bc57d83 | |||
9b2e68ae0a | |||
9e2662d1dd | |||
2daa8927d1 | |||
6c77212eba | |||
eb7ea55016 | |||
5ef001a877 |
@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye-slim
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
ADD dip /dip
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# dip
|
||||
[![Build Status](https://drone.paulbsd.com/api/badges/paulbsd/dip/status.svg)](https://drone.paulbsd.com/paulbsd/dip)
|
||||
|
||||
dip is a small webservice designed to return public ip address
|
||||
dip is a small webservice retrieving the IP addressing information
|
||||
|
||||
## Howto
|
||||
|
||||
@ -30,7 +30,7 @@ curl -H "Accept: text/html" http://localhost:8080/
|
||||
## License
|
||||
|
||||
```text
|
||||
Copyright (c) 2019, 2020, 2021, 2022 PaulBSD
|
||||
Copyright (c) 2020, 2021, 2022, 2023 PaulBSD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"git.paulbsd.com/paulbsd/dip/src/config"
|
||||
"git.paulbsd.com/paulbsd/dip/src/dip"
|
||||
"git.paulbsd.com/paulbsd/dip/src/ws"
|
||||
@ -18,5 +20,11 @@ func main() {
|
||||
ws := ws.WS{}
|
||||
ws.Page.Title = "Public IP Address Service"
|
||||
dip.Init()
|
||||
|
||||
memcacheconn, ok := os.LookupEnv("MEMCACHECONN")
|
||||
if ok {
|
||||
dip.MemcacheConn = memcacheconn
|
||||
}
|
||||
|
||||
ws.RunServer(config, Templates, Static)
|
||||
}
|
||||
|
34
go.mod
34
go.mod
@ -1,29 +1,27 @@
|
||||
module git.paulbsd.com/paulbsd/dip
|
||||
|
||||
go 1.20
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/labstack/echo/v4 v4.10.2
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/likexian/whois v1.14.6
|
||||
github.com/likexian/whois-parser v1.24.7
|
||||
github.com/oschwald/geoip2-golang v1.8.0
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
|
||||
github.com/labstack/echo/v4 v4.12.0
|
||||
github.com/likexian/whois v1.15.4
|
||||
github.com/likexian/whois-parser v1.24.19
|
||||
github.com/oschwald/geoip2-golang v1.11.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/labstack/gommon v0.4.0 // indirect
|
||||
github.com/likexian/gokit v0.25.11 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/likexian/gokit v0.25.15 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
)
|
||||
|
111
go.sum
111
go.sum
@ -1,82 +1,61 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA=
|
||||
github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ=
|
||||
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
||||
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/likexian/gokit v0.25.9 h1:rzSQ/dP7Qw+QUzSuWlrLF0AtZS3Di6uO5yWOKhx2Gk4=
|
||||
github.com/likexian/gokit v0.25.9/go.mod h1:oDDqJUcnnF9uAKuw54F7s6oEG+OJ7eallfDW2dq0A/o=
|
||||
github.com/likexian/gokit v0.25.11 h1:o5H5JgVtBYBQn0QX30zE5+V8j2rgLTDoZWAO8xLFFfY=
|
||||
github.com/likexian/gokit v0.25.11/go.mod h1:IKRQFPah2KQ0HL3iVjaOvFbx2apkSdFicGmsA0A4a1c=
|
||||
github.com/likexian/whois v1.14.4 h1:yNQVugAHfeoylzyhitcs0vaPksDduvzW46HLjqXhpCg=
|
||||
github.com/likexian/whois v1.14.4/go.mod h1:ijMqjPbtafr5TB49U3Hs3BsJx/93ixhRi/8YnCSK0iY=
|
||||
github.com/likexian/whois v1.14.6 h1:chNF6xkUShMQHq+5tiovVOQFadb9hqrWcaqbtlvbe3o=
|
||||
github.com/likexian/whois v1.14.6/go.mod h1:upfX0X3o78fvHyFY2zHv46zooPoydUV1msyovvLZTMU=
|
||||
github.com/likexian/whois-parser v1.24.2 h1:EaNwcXqWBfQPfLD5F6MxAA0o7FnzmGcN3mg7v7h0zfY=
|
||||
github.com/likexian/whois-parser v1.24.2/go.mod h1:fT0m/HCa4PXuR4ddA5PIE9V7gTWldeiMG/AHpeAhLtg=
|
||||
github.com/likexian/whois-parser v1.24.6 h1:Zaz4dEDxtLaz9Ot8jEdni4xUHqYqt/6DAhfrZmsUd9s=
|
||||
github.com/likexian/whois-parser v1.24.6/go.mod h1:MJN8IUeQ55VSG2OCB01a88T6V6VQm/UYxKLQySSqdSc=
|
||||
github.com/likexian/whois-parser v1.24.7 h1:UF36WfIXXu4BMwaUmWk6YbzolgpzWTGY0JQ4wZ/kumE=
|
||||
github.com/likexian/whois-parser v1.24.7/go.mod h1:MJN8IUeQ55VSG2OCB01a88T6V6VQm/UYxKLQySSqdSc=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
||||
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY=
|
||||
github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg=
|
||||
github.com/likexian/whois v1.15.3 h1:0emFSUSUj98Q12Wer3iM3eROPXjg+CyUBlibGPNbKHw=
|
||||
github.com/likexian/whois v1.15.3/go.mod h1:a6sGAAKEb+O3JRBuW2x/QDM80l5hJ07p0+SjQkJ1c+0=
|
||||
github.com/likexian/whois v1.15.4 h1:r5En62c+S9HKFgJtdh2WsdmRGTcxE4WUtGBdZkSBXmM=
|
||||
github.com/likexian/whois v1.15.4/go.mod h1:rXFTPcQdNlPQBJCQpPWTSIDGzzmgKBftmhdOOcLpwXk=
|
||||
github.com/likexian/whois-parser v1.24.18 h1:Xolieo/uwjNwhmQN/oDDNlwFajHipdHedyPBgzG44kw=
|
||||
github.com/likexian/whois-parser v1.24.18/go.mod h1:k5zmKRZ7xPg1TLv3BGT4g/LOPRIMhvdNMeB0F53V/jk=
|
||||
github.com/likexian/whois-parser v1.24.19 h1:vT8lWhnV8ogkdaYLyef6IvE5VTHVCwlUDG5BUXCx06k=
|
||||
github.com/likexian/whois-parser v1.24.19/go.mod h1:rAtaofg2luol09H+ogDzGIfcG8ig1NtM5R16uQADDz4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
||||
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
||||
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
||||
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
|
||||
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
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/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -4,3 +4,4 @@
|
||||
docker build -t dip:latest .
|
||||
docker tag dip:latest registry.paulbsd.com/images/dip:latest
|
||||
docker push registry.paulbsd.com/images/dip:latest
|
||||
kubectl rollout restart deployment dip
|
@ -1,11 +1,14 @@
|
||||
package dip
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"git.paulbsd.com/paulbsd/dip/src/geoip"
|
||||
"github.com/bradfitz/gomemcache/memcache"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/likexian/whois"
|
||||
whoisparser "github.com/likexian/whois-parser"
|
||||
@ -13,26 +16,53 @@ import (
|
||||
)
|
||||
|
||||
const defaultLanguage = "en"
|
||||
const cacheMaxTime = 604800
|
||||
|
||||
var citydb *geoip2.Reader
|
||||
var asndb *geoip2.Reader
|
||||
var MemcacheConn string = ""
|
||||
|
||||
func Init() (err error) {
|
||||
citydb, asndb, err = geoip.InitGeoIP()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("failed to get geoip database")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetIPInfo returns IP address informations
|
||||
func (ip *IP) GetIPInfo(c echo.Context) (err error) {
|
||||
if c.Param("ip") != "" {
|
||||
ip.IP = c.Param("ip")
|
||||
} else {
|
||||
func (ip *IP) GetIPInfo(c echo.Context) (cached bool, err error) {
|
||||
var mcenabled bool
|
||||
var mc *memcache.Client
|
||||
if MemcacheConn != "" {
|
||||
mc = memcache.New(MemcacheConn)
|
||||
mc.Timeout, err = time.ParseDuration("1s")
|
||||
mcenabled = true
|
||||
defer mc.Close()
|
||||
}
|
||||
|
||||
ip.IP = c.Param("ip")
|
||||
if c.Param("ip") == "" {
|
||||
ip.IP = c.RealIP()
|
||||
}
|
||||
|
||||
if mcenabled {
|
||||
item, err := mc.Get(ip.IP)
|
||||
if err != nil {
|
||||
log.Println("error from cache", ip.IP, err)
|
||||
cached = false
|
||||
} else {
|
||||
cachedip := IP{}
|
||||
err = json.Unmarshal(item.Value, &cachedip)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
*ip = cachedip
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
err = ip.CheckIPAddress()
|
||||
if err != nil {
|
||||
ip.IP = c.RealIP()
|
||||
@ -52,6 +82,16 @@ func (ip *IP) GetIPInfo(c echo.Context) (err error) {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
if mcenabled && !cached {
|
||||
go func() {
|
||||
dt, err := json.Marshal(*ip)
|
||||
err = mc.Set(&memcache.Item{Key: ip.IP, Value: dt, Expiration: cacheMaxTime})
|
||||
if err != nil {
|
||||
log.Println(err, "test")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
/*err = ip.GetWhois()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@ -13,24 +13,30 @@ import (
|
||||
geoip2 "github.com/oschwald/geoip2-golang"
|
||||
)
|
||||
|
||||
var RootURL = "https://git.paulbsd.com/paulbsd/GeoLite.mmdb/releases/download/%s/%s"
|
||||
var APIUrl = "https://git.paulbsd.com/api/v1/repos/paulbsd/GeoLite.mmdb/releases"
|
||||
const RootURL = "https://git.paulbsd.com/paulbsd/GeoLite.mmdb/releases/download/%s/%s"
|
||||
const APIUrl = "https://git.paulbsd.com/api/v1/repos/paulbsd/GeoLite.mmdb/releases"
|
||||
|
||||
func GetLastVersion() string {
|
||||
const CityFilename = "GeoLite2-City.mmdb"
|
||||
const ASNFilename = "GeoLite2-ASN.mmdb"
|
||||
|
||||
func GetLastVersion() (result string, err error) {
|
||||
var apiresults []struct {
|
||||
Tag string `json:"tag_name"`
|
||||
}
|
||||
res, err := http.Get(APIUrl)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiresults)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var tags []string
|
||||
@ -39,14 +45,18 @@ func GetLastVersion() string {
|
||||
}
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(tags)))
|
||||
|
||||
return tags[0]
|
||||
result = tags[0]
|
||||
return
|
||||
}
|
||||
|
||||
func InitGeoIP() (citydb *geoip2.Reader, asndb *geoip2.Reader, err error) {
|
||||
var version = GetLastVersion()
|
||||
version, err := GetLastVersion()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var dbs map[string]string = map[string]string{
|
||||
"city": fmt.Sprintf(RootURL, version, "GeoLite2-City.mmdb"),
|
||||
"asn": fmt.Sprintf(RootURL, version, "GeoLite2-ASN.mmdb")}
|
||||
"city": fmt.Sprintf(RootURL, version, CityFilename),
|
||||
"asn": fmt.Sprintf(RootURL, version, ASNFilename)}
|
||||
log.Printf("Fetching GeoLite.mmdb version %s\n", version)
|
||||
citydb, err = FetchDB(dbs["city"], version)
|
||||
if err != nil {
|
||||
|
@ -21,7 +21,10 @@ func GetStatic(staticfiles *embed.FS, c echo.Context) (err error) {
|
||||
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJavaScript)
|
||||
} else if strings.HasSuffix(name, ".css") {
|
||||
c.Response().Header().Set(echo.HeaderContentType, "text/css")
|
||||
} else if strings.HasSuffix(name, ".ico") {
|
||||
c.Response().Header().Set(echo.HeaderContentType, "image/x-icon")
|
||||
}
|
||||
c.Response().Header().Add(echo.HeaderCacheControl, "max-age=172800")
|
||||
return c.String(http.StatusOK, string(content))
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Con
|
||||
if strings.HasSuffix(name, ".html") {
|
||||
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
||||
}
|
||||
c.Response().Header().Add(echo.HeaderCacheControl, "max-age=172800")
|
||||
return t.templates.ExecuteTemplate(w, name, data)
|
||||
}
|
||||
|
||||
@ -38,29 +39,6 @@ func BuildTemplates(templatefiles *embed.FS) (builttemplates *Template, err erro
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
// BuildTemplatesDir converts packr packages to html/template
|
||||
func BuildTemplatesDir(dir string) (builttemplates *Template, err error) {
|
||||
tmpl := template.New("templates")
|
||||
|
||||
err = pkger.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
freader, _ := pkger.Open(path)
|
||||
tmplContent, err := ioutil.ReadAll(freader)
|
||||
tmpl.New(info.Name()).Parse(string(tmplContent))
|
||||
fmt.Println(info.Name(), tmplContent)
|
||||
return err
|
||||
})
|
||||
|
||||
builttemplates = &Template{
|
||||
templates: tmpl,
|
||||
}
|
||||
|
||||
return
|
||||
}*/
|
||||
|
||||
// Template is a template struct
|
||||
type Template struct {
|
||||
templates *template.Template
|
||||
|
@ -22,7 +22,7 @@ func (ws *WS) InitServer(templatefiles *embed.FS, staticfiles *embed.FS) (err er
|
||||
}))
|
||||
ws.e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
|
||||
AllowMethods: []string{http.MethodGet},
|
||||
}))
|
||||
|
||||
builtTemplates, _ := templates.BuildTemplates(templatefiles)
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func (p *Page) GetContent(c echo.Context) (err error) {
|
||||
func (p *Page) GetContent(c echo.Context) (cached bool, err error) {
|
||||
var ip dip.IP
|
||||
err = ip.GetIPInfo(c)
|
||||
cached, err = ip.GetIPInfo(c)
|
||||
p.IP = &ip
|
||||
|
||||
return
|
||||
@ -18,7 +18,11 @@ func (p *Page) GetContent(c echo.Context) (err error) {
|
||||
|
||||
// Process returns main webpage or a JSON
|
||||
func (p *Page) Process(c echo.Context, querytype string) (err error) {
|
||||
p.GetContent(c)
|
||||
cached, err := p.GetContent(c)
|
||||
c.Response().Header().Set("X-Cached", "false")
|
||||
if cached {
|
||||
c.Response().Header().Set("X-Cached", "true")
|
||||
}
|
||||
if querytype == "json" {
|
||||
return c.JSONPretty(http.StatusOK, p.IP, " ")
|
||||
}
|
||||
|
BIN
static/images/favicon.ico
Normal file
BIN
static/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
3
static/js/axios.min.js
vendored
3
static/js/axios.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,29 +1,39 @@
|
||||
var vue = new Vue({
|
||||
el: '#dip_main_div',
|
||||
const dip_ip = document.getElementById("dip_ip");
|
||||
const dip_hostname = document.getElementById("dip_hostname");
|
||||
const dip_city = document.getElementById("dip_city");
|
||||
const dip_country = document.getElementById("dip_country");
|
||||
const dip_as_number = document.getElementById("dip_as_number");
|
||||
const dip_as_org = document.getElementById("dip_as_org");
|
||||
|
||||
data () {
|
||||
return {
|
||||
title: "Public IP Address service",
|
||||
dip: {"ip": null,
|
||||
"hostname": null,
|
||||
"city": null,
|
||||
"country": null},
|
||||
}
|
||||
},
|
||||
function setData(res) {
|
||||
dip_ip.innerHTML = res["ip"];
|
||||
dip_hostname.innerHTML = res["hostname"];
|
||||
dip_city.innerHTML = res["city"];
|
||||
dip_country.innerHTML = res["country"];
|
||||
dip_as_number.innerHTML = res["as"]["number"];
|
||||
dip_as_org.innerHTML = res["as"]["org"];
|
||||
}
|
||||
|
||||
mounted () {
|
||||
var ip = "";
|
||||
if (window.location.pathname.length > 4) {
|
||||
ip = window.location.pathname.split("/")[1];
|
||||
console.log(ip);
|
||||
}
|
||||
axios.get(`/json/${ip}`)
|
||||
.then(response => {
|
||||
this.dip = response.data
|
||||
})
|
||||
.catch(err => {
|
||||
// Manage the state of the application if the request
|
||||
// has failed
|
||||
});
|
||||
function updateIP() {
|
||||
let ip = "";
|
||||
|
||||
if (window.location.pathname.length > 4) {
|
||||
ip = window.location.pathname.split("/")[1];
|
||||
}
|
||||
});
|
||||
|
||||
const localdata = localStorage.getItem("data");
|
||||
if (localdata) {
|
||||
const data = JSON.parse(localdata);
|
||||
setData(data);
|
||||
}
|
||||
|
||||
fetch(`/json/${ip}`).then((response) => {
|
||||
response.json().then((data) => {
|
||||
setData(data);
|
||||
localStorage.setItem("data",JSON.stringify(data));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateIP()
|
||||
setInterval(updateIP,1000);
|
||||
|
6
static/js/vue.min.js
vendored
6
static/js/vue.min.js
vendored
File diff suppressed because one or more lines are too long
@ -8,4 +8,5 @@ import (
|
||||
//
|
||||
//go:embed css/*
|
||||
//go:embed js/*
|
||||
//go:embed images/*
|
||||
var Static embed.FS
|
||||
|
@ -4,12 +4,11 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="icon" href="static/images/favicon.ico"/>
|
||||
<link rel="stylesheet" href="static/css/main.css" />
|
||||
<link rel="stylesheet" href="static/css/uikit.min.css" />
|
||||
<link rel="stylesheet" href="static/css/font-awesome.min.css" />
|
||||
|
||||
<script src="static/js/uikit.min.js"></script>
|
||||
<script src="static/js/uikit-icons.min.js"></script>
|
||||
<script src="static/js/axios.min.js"></script>
|
||||
<script src="static/js/vue.min.js"></script>
|
||||
</head>
|
||||
|
@ -8,29 +8,27 @@
|
||||
<caption>IP informations</caption>
|
||||
<tr>
|
||||
<td>IP</td>
|
||||
<td>{{ "{{" }} dip.ip {{ "}}" }}</td>
|
||||
<td id="dip_ip"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Reverse DNS</td>
|
||||
<td>{{ "{{" }} dip.hostname {{ "}}" }}</td>
|
||||
<td id="dip_hostname"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>City</td>
|
||||
<td>{{ "{{" }} dip.city {{ "}}" }}</td>
|
||||
<td id="dip_city"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Country</td>
|
||||
<td>{{ "{{" }} dip.country {{ "}}" }}</td>
|
||||
<td id="dip_country"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AS number</td>
|
||||
<td>{{ "{{" }} dip.as.number {{ "}}" }}</td>
|
||||
<td id="dip_as_number"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AS name</td>
|
||||
<td>
|
||||
{{ "{{" }} dip.as.org {{ "}}" }}
|
||||
</td>
|
||||
<td id="dip_as_org"></td>
|
||||
</tr>
|
||||
</div>
|
||||
{{ template "footer_js.html" .}}
|
||||
|
9
vendor/github.com/bradfitz/gomemcache/AUTHORS
generated
vendored
Normal file
9
vendor/github.com/bradfitz/gomemcache/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
The following people & companies are the copyright holders of this
|
||||
package. Feel free to add to this list if you or your employer cares,
|
||||
otherwise it's implicit from the git log.
|
||||
|
||||
Authors:
|
||||
|
||||
- Brad Fitzpatrick
|
||||
- Google, Inc. (from Googlers contributing)
|
||||
- Anybody else in the git log.
|
202
vendor/github.com/bradfitz/gomemcache/LICENSE
generated
vendored
Normal file
202
vendor/github.com/bradfitz/gomemcache/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
776
vendor/github.com/bradfitz/gomemcache/memcache/memcache.go
generated
vendored
Normal file
776
vendor/github.com/bradfitz/gomemcache/memcache/memcache.go
generated
vendored
Normal file
@ -0,0 +1,776 @@
|
||||
/*
|
||||
Copyright 2011 The gomemcache AUTHORS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package memcache provides a client for the memcached cache server.
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Similar to:
|
||||
// https://godoc.org/google.golang.org/appengine/memcache
|
||||
|
||||
var (
|
||||
// ErrCacheMiss means that a Get failed because the item wasn't present.
|
||||
ErrCacheMiss = errors.New("memcache: cache miss")
|
||||
|
||||
// ErrCASConflict means that a CompareAndSwap call failed due to the
|
||||
// cached value being modified between the Get and the CompareAndSwap.
|
||||
// If the cached value was simply evicted rather than replaced,
|
||||
// ErrNotStored will be returned instead.
|
||||
ErrCASConflict = errors.New("memcache: compare-and-swap conflict")
|
||||
|
||||
// ErrNotStored means that a conditional write operation (i.e. Add or
|
||||
// CompareAndSwap) failed because the condition was not satisfied.
|
||||
ErrNotStored = errors.New("memcache: item not stored")
|
||||
|
||||
// ErrServer means that a server error occurred.
|
||||
ErrServerError = errors.New("memcache: server error")
|
||||
|
||||
// ErrNoStats means that no statistics were available.
|
||||
ErrNoStats = errors.New("memcache: no statistics available")
|
||||
|
||||
// ErrMalformedKey is returned when an invalid key is used.
|
||||
// Keys must be at maximum 250 bytes long and not
|
||||
// contain whitespace or control characters.
|
||||
ErrMalformedKey = errors.New("malformed: key is too long or contains invalid characters")
|
||||
|
||||
// ErrNoServers is returned when no servers are configured or available.
|
||||
ErrNoServers = errors.New("memcache: no servers configured or available")
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultTimeout is the default socket read/write timeout.
|
||||
DefaultTimeout = 500 * time.Millisecond
|
||||
|
||||
// DefaultMaxIdleConns is the default maximum number of idle connections
|
||||
// kept for any single address.
|
||||
DefaultMaxIdleConns = 2
|
||||
)
|
||||
|
||||
const buffered = 8 // arbitrary buffered channel size, for readability
|
||||
|
||||
// resumableError returns true if err is only a protocol-level cache error.
|
||||
// This is used to determine whether or not a server connection should
|
||||
// be re-used or not. If an error occurs, by default we don't reuse the
|
||||
// connection, unless it was just a cache error.
|
||||
func resumableError(err error) bool {
|
||||
switch err {
|
||||
case ErrCacheMiss, ErrCASConflict, ErrNotStored, ErrMalformedKey:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func legalKey(key string) bool {
|
||||
if len(key) > 250 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(key); i++ {
|
||||
if key[i] <= ' ' || key[i] == 0x7f {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
crlf = []byte("\r\n")
|
||||
space = []byte(" ")
|
||||
resultOK = []byte("OK\r\n")
|
||||
resultStored = []byte("STORED\r\n")
|
||||
resultNotStored = []byte("NOT_STORED\r\n")
|
||||
resultExists = []byte("EXISTS\r\n")
|
||||
resultNotFound = []byte("NOT_FOUND\r\n")
|
||||
resultDeleted = []byte("DELETED\r\n")
|
||||
resultEnd = []byte("END\r\n")
|
||||
resultOk = []byte("OK\r\n")
|
||||
resultTouched = []byte("TOUCHED\r\n")
|
||||
|
||||
resultClientErrorPrefix = []byte("CLIENT_ERROR ")
|
||||
versionPrefix = []byte("VERSION")
|
||||
)
|
||||
|
||||
// New returns a memcache client using the provided server(s)
|
||||
// with equal weight. If a server is listed multiple times,
|
||||
// it gets a proportional amount of weight.
|
||||
func New(server ...string) *Client {
|
||||
ss := new(ServerList)
|
||||
ss.SetServers(server...)
|
||||
return NewFromSelector(ss)
|
||||
}
|
||||
|
||||
// NewFromSelector returns a new Client using the provided ServerSelector.
|
||||
func NewFromSelector(ss ServerSelector) *Client {
|
||||
return &Client{selector: ss}
|
||||
}
|
||||
|
||||
// Client is a memcache client.
|
||||
// It is safe for unlocked use by multiple concurrent goroutines.
|
||||
type Client struct {
|
||||
// DialContext connects to the address on the named network using the
|
||||
// provided context.
|
||||
//
|
||||
// To connect to servers using TLS (memcached running with "--enable-ssl"),
|
||||
// use a DialContext func that uses tls.Dialer.DialContext. See this
|
||||
// package's tests as an example.
|
||||
DialContext func(ctx context.Context, network, address string) (net.Conn, error)
|
||||
|
||||
// Timeout specifies the socket read/write timeout.
|
||||
// If zero, DefaultTimeout is used.
|
||||
Timeout time.Duration
|
||||
|
||||
// MaxIdleConns specifies the maximum number of idle connections that will
|
||||
// be maintained per address. If less than one, DefaultMaxIdleConns will be
|
||||
// used.
|
||||
//
|
||||
// Consider your expected traffic rates and latency carefully. This should
|
||||
// be set to a number higher than your peak parallel requests.
|
||||
MaxIdleConns int
|
||||
|
||||
selector ServerSelector
|
||||
|
||||
lk sync.Mutex
|
||||
freeconn map[string][]*conn
|
||||
}
|
||||
|
||||
// Item is an item to be got or stored in a memcached server.
|
||||
type Item struct {
|
||||
// Key is the Item's key (250 bytes maximum).
|
||||
Key string
|
||||
|
||||
// Value is the Item's value.
|
||||
Value []byte
|
||||
|
||||
// Flags are server-opaque flags whose semantics are entirely
|
||||
// up to the app.
|
||||
Flags uint32
|
||||
|
||||
// Expiration is the cache expiration time, in seconds: either a relative
|
||||
// time from now (up to 1 month), or an absolute Unix epoch time.
|
||||
// Zero means the Item has no expiration time.
|
||||
Expiration int32
|
||||
|
||||
// CasID is the compare and swap ID.
|
||||
//
|
||||
// It's populated by get requests and then the same value is
|
||||
// required for a CompareAndSwap request to succeed.
|
||||
CasID uint64
|
||||
}
|
||||
|
||||
// conn is a connection to a server.
|
||||
type conn struct {
|
||||
nc net.Conn
|
||||
rw *bufio.ReadWriter
|
||||
addr net.Addr
|
||||
c *Client
|
||||
}
|
||||
|
||||
// release returns this connection back to the client's free pool
|
||||
func (cn *conn) release() {
|
||||
cn.c.putFreeConn(cn.addr, cn)
|
||||
}
|
||||
|
||||
func (cn *conn) extendDeadline() {
|
||||
cn.nc.SetDeadline(time.Now().Add(cn.c.netTimeout()))
|
||||
}
|
||||
|
||||
// condRelease releases this connection if the error pointed to by err
|
||||
// is nil (not an error) or is only a protocol level error (e.g. a
|
||||
// cache miss). The purpose is to not recycle TCP connections that
|
||||
// are bad.
|
||||
func (cn *conn) condRelease(err *error) {
|
||||
if *err == nil || resumableError(*err) {
|
||||
cn.release()
|
||||
} else {
|
||||
cn.nc.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) putFreeConn(addr net.Addr, cn *conn) {
|
||||
c.lk.Lock()
|
||||
defer c.lk.Unlock()
|
||||
if c.freeconn == nil {
|
||||
c.freeconn = make(map[string][]*conn)
|
||||
}
|
||||
freelist := c.freeconn[addr.String()]
|
||||
if len(freelist) >= c.maxIdleConns() {
|
||||
cn.nc.Close()
|
||||
return
|
||||
}
|
||||
c.freeconn[addr.String()] = append(freelist, cn)
|
||||
}
|
||||
|
||||
func (c *Client) getFreeConn(addr net.Addr) (cn *conn, ok bool) {
|
||||
c.lk.Lock()
|
||||
defer c.lk.Unlock()
|
||||
if c.freeconn == nil {
|
||||
return nil, false
|
||||
}
|
||||
freelist, ok := c.freeconn[addr.String()]
|
||||
if !ok || len(freelist) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
cn = freelist[len(freelist)-1]
|
||||
c.freeconn[addr.String()] = freelist[:len(freelist)-1]
|
||||
return cn, true
|
||||
}
|
||||
|
||||
func (c *Client) netTimeout() time.Duration {
|
||||
if c.Timeout != 0 {
|
||||
return c.Timeout
|
||||
}
|
||||
return DefaultTimeout
|
||||
}
|
||||
|
||||
func (c *Client) maxIdleConns() int {
|
||||
if c.MaxIdleConns > 0 {
|
||||
return c.MaxIdleConns
|
||||
}
|
||||
return DefaultMaxIdleConns
|
||||
}
|
||||
|
||||
// ConnectTimeoutError is the error type used when it takes
|
||||
// too long to connect to the desired host. This level of
|
||||
// detail can generally be ignored.
|
||||
type ConnectTimeoutError struct {
|
||||
Addr net.Addr
|
||||
}
|
||||
|
||||
func (cte *ConnectTimeoutError) Error() string {
|
||||
return "memcache: connect timeout to " + cte.Addr.String()
|
||||
}
|
||||
|
||||
func (c *Client) dial(addr net.Addr) (net.Conn, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), c.netTimeout())
|
||||
defer cancel()
|
||||
|
||||
dialerContext := c.DialContext
|
||||
if dialerContext == nil {
|
||||
dialer := net.Dialer{
|
||||
Timeout: c.netTimeout(),
|
||||
}
|
||||
dialerContext = dialer.DialContext
|
||||
}
|
||||
|
||||
nc, err := dialerContext(ctx, addr.Network(), addr.String())
|
||||
if err == nil {
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
if ne, ok := err.(net.Error); ok && ne.Timeout() {
|
||||
return nil, &ConnectTimeoutError{addr}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *Client) getConn(addr net.Addr) (*conn, error) {
|
||||
cn, ok := c.getFreeConn(addr)
|
||||
if ok {
|
||||
cn.extendDeadline()
|
||||
return cn, nil
|
||||
}
|
||||
nc, err := c.dial(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cn = &conn{
|
||||
nc: nc,
|
||||
addr: addr,
|
||||
rw: bufio.NewReadWriter(bufio.NewReader(nc), bufio.NewWriter(nc)),
|
||||
c: c,
|
||||
}
|
||||
cn.extendDeadline()
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
func (c *Client) onItem(item *Item, fn func(*Client, *bufio.ReadWriter, *Item) error) error {
|
||||
addr, err := c.selector.PickServer(item.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cn, err := c.getConn(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cn.condRelease(&err)
|
||||
if err = fn(c, cn.rw, item); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) FlushAll() error {
|
||||
return c.selector.Each(c.flushAllFromAddr)
|
||||
}
|
||||
|
||||
// Get gets the item for the given key. ErrCacheMiss is returned for a
|
||||
// memcache cache miss. The key must be at most 250 bytes in length.
|
||||
func (c *Client) Get(key string) (item *Item, err error) {
|
||||
err = c.withKeyAddr(key, func(addr net.Addr) error {
|
||||
return c.getFromAddr(addr, []string{key}, func(it *Item) { item = it })
|
||||
})
|
||||
if err == nil && item == nil {
|
||||
err = ErrCacheMiss
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Touch updates the expiry for the given key. The seconds parameter is either
|
||||
// a Unix timestamp or, if seconds is less than 1 month, the number of seconds
|
||||
// into the future at which time the item will expire. Zero means the item has
|
||||
// no expiration time. ErrCacheMiss is returned if the key is not in the cache.
|
||||
// The key must be at most 250 bytes in length.
|
||||
func (c *Client) Touch(key string, seconds int32) (err error) {
|
||||
return c.withKeyAddr(key, func(addr net.Addr) error {
|
||||
return c.touchFromAddr(addr, []string{key}, seconds)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Client) withKeyAddr(key string, fn func(net.Addr) error) (err error) {
|
||||
if !legalKey(key) {
|
||||
return ErrMalformedKey
|
||||
}
|
||||
addr, err := c.selector.PickServer(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fn(addr)
|
||||
}
|
||||
|
||||
func (c *Client) withAddrRw(addr net.Addr, fn func(*bufio.ReadWriter) error) (err error) {
|
||||
cn, err := c.getConn(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cn.condRelease(&err)
|
||||
return fn(cn.rw)
|
||||
}
|
||||
|
||||
func (c *Client) withKeyRw(key string, fn func(*bufio.ReadWriter) error) error {
|
||||
return c.withKeyAddr(key, func(addr net.Addr) error {
|
||||
return c.withAddrRw(addr, fn)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Client) getFromAddr(addr net.Addr, keys []string, cb func(*Item)) error {
|
||||
return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
|
||||
if _, err := fmt.Fprintf(rw, "gets %s\r\n", strings.Join(keys, " ")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parseGetResponse(rw.Reader, cb); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// flushAllFromAddr send the flush_all command to the given addr
|
||||
func (c *Client) flushAllFromAddr(addr net.Addr) error {
|
||||
return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
|
||||
if _, err := fmt.Fprintf(rw, "flush_all\r\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
line, err := rw.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case bytes.Equal(line, resultOk):
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("memcache: unexpected response line from flush_all: %q", string(line))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// ping sends the version command to the given addr
|
||||
func (c *Client) ping(addr net.Addr) error {
|
||||
return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
|
||||
if _, err := fmt.Fprintf(rw, "version\r\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
line, err := rw.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case bytes.HasPrefix(line, versionPrefix):
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("memcache: unexpected response line from ping: %q", string(line))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Client) touchFromAddr(addr net.Addr, keys []string, expiration int32) error {
|
||||
return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
|
||||
for _, key := range keys {
|
||||
if _, err := fmt.Fprintf(rw, "touch %s %d\r\n", key, expiration); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
line, err := rw.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case bytes.Equal(line, resultTouched):
|
||||
break
|
||||
case bytes.Equal(line, resultNotFound):
|
||||
return ErrCacheMiss
|
||||
default:
|
||||
return fmt.Errorf("memcache: unexpected response line from touch: %q", string(line))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// GetMulti is a batch version of Get. The returned map from keys to
|
||||
// items may have fewer elements than the input slice, due to memcache
|
||||
// cache misses. Each key must be at most 250 bytes in length.
|
||||
// If no error is returned, the returned map will also be non-nil.
|
||||
func (c *Client) GetMulti(keys []string) (map[string]*Item, error) {
|
||||
var lk sync.Mutex
|
||||
m := make(map[string]*Item)
|
||||
addItemToMap := func(it *Item) {
|
||||
lk.Lock()
|
||||
defer lk.Unlock()
|
||||
m[it.Key] = it
|
||||
}
|
||||
|
||||
keyMap := make(map[net.Addr][]string)
|
||||
for _, key := range keys {
|
||||
if !legalKey(key) {
|
||||
return nil, ErrMalformedKey
|
||||
}
|
||||
addr, err := c.selector.PickServer(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyMap[addr] = append(keyMap[addr], key)
|
||||
}
|
||||
|
||||
ch := make(chan error, buffered)
|
||||
for addr, keys := range keyMap {
|
||||
go func(addr net.Addr, keys []string) {
|
||||
ch <- c.getFromAddr(addr, keys, addItemToMap)
|
||||
}(addr, keys)
|
||||
}
|
||||
|
||||
var err error
|
||||
for _ = range keyMap {
|
||||
if ge := <-ch; ge != nil {
|
||||
err = ge
|
||||
}
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
|
||||
// parseGetResponse reads a GET response from r and calls cb for each
|
||||
// read and allocated Item
|
||||
func parseGetResponse(r *bufio.Reader, cb func(*Item)) error {
|
||||
for {
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bytes.Equal(line, resultEnd) {
|
||||
return nil
|
||||
}
|
||||
it := new(Item)
|
||||
size, err := scanGetResponseLine(line, it)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
it.Value = make([]byte, size+2)
|
||||
_, err = io.ReadFull(r, it.Value)
|
||||
if err != nil {
|
||||
it.Value = nil
|
||||
return err
|
||||
}
|
||||
if !bytes.HasSuffix(it.Value, crlf) {
|
||||
it.Value = nil
|
||||
return fmt.Errorf("memcache: corrupt get result read")
|
||||
}
|
||||
it.Value = it.Value[:size]
|
||||
cb(it)
|
||||
}
|
||||
}
|
||||
|
||||
// scanGetResponseLine populates it and returns the declared size of the item.
|
||||
// It does not read the bytes of the item.
|
||||
func scanGetResponseLine(line []byte, it *Item) (size int, err error) {
|
||||
pattern := "VALUE %s %d %d %d\r\n"
|
||||
dest := []interface{}{&it.Key, &it.Flags, &size, &it.CasID}
|
||||
if bytes.Count(line, space) == 3 {
|
||||
pattern = "VALUE %s %d %d\r\n"
|
||||
dest = dest[:3]
|
||||
}
|
||||
n, err := fmt.Sscanf(string(line), pattern, dest...)
|
||||
if err != nil || n != len(dest) {
|
||||
return -1, fmt.Errorf("memcache: unexpected line in get response: %q", line)
|
||||
}
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// Set writes the given item, unconditionally.
|
||||
func (c *Client) Set(item *Item) error {
|
||||
return c.onItem(item, (*Client).set)
|
||||
}
|
||||
|
||||
func (c *Client) set(rw *bufio.ReadWriter, item *Item) error {
|
||||
return c.populateOne(rw, "set", item)
|
||||
}
|
||||
|
||||
// Add writes the given item, if no value already exists for its
|
||||
// key. ErrNotStored is returned if that condition is not met.
|
||||
func (c *Client) Add(item *Item) error {
|
||||
return c.onItem(item, (*Client).add)
|
||||
}
|
||||
|
||||
func (c *Client) add(rw *bufio.ReadWriter, item *Item) error {
|
||||
return c.populateOne(rw, "add", item)
|
||||
}
|
||||
|
||||
// Replace writes the given item, but only if the server *does*
|
||||
// already hold data for this key
|
||||
func (c *Client) Replace(item *Item) error {
|
||||
return c.onItem(item, (*Client).replace)
|
||||
}
|
||||
|
||||
func (c *Client) replace(rw *bufio.ReadWriter, item *Item) error {
|
||||
return c.populateOne(rw, "replace", item)
|
||||
}
|
||||
|
||||
// Append appends the given item to the existing item, if a value already
|
||||
// exists for its key. ErrNotStored is returned if that condition is not met.
|
||||
func (c *Client) Append(item *Item) error {
|
||||
return c.onItem(item, (*Client).append)
|
||||
}
|
||||
|
||||
func (c *Client) append(rw *bufio.ReadWriter, item *Item) error {
|
||||
return c.populateOne(rw, "append", item)
|
||||
}
|
||||
|
||||
// Prepend prepends the given item to the existing item, if a value already
|
||||
// exists for its key. ErrNotStored is returned if that condition is not met.
|
||||
func (c *Client) Prepend(item *Item) error {
|
||||
return c.onItem(item, (*Client).prepend)
|
||||
}
|
||||
|
||||
func (c *Client) prepend(rw *bufio.ReadWriter, item *Item) error {
|
||||
return c.populateOne(rw, "prepend", item)
|
||||
}
|
||||
|
||||
// CompareAndSwap writes the given item that was previously returned
|
||||
// by Get, if the value was neither modified or evicted between the
|
||||
// Get and the CompareAndSwap calls. The item's Key should not change
|
||||
// between calls but all other item fields may differ. ErrCASConflict
|
||||
// is returned if the value was modified in between the
|
||||
// calls. ErrNotStored is returned if the value was evicted in between
|
||||
// the calls.
|
||||
func (c *Client) CompareAndSwap(item *Item) error {
|
||||
return c.onItem(item, (*Client).cas)
|
||||
}
|
||||
|
||||
func (c *Client) cas(rw *bufio.ReadWriter, item *Item) error {
|
||||
return c.populateOne(rw, "cas", item)
|
||||
}
|
||||
|
||||
func (c *Client) populateOne(rw *bufio.ReadWriter, verb string, item *Item) error {
|
||||
if !legalKey(item.Key) {
|
||||
return ErrMalformedKey
|
||||
}
|
||||
var err error
|
||||
if verb == "cas" {
|
||||
_, err = fmt.Fprintf(rw, "%s %s %d %d %d %d\r\n",
|
||||
verb, item.Key, item.Flags, item.Expiration, len(item.Value), item.CasID)
|
||||
} else {
|
||||
_, err = fmt.Fprintf(rw, "%s %s %d %d %d\r\n",
|
||||
verb, item.Key, item.Flags, item.Expiration, len(item.Value))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = rw.Write(item.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := rw.Write(crlf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
line, err := rw.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case bytes.Equal(line, resultStored):
|
||||
return nil
|
||||
case bytes.Equal(line, resultNotStored):
|
||||
return ErrNotStored
|
||||
case bytes.Equal(line, resultExists):
|
||||
return ErrCASConflict
|
||||
case bytes.Equal(line, resultNotFound):
|
||||
return ErrCacheMiss
|
||||
}
|
||||
return fmt.Errorf("memcache: unexpected response line from %q: %q", verb, string(line))
|
||||
}
|
||||
|
||||
func writeReadLine(rw *bufio.ReadWriter, format string, args ...interface{}) ([]byte, error) {
|
||||
_, err := fmt.Fprintf(rw, format, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rw.Flush(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line, err := rw.ReadSlice('\n')
|
||||
return line, err
|
||||
}
|
||||
|
||||
func writeExpectf(rw *bufio.ReadWriter, expect []byte, format string, args ...interface{}) error {
|
||||
line, err := writeReadLine(rw, format, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case bytes.Equal(line, resultOK):
|
||||
return nil
|
||||
case bytes.Equal(line, expect):
|
||||
return nil
|
||||
case bytes.Equal(line, resultNotStored):
|
||||
return ErrNotStored
|
||||
case bytes.Equal(line, resultExists):
|
||||
return ErrCASConflict
|
||||
case bytes.Equal(line, resultNotFound):
|
||||
return ErrCacheMiss
|
||||
}
|
||||
return fmt.Errorf("memcache: unexpected response line: %q", string(line))
|
||||
}
|
||||
|
||||
// Delete deletes the item with the provided key. The error ErrCacheMiss is
|
||||
// returned if the item didn't already exist in the cache.
|
||||
func (c *Client) Delete(key string) error {
|
||||
return c.withKeyRw(key, func(rw *bufio.ReadWriter) error {
|
||||
return writeExpectf(rw, resultDeleted, "delete %s\r\n", key)
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteAll deletes all items in the cache.
|
||||
func (c *Client) DeleteAll() error {
|
||||
return c.withKeyRw("", func(rw *bufio.ReadWriter) error {
|
||||
return writeExpectf(rw, resultDeleted, "flush_all\r\n")
|
||||
})
|
||||
}
|
||||
|
||||
// Ping checks all instances if they are alive. Returns error if any
|
||||
// of them is down.
|
||||
func (c *Client) Ping() error {
|
||||
return c.selector.Each(c.ping)
|
||||
}
|
||||
|
||||
// Increment atomically increments key by delta. The return value is
|
||||
// the new value after being incremented or an error. If the value
|
||||
// didn't exist in memcached the error is ErrCacheMiss. The value in
|
||||
// memcached must be an decimal number, or an error will be returned.
|
||||
// On 64-bit overflow, the new value wraps around.
|
||||
func (c *Client) Increment(key string, delta uint64) (newValue uint64, err error) {
|
||||
return c.incrDecr("incr", key, delta)
|
||||
}
|
||||
|
||||
// Decrement atomically decrements key by delta. The return value is
|
||||
// the new value after being decremented or an error. If the value
|
||||
// didn't exist in memcached the error is ErrCacheMiss. The value in
|
||||
// memcached must be an decimal number, or an error will be returned.
|
||||
// On underflow, the new value is capped at zero and does not wrap
|
||||
// around.
|
||||
func (c *Client) Decrement(key string, delta uint64) (newValue uint64, err error) {
|
||||
return c.incrDecr("decr", key, delta)
|
||||
}
|
||||
|
||||
func (c *Client) incrDecr(verb, key string, delta uint64) (uint64, error) {
|
||||
var val uint64
|
||||
err := c.withKeyRw(key, func(rw *bufio.ReadWriter) error {
|
||||
line, err := writeReadLine(rw, "%s %s %d\r\n", verb, key, delta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case bytes.Equal(line, resultNotFound):
|
||||
return ErrCacheMiss
|
||||
case bytes.HasPrefix(line, resultClientErrorPrefix):
|
||||
errMsg := line[len(resultClientErrorPrefix) : len(line)-2]
|
||||
return errors.New("memcache: client error: " + string(errMsg))
|
||||
}
|
||||
val, err = strconv.ParseUint(string(line[:len(line)-2]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return val, err
|
||||
}
|
||||
|
||||
// Close closes any open connections.
|
||||
//
|
||||
// It returns the first error encountered closing connections, but always
|
||||
// closes all connections.
|
||||
//
|
||||
// After Close, the Client may still be used.
|
||||
func (c *Client) Close() error {
|
||||
c.lk.Lock()
|
||||
defer c.lk.Unlock()
|
||||
var ret error
|
||||
for _, conns := range c.freeconn {
|
||||
for _, c := range conns {
|
||||
if err := c.nc.Close(); err != nil && ret == nil {
|
||||
ret = err
|
||||
}
|
||||
}
|
||||
}
|
||||
c.freeconn = nil
|
||||
return ret
|
||||
}
|
129
vendor/github.com/bradfitz/gomemcache/memcache/selector.go
generated
vendored
Normal file
129
vendor/github.com/bradfitz/gomemcache/memcache/selector.go
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2011 The gomemcache AUTHORS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ServerSelector is the interface that selects a memcache server
|
||||
// as a function of the item's key.
|
||||
//
|
||||
// All ServerSelector implementations must be safe for concurrent use
|
||||
// by multiple goroutines.
|
||||
type ServerSelector interface {
|
||||
// PickServer returns the server address that a given item
|
||||
// should be shared onto.
|
||||
PickServer(key string) (net.Addr, error)
|
||||
Each(func(net.Addr) error) error
|
||||
}
|
||||
|
||||
// ServerList is a simple ServerSelector. Its zero value is usable.
|
||||
type ServerList struct {
|
||||
mu sync.RWMutex
|
||||
addrs []net.Addr
|
||||
}
|
||||
|
||||
// staticAddr caches the Network() and String() values from any net.Addr.
|
||||
type staticAddr struct {
|
||||
ntw, str string
|
||||
}
|
||||
|
||||
func newStaticAddr(a net.Addr) net.Addr {
|
||||
return &staticAddr{
|
||||
ntw: a.Network(),
|
||||
str: a.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *staticAddr) Network() string { return s.ntw }
|
||||
func (s *staticAddr) String() string { return s.str }
|
||||
|
||||
// SetServers changes a ServerList's set of servers at runtime and is
|
||||
// safe for concurrent use by multiple goroutines.
|
||||
//
|
||||
// Each server is given equal weight. A server is given more weight
|
||||
// if it's listed multiple times.
|
||||
//
|
||||
// SetServers returns an error if any of the server names fail to
|
||||
// resolve. No attempt is made to connect to the server. If any error
|
||||
// is returned, no changes are made to the ServerList.
|
||||
func (ss *ServerList) SetServers(servers ...string) error {
|
||||
naddr := make([]net.Addr, len(servers))
|
||||
for i, server := range servers {
|
||||
if strings.Contains(server, "/") {
|
||||
addr, err := net.ResolveUnixAddr("unix", server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
naddr[i] = newStaticAddr(addr)
|
||||
} else {
|
||||
tcpaddr, err := net.ResolveTCPAddr("tcp", server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
naddr[i] = newStaticAddr(tcpaddr)
|
||||
}
|
||||
}
|
||||
|
||||
ss.mu.Lock()
|
||||
defer ss.mu.Unlock()
|
||||
ss.addrs = naddr
|
||||
return nil
|
||||
}
|
||||
|
||||
// Each iterates over each server calling the given function
|
||||
func (ss *ServerList) Each(f func(net.Addr) error) error {
|
||||
ss.mu.RLock()
|
||||
defer ss.mu.RUnlock()
|
||||
for _, a := range ss.addrs {
|
||||
if err := f(a); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// keyBufPool returns []byte buffers for use by PickServer's call to
|
||||
// crc32.ChecksumIEEE to avoid allocations. (but doesn't avoid the
|
||||
// copies, which at least are bounded in size and small)
|
||||
var keyBufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
b := make([]byte, 256)
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
||||
func (ss *ServerList) PickServer(key string) (net.Addr, error) {
|
||||
ss.mu.RLock()
|
||||
defer ss.mu.RUnlock()
|
||||
if len(ss.addrs) == 0 {
|
||||
return nil, ErrNoServers
|
||||
}
|
||||
if len(ss.addrs) == 1 {
|
||||
return ss.addrs[0], nil
|
||||
}
|
||||
bufp := keyBufPool.Get().(*[]byte)
|
||||
n := copy(*bufp, key)
|
||||
cs := crc32.ChecksumIEEE((*bufp)[:n])
|
||||
keyBufPool.Put(bufp)
|
||||
|
||||
return ss.addrs[cs%uint32(len(ss.addrs))], nil
|
||||
}
|
105
vendor/github.com/labstack/echo/v4/CHANGELOG.md
generated
vendored
105
vendor/github.com/labstack/echo/v4/CHANGELOG.md
generated
vendored
@ -1,5 +1,110 @@
|
||||
# Changelog
|
||||
|
||||
## v4.12.0 - 2024-04-15
|
||||
|
||||
**Security**
|
||||
|
||||
* Update golang.org/x/net dep because of [GO-2024-2687](https://pkg.go.dev/vuln/GO-2024-2687) by @aldas in https://github.com/labstack/echo/pull/2625
|
||||
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* binder: make binding to Map work better with string destinations by @aldas in https://github.com/labstack/echo/pull/2554
|
||||
* README.md: add Encore as sponsor by @marcuskohlberg in https://github.com/labstack/echo/pull/2579
|
||||
* Reorder paragraphs in README.md by @aldas in https://github.com/labstack/echo/pull/2581
|
||||
* CI: upgrade actions/checkout to v4 by @aldas in https://github.com/labstack/echo/pull/2584
|
||||
* Remove default charset from 'application/json' Content-Type header by @doortts in https://github.com/labstack/echo/pull/2568
|
||||
* CI: Use Go 1.22 by @aldas in https://github.com/labstack/echo/pull/2588
|
||||
* binder: allow binding to a nil map by @georgmu in https://github.com/labstack/echo/pull/2574
|
||||
* Add Skipper Unit Test In BasicBasicAuthConfig and Add More Detail Explanation regarding BasicAuthValidator by @RyoKusnadi in https://github.com/labstack/echo/pull/2461
|
||||
* fix some typos by @teslaedison in https://github.com/labstack/echo/pull/2603
|
||||
* fix: some typos by @pomadev in https://github.com/labstack/echo/pull/2596
|
||||
* Allow ResponseWriters to unwrap writers when flushing/hijacking by @aldas in https://github.com/labstack/echo/pull/2595
|
||||
* Add SPDX licence comments to files. by @aldas in https://github.com/labstack/echo/pull/2604
|
||||
* Upgrade deps by @aldas in https://github.com/labstack/echo/pull/2605
|
||||
* Change type definition blocks to single declarations. This helps copy… by @aldas in https://github.com/labstack/echo/pull/2606
|
||||
* Fix Real IP logic by @cl-bvl in https://github.com/labstack/echo/pull/2550
|
||||
* Default binder can use `UnmarshalParams(params []string) error` inter… by @aldas in https://github.com/labstack/echo/pull/2607
|
||||
* Default binder can bind pointer to slice as struct field. For example `*[]string` by @aldas in https://github.com/labstack/echo/pull/2608
|
||||
* Remove maxparam dependence from Context by @aldas in https://github.com/labstack/echo/pull/2611
|
||||
* When route is registered with empty path it is normalized to `/`. by @aldas in https://github.com/labstack/echo/pull/2616
|
||||
* proxy middleware should use httputil.ReverseProxy for SSE requests by @aldas in https://github.com/labstack/echo/pull/2624
|
||||
|
||||
|
||||
## v4.11.4 - 2023-12-20
|
||||
|
||||
**Security**
|
||||
|
||||
* Upgrade golang.org/x/crypto to v0.17.0 to fix vulnerability [issue](https://pkg.go.dev/vuln/GO-2023-2402) [#2562](https://github.com/labstack/echo/pull/2562)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Update deps and mark Go version to 1.18 as this is what golang.org/x/* use [#2563](https://github.com/labstack/echo/pull/2563)
|
||||
* Request logger: add example for Slog https://pkg.go.dev/log/slog [#2543](https://github.com/labstack/echo/pull/2543)
|
||||
|
||||
|
||||
## v4.11.3 - 2023-11-07
|
||||
|
||||
**Security**
|
||||
|
||||
* 'c.Attachment' and 'c.Inline' should escape filename in 'Content-Disposition' header to avoid 'Reflect File Download' vulnerability. [#2541](https://github.com/labstack/echo/pull/2541)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Tests: refactor context tests to be separate functions [#2540](https://github.com/labstack/echo/pull/2540)
|
||||
* Proxy middleware: reuse echo request context [#2537](https://github.com/labstack/echo/pull/2537)
|
||||
* Mark unmarshallable yaml struct tags as ignored [#2536](https://github.com/labstack/echo/pull/2536)
|
||||
|
||||
|
||||
## v4.11.2 - 2023-10-11
|
||||
|
||||
**Security**
|
||||
|
||||
* Bump golang.org/x/net to prevent CVE-2023-39325 / CVE-2023-44487 HTTP/2 Rapid Reset Attack [#2527](https://github.com/labstack/echo/pull/2527)
|
||||
* fix(sec): randomString bias introduced by #2490 [#2492](https://github.com/labstack/echo/pull/2492)
|
||||
* CSRF/RequestID mw: switch math/random usage to crypto/random [#2490](https://github.com/labstack/echo/pull/2490)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Delete unused context in body_limit.go [#2483](https://github.com/labstack/echo/pull/2483)
|
||||
* Use Go 1.21 in CI [#2505](https://github.com/labstack/echo/pull/2505)
|
||||
* Fix some typos [#2511](https://github.com/labstack/echo/pull/2511)
|
||||
* Allow CORS middleware to send Access-Control-Max-Age: 0 [#2518](https://github.com/labstack/echo/pull/2518)
|
||||
* Bump dependancies [#2522](https://github.com/labstack/echo/pull/2522)
|
||||
|
||||
## v4.11.1 - 2023-07-16
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fix `Gzip` middleware not sending response code for no content responses (404, 301/302 redirects etc) [#2481](https://github.com/labstack/echo/pull/2481)
|
||||
|
||||
|
||||
## v4.11.0 - 2023-07-14
|
||||
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fixes the proxy middleware concurrency issue of calling the Next() proxy target on Round Robin Balancer [#2409](https://github.com/labstack/echo/pull/2409)
|
||||
* Fix `group.RouteNotFound` not working when group has attached middlewares [#2411](https://github.com/labstack/echo/pull/2411)
|
||||
* Fix global error handler return error message when message is an error [#2456](https://github.com/labstack/echo/pull/2456)
|
||||
* Do not use global timeNow variables [#2477](https://github.com/labstack/echo/pull/2477)
|
||||
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Added a optional config variable to disable centralized error handler in recovery middleware [#2410](https://github.com/labstack/echo/pull/2410)
|
||||
* refactor: use `strings.ReplaceAll` directly [#2424](https://github.com/labstack/echo/pull/2424)
|
||||
* Add support for Go1.20 `http.rwUnwrapper` to Response struct [#2425](https://github.com/labstack/echo/pull/2425)
|
||||
* Check whether is nil before invoking centralized error handling [#2429](https://github.com/labstack/echo/pull/2429)
|
||||
* Proper colon support in `echo.Reverse` method [#2416](https://github.com/labstack/echo/pull/2416)
|
||||
* Fix misuses of a vs an in documentation comments [#2436](https://github.com/labstack/echo/pull/2436)
|
||||
* Add link to slog.Handler library for Echo logging into README.md [#2444](https://github.com/labstack/echo/pull/2444)
|
||||
* In proxy middleware Support retries of failed proxy requests [#2414](https://github.com/labstack/echo/pull/2414)
|
||||
* gofmt fixes to comments [#2452](https://github.com/labstack/echo/pull/2452)
|
||||
* gzip response only if it exceeds a minimal length [#2267](https://github.com/labstack/echo/pull/2267)
|
||||
* Upgrade packages [#2475](https://github.com/labstack/echo/pull/2475)
|
||||
|
||||
|
||||
## v4.10.2 - 2023-02-22
|
||||
|
||||
**Security**
|
||||
|
4
vendor/github.com/labstack/echo/v4/Makefile
generated
vendored
4
vendor/github.com/labstack/echo/v4/Makefile
generated
vendored
@ -31,6 +31,6 @@ benchmark: ## Run benchmarks
|
||||
help: ## Display this help screen
|
||||
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
goversion ?= "1.17"
|
||||
test_version: ## Run tests inside Docker with given version (defaults to 1.17 oldest supported). Example: make test_version goversion=1.17
|
||||
goversion ?= "1.19"
|
||||
test_version: ## Run tests inside Docker with given version (defaults to 1.19 oldest supported). Example: make test_version goversion=1.19
|
||||
@docker run --rm -it -v $(shell pwd):/project golang:$(goversion) /bin/sh -c "cd /project && make init check"
|
||||
|
36
vendor/github.com/labstack/echo/v4/README.md
generated
vendored
36
vendor/github.com/labstack/echo/v4/README.md
generated
vendored
@ -3,26 +3,24 @@
|
||||
[![Sourcegraph](https://sourcegraph.com/github.com/labstack/echo/-/badge.svg?style=flat-square)](https://sourcegraph.com/github.com/labstack/echo?badge)
|
||||
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/labstack/echo/v4)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
|
||||
[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
|
||||
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/labstack/echo/echo.yml?style=flat-square)](https://github.com/labstack/echo/actions)
|
||||
[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
|
||||
[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions)
|
||||
[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
|
||||
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
|
||||
|
||||
## Supported Go versions
|
||||
## Echo
|
||||
|
||||
Latest version of Echo supports last four Go major [releases](https://go.dev/doc/devel/release) and might work with
|
||||
older versions.
|
||||
High performance, extensible, minimalist Go web framework.
|
||||
|
||||
As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
|
||||
Therefore a Go version capable of understanding /vN suffixed imports is required:
|
||||
* [Official website](https://echo.labstack.com)
|
||||
* [Quick start](https://echo.labstack.com/docs/quick-start)
|
||||
* [Middlewares](https://echo.labstack.com/docs/category/middleware)
|
||||
|
||||
Any of these versions will allow you to import Echo as `github.com/labstack/echo/v4` which is the recommended
|
||||
way of using Echo going forward.
|
||||
Help and questions: [Github Discussions](https://github.com/labstack/echo/discussions)
|
||||
|
||||
For older versions, please use the latest v3 tag.
|
||||
|
||||
## Feature Overview
|
||||
### Feature Overview
|
||||
|
||||
- Optimized HTTP router which smartly prioritize routes
|
||||
- Build robust and scalable RESTful APIs
|
||||
@ -38,6 +36,18 @@ For older versions, please use the latest v3 tag.
|
||||
- Automatic TLS via Let’s Encrypt
|
||||
- HTTP/2 support
|
||||
|
||||
## Sponsors
|
||||
|
||||
<div>
|
||||
<a href="https://encore.dev" style="display: inline-flex; align-items: center; gap: 10px">
|
||||
<img src="https://user-images.githubusercontent.com/78424526/214602214-52e0483a-b5fc-4d4c-b03e-0b7b23e012df.svg" height="28px" alt="encore icon"></img>
|
||||
<b>Encore – the platform for building Go-based cloud backends</b>
|
||||
</a>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
Click [here](https://github.com/sponsors/labstack) for more information on sponsorship.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Date: 2020/11/11<br>
|
||||
@ -57,6 +67,7 @@ The benchmarks above were run on an Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
|
||||
// go get github.com/labstack/echo/{version}
|
||||
go get github.com/labstack/echo/v4
|
||||
```
|
||||
Latest version of Echo supports last four Go major [releases](https://go.dev/doc/devel/release) and might work with older versions.
|
||||
|
||||
### Example
|
||||
|
||||
@ -110,16 +121,13 @@ of middlewares in this list.
|
||||
| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Automatically generate RESTful API documentation with [Swagger](https://swagger.io/) 2.0. |
|
||||
| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) logging library wrapper for Echo logger interface. |
|
||||
| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber´s [Zap](https://github.com/uber-go/zap) logging library wrapper for Echo logger interface. |
|
||||
| [github.com/samber/slog-echo](https://github.com/samber/slog-echo) | Go [slog](https://pkg.go.dev/golang.org/x/exp/slog) logging library wrapper for Echo logger interface. |
|
||||
| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache system based on [Souin](https://github.com/darkweak/souin) to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs. |
|
||||
| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Rapid, easy full-stack web development starter kit built with Echo. |
|
||||
| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | ProtoBuf generate Echo server side code |
|
||||
|
||||
Please send a PR to add your own library here.
|
||||
|
||||
## Help
|
||||
|
||||
- [Forum](https://github.com/labstack/echo/discussions)
|
||||
|
||||
## Contribute
|
||||
|
||||
**Use issues for everything**
|
||||
|
150
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
150
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
@ -11,23 +14,28 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// Binder is the interface that wraps the Bind method.
|
||||
Binder interface {
|
||||
Bind(i interface{}, c Context) error
|
||||
}
|
||||
// Binder is the interface that wraps the Bind method.
|
||||
type Binder interface {
|
||||
Bind(i interface{}, c Context) error
|
||||
}
|
||||
|
||||
// DefaultBinder is the default implementation of the Binder interface.
|
||||
DefaultBinder struct{}
|
||||
// DefaultBinder is the default implementation of the Binder interface.
|
||||
type DefaultBinder struct{}
|
||||
|
||||
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
||||
// Types that don't implement this, but do implement encoding.TextUnmarshaler
|
||||
// will use that interface instead.
|
||||
BindUnmarshaler interface {
|
||||
// UnmarshalParam decodes and assigns a value from an form or query param.
|
||||
UnmarshalParam(param string) error
|
||||
}
|
||||
)
|
||||
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
||||
// Types that don't implement this, but do implement encoding.TextUnmarshaler
|
||||
// will use that interface instead.
|
||||
type BindUnmarshaler interface {
|
||||
// UnmarshalParam decodes and assigns a value from an form or query param.
|
||||
UnmarshalParam(param string) error
|
||||
}
|
||||
|
||||
// bindMultipleUnmarshaler is used by binder to unmarshal multiple values from request at once to
|
||||
// type implementing this interface. For example request could have multiple query fields `?a=1&a=2&b=test` in that case
|
||||
// for `a` following slice `["1", "2"] will be passed to unmarshaller.
|
||||
type bindMultipleUnmarshaler interface {
|
||||
UnmarshalParams(params []string) error
|
||||
}
|
||||
|
||||
// BindPathParams binds path params to bindable object
|
||||
func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {
|
||||
@ -114,7 +122,7 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
|
||||
// Only bind query parameters for GET/DELETE/HEAD to avoid unexpected behavior with destination struct binding from body.
|
||||
// For example a request URL `&id=1&lang=en` with body `{"id":100,"lang":"de"}` would lead to precedence issues.
|
||||
// The HTTP method check restores pre-v4.1.11 behavior to avoid these problems (see issue #1670)
|
||||
method := c.Request().Method
|
||||
method := c.Request().Method
|
||||
if method == http.MethodGet || method == http.MethodDelete || method == http.MethodHead {
|
||||
if err = b.BindQueryParams(c, i); err != nil {
|
||||
return err
|
||||
@ -131,10 +139,29 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
||||
typ := reflect.TypeOf(destination).Elem()
|
||||
val := reflect.ValueOf(destination).Elem()
|
||||
|
||||
// Map
|
||||
if typ.Kind() == reflect.Map {
|
||||
// Support binding to limited Map destinations:
|
||||
// - map[string][]string,
|
||||
// - map[string]string <-- (binds first value from data slice)
|
||||
// - map[string]interface{}
|
||||
// You are better off binding to struct but there are user who want this map feature. Source of data for these cases are:
|
||||
// params,query,header,form as these sources produce string values, most of the time slice of strings, actually.
|
||||
if typ.Kind() == reflect.Map && typ.Key().Kind() == reflect.String {
|
||||
k := typ.Elem().Kind()
|
||||
isElemInterface := k == reflect.Interface
|
||||
isElemString := k == reflect.String
|
||||
isElemSliceOfStrings := k == reflect.Slice && typ.Elem().Elem().Kind() == reflect.String
|
||||
if !(isElemSliceOfStrings || isElemString || isElemInterface) {
|
||||
return nil
|
||||
}
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.MakeMap(typ))
|
||||
}
|
||||
for k, v := range data {
|
||||
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
|
||||
if isElemString {
|
||||
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
|
||||
} else {
|
||||
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -161,14 +188,14 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
||||
}
|
||||
structFieldKind := structField.Kind()
|
||||
inputFieldName := typeField.Tag.Get(tag)
|
||||
if typeField.Anonymous && structField.Kind() == reflect.Struct && inputFieldName != "" {
|
||||
if typeField.Anonymous && structFieldKind == reflect.Struct && inputFieldName != "" {
|
||||
// if anonymous struct with query/param/form tags, report an error
|
||||
return errors.New("query/param/form tags are not allowed with anonymous struct field")
|
||||
}
|
||||
|
||||
if inputFieldName == "" {
|
||||
// If tag is nil, we inspect if the field is a not BindUnmarshaler struct and try to bind data into it (might contains fields with tags).
|
||||
// structs that implement BindUnmarshaler are binded only when they have explicit tag
|
||||
// structs that implement BindUnmarshaler are bound only when they have explicit tag
|
||||
if _, ok := structField.Addr().Interface().(BindUnmarshaler); !ok && structFieldKind == reflect.Struct {
|
||||
if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
|
||||
return err
|
||||
@ -197,27 +224,46 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
||||
continue
|
||||
}
|
||||
|
||||
// Call this first, in case we're dealing with an alias to an array type
|
||||
if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
|
||||
// NOTE: algorithm here is not particularly sophisticated. It probably does not work with absurd types like `**[]*int`
|
||||
// but it is smart enough to handle niche cases like `*int`,`*[]string`,`[]*int` .
|
||||
|
||||
// try unmarshalling first, in case we're dealing with an alias to an array type
|
||||
if ok, err := unmarshalInputsToField(typeField.Type.Kind(), inputValue, structField); ok {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
numElems := len(inputValue)
|
||||
if structFieldKind == reflect.Slice && numElems > 0 {
|
||||
if ok, err := unmarshalInputToField(typeField.Type.Kind(), inputValue[0], structField); ok {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// we could be dealing with pointer to slice `*[]string` so dereference it. There are wierd OpenAPI generators
|
||||
// that could create struct fields like that.
|
||||
if structFieldKind == reflect.Pointer {
|
||||
structFieldKind = structField.Elem().Kind()
|
||||
structField = structField.Elem()
|
||||
}
|
||||
|
||||
if structFieldKind == reflect.Slice {
|
||||
sliceOf := structField.Type().Elem().Kind()
|
||||
numElems := len(inputValue)
|
||||
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
|
||||
for j := 0; j < numElems; j++ {
|
||||
if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
val.Field(i).Set(slice)
|
||||
} else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
|
||||
return err
|
||||
structField.Set(slice)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := setWithProperType(structFieldKind, inputValue[0], structField); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -225,7 +271,7 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
||||
|
||||
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
|
||||
// But also call it here, in case we're dealing with an array of BindUnmarshalers
|
||||
if ok, err := unmarshalField(valueKind, val, structField); ok {
|
||||
if ok, err := unmarshalInputToField(valueKind, val, structField); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -266,35 +312,41 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
|
||||
switch valueKind {
|
||||
case reflect.Ptr:
|
||||
return unmarshalFieldPtr(val, field)
|
||||
default:
|
||||
return unmarshalFieldNonPtr(val, field)
|
||||
func unmarshalInputsToField(valueKind reflect.Kind, values []string, field reflect.Value) (bool, error) {
|
||||
if valueKind == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
field.Set(reflect.New(field.Type().Elem()))
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
|
||||
fieldIValue := field.Addr().Interface()
|
||||
unmarshaler, ok := fieldIValue.(bindMultipleUnmarshaler)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
return true, unmarshaler.UnmarshalParams(values)
|
||||
}
|
||||
|
||||
func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
|
||||
fieldIValue := field.Addr().Interface()
|
||||
if unmarshaler, ok := fieldIValue.(BindUnmarshaler); ok {
|
||||
return true, unmarshaler.UnmarshalParam(value)
|
||||
func unmarshalInputToField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
|
||||
if valueKind == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
field.Set(reflect.New(field.Type().Elem()))
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
if unmarshaler, ok := fieldIValue.(encoding.TextUnmarshaler); ok {
|
||||
return true, unmarshaler.UnmarshalText([]byte(value))
|
||||
|
||||
fieldIValue := field.Addr().Interface()
|
||||
switch unmarshaler := fieldIValue.(type) {
|
||||
case BindUnmarshaler:
|
||||
return true, unmarshaler.UnmarshalParam(val)
|
||||
case encoding.TextUnmarshaler:
|
||||
return true, unmarshaler.UnmarshalText([]byte(val))
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
|
||||
if field.IsNil() {
|
||||
// Initialize the pointer to a nil value
|
||||
field.Set(reflect.New(field.Type().Elem()))
|
||||
}
|
||||
return unmarshalFieldNonPtr(value, field.Elem())
|
||||
}
|
||||
|
||||
func setIntField(value string, bitSize int, field reflect.Value) error {
|
||||
if value == "" {
|
||||
value = "0"
|
||||
|
21
vendor/github.com/labstack/echo/v4/binder.go
generated
vendored
21
vendor/github.com/labstack/echo/v4/binder.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
@ -1236,7 +1239,7 @@ func (b *ValueBinder) durations(sourceParam string, values []string, dest *[]tim
|
||||
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, false, time.Second)
|
||||
}
|
||||
@ -1247,7 +1250,7 @@ func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder
|
||||
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, true, time.Second)
|
||||
}
|
||||
@ -1257,7 +1260,7 @@ func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBi
|
||||
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, false, time.Millisecond)
|
||||
}
|
||||
@ -1268,7 +1271,7 @@ func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueB
|
||||
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, true, time.Millisecond)
|
||||
}
|
||||
@ -1280,8 +1283,8 @@ func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *Va
|
||||
// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
||||
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// - Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
||||
func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, false, time.Nanosecond)
|
||||
}
|
||||
@ -1294,8 +1297,8 @@ func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBi
|
||||
// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
||||
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// - Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
||||
func (b *ValueBinder) MustUnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, true, time.Nanosecond)
|
||||
}
|
||||
@ -1323,7 +1326,7 @@ func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExi
|
||||
case time.Second:
|
||||
*dest = time.Unix(n, 0)
|
||||
case time.Millisecond:
|
||||
*dest = time.Unix(n/1e3, (n%1e3)*1e6) // TODO: time.UnixMilli(n) exists since Go1.17 switch to that when min version allows
|
||||
*dest = time.UnixMilli(n)
|
||||
case time.Nanosecond:
|
||||
*dest = time.Unix(0, n)
|
||||
}
|
||||
|
325
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
325
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
@ -13,204 +16,216 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
// Context represents the context of the current HTTP request. It holds request and
|
||||
// response objects, path, path parameters, data and registered handler.
|
||||
Context interface {
|
||||
// Request returns `*http.Request`.
|
||||
Request() *http.Request
|
||||
// Context represents the context of the current HTTP request. It holds request and
|
||||
// response objects, path, path parameters, data and registered handler.
|
||||
type Context interface {
|
||||
// Request returns `*http.Request`.
|
||||
Request() *http.Request
|
||||
|
||||
// SetRequest sets `*http.Request`.
|
||||
SetRequest(r *http.Request)
|
||||
// SetRequest sets `*http.Request`.
|
||||
SetRequest(r *http.Request)
|
||||
|
||||
// SetResponse sets `*Response`.
|
||||
SetResponse(r *Response)
|
||||
// SetResponse sets `*Response`.
|
||||
SetResponse(r *Response)
|
||||
|
||||
// Response returns `*Response`.
|
||||
Response() *Response
|
||||
// Response returns `*Response`.
|
||||
Response() *Response
|
||||
|
||||
// IsTLS returns true if HTTP connection is TLS otherwise false.
|
||||
IsTLS() bool
|
||||
// IsTLS returns true if HTTP connection is TLS otherwise false.
|
||||
IsTLS() bool
|
||||
|
||||
// IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
|
||||
IsWebSocket() bool
|
||||
// IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
|
||||
IsWebSocket() bool
|
||||
|
||||
// Scheme returns the HTTP protocol scheme, `http` or `https`.
|
||||
Scheme() string
|
||||
// Scheme returns the HTTP protocol scheme, `http` or `https`.
|
||||
Scheme() string
|
||||
|
||||
// RealIP returns the client's network address based on `X-Forwarded-For`
|
||||
// or `X-Real-IP` request header.
|
||||
// The behavior can be configured using `Echo#IPExtractor`.
|
||||
RealIP() string
|
||||
// RealIP returns the client's network address based on `X-Forwarded-For`
|
||||
// or `X-Real-IP` request header.
|
||||
// The behavior can be configured using `Echo#IPExtractor`.
|
||||
RealIP() string
|
||||
|
||||
// Path returns the registered path for the handler.
|
||||
Path() string
|
||||
// Path returns the registered path for the handler.
|
||||
Path() string
|
||||
|
||||
// SetPath sets the registered path for the handler.
|
||||
SetPath(p string)
|
||||
// SetPath sets the registered path for the handler.
|
||||
SetPath(p string)
|
||||
|
||||
// Param returns path parameter by name.
|
||||
Param(name string) string
|
||||
// Param returns path parameter by name.
|
||||
Param(name string) string
|
||||
|
||||
// ParamNames returns path parameter names.
|
||||
ParamNames() []string
|
||||
// ParamNames returns path parameter names.
|
||||
ParamNames() []string
|
||||
|
||||
// SetParamNames sets path parameter names.
|
||||
SetParamNames(names ...string)
|
||||
// SetParamNames sets path parameter names.
|
||||
SetParamNames(names ...string)
|
||||
|
||||
// ParamValues returns path parameter values.
|
||||
ParamValues() []string
|
||||
// ParamValues returns path parameter values.
|
||||
ParamValues() []string
|
||||
|
||||
// SetParamValues sets path parameter values.
|
||||
SetParamValues(values ...string)
|
||||
// SetParamValues sets path parameter values.
|
||||
SetParamValues(values ...string)
|
||||
|
||||
// QueryParam returns the query param for the provided name.
|
||||
QueryParam(name string) string
|
||||
// QueryParam returns the query param for the provided name.
|
||||
QueryParam(name string) string
|
||||
|
||||
// QueryParams returns the query parameters as `url.Values`.
|
||||
QueryParams() url.Values
|
||||
// QueryParams returns the query parameters as `url.Values`.
|
||||
QueryParams() url.Values
|
||||
|
||||
// QueryString returns the URL query string.
|
||||
QueryString() string
|
||||
// QueryString returns the URL query string.
|
||||
QueryString() string
|
||||
|
||||
// FormValue returns the form field value for the provided name.
|
||||
FormValue(name string) string
|
||||
// FormValue returns the form field value for the provided name.
|
||||
FormValue(name string) string
|
||||
|
||||
// FormParams returns the form parameters as `url.Values`.
|
||||
FormParams() (url.Values, error)
|
||||
// FormParams returns the form parameters as `url.Values`.
|
||||
FormParams() (url.Values, error)
|
||||
|
||||
// FormFile returns the multipart form file for the provided name.
|
||||
FormFile(name string) (*multipart.FileHeader, error)
|
||||
// FormFile returns the multipart form file for the provided name.
|
||||
FormFile(name string) (*multipart.FileHeader, error)
|
||||
|
||||
// MultipartForm returns the multipart form.
|
||||
MultipartForm() (*multipart.Form, error)
|
||||
// MultipartForm returns the multipart form.
|
||||
MultipartForm() (*multipart.Form, error)
|
||||
|
||||
// Cookie returns the named cookie provided in the request.
|
||||
Cookie(name string) (*http.Cookie, error)
|
||||
// Cookie returns the named cookie provided in the request.
|
||||
Cookie(name string) (*http.Cookie, error)
|
||||
|
||||
// SetCookie adds a `Set-Cookie` header in HTTP response.
|
||||
SetCookie(cookie *http.Cookie)
|
||||
// SetCookie adds a `Set-Cookie` header in HTTP response.
|
||||
SetCookie(cookie *http.Cookie)
|
||||
|
||||
// Cookies returns the HTTP cookies sent with the request.
|
||||
Cookies() []*http.Cookie
|
||||
// Cookies returns the HTTP cookies sent with the request.
|
||||
Cookies() []*http.Cookie
|
||||
|
||||
// Get retrieves data from the context.
|
||||
Get(key string) interface{}
|
||||
// Get retrieves data from the context.
|
||||
Get(key string) interface{}
|
||||
|
||||
// Set saves data in the context.
|
||||
Set(key string, val interface{})
|
||||
// Set saves data in the context.
|
||||
Set(key string, val interface{})
|
||||
|
||||
// Bind binds the request body into provided type `i`. The default binder
|
||||
// does it based on Content-Type header.
|
||||
Bind(i interface{}) error
|
||||
// Bind binds path params, query params and the request body into provided type `i`. The default binder
|
||||
// binds body based on Content-Type header.
|
||||
Bind(i interface{}) error
|
||||
|
||||
// Validate validates provided `i`. It is usually called after `Context#Bind()`.
|
||||
// Validator must be registered using `Echo#Validator`.
|
||||
Validate(i interface{}) error
|
||||
// Validate validates provided `i`. It is usually called after `Context#Bind()`.
|
||||
// Validator must be registered using `Echo#Validator`.
|
||||
Validate(i interface{}) error
|
||||
|
||||
// Render renders a template with data and sends a text/html response with status
|
||||
// code. Renderer must be registered using `Echo.Renderer`.
|
||||
Render(code int, name string, data interface{}) error
|
||||
// Render renders a template with data and sends a text/html response with status
|
||||
// code. Renderer must be registered using `Echo.Renderer`.
|
||||
Render(code int, name string, data interface{}) error
|
||||
|
||||
// HTML sends an HTTP response with status code.
|
||||
HTML(code int, html string) error
|
||||
// HTML sends an HTTP response with status code.
|
||||
HTML(code int, html string) error
|
||||
|
||||
// HTMLBlob sends an HTTP blob response with status code.
|
||||
HTMLBlob(code int, b []byte) error
|
||||
// HTMLBlob sends an HTTP blob response with status code.
|
||||
HTMLBlob(code int, b []byte) error
|
||||
|
||||
// String sends a string response with status code.
|
||||
String(code int, s string) error
|
||||
// String sends a string response with status code.
|
||||
String(code int, s string) error
|
||||
|
||||
// JSON sends a JSON response with status code.
|
||||
JSON(code int, i interface{}) error
|
||||
// JSON sends a JSON response with status code.
|
||||
JSON(code int, i interface{}) error
|
||||
|
||||
// JSONPretty sends a pretty-print JSON with status code.
|
||||
JSONPretty(code int, i interface{}, indent string) error
|
||||
// JSONPretty sends a pretty-print JSON with status code.
|
||||
JSONPretty(code int, i interface{}, indent string) error
|
||||
|
||||
// JSONBlob sends a JSON blob response with status code.
|
||||
JSONBlob(code int, b []byte) error
|
||||
// JSONBlob sends a JSON blob response with status code.
|
||||
JSONBlob(code int, b []byte) error
|
||||
|
||||
// JSONP sends a JSONP response with status code. It uses `callback` to construct
|
||||
// the JSONP payload.
|
||||
JSONP(code int, callback string, i interface{}) error
|
||||
// JSONP sends a JSONP response with status code. It uses `callback` to construct
|
||||
// the JSONP payload.
|
||||
JSONP(code int, callback string, i interface{}) error
|
||||
|
||||
// JSONPBlob sends a JSONP blob response with status code. It uses `callback`
|
||||
// to construct the JSONP payload.
|
||||
JSONPBlob(code int, callback string, b []byte) error
|
||||
// JSONPBlob sends a JSONP blob response with status code. It uses `callback`
|
||||
// to construct the JSONP payload.
|
||||
JSONPBlob(code int, callback string, b []byte) error
|
||||
|
||||
// XML sends an XML response with status code.
|
||||
XML(code int, i interface{}) error
|
||||
// XML sends an XML response with status code.
|
||||
XML(code int, i interface{}) error
|
||||
|
||||
// XMLPretty sends a pretty-print XML with status code.
|
||||
XMLPretty(code int, i interface{}, indent string) error
|
||||
// XMLPretty sends a pretty-print XML with status code.
|
||||
XMLPretty(code int, i interface{}, indent string) error
|
||||
|
||||
// XMLBlob sends an XML blob response with status code.
|
||||
XMLBlob(code int, b []byte) error
|
||||
// XMLBlob sends an XML blob response with status code.
|
||||
XMLBlob(code int, b []byte) error
|
||||
|
||||
// Blob sends a blob response with status code and content type.
|
||||
Blob(code int, contentType string, b []byte) error
|
||||
// Blob sends a blob response with status code and content type.
|
||||
Blob(code int, contentType string, b []byte) error
|
||||
|
||||
// Stream sends a streaming response with status code and content type.
|
||||
Stream(code int, contentType string, r io.Reader) error
|
||||
// Stream sends a streaming response with status code and content type.
|
||||
Stream(code int, contentType string, r io.Reader) error
|
||||
|
||||
// File sends a response with the content of the file.
|
||||
File(file string) error
|
||||
// File sends a response with the content of the file.
|
||||
File(file string) error
|
||||
|
||||
// Attachment sends a response as attachment, prompting client to save the
|
||||
// file.
|
||||
Attachment(file string, name string) error
|
||||
// Attachment sends a response as attachment, prompting client to save the
|
||||
// file.
|
||||
Attachment(file string, name string) error
|
||||
|
||||
// Inline sends a response as inline, opening the file in the browser.
|
||||
Inline(file string, name string) error
|
||||
// Inline sends a response as inline, opening the file in the browser.
|
||||
Inline(file string, name string) error
|
||||
|
||||
// NoContent sends a response with no body and a status code.
|
||||
NoContent(code int) error
|
||||
// NoContent sends a response with no body and a status code.
|
||||
NoContent(code int) error
|
||||
|
||||
// Redirect redirects the request to a provided URL with status code.
|
||||
Redirect(code int, url string) error
|
||||
// Redirect redirects the request to a provided URL with status code.
|
||||
Redirect(code int, url string) error
|
||||
|
||||
// Error invokes the registered global HTTP error handler. Generally used by middleware.
|
||||
// A side-effect of calling global error handler is that now Response has been committed (sent to the client) and
|
||||
// middlewares up in chain can not change Response status code or Response body anymore.
|
||||
//
|
||||
// Avoid using this method in handlers as no middleware will be able to effectively handle errors after that.
|
||||
Error(err error)
|
||||
// Error invokes the registered global HTTP error handler. Generally used by middleware.
|
||||
// A side-effect of calling global error handler is that now Response has been committed (sent to the client) and
|
||||
// middlewares up in chain can not change Response status code or Response body anymore.
|
||||
//
|
||||
// Avoid using this method in handlers as no middleware will be able to effectively handle errors after that.
|
||||
Error(err error)
|
||||
|
||||
// Handler returns the matched handler by router.
|
||||
Handler() HandlerFunc
|
||||
// Handler returns the matched handler by router.
|
||||
Handler() HandlerFunc
|
||||
|
||||
// SetHandler sets the matched handler by router.
|
||||
SetHandler(h HandlerFunc)
|
||||
// SetHandler sets the matched handler by router.
|
||||
SetHandler(h HandlerFunc)
|
||||
|
||||
// Logger returns the `Logger` instance.
|
||||
Logger() Logger
|
||||
// Logger returns the `Logger` instance.
|
||||
Logger() Logger
|
||||
|
||||
// SetLogger Set the logger
|
||||
SetLogger(l Logger)
|
||||
// SetLogger Set the logger
|
||||
SetLogger(l Logger)
|
||||
|
||||
// Echo returns the `Echo` instance.
|
||||
Echo() *Echo
|
||||
// Echo returns the `Echo` instance.
|
||||
Echo() *Echo
|
||||
|
||||
// Reset resets the context after request completes. It must be called along
|
||||
// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
|
||||
// See `Echo#ServeHTTP()`
|
||||
Reset(r *http.Request, w http.ResponseWriter)
|
||||
}
|
||||
// Reset resets the context after request completes. It must be called along
|
||||
// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
|
||||
// See `Echo#ServeHTTP()`
|
||||
Reset(r *http.Request, w http.ResponseWriter)
|
||||
}
|
||||
|
||||
context struct {
|
||||
request *http.Request
|
||||
response *Response
|
||||
path string
|
||||
pnames []string
|
||||
pvalues []string
|
||||
query url.Values
|
||||
handler HandlerFunc
|
||||
store Map
|
||||
echo *Echo
|
||||
logger Logger
|
||||
lock sync.RWMutex
|
||||
}
|
||||
)
|
||||
type context struct {
|
||||
request *http.Request
|
||||
response *Response
|
||||
query url.Values
|
||||
echo *Echo
|
||||
logger Logger
|
||||
|
||||
store Map
|
||||
lock sync.RWMutex
|
||||
|
||||
// following fields are set by Router
|
||||
|
||||
// path is route path that Router matched. It is empty string where there is no route match.
|
||||
// Route registered with RouteNotFound is considered as a match and path therefore is not empty.
|
||||
path string
|
||||
|
||||
// pnames length is tied to param count for the matched route
|
||||
pnames []string
|
||||
|
||||
// Usually echo.Echo is sizing pvalues but there could be user created middlewares that decide to
|
||||
// overwrite parameter by calling SetParamNames + SetParamValues.
|
||||
// When echo.Echo allocated that slice it length/capacity is tied to echo.Echo.maxParam value.
|
||||
//
|
||||
// It is important that pvalues size is always equal or bigger to pnames length.
|
||||
pvalues []string
|
||||
handler HandlerFunc
|
||||
}
|
||||
|
||||
const (
|
||||
// ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain.
|
||||
@ -329,13 +344,9 @@ func (c *context) SetParamNames(names ...string) {
|
||||
c.pnames = names
|
||||
|
||||
l := len(names)
|
||||
if *c.echo.maxParam < l {
|
||||
*c.echo.maxParam = l
|
||||
}
|
||||
|
||||
if len(c.pvalues) < l {
|
||||
// Keeping the old pvalues just for backward compatibility, but it sounds that doesn't make sense to keep them,
|
||||
// probably those values will be overriden in a Context#SetParamValues
|
||||
// probably those values will be overridden in a Context#SetParamValues
|
||||
newPvalues := make([]string, l)
|
||||
copy(newPvalues, c.pvalues)
|
||||
c.pvalues = newPvalues
|
||||
@ -347,11 +358,11 @@ func (c *context) ParamValues() []string {
|
||||
}
|
||||
|
||||
func (c *context) SetParamValues(values ...string) {
|
||||
// NOTE: Don't just set c.pvalues = values, because it has to have length c.echo.maxParam at all times
|
||||
// NOTE: Don't just set c.pvalues = values, because it has to have length c.echo.maxParam (or bigger) at all times
|
||||
// It will brake the Router#Find code
|
||||
limit := len(values)
|
||||
if limit > *c.echo.maxParam {
|
||||
limit = *c.echo.maxParam
|
||||
if limit > len(c.pvalues) {
|
||||
c.pvalues = make([]string, limit)
|
||||
}
|
||||
for i := 0; i < limit; i++ {
|
||||
c.pvalues[i] = values[i]
|
||||
@ -489,7 +500,7 @@ func (c *context) jsonPBlob(code int, callback string, i interface{}) (err error
|
||||
}
|
||||
|
||||
func (c *context) json(code int, i interface{}, indent string) error {
|
||||
c.writeContentType(MIMEApplicationJSONCharsetUTF8)
|
||||
c.writeContentType(MIMEApplicationJSON)
|
||||
c.response.Status = code
|
||||
return c.echo.JSONSerializer.Serialize(c, i, indent)
|
||||
}
|
||||
@ -507,7 +518,7 @@ func (c *context) JSONPretty(code int, i interface{}, indent string) (err error)
|
||||
}
|
||||
|
||||
func (c *context) JSONBlob(code int, b []byte) (err error) {
|
||||
return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
|
||||
return c.Blob(code, MIMEApplicationJSON, b)
|
||||
}
|
||||
|
||||
func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
|
||||
@ -584,8 +595,10 @@ func (c *context) Inline(file, name string) error {
|
||||
return c.contentDisposition(file, name, "inline")
|
||||
}
|
||||
|
||||
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
func (c *context) contentDisposition(file, name, dispositionType string) error {
|
||||
c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
|
||||
c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf(`%s; filename="%s"`, dispositionType, quoteEscaper.Replace(name)))
|
||||
return c.File(file)
|
||||
}
|
||||
|
||||
@ -640,8 +653,8 @@ func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
|
||||
c.path = ""
|
||||
c.pnames = nil
|
||||
c.logger = nil
|
||||
// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
|
||||
for i := 0; i < *c.echo.maxParam; i++ {
|
||||
// NOTE: Don't reset because it has to have length c.echo.maxParam (or bigger) at all times
|
||||
for i := 0; i < len(c.pvalues); i++ {
|
||||
c.pvalues[i] = ""
|
||||
}
|
||||
}
|
||||
|
3
vendor/github.com/labstack/echo/v4/context_fs.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/context_fs.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
|
236
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
236
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
/*
|
||||
Package echo implements high performance, minimalist Go web framework.
|
||||
|
||||
@ -39,6 +42,7 @@ package echo
|
||||
import (
|
||||
stdContext "context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -59,97 +63,95 @@ import (
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
type (
|
||||
// Echo is the top-level framework instance.
|
||||
//
|
||||
// Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these
|
||||
// fields from handlers/middlewares and changing field values at the same time leads to data-races.
|
||||
// Adding new routes after the server has been started is also not safe!
|
||||
Echo struct {
|
||||
filesystem
|
||||
common
|
||||
// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
|
||||
// listener address info (on which interface/port was listener binded) without having data races.
|
||||
startupMutex sync.RWMutex
|
||||
colorer *color.Color
|
||||
// Echo is the top-level framework instance.
|
||||
//
|
||||
// Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these
|
||||
// fields from handlers/middlewares and changing field values at the same time leads to data-races.
|
||||
// Adding new routes after the server has been started is also not safe!
|
||||
type Echo struct {
|
||||
filesystem
|
||||
common
|
||||
// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
|
||||
// listener address info (on which interface/port was listener bound) without having data races.
|
||||
startupMutex sync.RWMutex
|
||||
colorer *color.Color
|
||||
|
||||
// premiddleware are middlewares that are run before routing is done. In case a pre-middleware returns
|
||||
// an error the router is not executed and the request will end up in the global error handler.
|
||||
premiddleware []MiddlewareFunc
|
||||
middleware []MiddlewareFunc
|
||||
maxParam *int
|
||||
router *Router
|
||||
routers map[string]*Router
|
||||
pool sync.Pool
|
||||
// premiddleware are middlewares that are run before routing is done. In case a pre-middleware returns
|
||||
// an error the router is not executed and the request will end up in the global error handler.
|
||||
premiddleware []MiddlewareFunc
|
||||
middleware []MiddlewareFunc
|
||||
maxParam *int
|
||||
router *Router
|
||||
routers map[string]*Router
|
||||
pool sync.Pool
|
||||
|
||||
StdLogger *stdLog.Logger
|
||||
Server *http.Server
|
||||
TLSServer *http.Server
|
||||
Listener net.Listener
|
||||
TLSListener net.Listener
|
||||
AutoTLSManager autocert.Manager
|
||||
DisableHTTP2 bool
|
||||
Debug bool
|
||||
HideBanner bool
|
||||
HidePort bool
|
||||
HTTPErrorHandler HTTPErrorHandler
|
||||
Binder Binder
|
||||
JSONSerializer JSONSerializer
|
||||
Validator Validator
|
||||
Renderer Renderer
|
||||
Logger Logger
|
||||
IPExtractor IPExtractor
|
||||
ListenerNetwork string
|
||||
StdLogger *stdLog.Logger
|
||||
Server *http.Server
|
||||
TLSServer *http.Server
|
||||
Listener net.Listener
|
||||
TLSListener net.Listener
|
||||
AutoTLSManager autocert.Manager
|
||||
DisableHTTP2 bool
|
||||
Debug bool
|
||||
HideBanner bool
|
||||
HidePort bool
|
||||
HTTPErrorHandler HTTPErrorHandler
|
||||
Binder Binder
|
||||
JSONSerializer JSONSerializer
|
||||
Validator Validator
|
||||
Renderer Renderer
|
||||
Logger Logger
|
||||
IPExtractor IPExtractor
|
||||
ListenerNetwork string
|
||||
|
||||
// OnAddRouteHandler is called when Echo adds new route to specific host router.
|
||||
OnAddRouteHandler func(host string, route Route, handler HandlerFunc, middleware []MiddlewareFunc)
|
||||
}
|
||||
// OnAddRouteHandler is called when Echo adds new route to specific host router.
|
||||
OnAddRouteHandler func(host string, route Route, handler HandlerFunc, middleware []MiddlewareFunc)
|
||||
}
|
||||
|
||||
// Route contains a handler and information for matching against requests.
|
||||
Route struct {
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
// Route contains a handler and information for matching against requests.
|
||||
type Route struct {
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// HTTPError represents an error that occurred while handling a request.
|
||||
HTTPError struct {
|
||||
Code int `json:"-"`
|
||||
Message interface{} `json:"message"`
|
||||
Internal error `json:"-"` // Stores the error returned by an external dependency
|
||||
}
|
||||
// HTTPError represents an error that occurred while handling a request.
|
||||
type HTTPError struct {
|
||||
Code int `json:"-"`
|
||||
Message interface{} `json:"message"`
|
||||
Internal error `json:"-"` // Stores the error returned by an external dependency
|
||||
}
|
||||
|
||||
// MiddlewareFunc defines a function to process middleware.
|
||||
MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
||||
// MiddlewareFunc defines a function to process middleware.
|
||||
type MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
||||
|
||||
// HandlerFunc defines a function to serve HTTP requests.
|
||||
HandlerFunc func(c Context) error
|
||||
// HandlerFunc defines a function to serve HTTP requests.
|
||||
type HandlerFunc func(c Context) error
|
||||
|
||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
||||
HTTPErrorHandler func(err error, c Context)
|
||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
||||
type HTTPErrorHandler func(err error, c Context)
|
||||
|
||||
// Validator is the interface that wraps the Validate function.
|
||||
Validator interface {
|
||||
Validate(i interface{}) error
|
||||
}
|
||||
// Validator is the interface that wraps the Validate function.
|
||||
type Validator interface {
|
||||
Validate(i interface{}) error
|
||||
}
|
||||
|
||||
// JSONSerializer is the interface that encodes and decodes JSON to and from interfaces.
|
||||
JSONSerializer interface {
|
||||
Serialize(c Context, i interface{}, indent string) error
|
||||
Deserialize(c Context, i interface{}) error
|
||||
}
|
||||
// JSONSerializer is the interface that encodes and decodes JSON to and from interfaces.
|
||||
type JSONSerializer interface {
|
||||
Serialize(c Context, i interface{}, indent string) error
|
||||
Deserialize(c Context, i interface{}) error
|
||||
}
|
||||
|
||||
// Renderer is the interface that wraps the Render function.
|
||||
Renderer interface {
|
||||
Render(io.Writer, string, interface{}, Context) error
|
||||
}
|
||||
// Renderer is the interface that wraps the Render function.
|
||||
type Renderer interface {
|
||||
Render(io.Writer, string, interface{}, Context) error
|
||||
}
|
||||
|
||||
// Map defines a generic map of type `map[string]interface{}`.
|
||||
Map map[string]interface{}
|
||||
// Map defines a generic map of type `map[string]interface{}`.
|
||||
type Map map[string]interface{}
|
||||
|
||||
// Common struct for Echo & Group.
|
||||
common struct{}
|
||||
)
|
||||
// Common struct for Echo & Group.
|
||||
type common struct{}
|
||||
|
||||
// HTTP methods
|
||||
// NOTE: Deprecated, please use the stdlib constants directly instead.
|
||||
@ -168,7 +170,12 @@ const (
|
||||
|
||||
// MIME types
|
||||
const (
|
||||
MIMEApplicationJSON = "application/json"
|
||||
// MIMEApplicationJSON JavaScript Object Notation (JSON) https://www.rfc-editor.org/rfc/rfc8259
|
||||
MIMEApplicationJSON = "application/json"
|
||||
// Deprecated: Please use MIMEApplicationJSON instead. JSON should be encoded using UTF-8 by default.
|
||||
// No "charset" parameter is defined for this registration.
|
||||
// Adding one really has no effect on compliant recipients.
|
||||
// See RFC 8259, section 8.1. https://datatracker.ietf.org/doc/html/rfc8259#section-8.1
|
||||
MIMEApplicationJSONCharsetUTF8 = MIMEApplicationJSON + "; " + charsetUTF8
|
||||
MIMEApplicationJavaScript = "application/javascript"
|
||||
MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
|
||||
@ -258,7 +265,7 @@ const (
|
||||
|
||||
const (
|
||||
// Version of Echo
|
||||
Version = "4.10.2"
|
||||
Version = "4.12.0"
|
||||
website = "https://echo.labstack.com"
|
||||
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
||||
banner = `
|
||||
@ -273,21 +280,19 @@ ____________________________________O/_______
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
methods = [...]string{
|
||||
http.MethodConnect,
|
||||
http.MethodDelete,
|
||||
http.MethodGet,
|
||||
http.MethodHead,
|
||||
http.MethodOptions,
|
||||
http.MethodPatch,
|
||||
http.MethodPost,
|
||||
PROPFIND,
|
||||
http.MethodPut,
|
||||
http.MethodTrace,
|
||||
REPORT,
|
||||
}
|
||||
)
|
||||
var methods = [...]string{
|
||||
http.MethodConnect,
|
||||
http.MethodDelete,
|
||||
http.MethodGet,
|
||||
http.MethodHead,
|
||||
http.MethodOptions,
|
||||
http.MethodPatch,
|
||||
http.MethodPost,
|
||||
PROPFIND,
|
||||
http.MethodPut,
|
||||
http.MethodTrace,
|
||||
REPORT,
|
||||
}
|
||||
|
||||
// Errors
|
||||
var (
|
||||
@ -340,22 +345,23 @@ var (
|
||||
ErrInvalidListenerNetwork = errors.New("invalid listener network")
|
||||
)
|
||||
|
||||
// Error handlers
|
||||
var (
|
||||
NotFoundHandler = func(c Context) error {
|
||||
return ErrNotFound
|
||||
}
|
||||
// NotFoundHandler is the handler that router uses in case there was no matching route found. Returns an error that results
|
||||
// HTTP 404 status code.
|
||||
var NotFoundHandler = func(c Context) error {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
MethodNotAllowedHandler = func(c Context) error {
|
||||
// See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed)
|
||||
// response and MAY do so in any other response. For disabled resources an empty Allow header may be returned
|
||||
routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
|
||||
if ok && routerAllowMethods != "" {
|
||||
c.Response().Header().Set(HeaderAllow, routerAllowMethods)
|
||||
}
|
||||
return ErrMethodNotAllowed
|
||||
// MethodNotAllowedHandler is the handler thar router uses in case there was no matching route found but there was
|
||||
// another matching routes for that requested URL. Returns an error that results HTTP 405 Method Not Allowed status code.
|
||||
var MethodNotAllowedHandler = func(c Context) error {
|
||||
// See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed)
|
||||
// response and MAY do so in any other response. For disabled resources an empty Allow header may be returned
|
||||
routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
|
||||
if ok && routerAllowMethods != "" {
|
||||
c.Response().Header().Set(HeaderAllow, routerAllowMethods)
|
||||
}
|
||||
)
|
||||
return ErrMethodNotAllowed
|
||||
}
|
||||
|
||||
// New creates an instance of Echo.
|
||||
func New() (e *Echo) {
|
||||
@ -413,7 +419,7 @@ func (e *Echo) Routers() map[string]*Router {
|
||||
//
|
||||
// NOTE: In case errors happens in middleware call-chain that is returning from handler (which did not return an error).
|
||||
// When handler has already sent response (ala c.JSON()) and there is error in middleware that is returning from
|
||||
// handler. Then the error that global error handler received will be ignored because we have already "commited" the
|
||||
// handler. Then the error that global error handler received will be ignored because we have already "committed" the
|
||||
// response and status code header has been sent to the client.
|
||||
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||
|
||||
@ -438,12 +444,18 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||
// Issue #1426
|
||||
code := he.Code
|
||||
message := he.Message
|
||||
if m, ok := he.Message.(string); ok {
|
||||
|
||||
switch m := he.Message.(type) {
|
||||
case string:
|
||||
if e.Debug {
|
||||
message = Map{"message": m, "error": err.Error()}
|
||||
} else {
|
||||
message = Map{"message": m}
|
||||
}
|
||||
case json.Marshaler:
|
||||
// do nothing - this type knows how to format itself to JSON
|
||||
case error:
|
||||
message = Map{"message": m.Error()}
|
||||
}
|
||||
|
||||
// Send response
|
||||
@ -614,7 +626,7 @@ func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
|
||||
return e.URI(h, params...)
|
||||
}
|
||||
|
||||
// Reverse generates an URL from route name and provided parameters.
|
||||
// Reverse generates a URL from route name and provided parameters.
|
||||
func (e *Echo) Reverse(name string, params ...interface{}) string {
|
||||
return e.router.Reverse(name, params...)
|
||||
}
|
||||
|
3
vendor/github.com/labstack/echo/v4/echo_fs.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/echo_fs.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
|
35
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
35
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
@ -1,21 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// Group is a set of sub-routes for a specified route. It can be used for inner
|
||||
// routes that share a common middleware or functionality that should be separate
|
||||
// from the parent echo instance while still inheriting from it.
|
||||
Group struct {
|
||||
common
|
||||
host string
|
||||
prefix string
|
||||
middleware []MiddlewareFunc
|
||||
echo *Echo
|
||||
}
|
||||
)
|
||||
// Group is a set of sub-routes for a specified route. It can be used for inner
|
||||
// routes that share a common middleware or functionality that should be separate
|
||||
// from the parent echo instance while still inheriting from it.
|
||||
type Group struct {
|
||||
common
|
||||
host string
|
||||
prefix string
|
||||
middleware []MiddlewareFunc
|
||||
echo *Echo
|
||||
}
|
||||
|
||||
// Use implements `Echo#Use()` for sub-routes within the Group.
|
||||
func (g *Group) Use(middleware ...MiddlewareFunc) {
|
||||
@ -23,10 +24,12 @@ func (g *Group) Use(middleware ...MiddlewareFunc) {
|
||||
if len(g.middleware) == 0 {
|
||||
return
|
||||
}
|
||||
// Allow all requests to reach the group as they might get dropped if router
|
||||
// doesn't find a match, making none of the group middleware process.
|
||||
g.Any("", NotFoundHandler)
|
||||
g.Any("/*", NotFoundHandler)
|
||||
// group level middlewares are different from Echo `Pre` and `Use` middlewares (those are global). Group level middlewares
|
||||
// are only executed if they are added to the Router with route.
|
||||
// So we register catch all route (404 is a safe way to emulate route match) for this group and now during routing the
|
||||
// Router would find route to match our request path and therefore guarantee the middleware(s) will get executed.
|
||||
g.RouteNotFound("", NotFoundHandler)
|
||||
g.RouteNotFound("/*", NotFoundHandler)
|
||||
}
|
||||
|
||||
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
|
||||
|
3
vendor/github.com/labstack/echo/v4/group_fs.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/group_fs.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
|
17
vendor/github.com/labstack/echo/v4/ip.go
generated
vendored
17
vendor/github.com/labstack/echo/v4/ip.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
@ -64,7 +67,7 @@ XFF: "x" "x, a" "x, a, b"
|
||||
```
|
||||
|
||||
In this case, use **first _untrustable_ IP reading from right**. Never use first one reading from left, as it is
|
||||
configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructre".
|
||||
configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructure".
|
||||
In above example, if `b` and `c` are trustable, the IP address of the client is `a` for both cases, never be `x`.
|
||||
|
||||
In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`.
|
||||
@ -225,15 +228,21 @@ func extractIP(req *http.Request) string {
|
||||
func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
|
||||
checker := newIPChecker(options)
|
||||
return func(req *http.Request) string {
|
||||
directIP := extractIP(req)
|
||||
realIP := req.Header.Get(HeaderXRealIP)
|
||||
if realIP != "" {
|
||||
if realIP == "" {
|
||||
return directIP
|
||||
}
|
||||
|
||||
if checker.trust(net.ParseIP(directIP)) {
|
||||
realIP = strings.TrimPrefix(realIP, "[")
|
||||
realIP = strings.TrimSuffix(realIP, "]")
|
||||
if ip := net.ParseIP(realIP); ip != nil && checker.trust(ip) {
|
||||
if rIP := net.ParseIP(realIP); rIP != nil {
|
||||
return realIP
|
||||
}
|
||||
}
|
||||
return extractIP(req)
|
||||
|
||||
return directIP
|
||||
}
|
||||
}
|
||||
|
||||
|
3
vendor/github.com/labstack/echo/v4/json.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/json.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
|
70
vendor/github.com/labstack/echo/v4/log.go
generated
vendored
70
vendor/github.com/labstack/echo/v4/log.go
generated
vendored
@ -1,41 +1,41 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/labstack/gommon/log"
|
||||
"io"
|
||||
)
|
||||
|
||||
type (
|
||||
// Logger defines the logging interface.
|
||||
Logger interface {
|
||||
Output() io.Writer
|
||||
SetOutput(w io.Writer)
|
||||
Prefix() string
|
||||
SetPrefix(p string)
|
||||
Level() log.Lvl
|
||||
SetLevel(v log.Lvl)
|
||||
SetHeader(h string)
|
||||
Print(i ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Printj(j log.JSON)
|
||||
Debug(i ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Debugj(j log.JSON)
|
||||
Info(i ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Infoj(j log.JSON)
|
||||
Warn(i ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warnj(j log.JSON)
|
||||
Error(i ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Errorj(j log.JSON)
|
||||
Fatal(i ...interface{})
|
||||
Fatalj(j log.JSON)
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panic(i ...interface{})
|
||||
Panicj(j log.JSON)
|
||||
Panicf(format string, args ...interface{})
|
||||
}
|
||||
)
|
||||
// Logger defines the logging interface.
|
||||
type Logger interface {
|
||||
Output() io.Writer
|
||||
SetOutput(w io.Writer)
|
||||
Prefix() string
|
||||
SetPrefix(p string)
|
||||
Level() log.Lvl
|
||||
SetLevel(v log.Lvl)
|
||||
SetHeader(h string)
|
||||
Print(i ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Printj(j log.JSON)
|
||||
Debug(i ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Debugj(j log.JSON)
|
||||
Info(i ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Infoj(j log.JSON)
|
||||
Warn(i ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warnj(j log.JSON)
|
||||
Error(i ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Errorj(j log.JSON)
|
||||
Fatal(i ...interface{})
|
||||
Fatalj(j log.JSON)
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panic(i ...interface{})
|
||||
Panicj(j log.JSON)
|
||||
Panicf(format string, args ...interface{})
|
||||
}
|
||||
|
47
vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
generated
vendored
47
vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
generated
vendored
@ -1,45 +1,46 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// BasicAuthConfig defines the config for BasicAuth middleware.
|
||||
BasicAuthConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// BasicAuthConfig defines the config for BasicAuth middleware.
|
||||
type BasicAuthConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Validator is a function to validate BasicAuth credentials.
|
||||
// Required.
|
||||
Validator BasicAuthValidator
|
||||
// Validator is a function to validate BasicAuth credentials.
|
||||
// Required.
|
||||
Validator BasicAuthValidator
|
||||
|
||||
// Realm is a string to define realm attribute of BasicAuth.
|
||||
// Default value "Restricted".
|
||||
Realm string
|
||||
}
|
||||
// Realm is a string to define realm attribute of BasicAuth.
|
||||
// Default value "Restricted".
|
||||
Realm string
|
||||
}
|
||||
|
||||
// BasicAuthValidator defines a function to validate BasicAuth credentials.
|
||||
BasicAuthValidator func(string, string, echo.Context) (bool, error)
|
||||
)
|
||||
// BasicAuthValidator defines a function to validate BasicAuth credentials.
|
||||
// The function should return a boolean indicating whether the credentials are valid,
|
||||
// and an error if any error occurs during the validation process.
|
||||
type BasicAuthValidator func(string, string, echo.Context) (bool, error)
|
||||
|
||||
const (
|
||||
basic = "basic"
|
||||
defaultRealm = "Restricted"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultBasicAuthConfig is the default BasicAuth middleware config.
|
||||
DefaultBasicAuthConfig = BasicAuthConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Realm: defaultRealm,
|
||||
}
|
||||
)
|
||||
// DefaultBasicAuthConfig is the default BasicAuth middleware config.
|
||||
var DefaultBasicAuthConfig = BasicAuthConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Realm: defaultRealm,
|
||||
}
|
||||
|
||||
// BasicAuth returns an BasicAuth middleware.
|
||||
//
|
||||
|
55
vendor/github.com/labstack/echo/v4/middleware/body_dump.go
generated
vendored
55
vendor/github.com/labstack/echo/v4/middleware/body_dump.go
generated
vendored
@ -1,8 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -10,32 +14,28 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// BodyDumpConfig defines the config for BodyDump middleware.
|
||||
BodyDumpConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// BodyDumpConfig defines the config for BodyDump middleware.
|
||||
type BodyDumpConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Handler receives request and response payload.
|
||||
// Required.
|
||||
Handler BodyDumpHandler
|
||||
}
|
||||
// Handler receives request and response payload.
|
||||
// Required.
|
||||
Handler BodyDumpHandler
|
||||
}
|
||||
|
||||
// BodyDumpHandler receives the request and response payload.
|
||||
BodyDumpHandler func(echo.Context, []byte, []byte)
|
||||
// BodyDumpHandler receives the request and response payload.
|
||||
type BodyDumpHandler func(echo.Context, []byte, []byte)
|
||||
|
||||
bodyDumpResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
}
|
||||
)
|
||||
type bodyDumpResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultBodyDumpConfig is the default BodyDump middleware config.
|
||||
DefaultBodyDumpConfig = BodyDumpConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
)
|
||||
// DefaultBodyDumpConfig is the default BodyDump middleware config.
|
||||
var DefaultBodyDumpConfig = BodyDumpConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
|
||||
// BodyDump returns a BodyDump middleware.
|
||||
//
|
||||
@ -98,9 +98,16 @@ func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (w *bodyDumpResponseWriter) Flush() {
|
||||
w.ResponseWriter.(http.Flusher).Flush()
|
||||
err := responseControllerFlush(w.ResponseWriter)
|
||||
if err != nil && errors.Is(err, http.ErrNotSupported) {
|
||||
panic(errors.New("response writer flushing is not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return w.ResponseWriter.(http.Hijacker).Hijack()
|
||||
return responseControllerHijack(w.ResponseWriter)
|
||||
}
|
||||
|
||||
func (w *bodyDumpResponseWriter) Unwrap() http.ResponseWriter {
|
||||
return w.ResponseWriter
|
||||
}
|
||||
|
49
vendor/github.com/labstack/echo/v4/middleware/body_limit.go
generated
vendored
49
vendor/github.com/labstack/echo/v4/middleware/body_limit.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -9,32 +12,27 @@ import (
|
||||
"github.com/labstack/gommon/bytes"
|
||||
)
|
||||
|
||||
type (
|
||||
// BodyLimitConfig defines the config for BodyLimit middleware.
|
||||
BodyLimitConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// BodyLimitConfig defines the config for BodyLimit middleware.
|
||||
type BodyLimitConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Maximum allowed size for a request body, it can be specified
|
||||
// as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P.
|
||||
Limit string `yaml:"limit"`
|
||||
limit int64
|
||||
}
|
||||
// Maximum allowed size for a request body, it can be specified
|
||||
// as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P.
|
||||
Limit string `yaml:"limit"`
|
||||
limit int64
|
||||
}
|
||||
|
||||
limitedReader struct {
|
||||
BodyLimitConfig
|
||||
reader io.ReadCloser
|
||||
read int64
|
||||
context echo.Context
|
||||
}
|
||||
)
|
||||
type limitedReader struct {
|
||||
BodyLimitConfig
|
||||
reader io.ReadCloser
|
||||
read int64
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultBodyLimitConfig is the default BodyLimit middleware config.
|
||||
DefaultBodyLimitConfig = BodyLimitConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
)
|
||||
// DefaultBodyLimitConfig is the default BodyLimit middleware config.
|
||||
var DefaultBodyLimitConfig = BodyLimitConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
|
||||
// BodyLimit returns a BodyLimit middleware.
|
||||
//
|
||||
@ -80,7 +78,7 @@ func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
|
||||
|
||||
// Based on content read
|
||||
r := pool.Get().(*limitedReader)
|
||||
r.Reset(req.Body, c)
|
||||
r.Reset(req.Body)
|
||||
defer pool.Put(r)
|
||||
req.Body = r
|
||||
|
||||
@ -102,9 +100,8 @@ func (r *limitedReader) Close() error {
|
||||
return r.reader.Close()
|
||||
}
|
||||
|
||||
func (r *limitedReader) Reset(reader io.ReadCloser, context echo.Context) {
|
||||
func (r *limitedReader) Reset(reader io.ReadCloser) {
|
||||
r.reader = reader
|
||||
r.context = context
|
||||
r.read = 0
|
||||
}
|
||||
|
||||
|
144
vendor/github.com/labstack/echo/v4/middleware/compress.go
generated
vendored
144
vendor/github.com/labstack/echo/v4/middleware/compress.go
generated
vendored
@ -1,7 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"net"
|
||||
@ -12,35 +16,50 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// GzipConfig defines the config for Gzip middleware.
|
||||
GzipConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// GzipConfig defines the config for Gzip middleware.
|
||||
type GzipConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Gzip compression level.
|
||||
// Optional. Default value -1.
|
||||
Level int `yaml:"level"`
|
||||
}
|
||||
// Gzip compression level.
|
||||
// Optional. Default value -1.
|
||||
Level int `yaml:"level"`
|
||||
|
||||
gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
wroteBody bool
|
||||
}
|
||||
)
|
||||
// Length threshold before gzip compression is applied.
|
||||
// Optional. Default value 0.
|
||||
//
|
||||
// Most of the time you will not need to change the default. Compressing
|
||||
// a short response might increase the transmitted data because of the
|
||||
// gzip format overhead. Compressing the response will also consume CPU
|
||||
// and time on the server and the client (for decompressing). Depending on
|
||||
// your use case such a threshold might be useful.
|
||||
//
|
||||
// See also:
|
||||
// https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits
|
||||
MinLength int
|
||||
}
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
wroteHeader bool
|
||||
wroteBody bool
|
||||
minLength int
|
||||
minLengthExceeded bool
|
||||
buffer *bytes.Buffer
|
||||
code int
|
||||
}
|
||||
|
||||
const (
|
||||
gzipScheme = "gzip"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultGzipConfig is the default Gzip middleware config.
|
||||
DefaultGzipConfig = GzipConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Level: -1,
|
||||
}
|
||||
)
|
||||
// DefaultGzipConfig is the default Gzip middleware config.
|
||||
var DefaultGzipConfig = GzipConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Level: -1,
|
||||
MinLength: 0,
|
||||
}
|
||||
|
||||
// Gzip returns a middleware which compresses HTTP response using gzip compression
|
||||
// scheme.
|
||||
@ -58,8 +77,12 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
if config.Level == 0 {
|
||||
config.Level = DefaultGzipConfig.Level
|
||||
}
|
||||
if config.MinLength < 0 {
|
||||
config.MinLength = DefaultGzipConfig.MinLength
|
||||
}
|
||||
|
||||
pool := gzipCompressPool(config)
|
||||
bpool := bufferPool()
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
@ -70,7 +93,6 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
res := c.Response()
|
||||
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
|
||||
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
|
||||
res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
|
||||
i := pool.Get()
|
||||
w, ok := i.(*gzip.Writer)
|
||||
if !ok {
|
||||
@ -78,19 +100,38 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
rw := res.Writer
|
||||
w.Reset(rw)
|
||||
grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
|
||||
|
||||
buf := bpool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
|
||||
grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw, minLength: config.MinLength, buffer: buf}
|
||||
defer func() {
|
||||
// There are different reasons for cases when we have not yet written response to the client and now need to do so.
|
||||
// a) handler response had only response code and no response body (ala 404 or redirects etc). Response code need to be written now.
|
||||
// b) body is shorter than our minimum length threshold and being buffered currently and needs to be written
|
||||
if !grw.wroteBody {
|
||||
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
|
||||
res.Header().Del(echo.HeaderContentEncoding)
|
||||
}
|
||||
if grw.wroteHeader {
|
||||
rw.WriteHeader(grw.code)
|
||||
}
|
||||
// We have to reset response to it's pristine state when
|
||||
// nothing is written to body or error is returned.
|
||||
// See issue #424, #407.
|
||||
res.Writer = rw
|
||||
w.Reset(io.Discard)
|
||||
} else if !grw.minLengthExceeded {
|
||||
// Write uncompressed response
|
||||
res.Writer = rw
|
||||
if grw.wroteHeader {
|
||||
grw.ResponseWriter.WriteHeader(grw.code)
|
||||
}
|
||||
grw.buffer.WriteTo(rw)
|
||||
w.Reset(io.Discard)
|
||||
}
|
||||
w.Close()
|
||||
bpool.Put(buf)
|
||||
pool.Put(w)
|
||||
}()
|
||||
res.Writer = grw
|
||||
@ -102,7 +143,11 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
|
||||
func (w *gzipResponseWriter) WriteHeader(code int) {
|
||||
w.Header().Del(echo.HeaderContentLength) // Issue #444
|
||||
w.ResponseWriter.WriteHeader(code)
|
||||
|
||||
w.wroteHeader = true
|
||||
|
||||
// Delay writing of the header until we know if we'll actually compress the response
|
||||
w.code = code
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
@ -110,18 +155,50 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
w.Header().Set(echo.HeaderContentType, http.DetectContentType(b))
|
||||
}
|
||||
w.wroteBody = true
|
||||
|
||||
if !w.minLengthExceeded {
|
||||
n, err := w.buffer.Write(b)
|
||||
|
||||
if w.buffer.Len() >= w.minLength {
|
||||
w.minLengthExceeded = true
|
||||
|
||||
// The minimum length is exceeded, add Content-Encoding header and write the header
|
||||
w.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
|
||||
if w.wroteHeader {
|
||||
w.ResponseWriter.WriteHeader(w.code)
|
||||
}
|
||||
|
||||
return w.Writer.Write(w.buffer.Bytes())
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) Flush() {
|
||||
w.Writer.(*gzip.Writer).Flush()
|
||||
if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
if !w.minLengthExceeded {
|
||||
// Enforce compression because we will not know how much more data will come
|
||||
w.minLengthExceeded = true
|
||||
w.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
|
||||
if w.wroteHeader {
|
||||
w.ResponseWriter.WriteHeader(w.code)
|
||||
}
|
||||
|
||||
w.Writer.Write(w.buffer.Bytes())
|
||||
}
|
||||
|
||||
w.Writer.(*gzip.Writer).Flush()
|
||||
_ = responseControllerFlush(w.ResponseWriter)
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) Unwrap() http.ResponseWriter {
|
||||
return w.ResponseWriter
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return w.ResponseWriter.(http.Hijacker).Hijack()
|
||||
return responseControllerHijack(w.ResponseWriter)
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) Push(target string, opts *http.PushOptions) error {
|
||||
@ -142,3 +219,12 @@ func gzipCompressPool(config GzipConfig) sync.Pool {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func bufferPool() sync.Pool {
|
||||
return sync.Pool{
|
||||
New: func() interface{} {
|
||||
b := &bytes.Buffer{}
|
||||
return b
|
||||
},
|
||||
}
|
||||
}
|
||||
|
5
vendor/github.com/labstack/echo/v4/middleware/context_timeout.go
generated
vendored
5
vendor/github.com/labstack/echo/v4/middleware/context_timeout.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -13,7 +16,7 @@ type ContextTimeoutConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// ErrorHandler is a function when error aries in middeware execution.
|
||||
// ErrorHandler is a function when error aries in middleware execution.
|
||||
ErrorHandler func(err error, c echo.Context) error
|
||||
|
||||
// Timeout configures a timeout for the middleware, defaults to 0 for no timeout
|
||||
|
206
vendor/github.com/labstack/echo/v4/middleware/cors.go
generated
vendored
206
vendor/github.com/labstack/echo/v4/middleware/cors.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -9,112 +12,109 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// CORSConfig defines the config for CORS middleware.
|
||||
CORSConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// CORSConfig defines the config for CORS middleware.
|
||||
type CORSConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// AllowOrigins determines the value of the Access-Control-Allow-Origin
|
||||
// response header. This header defines a list of origins that may access the
|
||||
// resource. The wildcard characters '*' and '?' are supported and are
|
||||
// converted to regex fragments '.*' and '.' accordingly.
|
||||
//
|
||||
// Security: use extreme caution when handling the origin, and carefully
|
||||
// validate any logic. Remember that attackers may register hostile domain names.
|
||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// Optional. Default value []string{"*"}.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
AllowOrigins []string `yaml:"allow_origins"`
|
||||
// AllowOrigins determines the value of the Access-Control-Allow-Origin
|
||||
// response header. This header defines a list of origins that may access the
|
||||
// resource. The wildcard characters '*' and '?' are supported and are
|
||||
// converted to regex fragments '.*' and '.' accordingly.
|
||||
//
|
||||
// Security: use extreme caution when handling the origin, and carefully
|
||||
// validate any logic. Remember that attackers may register hostile domain names.
|
||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// Optional. Default value []string{"*"}.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
AllowOrigins []string `yaml:"allow_origins"`
|
||||
|
||||
// AllowOriginFunc is a custom function to validate the origin. It takes the
|
||||
// origin as an argument and returns true if allowed or false otherwise. If
|
||||
// an error is returned, it is returned by the handler. If this option is
|
||||
// set, AllowOrigins is ignored.
|
||||
//
|
||||
// Security: use extreme caution when handling the origin, and carefully
|
||||
// validate any logic. Remember that attackers may register hostile domain names.
|
||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// Optional.
|
||||
AllowOriginFunc func(origin string) (bool, error) `yaml:"allow_origin_func"`
|
||||
// AllowOriginFunc is a custom function to validate the origin. It takes the
|
||||
// origin as an argument and returns true if allowed or false otherwise. If
|
||||
// an error is returned, it is returned by the handler. If this option is
|
||||
// set, AllowOrigins is ignored.
|
||||
//
|
||||
// Security: use extreme caution when handling the origin, and carefully
|
||||
// validate any logic. Remember that attackers may register hostile domain names.
|
||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// Optional.
|
||||
AllowOriginFunc func(origin string) (bool, error) `yaml:"-"`
|
||||
|
||||
// AllowMethods determines the value of the Access-Control-Allow-Methods
|
||||
// response header. This header specified the list of methods allowed when
|
||||
// accessing the resource. This is used in response to a preflight request.
|
||||
//
|
||||
// Optional. Default value DefaultCORSConfig.AllowMethods.
|
||||
// If `allowMethods` is left empty, this middleware will fill for preflight
|
||||
// request `Access-Control-Allow-Methods` header value
|
||||
// from `Allow` header that echo.Router set into context.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
||||
AllowMethods []string `yaml:"allow_methods"`
|
||||
// AllowMethods determines the value of the Access-Control-Allow-Methods
|
||||
// response header. This header specified the list of methods allowed when
|
||||
// accessing the resource. This is used in response to a preflight request.
|
||||
//
|
||||
// Optional. Default value DefaultCORSConfig.AllowMethods.
|
||||
// If `allowMethods` is left empty, this middleware will fill for preflight
|
||||
// request `Access-Control-Allow-Methods` header value
|
||||
// from `Allow` header that echo.Router set into context.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
||||
AllowMethods []string `yaml:"allow_methods"`
|
||||
|
||||
// AllowHeaders determines the value of the Access-Control-Allow-Headers
|
||||
// response header. This header is used in response to a preflight request to
|
||||
// indicate which HTTP headers can be used when making the actual request.
|
||||
//
|
||||
// Optional. Default value []string{}.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
||||
AllowHeaders []string `yaml:"allow_headers"`
|
||||
// AllowHeaders determines the value of the Access-Control-Allow-Headers
|
||||
// response header. This header is used in response to a preflight request to
|
||||
// indicate which HTTP headers can be used when making the actual request.
|
||||
//
|
||||
// Optional. Default value []string{}.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
||||
AllowHeaders []string `yaml:"allow_headers"`
|
||||
|
||||
// AllowCredentials determines the value of the
|
||||
// Access-Control-Allow-Credentials response header. This header indicates
|
||||
// whether or not the response to the request can be exposed when the
|
||||
// credentials mode (Request.credentials) is true. When used as part of a
|
||||
// response to a preflight request, this indicates whether or not the actual
|
||||
// request can be made using credentials. See also
|
||||
// [MDN: Access-Control-Allow-Credentials].
|
||||
//
|
||||
// Optional. Default value false, in which case the header is not set.
|
||||
//
|
||||
// Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
|
||||
// See "Exploiting CORS misconfigurations for Bitcoins and bounties",
|
||||
// https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
AllowCredentials bool `yaml:"allow_credentials"`
|
||||
// AllowCredentials determines the value of the
|
||||
// Access-Control-Allow-Credentials response header. This header indicates
|
||||
// whether or not the response to the request can be exposed when the
|
||||
// credentials mode (Request.credentials) is true. When used as part of a
|
||||
// response to a preflight request, this indicates whether or not the actual
|
||||
// request can be made using credentials. See also
|
||||
// [MDN: Access-Control-Allow-Credentials].
|
||||
//
|
||||
// Optional. Default value false, in which case the header is not set.
|
||||
//
|
||||
// Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
|
||||
// See "Exploiting CORS misconfigurations for Bitcoins and bounties",
|
||||
// https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
AllowCredentials bool `yaml:"allow_credentials"`
|
||||
|
||||
// UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials
|
||||
// flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header.
|
||||
//
|
||||
// This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties)
|
||||
// attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject.
|
||||
//
|
||||
// Optional. Default value is false.
|
||||
UnsafeWildcardOriginWithAllowCredentials bool `yaml:"unsafe_wildcard_origin_with_allow_credentials"`
|
||||
// UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials
|
||||
// flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header.
|
||||
//
|
||||
// This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties)
|
||||
// attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject.
|
||||
//
|
||||
// Optional. Default value is false.
|
||||
UnsafeWildcardOriginWithAllowCredentials bool `yaml:"unsafe_wildcard_origin_with_allow_credentials"`
|
||||
|
||||
// ExposeHeaders determines the value of Access-Control-Expose-Headers, which
|
||||
// defines a list of headers that clients are allowed to access.
|
||||
//
|
||||
// Optional. Default value []string{}, in which case the header is not set.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
|
||||
ExposeHeaders []string `yaml:"expose_headers"`
|
||||
// ExposeHeaders determines the value of Access-Control-Expose-Headers, which
|
||||
// defines a list of headers that clients are allowed to access.
|
||||
//
|
||||
// Optional. Default value []string{}, in which case the header is not set.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
|
||||
ExposeHeaders []string `yaml:"expose_headers"`
|
||||
|
||||
// MaxAge determines the value of the Access-Control-Max-Age response header.
|
||||
// This header indicates how long (in seconds) the results of a preflight
|
||||
// request can be cached.
|
||||
//
|
||||
// Optional. Default value 0. The header is set only if MaxAge > 0.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
)
|
||||
// MaxAge determines the value of the Access-Control-Max-Age response header.
|
||||
// This header indicates how long (in seconds) the results of a preflight
|
||||
// request can be cached.
|
||||
// The header is set only if MaxAge != 0, negative value sends "0" which instructs browsers not to cache that response.
|
||||
//
|
||||
// Optional. Default value 0 - meaning header is not sent.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultCORSConfig is the default CORS middleware config.
|
||||
DefaultCORSConfig = CORSConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
|
||||
}
|
||||
)
|
||||
// DefaultCORSConfig is the default CORS middleware config.
|
||||
var DefaultCORSConfig = CORSConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
|
||||
}
|
||||
|
||||
// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
|
||||
// See also [MDN: Cross-Origin Resource Sharing (CORS)].
|
||||
@ -150,8 +150,8 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
allowOriginPatterns := []string{}
|
||||
for _, origin := range config.AllowOrigins {
|
||||
pattern := regexp.QuoteMeta(origin)
|
||||
pattern = strings.Replace(pattern, "\\*", ".*", -1)
|
||||
pattern = strings.Replace(pattern, "\\?", ".", -1)
|
||||
pattern = strings.ReplaceAll(pattern, "\\*", ".*")
|
||||
pattern = strings.ReplaceAll(pattern, "\\?", ".")
|
||||
pattern = "^" + pattern + "$"
|
||||
allowOriginPatterns = append(allowOriginPatterns, pattern)
|
||||
}
|
||||
@ -159,7 +159,11 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
allowMethods := strings.Join(config.AllowMethods, ",")
|
||||
allowHeaders := strings.Join(config.AllowHeaders, ",")
|
||||
exposeHeaders := strings.Join(config.ExposeHeaders, ",")
|
||||
maxAge := strconv.Itoa(config.MaxAge)
|
||||
|
||||
maxAge := "0"
|
||||
if config.MaxAge > 0 {
|
||||
maxAge = strconv.Itoa(config.MaxAge)
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
@ -282,7 +286,7 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
|
||||
}
|
||||
}
|
||||
if config.MaxAge > 0 {
|
||||
if config.MaxAge != 0 {
|
||||
res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
|
||||
}
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
|
123
vendor/github.com/labstack/echo/v4/middleware/csrf.go
generated
vendored
123
vendor/github.com/labstack/echo/v4/middleware/csrf.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -6,85 +9,80 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/gommon/random"
|
||||
)
|
||||
|
||||
type (
|
||||
// CSRFConfig defines the config for CSRF middleware.
|
||||
CSRFConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// CSRFConfig defines the config for CSRF middleware.
|
||||
type CSRFConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// TokenLength is the length of the generated token.
|
||||
TokenLength uint8 `yaml:"token_length"`
|
||||
// Optional. Default value 32.
|
||||
// TokenLength is the length of the generated token.
|
||||
TokenLength uint8 `yaml:"token_length"`
|
||||
// Optional. Default value 32.
|
||||
|
||||
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:X-CSRF-Token".
|
||||
// Possible values:
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:X-CSRF-Token,query:csrf"
|
||||
TokenLookup string `yaml:"token_lookup"`
|
||||
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:X-CSRF-Token".
|
||||
// Possible values:
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:X-CSRF-Token,query:csrf"
|
||||
TokenLookup string `yaml:"token_lookup"`
|
||||
|
||||
// Context key to store generated CSRF token into context.
|
||||
// Optional. Default value "csrf".
|
||||
ContextKey string `yaml:"context_key"`
|
||||
// Context key to store generated CSRF token into context.
|
||||
// Optional. Default value "csrf".
|
||||
ContextKey string `yaml:"context_key"`
|
||||
|
||||
// Name of the CSRF cookie. This cookie will store CSRF token.
|
||||
// Optional. Default value "csrf".
|
||||
CookieName string `yaml:"cookie_name"`
|
||||
// Name of the CSRF cookie. This cookie will store CSRF token.
|
||||
// Optional. Default value "csrf".
|
||||
CookieName string `yaml:"cookie_name"`
|
||||
|
||||
// Domain of the CSRF cookie.
|
||||
// Optional. Default value none.
|
||||
CookieDomain string `yaml:"cookie_domain"`
|
||||
// Domain of the CSRF cookie.
|
||||
// Optional. Default value none.
|
||||
CookieDomain string `yaml:"cookie_domain"`
|
||||
|
||||
// Path of the CSRF cookie.
|
||||
// Optional. Default value none.
|
||||
CookiePath string `yaml:"cookie_path"`
|
||||
// Path of the CSRF cookie.
|
||||
// Optional. Default value none.
|
||||
CookiePath string `yaml:"cookie_path"`
|
||||
|
||||
// Max age (in seconds) of the CSRF cookie.
|
||||
// Optional. Default value 86400 (24hr).
|
||||
CookieMaxAge int `yaml:"cookie_max_age"`
|
||||
// Max age (in seconds) of the CSRF cookie.
|
||||
// Optional. Default value 86400 (24hr).
|
||||
CookieMaxAge int `yaml:"cookie_max_age"`
|
||||
|
||||
// Indicates if CSRF cookie is secure.
|
||||
// Optional. Default value false.
|
||||
CookieSecure bool `yaml:"cookie_secure"`
|
||||
// Indicates if CSRF cookie is secure.
|
||||
// Optional. Default value false.
|
||||
CookieSecure bool `yaml:"cookie_secure"`
|
||||
|
||||
// Indicates if CSRF cookie is HTTP only.
|
||||
// Optional. Default value false.
|
||||
CookieHTTPOnly bool `yaml:"cookie_http_only"`
|
||||
// Indicates if CSRF cookie is HTTP only.
|
||||
// Optional. Default value false.
|
||||
CookieHTTPOnly bool `yaml:"cookie_http_only"`
|
||||
|
||||
// Indicates SameSite mode of the CSRF cookie.
|
||||
// Optional. Default value SameSiteDefaultMode.
|
||||
CookieSameSite http.SameSite `yaml:"cookie_same_site"`
|
||||
// Indicates SameSite mode of the CSRF cookie.
|
||||
// Optional. Default value SameSiteDefaultMode.
|
||||
CookieSameSite http.SameSite `yaml:"cookie_same_site"`
|
||||
|
||||
// ErrorHandler defines a function which is executed for returning custom errors.
|
||||
ErrorHandler CSRFErrorHandler
|
||||
}
|
||||
// ErrorHandler defines a function which is executed for returning custom errors.
|
||||
ErrorHandler CSRFErrorHandler
|
||||
}
|
||||
|
||||
// CSRFErrorHandler is a function which is executed for creating custom errors.
|
||||
CSRFErrorHandler func(err error, c echo.Context) error
|
||||
)
|
||||
// CSRFErrorHandler is a function which is executed for creating custom errors.
|
||||
type CSRFErrorHandler func(err error, c echo.Context) error
|
||||
|
||||
// ErrCSRFInvalid is returned when CSRF check fails
|
||||
var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
|
||||
|
||||
var (
|
||||
// DefaultCSRFConfig is the default CSRF middleware config.
|
||||
DefaultCSRFConfig = CSRFConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
TokenLength: 32,
|
||||
TokenLookup: "header:" + echo.HeaderXCSRFToken,
|
||||
ContextKey: "csrf",
|
||||
CookieName: "_csrf",
|
||||
CookieMaxAge: 86400,
|
||||
CookieSameSite: http.SameSiteDefaultMode,
|
||||
}
|
||||
)
|
||||
// DefaultCSRFConfig is the default CSRF middleware config.
|
||||
var DefaultCSRFConfig = CSRFConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
TokenLength: 32,
|
||||
TokenLookup: "header:" + echo.HeaderXCSRFToken,
|
||||
ContextKey: "csrf",
|
||||
CookieName: "_csrf",
|
||||
CookieMaxAge: 86400,
|
||||
CookieSameSite: http.SameSiteDefaultMode,
|
||||
}
|
||||
|
||||
// CSRF returns a Cross-Site Request Forgery (CSRF) middleware.
|
||||
// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery
|
||||
@ -103,6 +101,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
||||
if config.TokenLength == 0 {
|
||||
config.TokenLength = DefaultCSRFConfig.TokenLength
|
||||
}
|
||||
|
||||
if config.TokenLookup == "" {
|
||||
config.TokenLookup = DefaultCSRFConfig.TokenLookup
|
||||
}
|
||||
@ -132,7 +131,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
||||
|
||||
token := ""
|
||||
if k, err := c.Cookie(config.CookieName); err != nil {
|
||||
token = random.String(config.TokenLength) // Generate token
|
||||
token = randomString(config.TokenLength)
|
||||
} else {
|
||||
token = k.Value // Reuse token
|
||||
}
|
||||
|
37
vendor/github.com/labstack/echo/v4/middleware/decompress.go
generated
vendored
37
vendor/github.com/labstack/echo/v4/middleware/decompress.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -9,18 +12,16 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// DecompressConfig defines the config for Decompress middleware.
|
||||
DecompressConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// DecompressConfig defines the config for Decompress middleware.
|
||||
type DecompressConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers
|
||||
GzipDecompressPool Decompressor
|
||||
}
|
||||
)
|
||||
// GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers
|
||||
GzipDecompressPool Decompressor
|
||||
}
|
||||
|
||||
//GZIPEncoding content-encoding header if set to "gzip", decompress body contents.
|
||||
// GZIPEncoding content-encoding header if set to "gzip", decompress body contents.
|
||||
const GZIPEncoding string = "gzip"
|
||||
|
||||
// Decompressor is used to get the sync.Pool used by the middleware to get Gzip readers
|
||||
@ -28,13 +29,11 @@ type Decompressor interface {
|
||||
gzipDecompressPool() sync.Pool
|
||||
}
|
||||
|
||||
var (
|
||||
//DefaultDecompressConfig defines the config for decompress middleware
|
||||
DefaultDecompressConfig = DecompressConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
GzipDecompressPool: &DefaultGzipDecompressPool{},
|
||||
}
|
||||
)
|
||||
// DefaultDecompressConfig defines the config for decompress middleware
|
||||
var DefaultDecompressConfig = DecompressConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
GzipDecompressPool: &DefaultGzipDecompressPool{},
|
||||
}
|
||||
|
||||
// DefaultGzipDecompressPool is the default implementation of Decompressor interface
|
||||
type DefaultGzipDecompressPool struct {
|
||||
@ -44,12 +43,12 @@ func (d *DefaultGzipDecompressPool) gzipDecompressPool() sync.Pool {
|
||||
return sync.Pool{New: func() interface{} { return new(gzip.Reader) }}
|
||||
}
|
||||
|
||||
//Decompress decompresses request body based if content encoding type is set to "gzip" with default config
|
||||
// Decompress decompresses request body based if content encoding type is set to "gzip" with default config
|
||||
func Decompress() echo.MiddlewareFunc {
|
||||
return DecompressWithConfig(DefaultDecompressConfig)
|
||||
}
|
||||
|
||||
//DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
|
||||
// DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
|
||||
func DecompressWithConfig(config DecompressConfig) echo.MiddlewareFunc {
|
||||
// Defaults
|
||||
if config.Skipper == nil {
|
||||
|
3
vendor/github.com/labstack/echo/v4/middleware/extractor.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/middleware/extractor.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
|
215
vendor/github.com/labstack/echo/v4/middleware/jwt.go
generated
vendored
215
vendor/github.com/labstack/echo/v4/middleware/jwt.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
//go:build go1.15
|
||||
// +build go1.15
|
||||
|
||||
@ -12,139 +15,135 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type (
|
||||
// JWTConfig defines the config for JWT middleware.
|
||||
JWTConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// JWTConfig defines the config for JWT middleware.
|
||||
type JWTConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// BeforeFunc defines a function which is executed just before the middleware.
|
||||
BeforeFunc BeforeFunc
|
||||
// BeforeFunc defines a function which is executed just before the middleware.
|
||||
BeforeFunc BeforeFunc
|
||||
|
||||
// SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next
|
||||
// middleware or handler.
|
||||
SuccessHandler JWTSuccessHandler
|
||||
// SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next
|
||||
// middleware or handler.
|
||||
SuccessHandler JWTSuccessHandler
|
||||
|
||||
// ErrorHandler defines a function which is executed for an invalid token.
|
||||
// It may be used to define a custom JWT error.
|
||||
ErrorHandler JWTErrorHandler
|
||||
// ErrorHandler defines a function which is executed for an invalid token.
|
||||
// It may be used to define a custom JWT error.
|
||||
ErrorHandler JWTErrorHandler
|
||||
|
||||
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
|
||||
ErrorHandlerWithContext JWTErrorHandlerWithContext
|
||||
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
|
||||
ErrorHandlerWithContext JWTErrorHandlerWithContext
|
||||
|
||||
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to
|
||||
// ignore the error (by returning `nil`).
|
||||
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
|
||||
// In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context
|
||||
// and continue. Some logic down the remaining execution chain needs to check that (public) token value then.
|
||||
ContinueOnIgnoredError bool
|
||||
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to
|
||||
// ignore the error (by returning `nil`).
|
||||
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
|
||||
// In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context
|
||||
// and continue. Some logic down the remaining execution chain needs to check that (public) token value then.
|
||||
ContinueOnIgnoredError bool
|
||||
|
||||
// Signing key to validate token.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
// Required if neither user-defined KeyFunc nor SigningKeys is provided.
|
||||
SigningKey interface{}
|
||||
// Signing key to validate token.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
// Required if neither user-defined KeyFunc nor SigningKeys is provided.
|
||||
SigningKey interface{}
|
||||
|
||||
// Map of signing keys to validate token with kid field usage.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
// Required if neither user-defined KeyFunc nor SigningKey is provided.
|
||||
SigningKeys map[string]interface{}
|
||||
// Map of signing keys to validate token with kid field usage.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
// Required if neither user-defined KeyFunc nor SigningKey is provided.
|
||||
SigningKeys map[string]interface{}
|
||||
|
||||
// Signing method used to check the token's signing algorithm.
|
||||
// Optional. Default value HS256.
|
||||
SigningMethod string
|
||||
// Signing method used to check the token's signing algorithm.
|
||||
// Optional. Default value HS256.
|
||||
SigningMethod string
|
||||
|
||||
// Context key to store user information from the token into context.
|
||||
// Optional. Default value "user".
|
||||
ContextKey string
|
||||
// Context key to store user information from the token into context.
|
||||
// Optional. Default value "user".
|
||||
ContextKey string
|
||||
|
||||
// Claims are extendable claims data defining token content. Used by default ParseTokenFunc implementation.
|
||||
// Not used if custom ParseTokenFunc is set.
|
||||
// Optional. Default value jwt.MapClaims
|
||||
Claims jwt.Claims
|
||||
// Claims are extendable claims data defining token content. Used by default ParseTokenFunc implementation.
|
||||
// Not used if custom ParseTokenFunc is set.
|
||||
// Optional. Default value jwt.MapClaims
|
||||
Claims jwt.Claims
|
||||
|
||||
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
|
||||
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
|
||||
// want to cut is `<auth-scheme> ` note the space at the end.
|
||||
// In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `.
|
||||
// If prefix is left empty the whole value is returned.
|
||||
// - "query:<name>"
|
||||
// - "param:<name>"
|
||||
// - "cookie:<name>"
|
||||
// - "form:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:Authorization,cookie:myowncookie"
|
||||
TokenLookup string
|
||||
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
|
||||
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
|
||||
// want to cut is `<auth-scheme> ` note the space at the end.
|
||||
// In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `.
|
||||
// If prefix is left empty the whole value is returned.
|
||||
// - "query:<name>"
|
||||
// - "param:<name>"
|
||||
// - "cookie:<name>"
|
||||
// - "form:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:Authorization,cookie:myowncookie"
|
||||
TokenLookup string
|
||||
|
||||
// TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context.
|
||||
// This is one of the two options to provide a token extractor.
|
||||
// The order of precedence is user-defined TokenLookupFuncs, and TokenLookup.
|
||||
// You can also provide both if you want.
|
||||
TokenLookupFuncs []ValuesExtractor
|
||||
// TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context.
|
||||
// This is one of the two options to provide a token extractor.
|
||||
// The order of precedence is user-defined TokenLookupFuncs, and TokenLookup.
|
||||
// You can also provide both if you want.
|
||||
TokenLookupFuncs []ValuesExtractor
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
|
||||
// KeyFunc defines a user-defined function that supplies the public key for a token validation.
|
||||
// The function shall take care of verifying the signing algorithm and selecting the proper key.
|
||||
// A user-defined KeyFunc can be useful if tokens are issued by an external party.
|
||||
// Used by default ParseTokenFunc implementation.
|
||||
//
|
||||
// When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
// Required if neither SigningKeys nor SigningKey is provided.
|
||||
// Not used if custom ParseTokenFunc is set.
|
||||
// Default to an internal implementation verifying the signing algorithm and selecting the proper key.
|
||||
KeyFunc jwt.Keyfunc
|
||||
// KeyFunc defines a user-defined function that supplies the public key for a token validation.
|
||||
// The function shall take care of verifying the signing algorithm and selecting the proper key.
|
||||
// A user-defined KeyFunc can be useful if tokens are issued by an external party.
|
||||
// Used by default ParseTokenFunc implementation.
|
||||
//
|
||||
// When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
// Required if neither SigningKeys nor SigningKey is provided.
|
||||
// Not used if custom ParseTokenFunc is set.
|
||||
// Default to an internal implementation verifying the signing algorithm and selecting the proper key.
|
||||
KeyFunc jwt.Keyfunc
|
||||
|
||||
// ParseTokenFunc defines a user-defined function that parses token from given auth. Returns an error when token
|
||||
// parsing fails or parsed token is invalid.
|
||||
// Defaults to implementation using `github.com/golang-jwt/jwt` as JWT implementation library
|
||||
ParseTokenFunc func(auth string, c echo.Context) (interface{}, error)
|
||||
}
|
||||
// ParseTokenFunc defines a user-defined function that parses token from given auth. Returns an error when token
|
||||
// parsing fails or parsed token is invalid.
|
||||
// Defaults to implementation using `github.com/golang-jwt/jwt` as JWT implementation library
|
||||
ParseTokenFunc func(auth string, c echo.Context) (interface{}, error)
|
||||
}
|
||||
|
||||
// JWTSuccessHandler defines a function which is executed for a valid token.
|
||||
JWTSuccessHandler func(c echo.Context)
|
||||
// JWTSuccessHandler defines a function which is executed for a valid token.
|
||||
type JWTSuccessHandler func(c echo.Context)
|
||||
|
||||
// JWTErrorHandler defines a function which is executed for an invalid token.
|
||||
JWTErrorHandler func(err error) error
|
||||
// JWTErrorHandler defines a function which is executed for an invalid token.
|
||||
type JWTErrorHandler func(err error) error
|
||||
|
||||
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
|
||||
JWTErrorHandlerWithContext func(err error, c echo.Context) error
|
||||
)
|
||||
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
|
||||
type JWTErrorHandlerWithContext func(err error, c echo.Context) error
|
||||
|
||||
// Algorithms
|
||||
const (
|
||||
AlgorithmHS256 = "HS256"
|
||||
)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
|
||||
ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
|
||||
)
|
||||
// ErrJWTMissing is error that is returned when no JWToken was extracted from the request.
|
||||
var ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
|
||||
|
||||
var (
|
||||
// DefaultJWTConfig is the default JWT auth middleware config.
|
||||
DefaultJWTConfig = JWTConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
SigningMethod: AlgorithmHS256,
|
||||
ContextKey: "user",
|
||||
TokenLookup: "header:" + echo.HeaderAuthorization,
|
||||
TokenLookupFuncs: nil,
|
||||
AuthScheme: "Bearer",
|
||||
Claims: jwt.MapClaims{},
|
||||
KeyFunc: nil,
|
||||
}
|
||||
)
|
||||
// ErrJWTInvalid is error that is returned when middleware could not parse JWT correctly.
|
||||
var ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
|
||||
|
||||
// DefaultJWTConfig is the default JWT auth middleware config.
|
||||
var DefaultJWTConfig = JWTConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
SigningMethod: AlgorithmHS256,
|
||||
ContextKey: "user",
|
||||
TokenLookup: "header:" + echo.HeaderAuthorization,
|
||||
TokenLookupFuncs: nil,
|
||||
AuthScheme: "Bearer",
|
||||
Claims: jwt.MapClaims{},
|
||||
KeyFunc: nil,
|
||||
}
|
||||
|
||||
// JWT returns a JSON Web Token (JWT) auth middleware.
|
||||
//
|
||||
|
99
vendor/github.com/labstack/echo/v4/middleware/key_auth.go
generated
vendored
99
vendor/github.com/labstack/echo/v4/middleware/key_auth.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -6,69 +9,65 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// KeyAuthConfig defines the config for KeyAuth middleware.
|
||||
KeyAuthConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// KeyAuthConfig defines the config for KeyAuth middleware.
|
||||
type KeyAuthConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// KeyLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract key from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
|
||||
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
|
||||
// want to cut is `<auth-scheme> ` note the space at the end.
|
||||
// In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `.
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// - "cookie:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:Authorization,header:X-Api-Key"
|
||||
KeyLookup string
|
||||
// KeyLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract key from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
|
||||
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
|
||||
// want to cut is `<auth-scheme> ` note the space at the end.
|
||||
// In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `.
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// - "cookie:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:Authorization,header:X-Api-Key"
|
||||
KeyLookup string
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
|
||||
// Validator is a function to validate key.
|
||||
// Required.
|
||||
Validator KeyAuthValidator
|
||||
// Validator is a function to validate key.
|
||||
// Required.
|
||||
Validator KeyAuthValidator
|
||||
|
||||
// ErrorHandler defines a function which is executed for an invalid key.
|
||||
// It may be used to define a custom error.
|
||||
ErrorHandler KeyAuthErrorHandler
|
||||
// ErrorHandler defines a function which is executed for an invalid key.
|
||||
// It may be used to define a custom error.
|
||||
ErrorHandler KeyAuthErrorHandler
|
||||
|
||||
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to
|
||||
// ignore the error (by returning `nil`).
|
||||
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
|
||||
// In that case you can use ErrorHandler to set a default public key auth value in the request context
|
||||
// and continue. Some logic down the remaining execution chain needs to check that (public) key auth value then.
|
||||
ContinueOnIgnoredError bool
|
||||
}
|
||||
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to
|
||||
// ignore the error (by returning `nil`).
|
||||
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
|
||||
// In that case you can use ErrorHandler to set a default public key auth value in the request context
|
||||
// and continue. Some logic down the remaining execution chain needs to check that (public) key auth value then.
|
||||
ContinueOnIgnoredError bool
|
||||
}
|
||||
|
||||
// KeyAuthValidator defines a function to validate KeyAuth credentials.
|
||||
KeyAuthValidator func(auth string, c echo.Context) (bool, error)
|
||||
// KeyAuthValidator defines a function to validate KeyAuth credentials.
|
||||
type KeyAuthValidator func(auth string, c echo.Context) (bool, error)
|
||||
|
||||
// KeyAuthErrorHandler defines a function which is executed for an invalid key.
|
||||
KeyAuthErrorHandler func(err error, c echo.Context) error
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultKeyAuthConfig is the default KeyAuth middleware config.
|
||||
DefaultKeyAuthConfig = KeyAuthConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
KeyLookup: "header:" + echo.HeaderAuthorization,
|
||||
AuthScheme: "Bearer",
|
||||
}
|
||||
)
|
||||
// KeyAuthErrorHandler defines a function which is executed for an invalid key.
|
||||
type KeyAuthErrorHandler func(err error, c echo.Context) error
|
||||
|
||||
// ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups
|
||||
type ErrKeyAuthMissing struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// DefaultKeyAuthConfig is the default KeyAuth middleware config.
|
||||
var DefaultKeyAuthConfig = KeyAuthConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
KeyLookup: "header:" + echo.HeaderAuthorization,
|
||||
AuthScheme: "Bearer",
|
||||
}
|
||||
|
||||
// Error returns errors text
|
||||
func (e *ErrKeyAuthMissing) Error() string {
|
||||
return e.Err.Error()
|
||||
|
129
vendor/github.com/labstack/echo/v4/middleware/logger.go
generated
vendored
129
vendor/github.com/labstack/echo/v4/middleware/logger.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -14,77 +17,73 @@ import (
|
||||
"github.com/valyala/fasttemplate"
|
||||
)
|
||||
|
||||
type (
|
||||
// LoggerConfig defines the config for Logger middleware.
|
||||
LoggerConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// LoggerConfig defines the config for Logger middleware.
|
||||
type LoggerConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Tags to construct the logger format.
|
||||
//
|
||||
// - time_unix
|
||||
// - time_unix_milli
|
||||
// - time_unix_micro
|
||||
// - time_unix_nano
|
||||
// - time_rfc3339
|
||||
// - time_rfc3339_nano
|
||||
// - time_custom
|
||||
// - id (Request ID)
|
||||
// - remote_ip
|
||||
// - uri
|
||||
// - host
|
||||
// - method
|
||||
// - path
|
||||
// - route
|
||||
// - protocol
|
||||
// - referer
|
||||
// - user_agent
|
||||
// - status
|
||||
// - error
|
||||
// - latency (In nanoseconds)
|
||||
// - latency_human (Human readable)
|
||||
// - bytes_in (Bytes received)
|
||||
// - bytes_out (Bytes sent)
|
||||
// - header:<NAME>
|
||||
// - query:<NAME>
|
||||
// - form:<NAME>
|
||||
// - custom (see CustomTagFunc field)
|
||||
//
|
||||
// Example "${remote_ip} ${status}"
|
||||
//
|
||||
// Optional. Default value DefaultLoggerConfig.Format.
|
||||
Format string `yaml:"format"`
|
||||
// Tags to construct the logger format.
|
||||
//
|
||||
// - time_unix
|
||||
// - time_unix_milli
|
||||
// - time_unix_micro
|
||||
// - time_unix_nano
|
||||
// - time_rfc3339
|
||||
// - time_rfc3339_nano
|
||||
// - time_custom
|
||||
// - id (Request ID)
|
||||
// - remote_ip
|
||||
// - uri
|
||||
// - host
|
||||
// - method
|
||||
// - path
|
||||
// - route
|
||||
// - protocol
|
||||
// - referer
|
||||
// - user_agent
|
||||
// - status
|
||||
// - error
|
||||
// - latency (In nanoseconds)
|
||||
// - latency_human (Human readable)
|
||||
// - bytes_in (Bytes received)
|
||||
// - bytes_out (Bytes sent)
|
||||
// - header:<NAME>
|
||||
// - query:<NAME>
|
||||
// - form:<NAME>
|
||||
// - custom (see CustomTagFunc field)
|
||||
//
|
||||
// Example "${remote_ip} ${status}"
|
||||
//
|
||||
// Optional. Default value DefaultLoggerConfig.Format.
|
||||
Format string `yaml:"format"`
|
||||
|
||||
// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
|
||||
CustomTimeFormat string `yaml:"custom_time_format"`
|
||||
// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
|
||||
CustomTimeFormat string `yaml:"custom_time_format"`
|
||||
|
||||
// CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf.
|
||||
// Make sure that outputted text creates valid JSON string with other logged tags.
|
||||
// Optional.
|
||||
CustomTagFunc func(c echo.Context, buf *bytes.Buffer) (int, error)
|
||||
// CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf.
|
||||
// Make sure that outputted text creates valid JSON string with other logged tags.
|
||||
// Optional.
|
||||
CustomTagFunc func(c echo.Context, buf *bytes.Buffer) (int, error)
|
||||
|
||||
// Output is a writer where logs in JSON format are written.
|
||||
// Optional. Default value os.Stdout.
|
||||
Output io.Writer
|
||||
// Output is a writer where logs in JSON format are written.
|
||||
// Optional. Default value os.Stdout.
|
||||
Output io.Writer
|
||||
|
||||
template *fasttemplate.Template
|
||||
colorer *color.Color
|
||||
pool *sync.Pool
|
||||
}
|
||||
)
|
||||
template *fasttemplate.Template
|
||||
colorer *color.Color
|
||||
pool *sync.Pool
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultLoggerConfig is the default Logger middleware config.
|
||||
DefaultLoggerConfig = LoggerConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` +
|
||||
`"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
|
||||
`"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` +
|
||||
`,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
|
||||
CustomTimeFormat: "2006-01-02 15:04:05.00000",
|
||||
colorer: color.New(),
|
||||
}
|
||||
)
|
||||
// DefaultLoggerConfig is the default Logger middleware config.
|
||||
var DefaultLoggerConfig = LoggerConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` +
|
||||
`"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
|
||||
`"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` +
|
||||
`,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
|
||||
CustomTimeFormat: "2006-01-02 15:04:05.00000",
|
||||
colorer: color.New(),
|
||||
}
|
||||
|
||||
// Logger returns a middleware that logs HTTP requests.
|
||||
func Logger() echo.MiddlewareFunc {
|
||||
|
37
vendor/github.com/labstack/echo/v4/middleware/method_override.go
generated
vendored
37
vendor/github.com/labstack/echo/v4/middleware/method_override.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -6,28 +9,24 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// MethodOverrideConfig defines the config for MethodOverride middleware.
|
||||
MethodOverrideConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// MethodOverrideConfig defines the config for MethodOverride middleware.
|
||||
type MethodOverrideConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Getter is a function that gets overridden method from the request.
|
||||
// Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride).
|
||||
Getter MethodOverrideGetter
|
||||
}
|
||||
// Getter is a function that gets overridden method from the request.
|
||||
// Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride).
|
||||
Getter MethodOverrideGetter
|
||||
}
|
||||
|
||||
// MethodOverrideGetter is a function that gets overridden method from the request
|
||||
MethodOverrideGetter func(echo.Context) string
|
||||
)
|
||||
// MethodOverrideGetter is a function that gets overridden method from the request
|
||||
type MethodOverrideGetter func(echo.Context) string
|
||||
|
||||
var (
|
||||
// DefaultMethodOverrideConfig is the default MethodOverride middleware config.
|
||||
DefaultMethodOverrideConfig = MethodOverrideConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),
|
||||
}
|
||||
)
|
||||
// DefaultMethodOverrideConfig is the default MethodOverride middleware config.
|
||||
var DefaultMethodOverrideConfig = MethodOverrideConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),
|
||||
}
|
||||
|
||||
// MethodOverride returns a MethodOverride middleware.
|
||||
// MethodOverride middleware checks for the overridden method from the request and
|
||||
|
21
vendor/github.com/labstack/echo/v4/middleware/middleware.go
generated
vendored
21
vendor/github.com/labstack/echo/v4/middleware/middleware.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -9,14 +12,12 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// Skipper defines a function to skip middleware. Returning true skips processing
|
||||
// the middleware.
|
||||
Skipper func(c echo.Context) bool
|
||||
// Skipper defines a function to skip middleware. Returning true skips processing
|
||||
// the middleware.
|
||||
type Skipper func(c echo.Context) bool
|
||||
|
||||
// BeforeFunc defines a function which is executed just before the middleware.
|
||||
BeforeFunc func(c echo.Context)
|
||||
)
|
||||
// BeforeFunc defines a function which is executed just before the middleware.
|
||||
type BeforeFunc func(c echo.Context)
|
||||
|
||||
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
||||
groups := pattern.FindAllStringSubmatch(input, -1)
|
||||
@ -38,9 +39,9 @@ func rewriteRulesRegex(rewrite map[string]string) map[*regexp.Regexp]string {
|
||||
rulesRegex := map[*regexp.Regexp]string{}
|
||||
for k, v := range rewrite {
|
||||
k = regexp.QuoteMeta(k)
|
||||
k = strings.Replace(k, `\*`, "(.*?)", -1)
|
||||
k = strings.ReplaceAll(k, `\*`, "(.*?)")
|
||||
if strings.HasPrefix(k, `\^`) {
|
||||
k = strings.Replace(k, `\^`, "^", -1)
|
||||
k = strings.ReplaceAll(k, `\^`, "^")
|
||||
}
|
||||
k = k + "$"
|
||||
rulesRegex[regexp.MustCompile(k)] = v
|
||||
@ -53,7 +54,7 @@ func rewriteURL(rewriteRegex map[*regexp.Regexp]string, req *http.Request) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// Depending how HTTP request is sent RequestURI could contain Scheme://Host/path or be just /path.
|
||||
// Depending on how HTTP request is sent RequestURI could contain Scheme://Host/path or be just /path.
|
||||
// We only want to use path part for rewriting and therefore trim prefix if it exists
|
||||
rawURI := req.RequestURI
|
||||
if rawURI != "" && rawURI[0] != '/' {
|
||||
|
343
vendor/github.com/labstack/echo/v4/middleware/proxy.go
generated
vendored
343
vendor/github.com/labstack/echo/v4/middleware/proxy.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -12,7 +15,6 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
@ -20,101 +22,126 @@ import (
|
||||
|
||||
// TODO: Handle TLS proxy
|
||||
|
||||
type (
|
||||
// ProxyConfig defines the config for Proxy middleware.
|
||||
ProxyConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// ProxyConfig defines the config for Proxy middleware.
|
||||
type ProxyConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Balancer defines a load balancing technique.
|
||||
// Required.
|
||||
Balancer ProxyBalancer
|
||||
// Balancer defines a load balancing technique.
|
||||
// Required.
|
||||
Balancer ProxyBalancer
|
||||
|
||||
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Examples:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
Rewrite map[string]string
|
||||
// RetryCount defines the number of times a failed proxied request should be retried
|
||||
// using the next available ProxyTarget. Defaults to 0, meaning requests are never retried.
|
||||
RetryCount int
|
||||
|
||||
// RegexRewrite defines rewrite rules using regexp.Rexexp with captures
|
||||
// Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
|
||||
// Example:
|
||||
// "^/old/[0.9]+/": "/new",
|
||||
// "^/api/.+?/(.*)": "/v2/$1",
|
||||
RegexRewrite map[*regexp.Regexp]string
|
||||
// RetryFilter defines a function used to determine if a failed request to a
|
||||
// ProxyTarget should be retried. The RetryFilter will only be called when the number
|
||||
// of previous retries is less than RetryCount. If the function returns true, the
|
||||
// request will be retried. The provided error indicates the reason for the request
|
||||
// failure. When the ProxyTarget is unavailable, the error will be an instance of
|
||||
// echo.HTTPError with a Code of http.StatusBadGateway. In all other cases, the error
|
||||
// will indicate an internal error in the Proxy middleware. When a RetryFilter is not
|
||||
// specified, all requests that fail with http.StatusBadGateway will be retried. A custom
|
||||
// RetryFilter can be provided to only retry specific requests. Note that RetryFilter is
|
||||
// only called when the request to the target fails, or an internal error in the Proxy
|
||||
// middleware has occurred. Successful requests that return a non-200 response code cannot
|
||||
// be retried.
|
||||
RetryFilter func(c echo.Context, e error) bool
|
||||
|
||||
// Context key to store selected ProxyTarget into context.
|
||||
// Optional. Default value "target".
|
||||
ContextKey string
|
||||
// ErrorHandler defines a function which can be used to return custom errors from
|
||||
// the Proxy middleware. ErrorHandler is only invoked when there has been
|
||||
// either an internal error in the Proxy middleware or the ProxyTarget is
|
||||
// unavailable. Due to the way requests are proxied, ErrorHandler is not invoked
|
||||
// when a ProxyTarget returns a non-200 response. In these cases, the response
|
||||
// is already written so errors cannot be modified. ErrorHandler is only
|
||||
// invoked after all retry attempts have been exhausted.
|
||||
ErrorHandler func(c echo.Context, err error) error
|
||||
|
||||
// To customize the transport to remote.
|
||||
// Examples: If custom TLS certificates are required.
|
||||
Transport http.RoundTripper
|
||||
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Examples:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
Rewrite map[string]string
|
||||
|
||||
// ModifyResponse defines function to modify response from ProxyTarget.
|
||||
ModifyResponse func(*http.Response) error
|
||||
}
|
||||
// RegexRewrite defines rewrite rules using regexp.Rexexp with captures
|
||||
// Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
|
||||
// Example:
|
||||
// "^/old/[0.9]+/": "/new",
|
||||
// "^/api/.+?/(.*)": "/v2/$1",
|
||||
RegexRewrite map[*regexp.Regexp]string
|
||||
|
||||
// ProxyTarget defines the upstream target.
|
||||
ProxyTarget struct {
|
||||
Name string
|
||||
URL *url.URL
|
||||
Meta echo.Map
|
||||
}
|
||||
// Context key to store selected ProxyTarget into context.
|
||||
// Optional. Default value "target".
|
||||
ContextKey string
|
||||
|
||||
// ProxyBalancer defines an interface to implement a load balancing technique.
|
||||
ProxyBalancer interface {
|
||||
AddTarget(*ProxyTarget) bool
|
||||
RemoveTarget(string) bool
|
||||
Next(echo.Context) *ProxyTarget
|
||||
}
|
||||
// To customize the transport to remote.
|
||||
// Examples: If custom TLS certificates are required.
|
||||
Transport http.RoundTripper
|
||||
|
||||
// TargetProvider defines an interface that gives the opportunity for balancer to return custom errors when selecting target.
|
||||
TargetProvider interface {
|
||||
NextTarget(echo.Context) (*ProxyTarget, error)
|
||||
}
|
||||
// ModifyResponse defines function to modify response from ProxyTarget.
|
||||
ModifyResponse func(*http.Response) error
|
||||
}
|
||||
|
||||
commonBalancer struct {
|
||||
targets []*ProxyTarget
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
// ProxyTarget defines the upstream target.
|
||||
type ProxyTarget struct {
|
||||
Name string
|
||||
URL *url.URL
|
||||
Meta echo.Map
|
||||
}
|
||||
|
||||
// RandomBalancer implements a random load balancing technique.
|
||||
randomBalancer struct {
|
||||
*commonBalancer
|
||||
random *rand.Rand
|
||||
}
|
||||
// ProxyBalancer defines an interface to implement a load balancing technique.
|
||||
type ProxyBalancer interface {
|
||||
AddTarget(*ProxyTarget) bool
|
||||
RemoveTarget(string) bool
|
||||
Next(echo.Context) *ProxyTarget
|
||||
}
|
||||
|
||||
// RoundRobinBalancer implements a round-robin load balancing technique.
|
||||
roundRobinBalancer struct {
|
||||
*commonBalancer
|
||||
i uint32
|
||||
}
|
||||
)
|
||||
// TargetProvider defines an interface that gives the opportunity for balancer
|
||||
// to return custom errors when selecting target.
|
||||
type TargetProvider interface {
|
||||
NextTarget(echo.Context) (*ProxyTarget, error)
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultProxyConfig is the default Proxy middleware config.
|
||||
DefaultProxyConfig = ProxyConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
ContextKey: "target",
|
||||
}
|
||||
)
|
||||
type commonBalancer struct {
|
||||
targets []*ProxyTarget
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// RandomBalancer implements a random load balancing technique.
|
||||
type randomBalancer struct {
|
||||
commonBalancer
|
||||
random *rand.Rand
|
||||
}
|
||||
|
||||
// RoundRobinBalancer implements a round-robin load balancing technique.
|
||||
type roundRobinBalancer struct {
|
||||
commonBalancer
|
||||
// tracking the index on `targets` slice for the next `*ProxyTarget` to be used
|
||||
i int
|
||||
}
|
||||
|
||||
// DefaultProxyConfig is the default Proxy middleware config.
|
||||
var DefaultProxyConfig = ProxyConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
ContextKey: "target",
|
||||
}
|
||||
|
||||
func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
in, _, err := c.Response().Hijack()
|
||||
if err != nil {
|
||||
c.Set("_error", fmt.Sprintf("proxy raw, hijack error=%v, url=%s", t.URL, err))
|
||||
c.Set("_error", fmt.Errorf("proxy raw, hijack error=%w, url=%s", err, t.URL))
|
||||
return
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := net.Dial("tcp", t.URL.Host)
|
||||
if err != nil {
|
||||
c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err)))
|
||||
c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", err, t.URL)))
|
||||
return
|
||||
}
|
||||
defer out.Close()
|
||||
@ -122,7 +149,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
||||
// Write header
|
||||
err = r.Write(out)
|
||||
if err != nil {
|
||||
c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err)))
|
||||
c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", err, t.URL)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -136,39 +163,44 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
||||
go cp(in, out)
|
||||
err = <-errCh
|
||||
if err != nil && err != io.EOF {
|
||||
c.Set("_error", fmt.Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err))
|
||||
c.Set("_error", fmt.Errorf("proxy raw, copy body error=%w, url=%s", err, t.URL))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// NewRandomBalancer returns a random proxy balancer.
|
||||
func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer {
|
||||
b := &randomBalancer{commonBalancer: new(commonBalancer)}
|
||||
b := randomBalancer{}
|
||||
b.targets = targets
|
||||
return b
|
||||
b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||
return &b
|
||||
}
|
||||
|
||||
// NewRoundRobinBalancer returns a round-robin proxy balancer.
|
||||
func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer {
|
||||
b := &roundRobinBalancer{commonBalancer: new(commonBalancer)}
|
||||
b := roundRobinBalancer{}
|
||||
b.targets = targets
|
||||
return b
|
||||
return &b
|
||||
}
|
||||
|
||||
// AddTarget adds an upstream target to the list.
|
||||
// AddTarget adds an upstream target to the list and returns `true`.
|
||||
//
|
||||
// However, if a target with the same name already exists then the operation is aborted returning `false`.
|
||||
func (b *commonBalancer) AddTarget(target *ProxyTarget) bool {
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
for _, t := range b.targets {
|
||||
if t.Name == target.Name {
|
||||
return false
|
||||
}
|
||||
}
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
b.targets = append(b.targets, target)
|
||||
return true
|
||||
}
|
||||
|
||||
// RemoveTarget removes an upstream target from the list.
|
||||
// RemoveTarget removes an upstream target from the list by name.
|
||||
//
|
||||
// Returns `true` on success, `false` if no target with the name is found.
|
||||
func (b *commonBalancer) RemoveTarget(name string) bool {
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
@ -182,21 +214,58 @@ func (b *commonBalancer) RemoveTarget(name string) bool {
|
||||
}
|
||||
|
||||
// Next randomly returns an upstream target.
|
||||
//
|
||||
// Note: `nil` is returned in case upstream target list is empty.
|
||||
func (b *randomBalancer) Next(c echo.Context) *ProxyTarget {
|
||||
if b.random == nil {
|
||||
b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
if len(b.targets) == 0 {
|
||||
return nil
|
||||
} else if len(b.targets) == 1 {
|
||||
return b.targets[0]
|
||||
}
|
||||
b.mutex.RLock()
|
||||
defer b.mutex.RUnlock()
|
||||
return b.targets[b.random.Intn(len(b.targets))]
|
||||
}
|
||||
|
||||
// Next returns an upstream target using round-robin technique.
|
||||
// Next returns an upstream target using round-robin technique. In the case
|
||||
// where a previously failed request is being retried, the round-robin
|
||||
// balancer will attempt to use the next target relative to the original
|
||||
// request. If the list of targets held by the balancer is modified while a
|
||||
// failed request is being retried, it is possible that the balancer will
|
||||
// return the original failed target.
|
||||
//
|
||||
// Note: `nil` is returned in case upstream target list is empty.
|
||||
func (b *roundRobinBalancer) Next(c echo.Context) *ProxyTarget {
|
||||
b.i = b.i % uint32(len(b.targets))
|
||||
t := b.targets[b.i]
|
||||
atomic.AddUint32(&b.i, 1)
|
||||
return t
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
if len(b.targets) == 0 {
|
||||
return nil
|
||||
} else if len(b.targets) == 1 {
|
||||
return b.targets[0]
|
||||
}
|
||||
|
||||
var i int
|
||||
const lastIdxKey = "_round_robin_last_index"
|
||||
// This request is a retry, start from the index of the previous
|
||||
// target to ensure we don't attempt to retry the request with
|
||||
// the same failed target
|
||||
if c.Get(lastIdxKey) != nil {
|
||||
i = c.Get(lastIdxKey).(int)
|
||||
i++
|
||||
if i >= len(b.targets) {
|
||||
i = 0
|
||||
}
|
||||
} else {
|
||||
// This is a first time request, use the global index
|
||||
if b.i >= len(b.targets) {
|
||||
b.i = 0
|
||||
}
|
||||
i = b.i
|
||||
b.i++
|
||||
}
|
||||
|
||||
c.Set(lastIdxKey, i)
|
||||
return b.targets[i]
|
||||
}
|
||||
|
||||
// Proxy returns a Proxy middleware.
|
||||
@ -211,14 +280,26 @@ func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
|
||||
// ProxyWithConfig returns a Proxy middleware with config.
|
||||
// See: `Proxy()`
|
||||
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||
if config.Balancer == nil {
|
||||
panic("echo: proxy middleware requires balancer")
|
||||
}
|
||||
// Defaults
|
||||
if config.Skipper == nil {
|
||||
config.Skipper = DefaultProxyConfig.Skipper
|
||||
}
|
||||
if config.Balancer == nil {
|
||||
panic("echo: proxy middleware requires balancer")
|
||||
if config.RetryFilter == nil {
|
||||
config.RetryFilter = func(c echo.Context, e error) bool {
|
||||
if httpErr, ok := e.(*echo.HTTPError); ok {
|
||||
return httpErr.Code == http.StatusBadGateway
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
if config.ErrorHandler == nil {
|
||||
config.ErrorHandler = func(c echo.Context, err error) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.Rewrite != nil {
|
||||
if config.RegexRewrite == nil {
|
||||
config.RegexRewrite = make(map[*regexp.Regexp]string)
|
||||
@ -229,28 +310,17 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
|
||||
provider, isTargetProvider := config.Balancer.(TargetProvider)
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) (err error) {
|
||||
return func(c echo.Context) error {
|
||||
if config.Skipper(c) {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
req := c.Request()
|
||||
res := c.Response()
|
||||
|
||||
var tgt *ProxyTarget
|
||||
if isTargetProvider {
|
||||
tgt, err = provider.NextTarget(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
tgt = config.Balancer.Next(c)
|
||||
}
|
||||
c.Set(config.ContextKey, tgt)
|
||||
|
||||
if err := rewriteURL(config.RegexRewrite, req); err != nil {
|
||||
return err
|
||||
return config.ErrorHandler(c, err)
|
||||
}
|
||||
|
||||
// Fix header
|
||||
@ -266,19 +336,52 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||
req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
|
||||
}
|
||||
|
||||
// Proxy
|
||||
switch {
|
||||
case c.IsWebSocket():
|
||||
proxyRaw(tgt, c).ServeHTTP(res, req)
|
||||
case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
|
||||
default:
|
||||
proxyHTTP(tgt, c, config).ServeHTTP(res, req)
|
||||
}
|
||||
if e, ok := c.Get("_error").(error); ok {
|
||||
err = e
|
||||
}
|
||||
retries := config.RetryCount
|
||||
for {
|
||||
var tgt *ProxyTarget
|
||||
var err error
|
||||
if isTargetProvider {
|
||||
tgt, err = provider.NextTarget(c)
|
||||
if err != nil {
|
||||
return config.ErrorHandler(c, err)
|
||||
}
|
||||
} else {
|
||||
tgt = config.Balancer.Next(c)
|
||||
}
|
||||
|
||||
return
|
||||
c.Set(config.ContextKey, tgt)
|
||||
|
||||
//If retrying a failed request, clear any previous errors from
|
||||
//context here so that balancers have the option to check for
|
||||
//errors that occurred using previous target
|
||||
if retries < config.RetryCount {
|
||||
c.Set("_error", nil)
|
||||
}
|
||||
|
||||
// This is needed for ProxyConfig.ModifyResponse and/or ProxyConfig.Transport to be able to process the Request
|
||||
// that Balancer may have replaced with c.SetRequest.
|
||||
req = c.Request()
|
||||
|
||||
// Proxy
|
||||
switch {
|
||||
case c.IsWebSocket():
|
||||
proxyRaw(tgt, c).ServeHTTP(res, req)
|
||||
default: // even SSE requests
|
||||
proxyHTTP(tgt, c, config).ServeHTTP(res, req)
|
||||
}
|
||||
|
||||
err, hasError := c.Get("_error").(error)
|
||||
if !hasError {
|
||||
return nil
|
||||
}
|
||||
|
||||
retry := retries > 0 && config.RetryFilter(c, err)
|
||||
if !retry {
|
||||
return config.ErrorHandler(c, err)
|
||||
}
|
||||
|
||||
retries--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
112
vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
generated
vendored
112
vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -9,39 +12,34 @@ import (
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
type (
|
||||
// RateLimiterStore is the interface to be implemented by custom stores.
|
||||
RateLimiterStore interface {
|
||||
// Stores for the rate limiter have to implement the Allow method
|
||||
Allow(identifier string) (bool, error)
|
||||
}
|
||||
)
|
||||
// RateLimiterStore is the interface to be implemented by custom stores.
|
||||
type RateLimiterStore interface {
|
||||
// Stores for the rate limiter have to implement the Allow method
|
||||
Allow(identifier string) (bool, error)
|
||||
}
|
||||
|
||||
type (
|
||||
// RateLimiterConfig defines the configuration for the rate limiter
|
||||
RateLimiterConfig struct {
|
||||
Skipper Skipper
|
||||
BeforeFunc BeforeFunc
|
||||
// IdentifierExtractor uses echo.Context to extract the identifier for a visitor
|
||||
IdentifierExtractor Extractor
|
||||
// Store defines a store for the rate limiter
|
||||
Store RateLimiterStore
|
||||
// ErrorHandler provides a handler to be called when IdentifierExtractor returns an error
|
||||
ErrorHandler func(context echo.Context, err error) error
|
||||
// DenyHandler provides a handler to be called when RateLimiter denies access
|
||||
DenyHandler func(context echo.Context, identifier string, err error) error
|
||||
}
|
||||
// Extractor is used to extract data from echo.Context
|
||||
Extractor func(context echo.Context) (string, error)
|
||||
)
|
||||
// RateLimiterConfig defines the configuration for the rate limiter
|
||||
type RateLimiterConfig struct {
|
||||
Skipper Skipper
|
||||
BeforeFunc BeforeFunc
|
||||
// IdentifierExtractor uses echo.Context to extract the identifier for a visitor
|
||||
IdentifierExtractor Extractor
|
||||
// Store defines a store for the rate limiter
|
||||
Store RateLimiterStore
|
||||
// ErrorHandler provides a handler to be called when IdentifierExtractor returns an error
|
||||
ErrorHandler func(context echo.Context, err error) error
|
||||
// DenyHandler provides a handler to be called when RateLimiter denies access
|
||||
DenyHandler func(context echo.Context, identifier string, err error) error
|
||||
}
|
||||
|
||||
// errors
|
||||
var (
|
||||
// ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
|
||||
ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
|
||||
// ErrExtractorError denotes an error raised when extractor function is unsuccessful
|
||||
ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
|
||||
)
|
||||
// Extractor is used to extract data from echo.Context
|
||||
type Extractor func(context echo.Context) (string, error)
|
||||
|
||||
// ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
|
||||
var ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
|
||||
|
||||
// ErrExtractorError denotes an error raised when extractor function is unsuccessful
|
||||
var ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
|
||||
|
||||
// DefaultRateLimiterConfig defines default values for RateLimiterConfig
|
||||
var DefaultRateLimiterConfig = RateLimiterConfig{
|
||||
@ -150,23 +148,24 @@ func RateLimiterWithConfig(config RateLimiterConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
// RateLimiterMemoryStore is the built-in store implementation for RateLimiter
|
||||
RateLimiterMemoryStore struct {
|
||||
visitors map[string]*Visitor
|
||||
mutex sync.Mutex
|
||||
rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
||||
// RateLimiterMemoryStore is the built-in store implementation for RateLimiter
|
||||
type RateLimiterMemoryStore struct {
|
||||
visitors map[string]*Visitor
|
||||
mutex sync.Mutex
|
||||
rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
||||
|
||||
burst int
|
||||
expiresIn time.Duration
|
||||
lastCleanup time.Time
|
||||
}
|
||||
// Visitor signifies a unique user's limiter details
|
||||
Visitor struct {
|
||||
*rate.Limiter
|
||||
lastSeen time.Time
|
||||
}
|
||||
)
|
||||
burst int
|
||||
expiresIn time.Duration
|
||||
lastCleanup time.Time
|
||||
|
||||
timeNow func() time.Time
|
||||
}
|
||||
|
||||
// Visitor signifies a unique user's limiter details
|
||||
type Visitor struct {
|
||||
*rate.Limiter
|
||||
lastSeen time.Time
|
||||
}
|
||||
|
||||
/*
|
||||
NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with
|
||||
@ -219,7 +218,8 @@ func NewRateLimiterMemoryStoreWithConfig(config RateLimiterMemoryStoreConfig) (s
|
||||
store.burst = int(config.Rate)
|
||||
}
|
||||
store.visitors = make(map[string]*Visitor)
|
||||
store.lastCleanup = now()
|
||||
store.timeNow = time.Now
|
||||
store.lastCleanup = store.timeNow()
|
||||
return
|
||||
}
|
||||
|
||||
@ -244,12 +244,13 @@ func (store *RateLimiterMemoryStore) Allow(identifier string) (bool, error) {
|
||||
limiter.Limiter = rate.NewLimiter(store.rate, store.burst)
|
||||
store.visitors[identifier] = limiter
|
||||
}
|
||||
limiter.lastSeen = now()
|
||||
if now().Sub(store.lastCleanup) > store.expiresIn {
|
||||
now := store.timeNow()
|
||||
limiter.lastSeen = now
|
||||
if now.Sub(store.lastCleanup) > store.expiresIn {
|
||||
store.cleanupStaleVisitors()
|
||||
}
|
||||
store.mutex.Unlock()
|
||||
return limiter.AllowN(now(), 1), nil
|
||||
return limiter.AllowN(store.timeNow(), 1), nil
|
||||
}
|
||||
|
||||
/*
|
||||
@ -258,14 +259,9 @@ of users who haven't visited again after the configured expiry time has elapsed
|
||||
*/
|
||||
func (store *RateLimiterMemoryStore) cleanupStaleVisitors() {
|
||||
for id, visitor := range store.visitors {
|
||||
if now().Sub(visitor.lastSeen) > store.expiresIn {
|
||||
if store.timeNow().Sub(visitor.lastSeen) > store.expiresIn {
|
||||
delete(store.visitors, id)
|
||||
}
|
||||
}
|
||||
store.lastCleanup = now()
|
||||
store.lastCleanup = store.timeNow()
|
||||
}
|
||||
|
||||
/*
|
||||
actual time method which is mocked in test file
|
||||
*/
|
||||
var now = time.Now
|
||||
|
95
vendor/github.com/labstack/echo/v4/middleware/recover.go
generated
vendored
95
vendor/github.com/labstack/echo/v4/middleware/recover.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -9,49 +12,52 @@ import (
|
||||
"github.com/labstack/gommon/log"
|
||||
)
|
||||
|
||||
type (
|
||||
// LogErrorFunc defines a function for custom logging in the middleware.
|
||||
type LogErrorFunc func(c echo.Context, err error, stack []byte) error
|
||||
|
||||
// RecoverConfig defines the config for Recover middleware.
|
||||
type RecoverConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Size of the stack to be printed.
|
||||
// Optional. Default value 4KB.
|
||||
StackSize int `yaml:"stack_size"`
|
||||
|
||||
// DisableStackAll disables formatting stack traces of all other goroutines
|
||||
// into buffer after the trace for the current goroutine.
|
||||
// Optional. Default value false.
|
||||
DisableStackAll bool `yaml:"disable_stack_all"`
|
||||
|
||||
// DisablePrintStack disables printing stack trace.
|
||||
// Optional. Default value as false.
|
||||
DisablePrintStack bool `yaml:"disable_print_stack"`
|
||||
|
||||
// LogLevel is log level to printing stack trace.
|
||||
// Optional. Default value 0 (Print).
|
||||
LogLevel log.Lvl
|
||||
|
||||
// LogErrorFunc defines a function for custom logging in the middleware.
|
||||
LogErrorFunc func(c echo.Context, err error, stack []byte) error
|
||||
// If it's set you don't need to provide LogLevel for config.
|
||||
// If this function returns nil, the centralized HTTPErrorHandler will not be called.
|
||||
LogErrorFunc LogErrorFunc
|
||||
|
||||
// RecoverConfig defines the config for Recover middleware.
|
||||
RecoverConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// DisableErrorHandler disables the call to centralized HTTPErrorHandler.
|
||||
// The recovered error is then passed back to upstream middleware, instead of swallowing the error.
|
||||
// Optional. Default value false.
|
||||
DisableErrorHandler bool `yaml:"disable_error_handler"`
|
||||
}
|
||||
|
||||
// Size of the stack to be printed.
|
||||
// Optional. Default value 4KB.
|
||||
StackSize int `yaml:"stack_size"`
|
||||
|
||||
// DisableStackAll disables formatting stack traces of all other goroutines
|
||||
// into buffer after the trace for the current goroutine.
|
||||
// Optional. Default value false.
|
||||
DisableStackAll bool `yaml:"disable_stack_all"`
|
||||
|
||||
// DisablePrintStack disables printing stack trace.
|
||||
// Optional. Default value as false.
|
||||
DisablePrintStack bool `yaml:"disable_print_stack"`
|
||||
|
||||
// LogLevel is log level to printing stack trace.
|
||||
// Optional. Default value 0 (Print).
|
||||
LogLevel log.Lvl
|
||||
|
||||
// LogErrorFunc defines a function for custom logging in the middleware.
|
||||
// If it's set you don't need to provide LogLevel for config.
|
||||
LogErrorFunc LogErrorFunc
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultRecoverConfig is the default Recover middleware config.
|
||||
DefaultRecoverConfig = RecoverConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
StackSize: 4 << 10, // 4 KB
|
||||
DisableStackAll: false,
|
||||
DisablePrintStack: false,
|
||||
LogLevel: 0,
|
||||
LogErrorFunc: nil,
|
||||
}
|
||||
)
|
||||
// DefaultRecoverConfig is the default Recover middleware config.
|
||||
var DefaultRecoverConfig = RecoverConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
StackSize: 4 << 10, // 4 KB
|
||||
DisableStackAll: false,
|
||||
DisablePrintStack: false,
|
||||
LogLevel: 0,
|
||||
LogErrorFunc: nil,
|
||||
DisableErrorHandler: false,
|
||||
}
|
||||
|
||||
// Recover returns a middleware which recovers from panics anywhere in the chain
|
||||
// and handles the control to the centralized HTTPErrorHandler.
|
||||
@ -71,7 +77,7 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
return func(c echo.Context) (returnErr error) {
|
||||
if config.Skipper(c) {
|
||||
return next(c)
|
||||
}
|
||||
@ -113,7 +119,12 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
|
||||
c.Logger().Print(msg)
|
||||
}
|
||||
}
|
||||
c.Error(err)
|
||||
|
||||
if err != nil && !config.DisableErrorHandler {
|
||||
c.Error(err)
|
||||
} else {
|
||||
returnErr = err
|
||||
}
|
||||
}
|
||||
}()
|
||||
return next(c)
|
||||
|
3
vendor/github.com/labstack/echo/v4/middleware/redirect.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/middleware/redirect.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
|
46
vendor/github.com/labstack/echo/v4/middleware/request_id.go
generated
vendored
46
vendor/github.com/labstack/echo/v4/middleware/request_id.go
generated
vendored
@ -1,36 +1,34 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/gommon/random"
|
||||
)
|
||||
|
||||
type (
|
||||
// RequestIDConfig defines the config for RequestID middleware.
|
||||
RequestIDConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// RequestIDConfig defines the config for RequestID middleware.
|
||||
type RequestIDConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Generator defines a function to generate an ID.
|
||||
// Optional. Default value random.String(32).
|
||||
Generator func() string
|
||||
// Generator defines a function to generate an ID.
|
||||
// Optional. Defaults to generator for random string of length 32.
|
||||
Generator func() string
|
||||
|
||||
// RequestIDHandler defines a function which is executed for a request id.
|
||||
RequestIDHandler func(echo.Context, string)
|
||||
// RequestIDHandler defines a function which is executed for a request id.
|
||||
RequestIDHandler func(echo.Context, string)
|
||||
|
||||
// TargetHeader defines what header to look for to populate the id
|
||||
TargetHeader string
|
||||
}
|
||||
)
|
||||
// TargetHeader defines what header to look for to populate the id
|
||||
TargetHeader string
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultRequestIDConfig is the default RequestID middleware config.
|
||||
DefaultRequestIDConfig = RequestIDConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Generator: generator,
|
||||
TargetHeader: echo.HeaderXRequestID,
|
||||
}
|
||||
)
|
||||
// DefaultRequestIDConfig is the default RequestID middleware config.
|
||||
var DefaultRequestIDConfig = RequestIDConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Generator: generator,
|
||||
TargetHeader: echo.HeaderXRequestID,
|
||||
}
|
||||
|
||||
// RequestID returns a X-Request-ID middleware.
|
||||
func RequestID() echo.MiddlewareFunc {
|
||||
@ -73,5 +71,5 @@ func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
|
||||
func generator() string {
|
||||
return random.String(32)
|
||||
return randomString(32)
|
||||
}
|
||||
|
31
vendor/github.com/labstack/echo/v4/middleware/request_logger.go
generated
vendored
31
vendor/github.com/labstack/echo/v4/middleware/request_logger.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -8,6 +11,30 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
// Example for `slog` https://pkg.go.dev/log/slog
|
||||
// logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
||||
// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
|
||||
// LogStatus: true,
|
||||
// LogURI: true,
|
||||
// LogError: true,
|
||||
// HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code
|
||||
// LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
|
||||
// if v.Error == nil {
|
||||
// logger.LogAttrs(context.Background(), slog.LevelInfo, "REQUEST",
|
||||
// slog.String("uri", v.URI),
|
||||
// slog.Int("status", v.Status),
|
||||
// )
|
||||
// } else {
|
||||
// logger.LogAttrs(context.Background(), slog.LevelError, "REQUEST_ERROR",
|
||||
// slog.String("uri", v.URI),
|
||||
// slog.Int("status", v.Status),
|
||||
// slog.String("err", v.Error.Error()),
|
||||
// )
|
||||
// }
|
||||
// return nil
|
||||
// },
|
||||
// }))
|
||||
//
|
||||
// Example for `fmt.Printf`
|
||||
// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
|
||||
// LogStatus: true,
|
||||
@ -225,7 +252,7 @@ func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
|
||||
if config.Skipper == nil {
|
||||
config.Skipper = DefaultSkipper
|
||||
}
|
||||
now = time.Now
|
||||
now := time.Now
|
||||
if config.timeNow != nil {
|
||||
now = config.timeNow
|
||||
}
|
||||
@ -257,7 +284,7 @@ func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
|
||||
config.BeforeNextFunc(c)
|
||||
}
|
||||
err := next(c)
|
||||
if config.HandleError {
|
||||
if err != nil && config.HandleError {
|
||||
c.Error(err)
|
||||
}
|
||||
|
||||
|
44
vendor/github.com/labstack/echo/v4/middleware/responsecontroller_1.19.go
generated
vendored
Normal file
44
vendor/github.com/labstack/echo/v4/middleware/responsecontroller_1.19.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// TODO: remove when Go 1.23 is released and we do not support 1.19 anymore
|
||||
func responseControllerFlush(rw http.ResponseWriter) error {
|
||||
for {
|
||||
switch t := rw.(type) {
|
||||
case interface{ FlushError() error }:
|
||||
return t.FlushError()
|
||||
case http.Flusher:
|
||||
t.Flush()
|
||||
return nil
|
||||
case interface{ Unwrap() http.ResponseWriter }:
|
||||
rw = t.Unwrap()
|
||||
default:
|
||||
return fmt.Errorf("%w", http.ErrNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove when Go 1.23 is released and we do not support 1.19 anymore
|
||||
func responseControllerHijack(rw http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) {
|
||||
for {
|
||||
switch t := rw.(type) {
|
||||
case http.Hijacker:
|
||||
return t.Hijack()
|
||||
case interface{ Unwrap() http.ResponseWriter }:
|
||||
rw = t.Unwrap()
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("%w", http.ErrNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
20
vendor/github.com/labstack/echo/v4/middleware/responsecontroller_1.20.go
generated
vendored
Normal file
20
vendor/github.com/labstack/echo/v4/middleware/responsecontroller_1.20.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
//go:build go1.20
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func responseControllerFlush(rw http.ResponseWriter) error {
|
||||
return http.NewResponseController(rw).Flush()
|
||||
}
|
||||
|
||||
func responseControllerHijack(rw http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) {
|
||||
return http.NewResponseController(rw).Hijack()
|
||||
}
|
55
vendor/github.com/labstack/echo/v4/middleware/rewrite.go
generated
vendored
55
vendor/github.com/labstack/echo/v4/middleware/rewrite.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -6,37 +9,33 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// RewriteConfig defines the config for Rewrite middleware.
|
||||
RewriteConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// RewriteConfig defines the config for Rewrite middleware.
|
||||
type RewriteConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Rules defines the URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Example:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
// Required.
|
||||
Rules map[string]string `yaml:"rules"`
|
||||
// Rules defines the URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Example:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
// Required.
|
||||
Rules map[string]string `yaml:"rules"`
|
||||
|
||||
// RegexRules defines the URL path rewrite rules using regexp.Rexexp with captures
|
||||
// Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
|
||||
// Example:
|
||||
// "^/old/[0.9]+/": "/new",
|
||||
// "^/api/.+?/(.*)": "/v2/$1",
|
||||
RegexRules map[*regexp.Regexp]string `yaml:"regex_rules"`
|
||||
}
|
||||
)
|
||||
// RegexRules defines the URL path rewrite rules using regexp.Rexexp with captures
|
||||
// Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
|
||||
// Example:
|
||||
// "^/old/[0.9]+/": "/new",
|
||||
// "^/api/.+?/(.*)": "/v2/$1",
|
||||
RegexRules map[*regexp.Regexp]string `yaml:"-"`
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultRewriteConfig is the default Rewrite middleware config.
|
||||
DefaultRewriteConfig = RewriteConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
)
|
||||
// DefaultRewriteConfig is the default Rewrite middleware config.
|
||||
var DefaultRewriteConfig = RewriteConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
|
||||
// Rewrite returns a Rewrite middleware.
|
||||
//
|
||||
|
135
vendor/github.com/labstack/echo/v4/middleware/secure.go
generated
vendored
135
vendor/github.com/labstack/echo/v4/middleware/secure.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -6,84 +9,80 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// SecureConfig defines the config for Secure middleware.
|
||||
SecureConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// SecureConfig defines the config for Secure middleware.
|
||||
type SecureConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// XSSProtection provides protection against cross-site scripting attack (XSS)
|
||||
// by setting the `X-XSS-Protection` header.
|
||||
// Optional. Default value "1; mode=block".
|
||||
XSSProtection string `yaml:"xss_protection"`
|
||||
// XSSProtection provides protection against cross-site scripting attack (XSS)
|
||||
// by setting the `X-XSS-Protection` header.
|
||||
// Optional. Default value "1; mode=block".
|
||||
XSSProtection string `yaml:"xss_protection"`
|
||||
|
||||
// ContentTypeNosniff provides protection against overriding Content-Type
|
||||
// header by setting the `X-Content-Type-Options` header.
|
||||
// Optional. Default value "nosniff".
|
||||
ContentTypeNosniff string `yaml:"content_type_nosniff"`
|
||||
// ContentTypeNosniff provides protection against overriding Content-Type
|
||||
// header by setting the `X-Content-Type-Options` header.
|
||||
// Optional. Default value "nosniff".
|
||||
ContentTypeNosniff string `yaml:"content_type_nosniff"`
|
||||
|
||||
// XFrameOptions can be used to indicate whether or not a browser should
|
||||
// be allowed to render a page in a <frame>, <iframe> or <object> .
|
||||
// Sites can use this to avoid clickjacking attacks, by ensuring that their
|
||||
// content is not embedded into other sites.provides protection against
|
||||
// clickjacking.
|
||||
// Optional. Default value "SAMEORIGIN".
|
||||
// Possible values:
|
||||
// - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself.
|
||||
// - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so.
|
||||
// - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin.
|
||||
XFrameOptions string `yaml:"x_frame_options"`
|
||||
// XFrameOptions can be used to indicate whether or not a browser should
|
||||
// be allowed to render a page in a <frame>, <iframe> or <object> .
|
||||
// Sites can use this to avoid clickjacking attacks, by ensuring that their
|
||||
// content is not embedded into other sites.provides protection against
|
||||
// clickjacking.
|
||||
// Optional. Default value "SAMEORIGIN".
|
||||
// Possible values:
|
||||
// - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself.
|
||||
// - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so.
|
||||
// - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin.
|
||||
XFrameOptions string `yaml:"x_frame_options"`
|
||||
|
||||
// HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
|
||||
// long (in seconds) browsers should remember that this site is only to
|
||||
// be accessed using HTTPS. This reduces your exposure to some SSL-stripping
|
||||
// man-in-the-middle (MITM) attacks.
|
||||
// Optional. Default value 0.
|
||||
HSTSMaxAge int `yaml:"hsts_max_age"`
|
||||
// HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
|
||||
// long (in seconds) browsers should remember that this site is only to
|
||||
// be accessed using HTTPS. This reduces your exposure to some SSL-stripping
|
||||
// man-in-the-middle (MITM) attacks.
|
||||
// Optional. Default value 0.
|
||||
HSTSMaxAge int `yaml:"hsts_max_age"`
|
||||
|
||||
// HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
|
||||
// header, excluding all subdomains from security policy. It has no effect
|
||||
// unless HSTSMaxAge is set to a non-zero value.
|
||||
// Optional. Default value false.
|
||||
HSTSExcludeSubdomains bool `yaml:"hsts_exclude_subdomains"`
|
||||
// HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
|
||||
// header, excluding all subdomains from security policy. It has no effect
|
||||
// unless HSTSMaxAge is set to a non-zero value.
|
||||
// Optional. Default value false.
|
||||
HSTSExcludeSubdomains bool `yaml:"hsts_exclude_subdomains"`
|
||||
|
||||
// ContentSecurityPolicy sets the `Content-Security-Policy` header providing
|
||||
// security against cross-site scripting (XSS), clickjacking and other code
|
||||
// injection attacks resulting from execution of malicious content in the
|
||||
// trusted web page context.
|
||||
// Optional. Default value "".
|
||||
ContentSecurityPolicy string `yaml:"content_security_policy"`
|
||||
// ContentSecurityPolicy sets the `Content-Security-Policy` header providing
|
||||
// security against cross-site scripting (XSS), clickjacking and other code
|
||||
// injection attacks resulting from execution of malicious content in the
|
||||
// trusted web page context.
|
||||
// Optional. Default value "".
|
||||
ContentSecurityPolicy string `yaml:"content_security_policy"`
|
||||
|
||||
// CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead
|
||||
// of the `Content-Security-Policy` header. This allows iterative updates of the
|
||||
// content security policy by only reporting the violations that would
|
||||
// have occurred instead of blocking the resource.
|
||||
// Optional. Default value false.
|
||||
CSPReportOnly bool `yaml:"csp_report_only"`
|
||||
// CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead
|
||||
// of the `Content-Security-Policy` header. This allows iterative updates of the
|
||||
// content security policy by only reporting the violations that would
|
||||
// have occurred instead of blocking the resource.
|
||||
// Optional. Default value false.
|
||||
CSPReportOnly bool `yaml:"csp_report_only"`
|
||||
|
||||
// HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security`
|
||||
// header, which enables the domain to be included in the HSTS preload list
|
||||
// maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
|
||||
// Optional. Default value false.
|
||||
HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"`
|
||||
// HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security`
|
||||
// header, which enables the domain to be included in the HSTS preload list
|
||||
// maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
|
||||
// Optional. Default value false.
|
||||
HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"`
|
||||
|
||||
// ReferrerPolicy sets the `Referrer-Policy` header providing security against
|
||||
// leaking potentially sensitive request paths to third parties.
|
||||
// Optional. Default value "".
|
||||
ReferrerPolicy string `yaml:"referrer_policy"`
|
||||
}
|
||||
)
|
||||
// ReferrerPolicy sets the `Referrer-Policy` header providing security against
|
||||
// leaking potentially sensitive request paths to third parties.
|
||||
// Optional. Default value "".
|
||||
ReferrerPolicy string `yaml:"referrer_policy"`
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultSecureConfig is the default Secure middleware config.
|
||||
DefaultSecureConfig = SecureConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
XSSProtection: "1; mode=block",
|
||||
ContentTypeNosniff: "nosniff",
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
HSTSPreloadEnabled: false,
|
||||
}
|
||||
)
|
||||
// DefaultSecureConfig is the default Secure middleware config.
|
||||
var DefaultSecureConfig = SecureConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
XSSProtection: "1; mode=block",
|
||||
ContentTypeNosniff: "nosniff",
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
HSTSPreloadEnabled: false,
|
||||
}
|
||||
|
||||
// Secure returns a Secure middleware.
|
||||
// Secure middleware provides protection against cross-site scripting (XSS) attack,
|
||||
|
31
vendor/github.com/labstack/echo/v4/middleware/slash.go
generated
vendored
31
vendor/github.com/labstack/echo/v4/middleware/slash.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -6,24 +9,20 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type (
|
||||
// TrailingSlashConfig defines the config for TrailingSlash middleware.
|
||||
TrailingSlashConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// TrailingSlashConfig defines the config for TrailingSlash middleware.
|
||||
type TrailingSlashConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Status code to be used when redirecting the request.
|
||||
// Optional, but when provided the request is redirected using this code.
|
||||
RedirectCode int `yaml:"redirect_code"`
|
||||
}
|
||||
)
|
||||
// Status code to be used when redirecting the request.
|
||||
// Optional, but when provided the request is redirected using this code.
|
||||
RedirectCode int `yaml:"redirect_code"`
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
|
||||
DefaultTrailingSlashConfig = TrailingSlashConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
)
|
||||
// DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
|
||||
var DefaultTrailingSlashConfig = TrailingSlashConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
|
||||
// AddTrailingSlash returns a root level (before router) middleware which adds a
|
||||
// trailing slash to the request `URL#Path`.
|
||||
|
69
vendor/github.com/labstack/echo/v4/middleware/static.go
generated
vendored
69
vendor/github.com/labstack/echo/v4/middleware/static.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -14,40 +17,38 @@ import (
|
||||
"github.com/labstack/gommon/bytes"
|
||||
)
|
||||
|
||||
type (
|
||||
// StaticConfig defines the config for Static middleware.
|
||||
StaticConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// StaticConfig defines the config for Static middleware.
|
||||
type StaticConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// Root directory from where the static content is served.
|
||||
// Required.
|
||||
Root string `yaml:"root"`
|
||||
// Root directory from where the static content is served.
|
||||
// Required.
|
||||
Root string `yaml:"root"`
|
||||
|
||||
// Index file for serving a directory.
|
||||
// Optional. Default value "index.html".
|
||||
Index string `yaml:"index"`
|
||||
// Index file for serving a directory.
|
||||
// Optional. Default value "index.html".
|
||||
Index string `yaml:"index"`
|
||||
|
||||
// Enable HTML5 mode by forwarding all not-found requests to root so that
|
||||
// SPA (single-page application) can handle the routing.
|
||||
// Optional. Default value false.
|
||||
HTML5 bool `yaml:"html5"`
|
||||
// Enable HTML5 mode by forwarding all not-found requests to root so that
|
||||
// SPA (single-page application) can handle the routing.
|
||||
// Optional. Default value false.
|
||||
HTML5 bool `yaml:"html5"`
|
||||
|
||||
// Enable directory browsing.
|
||||
// Optional. Default value false.
|
||||
Browse bool `yaml:"browse"`
|
||||
// Enable directory browsing.
|
||||
// Optional. Default value false.
|
||||
Browse bool `yaml:"browse"`
|
||||
|
||||
// Enable ignoring of the base of the URL path.
|
||||
// Example: when assigning a static middleware to a non root path group,
|
||||
// the filesystem path is not doubled
|
||||
// Optional. Default value false.
|
||||
IgnoreBase bool `yaml:"ignoreBase"`
|
||||
// Enable ignoring of the base of the URL path.
|
||||
// Example: when assigning a static middleware to a non root path group,
|
||||
// the filesystem path is not doubled
|
||||
// Optional. Default value false.
|
||||
IgnoreBase bool `yaml:"ignoreBase"`
|
||||
|
||||
// Filesystem provides access to the static content.
|
||||
// Optional. Defaults to http.Dir(config.Root)
|
||||
Filesystem http.FileSystem `yaml:"-"`
|
||||
}
|
||||
)
|
||||
// Filesystem provides access to the static content.
|
||||
// Optional. Defaults to http.Dir(config.Root)
|
||||
Filesystem http.FileSystem `yaml:"-"`
|
||||
}
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
@ -121,13 +122,11 @@ const html = `
|
||||
</html>
|
||||
`
|
||||
|
||||
var (
|
||||
// DefaultStaticConfig is the default Static middleware config.
|
||||
DefaultStaticConfig = StaticConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Index: "index.html",
|
||||
}
|
||||
)
|
||||
// DefaultStaticConfig is the default Static middleware config.
|
||||
var DefaultStaticConfig = StaticConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Index: "index.html",
|
||||
}
|
||||
|
||||
// Static returns a Static middleware to serves static content from the provided
|
||||
// root directory.
|
||||
|
3
vendor/github.com/labstack/echo/v4/middleware/static_other.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/middleware/static_other.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package middleware
|
||||
|
3
vendor/github.com/labstack/echo/v4/middleware/static_windows.go
generated
vendored
3
vendor/github.com/labstack/echo/v4/middleware/static_windows.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
|
17
vendor/github.com/labstack/echo/v4/middleware/timeout.go
generated
vendored
17
vendor/github.com/labstack/echo/v4/middleware/timeout.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
@ -77,14 +80,12 @@ type TimeoutConfig struct {
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultTimeoutConfig is the default Timeout middleware config.
|
||||
DefaultTimeoutConfig = TimeoutConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Timeout: 0,
|
||||
ErrorMessage: "",
|
||||
}
|
||||
)
|
||||
// DefaultTimeoutConfig is the default Timeout middleware config.
|
||||
var DefaultTimeoutConfig = TimeoutConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
Timeout: 0,
|
||||
ErrorMessage: "",
|
||||
}
|
||||
|
||||
// Timeout returns a middleware which returns error (503 Service Unavailable error) to client immediately when handler
|
||||
// call runs for longer than its time limit. NB: timeout does not stop handler execution.
|
||||
|
49
vendor/github.com/labstack/echo/v4/middleware/util.go
generated
vendored
49
vendor/github.com/labstack/echo/v4/middleware/util.go
generated
vendored
@ -1,7 +1,14 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func matchScheme(domain, pattern string) bool {
|
||||
@ -52,3 +59,45 @@ func matchSubdomain(domain, pattern string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// https://tip.golang.org/doc/go1.19#:~:text=Read%20no%20longer%20buffers%20random%20data%20obtained%20from%20the%20operating%20system%20between%20calls
|
||||
var randomReaderPool = sync.Pool{New: func() interface{} {
|
||||
return bufio.NewReader(rand.Reader)
|
||||
}}
|
||||
|
||||
const randomStringCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
const randomStringCharsetLen = 52 // len(randomStringCharset)
|
||||
const randomStringMaxByte = 255 - (256 % randomStringCharsetLen)
|
||||
|
||||
func randomString(length uint8) string {
|
||||
reader := randomReaderPool.Get().(*bufio.Reader)
|
||||
defer randomReaderPool.Put(reader)
|
||||
|
||||
b := make([]byte, length)
|
||||
r := make([]byte, length+(length/4)) // perf: avoid read from rand.Reader many times
|
||||
var i uint8 = 0
|
||||
|
||||
// security note:
|
||||
// we can't just simply do b[i]=randomStringCharset[rb%len(randomStringCharset)],
|
||||
// len(len(randomStringCharset)) is 52, and rb is [0, 255], 256 = 52 * 4 + 48.
|
||||
// make the first 48 characters more possibly to be generated then others.
|
||||
// So we have to skip bytes when rb > randomStringMaxByte
|
||||
|
||||
for {
|
||||
_, err := io.ReadFull(reader, r)
|
||||
if err != nil {
|
||||
panic("unexpected error happened when reading from bufio.NewReader(crypto/rand.Reader)")
|
||||
}
|
||||
for _, rb := range r {
|
||||
if rb > randomStringMaxByte {
|
||||
// Skip this number to avoid bias.
|
||||
continue
|
||||
}
|
||||
b[i] = randomStringCharset[rb%randomStringCharsetLen]
|
||||
i++
|
||||
if i == length {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
vendor/github.com/labstack/echo/v4/response.go
generated
vendored
44
vendor/github.com/labstack/echo/v4/response.go
generated
vendored
@ -1,25 +1,27 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// Response wraps an http.ResponseWriter and implements its interface to be used
|
||||
// by an HTTP handler to construct an HTTP response.
|
||||
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
||||
Response struct {
|
||||
echo *Echo
|
||||
beforeFuncs []func()
|
||||
afterFuncs []func()
|
||||
Writer http.ResponseWriter
|
||||
Status int
|
||||
Size int64
|
||||
Committed bool
|
||||
}
|
||||
)
|
||||
// Response wraps an http.ResponseWriter and implements its interface to be used
|
||||
// by an HTTP handler to construct an HTTP response.
|
||||
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
||||
type Response struct {
|
||||
echo *Echo
|
||||
beforeFuncs []func()
|
||||
afterFuncs []func()
|
||||
Writer http.ResponseWriter
|
||||
Status int
|
||||
Size int64
|
||||
Committed bool
|
||||
}
|
||||
|
||||
// NewResponse creates a new instance of Response.
|
||||
func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) {
|
||||
@ -84,14 +86,24 @@ func (r *Response) Write(b []byte) (n int, err error) {
|
||||
// buffered data to the client.
|
||||
// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
|
||||
func (r *Response) Flush() {
|
||||
r.Writer.(http.Flusher).Flush()
|
||||
err := responseControllerFlush(r.Writer)
|
||||
if err != nil && errors.Is(err, http.ErrNotSupported) {
|
||||
panic(errors.New("response writer flushing is not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
// Hijack implements the http.Hijacker interface to allow an HTTP handler to
|
||||
// take over the connection.
|
||||
// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
|
||||
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return r.Writer.(http.Hijacker).Hijack()
|
||||
return responseControllerHijack(r.Writer)
|
||||
}
|
||||
|
||||
// Unwrap returns the original http.ResponseWriter.
|
||||
// ResponseController can be used to access the original http.ResponseWriter.
|
||||
// See [https://go.dev/blog/go1.20]
|
||||
func (r *Response) Unwrap() http.ResponseWriter {
|
||||
return r.Writer
|
||||
}
|
||||
|
||||
func (r *Response) reset(w http.ResponseWriter) {
|
||||
|
44
vendor/github.com/labstack/echo/v4/responsecontroller_1.19.go
generated
vendored
Normal file
44
vendor/github.com/labstack/echo/v4/responsecontroller_1.19.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// TODO: remove when Go 1.23 is released and we do not support 1.19 anymore
|
||||
func responseControllerFlush(rw http.ResponseWriter) error {
|
||||
for {
|
||||
switch t := rw.(type) {
|
||||
case interface{ FlushError() error }:
|
||||
return t.FlushError()
|
||||
case http.Flusher:
|
||||
t.Flush()
|
||||
return nil
|
||||
case interface{ Unwrap() http.ResponseWriter }:
|
||||
rw = t.Unwrap()
|
||||
default:
|
||||
return fmt.Errorf("%w", http.ErrNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove when Go 1.23 is released and we do not support 1.19 anymore
|
||||
func responseControllerHijack(rw http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) {
|
||||
for {
|
||||
switch t := rw.(type) {
|
||||
case http.Hijacker:
|
||||
return t.Hijack()
|
||||
case interface{ Unwrap() http.ResponseWriter }:
|
||||
rw = t.Unwrap()
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("%w", http.ErrNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
20
vendor/github.com/labstack/echo/v4/responsecontroller_1.20.go
generated
vendored
Normal file
20
vendor/github.com/labstack/echo/v4/responsecontroller_1.20.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
//go:build go1.20
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func responseControllerFlush(rw http.ResponseWriter) error {
|
||||
return http.NewResponseController(rw).Flush()
|
||||
}
|
||||
|
||||
func responseControllerHijack(rw http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) {
|
||||
return http.NewResponseController(rw).Hijack()
|
||||
}
|
150
vendor/github.com/labstack/echo/v4/router.go
generated
vendored
150
vendor/github.com/labstack/echo/v4/router.go
generated
vendored
@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||
|
||||
package echo
|
||||
|
||||
import (
|
||||
@ -6,56 +9,58 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// Router is the registry of all registered routes for an `Echo` instance for
|
||||
// request matching and URL path parameter parsing.
|
||||
Router struct {
|
||||
tree *node
|
||||
routes map[string]*Route
|
||||
echo *Echo
|
||||
}
|
||||
node struct {
|
||||
kind kind
|
||||
label byte
|
||||
prefix string
|
||||
parent *node
|
||||
staticChildren children
|
||||
originalPath string
|
||||
methods *routeMethods
|
||||
paramChild *node
|
||||
anyChild *node
|
||||
paramsCount int
|
||||
// isLeaf indicates that node does not have child routes
|
||||
isLeaf bool
|
||||
// isHandler indicates that node has at least one handler registered to it
|
||||
isHandler bool
|
||||
// Router is the registry of all registered routes for an `Echo` instance for
|
||||
// request matching and URL path parameter parsing.
|
||||
type Router struct {
|
||||
tree *node
|
||||
routes map[string]*Route
|
||||
echo *Echo
|
||||
}
|
||||
|
||||
// notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases
|
||||
notFoundHandler *routeMethod
|
||||
}
|
||||
kind uint8
|
||||
children []*node
|
||||
routeMethod struct {
|
||||
ppath string
|
||||
pnames []string
|
||||
handler HandlerFunc
|
||||
}
|
||||
routeMethods struct {
|
||||
connect *routeMethod
|
||||
delete *routeMethod
|
||||
get *routeMethod
|
||||
head *routeMethod
|
||||
options *routeMethod
|
||||
patch *routeMethod
|
||||
post *routeMethod
|
||||
propfind *routeMethod
|
||||
put *routeMethod
|
||||
trace *routeMethod
|
||||
report *routeMethod
|
||||
anyOther map[string]*routeMethod
|
||||
allowHeader string
|
||||
}
|
||||
)
|
||||
type node struct {
|
||||
kind kind
|
||||
label byte
|
||||
prefix string
|
||||
parent *node
|
||||
staticChildren children
|
||||
originalPath string
|
||||
methods *routeMethods
|
||||
paramChild *node
|
||||
anyChild *node
|
||||
paramsCount int
|
||||
// isLeaf indicates that node does not have child routes
|
||||
isLeaf bool
|
||||
// isHandler indicates that node has at least one handler registered to it
|
||||
isHandler bool
|
||||
|
||||
// notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases
|
||||
notFoundHandler *routeMethod
|
||||
}
|
||||
|
||||
type kind uint8
|
||||
type children []*node
|
||||
|
||||
type routeMethod struct {
|
||||
ppath string
|
||||
pnames []string
|
||||
handler HandlerFunc
|
||||
}
|
||||
|
||||
type routeMethods struct {
|
||||
connect *routeMethod
|
||||
delete *routeMethod
|
||||
get *routeMethod
|
||||
head *routeMethod
|
||||
options *routeMethod
|
||||
patch *routeMethod
|
||||
post *routeMethod
|
||||
propfind *routeMethod
|
||||
put *routeMethod
|
||||
trace *routeMethod
|
||||
report *routeMethod
|
||||
anyOther map[string]*routeMethod
|
||||
allowHeader string
|
||||
}
|
||||
|
||||
const (
|
||||
staticKind kind = iota
|
||||
@ -151,7 +156,7 @@ func (r *Router) Routes() []*Route {
|
||||
return routes
|
||||
}
|
||||
|
||||
// Reverse generates an URL from route name and provided parameters.
|
||||
// Reverse generates a URL from route name and provided parameters.
|
||||
func (r *Router) Reverse(name string, params ...interface{}) string {
|
||||
uri := new(bytes.Buffer)
|
||||
ln := len(params)
|
||||
@ -159,7 +164,12 @@ func (r *Router) Reverse(name string, params ...interface{}) string {
|
||||
for _, route := range r.routes {
|
||||
if route.Name == name {
|
||||
for i, l := 0, len(route.Path); i < l; i++ {
|
||||
if (route.Path[i] == ':' || route.Path[i] == '*') && n < ln {
|
||||
hasBackslash := route.Path[i] == '\\'
|
||||
if hasBackslash && i+1 < l && route.Path[i+1] == ':' {
|
||||
i++ // backslash before colon escapes that colon. in that case skip backslash
|
||||
}
|
||||
if n < ln && (route.Path[i] == '*' || (!hasBackslash && route.Path[i] == ':')) {
|
||||
// in case of `*` wildcard or `:` (unescaped colon) param we replace everything till next slash or end of path
|
||||
for ; i < l && route.Path[i] != '/'; i++ {
|
||||
}
|
||||
uri.WriteString(fmt.Sprintf("%v", params[n]))
|
||||
@ -175,8 +185,18 @@ func (r *Router) Reverse(name string, params ...interface{}) string {
|
||||
return uri.String()
|
||||
}
|
||||
|
||||
func normalizePathSlash(path string) string {
|
||||
if path == "" {
|
||||
path = "/"
|
||||
} else if path[0] != '/' {
|
||||
path = "/" + path
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
|
||||
r.Add(method, path, h)
|
||||
path = normalizePathSlash(path)
|
||||
r.insert(method, path, h)
|
||||
|
||||
route := &Route{
|
||||
Method: method,
|
||||
@ -189,13 +209,11 @@ func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
|
||||
|
||||
// Add registers a new route for method and path with matching handler.
|
||||
func (r *Router) Add(method, path string, h HandlerFunc) {
|
||||
// Validate path
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
if path[0] != '/' {
|
||||
path = "/" + path
|
||||
}
|
||||
r.insert(method, normalizePathSlash(path), h)
|
||||
}
|
||||
|
||||
func (r *Router) insert(method, path string, h HandlerFunc) {
|
||||
path = normalizePathSlash(path)
|
||||
pnames := []string{} // Param names
|
||||
ppath := path // Pristine path
|
||||
|
||||
@ -214,7 +232,7 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
|
||||
}
|
||||
j := i + 1
|
||||
|
||||
r.insert(method, path[:i], staticKind, routeMethod{})
|
||||
r.insertNode(method, path[:i], staticKind, routeMethod{})
|
||||
for ; i < lcpIndex && path[i] != '/'; i++ {
|
||||
}
|
||||
|
||||
@ -224,21 +242,21 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
|
||||
|
||||
if i == lcpIndex {
|
||||
// path node is last fragment of route path. ie. `/users/:id`
|
||||
r.insert(method, path[:i], paramKind, routeMethod{ppath, pnames, h})
|
||||
r.insertNode(method, path[:i], paramKind, routeMethod{ppath, pnames, h})
|
||||
} else {
|
||||
r.insert(method, path[:i], paramKind, routeMethod{})
|
||||
r.insertNode(method, path[:i], paramKind, routeMethod{})
|
||||
}
|
||||
} else if path[i] == '*' {
|
||||
r.insert(method, path[:i], staticKind, routeMethod{})
|
||||
r.insertNode(method, path[:i], staticKind, routeMethod{})
|
||||
pnames = append(pnames, "*")
|
||||
r.insert(method, path[:i+1], anyKind, routeMethod{ppath, pnames, h})
|
||||
r.insertNode(method, path[:i+1], anyKind, routeMethod{ppath, pnames, h})
|
||||
}
|
||||
}
|
||||
|
||||
r.insert(method, path, staticKind, routeMethod{ppath, pnames, h})
|
||||
r.insertNode(method, path, staticKind, routeMethod{ppath, pnames, h})
|
||||
}
|
||||
|
||||
func (r *Router) insert(method, path string, t kind, rm routeMethod) {
|
||||
func (r *Router) insertNode(method, path string, t kind, rm routeMethod) {
|
||||
// Adjust max param
|
||||
paramLen := len(rm.pnames)
|
||||
if *r.echo.maxParam < paramLen {
|
||||
|
48
vendor/github.com/labstack/gommon/random/random.go
generated
vendored
48
vendor/github.com/labstack/gommon/random/random.go
generated
vendored
@ -1,48 +0,0 @@
|
||||
package random
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
Random struct {
|
||||
}
|
||||
)
|
||||
|
||||
// Charsets
|
||||
const (
|
||||
Uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
Lowercase = "abcdefghijklmnopqrstuvwxyz"
|
||||
Alphabetic = Uppercase + Lowercase
|
||||
Numeric = "0123456789"
|
||||
Alphanumeric = Alphabetic + Numeric
|
||||
Symbols = "`" + `~!@#$%^&*()-_+={}[]|\;:"<>,./?`
|
||||
Hex = Numeric + "abcdef"
|
||||
)
|
||||
|
||||
var (
|
||||
global = New()
|
||||
)
|
||||
|
||||
func New() *Random {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return new(Random)
|
||||
}
|
||||
|
||||
func (r *Random) String(length uint8, charsets ...string) string {
|
||||
charset := strings.Join(charsets, "")
|
||||
if charset == "" {
|
||||
charset = Alphanumeric
|
||||
}
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.Int63()%int64(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func String(length uint8, charsets ...string) string {
|
||||
return global.String(length, charsets...)
|
||||
}
|
4
vendor/github.com/likexian/gokit/LICENSE
generated
vendored
4
vendor/github.com/likexian/gokit/LICENSE
generated
vendored
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2012-2023 Li Kexian
|
||||
Copyright 2012-2024 Li Kexian
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -200,6 +200,6 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
APPENDIX: Copyright 2012-2023 Li Kexian
|
||||
APPENDIX: Copyright 2012-2024 Li Kexian
|
||||
|
||||
https://www.likexian.com/
|
||||
|
2
vendor/github.com/likexian/gokit/assert/README.md
generated
vendored
2
vendor/github.com/likexian/gokit/assert/README.md
generated
vendored
@ -85,7 +85,7 @@ b := assert.If(a == 1, true, false)
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2012-2023 [Li Kexian](https://www.likexian.com/)
|
||||
Copyright 2012-2024 [Li Kexian](https://www.likexian.com/)
|
||||
|
||||
Licensed under the Apache License 2.0
|
||||
|
||||
|
2
vendor/github.com/likexian/gokit/assert/assert.go
generated
vendored
2
vendor/github.com/likexian/gokit/assert/assert.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 Li Kexian
|
||||
* Copyright 2012-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
2
vendor/github.com/likexian/gokit/assert/values.go
generated
vendored
2
vendor/github.com/likexian/gokit/assert/values.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 Li Kexian
|
||||
* Copyright 2012-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
54
vendor/github.com/likexian/gokit/xrand/README.md
generated
vendored
Normal file
54
vendor/github.com/likexian/gokit/xrand/README.md
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# GoKit - xrand
|
||||
|
||||
Rand kits for Golang development.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/likexian/gokit
|
||||
|
||||
## Importing
|
||||
|
||||
import (
|
||||
"github.com/likexian/gokit/xrand"
|
||||
)
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit the docs on [GoDoc](https://godoc.org/github.com/likexian/gokit/xrand)
|
||||
|
||||
## Example
|
||||
|
||||
### Rand int between 0 and 10000
|
||||
|
||||
```go
|
||||
n := xrand.Int(10000)
|
||||
fmt.Println("rand int between 0 and 10000 is:", n)
|
||||
```
|
||||
|
||||
### Rand int between 1000 and 10000
|
||||
|
||||
```go
|
||||
n := xrand.IntRange(1000, 10000)
|
||||
fmt.Println("rand int between 1000 and 10000 is:", n)
|
||||
```
|
||||
|
||||
### Rand bytes with length of 10
|
||||
|
||||
```go
|
||||
b, err := xrand.Bytes(10)
|
||||
if err != nil {
|
||||
fmt.Println("rand bytes:", b)
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2012-2024 [Li Kexian](https://www.likexian.com/)
|
||||
|
||||
Licensed under the Apache License 2.0
|
||||
|
||||
## Donation
|
||||
|
||||
If this project is helpful, please share it with friends.
|
||||
|
||||
If you want to thank me, you can [give me a cup of coffee](https://www.likexian.com/donate/).
|
115
vendor/github.com/likexian/gokit/xrand/xrand.go
generated
vendored
Normal file
115
vendor/github.com/likexian/gokit/xrand/xrand.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* A toolkit for Golang development
|
||||
* https://www.likexian.com/
|
||||
*/
|
||||
|
||||
package xrand
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Version returns package version
|
||||
func Version() string {
|
||||
return "0.2.0"
|
||||
}
|
||||
|
||||
// Author returns package author
|
||||
func Author() string {
|
||||
return "[Li Kexian](https://www.likexian.com/)"
|
||||
}
|
||||
|
||||
// License returns package license
|
||||
func License() string {
|
||||
return "Licensed under the Apache License 2.0"
|
||||
}
|
||||
|
||||
// Int returns random int in [0, max)
|
||||
func Int(max int) int {
|
||||
if max <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
seed := rand.NewSource(time.Now().UnixNano())
|
||||
|
||||
return rand.New(seed).Intn(max)
|
||||
}
|
||||
|
||||
// IntRange returns random int in [min, max)
|
||||
func IntRange(min, max int) int {
|
||||
if min > max {
|
||||
min, max = max, min
|
||||
}
|
||||
|
||||
return Int(max-min) + min
|
||||
}
|
||||
|
||||
// String returns n random string from 0-9,a-z,A-Z
|
||||
func String(n int) string {
|
||||
sources := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
return StringRange(n, sources)
|
||||
}
|
||||
|
||||
// StringRange returns n random string base on source
|
||||
func StringRange(n int, source string) string {
|
||||
if source == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
ss := []rune(source)
|
||||
bs := make([]rune, n)
|
||||
for i := range bs {
|
||||
bs[i] = ss[Int(len(ss))]
|
||||
}
|
||||
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// Bytes returns n random bytes
|
||||
func Bytes(n int) (bs []byte, err error) {
|
||||
bs = make([]byte, n)
|
||||
_, err = crand.Read(bs)
|
||||
return
|
||||
}
|
||||
|
||||
// Hex returns hex string of n random bytes
|
||||
func Hex(n int) (ss string, err error) {
|
||||
bs, err := Bytes(n)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ss = hex.EncodeToString(bs)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Base64 returns base64 string of n random bytes
|
||||
func Base64(n int) (ss string, err error) {
|
||||
bs, err := Bytes(n)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ss = base64.StdEncoding.EncodeToString(bs)
|
||||
|
||||
return
|
||||
}
|
2
vendor/github.com/likexian/gokit/xslice/README.md
generated
vendored
2
vendor/github.com/likexian/gokit/xslice/README.md
generated
vendored
@ -34,7 +34,7 @@ fmt.Println("new array:", array)
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2012-2023 [Li Kexian](https://www.likexian.com/)
|
||||
Copyright 2012-2024 [Li Kexian](https://www.likexian.com/)
|
||||
|
||||
Licensed under the Apache License 2.0
|
||||
|
||||
|
9
vendor/github.com/likexian/gokit/xslice/xslice.go
generated
vendored
9
vendor/github.com/likexian/gokit/xslice/xslice.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 Li Kexian
|
||||
* Copyright 2012-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -22,13 +22,14 @@ package xslice
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
|
||||
"github.com/likexian/gokit/xrand"
|
||||
)
|
||||
|
||||
// Version returns package version
|
||||
func Version() string {
|
||||
return "0.22.0"
|
||||
return "0.23.0"
|
||||
}
|
||||
|
||||
// Author returns package author
|
||||
@ -209,7 +210,7 @@ func Shuffle(v interface{}) {
|
||||
|
||||
swap := reflect.Swapper(v)
|
||||
for i := vv.Len() - 1; i >= 1; i-- {
|
||||
j := rand.Intn(i + 1)
|
||||
j := xrand.Int(i + 1)
|
||||
swap(i, j)
|
||||
}
|
||||
}
|
||||
|
4
vendor/github.com/likexian/whois-parser/LICENSE
generated
vendored
4
vendor/github.com/likexian/whois-parser/LICENSE
generated
vendored
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014-2023 Li Kexian
|
||||
Copyright 2014-2024 Li Kexian
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -200,6 +200,6 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
APPENDIX: Copyright 2014-2023 Li Kexian
|
||||
APPENDIX: Copyright 2014-2024 Li Kexian
|
||||
|
||||
https://www.likexian.com/
|
||||
|
2
vendor/github.com/likexian/whois-parser/README.md
generated
vendored
2
vendor/github.com/likexian/whois-parser/README.md
generated
vendored
@ -71,7 +71,7 @@ Please refer to [whois](https://github.com/likexian/whois)
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2014-2023 [Li Kexian](https://www.likexian.com/)
|
||||
Copyright 2014-2024 [Li Kexian](https://www.likexian.com/)
|
||||
|
||||
Licensed under the Apache License 2.0
|
||||
|
||||
|
3
vendor/github.com/likexian/whois-parser/error.go
generated
vendored
3
vendor/github.com/likexian/whois-parser/error.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -66,6 +66,7 @@ func isNotFoundDomain(data string) bool {
|
||||
"no match",
|
||||
"not found",
|
||||
"not match",
|
||||
"not available",
|
||||
"no data found",
|
||||
"nothing found",
|
||||
"no entries found",
|
||||
|
10
vendor/github.com/likexian/whois-parser/parser.go
generated
vendored
10
vendor/github.com/likexian/whois-parser/parser.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -30,7 +30,7 @@ import (
|
||||
|
||||
// Version returns package version
|
||||
func Version() string {
|
||||
return "1.24.1"
|
||||
return "1.24.18"
|
||||
}
|
||||
|
||||
// Author returns package author
|
||||
@ -153,6 +153,8 @@ func Parse(text string) (whoisInfo WhoisInfo, err error) { //nolint:cyclop
|
||||
if !strings.Contains(name, " ") {
|
||||
if name == "registrar" {
|
||||
name += " name"
|
||||
} else if domain.Extension == "dk" {
|
||||
name = "registrant " + name
|
||||
} else {
|
||||
name += " organization"
|
||||
}
|
||||
@ -244,9 +246,9 @@ func parseContact(contact *Contact, name, value string) {
|
||||
}
|
||||
|
||||
var searchDomainRx1 = regexp.MustCompile(`(?i)\[?domain\:?(\s*\_?name)?\]?[\s\.]*\:?` +
|
||||
`\s*([^\s\,\;\(\)]+)\.([^\s\,\;\(\)\.]{2,})`)
|
||||
`\s*([^\s\,\;\@\(\)]+)\.([^\s\,\;\(\)\.]{2,})`)
|
||||
var searchDomainRx2 = regexp.MustCompile(`(?i)\[?domain\:?(\s*\_?name)?\]?[\s\.]*\:?` +
|
||||
`\s*([^\s\,\;\(\)\.]{2,})\n`)
|
||||
`\s*([^\s\,\;\@\(\)\.]{2,})\n`)
|
||||
|
||||
// searchDomain finds domain name and extension from whois information
|
||||
func searchDomain(text string) (name, extension string) {
|
||||
|
128
vendor/github.com/likexian/whois-parser/prepare.go
generated
vendored
128
vendor/github.com/likexian/whois-parser/prepare.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -91,6 +91,8 @@ func Prepare(text, ext string) (string, bool) { //nolint:cyclop
|
||||
return prepareBY(text), true
|
||||
case "ua":
|
||||
return prepareUA(text), true
|
||||
case "at":
|
||||
return prepareAT(text), true
|
||||
default:
|
||||
return text, false
|
||||
}
|
||||
@ -685,7 +687,7 @@ func prepareRU(text string) string {
|
||||
return result
|
||||
}
|
||||
|
||||
var prepareJPreplacerRx = regexp.MustCompile(`\n\[(.+?)\][\ ]*(.+?)?`)
|
||||
var prepareJPreplacerRx = regexp.MustCompile(`\n(?:\w+\.\s)?\[(.+?)\][\ ]*(.+?)?`)
|
||||
|
||||
// prepareJP do prepare the .jp domain
|
||||
func prepareJP(text string) string {
|
||||
@ -712,6 +714,7 @@ func prepareJP(text string) string {
|
||||
if strings.ToLower(token) == "registrant" {
|
||||
v = fmt.Sprintf("registrant name: %s", vs[1])
|
||||
}
|
||||
v = prepareSecondLevelJP(v, token, vs[1])
|
||||
} else {
|
||||
if token == addressToken {
|
||||
result += ", " + v
|
||||
@ -724,6 +727,29 @@ func prepareJP(text string) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// prepareJP prepares specific mappings for second level .jp domains
|
||||
// examples include:
|
||||
// - co.jp
|
||||
// - ac.jp
|
||||
// - go.jp
|
||||
// - or.jp
|
||||
// - ad.jp
|
||||
// - ne.jp
|
||||
// - gr.jp
|
||||
// - ed.jp
|
||||
func prepareSecondLevelJP(original string, token string, value string) string {
|
||||
if strings.ToLower(token) == "administrative contact" {
|
||||
return fmt.Sprintf("Administrative Contact ID: %s", strings.TrimSpace(value))
|
||||
}
|
||||
if strings.ToLower(token) == "technical contact" {
|
||||
return fmt.Sprintf("Technical Contact ID: %s", strings.TrimSpace(value))
|
||||
}
|
||||
if strings.ToLower(token) == "organization" || strings.ToLower(token) == "network service name" {
|
||||
return fmt.Sprintf("Registrant Organization: %s", strings.TrimSpace(value))
|
||||
}
|
||||
return original
|
||||
}
|
||||
|
||||
// prepareUK do prepare the .uk domain
|
||||
func prepareUK(text string) string {
|
||||
tokens := map[string]string{
|
||||
@ -929,16 +955,15 @@ func prepareEU(text string) string {
|
||||
if _, ok := tokens[v]; ok {
|
||||
token = tokens[v]
|
||||
continue
|
||||
} else {
|
||||
if token != "" {
|
||||
if strings.Contains(v, ":") {
|
||||
v = fmt.Sprintf("%s %s", token, v)
|
||||
} else {
|
||||
if strings.HasPrefix(v, "Visit www.eurid.eu") {
|
||||
continue
|
||||
}
|
||||
v = fmt.Sprintf("%s: %s", token, v)
|
||||
}
|
||||
if token != "" {
|
||||
if strings.Contains(v, ":") {
|
||||
v = fmt.Sprintf("%s %s", token, v)
|
||||
} else {
|
||||
if strings.HasPrefix(v, "Visit www.eurid.eu") {
|
||||
continue
|
||||
}
|
||||
v = fmt.Sprintf("%s: %s", token, v)
|
||||
}
|
||||
}
|
||||
result += "\n" + v
|
||||
@ -1155,9 +1180,8 @@ func prepareEE(text string) string {
|
||||
if t, ok := tokens[v]; ok {
|
||||
token = t
|
||||
continue
|
||||
} else {
|
||||
v = fmt.Sprintf("%s %s", token, v)
|
||||
}
|
||||
v = fmt.Sprintf("%s %s", token, v)
|
||||
result += "\n" + strings.TrimSpace(v)
|
||||
}
|
||||
|
||||
@ -1194,9 +1218,8 @@ func preparePL(text string) string {
|
||||
ns := strings.SplitN(v, "[", 2)
|
||||
result += fmt.Sprintf("\nnameservers: %s", strings.TrimSpace(ns[0]))
|
||||
continue
|
||||
} else {
|
||||
special = ""
|
||||
}
|
||||
special = ""
|
||||
} else if special == "REGISTRAR" {
|
||||
if strings.TrimSpace(v) == "" {
|
||||
special = ""
|
||||
@ -1338,3 +1361,78 @@ func prepareUA(text string) string {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// prepareAT prepares the .at domain
|
||||
func prepareAT(text string) string {
|
||||
result := ""
|
||||
registrantID := ""
|
||||
techID := ""
|
||||
|
||||
tokens := map[string]string{
|
||||
"street address": "address",
|
||||
"postal code": "address",
|
||||
"city": "address",
|
||||
"country": "address",
|
||||
"e-mail": "email",
|
||||
"nic-hdl": "id",
|
||||
"personname": "name",
|
||||
}
|
||||
|
||||
formatLine := func(line, token string) string {
|
||||
before, after, _ := strings.Cut(line, ":")
|
||||
key := strings.TrimSpace(before)
|
||||
if t, ok := tokens[key]; ok {
|
||||
key = t
|
||||
}
|
||||
val := strings.TrimSpace(after)
|
||||
return fmt.Sprintf("%s %s: %s", token, key, val)
|
||||
}
|
||||
|
||||
for _, v := range strings.Split(text, "\n\n") {
|
||||
v = strings.TrimSpace(v)
|
||||
if strings.HasPrefix(v, "%") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(v, ":") {
|
||||
b := strings.Split(v, "\n")
|
||||
if strings.HasPrefix(b[0], "domain") {
|
||||
for _, l := range b {
|
||||
w := ""
|
||||
if before, after, ok := strings.Cut(l, ":"); ok {
|
||||
key := strings.TrimSpace(before)
|
||||
val := strings.TrimSpace(after)
|
||||
switch key {
|
||||
case "domain":
|
||||
w = fmt.Sprintf("%s: %s", "domain name", val)
|
||||
case "registrant":
|
||||
registrantID = val
|
||||
case "tech-c":
|
||||
techID = val
|
||||
case "changed":
|
||||
w = fmt.Sprintf("%s: %s", "updated_date", val)
|
||||
case "nserver":
|
||||
w = fmt.Sprintf("%s: %s", "name_servers", val)
|
||||
default:
|
||||
w = fmt.Sprintf("domain %s: %s", key, val)
|
||||
}
|
||||
if w != "" {
|
||||
result += w + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if strings.HasPrefix(b[0], "personname") {
|
||||
token := ""
|
||||
if strings.Contains(v, registrantID) {
|
||||
token = "registrant"
|
||||
} else if strings.Contains(v, techID) {
|
||||
token = "technical contact"
|
||||
}
|
||||
for _, l := range strings.Split(v, "\n") {
|
||||
result += formatLine(l, token) + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
6
vendor/github.com/likexian/whois-parser/rule.go
generated
vendored
6
vendor/github.com/likexian/whois-parser/rule.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -68,9 +68,9 @@ var (
|
||||
"registration time": "created_date",
|
||||
"first registration date": "created_date",
|
||||
"domain record activated": "created_date",
|
||||
"record created": "created_date",
|
||||
"record created on": "created_date",
|
||||
"domain registered": "created_date",
|
||||
"record created": "created_date",
|
||||
"modified": "updated_date",
|
||||
"changed": "updated_date",
|
||||
"update date": "updated_date",
|
||||
@ -152,7 +152,9 @@ var (
|
||||
"registrant contact state province": "registrant_state_province",
|
||||
"registrant zipcode": "registrant_postal_code",
|
||||
"registrant zip code": "registrant_postal_code",
|
||||
"registrant postalcode": "registrant_postal_code",
|
||||
"registrant postal code": "registrant_postal_code",
|
||||
"registrant contact postalcode": "registrant_postal_code",
|
||||
"registrant contact postal code": "registrant_postal_code",
|
||||
"registrant country": "registrant_country",
|
||||
"registrant country economy": "registrant_country",
|
||||
|
2
vendor/github.com/likexian/whois-parser/struct.go
generated
vendored
2
vendor/github.com/likexian/whois-parser/struct.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
22
vendor/github.com/likexian/whois-parser/util.go
generated
vendored
22
vendor/github.com/likexian/whois-parser/util.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -73,6 +73,9 @@ func fixDomainStatus(status []string) []string {
|
||||
for k, v := range status {
|
||||
names := strings.Split(strings.TrimSpace(v), " ")
|
||||
status[k] = strings.ToLower(names[0])
|
||||
if status[k] == "not" && len(names) > 1 && strings.ToLower(names[1]) == "delegated" {
|
||||
status[k] = "not delegated"
|
||||
}
|
||||
}
|
||||
|
||||
return status
|
||||
@ -115,16 +118,20 @@ func keys(m map[string]string) []string {
|
||||
// parseDateString attempts to parse a given date using a collection of common
|
||||
// format strings. Date formats containing time components are tried first
|
||||
// before attempts are made using date-only formats.
|
||||
func parseDateString(dateString string) (time.Time, error) {
|
||||
formats := [...]string{
|
||||
func parseDateString(datetime string) (time.Time, error) {
|
||||
datetime = strings.Trim(datetime, ".")
|
||||
datetime = strings.ReplaceAll(datetime, ". ", "-")
|
||||
|
||||
formats := [...]string{
|
||||
// Date & time formats
|
||||
"2006-01-02 15:04:05",
|
||||
"2006.01.02 15:04:05",
|
||||
"02/01/2006 15:04:05",
|
||||
"02.01.2006 15:04:05",
|
||||
"02.1.2006 15:04:05",
|
||||
"2.1.2006 15:04:05",
|
||||
"02-Jan-2006 15:04:05",
|
||||
"20060102 15:04:05",
|
||||
time.ANSIC,
|
||||
time.Stamp,
|
||||
time.StampMilli,
|
||||
@ -148,24 +155,25 @@ func parseDateString(dateString string) (time.Time, error) {
|
||||
|
||||
// Date only formats
|
||||
"2006-01-02",
|
||||
"2006. 01. 02.",
|
||||
"02-Jan-2006",
|
||||
"02.01.2006",
|
||||
"02-01-2006",
|
||||
"January _2 2006",
|
||||
"Mon Jan _2 2006",
|
||||
"02/01/2006",
|
||||
"01/02/2006",
|
||||
"2006/01/02",
|
||||
"2006-Jan-02",
|
||||
"2006-Jan-02.",
|
||||
"before Jan-2006",
|
||||
}
|
||||
|
||||
for _, format := range formats {
|
||||
result, err := time.Parse(format, dateString)
|
||||
result, err := time.Parse(format, datetime)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return time.Now(), fmt.Errorf("could not parse %s as a date", dateString)
|
||||
return time.Now(), fmt.Errorf("could not parse %s as a date", datetime)
|
||||
}
|
||||
|
1
vendor/github.com/likexian/whois/.gitignore
generated
vendored
1
vendor/github.com/likexian/whois/.gitignore
generated
vendored
@ -1 +1,2 @@
|
||||
.DS_Store
|
||||
.idea
|
||||
|
4
vendor/github.com/likexian/whois/LICENSE
generated
vendored
4
vendor/github.com/likexian/whois/LICENSE
generated
vendored
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014-2023 Li Kexian
|
||||
Copyright 2014-2024 Li Kexian
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -200,6 +200,6 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
APPENDIX: Copyright 2014-2023 Li Kexian
|
||||
APPENDIX: Copyright 2014-2024 Li Kexian
|
||||
|
||||
https://www.likexian.com/
|
||||
|
2
vendor/github.com/likexian/whois/README.md
generated
vendored
2
vendor/github.com/likexian/whois/README.md
generated
vendored
@ -79,7 +79,7 @@ Please refer to [whois-parser](https://github.com/likexian/whois-parser)
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2014-2023 [Li Kexian](https://www.likexian.com/)
|
||||
Copyright 2014-2024 [Li Kexian](https://www.likexian.com/)
|
||||
|
||||
Licensed under the Apache License 2.0
|
||||
|
||||
|
2
vendor/github.com/likexian/whois/error.go
generated
vendored
2
vendor/github.com/likexian/whois/error.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
46
vendor/github.com/likexian/whois/whois.go
generated
vendored
46
vendor/github.com/likexian/whois/whois.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 Li Kexian
|
||||
* Copyright 2014-2024 Li Kexian
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -46,14 +46,16 @@ var DefaultClient = NewClient()
|
||||
|
||||
// Client is whois client
|
||||
type Client struct {
|
||||
dialer proxy.Dialer
|
||||
timeout time.Duration
|
||||
elapsed time.Duration
|
||||
dialer proxy.Dialer
|
||||
timeout time.Duration
|
||||
elapsed time.Duration
|
||||
disableStats bool
|
||||
disableReferral bool
|
||||
}
|
||||
|
||||
// Version returns package version
|
||||
func Version() string {
|
||||
return "1.14.5"
|
||||
return "1.15.4"
|
||||
}
|
||||
|
||||
// Author returns package author
|
||||
@ -82,24 +84,39 @@ func NewClient() *Client {
|
||||
}
|
||||
|
||||
// SetDialer set query net dialer
|
||||
func (c *Client) SetDialer(dialer proxy.Dialer) {
|
||||
func (c *Client) SetDialer(dialer proxy.Dialer) *Client {
|
||||
c.dialer = dialer
|
||||
return c
|
||||
}
|
||||
|
||||
// SetTimeout set query timeout
|
||||
func (c *Client) SetTimeout(timeout time.Duration) {
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.timeout = timeout
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDisableStats set disable stats
|
||||
func (c *Client) SetDisableStats(disabled bool) *Client {
|
||||
c.disableStats = disabled
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDisableReferral if set to true, will not query the referral server.
|
||||
func (c *Client) SetDisableReferral(disabled bool) *Client {
|
||||
c.disableReferral = disabled
|
||||
return c
|
||||
}
|
||||
|
||||
// Whois do the whois query and returns whois information
|
||||
func (c *Client) Whois(domain string, servers ...string) (result string, err error) {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
result = fmt.Sprintf("%s\n\n;; Query time: %d msec\n;; WHEN: %s\n",
|
||||
strings.TrimRight(result, "\n"),
|
||||
time.Since(start).Milliseconds(),
|
||||
start.Format("Mon Jan 02 15:04:05 MST 2006"),
|
||||
)
|
||||
result = strings.TrimSpace(result)
|
||||
if result != "" && !c.disableStats {
|
||||
result = fmt.Sprintf("%s\n\n%% Query time: %d msec\n%% WHEN: %s\n",
|
||||
result, time.Since(start).Milliseconds(), start.Format("Mon Jan 02 15:04:05 MST 2006"),
|
||||
)
|
||||
}
|
||||
}()
|
||||
|
||||
domain = strings.Trim(strings.TrimSpace(domain), ".")
|
||||
@ -139,6 +156,10 @@ func (c *Client) Whois(domain string, servers ...string) (result string, err err
|
||||
return
|
||||
}
|
||||
|
||||
if c.disableReferral {
|
||||
return
|
||||
}
|
||||
|
||||
refServer, refPort := getServer(result)
|
||||
if refServer == "" || refServer == server {
|
||||
return
|
||||
@ -170,6 +191,7 @@ func (c *Client) rawQuery(domain, server, port string) (string, error) {
|
||||
server = "whois.godaddy.com"
|
||||
}
|
||||
|
||||
// See: https://github.com/likexian/whois/pull/30
|
||||
if server == "porkbun.com/whois" {
|
||||
server = "whois.porkbun.com"
|
||||
}
|
||||
|
3
vendor/github.com/mattn/go-isatty/isatty_bsd.go
generated
vendored
3
vendor/github.com/mattn/go-isatty/isatty_bsd.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine
|
||||
//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine && !tinygo
|
||||
// +build darwin freebsd openbsd netbsd dragonfly hurd
|
||||
// +build !appengine
|
||||
// +build !tinygo
|
||||
|
||||
package isatty
|
||||
|
||||
|
5
vendor/github.com/mattn/go-isatty/isatty_others.go
generated
vendored
5
vendor/github.com/mattn/go-isatty/isatty_others.go
generated
vendored
@ -1,5 +1,6 @@
|
||||
//go:build appengine || js || nacl || wasm
|
||||
// +build appengine js nacl wasm
|
||||
//go:build (appengine || js || nacl || tinygo || wasm) && !windows
|
||||
// +build appengine js nacl tinygo wasm
|
||||
// +build !windows
|
||||
|
||||
package isatty
|
||||
|
||||
|
3
vendor/github.com/mattn/go-isatty/isatty_tcgets.go
generated
vendored
3
vendor/github.com/mattn/go-isatty/isatty_tcgets.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
//go:build (linux || aix || zos) && !appengine
|
||||
//go:build (linux || aix || zos) && !appengine && !tinygo
|
||||
// +build linux aix zos
|
||||
// +build !appengine
|
||||
// +build !tinygo
|
||||
|
||||
package isatty
|
||||
|
||||
|
610
vendor/github.com/oschwald/geoip2-golang/.golangci.toml
generated
vendored
610
vendor/github.com/oschwald/geoip2-golang/.golangci.toml
generated
vendored
@ -1,472 +1,192 @@
|
||||
[run]
|
||||
deadline = "10m"
|
||||
|
||||
tests = true
|
||||
# This is needed for precious, which may run multiple instances
|
||||
# in parallel
|
||||
allow-parallel-runners = true
|
||||
go = "1.21"
|
||||
tests = true
|
||||
timeout = "10m"
|
||||
|
||||
[linters]
|
||||
disable-all = true
|
||||
enable = [
|
||||
"asciicheck",
|
||||
"bidichk",
|
||||
"bodyclose",
|
||||
"containedctx",
|
||||
"contextcheck",
|
||||
"deadcode",
|
||||
enable-all = true
|
||||
disable = [
|
||||
"cyclop",
|
||||
"depguard",
|
||||
"durationcheck",
|
||||
"errcheck",
|
||||
"errchkjson",
|
||||
"errname",
|
||||
"errorlint",
|
||||
"exportloopref",
|
||||
"forbidigo",
|
||||
#"forcetypeassert",
|
||||
"goconst",
|
||||
"gocyclo",
|
||||
"gocritic",
|
||||
"godot",
|
||||
"gofumpt",
|
||||
"gomodguard",
|
||||
"gosec",
|
||||
"gosimple",
|
||||
"govet",
|
||||
"grouper",
|
||||
"ineffassign",
|
||||
"lll",
|
||||
"makezero",
|
||||
"maintidx",
|
||||
"misspell",
|
||||
"nakedret",
|
||||
"nilerr",
|
||||
"noctx",
|
||||
"nolintlint",
|
||||
"nosprintfhostport",
|
||||
"predeclared",
|
||||
"revive",
|
||||
"rowserrcheck",
|
||||
"sqlclosecheck",
|
||||
"staticcheck",
|
||||
"structcheck",
|
||||
"stylecheck",
|
||||
"tenv",
|
||||
"tparallel",
|
||||
"typecheck",
|
||||
"unconvert",
|
||||
"unparam",
|
||||
"unused",
|
||||
"varcheck",
|
||||
"vetshadow",
|
||||
"wastedassign",
|
||||
]
|
||||
"err113",
|
||||
"execinquery",
|
||||
"exhaustive",
|
||||
"exhaustruct",
|
||||
"forcetypeassert",
|
||||
"funlen",
|
||||
"gochecknoglobals",
|
||||
"godox",
|
||||
"gomnd",
|
||||
"inamedparam",
|
||||
"interfacebloat",
|
||||
"mnd",
|
||||
"nlreturn",
|
||||
"nonamedreturns",
|
||||
"paralleltest",
|
||||
"thelper",
|
||||
"testpackage",
|
||||
|
||||
# Please note that we only use depguard for stdlib as gomodguard only
|
||||
# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12
|
||||
[linters-settings.depguard]
|
||||
list-type = "blacklist"
|
||||
include-go-root = true
|
||||
packages = [
|
||||
# ioutil is deprecated. The functions have been moved elsewhere:
|
||||
# https://golang.org/doc/go1.16#ioutil
|
||||
"io/ioutil",
|
||||
]
|
||||
"varnamelen",
|
||||
"wrapcheck",
|
||||
"wsl",
|
||||
|
||||
[linters-settings.errcheck]
|
||||
# Don't allow setting of error to the blank identifier. If there is a legtimate
|
||||
# reason, there should be a nolint with an explanation.
|
||||
check-blank = true
|
||||
|
||||
exclude-functions = [
|
||||
# If we are rolling back a transaction, we are often already in an error
|
||||
# state.
|
||||
'(*database/sql.Tx).Rollback',
|
||||
|
||||
# It is reasonable to ignore errors if Cleanup fails in most cases.
|
||||
'(*github.com/google/renameio/v2.PendingFile).Cleanup',
|
||||
|
||||
# We often don't care if removing a file failed (e.g., it doesn't exist)
|
||||
'os.Remove',
|
||||
'os.RemoveAll',
|
||||
]
|
||||
|
||||
# Ignoring Close so that we don't have to have a bunch of
|
||||
# `defer func() { _ = r.Close() }()` constructs when we
|
||||
# don't actually care about the error.
|
||||
ignore = "Close,fmt:.*"
|
||||
# Require Go 1.22
|
||||
"copyloopvar",
|
||||
"intrange",
|
||||
]
|
||||
|
||||
[linters-settings.errorlint]
|
||||
errorf = true
|
||||
asserts = true
|
||||
comparison = true
|
||||
errorf = true
|
||||
asserts = true
|
||||
comparison = true
|
||||
|
||||
[linters-settings.exhaustive]
|
||||
default-signifies-exhaustive = true
|
||||
default-signifies-exhaustive = true
|
||||
|
||||
[linters-settings.forbidigo]
|
||||
# Forbid the following identifiers
|
||||
forbid = [
|
||||
"^minFraud*",
|
||||
"^maxMind*",
|
||||
]
|
||||
# Forbid the following identifiers
|
||||
forbid = [
|
||||
{ p = "Geoip", msg = "you should use `GeoIP`" },
|
||||
{ p = "geoIP", msg = "you should use `geoip`" },
|
||||
{ p = "Maxmind", msg = "you should use `MaxMind`" },
|
||||
{ p = "^maxMind", msg = "you should use `maxmind`" },
|
||||
{ p = "Minfraud", msg = "you should use `MinFraud`" },
|
||||
{ p = "^minFraud", msg = "you should use `minfraud`" },
|
||||
{ p = "^math.Max$", msg = "you should use the max built-in instead." },
|
||||
{ p = "^math.Min$", msg = "you should use the min built-in instead." },
|
||||
{ p = "^os.IsNotExist", msg = "As per their docs, new code should use errors.Is(err, fs.ErrNotExist)." },
|
||||
{ p = "^os.IsExist", msg = "As per their docs, new code should use errors.Is(err, fs.ErrExist)" },
|
||||
]
|
||||
|
||||
[linters-settings.gocritic]
|
||||
enabled-checks = [
|
||||
"appendAssign",
|
||||
"appendCombine",
|
||||
"argOrder",
|
||||
"assignOp",
|
||||
"badCall",
|
||||
"badCond",
|
||||
"badLock",
|
||||
"badRegexp",
|
||||
"badSorting",
|
||||
"boolExprSimplify",
|
||||
"builtinShadow",
|
||||
"builtinShadowDecl",
|
||||
"captLocal",
|
||||
"caseOrder",
|
||||
"codegenComment",
|
||||
"commentedOutCode",
|
||||
"commentedOutImport",
|
||||
"commentFormatting",
|
||||
"defaultCaseOrder",
|
||||
# Revive's defer rule already captures this. This caught no extra cases.
|
||||
# "deferInLoop",
|
||||
"deferUnlambda",
|
||||
"deprecatedComment",
|
||||
"docStub",
|
||||
"dupArg",
|
||||
"dupBranchBody",
|
||||
"dupCase",
|
||||
"dupImport",
|
||||
"dupSubExpr",
|
||||
"dynamicFmtString",
|
||||
"elseif",
|
||||
"emptyDecl",
|
||||
"emptyFallthrough",
|
||||
"emptyStringTest",
|
||||
"equalFold",
|
||||
"evalOrder",
|
||||
"exitAfterDefer",
|
||||
"exposedSyncMutex",
|
||||
"externalErrorReassign",
|
||||
# Given that all of our code runs on Linux and the / separate should
|
||||
# work fine, this seems less important.
|
||||
# "filepathJoin",
|
||||
"flagDeref",
|
||||
"flagName",
|
||||
"hexLiteral",
|
||||
"ifElseChain",
|
||||
"importShadow",
|
||||
"indexAlloc",
|
||||
"initClause",
|
||||
"ioutilDeprecated",
|
||||
"mapKey",
|
||||
"methodExprCall",
|
||||
"nestingReduce",
|
||||
"newDeref",
|
||||
"nilValReturn",
|
||||
"octalLiteral",
|
||||
"offBy1",
|
||||
"paramTypeCombine",
|
||||
"preferDecodeRune",
|
||||
"preferFilepathJoin",
|
||||
"preferFprint",
|
||||
"preferStringWriter",
|
||||
"preferWriteByte",
|
||||
"ptrToRefParam",
|
||||
"rangeExprCopy",
|
||||
"rangeValCopy",
|
||||
"redundantSprint",
|
||||
"regexpMust",
|
||||
"regexpPattern",
|
||||
# This might be good, but I don't think we want to encourage
|
||||
# significant changes to regexes as we port stuff from Perl.
|
||||
# "regexpSimplify",
|
||||
"ruleguard",
|
||||
"singleCaseSwitch",
|
||||
"sliceClear",
|
||||
"sloppyLen",
|
||||
# This seems like it might also be good, but a lot of existing code
|
||||
# fails.
|
||||
# "sloppyReassign",
|
||||
"returnAfterHttpError",
|
||||
"sloppyTypeAssert",
|
||||
"sortSlice",
|
||||
"sprintfQuotedString",
|
||||
"sqlQuery",
|
||||
"stringsCompare",
|
||||
"stringXbytes",
|
||||
"switchTrue",
|
||||
"syncMapLoadAndDelete",
|
||||
"timeExprSimplify",
|
||||
"todoCommentWithoutDetail",
|
||||
"tooManyResultsChecker",
|
||||
"truncateCmp",
|
||||
"typeAssertChain",
|
||||
"typeDefFirst",
|
||||
"typeSwitchVar",
|
||||
"typeUnparen",
|
||||
"underef",
|
||||
"unlabelStmt",
|
||||
"unlambda",
|
||||
# I am not sure we would want this linter and a lot of existing
|
||||
# code fails.
|
||||
# "unnamedResult",
|
||||
"unnecessaryBlock",
|
||||
"unnecessaryDefer",
|
||||
"unslice",
|
||||
"valSwap",
|
||||
"weakCond",
|
||||
"wrapperFunc",
|
||||
"yodaStyleExpr",
|
||||
# This requires explanations for "nolint" directives. This would be
|
||||
# nice for gosec ones, but I am not sure we want it generally unless
|
||||
# we can get the false positive rate lower.
|
||||
# "whyNoLint"
|
||||
]
|
||||
[linters-settings.gci]
|
||||
sections = ["standard", "default", "prefix(github.com/oschwald/maxminddb-golang)"]
|
||||
|
||||
[linters-settings.gofumpt]
|
||||
extra-rules = true
|
||||
lang-version = "1.18"
|
||||
extra-rules = true
|
||||
|
||||
[linters-settings.govet]
|
||||
"enable-all" = true
|
||||
enable-all = true
|
||||
disable = "shadow"
|
||||
|
||||
[linters-settings.lll]
|
||||
line-length = 120
|
||||
tab-width = 4
|
||||
line-length = 120
|
||||
tab-width = 4
|
||||
|
||||
[linters-settings.misspell]
|
||||
locale = "US"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "marshall"
|
||||
correction = "marshal"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "marshalling"
|
||||
correction = "marshaling"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "marshalls"
|
||||
correction = "marshals"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "unmarshall"
|
||||
correction = "unmarshal"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "unmarshalling"
|
||||
correction = "unmarshaling"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "unmarshalls"
|
||||
correction = "unmarshals"
|
||||
|
||||
[linters-settings.nolintlint]
|
||||
allow-leading-space = false
|
||||
allow-unused = false
|
||||
allow-no-explanation = ["lll", "misspell"]
|
||||
require-explanation = true
|
||||
require-specific = true
|
||||
allow-unused = false
|
||||
allow-no-explanation = ["lll", "misspell"]
|
||||
require-explanation = true
|
||||
require-specific = true
|
||||
|
||||
[linters-settings.revive]
|
||||
ignore-generated-header = true
|
||||
severity = "warning"
|
||||
|
||||
# This might be nice but it is so common that it is hard
|
||||
# to enable.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "add-constant"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "argument-limit"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "atomic"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "bare-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "blank-imports"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "bool-literal-in-expr"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "call-to-gc"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "cognitive-complexity"
|
||||
|
||||
# Probably a good rule, but we have a lot of names that
|
||||
# only have case differences.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "confusing-naming"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "confusing-results"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "constant-logical-expr"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "context-as-argument"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "context-keys-type"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "cyclomatic"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "deep-exit"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "defer"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "dot-imports"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "duplicated-imports"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "early-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "empty-block"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "empty-lines"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "errorf"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "error-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "error-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "error-strings"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "exported"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "file-header"
|
||||
|
||||
# We have a lot of flag parameters. This linter probably makes
|
||||
# a good point, but we would need some cleanup or a lot of nolints.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "flag-parameter"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "function-result-limit"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "get-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "identical-branches"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "if-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "imports-blacklist"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "import-shadowing"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "increment-decrement"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "indent-error-flow"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "line-length-limit"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "max-public-structs"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "modifies-parameter"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "modifies-value-receiver"
|
||||
|
||||
# We frequently use nested structs, particularly in tests.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "nested-structs"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "optimize-operands-order"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "package-comments"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "range"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "range-val-address"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "range-val-in-closure"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "receiver-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "redefines-builtin-id"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "string-of-int"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "struct-tag"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "superfluous-else"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "time-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unconditional-recursion"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unexported-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unexported-return"
|
||||
|
||||
# This is covered elsewhere and we want to ignore some
|
||||
# functions such as fmt.Fprintf.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "unhandled-error"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unnecessary-stmt"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unreachable-code"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unused-parameter"
|
||||
|
||||
# We generally have unused receivers in tests for meeting the
|
||||
# requirements of an interface.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "unused-receiver"
|
||||
|
||||
# This probably makes sense after we upgrade to 1.18
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "use-any"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "useless-break"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "var-declaration"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "var-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "waitgroup-by-value"
|
||||
enable-all-rules = true
|
||||
ignore-generated-header = true
|
||||
severity = "warning"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "add-constant"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "cognitive-complexity"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "confusing-naming"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "confusing-results"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "cyclomatic"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "deep-exit"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "flag-parameter"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "function-length"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "function-result-limit"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "line-length-limit"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "max-public-structs"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "nested-structs"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unchecked-type-assertion"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unhandled-error"
|
||||
disabled = true
|
||||
|
||||
[linters-settings.tagliatelle.case.rules]
|
||||
avro = "snake"
|
||||
bson = "snake"
|
||||
env = "upperSnake"
|
||||
envconfig = "upperSnake"
|
||||
json = "snake"
|
||||
mapstructure = "snake"
|
||||
xml = "snake"
|
||||
yaml = "snake"
|
||||
|
||||
[linters-settings.unparam]
|
||||
check-exported = true
|
||||
check-exported = true
|
||||
|
||||
|
||||
[[issues.exclude-rules]]
|
||||
linters = [
|
||||
"govet"
|
||||
]
|
||||
# we want to enable almost all govet rules. It is easier to just filter out
|
||||
# the ones we don't want:
|
||||
#
|
||||
# * fieldalignment - way too noisy. Although it is very useful in particular
|
||||
# cases where we are trying to use as little memory as possible, having
|
||||
# it go off on every struct isn't helpful.
|
||||
# * shadow - although often useful, it complains about _many_ err
|
||||
# shadowing assignments and some others where shadowing is clear.
|
||||
text = "^(fieldalignment|shadow)"
|
||||
linters = [
|
||||
"govet",
|
||||
"revive",
|
||||
]
|
||||
path = "_test.go"
|
||||
text = "fieldalignment:"
|
||||
|
178
vendor/github.com/oschwald/geoip2-golang/reader.go
generated
vendored
178
vendor/github.com/oschwald/geoip2-golang/reader.go
generated
vendored
@ -17,119 +17,121 @@ import (
|
||||
// The Enterprise struct corresponds to the data in the GeoIP2 Enterprise
|
||||
// database.
|
||||
type Enterprise struct {
|
||||
City struct {
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"city"`
|
||||
Continent struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Code string `maxminddb:"code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"continent"`
|
||||
Country struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"country"`
|
||||
Location struct {
|
||||
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
|
||||
Latitude float64 `maxminddb:"latitude"`
|
||||
Longitude float64 `maxminddb:"longitude"`
|
||||
MetroCode uint `maxminddb:"metro_code"`
|
||||
TimeZone string `maxminddb:"time_zone"`
|
||||
} `maxminddb:"location"`
|
||||
City struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
} `maxminddb:"city"`
|
||||
Postal struct {
|
||||
Code string `maxminddb:"code"`
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
} `maxminddb:"postal"`
|
||||
RegisteredCountry struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Subdivisions []struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
} `maxminddb:"subdivisions"`
|
||||
RepresentedCountry struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Type string `maxminddb:"type"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"represented_country"`
|
||||
Country struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"country"`
|
||||
RegisteredCountry struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"registered_country"`
|
||||
RepresentedCountry struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Type string `maxminddb:"type"`
|
||||
} `maxminddb:"represented_country"`
|
||||
Subdivisions []struct {
|
||||
Confidence uint8 `maxminddb:"confidence"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"subdivisions"`
|
||||
Traits struct {
|
||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
||||
ConnectionType string `maxminddb:"connection_type"`
|
||||
Domain string `maxminddb:"domain"`
|
||||
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
||||
IsLegitimateProxy bool `maxminddb:"is_legitimate_proxy"`
|
||||
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
||||
ISP string `maxminddb:"isp"`
|
||||
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
||||
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
||||
Organization string `maxminddb:"organization"`
|
||||
StaticIPScore float64 `maxminddb:"static_ip_score"`
|
||||
UserType string `maxminddb:"user_type"`
|
||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||
StaticIPScore float64 `maxminddb:"static_ip_score"`
|
||||
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
||||
IsAnycast bool `maxminddb:"is_anycast"`
|
||||
IsLegitimateProxy bool `maxminddb:"is_legitimate_proxy"`
|
||||
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
||||
} `maxminddb:"traits"`
|
||||
Location struct {
|
||||
TimeZone string `maxminddb:"time_zone"`
|
||||
Latitude float64 `maxminddb:"latitude"`
|
||||
Longitude float64 `maxminddb:"longitude"`
|
||||
MetroCode uint `maxminddb:"metro_code"`
|
||||
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
|
||||
} `maxminddb:"location"`
|
||||
}
|
||||
|
||||
// The City struct corresponds to the data in the GeoIP2/GeoLite2 City
|
||||
// databases.
|
||||
type City struct {
|
||||
City struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
} `maxminddb:"city"`
|
||||
Continent struct {
|
||||
Code string `maxminddb:"code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"continent"`
|
||||
Country struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"country"`
|
||||
Location struct {
|
||||
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
|
||||
Latitude float64 `maxminddb:"latitude"`
|
||||
Longitude float64 `maxminddb:"longitude"`
|
||||
MetroCode uint `maxminddb:"metro_code"`
|
||||
TimeZone string `maxminddb:"time_zone"`
|
||||
} `maxminddb:"location"`
|
||||
Postal struct {
|
||||
Code string `maxminddb:"code"`
|
||||
} `maxminddb:"postal"`
|
||||
RegisteredCountry struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"registered_country"`
|
||||
RepresentedCountry struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Type string `maxminddb:"type"`
|
||||
} `maxminddb:"represented_country"`
|
||||
Subdivisions []struct {
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Continent struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Code string `maxminddb:"code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
} `maxminddb:"continent"`
|
||||
Subdivisions []struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
} `maxminddb:"subdivisions"`
|
||||
RepresentedCountry struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Type string `maxminddb:"type"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"represented_country"`
|
||||
Country struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"country"`
|
||||
RegisteredCountry struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
} `maxminddb:"registered_country"`
|
||||
Location struct {
|
||||
TimeZone string `maxminddb:"time_zone"`
|
||||
Latitude float64 `maxminddb:"latitude"`
|
||||
Longitude float64 `maxminddb:"longitude"`
|
||||
MetroCode uint `maxminddb:"metro_code"`
|
||||
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
|
||||
} `maxminddb:"location"`
|
||||
Traits struct {
|
||||
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
||||
IsAnycast bool `maxminddb:"is_anycast"`
|
||||
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
||||
} `maxminddb:"traits"`
|
||||
}
|
||||
@ -138,31 +140,32 @@ type City struct {
|
||||
// Country databases.
|
||||
type Country struct {
|
||||
Continent struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Code string `maxminddb:"code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"continent"`
|
||||
Country struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"country"`
|
||||
RegisteredCountry struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
} `maxminddb:"registered_country"`
|
||||
RepresentedCountry struct {
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Type string `maxminddb:"type"`
|
||||
GeoNameID uint `maxminddb:"geoname_id"`
|
||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||
IsoCode string `maxminddb:"iso_code"`
|
||||
Names map[string]string `maxminddb:"names"`
|
||||
Type string `maxminddb:"type"`
|
||||
} `maxminddb:"represented_country"`
|
||||
Traits struct {
|
||||
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
||||
IsAnycast bool `maxminddb:"is_anycast"`
|
||||
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
||||
} `maxminddb:"traits"`
|
||||
}
|
||||
@ -180,8 +183,8 @@ type AnonymousIP struct {
|
||||
|
||||
// The ASN struct corresponds to the data in the GeoLite2 ASN database.
|
||||
type ASN struct {
|
||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||
}
|
||||
|
||||
// The ConnectionType struct corresponds to the data in the GeoIP2
|
||||
@ -197,12 +200,12 @@ type Domain struct {
|
||||
|
||||
// The ISP struct corresponds to the data in the GeoIP2 ISP database.
|
||||
type ISP struct {
|
||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
||||
ISP string `maxminddb:"isp"`
|
||||
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
||||
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
||||
Organization string `maxminddb:"organization"`
|
||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||
}
|
||||
|
||||
type databaseType int
|
||||
@ -305,8 +308,7 @@ func getDBType(reader *maxminddb.Reader) (databaseType, error) {
|
||||
"DBIP-Location-ISP (compat=Enterprise)",
|
||||
"GeoIP2-Enterprise":
|
||||
return isEnterprise | isCity | isCountry, nil
|
||||
case "GeoIP2-ISP",
|
||||
"GeoIP2-Precision-ISP":
|
||||
case "GeoIP2-ISP", "GeoIP2-Precision-ISP":
|
||||
return isISP | isASN, nil
|
||||
default:
|
||||
return 0, UnknownDatabaseTypeError{reader.Metadata.DatabaseType}
|
||||
|
610
vendor/github.com/oschwald/maxminddb-golang/.golangci.toml
generated
vendored
610
vendor/github.com/oschwald/maxminddb-golang/.golangci.toml
generated
vendored
@ -1,472 +1,192 @@
|
||||
[run]
|
||||
deadline = "10m"
|
||||
|
||||
tests = true
|
||||
# This is needed for precious, which may run multiple instances
|
||||
# in parallel
|
||||
allow-parallel-runners = true
|
||||
go = "1.21"
|
||||
tests = true
|
||||
timeout = "10m"
|
||||
|
||||
[linters]
|
||||
disable-all = true
|
||||
enable = [
|
||||
"asciicheck",
|
||||
"bidichk",
|
||||
"bodyclose",
|
||||
"containedctx",
|
||||
"contextcheck",
|
||||
"deadcode",
|
||||
enable-all = true
|
||||
disable = [
|
||||
"cyclop",
|
||||
"depguard",
|
||||
"durationcheck",
|
||||
"errcheck",
|
||||
"errchkjson",
|
||||
"errname",
|
||||
"errorlint",
|
||||
"exportloopref",
|
||||
"forbidigo",
|
||||
#"forcetypeassert",
|
||||
"goconst",
|
||||
"gocyclo",
|
||||
"gocritic",
|
||||
"godot",
|
||||
"gofumpt",
|
||||
"gomodguard",
|
||||
"gosec",
|
||||
"gosimple",
|
||||
"govet",
|
||||
"grouper",
|
||||
"ineffassign",
|
||||
"lll",
|
||||
"makezero",
|
||||
"maintidx",
|
||||
"misspell",
|
||||
"nakedret",
|
||||
"nilerr",
|
||||
"noctx",
|
||||
"nolintlint",
|
||||
"nosprintfhostport",
|
||||
"predeclared",
|
||||
"revive",
|
||||
"rowserrcheck",
|
||||
"sqlclosecheck",
|
||||
"staticcheck",
|
||||
"structcheck",
|
||||
"stylecheck",
|
||||
"tenv",
|
||||
"tparallel",
|
||||
"typecheck",
|
||||
"unconvert",
|
||||
"unparam",
|
||||
"unused",
|
||||
"varcheck",
|
||||
"vetshadow",
|
||||
"wastedassign",
|
||||
]
|
||||
"err113",
|
||||
"execinquery",
|
||||
"exhaustive",
|
||||
"exhaustruct",
|
||||
"forcetypeassert",
|
||||
"funlen",
|
||||
"gochecknoglobals",
|
||||
"godox",
|
||||
"gomnd",
|
||||
"inamedparam",
|
||||
"interfacebloat",
|
||||
"mnd",
|
||||
"nlreturn",
|
||||
"nonamedreturns",
|
||||
"paralleltest",
|
||||
"thelper",
|
||||
"testpackage",
|
||||
|
||||
# Please note that we only use depguard for stdlib as gomodguard only
|
||||
# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12
|
||||
[linters-settings.depguard]
|
||||
list-type = "blacklist"
|
||||
include-go-root = true
|
||||
packages = [
|
||||
# ioutil is deprecated. The functions have been moved elsewhere:
|
||||
# https://golang.org/doc/go1.16#ioutil
|
||||
"io/ioutil",
|
||||
]
|
||||
"varnamelen",
|
||||
"wrapcheck",
|
||||
"wsl",
|
||||
|
||||
[linters-settings.errcheck]
|
||||
# Don't allow setting of error to the blank identifier. If there is a legtimate
|
||||
# reason, there should be a nolint with an explanation.
|
||||
check-blank = true
|
||||
|
||||
exclude-functions = [
|
||||
# If we are rolling back a transaction, we are often already in an error
|
||||
# state.
|
||||
'(*database/sql.Tx).Rollback',
|
||||
|
||||
# It is reasonable to ignore errors if Cleanup fails in most cases.
|
||||
'(*github.com/google/renameio/v2.PendingFile).Cleanup',
|
||||
|
||||
# We often don't care if removing a file failed (e.g., it doesn't exist)
|
||||
'os.Remove',
|
||||
'os.RemoveAll',
|
||||
]
|
||||
|
||||
# Ignoring Close so that we don't have to have a bunch of
|
||||
# `defer func() { _ = r.Close() }()` constructs when we
|
||||
# don't actually care about the error.
|
||||
ignore = "Close,fmt:.*"
|
||||
# Require Go 1.22
|
||||
"copyloopvar",
|
||||
"intrange",
|
||||
]
|
||||
|
||||
[linters-settings.errorlint]
|
||||
errorf = true
|
||||
asserts = true
|
||||
comparison = true
|
||||
errorf = true
|
||||
asserts = true
|
||||
comparison = true
|
||||
|
||||
[linters-settings.exhaustive]
|
||||
default-signifies-exhaustive = true
|
||||
default-signifies-exhaustive = true
|
||||
|
||||
[linters-settings.forbidigo]
|
||||
# Forbid the following identifiers
|
||||
forbid = [
|
||||
"^minFraud*",
|
||||
"^maxMind*",
|
||||
]
|
||||
# Forbid the following identifiers
|
||||
forbid = [
|
||||
{ p = "Geoip", msg = "you should use `GeoIP`" },
|
||||
{ p = "geoIP", msg = "you should use `geoip`" },
|
||||
{ p = "Maxmind", msg = "you should use `MaxMind`" },
|
||||
{ p = "^maxMind", msg = "you should use `maxmind`" },
|
||||
{ p = "Minfraud", msg = "you should use `MinFraud`" },
|
||||
{ p = "^minFraud", msg = "you should use `minfraud`" },
|
||||
{ p = "^math.Max$", msg = "you should use the max built-in instead." },
|
||||
{ p = "^math.Min$", msg = "you should use the min built-in instead." },
|
||||
{ p = "^os.IsNotExist", msg = "As per their docs, new code should use errors.Is(err, fs.ErrNotExist)." },
|
||||
{ p = "^os.IsExist", msg = "As per their docs, new code should use errors.Is(err, fs.ErrExist)" },
|
||||
]
|
||||
|
||||
[linters-settings.gocritic]
|
||||
enabled-checks = [
|
||||
"appendAssign",
|
||||
"appendCombine",
|
||||
"argOrder",
|
||||
"assignOp",
|
||||
"badCall",
|
||||
"badCond",
|
||||
"badLock",
|
||||
"badRegexp",
|
||||
"badSorting",
|
||||
"boolExprSimplify",
|
||||
"builtinShadow",
|
||||
"builtinShadowDecl",
|
||||
"captLocal",
|
||||
"caseOrder",
|
||||
"codegenComment",
|
||||
"commentedOutCode",
|
||||
"commentedOutImport",
|
||||
"commentFormatting",
|
||||
"defaultCaseOrder",
|
||||
# Revive's defer rule already captures this. This caught no extra cases.
|
||||
# "deferInLoop",
|
||||
"deferUnlambda",
|
||||
"deprecatedComment",
|
||||
"docStub",
|
||||
"dupArg",
|
||||
"dupBranchBody",
|
||||
"dupCase",
|
||||
"dupImport",
|
||||
"dupSubExpr",
|
||||
"dynamicFmtString",
|
||||
"elseif",
|
||||
"emptyDecl",
|
||||
"emptyFallthrough",
|
||||
"emptyStringTest",
|
||||
"equalFold",
|
||||
"evalOrder",
|
||||
"exitAfterDefer",
|
||||
"exposedSyncMutex",
|
||||
"externalErrorReassign",
|
||||
# Given that all of our code runs on Linux and the / separate should
|
||||
# work fine, this seems less important.
|
||||
# "filepathJoin",
|
||||
"flagDeref",
|
||||
"flagName",
|
||||
"hexLiteral",
|
||||
"ifElseChain",
|
||||
"importShadow",
|
||||
"indexAlloc",
|
||||
"initClause",
|
||||
"ioutilDeprecated",
|
||||
"mapKey",
|
||||
"methodExprCall",
|
||||
"nestingReduce",
|
||||
"newDeref",
|
||||
"nilValReturn",
|
||||
"octalLiteral",
|
||||
"offBy1",
|
||||
"paramTypeCombine",
|
||||
"preferDecodeRune",
|
||||
"preferFilepathJoin",
|
||||
"preferFprint",
|
||||
"preferStringWriter",
|
||||
"preferWriteByte",
|
||||
"ptrToRefParam",
|
||||
"rangeExprCopy",
|
||||
"rangeValCopy",
|
||||
"redundantSprint",
|
||||
"regexpMust",
|
||||
"regexpPattern",
|
||||
# This might be good, but I don't think we want to encourage
|
||||
# significant changes to regexes as we port stuff from Perl.
|
||||
# "regexpSimplify",
|
||||
"ruleguard",
|
||||
"singleCaseSwitch",
|
||||
"sliceClear",
|
||||
"sloppyLen",
|
||||
# This seems like it might also be good, but a lot of existing code
|
||||
# fails.
|
||||
# "sloppyReassign",
|
||||
"returnAfterHttpError",
|
||||
"sloppyTypeAssert",
|
||||
"sortSlice",
|
||||
"sprintfQuotedString",
|
||||
"sqlQuery",
|
||||
"stringsCompare",
|
||||
"stringXbytes",
|
||||
"switchTrue",
|
||||
"syncMapLoadAndDelete",
|
||||
"timeExprSimplify",
|
||||
"todoCommentWithoutDetail",
|
||||
"tooManyResultsChecker",
|
||||
"truncateCmp",
|
||||
"typeAssertChain",
|
||||
"typeDefFirst",
|
||||
"typeSwitchVar",
|
||||
"typeUnparen",
|
||||
"underef",
|
||||
"unlabelStmt",
|
||||
"unlambda",
|
||||
# I am not sure we would want this linter and a lot of existing
|
||||
# code fails.
|
||||
# "unnamedResult",
|
||||
"unnecessaryBlock",
|
||||
"unnecessaryDefer",
|
||||
"unslice",
|
||||
"valSwap",
|
||||
"weakCond",
|
||||
"wrapperFunc",
|
||||
"yodaStyleExpr",
|
||||
# This requires explanations for "nolint" directives. This would be
|
||||
# nice for gosec ones, but I am not sure we want it generally unless
|
||||
# we can get the false positive rate lower.
|
||||
# "whyNoLint"
|
||||
]
|
||||
[linters-settings.gci]
|
||||
sections = ["standard", "default", "prefix(github.com/oschwald/maxminddb-golang)"]
|
||||
|
||||
[linters-settings.gofumpt]
|
||||
extra-rules = true
|
||||
lang-version = "1.18"
|
||||
extra-rules = true
|
||||
|
||||
[linters-settings.govet]
|
||||
"enable-all" = true
|
||||
enable-all = true
|
||||
disable = "shadow"
|
||||
|
||||
[linters-settings.lll]
|
||||
line-length = 120
|
||||
tab-width = 4
|
||||
line-length = 120
|
||||
tab-width = 4
|
||||
|
||||
[linters-settings.misspell]
|
||||
locale = "US"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "marshall"
|
||||
correction = "marshal"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "marshalling"
|
||||
correction = "marshaling"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "marshalls"
|
||||
correction = "marshals"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "unmarshall"
|
||||
correction = "unmarshal"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "unmarshalling"
|
||||
correction = "unmarshaling"
|
||||
|
||||
[[linters-settings.misspell.extra-words]]
|
||||
typo = "unmarshalls"
|
||||
correction = "unmarshals"
|
||||
|
||||
[linters-settings.nolintlint]
|
||||
allow-leading-space = false
|
||||
allow-unused = false
|
||||
allow-no-explanation = ["lll", "misspell"]
|
||||
require-explanation = true
|
||||
require-specific = true
|
||||
allow-unused = false
|
||||
allow-no-explanation = ["lll", "misspell"]
|
||||
require-explanation = true
|
||||
require-specific = true
|
||||
|
||||
[linters-settings.revive]
|
||||
ignore-generated-header = true
|
||||
severity = "warning"
|
||||
|
||||
# This might be nice but it is so common that it is hard
|
||||
# to enable.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "add-constant"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "argument-limit"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "atomic"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "bare-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "blank-imports"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "bool-literal-in-expr"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "call-to-gc"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "cognitive-complexity"
|
||||
|
||||
# Probably a good rule, but we have a lot of names that
|
||||
# only have case differences.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "confusing-naming"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "confusing-results"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "constant-logical-expr"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "context-as-argument"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "context-keys-type"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "cyclomatic"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "deep-exit"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "defer"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "dot-imports"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "duplicated-imports"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "early-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "empty-block"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "empty-lines"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "errorf"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "error-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "error-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "error-strings"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "exported"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "file-header"
|
||||
|
||||
# We have a lot of flag parameters. This linter probably makes
|
||||
# a good point, but we would need some cleanup or a lot of nolints.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "flag-parameter"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "function-result-limit"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "get-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "identical-branches"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "if-return"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "imports-blacklist"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "import-shadowing"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "increment-decrement"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "indent-error-flow"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "line-length-limit"
|
||||
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "max-public-structs"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "modifies-parameter"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "modifies-value-receiver"
|
||||
|
||||
# We frequently use nested structs, particularly in tests.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "nested-structs"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "optimize-operands-order"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "package-comments"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "range"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "range-val-address"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "range-val-in-closure"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "receiver-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "redefines-builtin-id"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "string-of-int"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "struct-tag"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "superfluous-else"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "time-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unconditional-recursion"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unexported-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unexported-return"
|
||||
|
||||
# This is covered elsewhere and we want to ignore some
|
||||
# functions such as fmt.Fprintf.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "unhandled-error"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unnecessary-stmt"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unreachable-code"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unused-parameter"
|
||||
|
||||
# We generally have unused receivers in tests for meeting the
|
||||
# requirements of an interface.
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "unused-receiver"
|
||||
|
||||
# This probably makes sense after we upgrade to 1.18
|
||||
# [[linters-settings.revive.rules]]
|
||||
# name = "use-any"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "useless-break"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "var-declaration"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "var-naming"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "waitgroup-by-value"
|
||||
enable-all-rules = true
|
||||
ignore-generated-header = true
|
||||
severity = "warning"
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "add-constant"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "cognitive-complexity"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "confusing-naming"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "confusing-results"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "cyclomatic"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "deep-exit"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "flag-parameter"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "function-length"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "function-result-limit"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "line-length-limit"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "max-public-structs"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "nested-structs"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unchecked-type-assertion"
|
||||
disabled = true
|
||||
|
||||
[[linters-settings.revive.rules]]
|
||||
name = "unhandled-error"
|
||||
disabled = true
|
||||
|
||||
[linters-settings.tagliatelle.case.rules]
|
||||
avro = "snake"
|
||||
bson = "snake"
|
||||
env = "upperSnake"
|
||||
envconfig = "upperSnake"
|
||||
json = "snake"
|
||||
mapstructure = "snake"
|
||||
xml = "snake"
|
||||
yaml = "snake"
|
||||
|
||||
[linters-settings.unparam]
|
||||
check-exported = true
|
||||
check-exported = true
|
||||
|
||||
|
||||
[[issues.exclude-rules]]
|
||||
linters = [
|
||||
"govet"
|
||||
]
|
||||
# we want to enable almost all govet rules. It is easier to just filter out
|
||||
# the ones we don't want:
|
||||
#
|
||||
# * fieldalignment - way too noisy. Although it is very useful in particular
|
||||
# cases where we are trying to use as little memory as possible, having
|
||||
# it go off on every struct isn't helpful.
|
||||
# * shadow - although often useful, it complains about _many_ err
|
||||
# shadowing assignments and some others where shadowing is clear.
|
||||
text = "^(fieldalignment|shadow)"
|
||||
linters = [
|
||||
"govet",
|
||||
"revive",
|
||||
]
|
||||
path = "_test.go"
|
||||
text = "fieldalignment:"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user