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
|
ADD dip /dip
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# dip
|
# dip
|
||||||
[![Build Status](https://drone.paulbsd.com/api/badges/paulbsd/dip/status.svg)](https://drone.paulbsd.com/paulbsd/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
|
## Howto
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ curl -H "Accept: text/html" http://localhost:8080/
|
|||||||
## License
|
## License
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Copyright (c) 2019, 2020, 2021, 2022 PaulBSD
|
Copyright (c) 2020, 2021, 2022, 2023 PaulBSD
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"git.paulbsd.com/paulbsd/dip/src/config"
|
"git.paulbsd.com/paulbsd/dip/src/config"
|
||||||
"git.paulbsd.com/paulbsd/dip/src/dip"
|
"git.paulbsd.com/paulbsd/dip/src/dip"
|
||||||
"git.paulbsd.com/paulbsd/dip/src/ws"
|
"git.paulbsd.com/paulbsd/dip/src/ws"
|
||||||
@ -18,5 +20,11 @@ func main() {
|
|||||||
ws := ws.WS{}
|
ws := ws.WS{}
|
||||||
ws.Page.Title = "Public IP Address Service"
|
ws.Page.Title = "Public IP Address Service"
|
||||||
dip.Init()
|
dip.Init()
|
||||||
|
|
||||||
|
memcacheconn, ok := os.LookupEnv("MEMCACHECONN")
|
||||||
|
if ok {
|
||||||
|
dip.MemcacheConn = memcacheconn
|
||||||
|
}
|
||||||
|
|
||||||
ws.RunServer(config, Templates, Static)
|
ws.RunServer(config, Templates, Static)
|
||||||
}
|
}
|
||||||
|
34
go.mod
34
go.mod
@ -1,29 +1,27 @@
|
|||||||
module git.paulbsd.com/paulbsd/dip
|
module git.paulbsd.com/paulbsd/dip
|
||||||
|
|
||||||
go 1.20
|
go 1.23
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/labstack/echo/v4 v4.10.2
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/labstack/echo/v4 v4.12.0
|
||||||
golang.org/x/crypto v0.7.0 // indirect
|
github.com/likexian/whois v1.15.4
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
github.com/likexian/whois-parser v1.24.19
|
||||||
golang.org/x/text v0.8.0 // indirect
|
github.com/oschwald/geoip2-golang v1.11.0
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/likexian/whois v1.14.6
|
|
||||||
github.com/likexian/whois-parser v1.24.7
|
|
||||||
github.com/oschwald/geoip2-golang v1.8.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/labstack/gommon v0.4.0 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/likexian/gokit v0.25.11 // indirect
|
github.com/likexian/gokit v0.25.15 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 // 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/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/crypto v0.26.0 // indirect
|
||||||
golang.org/x/time v0.3.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
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.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
||||||
github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ=
|
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
||||||
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY=
|
||||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg=
|
||||||
github.com/likexian/gokit v0.25.9 h1:rzSQ/dP7Qw+QUzSuWlrLF0AtZS3Di6uO5yWOKhx2Gk4=
|
github.com/likexian/whois v1.15.3 h1:0emFSUSUj98Q12Wer3iM3eROPXjg+CyUBlibGPNbKHw=
|
||||||
github.com/likexian/gokit v0.25.9/go.mod h1:oDDqJUcnnF9uAKuw54F7s6oEG+OJ7eallfDW2dq0A/o=
|
github.com/likexian/whois v1.15.3/go.mod h1:a6sGAAKEb+O3JRBuW2x/QDM80l5hJ07p0+SjQkJ1c+0=
|
||||||
github.com/likexian/gokit v0.25.11 h1:o5H5JgVtBYBQn0QX30zE5+V8j2rgLTDoZWAO8xLFFfY=
|
github.com/likexian/whois v1.15.4 h1:r5En62c+S9HKFgJtdh2WsdmRGTcxE4WUtGBdZkSBXmM=
|
||||||
github.com/likexian/gokit v0.25.11/go.mod h1:IKRQFPah2KQ0HL3iVjaOvFbx2apkSdFicGmsA0A4a1c=
|
github.com/likexian/whois v1.15.4/go.mod h1:rXFTPcQdNlPQBJCQpPWTSIDGzzmgKBftmhdOOcLpwXk=
|
||||||
github.com/likexian/whois v1.14.4 h1:yNQVugAHfeoylzyhitcs0vaPksDduvzW46HLjqXhpCg=
|
github.com/likexian/whois-parser v1.24.18 h1:Xolieo/uwjNwhmQN/oDDNlwFajHipdHedyPBgzG44kw=
|
||||||
github.com/likexian/whois v1.14.4/go.mod h1:ijMqjPbtafr5TB49U3Hs3BsJx/93ixhRi/8YnCSK0iY=
|
github.com/likexian/whois-parser v1.24.18/go.mod h1:k5zmKRZ7xPg1TLv3BGT4g/LOPRIMhvdNMeB0F53V/jk=
|
||||||
github.com/likexian/whois v1.14.6 h1:chNF6xkUShMQHq+5tiovVOQFadb9hqrWcaqbtlvbe3o=
|
github.com/likexian/whois-parser v1.24.19 h1:vT8lWhnV8ogkdaYLyef6IvE5VTHVCwlUDG5BUXCx06k=
|
||||||
github.com/likexian/whois v1.14.6/go.mod h1:upfX0X3o78fvHyFY2zHv46zooPoydUV1msyovvLZTMU=
|
github.com/likexian/whois-parser v1.24.19/go.mod h1:rAtaofg2luol09H+ogDzGIfcG8ig1NtM5R16uQADDz4=
|
||||||
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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
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-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.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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
|
||||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
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/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 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
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/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
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 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 build -t dip:latest .
|
||||||
docker tag dip:latest registry.paulbsd.com/images/dip:latest
|
docker tag dip:latest registry.paulbsd.com/images/dip:latest
|
||||||
docker push 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
|
package dip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.paulbsd.com/paulbsd/dip/src/geoip"
|
"git.paulbsd.com/paulbsd/dip/src/geoip"
|
||||||
|
"github.com/bradfitz/gomemcache/memcache"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/likexian/whois"
|
"github.com/likexian/whois"
|
||||||
whoisparser "github.com/likexian/whois-parser"
|
whoisparser "github.com/likexian/whois-parser"
|
||||||
@ -13,26 +16,53 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const defaultLanguage = "en"
|
const defaultLanguage = "en"
|
||||||
|
const cacheMaxTime = 604800
|
||||||
|
|
||||||
var citydb *geoip2.Reader
|
var citydb *geoip2.Reader
|
||||||
var asndb *geoip2.Reader
|
var asndb *geoip2.Reader
|
||||||
|
var MemcacheConn string = ""
|
||||||
|
|
||||||
func Init() (err error) {
|
func Init() (err error) {
|
||||||
citydb, asndb, err = geoip.InitGeoIP()
|
citydb, asndb, err = geoip.InitGeoIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
log.Println("failed to get geoip database")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIPInfo returns IP address informations
|
// GetIPInfo returns IP address informations
|
||||||
func (ip *IP) GetIPInfo(c echo.Context) (err error) {
|
func (ip *IP) GetIPInfo(c echo.Context) (cached bool, err error) {
|
||||||
if c.Param("ip") != "" {
|
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")
|
ip.IP = c.Param("ip")
|
||||||
} else {
|
if c.Param("ip") == "" {
|
||||||
ip.IP = c.RealIP()
|
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()
|
err = ip.CheckIPAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ip.IP = c.RealIP()
|
ip.IP = c.RealIP()
|
||||||
@ -52,6 +82,16 @@ func (ip *IP) GetIPInfo(c echo.Context) (err error) {
|
|||||||
log.Println(err)
|
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()
|
/*err = ip.GetWhois()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
@ -13,24 +13,30 @@ import (
|
|||||||
geoip2 "github.com/oschwald/geoip2-golang"
|
geoip2 "github.com/oschwald/geoip2-golang"
|
||||||
)
|
)
|
||||||
|
|
||||||
var RootURL = "https://git.paulbsd.com/paulbsd/GeoLite.mmdb/releases/download/%s/%s"
|
const 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 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 {
|
var apiresults []struct {
|
||||||
Tag string `json:"tag_name"`
|
Tag string `json:"tag_name"`
|
||||||
}
|
}
|
||||||
res, err := http.Get(APIUrl)
|
res, err := http.Get(APIUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
body, err := io.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(body, &apiresults)
|
err = json.Unmarshal(body, &apiresults)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var tags []string
|
var tags []string
|
||||||
@ -39,14 +45,18 @@ func GetLastVersion() string {
|
|||||||
}
|
}
|
||||||
sort.Sort(sort.Reverse(sort.StringSlice(tags)))
|
sort.Sort(sort.Reverse(sort.StringSlice(tags)))
|
||||||
|
|
||||||
return tags[0]
|
result = tags[0]
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitGeoIP() (citydb *geoip2.Reader, asndb *geoip2.Reader, err error) {
|
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{
|
var dbs map[string]string = map[string]string{
|
||||||
"city": fmt.Sprintf(RootURL, version, "GeoLite2-City.mmdb"),
|
"city": fmt.Sprintf(RootURL, version, CityFilename),
|
||||||
"asn": fmt.Sprintf(RootURL, version, "GeoLite2-ASN.mmdb")}
|
"asn": fmt.Sprintf(RootURL, version, ASNFilename)}
|
||||||
log.Printf("Fetching GeoLite.mmdb version %s\n", version)
|
log.Printf("Fetching GeoLite.mmdb version %s\n", version)
|
||||||
citydb, err = FetchDB(dbs["city"], version)
|
citydb, err = FetchDB(dbs["city"], version)
|
||||||
if err != nil {
|
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)
|
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJavaScript)
|
||||||
} else if strings.HasSuffix(name, ".css") {
|
} else if strings.HasSuffix(name, ".css") {
|
||||||
c.Response().Header().Set(echo.HeaderContentType, "text/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))
|
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") {
|
if strings.HasSuffix(name, ".html") {
|
||||||
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
||||||
}
|
}
|
||||||
|
c.Response().Header().Add(echo.HeaderCacheControl, "max-age=172800")
|
||||||
return t.templates.ExecuteTemplate(w, name, data)
|
return t.templates.ExecuteTemplate(w, name, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,29 +39,6 @@ func BuildTemplates(templatefiles *embed.FS) (builttemplates *Template, err erro
|
|||||||
return
|
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
|
// Template is a template struct
|
||||||
type Template struct {
|
type Template struct {
|
||||||
templates *template.Template
|
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{
|
ws.e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
||||||
AllowOrigins: []string{"*"},
|
AllowOrigins: []string{"*"},
|
||||||
AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
|
AllowMethods: []string{http.MethodGet},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
builtTemplates, _ := templates.BuildTemplates(templatefiles)
|
builtTemplates, _ := templates.BuildTemplates(templatefiles)
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"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
|
var ip dip.IP
|
||||||
err = ip.GetIPInfo(c)
|
cached, err = ip.GetIPInfo(c)
|
||||||
p.IP = &ip
|
p.IP = &ip
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -18,7 +18,11 @@ func (p *Page) GetContent(c echo.Context) (err error) {
|
|||||||
|
|
||||||
// Process returns main webpage or a JSON
|
// Process returns main webpage or a JSON
|
||||||
func (p *Page) Process(c echo.Context, querytype string) (err error) {
|
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" {
|
if querytype == "json" {
|
||||||
return c.JSONPretty(http.StatusOK, p.IP, " ")
|
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({
|
const dip_ip = document.getElementById("dip_ip");
|
||||||
el: '#dip_main_div',
|
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 () {
|
function setData(res) {
|
||||||
return {
|
dip_ip.innerHTML = res["ip"];
|
||||||
title: "Public IP Address service",
|
dip_hostname.innerHTML = res["hostname"];
|
||||||
dip: {"ip": null,
|
dip_city.innerHTML = res["city"];
|
||||||
"hostname": null,
|
dip_country.innerHTML = res["country"];
|
||||||
"city": null,
|
dip_as_number.innerHTML = res["as"]["number"];
|
||||||
"country": null},
|
dip_as_org.innerHTML = res["as"]["org"];
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
function updateIP() {
|
||||||
var ip = "";
|
let ip = "";
|
||||||
|
|
||||||
if (window.location.pathname.length > 4) {
|
if (window.location.pathname.length > 4) {
|
||||||
ip = window.location.pathname.split("/")[1];
|
ip = window.location.pathname.split("/")[1];
|
||||||
console.log(ip);
|
|
||||||
}
|
}
|
||||||
axios.get(`/json/${ip}`)
|
|
||||||
.then(response => {
|
const localdata = localStorage.getItem("data");
|
||||||
this.dip = response.data
|
if (localdata) {
|
||||||
})
|
const data = JSON.parse(localdata);
|
||||||
.catch(err => {
|
setData(data);
|
||||||
// Manage the state of the application if the request
|
}
|
||||||
// has failed
|
|
||||||
|
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 css/*
|
||||||
//go:embed js/*
|
//go:embed js/*
|
||||||
|
//go:embed images/*
|
||||||
var Static embed.FS
|
var Static embed.FS
|
||||||
|
@ -4,12 +4,11 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<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/main.css" />
|
||||||
<link rel="stylesheet" href="static/css/uikit.min.css" />
|
<link rel="stylesheet" href="static/css/uikit.min.css" />
|
||||||
<link rel="stylesheet" href="static/css/font-awesome.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.min.js"></script>
|
||||||
<script src="static/js/uikit-icons.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>
|
</head>
|
||||||
|
@ -8,29 +8,27 @@
|
|||||||
<caption>IP informations</caption>
|
<caption>IP informations</caption>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IP</td>
|
<td>IP</td>
|
||||||
<td>{{ "{{" }} dip.ip {{ "}}" }}</td>
|
<td id="dip_ip"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Reverse DNS</td>
|
<td>Reverse DNS</td>
|
||||||
<td>{{ "{{" }} dip.hostname {{ "}}" }}</td>
|
<td id="dip_hostname"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>City</td>
|
<td>City</td>
|
||||||
<td>{{ "{{" }} dip.city {{ "}}" }}</td>
|
<td id="dip_city"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Country</td>
|
<td>Country</td>
|
||||||
<td>{{ "{{" }} dip.country {{ "}}" }}</td>
|
<td id="dip_country"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>AS number</td>
|
<td>AS number</td>
|
||||||
<td>{{ "{{" }} dip.as.number {{ "}}" }}</td>
|
<td id="dip_as_number"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>AS name</td>
|
<td>AS name</td>
|
||||||
<td>
|
<td id="dip_as_org"></td>
|
||||||
{{ "{{" }} dip.as.org {{ "}}" }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</div>
|
</div>
|
||||||
{{ template "footer_js.html" .}}
|
{{ 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
|
# 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
|
## v4.10.2 - 2023-02-22
|
||||||
|
|
||||||
**Security**
|
**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
|
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}'
|
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
goversion ?= "1.17"
|
goversion ?= "1.19"
|
||||||
test_version: ## Run tests inside Docker with given version (defaults to 1.17 oldest supported). Example: make test_version goversion=1.17
|
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"
|
@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)
|
[![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)
|
[![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)
|
[![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)
|
[![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)
|
[![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)
|
[![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)
|
[![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
|
High performance, extensible, minimalist Go web framework.
|
||||||
older versions.
|
|
||||||
|
|
||||||
As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
|
* [Official website](https://echo.labstack.com)
|
||||||
Therefore a Go version capable of understanding /vN suffixed imports is required:
|
* [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
|
Help and questions: [Github Discussions](https://github.com/labstack/echo/discussions)
|
||||||
way of using Echo going forward.
|
|
||||||
|
|
||||||
For older versions, please use the latest v3 tag.
|
|
||||||
|
|
||||||
## Feature Overview
|
### Feature Overview
|
||||||
|
|
||||||
- Optimized HTTP router which smartly prioritize routes
|
- Optimized HTTP router which smartly prioritize routes
|
||||||
- Build robust and scalable RESTful APIs
|
- 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
|
- Automatic TLS via Let’s Encrypt
|
||||||
- HTTP/2 support
|
- 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
|
## Benchmarks
|
||||||
|
|
||||||
Date: 2020/11/11<br>
|
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/{version}
|
||||||
go get github.com/labstack/echo/v4
|
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
|
### 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/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/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/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/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/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 |
|
| [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.
|
Please send a PR to add your own library here.
|
||||||
|
|
||||||
## Help
|
|
||||||
|
|
||||||
- [Forum](https://github.com/labstack/echo/discussions)
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
**Use issues for everything**
|
**Use issues for everything**
|
||||||
|
124
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
124
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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -11,23 +14,28 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Binder is the interface that wraps the Bind method.
|
// Binder is the interface that wraps the Bind method.
|
||||||
Binder interface {
|
type Binder interface {
|
||||||
Bind(i interface{}, c Context) error
|
Bind(i interface{}, c Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultBinder is the default implementation of the Binder interface.
|
// DefaultBinder is the default implementation of the Binder interface.
|
||||||
DefaultBinder struct{}
|
type DefaultBinder struct{}
|
||||||
|
|
||||||
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
||||||
// Types that don't implement this, but do implement encoding.TextUnmarshaler
|
// Types that don't implement this, but do implement encoding.TextUnmarshaler
|
||||||
// will use that interface instead.
|
// will use that interface instead.
|
||||||
BindUnmarshaler interface {
|
type BindUnmarshaler interface {
|
||||||
// UnmarshalParam decodes and assigns a value from an form or query param.
|
// UnmarshalParam decodes and assigns a value from an form or query param.
|
||||||
UnmarshalParam(param string) error
|
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
|
// BindPathParams binds path params to bindable object
|
||||||
func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {
|
func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {
|
||||||
@ -131,10 +139,29 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
|||||||
typ := reflect.TypeOf(destination).Elem()
|
typ := reflect.TypeOf(destination).Elem()
|
||||||
val := reflect.ValueOf(destination).Elem()
|
val := reflect.ValueOf(destination).Elem()
|
||||||
|
|
||||||
// Map
|
// Support binding to limited Map destinations:
|
||||||
if typ.Kind() == reflect.Map {
|
// - 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 {
|
for k, v := range data {
|
||||||
|
if isElemString {
|
||||||
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
|
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
|
||||||
|
} else {
|
||||||
|
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -161,14 +188,14 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
|||||||
}
|
}
|
||||||
structFieldKind := structField.Kind()
|
structFieldKind := structField.Kind()
|
||||||
inputFieldName := typeField.Tag.Get(tag)
|
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
|
// 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")
|
return errors.New("query/param/form tags are not allowed with anonymous struct field")
|
||||||
}
|
}
|
||||||
|
|
||||||
if inputFieldName == "" {
|
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).
|
// 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 _, ok := structField.Addr().Interface().(BindUnmarshaler); !ok && structFieldKind == reflect.Struct {
|
||||||
if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
|
if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -197,27 +224,46 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this first, in case we're dealing with an alias to an array type
|
// NOTE: algorithm here is not particularly sophisticated. It probably does not work with absurd types like `**[]*int`
|
||||||
if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
numElems := len(inputValue)
|
if ok, err := unmarshalInputToField(typeField.Type.Kind(), inputValue[0], structField); ok {
|
||||||
if structFieldKind == reflect.Slice && numElems > 0 {
|
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()
|
sliceOf := structField.Type().Elem().Kind()
|
||||||
|
numElems := len(inputValue)
|
||||||
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
|
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
|
||||||
for j := 0; j < numElems; j++ {
|
for j := 0; j < numElems; j++ {
|
||||||
if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
|
if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val.Field(i).Set(slice)
|
structField.Set(slice)
|
||||||
} else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
|
continue
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
if err := setWithProperType(structFieldKind, inputValue[0], structField); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
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
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,35 +312,41 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
|
func unmarshalInputsToField(valueKind reflect.Kind, values []string, field reflect.Value) (bool, error) {
|
||||||
switch valueKind {
|
if valueKind == reflect.Ptr {
|
||||||
case reflect.Ptr:
|
if field.IsNil() {
|
||||||
return unmarshalFieldPtr(val, field)
|
field.Set(reflect.New(field.Type().Elem()))
|
||||||
default:
|
|
||||||
return unmarshalFieldNonPtr(val, field)
|
|
||||||
}
|
}
|
||||||
|
field = field.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
|
|
||||||
fieldIValue := field.Addr().Interface()
|
fieldIValue := field.Addr().Interface()
|
||||||
if unmarshaler, ok := fieldIValue.(BindUnmarshaler); ok {
|
unmarshaler, ok := fieldIValue.(bindMultipleUnmarshaler)
|
||||||
return true, unmarshaler.UnmarshalParam(value)
|
if !ok {
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
if unmarshaler, ok := fieldIValue.(encoding.TextUnmarshaler); ok {
|
return true, unmarshaler.UnmarshalParams(values)
|
||||||
return true, unmarshaler.UnmarshalText([]byte(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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
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 {
|
func setIntField(value string, bitSize int, field reflect.Value) error {
|
||||||
if value == "" {
|
if value == "" {
|
||||||
value = "0"
|
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
|
package echo
|
||||||
|
|
||||||
import (
|
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
|
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
||||||
//
|
//
|
||||||
// Note:
|
// 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 {
|
func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
||||||
return b.unixTime(sourceParam, dest, false, time.Second)
|
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
|
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
||||||
//
|
//
|
||||||
// Note:
|
// 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 {
|
func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
||||||
return b.unixTime(sourceParam, dest, true, time.Second)
|
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
|
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
||||||
//
|
//
|
||||||
// Note:
|
// 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 {
|
func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
||||||
return b.unixTime(sourceParam, dest, false, time.Millisecond)
|
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
|
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
||||||
//
|
//
|
||||||
// Note:
|
// 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 {
|
func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
||||||
return b.unixTime(sourceParam, dest, true, time.Millisecond)
|
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
|
// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
|
||||||
//
|
//
|
||||||
// Note:
|
// 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
|
||||||
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
// - 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 {
|
func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
||||||
return b.unixTime(sourceParam, dest, false, time.Nanosecond)
|
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
|
// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
|
||||||
//
|
//
|
||||||
// Note:
|
// 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
|
||||||
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
// - 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 {
|
func (b *ValueBinder) MustUnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
||||||
return b.unixTime(sourceParam, dest, true, time.Nanosecond)
|
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:
|
case time.Second:
|
||||||
*dest = time.Unix(n, 0)
|
*dest = time.Unix(n, 0)
|
||||||
case time.Millisecond:
|
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:
|
case time.Nanosecond:
|
||||||
*dest = time.Unix(0, n)
|
*dest = time.Unix(0, n)
|
||||||
}
|
}
|
||||||
|
61
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
61
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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -13,10 +16,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Context represents the context of the current HTTP request. It holds request and
|
// Context represents the context of the current HTTP request. It holds request and
|
||||||
// response objects, path, path parameters, data and registered handler.
|
// response objects, path, path parameters, data and registered handler.
|
||||||
Context interface {
|
type Context interface {
|
||||||
// Request returns `*http.Request`.
|
// Request returns `*http.Request`.
|
||||||
Request() *http.Request
|
Request() *http.Request
|
||||||
|
|
||||||
@ -100,8 +102,8 @@ type (
|
|||||||
// Set saves data in the context.
|
// Set saves data in the context.
|
||||||
Set(key string, val interface{})
|
Set(key string, val interface{})
|
||||||
|
|
||||||
// Bind binds the request body into provided type `i`. The default binder
|
// Bind binds path params, query params and the request body into provided type `i`. The default binder
|
||||||
// does it based on Content-Type header.
|
// binds body based on Content-Type header.
|
||||||
Bind(i interface{}) error
|
Bind(i interface{}) error
|
||||||
|
|
||||||
// Validate validates provided `i`. It is usually called after `Context#Bind()`.
|
// Validate validates provided `i`. It is usually called after `Context#Bind()`.
|
||||||
@ -197,20 +199,33 @@ type (
|
|||||||
Reset(r *http.Request, w http.ResponseWriter)
|
Reset(r *http.Request, w http.ResponseWriter)
|
||||||
}
|
}
|
||||||
|
|
||||||
context struct {
|
type context struct {
|
||||||
request *http.Request
|
request *http.Request
|
||||||
response *Response
|
response *Response
|
||||||
path string
|
|
||||||
pnames []string
|
|
||||||
pvalues []string
|
|
||||||
query url.Values
|
query url.Values
|
||||||
handler HandlerFunc
|
|
||||||
store Map
|
|
||||||
echo *Echo
|
echo *Echo
|
||||||
logger Logger
|
logger Logger
|
||||||
|
|
||||||
|
store Map
|
||||||
lock sync.RWMutex
|
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 (
|
const (
|
||||||
// ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain.
|
// 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
|
c.pnames = names
|
||||||
|
|
||||||
l := len(names)
|
l := len(names)
|
||||||
if *c.echo.maxParam < l {
|
|
||||||
*c.echo.maxParam = l
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.pvalues) < 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,
|
// 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)
|
newPvalues := make([]string, l)
|
||||||
copy(newPvalues, c.pvalues)
|
copy(newPvalues, c.pvalues)
|
||||||
c.pvalues = newPvalues
|
c.pvalues = newPvalues
|
||||||
@ -347,11 +358,11 @@ func (c *context) ParamValues() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) SetParamValues(values ...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
|
// It will brake the Router#Find code
|
||||||
limit := len(values)
|
limit := len(values)
|
||||||
if limit > *c.echo.maxParam {
|
if limit > len(c.pvalues) {
|
||||||
limit = *c.echo.maxParam
|
c.pvalues = make([]string, limit)
|
||||||
}
|
}
|
||||||
for i := 0; i < limit; i++ {
|
for i := 0; i < limit; i++ {
|
||||||
c.pvalues[i] = values[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 {
|
func (c *context) json(code int, i interface{}, indent string) error {
|
||||||
c.writeContentType(MIMEApplicationJSONCharsetUTF8)
|
c.writeContentType(MIMEApplicationJSON)
|
||||||
c.response.Status = code
|
c.response.Status = code
|
||||||
return c.echo.JSONSerializer.Serialize(c, i, indent)
|
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) {
|
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) {
|
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")
|
return c.contentDisposition(file, name, "inline")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||||
|
|
||||||
func (c *context) contentDisposition(file, name, dispositionType string) error {
|
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)
|
return c.File(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,8 +653,8 @@ func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
|
|||||||
c.path = ""
|
c.path = ""
|
||||||
c.pnames = nil
|
c.pnames = nil
|
||||||
c.logger = nil
|
c.logger = nil
|
||||||
// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
|
// NOTE: Don't reset because it has to have length c.echo.maxParam (or bigger) at all times
|
||||||
for i := 0; i < *c.echo.maxParam; i++ {
|
for i := 0; i < len(c.pvalues); i++ {
|
||||||
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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
64
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
64
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.
|
Package echo implements high performance, minimalist Go web framework.
|
||||||
|
|
||||||
@ -39,6 +42,7 @@ package echo
|
|||||||
import (
|
import (
|
||||||
stdContext "context"
|
stdContext "context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -59,17 +63,16 @@ import (
|
|||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Echo is the top-level framework instance.
|
// Echo is the top-level framework instance.
|
||||||
//
|
//
|
||||||
// Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these
|
// 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.
|
// 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!
|
// Adding new routes after the server has been started is also not safe!
|
||||||
Echo struct {
|
type Echo struct {
|
||||||
filesystem
|
filesystem
|
||||||
common
|
common
|
||||||
// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
|
// 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.
|
// listener address info (on which interface/port was listener bound) without having data races.
|
||||||
startupMutex sync.RWMutex
|
startupMutex sync.RWMutex
|
||||||
colorer *color.Color
|
colorer *color.Color
|
||||||
|
|
||||||
@ -106,50 +109,49 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Route contains a handler and information for matching against requests.
|
// Route contains a handler and information for matching against requests.
|
||||||
Route struct {
|
type Route struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPError represents an error that occurred while handling a request.
|
// HTTPError represents an error that occurred while handling a request.
|
||||||
HTTPError struct {
|
type HTTPError struct {
|
||||||
Code int `json:"-"`
|
Code int `json:"-"`
|
||||||
Message interface{} `json:"message"`
|
Message interface{} `json:"message"`
|
||||||
Internal error `json:"-"` // Stores the error returned by an external dependency
|
Internal error `json:"-"` // Stores the error returned by an external dependency
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiddlewareFunc defines a function to process middleware.
|
// MiddlewareFunc defines a function to process middleware.
|
||||||
MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
type MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
||||||
|
|
||||||
// HandlerFunc defines a function to serve HTTP requests.
|
// HandlerFunc defines a function to serve HTTP requests.
|
||||||
HandlerFunc func(c Context) error
|
type HandlerFunc func(c Context) error
|
||||||
|
|
||||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
// HTTPErrorHandler is a centralized HTTP error handler.
|
||||||
HTTPErrorHandler func(err error, c Context)
|
type HTTPErrorHandler func(err error, c Context)
|
||||||
|
|
||||||
// Validator is the interface that wraps the Validate function.
|
// Validator is the interface that wraps the Validate function.
|
||||||
Validator interface {
|
type Validator interface {
|
||||||
Validate(i interface{}) error
|
Validate(i interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONSerializer is the interface that encodes and decodes JSON to and from interfaces.
|
// JSONSerializer is the interface that encodes and decodes JSON to and from interfaces.
|
||||||
JSONSerializer interface {
|
type JSONSerializer interface {
|
||||||
Serialize(c Context, i interface{}, indent string) error
|
Serialize(c Context, i interface{}, indent string) error
|
||||||
Deserialize(c Context, i interface{}) error
|
Deserialize(c Context, i interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renderer is the interface that wraps the Render function.
|
// Renderer is the interface that wraps the Render function.
|
||||||
Renderer interface {
|
type Renderer interface {
|
||||||
Render(io.Writer, string, interface{}, Context) error
|
Render(io.Writer, string, interface{}, Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map defines a generic map of type `map[string]interface{}`.
|
// Map defines a generic map of type `map[string]interface{}`.
|
||||||
Map map[string]interface{}
|
type Map map[string]interface{}
|
||||||
|
|
||||||
// Common struct for Echo & Group.
|
// Common struct for Echo & Group.
|
||||||
common struct{}
|
type common struct{}
|
||||||
)
|
|
||||||
|
|
||||||
// HTTP methods
|
// HTTP methods
|
||||||
// NOTE: Deprecated, please use the stdlib constants directly instead.
|
// NOTE: Deprecated, please use the stdlib constants directly instead.
|
||||||
@ -168,7 +170,12 @@ const (
|
|||||||
|
|
||||||
// MIME types
|
// MIME types
|
||||||
const (
|
const (
|
||||||
|
// MIMEApplicationJSON JavaScript Object Notation (JSON) https://www.rfc-editor.org/rfc/rfc8259
|
||||||
MIMEApplicationJSON = "application/json"
|
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
|
MIMEApplicationJSONCharsetUTF8 = MIMEApplicationJSON + "; " + charsetUTF8
|
||||||
MIMEApplicationJavaScript = "application/javascript"
|
MIMEApplicationJavaScript = "application/javascript"
|
||||||
MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
|
MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
|
||||||
@ -258,7 +265,7 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Version of Echo
|
// Version of Echo
|
||||||
Version = "4.10.2"
|
Version = "4.12.0"
|
||||||
website = "https://echo.labstack.com"
|
website = "https://echo.labstack.com"
|
||||||
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
||||||
banner = `
|
banner = `
|
||||||
@ -273,8 +280,7 @@ ____________________________________O/_______
|
|||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var methods = [...]string{
|
||||||
methods = [...]string{
|
|
||||||
http.MethodConnect,
|
http.MethodConnect,
|
||||||
http.MethodDelete,
|
http.MethodDelete,
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
@ -287,7 +293,6 @@ var (
|
|||||||
http.MethodTrace,
|
http.MethodTrace,
|
||||||
REPORT,
|
REPORT,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
var (
|
var (
|
||||||
@ -340,13 +345,15 @@ var (
|
|||||||
ErrInvalidListenerNetwork = errors.New("invalid listener network")
|
ErrInvalidListenerNetwork = errors.New("invalid listener network")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error handlers
|
// NotFoundHandler is the handler that router uses in case there was no matching route found. Returns an error that results
|
||||||
var (
|
// HTTP 404 status code.
|
||||||
NotFoundHandler = func(c Context) error {
|
var NotFoundHandler = func(c Context) error {
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodNotAllowedHandler = func(c Context) error {
|
// 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)
|
// 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
|
// 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)
|
routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
|
||||||
@ -355,7 +362,6 @@ var (
|
|||||||
}
|
}
|
||||||
return ErrMethodNotAllowed
|
return ErrMethodNotAllowed
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// New creates an instance of Echo.
|
// New creates an instance of Echo.
|
||||||
func New() (e *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).
|
// 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
|
// 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.
|
// response and status code header has been sent to the client.
|
||||||
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||||
|
|
||||||
@ -438,12 +444,18 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
|||||||
// Issue #1426
|
// Issue #1426
|
||||||
code := he.Code
|
code := he.Code
|
||||||
message := he.Message
|
message := he.Message
|
||||||
if m, ok := he.Message.(string); ok {
|
|
||||||
|
switch m := he.Message.(type) {
|
||||||
|
case string:
|
||||||
if e.Debug {
|
if e.Debug {
|
||||||
message = Map{"message": m, "error": err.Error()}
|
message = Map{"message": m, "error": err.Error()}
|
||||||
} else {
|
} else {
|
||||||
message = Map{"message": m}
|
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
|
// Send response
|
||||||
@ -614,7 +626,7 @@ func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
|
|||||||
return e.URI(h, params...)
|
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 {
|
func (e *Echo) Reverse(name string, params ...interface{}) string {
|
||||||
return e.router.Reverse(name, params...)
|
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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
17
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
17
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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Group is a set of sub-routes for a specified route. It can be used for inner
|
// 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
|
// routes that share a common middleware or functionality that should be separate
|
||||||
// from the parent echo instance while still inheriting from it.
|
// from the parent echo instance while still inheriting from it.
|
||||||
Group struct {
|
type Group struct {
|
||||||
common
|
common
|
||||||
host string
|
host string
|
||||||
prefix string
|
prefix string
|
||||||
middleware []MiddlewareFunc
|
middleware []MiddlewareFunc
|
||||||
echo *Echo
|
echo *Echo
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Use implements `Echo#Use()` for sub-routes within the Group.
|
// Use implements `Echo#Use()` for sub-routes within the Group.
|
||||||
func (g *Group) Use(middleware ...MiddlewareFunc) {
|
func (g *Group) Use(middleware ...MiddlewareFunc) {
|
||||||
@ -23,10 +24,12 @@ func (g *Group) Use(middleware ...MiddlewareFunc) {
|
|||||||
if len(g.middleware) == 0 {
|
if len(g.middleware) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Allow all requests to reach the group as they might get dropped if router
|
// group level middlewares are different from Echo `Pre` and `Use` middlewares (those are global). Group level middlewares
|
||||||
// doesn't find a match, making none of the group middleware process.
|
// are only executed if they are added to the Router with route.
|
||||||
g.Any("", NotFoundHandler)
|
// So we register catch all route (404 is a safe way to emulate route match) for this group and now during routing the
|
||||||
g.Any("/*", NotFoundHandler)
|
// 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.
|
// 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
|
package echo
|
||||||
|
|
||||||
import (
|
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
|
package echo
|
||||||
|
|
||||||
import (
|
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
|
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 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)`.
|
In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`.
|
||||||
@ -225,15 +228,21 @@ func extractIP(req *http.Request) string {
|
|||||||
func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
|
func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
|
||||||
checker := newIPChecker(options)
|
checker := newIPChecker(options)
|
||||||
return func(req *http.Request) string {
|
return func(req *http.Request) string {
|
||||||
|
directIP := extractIP(req)
|
||||||
realIP := req.Header.Get(HeaderXRealIP)
|
realIP := req.Header.Get(HeaderXRealIP)
|
||||||
if realIP != "" {
|
if realIP == "" {
|
||||||
|
return directIP
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker.trust(net.ParseIP(directIP)) {
|
||||||
realIP = strings.TrimPrefix(realIP, "[")
|
realIP = strings.TrimPrefix(realIP, "[")
|
||||||
realIP = strings.TrimSuffix(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 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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
10
vendor/github.com/labstack/echo/v4/log.go
generated
vendored
10
vendor/github.com/labstack/echo/v4/log.go
generated
vendored
@ -1,14 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||||
|
|
||||||
package echo
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Logger defines the logging interface.
|
// Logger defines the logging interface.
|
||||||
Logger interface {
|
type Logger interface {
|
||||||
Output() io.Writer
|
Output() io.Writer
|
||||||
SetOutput(w io.Writer)
|
SetOutput(w io.Writer)
|
||||||
Prefix() string
|
Prefix() string
|
||||||
@ -38,4 +39,3 @@ type (
|
|||||||
Panicj(j log.JSON)
|
Panicj(j log.JSON)
|
||||||
Panicf(format string, args ...interface{})
|
Panicf(format string, args ...interface{})
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
17
vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
generated
vendored
17
vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
generated
vendored
@ -1,17 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||||
|
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// BasicAuthConfig defines the config for BasicAuth middleware.
|
// BasicAuthConfig defines the config for BasicAuth middleware.
|
||||||
BasicAuthConfig struct {
|
type BasicAuthConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -25,21 +27,20 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BasicAuthValidator defines a function to validate BasicAuth credentials.
|
// BasicAuthValidator defines a function to validate BasicAuth credentials.
|
||||||
BasicAuthValidator func(string, string, echo.Context) (bool, error)
|
// 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 (
|
const (
|
||||||
basic = "basic"
|
basic = "basic"
|
||||||
defaultRealm = "Restricted"
|
defaultRealm = "Restricted"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultBasicAuthConfig is the default BasicAuth middleware config.
|
// DefaultBasicAuthConfig is the default BasicAuth middleware config.
|
||||||
DefaultBasicAuthConfig = BasicAuthConfig{
|
var DefaultBasicAuthConfig = BasicAuthConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Realm: defaultRealm,
|
Realm: defaultRealm,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// BasicAuth returns an BasicAuth middleware.
|
// BasicAuth returns an BasicAuth middleware.
|
||||||
//
|
//
|
||||||
|
27
vendor/github.com/labstack/echo/v4/middleware/body_dump.go
generated
vendored
27
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -10,9 +14,8 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// BodyDumpConfig defines the config for BodyDump middleware.
|
// BodyDumpConfig defines the config for BodyDump middleware.
|
||||||
BodyDumpConfig struct {
|
type BodyDumpConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -22,20 +25,17 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BodyDumpHandler receives the request and response payload.
|
// BodyDumpHandler receives the request and response payload.
|
||||||
BodyDumpHandler func(echo.Context, []byte, []byte)
|
type BodyDumpHandler func(echo.Context, []byte, []byte)
|
||||||
|
|
||||||
bodyDumpResponseWriter struct {
|
type bodyDumpResponseWriter struct {
|
||||||
io.Writer
|
io.Writer
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultBodyDumpConfig is the default BodyDump middleware config.
|
// DefaultBodyDumpConfig is the default BodyDump middleware config.
|
||||||
DefaultBodyDumpConfig = BodyDumpConfig{
|
var DefaultBodyDumpConfig = BodyDumpConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// BodyDump returns a BodyDump middleware.
|
// BodyDump returns a BodyDump middleware.
|
||||||
//
|
//
|
||||||
@ -98,9 +98,16 @@ func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *bodyDumpResponseWriter) Flush() {
|
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) {
|
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
|
||||||
}
|
}
|
||||||
|
19
vendor/github.com/labstack/echo/v4/middleware/body_limit.go
generated
vendored
19
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,9 +12,8 @@ import (
|
|||||||
"github.com/labstack/gommon/bytes"
|
"github.com/labstack/gommon/bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// BodyLimitConfig defines the config for BodyLimit middleware.
|
// BodyLimitConfig defines the config for BodyLimit middleware.
|
||||||
BodyLimitConfig struct {
|
type BodyLimitConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -21,20 +23,16 @@ type (
|
|||||||
limit int64
|
limit int64
|
||||||
}
|
}
|
||||||
|
|
||||||
limitedReader struct {
|
type limitedReader struct {
|
||||||
BodyLimitConfig
|
BodyLimitConfig
|
||||||
reader io.ReadCloser
|
reader io.ReadCloser
|
||||||
read int64
|
read int64
|
||||||
context echo.Context
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultBodyLimitConfig is the default BodyLimit middleware config.
|
// DefaultBodyLimitConfig is the default BodyLimit middleware config.
|
||||||
DefaultBodyLimitConfig = BodyLimitConfig{
|
var DefaultBodyLimitConfig = BodyLimitConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// BodyLimit returns a BodyLimit middleware.
|
// BodyLimit returns a BodyLimit middleware.
|
||||||
//
|
//
|
||||||
@ -80,7 +78,7 @@ func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
// Based on content read
|
// Based on content read
|
||||||
r := pool.Get().(*limitedReader)
|
r := pool.Get().(*limitedReader)
|
||||||
r.Reset(req.Body, c)
|
r.Reset(req.Body)
|
||||||
defer pool.Put(r)
|
defer pool.Put(r)
|
||||||
req.Body = r
|
req.Body = r
|
||||||
|
|
||||||
@ -102,9 +100,8 @@ func (r *limitedReader) Close() error {
|
|||||||
return r.reader.Close()
|
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.reader = reader
|
||||||
r.context = context
|
|
||||||
r.read = 0
|
r.read = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
vendor/github.com/labstack/echo/v4/middleware/compress.go
generated
vendored
114
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -12,35 +16,50 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// GzipConfig defines the config for Gzip middleware.
|
// GzipConfig defines the config for Gzip middleware.
|
||||||
GzipConfig struct {
|
type GzipConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
// Gzip compression level.
|
// Gzip compression level.
|
||||||
// Optional. Default value -1.
|
// Optional. Default value -1.
|
||||||
Level int `yaml:"level"`
|
Level int `yaml:"level"`
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
gzipResponseWriter struct {
|
type gzipResponseWriter struct {
|
||||||
io.Writer
|
io.Writer
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
|
wroteHeader bool
|
||||||
wroteBody bool
|
wroteBody bool
|
||||||
|
minLength int
|
||||||
|
minLengthExceeded bool
|
||||||
|
buffer *bytes.Buffer
|
||||||
|
code int
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
gzipScheme = "gzip"
|
gzipScheme = "gzip"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultGzipConfig is the default Gzip middleware config.
|
// DefaultGzipConfig is the default Gzip middleware config.
|
||||||
DefaultGzipConfig = GzipConfig{
|
var DefaultGzipConfig = GzipConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Level: -1,
|
Level: -1,
|
||||||
|
MinLength: 0,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Gzip returns a middleware which compresses HTTP response using gzip compression
|
// Gzip returns a middleware which compresses HTTP response using gzip compression
|
||||||
// scheme.
|
// scheme.
|
||||||
@ -58,8 +77,12 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
|||||||
if config.Level == 0 {
|
if config.Level == 0 {
|
||||||
config.Level = DefaultGzipConfig.Level
|
config.Level = DefaultGzipConfig.Level
|
||||||
}
|
}
|
||||||
|
if config.MinLength < 0 {
|
||||||
|
config.MinLength = DefaultGzipConfig.MinLength
|
||||||
|
}
|
||||||
|
|
||||||
pool := gzipCompressPool(config)
|
pool := gzipCompressPool(config)
|
||||||
|
bpool := bufferPool()
|
||||||
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
@ -70,7 +93,6 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
|||||||
res := c.Response()
|
res := c.Response()
|
||||||
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
|
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
|
||||||
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
|
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
|
||||||
res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
|
|
||||||
i := pool.Get()
|
i := pool.Get()
|
||||||
w, ok := i.(*gzip.Writer)
|
w, ok := i.(*gzip.Writer)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -78,19 +100,38 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
rw := res.Writer
|
rw := res.Writer
|
||||||
w.Reset(rw)
|
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() {
|
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 !grw.wroteBody {
|
||||||
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
|
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
|
||||||
res.Header().Del(echo.HeaderContentEncoding)
|
res.Header().Del(echo.HeaderContentEncoding)
|
||||||
}
|
}
|
||||||
|
if grw.wroteHeader {
|
||||||
|
rw.WriteHeader(grw.code)
|
||||||
|
}
|
||||||
// We have to reset response to it's pristine state when
|
// We have to reset response to it's pristine state when
|
||||||
// nothing is written to body or error is returned.
|
// nothing is written to body or error is returned.
|
||||||
// See issue #424, #407.
|
// See issue #424, #407.
|
||||||
res.Writer = rw
|
res.Writer = rw
|
||||||
w.Reset(io.Discard)
|
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()
|
w.Close()
|
||||||
|
bpool.Put(buf)
|
||||||
pool.Put(w)
|
pool.Put(w)
|
||||||
}()
|
}()
|
||||||
res.Writer = grw
|
res.Writer = grw
|
||||||
@ -102,7 +143,11 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
func (w *gzipResponseWriter) WriteHeader(code int) {
|
func (w *gzipResponseWriter) WriteHeader(code int) {
|
||||||
w.Header().Del(echo.HeaderContentLength) // Issue #444
|
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) {
|
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.Header().Set(echo.HeaderContentType, http.DetectContentType(b))
|
||||||
}
|
}
|
||||||
w.wroteBody = true
|
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)
|
return w.Writer.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *gzipResponseWriter) Flush() {
|
func (w *gzipResponseWriter) Flush() {
|
||||||
w.Writer.(*gzip.Writer).Flush()
|
if !w.minLengthExceeded {
|
||||||
if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
|
// Enforce compression because we will not know how much more data will come
|
||||||
flusher.Flush()
|
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) {
|
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 {
|
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -13,7 +16,7 @@ type ContextTimeoutConfig struct {
|
|||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
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
|
ErrorHandler func(err error, c echo.Context) error
|
||||||
|
|
||||||
// Timeout configures a timeout for the middleware, defaults to 0 for no timeout
|
// Timeout configures a timeout for the middleware, defaults to 0 for no timeout
|
||||||
|
28
vendor/github.com/labstack/echo/v4/middleware/cors.go
generated
vendored
28
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,9 +12,8 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// CORSConfig defines the config for CORS middleware.
|
// CORSConfig defines the config for CORS middleware.
|
||||||
CORSConfig struct {
|
type CORSConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ type (
|
|||||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||||
//
|
//
|
||||||
// Optional.
|
// Optional.
|
||||||
AllowOriginFunc func(origin string) (bool, error) `yaml:"allow_origin_func"`
|
AllowOriginFunc func(origin string) (bool, error) `yaml:"-"`
|
||||||
|
|
||||||
// AllowMethods determines the value of the Access-Control-Allow-Methods
|
// AllowMethods determines the value of the Access-Control-Allow-Methods
|
||||||
// response header. This header specified the list of methods allowed when
|
// response header. This header specified the list of methods allowed when
|
||||||
@ -99,22 +101,20 @@ type (
|
|||||||
// MaxAge determines the value of the Access-Control-Max-Age response header.
|
// MaxAge determines the value of the Access-Control-Max-Age response header.
|
||||||
// This header indicates how long (in seconds) the results of a preflight
|
// This header indicates how long (in seconds) the results of a preflight
|
||||||
// request can be cached.
|
// 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. The header is set only if MaxAge > 0.
|
// 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
|
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||||
MaxAge int `yaml:"max_age"`
|
MaxAge int `yaml:"max_age"`
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultCORSConfig is the default CORS middleware config.
|
// DefaultCORSConfig is the default CORS middleware config.
|
||||||
DefaultCORSConfig = CORSConfig{
|
var DefaultCORSConfig = CORSConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
AllowOrigins: []string{"*"},
|
AllowOrigins: []string{"*"},
|
||||||
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
|
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
|
// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
|
||||||
// See also [MDN: Cross-Origin Resource Sharing (CORS)].
|
// See also [MDN: Cross-Origin Resource Sharing (CORS)].
|
||||||
@ -150,8 +150,8 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
|||||||
allowOriginPatterns := []string{}
|
allowOriginPatterns := []string{}
|
||||||
for _, origin := range config.AllowOrigins {
|
for _, origin := range config.AllowOrigins {
|
||||||
pattern := regexp.QuoteMeta(origin)
|
pattern := regexp.QuoteMeta(origin)
|
||||||
pattern = strings.Replace(pattern, "\\*", ".*", -1)
|
pattern = strings.ReplaceAll(pattern, "\\*", ".*")
|
||||||
pattern = strings.Replace(pattern, "\\?", ".", -1)
|
pattern = strings.ReplaceAll(pattern, "\\?", ".")
|
||||||
pattern = "^" + pattern + "$"
|
pattern = "^" + pattern + "$"
|
||||||
allowOriginPatterns = append(allowOriginPatterns, pattern)
|
allowOriginPatterns = append(allowOriginPatterns, pattern)
|
||||||
}
|
}
|
||||||
@ -159,7 +159,11 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
|||||||
allowMethods := strings.Join(config.AllowMethods, ",")
|
allowMethods := strings.Join(config.AllowMethods, ",")
|
||||||
allowHeaders := strings.Join(config.AllowHeaders, ",")
|
allowHeaders := strings.Join(config.AllowHeaders, ",")
|
||||||
exposeHeaders := strings.Join(config.ExposeHeaders, ",")
|
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(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
@ -282,7 +286,7 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
|||||||
res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
|
res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.MaxAge > 0 {
|
if config.MaxAge != 0 {
|
||||||
res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
|
res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
|
||||||
}
|
}
|
||||||
return c.NoContent(http.StatusNoContent)
|
return c.NoContent(http.StatusNoContent)
|
||||||
|
17
vendor/github.com/labstack/echo/v4/middleware/csrf.go
generated
vendored
17
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,12 +9,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/labstack/gommon/random"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// CSRFConfig defines the config for CSRF middleware.
|
// CSRFConfig defines the config for CSRF middleware.
|
||||||
CSRFConfig struct {
|
type CSRFConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -67,15 +68,13 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CSRFErrorHandler is a function which is executed for creating custom errors.
|
// CSRFErrorHandler is a function which is executed for creating custom errors.
|
||||||
CSRFErrorHandler func(err error, c echo.Context) error
|
type CSRFErrorHandler func(err error, c echo.Context) error
|
||||||
)
|
|
||||||
|
|
||||||
// ErrCSRFInvalid is returned when CSRF check fails
|
// ErrCSRFInvalid is returned when CSRF check fails
|
||||||
var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
|
var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultCSRFConfig is the default CSRF middleware config.
|
// DefaultCSRFConfig is the default CSRF middleware config.
|
||||||
DefaultCSRFConfig = CSRFConfig{
|
var DefaultCSRFConfig = CSRFConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
TokenLength: 32,
|
TokenLength: 32,
|
||||||
TokenLookup: "header:" + echo.HeaderXCSRFToken,
|
TokenLookup: "header:" + echo.HeaderXCSRFToken,
|
||||||
@ -84,7 +83,6 @@ var (
|
|||||||
CookieMaxAge: 86400,
|
CookieMaxAge: 86400,
|
||||||
CookieSameSite: http.SameSiteDefaultMode,
|
CookieSameSite: http.SameSiteDefaultMode,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// CSRF returns a Cross-Site Request Forgery (CSRF) middleware.
|
// CSRF returns a Cross-Site Request Forgery (CSRF) middleware.
|
||||||
// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery
|
// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery
|
||||||
@ -103,6 +101,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
|||||||
if config.TokenLength == 0 {
|
if config.TokenLength == 0 {
|
||||||
config.TokenLength = DefaultCSRFConfig.TokenLength
|
config.TokenLength = DefaultCSRFConfig.TokenLength
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TokenLookup == "" {
|
if config.TokenLookup == "" {
|
||||||
config.TokenLookup = DefaultCSRFConfig.TokenLookup
|
config.TokenLookup = DefaultCSRFConfig.TokenLookup
|
||||||
}
|
}
|
||||||
@ -132,7 +131,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
token := ""
|
token := ""
|
||||||
if k, err := c.Cookie(config.CookieName); err != nil {
|
if k, err := c.Cookie(config.CookieName); err != nil {
|
||||||
token = random.String(config.TokenLength) // Generate token
|
token = randomString(config.TokenLength)
|
||||||
} else {
|
} else {
|
||||||
token = k.Value // Reuse token
|
token = k.Value // Reuse token
|
||||||
}
|
}
|
||||||
|
11
vendor/github.com/labstack/echo/v4/middleware/decompress.go
generated
vendored
11
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,16 +12,14 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// DecompressConfig defines the config for Decompress middleware.
|
// DecompressConfig defines the config for Decompress middleware.
|
||||||
DecompressConfig struct {
|
type DecompressConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
// GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers
|
// GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers
|
||||||
GzipDecompressPool Decompressor
|
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"
|
const GZIPEncoding string = "gzip"
|
||||||
@ -28,13 +29,11 @@ type Decompressor interface {
|
|||||||
gzipDecompressPool() sync.Pool
|
gzipDecompressPool() sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultDecompressConfig defines the config for decompress middleware
|
// DefaultDecompressConfig defines the config for decompress middleware
|
||||||
DefaultDecompressConfig = DecompressConfig{
|
var DefaultDecompressConfig = DecompressConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
GzipDecompressPool: &DefaultGzipDecompressPool{},
|
GzipDecompressPool: &DefaultGzipDecompressPool{},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// DefaultGzipDecompressPool is the default implementation of Decompressor interface
|
// DefaultGzipDecompressPool is the default implementation of Decompressor interface
|
||||||
type DefaultGzipDecompressPool struct {
|
type DefaultGzipDecompressPool struct {
|
||||||
|
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
27
vendor/github.com/labstack/echo/v4/middleware/jwt.go
generated
vendored
27
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
|
//go:build go1.15
|
||||||
// +build go1.15
|
// +build go1.15
|
||||||
|
|
||||||
@ -12,9 +15,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// JWTConfig defines the config for JWT middleware.
|
// JWTConfig defines the config for JWT middleware.
|
||||||
JWTConfig struct {
|
type JWTConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -112,29 +114,27 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JWTSuccessHandler defines a function which is executed for a valid token.
|
// JWTSuccessHandler defines a function which is executed for a valid token.
|
||||||
JWTSuccessHandler func(c echo.Context)
|
type JWTSuccessHandler func(c echo.Context)
|
||||||
|
|
||||||
// JWTErrorHandler defines a function which is executed for an invalid token.
|
// JWTErrorHandler defines a function which is executed for an invalid token.
|
||||||
JWTErrorHandler func(err error) error
|
type JWTErrorHandler func(err error) error
|
||||||
|
|
||||||
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
|
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
|
||||||
JWTErrorHandlerWithContext func(err error, c echo.Context) error
|
type JWTErrorHandlerWithContext func(err error, c echo.Context) error
|
||||||
)
|
|
||||||
|
|
||||||
// Algorithms
|
// Algorithms
|
||||||
const (
|
const (
|
||||||
AlgorithmHS256 = "HS256"
|
AlgorithmHS256 = "HS256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors
|
// ErrJWTMissing is error that is returned when no JWToken was extracted from the request.
|
||||||
var (
|
var ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
|
||||||
ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
|
|
||||||
ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
|
// ErrJWTInvalid is error that is returned when middleware could not parse JWT correctly.
|
||||||
)
|
var ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultJWTConfig is the default JWT auth middleware config.
|
// DefaultJWTConfig is the default JWT auth middleware config.
|
||||||
DefaultJWTConfig = JWTConfig{
|
var DefaultJWTConfig = JWTConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
SigningMethod: AlgorithmHS256,
|
SigningMethod: AlgorithmHS256,
|
||||||
ContextKey: "user",
|
ContextKey: "user",
|
||||||
@ -144,7 +144,6 @@ var (
|
|||||||
Claims: jwt.MapClaims{},
|
Claims: jwt.MapClaims{},
|
||||||
KeyFunc: nil,
|
KeyFunc: nil,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// JWT returns a JSON Web Token (JWT) auth middleware.
|
// JWT returns a JSON Web Token (JWT) auth middleware.
|
||||||
//
|
//
|
||||||
|
27
vendor/github.com/labstack/echo/v4/middleware/key_auth.go
generated
vendored
27
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,9 +9,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// KeyAuthConfig defines the config for KeyAuth middleware.
|
// KeyAuthConfig defines the config for KeyAuth middleware.
|
||||||
KeyAuthConfig struct {
|
type KeyAuthConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -49,26 +51,23 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KeyAuthValidator defines a function to validate KeyAuth credentials.
|
// KeyAuthValidator defines a function to validate KeyAuth credentials.
|
||||||
KeyAuthValidator func(auth string, c echo.Context) (bool, error)
|
type KeyAuthValidator func(auth string, c echo.Context) (bool, error)
|
||||||
|
|
||||||
// KeyAuthErrorHandler defines a function which is executed for an invalid key.
|
// KeyAuthErrorHandler defines a function which is executed for an invalid key.
|
||||||
KeyAuthErrorHandler func(err error, c echo.Context) error
|
type 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",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups
|
// ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups
|
||||||
type ErrKeyAuthMissing struct {
|
type ErrKeyAuthMissing struct {
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultKeyAuthConfig is the default KeyAuth middleware config.
|
||||||
|
var DefaultKeyAuthConfig = KeyAuthConfig{
|
||||||
|
Skipper: DefaultSkipper,
|
||||||
|
KeyLookup: "header:" + echo.HeaderAuthorization,
|
||||||
|
AuthScheme: "Bearer",
|
||||||
|
}
|
||||||
|
|
||||||
// Error returns errors text
|
// Error returns errors text
|
||||||
func (e *ErrKeyAuthMissing) Error() string {
|
func (e *ErrKeyAuthMissing) Error() string {
|
||||||
return e.Err.Error()
|
return e.Err.Error()
|
||||||
|
11
vendor/github.com/labstack/echo/v4/middleware/logger.go
generated
vendored
11
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -14,9 +17,8 @@ import (
|
|||||||
"github.com/valyala/fasttemplate"
|
"github.com/valyala/fasttemplate"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// LoggerConfig defines the config for Logger middleware.
|
// LoggerConfig defines the config for Logger middleware.
|
||||||
LoggerConfig struct {
|
type LoggerConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -71,11 +73,9 @@ type (
|
|||||||
colorer *color.Color
|
colorer *color.Color
|
||||||
pool *sync.Pool
|
pool *sync.Pool
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultLoggerConfig is the default Logger middleware config.
|
// DefaultLoggerConfig is the default Logger middleware config.
|
||||||
DefaultLoggerConfig = LoggerConfig{
|
var DefaultLoggerConfig = LoggerConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` +
|
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` +
|
||||||
`"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
|
`"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
|
||||||
@ -84,7 +84,6 @@ var (
|
|||||||
CustomTimeFormat: "2006-01-02 15:04:05.00000",
|
CustomTimeFormat: "2006-01-02 15:04:05.00000",
|
||||||
colorer: color.New(),
|
colorer: color.New(),
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Logger returns a middleware that logs HTTP requests.
|
// Logger returns a middleware that logs HTTP requests.
|
||||||
func Logger() echo.MiddlewareFunc {
|
func Logger() echo.MiddlewareFunc {
|
||||||
|
13
vendor/github.com/labstack/echo/v4/middleware/method_override.go
generated
vendored
13
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,9 +9,8 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// MethodOverrideConfig defines the config for MethodOverride middleware.
|
// MethodOverrideConfig defines the config for MethodOverride middleware.
|
||||||
MethodOverrideConfig struct {
|
type MethodOverrideConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -18,16 +20,13 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MethodOverrideGetter is a function that gets overridden method from the request
|
// MethodOverrideGetter is a function that gets overridden method from the request
|
||||||
MethodOverrideGetter func(echo.Context) string
|
type MethodOverrideGetter func(echo.Context) string
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultMethodOverrideConfig is the default MethodOverride middleware config.
|
// DefaultMethodOverrideConfig is the default MethodOverride middleware config.
|
||||||
DefaultMethodOverrideConfig = MethodOverrideConfig{
|
var DefaultMethodOverrideConfig = MethodOverrideConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),
|
Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// MethodOverride returns a MethodOverride middleware.
|
// MethodOverride returns a MethodOverride middleware.
|
||||||
// MethodOverride middleware checks for the overridden method from the request and
|
// MethodOverride middleware checks for the overridden method from the request and
|
||||||
|
15
vendor/github.com/labstack/echo/v4/middleware/middleware.go
generated
vendored
15
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,14 +12,12 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Skipper defines a function to skip middleware. Returning true skips processing
|
// Skipper defines a function to skip middleware. Returning true skips processing
|
||||||
// the middleware.
|
// the middleware.
|
||||||
Skipper func(c echo.Context) bool
|
type Skipper func(c echo.Context) bool
|
||||||
|
|
||||||
// BeforeFunc defines a function which is executed just before the middleware.
|
// BeforeFunc defines a function which is executed just before the middleware.
|
||||||
BeforeFunc func(c echo.Context)
|
type BeforeFunc func(c echo.Context)
|
||||||
)
|
|
||||||
|
|
||||||
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
||||||
groups := pattern.FindAllStringSubmatch(input, -1)
|
groups := pattern.FindAllStringSubmatch(input, -1)
|
||||||
@ -38,9 +39,9 @@ func rewriteRulesRegex(rewrite map[string]string) map[*regexp.Regexp]string {
|
|||||||
rulesRegex := map[*regexp.Regexp]string{}
|
rulesRegex := map[*regexp.Regexp]string{}
|
||||||
for k, v := range rewrite {
|
for k, v := range rewrite {
|
||||||
k = regexp.QuoteMeta(k)
|
k = regexp.QuoteMeta(k)
|
||||||
k = strings.Replace(k, `\*`, "(.*?)", -1)
|
k = strings.ReplaceAll(k, `\*`, "(.*?)")
|
||||||
if strings.HasPrefix(k, `\^`) {
|
if strings.HasPrefix(k, `\^`) {
|
||||||
k = strings.Replace(k, `\^`, "^", -1)
|
k = strings.ReplaceAll(k, `\^`, "^")
|
||||||
}
|
}
|
||||||
k = k + "$"
|
k = k + "$"
|
||||||
rulesRegex[regexp.MustCompile(k)] = v
|
rulesRegex[regexp.MustCompile(k)] = v
|
||||||
@ -53,7 +54,7 @@ func rewriteURL(rewriteRegex map[*regexp.Regexp]string, req *http.Request) error
|
|||||||
return nil
|
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
|
// We only want to use path part for rewriting and therefore trim prefix if it exists
|
||||||
rawURI := req.RequestURI
|
rawURI := req.RequestURI
|
||||||
if rawURI != "" && rawURI[0] != '/' {
|
if rawURI != "" && rawURI[0] != '/' {
|
||||||
|
225
vendor/github.com/labstack/echo/v4/middleware/proxy.go
generated
vendored
225
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -12,7 +15,6 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
@ -20,9 +22,8 @@ import (
|
|||||||
|
|
||||||
// TODO: Handle TLS proxy
|
// TODO: Handle TLS proxy
|
||||||
|
|
||||||
type (
|
|
||||||
// ProxyConfig defines the config for Proxy middleware.
|
// ProxyConfig defines the config for Proxy middleware.
|
||||||
ProxyConfig struct {
|
type ProxyConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -30,6 +31,33 @@ type (
|
|||||||
// Required.
|
// Required.
|
||||||
Balancer ProxyBalancer
|
Balancer ProxyBalancer
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
|
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
|
||||||
// retrieved by index e.g. $1, $2 and so on.
|
// retrieved by index e.g. $1, $2 and so on.
|
||||||
// Examples:
|
// Examples:
|
||||||
@ -59,62 +87,61 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProxyTarget defines the upstream target.
|
// ProxyTarget defines the upstream target.
|
||||||
ProxyTarget struct {
|
type ProxyTarget struct {
|
||||||
Name string
|
Name string
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
Meta echo.Map
|
Meta echo.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyBalancer defines an interface to implement a load balancing technique.
|
// ProxyBalancer defines an interface to implement a load balancing technique.
|
||||||
ProxyBalancer interface {
|
type ProxyBalancer interface {
|
||||||
AddTarget(*ProxyTarget) bool
|
AddTarget(*ProxyTarget) bool
|
||||||
RemoveTarget(string) bool
|
RemoveTarget(string) bool
|
||||||
Next(echo.Context) *ProxyTarget
|
Next(echo.Context) *ProxyTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
// TargetProvider defines an interface that gives the opportunity for balancer to return custom errors when selecting target.
|
// TargetProvider defines an interface that gives the opportunity for balancer
|
||||||
TargetProvider interface {
|
// to return custom errors when selecting target.
|
||||||
|
type TargetProvider interface {
|
||||||
NextTarget(echo.Context) (*ProxyTarget, error)
|
NextTarget(echo.Context) (*ProxyTarget, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
commonBalancer struct {
|
type commonBalancer struct {
|
||||||
targets []*ProxyTarget
|
targets []*ProxyTarget
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomBalancer implements a random load balancing technique.
|
// RandomBalancer implements a random load balancing technique.
|
||||||
randomBalancer struct {
|
type randomBalancer struct {
|
||||||
*commonBalancer
|
commonBalancer
|
||||||
random *rand.Rand
|
random *rand.Rand
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoundRobinBalancer implements a round-robin load balancing technique.
|
// RoundRobinBalancer implements a round-robin load balancing technique.
|
||||||
roundRobinBalancer struct {
|
type roundRobinBalancer struct {
|
||||||
*commonBalancer
|
commonBalancer
|
||||||
i uint32
|
// tracking the index on `targets` slice for the next `*ProxyTarget` to be used
|
||||||
|
i int
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultProxyConfig is the default Proxy middleware config.
|
// DefaultProxyConfig is the default Proxy middleware config.
|
||||||
DefaultProxyConfig = ProxyConfig{
|
var DefaultProxyConfig = ProxyConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
ContextKey: "target",
|
ContextKey: "target",
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
in, _, err := c.Response().Hijack()
|
in, _, err := c.Response().Hijack()
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
defer in.Close()
|
defer in.Close()
|
||||||
|
|
||||||
out, err := net.Dial("tcp", t.URL.Host)
|
out, err := net.Dial("tcp", t.URL.Host)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
@ -122,7 +149,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
|||||||
// Write header
|
// Write header
|
||||||
err = r.Write(out)
|
err = r.Write(out)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,39 +163,44 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
|||||||
go cp(in, out)
|
go cp(in, out)
|
||||||
err = <-errCh
|
err = <-errCh
|
||||||
if err != nil && err != io.EOF {
|
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.
|
// NewRandomBalancer returns a random proxy balancer.
|
||||||
func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer {
|
func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer {
|
||||||
b := &randomBalancer{commonBalancer: new(commonBalancer)}
|
b := randomBalancer{}
|
||||||
b.targets = targets
|
b.targets = targets
|
||||||
return b
|
b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||||
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRoundRobinBalancer returns a round-robin proxy balancer.
|
// NewRoundRobinBalancer returns a round-robin proxy balancer.
|
||||||
func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer {
|
func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer {
|
||||||
b := &roundRobinBalancer{commonBalancer: new(commonBalancer)}
|
b := roundRobinBalancer{}
|
||||||
b.targets = targets
|
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 {
|
func (b *commonBalancer) AddTarget(target *ProxyTarget) bool {
|
||||||
|
b.mutex.Lock()
|
||||||
|
defer b.mutex.Unlock()
|
||||||
for _, t := range b.targets {
|
for _, t := range b.targets {
|
||||||
if t.Name == target.Name {
|
if t.Name == target.Name {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.mutex.Lock()
|
|
||||||
defer b.mutex.Unlock()
|
|
||||||
b.targets = append(b.targets, target)
|
b.targets = append(b.targets, target)
|
||||||
return true
|
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 {
|
func (b *commonBalancer) RemoveTarget(name string) bool {
|
||||||
b.mutex.Lock()
|
b.mutex.Lock()
|
||||||
defer b.mutex.Unlock()
|
defer b.mutex.Unlock()
|
||||||
@ -182,21 +214,58 @@ func (b *commonBalancer) RemoveTarget(name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Next randomly returns an upstream target.
|
// 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 {
|
func (b *randomBalancer) Next(c echo.Context) *ProxyTarget {
|
||||||
if b.random == nil {
|
b.mutex.Lock()
|
||||||
b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
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))]
|
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 {
|
func (b *roundRobinBalancer) Next(c echo.Context) *ProxyTarget {
|
||||||
b.i = b.i % uint32(len(b.targets))
|
b.mutex.Lock()
|
||||||
t := b.targets[b.i]
|
defer b.mutex.Unlock()
|
||||||
atomic.AddUint32(&b.i, 1)
|
if len(b.targets) == 0 {
|
||||||
return t
|
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.
|
// Proxy returns a Proxy middleware.
|
||||||
@ -211,14 +280,26 @@ func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
|
|||||||
// ProxyWithConfig returns a Proxy middleware with config.
|
// ProxyWithConfig returns a Proxy middleware with config.
|
||||||
// See: `Proxy()`
|
// See: `Proxy()`
|
||||||
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||||
|
if config.Balancer == nil {
|
||||||
|
panic("echo: proxy middleware requires balancer")
|
||||||
|
}
|
||||||
// Defaults
|
// Defaults
|
||||||
if config.Skipper == nil {
|
if config.Skipper == nil {
|
||||||
config.Skipper = DefaultProxyConfig.Skipper
|
config.Skipper = DefaultProxyConfig.Skipper
|
||||||
}
|
}
|
||||||
if config.Balancer == nil {
|
if config.RetryFilter == nil {
|
||||||
panic("echo: proxy middleware requires balancer")
|
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.Rewrite != nil {
|
||||||
if config.RegexRewrite == nil {
|
if config.RegexRewrite == nil {
|
||||||
config.RegexRewrite = make(map[*regexp.Regexp]string)
|
config.RegexRewrite = make(map[*regexp.Regexp]string)
|
||||||
@ -229,28 +310,17 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider, isTargetProvider := config.Balancer.(TargetProvider)
|
provider, isTargetProvider := config.Balancer.(TargetProvider)
|
||||||
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) (err error) {
|
return func(c echo.Context) error {
|
||||||
if config.Skipper(c) {
|
if config.Skipper(c) {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := c.Request()
|
req := c.Request()
|
||||||
res := c.Response()
|
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 {
|
if err := rewriteURL(config.RegexRewrite, req); err != nil {
|
||||||
return err
|
return config.ErrorHandler(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix header
|
// Fix header
|
||||||
@ -266,19 +336,52 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
|||||||
req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
|
req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// Proxy
|
||||||
switch {
|
switch {
|
||||||
case c.IsWebSocket():
|
case c.IsWebSocket():
|
||||||
proxyRaw(tgt, c).ServeHTTP(res, req)
|
proxyRaw(tgt, c).ServeHTTP(res, req)
|
||||||
case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
|
default: // even SSE requests
|
||||||
default:
|
|
||||||
proxyHTTP(tgt, c, config).ServeHTTP(res, req)
|
proxyHTTP(tgt, c, config).ServeHTTP(res, req)
|
||||||
}
|
}
|
||||||
if e, ok := c.Get("_error").(error); ok {
|
|
||||||
err = e
|
err, hasError := c.Get("_error").(error)
|
||||||
|
if !hasError {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
retry := retries > 0 && config.RetryFilter(c, err)
|
||||||
|
if !retry {
|
||||||
|
return config.ErrorHandler(c, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retries--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
generated
vendored
52
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,17 +12,14 @@ import (
|
|||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// RateLimiterStore is the interface to be implemented by custom stores.
|
// RateLimiterStore is the interface to be implemented by custom stores.
|
||||||
RateLimiterStore interface {
|
type RateLimiterStore interface {
|
||||||
// Stores for the rate limiter have to implement the Allow method
|
// Stores for the rate limiter have to implement the Allow method
|
||||||
Allow(identifier string) (bool, error)
|
Allow(identifier string) (bool, error)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// RateLimiterConfig defines the configuration for the rate limiter
|
// RateLimiterConfig defines the configuration for the rate limiter
|
||||||
RateLimiterConfig struct {
|
type RateLimiterConfig struct {
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
BeforeFunc BeforeFunc
|
BeforeFunc BeforeFunc
|
||||||
// IdentifierExtractor uses echo.Context to extract the identifier for a visitor
|
// IdentifierExtractor uses echo.Context to extract the identifier for a visitor
|
||||||
@ -31,17 +31,15 @@ type (
|
|||||||
// DenyHandler provides a handler to be called when RateLimiter denies access
|
// DenyHandler provides a handler to be called when RateLimiter denies access
|
||||||
DenyHandler func(context echo.Context, identifier string, err error) error
|
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
// errors
|
// Extractor is used to extract data from echo.Context
|
||||||
var (
|
type Extractor func(context echo.Context) (string, error)
|
||||||
|
|
||||||
// ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
|
// ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
|
||||||
ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
|
var ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
|
||||||
|
|
||||||
// ErrExtractorError denotes an error raised when extractor function is unsuccessful
|
// ErrExtractorError denotes an error raised when extractor function is unsuccessful
|
||||||
ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
|
var ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
|
||||||
)
|
|
||||||
|
|
||||||
// DefaultRateLimiterConfig defines default values for RateLimiterConfig
|
// DefaultRateLimiterConfig defines default values for RateLimiterConfig
|
||||||
var DefaultRateLimiterConfig = RateLimiterConfig{
|
var DefaultRateLimiterConfig = RateLimiterConfig{
|
||||||
@ -150,9 +148,8 @@ func RateLimiterWithConfig(config RateLimiterConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
|
||||||
// RateLimiterMemoryStore is the built-in store implementation for RateLimiter
|
// RateLimiterMemoryStore is the built-in store implementation for RateLimiter
|
||||||
RateLimiterMemoryStore struct {
|
type RateLimiterMemoryStore struct {
|
||||||
visitors map[string]*Visitor
|
visitors map[string]*Visitor
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
||||||
@ -160,13 +157,15 @@ type (
|
|||||||
burst int
|
burst int
|
||||||
expiresIn time.Duration
|
expiresIn time.Duration
|
||||||
lastCleanup time.Time
|
lastCleanup time.Time
|
||||||
|
|
||||||
|
timeNow func() time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visitor signifies a unique user's limiter details
|
// Visitor signifies a unique user's limiter details
|
||||||
Visitor struct {
|
type Visitor struct {
|
||||||
*rate.Limiter
|
*rate.Limiter
|
||||||
lastSeen time.Time
|
lastSeen time.Time
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with
|
NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with
|
||||||
@ -219,7 +218,8 @@ func NewRateLimiterMemoryStoreWithConfig(config RateLimiterMemoryStoreConfig) (s
|
|||||||
store.burst = int(config.Rate)
|
store.burst = int(config.Rate)
|
||||||
}
|
}
|
||||||
store.visitors = make(map[string]*Visitor)
|
store.visitors = make(map[string]*Visitor)
|
||||||
store.lastCleanup = now()
|
store.timeNow = time.Now
|
||||||
|
store.lastCleanup = store.timeNow()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,12 +244,13 @@ func (store *RateLimiterMemoryStore) Allow(identifier string) (bool, error) {
|
|||||||
limiter.Limiter = rate.NewLimiter(store.rate, store.burst)
|
limiter.Limiter = rate.NewLimiter(store.rate, store.burst)
|
||||||
store.visitors[identifier] = limiter
|
store.visitors[identifier] = limiter
|
||||||
}
|
}
|
||||||
limiter.lastSeen = now()
|
now := store.timeNow()
|
||||||
if now().Sub(store.lastCleanup) > store.expiresIn {
|
limiter.lastSeen = now
|
||||||
|
if now.Sub(store.lastCleanup) > store.expiresIn {
|
||||||
store.cleanupStaleVisitors()
|
store.cleanupStaleVisitors()
|
||||||
}
|
}
|
||||||
store.mutex.Unlock()
|
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() {
|
func (store *RateLimiterMemoryStore) cleanupStaleVisitors() {
|
||||||
for id, visitor := range store.visitors {
|
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)
|
delete(store.visitors, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store.lastCleanup = now()
|
store.lastCleanup = store.timeNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
actual time method which is mocked in test file
|
|
||||||
*/
|
|
||||||
var now = time.Now
|
|
||||||
|
29
vendor/github.com/labstack/echo/v4/middleware/recover.go
generated
vendored
29
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,12 +12,11 @@ import (
|
|||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// LogErrorFunc defines a function for custom logging in the middleware.
|
// LogErrorFunc defines a function for custom logging in the middleware.
|
||||||
LogErrorFunc func(c echo.Context, err error, stack []byte) error
|
type LogErrorFunc func(c echo.Context, err error, stack []byte) error
|
||||||
|
|
||||||
// RecoverConfig defines the config for Recover middleware.
|
// RecoverConfig defines the config for Recover middleware.
|
||||||
RecoverConfig struct {
|
type RecoverConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -37,21 +39,25 @@ type (
|
|||||||
|
|
||||||
// LogErrorFunc defines a function for custom logging in the middleware.
|
// LogErrorFunc defines a function for custom logging in the middleware.
|
||||||
// If it's set you don't need to provide LogLevel for config.
|
// 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
|
LogErrorFunc LogErrorFunc
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultRecoverConfig is the default Recover middleware config.
|
// DefaultRecoverConfig is the default Recover middleware config.
|
||||||
DefaultRecoverConfig = RecoverConfig{
|
var DefaultRecoverConfig = RecoverConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
StackSize: 4 << 10, // 4 KB
|
StackSize: 4 << 10, // 4 KB
|
||||||
DisableStackAll: false,
|
DisableStackAll: false,
|
||||||
DisablePrintStack: false,
|
DisablePrintStack: false,
|
||||||
LogLevel: 0,
|
LogLevel: 0,
|
||||||
LogErrorFunc: nil,
|
LogErrorFunc: nil,
|
||||||
|
DisableErrorHandler: false,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Recover returns a middleware which recovers from panics anywhere in the chain
|
// Recover returns a middleware which recovers from panics anywhere in the chain
|
||||||
// and handles the control to the centralized HTTPErrorHandler.
|
// 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(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) (returnErr error) {
|
||||||
if config.Skipper(c) {
|
if config.Skipper(c) {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
@ -113,7 +119,12 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
|
|||||||
c.Logger().Print(msg)
|
c.Logger().Print(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil && !config.DisableErrorHandler {
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
|
} else {
|
||||||
|
returnErr = err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return next(c)
|
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
16
vendor/github.com/labstack/echo/v4/middleware/request_id.go
generated
vendored
16
vendor/github.com/labstack/echo/v4/middleware/request_id.go
generated
vendored
@ -1,18 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||||
|
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/labstack/gommon/random"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// RequestIDConfig defines the config for RequestID middleware.
|
// RequestIDConfig defines the config for RequestID middleware.
|
||||||
RequestIDConfig struct {
|
type RequestIDConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
// Generator defines a function to generate an ID.
|
// Generator defines a function to generate an ID.
|
||||||
// Optional. Default value random.String(32).
|
// Optional. Defaults to generator for random string of length 32.
|
||||||
Generator func() string
|
Generator func() string
|
||||||
|
|
||||||
// RequestIDHandler defines a function which is executed for a request id.
|
// RequestIDHandler defines a function which is executed for a request id.
|
||||||
@ -21,16 +22,13 @@ type (
|
|||||||
// TargetHeader defines what header to look for to populate the id
|
// TargetHeader defines what header to look for to populate the id
|
||||||
TargetHeader string
|
TargetHeader string
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultRequestIDConfig is the default RequestID middleware config.
|
// DefaultRequestIDConfig is the default RequestID middleware config.
|
||||||
DefaultRequestIDConfig = RequestIDConfig{
|
var DefaultRequestIDConfig = RequestIDConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Generator: generator,
|
Generator: generator,
|
||||||
TargetHeader: echo.HeaderXRequestID,
|
TargetHeader: echo.HeaderXRequestID,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// RequestID returns a X-Request-ID middleware.
|
// RequestID returns a X-Request-ID middleware.
|
||||||
func RequestID() echo.MiddlewareFunc {
|
func RequestID() echo.MiddlewareFunc {
|
||||||
@ -73,5 +71,5 @@ func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generator() string {
|
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -8,6 +11,30 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"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`
|
// Example for `fmt.Printf`
|
||||||
// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
|
// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
|
||||||
// LogStatus: true,
|
// LogStatus: true,
|
||||||
@ -225,7 +252,7 @@ func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
|
|||||||
if config.Skipper == nil {
|
if config.Skipper == nil {
|
||||||
config.Skipper = DefaultSkipper
|
config.Skipper = DefaultSkipper
|
||||||
}
|
}
|
||||||
now = time.Now
|
now := time.Now
|
||||||
if config.timeNow != nil {
|
if config.timeNow != nil {
|
||||||
now = config.timeNow
|
now = config.timeNow
|
||||||
}
|
}
|
||||||
@ -257,7 +284,7 @@ func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
|
|||||||
config.BeforeNextFunc(c)
|
config.BeforeNextFunc(c)
|
||||||
}
|
}
|
||||||
err := next(c)
|
err := next(c)
|
||||||
if config.HandleError {
|
if err != nil && config.HandleError {
|
||||||
c.Error(err)
|
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()
|
||||||
|
}
|
13
vendor/github.com/labstack/echo/v4/middleware/rewrite.go
generated
vendored
13
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,9 +9,8 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// RewriteConfig defines the config for Rewrite middleware.
|
// RewriteConfig defines the config for Rewrite middleware.
|
||||||
RewriteConfig struct {
|
type RewriteConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -27,16 +29,13 @@ type (
|
|||||||
// Example:
|
// Example:
|
||||||
// "^/old/[0.9]+/": "/new",
|
// "^/old/[0.9]+/": "/new",
|
||||||
// "^/api/.+?/(.*)": "/v2/$1",
|
// "^/api/.+?/(.*)": "/v2/$1",
|
||||||
RegexRules map[*regexp.Regexp]string `yaml:"regex_rules"`
|
RegexRules map[*regexp.Regexp]string `yaml:"-"`
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultRewriteConfig is the default Rewrite middleware config.
|
// DefaultRewriteConfig is the default Rewrite middleware config.
|
||||||
DefaultRewriteConfig = RewriteConfig{
|
var DefaultRewriteConfig = RewriteConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Rewrite returns a Rewrite middleware.
|
// Rewrite returns a Rewrite middleware.
|
||||||
//
|
//
|
||||||
|
11
vendor/github.com/labstack/echo/v4/middleware/secure.go
generated
vendored
11
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,9 +9,8 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// SecureConfig defines the config for Secure middleware.
|
// SecureConfig defines the config for Secure middleware.
|
||||||
SecureConfig struct {
|
type SecureConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -72,18 +74,15 @@ type (
|
|||||||
// Optional. Default value "".
|
// Optional. Default value "".
|
||||||
ReferrerPolicy string `yaml:"referrer_policy"`
|
ReferrerPolicy string `yaml:"referrer_policy"`
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultSecureConfig is the default Secure middleware config.
|
// DefaultSecureConfig is the default Secure middleware config.
|
||||||
DefaultSecureConfig = SecureConfig{
|
var DefaultSecureConfig = SecureConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
XSSProtection: "1; mode=block",
|
XSSProtection: "1; mode=block",
|
||||||
ContentTypeNosniff: "nosniff",
|
ContentTypeNosniff: "nosniff",
|
||||||
XFrameOptions: "SAMEORIGIN",
|
XFrameOptions: "SAMEORIGIN",
|
||||||
HSTSPreloadEnabled: false,
|
HSTSPreloadEnabled: false,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Secure returns a Secure middleware.
|
// Secure returns a Secure middleware.
|
||||||
// Secure middleware provides protection against cross-site scripting (XSS) attack,
|
// Secure middleware provides protection against cross-site scripting (XSS) attack,
|
||||||
|
11
vendor/github.com/labstack/echo/v4/middleware/slash.go
generated
vendored
11
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,9 +9,8 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// TrailingSlashConfig defines the config for TrailingSlash middleware.
|
// TrailingSlashConfig defines the config for TrailingSlash middleware.
|
||||||
TrailingSlashConfig struct {
|
type TrailingSlashConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -16,14 +18,11 @@ type (
|
|||||||
// Optional, but when provided the request is redirected using this code.
|
// Optional, but when provided the request is redirected using this code.
|
||||||
RedirectCode int `yaml:"redirect_code"`
|
RedirectCode int `yaml:"redirect_code"`
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
|
// DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
|
||||||
DefaultTrailingSlashConfig = TrailingSlashConfig{
|
var DefaultTrailingSlashConfig = TrailingSlashConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// AddTrailingSlash returns a root level (before router) middleware which adds a
|
// AddTrailingSlash returns a root level (before router) middleware which adds a
|
||||||
// trailing slash to the request `URL#Path`.
|
// trailing slash to the request `URL#Path`.
|
||||||
|
11
vendor/github.com/labstack/echo/v4/middleware/static.go
generated
vendored
11
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -14,9 +17,8 @@ import (
|
|||||||
"github.com/labstack/gommon/bytes"
|
"github.com/labstack/gommon/bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// StaticConfig defines the config for Static middleware.
|
// StaticConfig defines the config for Static middleware.
|
||||||
StaticConfig struct {
|
type StaticConfig struct {
|
||||||
// Skipper defines a function to skip middleware.
|
// Skipper defines a function to skip middleware.
|
||||||
Skipper Skipper
|
Skipper Skipper
|
||||||
|
|
||||||
@ -47,7 +49,6 @@ type (
|
|||||||
// Optional. Defaults to http.Dir(config.Root)
|
// Optional. Defaults to http.Dir(config.Root)
|
||||||
Filesystem http.FileSystem `yaml:"-"`
|
Filesystem http.FileSystem `yaml:"-"`
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
const html = `
|
const html = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -121,13 +122,11 @@ const html = `
|
|||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultStaticConfig is the default Static middleware config.
|
// DefaultStaticConfig is the default Static middleware config.
|
||||||
DefaultStaticConfig = StaticConfig{
|
var DefaultStaticConfig = StaticConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Index: "index.html",
|
Index: "index.html",
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Static returns a Static middleware to serves static content from the provided
|
// Static returns a Static middleware to serves static content from the provided
|
||||||
// root directory.
|
// 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
|
//go:build !windows
|
||||||
|
|
||||||
package middleware
|
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
7
vendor/github.com/labstack/echo/v4/middleware/timeout.go
generated
vendored
7
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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -77,14 +80,12 @@ type TimeoutConfig struct {
|
|||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultTimeoutConfig is the default Timeout middleware config.
|
// DefaultTimeoutConfig is the default Timeout middleware config.
|
||||||
DefaultTimeoutConfig = TimeoutConfig{
|
var DefaultTimeoutConfig = TimeoutConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
Timeout: 0,
|
Timeout: 0,
|
||||||
ErrorMessage: "",
|
ErrorMessage: "",
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// Timeout returns a middleware which returns error (503 Service Unavailable error) to client immediately when handler
|
// 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.
|
// 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
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/rand"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func matchScheme(domain, pattern string) bool {
|
func matchScheme(domain, pattern string) bool {
|
||||||
@ -52,3 +59,45 @@ func matchSubdomain(domain, pattern string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
22
vendor/github.com/labstack/echo/v4/response.go
generated
vendored
22
vendor/github.com/labstack/echo/v4/response.go
generated
vendored
@ -1,16 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
|
||||||
|
|
||||||
package echo
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Response wraps an http.ResponseWriter and implements its interface to be used
|
// Response wraps an http.ResponseWriter and implements its interface to be used
|
||||||
// by an HTTP handler to construct an HTTP response.
|
// by an HTTP handler to construct an HTTP response.
|
||||||
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
||||||
Response struct {
|
type Response struct {
|
||||||
echo *Echo
|
echo *Echo
|
||||||
beforeFuncs []func()
|
beforeFuncs []func()
|
||||||
afterFuncs []func()
|
afterFuncs []func()
|
||||||
@ -19,7 +22,6 @@ type (
|
|||||||
Size int64
|
Size int64
|
||||||
Committed bool
|
Committed bool
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
// NewResponse creates a new instance of Response.
|
// NewResponse creates a new instance of Response.
|
||||||
func NewResponse(w http.ResponseWriter, e *Echo) (r *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.
|
// buffered data to the client.
|
||||||
// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
|
// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
|
||||||
func (r *Response) Flush() {
|
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
|
// Hijack implements the http.Hijacker interface to allow an HTTP handler to
|
||||||
// take over the connection.
|
// take over the connection.
|
||||||
// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
|
// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
|
||||||
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
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) {
|
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()
|
||||||
|
}
|
66
vendor/github.com/labstack/echo/v4/router.go
generated
vendored
66
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
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,15 +9,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
|
||||||
// Router is the registry of all registered routes for an `Echo` instance for
|
// Router is the registry of all registered routes for an `Echo` instance for
|
||||||
// request matching and URL path parameter parsing.
|
// request matching and URL path parameter parsing.
|
||||||
Router struct {
|
type Router struct {
|
||||||
tree *node
|
tree *node
|
||||||
routes map[string]*Route
|
routes map[string]*Route
|
||||||
echo *Echo
|
echo *Echo
|
||||||
}
|
}
|
||||||
node struct {
|
|
||||||
|
type node struct {
|
||||||
kind kind
|
kind kind
|
||||||
label byte
|
label byte
|
||||||
prefix string
|
prefix string
|
||||||
@ -33,14 +36,17 @@ type (
|
|||||||
// notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases
|
// notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases
|
||||||
notFoundHandler *routeMethod
|
notFoundHandler *routeMethod
|
||||||
}
|
}
|
||||||
kind uint8
|
|
||||||
children []*node
|
type kind uint8
|
||||||
routeMethod struct {
|
type children []*node
|
||||||
|
|
||||||
|
type routeMethod struct {
|
||||||
ppath string
|
ppath string
|
||||||
pnames []string
|
pnames []string
|
||||||
handler HandlerFunc
|
handler HandlerFunc
|
||||||
}
|
}
|
||||||
routeMethods struct {
|
|
||||||
|
type routeMethods struct {
|
||||||
connect *routeMethod
|
connect *routeMethod
|
||||||
delete *routeMethod
|
delete *routeMethod
|
||||||
get *routeMethod
|
get *routeMethod
|
||||||
@ -55,7 +61,6 @@ type (
|
|||||||
anyOther map[string]*routeMethod
|
anyOther map[string]*routeMethod
|
||||||
allowHeader string
|
allowHeader string
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
staticKind kind = iota
|
staticKind kind = iota
|
||||||
@ -151,7 +156,7 @@ func (r *Router) Routes() []*Route {
|
|||||||
return routes
|
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 {
|
func (r *Router) Reverse(name string, params ...interface{}) string {
|
||||||
uri := new(bytes.Buffer)
|
uri := new(bytes.Buffer)
|
||||||
ln := len(params)
|
ln := len(params)
|
||||||
@ -159,7 +164,12 @@ func (r *Router) Reverse(name string, params ...interface{}) string {
|
|||||||
for _, route := range r.routes {
|
for _, route := range r.routes {
|
||||||
if route.Name == name {
|
if route.Name == name {
|
||||||
for i, l := 0, len(route.Path); i < l; i++ {
|
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++ {
|
for ; i < l && route.Path[i] != '/'; i++ {
|
||||||
}
|
}
|
||||||
uri.WriteString(fmt.Sprintf("%v", params[n]))
|
uri.WriteString(fmt.Sprintf("%v", params[n]))
|
||||||
@ -175,8 +185,18 @@ func (r *Router) Reverse(name string, params ...interface{}) string {
|
|||||||
return uri.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 {
|
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{
|
route := &Route{
|
||||||
Method: method,
|
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.
|
// Add registers a new route for method and path with matching handler.
|
||||||
func (r *Router) Add(method, path string, h HandlerFunc) {
|
func (r *Router) Add(method, path string, h HandlerFunc) {
|
||||||
// Validate path
|
r.insert(method, normalizePathSlash(path), h)
|
||||||
if path == "" {
|
|
||||||
path = "/"
|
|
||||||
}
|
|
||||||
if path[0] != '/' {
|
|
||||||
path = "/" + path
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Router) insert(method, path string, h HandlerFunc) {
|
||||||
|
path = normalizePathSlash(path)
|
||||||
pnames := []string{} // Param names
|
pnames := []string{} // Param names
|
||||||
ppath := path // Pristine path
|
ppath := path // Pristine path
|
||||||
|
|
||||||
@ -214,7 +232,7 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
|
|||||||
}
|
}
|
||||||
j := i + 1
|
j := i + 1
|
||||||
|
|
||||||
r.insert(method, path[:i], staticKind, routeMethod{})
|
r.insertNode(method, path[:i], staticKind, routeMethod{})
|
||||||
for ; i < lcpIndex && path[i] != '/'; i++ {
|
for ; i < lcpIndex && path[i] != '/'; i++ {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,21 +242,21 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
|
|||||||
|
|
||||||
if i == lcpIndex {
|
if i == lcpIndex {
|
||||||
// path node is last fragment of route path. ie. `/users/:id`
|
// 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 {
|
} else {
|
||||||
r.insert(method, path[:i], paramKind, routeMethod{})
|
r.insertNode(method, path[:i], paramKind, routeMethod{})
|
||||||
}
|
}
|
||||||
} else if path[i] == '*' {
|
} else if path[i] == '*' {
|
||||||
r.insert(method, path[:i], staticKind, routeMethod{})
|
r.insertNode(method, path[:i], staticKind, routeMethod{})
|
||||||
pnames = append(pnames, "*")
|
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
|
// Adjust max param
|
||||||
paramLen := len(rm.pnames)
|
paramLen := len(rm.pnames)
|
||||||
if *r.echo.maxParam < paramLen {
|
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
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with 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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
APPENDIX: Copyright 2012-2023 Li Kexian
|
APPENDIX: Copyright 2012-2024 Li Kexian
|
||||||
|
|
||||||
https://www.likexian.com/
|
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
|
## 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
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
## 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
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -22,13 +22,14 @@ package xslice
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/likexian/gokit/xrand"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version returns package version
|
// Version returns package version
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return "0.22.0"
|
return "0.23.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author returns package author
|
// Author returns package author
|
||||||
@ -209,7 +210,7 @@ func Shuffle(v interface{}) {
|
|||||||
|
|
||||||
swap := reflect.Swapper(v)
|
swap := reflect.Swapper(v)
|
||||||
for i := vv.Len() - 1; i >= 1; i-- {
|
for i := vv.Len() - 1; i >= 1; i-- {
|
||||||
j := rand.Intn(i + 1)
|
j := xrand.Int(i + 1)
|
||||||
swap(i, j)
|
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
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with 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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
APPENDIX: Copyright 2014-2023 Li Kexian
|
APPENDIX: Copyright 2014-2024 Li Kexian
|
||||||
|
|
||||||
https://www.likexian.com/
|
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
|
## 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
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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",
|
"no match",
|
||||||
"not found",
|
"not found",
|
||||||
"not match",
|
"not match",
|
||||||
|
"not available",
|
||||||
"no data found",
|
"no data found",
|
||||||
"nothing found",
|
"nothing found",
|
||||||
"no entries 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -30,7 +30,7 @@ import (
|
|||||||
|
|
||||||
// Version returns package version
|
// Version returns package version
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return "1.24.1"
|
return "1.24.18"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author returns package author
|
// Author returns package author
|
||||||
@ -153,6 +153,8 @@ func Parse(text string) (whoisInfo WhoisInfo, err error) { //nolint:cyclop
|
|||||||
if !strings.Contains(name, " ") {
|
if !strings.Contains(name, " ") {
|
||||||
if name == "registrar" {
|
if name == "registrar" {
|
||||||
name += " name"
|
name += " name"
|
||||||
|
} else if domain.Extension == "dk" {
|
||||||
|
name = "registrant " + name
|
||||||
} else {
|
} else {
|
||||||
name += " organization"
|
name += " organization"
|
||||||
}
|
}
|
||||||
@ -244,9 +246,9 @@ func parseContact(contact *Contact, name, value string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var searchDomainRx1 = regexp.MustCompile(`(?i)\[?domain\:?(\s*\_?name)?\]?[\s\.]*\:?` +
|
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\.]*\:?` +
|
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
|
// searchDomain finds domain name and extension from whois information
|
||||||
func searchDomain(text string) (name, extension string) {
|
func searchDomain(text string) (name, extension string) {
|
||||||
|
114
vendor/github.com/likexian/whois-parser/prepare.go
generated
vendored
114
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
return prepareBY(text), true
|
||||||
case "ua":
|
case "ua":
|
||||||
return prepareUA(text), true
|
return prepareUA(text), true
|
||||||
|
case "at":
|
||||||
|
return prepareAT(text), true
|
||||||
default:
|
default:
|
||||||
return text, false
|
return text, false
|
||||||
}
|
}
|
||||||
@ -685,7 +687,7 @@ func prepareRU(text string) string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
var prepareJPreplacerRx = regexp.MustCompile(`\n\[(.+?)\][\ ]*(.+?)?`)
|
var prepareJPreplacerRx = regexp.MustCompile(`\n(?:\w+\.\s)?\[(.+?)\][\ ]*(.+?)?`)
|
||||||
|
|
||||||
// prepareJP do prepare the .jp domain
|
// prepareJP do prepare the .jp domain
|
||||||
func prepareJP(text string) string {
|
func prepareJP(text string) string {
|
||||||
@ -712,6 +714,7 @@ func prepareJP(text string) string {
|
|||||||
if strings.ToLower(token) == "registrant" {
|
if strings.ToLower(token) == "registrant" {
|
||||||
v = fmt.Sprintf("registrant name: %s", vs[1])
|
v = fmt.Sprintf("registrant name: %s", vs[1])
|
||||||
}
|
}
|
||||||
|
v = prepareSecondLevelJP(v, token, vs[1])
|
||||||
} else {
|
} else {
|
||||||
if token == addressToken {
|
if token == addressToken {
|
||||||
result += ", " + v
|
result += ", " + v
|
||||||
@ -724,6 +727,29 @@ func prepareJP(text string) string {
|
|||||||
return result
|
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
|
// prepareUK do prepare the .uk domain
|
||||||
func prepareUK(text string) string {
|
func prepareUK(text string) string {
|
||||||
tokens := map[string]string{
|
tokens := map[string]string{
|
||||||
@ -929,7 +955,7 @@ func prepareEU(text string) string {
|
|||||||
if _, ok := tokens[v]; ok {
|
if _, ok := tokens[v]; ok {
|
||||||
token = tokens[v]
|
token = tokens[v]
|
||||||
continue
|
continue
|
||||||
} else {
|
}
|
||||||
if token != "" {
|
if token != "" {
|
||||||
if strings.Contains(v, ":") {
|
if strings.Contains(v, ":") {
|
||||||
v = fmt.Sprintf("%s %s", token, v)
|
v = fmt.Sprintf("%s %s", token, v)
|
||||||
@ -940,7 +966,6 @@ func prepareEU(text string) string {
|
|||||||
v = fmt.Sprintf("%s: %s", token, v)
|
v = fmt.Sprintf("%s: %s", token, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
result += "\n" + v
|
result += "\n" + v
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1155,9 +1180,8 @@ func prepareEE(text string) string {
|
|||||||
if t, ok := tokens[v]; ok {
|
if t, ok := tokens[v]; ok {
|
||||||
token = t
|
token = t
|
||||||
continue
|
continue
|
||||||
} else {
|
|
||||||
v = fmt.Sprintf("%s %s", token, v)
|
|
||||||
}
|
}
|
||||||
|
v = fmt.Sprintf("%s %s", token, v)
|
||||||
result += "\n" + strings.TrimSpace(v)
|
result += "\n" + strings.TrimSpace(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1194,9 +1218,8 @@ func preparePL(text string) string {
|
|||||||
ns := strings.SplitN(v, "[", 2)
|
ns := strings.SplitN(v, "[", 2)
|
||||||
result += fmt.Sprintf("\nnameservers: %s", strings.TrimSpace(ns[0]))
|
result += fmt.Sprintf("\nnameservers: %s", strings.TrimSpace(ns[0]))
|
||||||
continue
|
continue
|
||||||
} else {
|
|
||||||
special = ""
|
|
||||||
}
|
}
|
||||||
|
special = ""
|
||||||
} else if special == "REGISTRAR" {
|
} else if special == "REGISTRAR" {
|
||||||
if strings.TrimSpace(v) == "" {
|
if strings.TrimSpace(v) == "" {
|
||||||
special = ""
|
special = ""
|
||||||
@ -1338,3 +1361,78 @@ func prepareUA(text string) string {
|
|||||||
|
|
||||||
return result
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -68,9 +68,9 @@ var (
|
|||||||
"registration time": "created_date",
|
"registration time": "created_date",
|
||||||
"first registration date": "created_date",
|
"first registration date": "created_date",
|
||||||
"domain record activated": "created_date",
|
"domain record activated": "created_date",
|
||||||
|
"record created": "created_date",
|
||||||
"record created on": "created_date",
|
"record created on": "created_date",
|
||||||
"domain registered": "created_date",
|
"domain registered": "created_date",
|
||||||
"record created": "created_date",
|
|
||||||
"modified": "updated_date",
|
"modified": "updated_date",
|
||||||
"changed": "updated_date",
|
"changed": "updated_date",
|
||||||
"update date": "updated_date",
|
"update date": "updated_date",
|
||||||
@ -153,6 +153,8 @@ var (
|
|||||||
"registrant zipcode": "registrant_postal_code",
|
"registrant zipcode": "registrant_postal_code",
|
||||||
"registrant zip code": "registrant_postal_code",
|
"registrant zip code": "registrant_postal_code",
|
||||||
"registrant postalcode": "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 contact postal code": "registrant_postal_code",
|
||||||
"registrant country": "registrant_country",
|
"registrant country": "registrant_country",
|
||||||
"registrant country economy": "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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 {
|
for k, v := range status {
|
||||||
names := strings.Split(strings.TrimSpace(v), " ")
|
names := strings.Split(strings.TrimSpace(v), " ")
|
||||||
status[k] = strings.ToLower(names[0])
|
status[k] = strings.ToLower(names[0])
|
||||||
|
if status[k] == "not" && len(names) > 1 && strings.ToLower(names[1]) == "delegated" {
|
||||||
|
status[k] = "not delegated"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status
|
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
|
// parseDateString attempts to parse a given date using a collection of common
|
||||||
// format strings. Date formats containing time components are tried first
|
// format strings. Date formats containing time components are tried first
|
||||||
// before attempts are made using date-only formats.
|
// before attempts are made using date-only formats.
|
||||||
func parseDateString(dateString string) (time.Time, error) {
|
func parseDateString(datetime string) (time.Time, error) {
|
||||||
formats := [...]string{
|
datetime = strings.Trim(datetime, ".")
|
||||||
|
datetime = strings.ReplaceAll(datetime, ". ", "-")
|
||||||
|
|
||||||
|
formats := [...]string{
|
||||||
// Date & time formats
|
// Date & time formats
|
||||||
"2006-01-02 15:04:05",
|
"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.01.2006 15:04:05",
|
"02.01.2006 15:04:05",
|
||||||
"02.1.2006 15:04:05",
|
"02.1.2006 15:04:05",
|
||||||
"2.1.2006 15:04:05",
|
"2.1.2006 15:04:05",
|
||||||
"02-Jan-2006 15:04:05",
|
"02-Jan-2006 15:04:05",
|
||||||
|
"20060102 15:04:05",
|
||||||
time.ANSIC,
|
time.ANSIC,
|
||||||
time.Stamp,
|
time.Stamp,
|
||||||
time.StampMilli,
|
time.StampMilli,
|
||||||
@ -148,24 +155,25 @@ func parseDateString(dateString string) (time.Time, error) {
|
|||||||
|
|
||||||
// Date only formats
|
// Date only formats
|
||||||
"2006-01-02",
|
"2006-01-02",
|
||||||
"2006. 01. 02.",
|
|
||||||
"02-Jan-2006",
|
"02-Jan-2006",
|
||||||
"02.01.2006",
|
"02.01.2006",
|
||||||
"02-01-2006",
|
"02-01-2006",
|
||||||
"January _2 2006",
|
"January _2 2006",
|
||||||
|
"Mon Jan _2 2006",
|
||||||
"02/01/2006",
|
"02/01/2006",
|
||||||
"01/02/2006",
|
"01/02/2006",
|
||||||
|
"2006/01/02",
|
||||||
"2006-Jan-02",
|
"2006-Jan-02",
|
||||||
"2006-Jan-02.",
|
"before Jan-2006",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, format := range formats {
|
for _, format := range formats {
|
||||||
result, err := time.Parse(format, dateString)
|
result, err := time.Parse(format, datetime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return result, nil
|
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
|
.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
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with 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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
APPENDIX: Copyright 2014-2023 Li Kexian
|
APPENDIX: Copyright 2014-2024 Li Kexian
|
||||||
|
|
||||||
https://www.likexian.com/
|
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
|
## 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
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
38
vendor/github.com/likexian/whois/whois.go
generated
vendored
38
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -49,11 +49,13 @@ type Client struct {
|
|||||||
dialer proxy.Dialer
|
dialer proxy.Dialer
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
elapsed time.Duration
|
elapsed time.Duration
|
||||||
|
disableStats bool
|
||||||
|
disableReferral bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns package version
|
// Version returns package version
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return "1.14.5"
|
return "1.15.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author returns package author
|
// Author returns package author
|
||||||
@ -82,24 +84,39 @@ func NewClient() *Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetDialer set query net dialer
|
// SetDialer set query net dialer
|
||||||
func (c *Client) SetDialer(dialer proxy.Dialer) {
|
func (c *Client) SetDialer(dialer proxy.Dialer) *Client {
|
||||||
c.dialer = dialer
|
c.dialer = dialer
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTimeout set query timeout
|
// SetTimeout set query timeout
|
||||||
func (c *Client) SetTimeout(timeout time.Duration) {
|
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||||
c.timeout = timeout
|
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
|
// Whois do the whois query and returns whois information
|
||||||
func (c *Client) Whois(domain string, servers ...string) (result string, err error) {
|
func (c *Client) Whois(domain string, servers ...string) (result string, err error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
result = fmt.Sprintf("%s\n\n;; Query time: %d msec\n;; WHEN: %s\n",
|
result = strings.TrimSpace(result)
|
||||||
strings.TrimRight(result, "\n"),
|
if result != "" && !c.disableStats {
|
||||||
time.Since(start).Milliseconds(),
|
result = fmt.Sprintf("%s\n\n%% Query time: %d msec\n%% WHEN: %s\n",
|
||||||
start.Format("Mon Jan 02 15:04:05 MST 2006"),
|
result, time.Since(start).Milliseconds(), start.Format("Mon Jan 02 15:04:05 MST 2006"),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
domain = strings.Trim(strings.TrimSpace(domain), ".")
|
domain = strings.Trim(strings.TrimSpace(domain), ".")
|
||||||
@ -139,6 +156,10 @@ func (c *Client) Whois(domain string, servers ...string) (result string, err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.disableReferral {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
refServer, refPort := getServer(result)
|
refServer, refPort := getServer(result)
|
||||||
if refServer == "" || refServer == server {
|
if refServer == "" || refServer == server {
|
||||||
return
|
return
|
||||||
@ -170,6 +191,7 @@ func (c *Client) rawQuery(domain, server, port string) (string, error) {
|
|||||||
server = "whois.godaddy.com"
|
server = "whois.godaddy.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/likexian/whois/pull/30
|
||||||
if server == "porkbun.com/whois" {
|
if server == "porkbun.com/whois" {
|
||||||
server = "whois.porkbun.com"
|
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 darwin freebsd openbsd netbsd dragonfly hurd
|
||||||
// +build !appengine
|
// +build !appengine
|
||||||
|
// +build !tinygo
|
||||||
|
|
||||||
package isatty
|
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
|
//go:build (appengine || js || nacl || tinygo || wasm) && !windows
|
||||||
// +build appengine js nacl wasm
|
// +build appengine js nacl tinygo wasm
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package isatty
|
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 linux aix zos
|
||||||
// +build !appengine
|
// +build !appengine
|
||||||
|
// +build !tinygo
|
||||||
|
|
||||||
package isatty
|
package isatty
|
||||||
|
|
||||||
|
516
vendor/github.com/oschwald/geoip2-golang/.golangci.toml
generated
vendored
516
vendor/github.com/oschwald/geoip2-golang/.golangci.toml
generated
vendored
@ -1,98 +1,43 @@
|
|||||||
[run]
|
[run]
|
||||||
deadline = "10m"
|
# This is needed for precious, which may run multiple instances
|
||||||
|
# in parallel
|
||||||
|
allow-parallel-runners = true
|
||||||
|
go = "1.21"
|
||||||
tests = true
|
tests = true
|
||||||
|
timeout = "10m"
|
||||||
|
|
||||||
[linters]
|
[linters]
|
||||||
disable-all = true
|
enable-all = true
|
||||||
enable = [
|
disable = [
|
||||||
"asciicheck",
|
"cyclop",
|
||||||
"bidichk",
|
|
||||||
"bodyclose",
|
|
||||||
"containedctx",
|
|
||||||
"contextcheck",
|
|
||||||
"deadcode",
|
|
||||||
"depguard",
|
"depguard",
|
||||||
"durationcheck",
|
"err113",
|
||||||
"errcheck",
|
"execinquery",
|
||||||
"errchkjson",
|
"exhaustive",
|
||||||
"errname",
|
"exhaustruct",
|
||||||
"errorlint",
|
"forcetypeassert",
|
||||||
"exportloopref",
|
"funlen",
|
||||||
"forbidigo",
|
"gochecknoglobals",
|
||||||
#"forcetypeassert",
|
"godox",
|
||||||
"goconst",
|
"gomnd",
|
||||||
"gocyclo",
|
"inamedparam",
|
||||||
"gocritic",
|
"interfacebloat",
|
||||||
"godot",
|
"mnd",
|
||||||
"gofumpt",
|
"nlreturn",
|
||||||
"gomodguard",
|
"nonamedreturns",
|
||||||
"gosec",
|
"paralleltest",
|
||||||
"gosimple",
|
"thelper",
|
||||||
"govet",
|
"testpackage",
|
||||||
"grouper",
|
|
||||||
"ineffassign",
|
"varnamelen",
|
||||||
"lll",
|
"wrapcheck",
|
||||||
"makezero",
|
"wsl",
|
||||||
"maintidx",
|
|
||||||
"misspell",
|
# Require Go 1.22
|
||||||
"nakedret",
|
"copyloopvar",
|
||||||
"nilerr",
|
"intrange",
|
||||||
"noctx",
|
|
||||||
"nolintlint",
|
|
||||||
"nosprintfhostport",
|
|
||||||
"predeclared",
|
|
||||||
"revive",
|
|
||||||
"rowserrcheck",
|
|
||||||
"sqlclosecheck",
|
|
||||||
"staticcheck",
|
|
||||||
"structcheck",
|
|
||||||
"stylecheck",
|
|
||||||
"tenv",
|
|
||||||
"tparallel",
|
|
||||||
"typecheck",
|
|
||||||
"unconvert",
|
|
||||||
"unparam",
|
|
||||||
"unused",
|
|
||||||
"varcheck",
|
|
||||||
"vetshadow",
|
|
||||||
"wastedassign",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# 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",
|
|
||||||
]
|
|
||||||
|
|
||||||
[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:.*"
|
|
||||||
|
|
||||||
[linters-settings.errorlint]
|
[linters-settings.errorlint]
|
||||||
errorf = true
|
errorf = true
|
||||||
asserts = true
|
asserts = true
|
||||||
@ -104,369 +49,144 @@
|
|||||||
[linters-settings.forbidigo]
|
[linters-settings.forbidigo]
|
||||||
# Forbid the following identifiers
|
# Forbid the following identifiers
|
||||||
forbid = [
|
forbid = [
|
||||||
"^minFraud*",
|
{ p = "Geoip", msg = "you should use `GeoIP`" },
|
||||||
"^maxMind*",
|
{ 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]
|
[linters-settings.gci]
|
||||||
enabled-checks = [
|
sections = ["standard", "default", "prefix(github.com/oschwald/maxminddb-golang)"]
|
||||||
"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.gofumpt]
|
[linters-settings.gofumpt]
|
||||||
extra-rules = true
|
extra-rules = true
|
||||||
lang-version = "1.18"
|
|
||||||
|
|
||||||
[linters-settings.govet]
|
[linters-settings.govet]
|
||||||
"enable-all" = true
|
enable-all = true
|
||||||
|
disable = "shadow"
|
||||||
|
|
||||||
[linters-settings.lll]
|
[linters-settings.lll]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
tab-width = 4
|
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]
|
[linters-settings.nolintlint]
|
||||||
allow-leading-space = false
|
|
||||||
allow-unused = false
|
allow-unused = false
|
||||||
allow-no-explanation = ["lll", "misspell"]
|
allow-no-explanation = ["lll", "misspell"]
|
||||||
require-explanation = true
|
require-explanation = true
|
||||||
require-specific = true
|
require-specific = true
|
||||||
|
|
||||||
[linters-settings.revive]
|
[linters-settings.revive]
|
||||||
|
enable-all-rules = true
|
||||||
ignore-generated-header = true
|
ignore-generated-header = true
|
||||||
severity = "warning"
|
severity = "warning"
|
||||||
|
|
||||||
# This might be nice but it is so common that it is hard
|
[[linters-settings.revive.rules]]
|
||||||
# to enable.
|
name = "add-constant"
|
||||||
# [[linters-settings.revive.rules]]
|
disabled = true
|
||||||
# name = "add-constant"
|
|
||||||
|
|
||||||
# [[linters-settings.revive.rules]]
|
|
||||||
# name = "argument-limit"
|
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "atomic"
|
name = "cognitive-complexity"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "bare-return"
|
name = "confusing-naming"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "blank-imports"
|
name = "confusing-results"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "bool-literal-in-expr"
|
name = "cyclomatic"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "call-to-gc"
|
name = "deep-exit"
|
||||||
|
disabled = true
|
||||||
# [[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]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "constant-logical-expr"
|
name = "flag-parameter"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "context-as-argument"
|
name = "function-length"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "context-keys-type"
|
name = "function-result-limit"
|
||||||
|
disabled = true
|
||||||
# [[linters-settings.revive.rules]]
|
|
||||||
# name = "cyclomatic"
|
|
||||||
|
|
||||||
# [[linters-settings.revive.rules]]
|
|
||||||
# name = "deep-exit"
|
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "defer"
|
name = "line-length-limit"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "dot-imports"
|
name = "max-public-structs"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "duplicated-imports"
|
name = "nested-structs"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "early-return"
|
name = "unchecked-type-assertion"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "empty-block"
|
name = "unhandled-error"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[linters-settings.tagliatelle.case.rules]
|
||||||
name = "empty-lines"
|
avro = "snake"
|
||||||
|
bson = "snake"
|
||||||
[[linters-settings.revive.rules]]
|
env = "upperSnake"
|
||||||
name = "errorf"
|
envconfig = "upperSnake"
|
||||||
|
json = "snake"
|
||||||
[[linters-settings.revive.rules]]
|
mapstructure = "snake"
|
||||||
name = "error-naming"
|
xml = "snake"
|
||||||
|
yaml = "snake"
|
||||||
[[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"
|
|
||||||
|
|
||||||
[linters-settings.unparam]
|
[linters-settings.unparam]
|
||||||
check-exported = true
|
check-exported = true
|
||||||
|
|
||||||
|
|
||||||
[[issues.exclude-rules]]
|
[[issues.exclude-rules]]
|
||||||
linters = [
|
linters = [
|
||||||
"govet"
|
"govet",
|
||||||
|
"revive",
|
||||||
]
|
]
|
||||||
# we want to enable almost all govet rules. It is easier to just filter out
|
path = "_test.go"
|
||||||
# the ones we don't want:
|
text = "fieldalignment:"
|
||||||
#
|
|
||||||
# * 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)"
|
|
||||||
|
168
vendor/github.com/oschwald/geoip2-golang/reader.go
generated
vendored
168
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
|
// The Enterprise struct corresponds to the data in the GeoIP2 Enterprise
|
||||||
// database.
|
// database.
|
||||||
type Enterprise struct {
|
type Enterprise struct {
|
||||||
City struct {
|
|
||||||
Confidence uint8 `maxminddb:"confidence"`
|
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
|
||||||
} `maxminddb:"city"`
|
|
||||||
Continent struct {
|
Continent struct {
|
||||||
|
Names map[string]string `maxminddb:"names"`
|
||||||
Code string `maxminddb:"code"`
|
Code string `maxminddb:"code"`
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
Names map[string]string `maxminddb:"names"`
|
|
||||||
} `maxminddb:"continent"`
|
} `maxminddb:"continent"`
|
||||||
Country struct {
|
City struct {
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
Names map[string]string `maxminddb:"names"`
|
||||||
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
Confidence uint8 `maxminddb:"confidence"`
|
Confidence uint8 `maxminddb:"confidence"`
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
} `maxminddb:"city"`
|
||||||
} `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 {
|
Postal struct {
|
||||||
Code string `maxminddb:"code"`
|
Code string `maxminddb:"code"`
|
||||||
Confidence uint8 `maxminddb:"confidence"`
|
Confidence uint8 `maxminddb:"confidence"`
|
||||||
} `maxminddb:"postal"`
|
} `maxminddb:"postal"`
|
||||||
RegisteredCountry struct {
|
Subdivisions []struct {
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
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"`
|
Confidence uint8 `maxminddb:"confidence"`
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||||
} `maxminddb:"registered_country"`
|
} `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 {
|
Traits struct {
|
||||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
|
||||||
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
||||||
ConnectionType string `maxminddb:"connection_type"`
|
ConnectionType string `maxminddb:"connection_type"`
|
||||||
Domain string `maxminddb:"domain"`
|
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"`
|
ISP string `maxminddb:"isp"`
|
||||||
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
||||||
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
||||||
Organization string `maxminddb:"organization"`
|
Organization string `maxminddb:"organization"`
|
||||||
StaticIPScore float64 `maxminddb:"static_ip_score"`
|
|
||||||
UserType string `maxminddb:"user_type"`
|
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"`
|
} `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
|
// The City struct corresponds to the data in the GeoIP2/GeoLite2 City
|
||||||
// databases.
|
// databases.
|
||||||
type City struct {
|
type City struct {
|
||||||
City struct {
|
City struct {
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
Names map[string]string `maxminddb:"names"`
|
||||||
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
} `maxminddb:"city"`
|
} `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 {
|
Postal struct {
|
||||||
Code string `maxminddb:"code"`
|
Code string `maxminddb:"code"`
|
||||||
} `maxminddb:"postal"`
|
} `maxminddb:"postal"`
|
||||||
RegisteredCountry struct {
|
Continent struct {
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
Names map[string]string `maxminddb:"names"`
|
||||||
} `maxminddb:"registered_country"`
|
Code string `maxminddb:"code"`
|
||||||
RepresentedCountry struct {
|
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
} `maxminddb:"continent"`
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
|
||||||
Type string `maxminddb:"type"`
|
|
||||||
} `maxminddb:"represented_country"`
|
|
||||||
Subdivisions []struct {
|
Subdivisions []struct {
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
Names map[string]string `maxminddb:"names"`
|
||||||
|
IsoCode string `maxminddb:"iso_code"`
|
||||||
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
} `maxminddb:"subdivisions"`
|
} `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 {
|
Traits struct {
|
||||||
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
||||||
|
IsAnycast bool `maxminddb:"is_anycast"`
|
||||||
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
||||||
} `maxminddb:"traits"`
|
} `maxminddb:"traits"`
|
||||||
}
|
}
|
||||||
@ -138,31 +140,32 @@ type City struct {
|
|||||||
// Country databases.
|
// Country databases.
|
||||||
type Country struct {
|
type Country struct {
|
||||||
Continent struct {
|
Continent struct {
|
||||||
|
Names map[string]string `maxminddb:"names"`
|
||||||
Code string `maxminddb:"code"`
|
Code string `maxminddb:"code"`
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
Names map[string]string `maxminddb:"names"`
|
|
||||||
} `maxminddb:"continent"`
|
} `maxminddb:"continent"`
|
||||||
Country struct {
|
Country struct {
|
||||||
|
Names map[string]string `maxminddb:"names"`
|
||||||
|
IsoCode string `maxminddb:"iso_code"`
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
|
||||||
} `maxminddb:"country"`
|
} `maxminddb:"country"`
|
||||||
RegisteredCountry struct {
|
RegisteredCountry struct {
|
||||||
|
Names map[string]string `maxminddb:"names"`
|
||||||
|
IsoCode string `maxminddb:"iso_code"`
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
||||||
IsoCode string `maxminddb:"iso_code"`
|
|
||||||
Names map[string]string `maxminddb:"names"`
|
|
||||||
} `maxminddb:"registered_country"`
|
} `maxminddb:"registered_country"`
|
||||||
RepresentedCountry struct {
|
RepresentedCountry struct {
|
||||||
|
Names map[string]string `maxminddb:"names"`
|
||||||
|
IsoCode string `maxminddb:"iso_code"`
|
||||||
|
Type string `maxminddb:"type"`
|
||||||
GeoNameID uint `maxminddb:"geoname_id"`
|
GeoNameID uint `maxminddb:"geoname_id"`
|
||||||
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
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"`
|
} `maxminddb:"represented_country"`
|
||||||
Traits struct {
|
Traits struct {
|
||||||
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
||||||
|
IsAnycast bool `maxminddb:"is_anycast"`
|
||||||
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
||||||
} `maxminddb:"traits"`
|
} `maxminddb:"traits"`
|
||||||
}
|
}
|
||||||
@ -180,8 +183,8 @@ type AnonymousIP struct {
|
|||||||
|
|
||||||
// The ASN struct corresponds to the data in the GeoLite2 ASN database.
|
// The ASN struct corresponds to the data in the GeoLite2 ASN database.
|
||||||
type ASN struct {
|
type ASN struct {
|
||||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
|
||||||
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
||||||
|
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ConnectionType struct corresponds to the data in the GeoIP2
|
// 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.
|
// The ISP struct corresponds to the data in the GeoIP2 ISP database.
|
||||||
type ISP struct {
|
type ISP struct {
|
||||||
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
|
||||||
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
||||||
ISP string `maxminddb:"isp"`
|
ISP string `maxminddb:"isp"`
|
||||||
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
||||||
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
||||||
Organization string `maxminddb:"organization"`
|
Organization string `maxminddb:"organization"`
|
||||||
|
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type databaseType int
|
type databaseType int
|
||||||
@ -305,8 +308,7 @@ func getDBType(reader *maxminddb.Reader) (databaseType, error) {
|
|||||||
"DBIP-Location-ISP (compat=Enterprise)",
|
"DBIP-Location-ISP (compat=Enterprise)",
|
||||||
"GeoIP2-Enterprise":
|
"GeoIP2-Enterprise":
|
||||||
return isEnterprise | isCity | isCountry, nil
|
return isEnterprise | isCity | isCountry, nil
|
||||||
case "GeoIP2-ISP",
|
case "GeoIP2-ISP", "GeoIP2-Precision-ISP":
|
||||||
"GeoIP2-Precision-ISP":
|
|
||||||
return isISP | isASN, nil
|
return isISP | isASN, nil
|
||||||
default:
|
default:
|
||||||
return 0, UnknownDatabaseTypeError{reader.Metadata.DatabaseType}
|
return 0, UnknownDatabaseTypeError{reader.Metadata.DatabaseType}
|
||||||
|
516
vendor/github.com/oschwald/maxminddb-golang/.golangci.toml
generated
vendored
516
vendor/github.com/oschwald/maxminddb-golang/.golangci.toml
generated
vendored
@ -1,98 +1,43 @@
|
|||||||
[run]
|
[run]
|
||||||
deadline = "10m"
|
# This is needed for precious, which may run multiple instances
|
||||||
|
# in parallel
|
||||||
|
allow-parallel-runners = true
|
||||||
|
go = "1.21"
|
||||||
tests = true
|
tests = true
|
||||||
|
timeout = "10m"
|
||||||
|
|
||||||
[linters]
|
[linters]
|
||||||
disable-all = true
|
enable-all = true
|
||||||
enable = [
|
disable = [
|
||||||
"asciicheck",
|
"cyclop",
|
||||||
"bidichk",
|
|
||||||
"bodyclose",
|
|
||||||
"containedctx",
|
|
||||||
"contextcheck",
|
|
||||||
"deadcode",
|
|
||||||
"depguard",
|
"depguard",
|
||||||
"durationcheck",
|
"err113",
|
||||||
"errcheck",
|
"execinquery",
|
||||||
"errchkjson",
|
"exhaustive",
|
||||||
"errname",
|
"exhaustruct",
|
||||||
"errorlint",
|
"forcetypeassert",
|
||||||
"exportloopref",
|
"funlen",
|
||||||
"forbidigo",
|
"gochecknoglobals",
|
||||||
#"forcetypeassert",
|
"godox",
|
||||||
"goconst",
|
"gomnd",
|
||||||
"gocyclo",
|
"inamedparam",
|
||||||
"gocritic",
|
"interfacebloat",
|
||||||
"godot",
|
"mnd",
|
||||||
"gofumpt",
|
"nlreturn",
|
||||||
"gomodguard",
|
"nonamedreturns",
|
||||||
"gosec",
|
"paralleltest",
|
||||||
"gosimple",
|
"thelper",
|
||||||
"govet",
|
"testpackage",
|
||||||
"grouper",
|
|
||||||
"ineffassign",
|
"varnamelen",
|
||||||
"lll",
|
"wrapcheck",
|
||||||
"makezero",
|
"wsl",
|
||||||
"maintidx",
|
|
||||||
"misspell",
|
# Require Go 1.22
|
||||||
"nakedret",
|
"copyloopvar",
|
||||||
"nilerr",
|
"intrange",
|
||||||
"noctx",
|
|
||||||
"nolintlint",
|
|
||||||
"nosprintfhostport",
|
|
||||||
"predeclared",
|
|
||||||
"revive",
|
|
||||||
"rowserrcheck",
|
|
||||||
"sqlclosecheck",
|
|
||||||
"staticcheck",
|
|
||||||
"structcheck",
|
|
||||||
"stylecheck",
|
|
||||||
"tenv",
|
|
||||||
"tparallel",
|
|
||||||
"typecheck",
|
|
||||||
"unconvert",
|
|
||||||
"unparam",
|
|
||||||
"unused",
|
|
||||||
"varcheck",
|
|
||||||
"vetshadow",
|
|
||||||
"wastedassign",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# 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",
|
|
||||||
]
|
|
||||||
|
|
||||||
[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:.*"
|
|
||||||
|
|
||||||
[linters-settings.errorlint]
|
[linters-settings.errorlint]
|
||||||
errorf = true
|
errorf = true
|
||||||
asserts = true
|
asserts = true
|
||||||
@ -104,369 +49,144 @@
|
|||||||
[linters-settings.forbidigo]
|
[linters-settings.forbidigo]
|
||||||
# Forbid the following identifiers
|
# Forbid the following identifiers
|
||||||
forbid = [
|
forbid = [
|
||||||
"^minFraud*",
|
{ p = "Geoip", msg = "you should use `GeoIP`" },
|
||||||
"^maxMind*",
|
{ 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]
|
[linters-settings.gci]
|
||||||
enabled-checks = [
|
sections = ["standard", "default", "prefix(github.com/oschwald/maxminddb-golang)"]
|
||||||
"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.gofumpt]
|
[linters-settings.gofumpt]
|
||||||
extra-rules = true
|
extra-rules = true
|
||||||
lang-version = "1.18"
|
|
||||||
|
|
||||||
[linters-settings.govet]
|
[linters-settings.govet]
|
||||||
"enable-all" = true
|
enable-all = true
|
||||||
|
disable = "shadow"
|
||||||
|
|
||||||
[linters-settings.lll]
|
[linters-settings.lll]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
tab-width = 4
|
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]
|
[linters-settings.nolintlint]
|
||||||
allow-leading-space = false
|
|
||||||
allow-unused = false
|
allow-unused = false
|
||||||
allow-no-explanation = ["lll", "misspell"]
|
allow-no-explanation = ["lll", "misspell"]
|
||||||
require-explanation = true
|
require-explanation = true
|
||||||
require-specific = true
|
require-specific = true
|
||||||
|
|
||||||
[linters-settings.revive]
|
[linters-settings.revive]
|
||||||
|
enable-all-rules = true
|
||||||
ignore-generated-header = true
|
ignore-generated-header = true
|
||||||
severity = "warning"
|
severity = "warning"
|
||||||
|
|
||||||
# This might be nice but it is so common that it is hard
|
[[linters-settings.revive.rules]]
|
||||||
# to enable.
|
name = "add-constant"
|
||||||
# [[linters-settings.revive.rules]]
|
disabled = true
|
||||||
# name = "add-constant"
|
|
||||||
|
|
||||||
# [[linters-settings.revive.rules]]
|
|
||||||
# name = "argument-limit"
|
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "atomic"
|
name = "cognitive-complexity"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "bare-return"
|
name = "confusing-naming"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "blank-imports"
|
name = "confusing-results"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "bool-literal-in-expr"
|
name = "cyclomatic"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "call-to-gc"
|
name = "deep-exit"
|
||||||
|
disabled = true
|
||||||
# [[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]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "constant-logical-expr"
|
name = "flag-parameter"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "context-as-argument"
|
name = "function-length"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "context-keys-type"
|
name = "function-result-limit"
|
||||||
|
disabled = true
|
||||||
# [[linters-settings.revive.rules]]
|
|
||||||
# name = "cyclomatic"
|
|
||||||
|
|
||||||
# [[linters-settings.revive.rules]]
|
|
||||||
# name = "deep-exit"
|
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "defer"
|
name = "line-length-limit"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "dot-imports"
|
name = "max-public-structs"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "duplicated-imports"
|
name = "nested-structs"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "early-return"
|
name = "unchecked-type-assertion"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[[linters-settings.revive.rules]]
|
||||||
name = "empty-block"
|
name = "unhandled-error"
|
||||||
|
disabled = true
|
||||||
|
|
||||||
[[linters-settings.revive.rules]]
|
[linters-settings.tagliatelle.case.rules]
|
||||||
name = "empty-lines"
|
avro = "snake"
|
||||||
|
bson = "snake"
|
||||||
[[linters-settings.revive.rules]]
|
env = "upperSnake"
|
||||||
name = "errorf"
|
envconfig = "upperSnake"
|
||||||
|
json = "snake"
|
||||||
[[linters-settings.revive.rules]]
|
mapstructure = "snake"
|
||||||
name = "error-naming"
|
xml = "snake"
|
||||||
|
yaml = "snake"
|
||||||
[[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"
|
|
||||||
|
|
||||||
[linters-settings.unparam]
|
[linters-settings.unparam]
|
||||||
check-exported = true
|
check-exported = true
|
||||||
|
|
||||||
|
|
||||||
[[issues.exclude-rules]]
|
[[issues.exclude-rules]]
|
||||||
linters = [
|
linters = [
|
||||||
"govet"
|
"govet",
|
||||||
|
"revive",
|
||||||
]
|
]
|
||||||
# we want to enable almost all govet rules. It is easier to just filter out
|
path = "_test.go"
|
||||||
# the ones we don't want:
|
text = "fieldalignment:"
|
||||||
#
|
|
||||||
# * 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)"
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user