diff --git a/go.mod b/go.mod index 0d1ebc1915459..c28c8d470b379 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.14 require ( code.gitea.io/gitea-vet v0.2.1 code.gitea.io/sdk/gitea v0.13.1 - gitea.com/go-chi/session v0.0.0-20201218134809-7209fa084f27 gitea.com/lunny/levelqueue v0.3.0 gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b gitea.com/macaron/cache v0.0.0-20200924044943-905232fba10b @@ -34,7 +33,7 @@ require ( github.com/ethantkoenig/rupture v0.0.0-20181029165146-c3b3b810dc77 github.com/gliderlabs/ssh v0.3.1 github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect - github.com/go-chi/chi v1.5.1 + github.com/go-chi/chi v1.5.0 github.com/go-enry/go-enry/v2 v2.6.0 github.com/go-git/go-billy/v5 v5.0.0 github.com/go-git/go-git/v5 v5.2.0 @@ -79,6 +78,7 @@ require ( github.com/niklasfasching/go-org v1.3.2 github.com/oliamb/cutter v0.2.2 github.com/olivere/elastic/v7 v7.0.21 + github.com/onsi/ginkgo v1.13.0 // indirect github.com/pelletier/go-toml v1.8.1 github.com/pierrec/lz4/v4 v4.1.1 // indirect github.com/pkg/errors v0.9.1 @@ -98,7 +98,6 @@ require ( github.com/unknwon/com v1.0.1 github.com/unknwon/i18n v0.0.0-20200823051745-09abd91c7f2c github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae - github.com/unrolled/render v1.0.3 github.com/urfave/cli v1.22.5 github.com/willf/bitset v1.1.11 // indirect github.com/xanzy/go-gitlab v0.39.0 @@ -115,6 +114,7 @@ require ( golang.org/x/text v0.3.4 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 + google.golang.org/appengine v1.6.7 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.62.0 diff --git a/go.sum b/go.sum index ad51f4c67a892..66b8083e0e598 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,6 @@ code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFj code.gitea.io/sdk/gitea v0.13.1 h1:Y7bpH2iO6Q0KhhMJfjP/LZ0AmiYITeRQlCD8b0oYqhk= code.gitea.io/sdk/gitea v0.13.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gitea.com/go-chi/session v0.0.0-20201218134809-7209fa084f27 h1:cdb1OTNXGLwQ55gg+9tIPWufdsnrHWcIq8Qs+j/E8JU= -gitea.com/go-chi/session v0.0.0-20201218134809-7209fa084f27/go.mod h1:Ozg8IchVNb/Udg+ui39iHRYqVHSvf3C99ixdpLR8Vu0= gitea.com/lunny/levelqueue v0.3.0 h1:MHn1GuSZkxvVEDMyAPqlc7A3cOW+q8RcGhRgH/xtm6I= gitea.com/lunny/levelqueue v0.3.0/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= gitea.com/lunny/log v0.0.0-20190322053110-01b5df579c4e h1:r1en/D7xJmcY24VkHkjkcJFa+7ZWubVWPBrvsHkmHxk= @@ -229,8 +227,6 @@ github.com/couchbase/go-couchbase v0.0.0-20201026062457-7b3be89bbd89/go.mod h1:+ github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/gomemcached v0.1.0 h1:whUde87n8CScx8ckMp2En5liqAlcuG3aKy/BQeBPu84= github.com/couchbase/gomemcached v0.1.0/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= -github.com/couchbase/gomemcached v0.1.1 h1:xCS8ZglJDhrlQg3jmK7Rn1V8f7bPjXABLC05CgLQauc= -github.com/couchbase/gomemcached v0.1.1/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67 h1:NCqJ6fwen6YP0WlV/IyibaT0kPt3JEI1rA62V/UPKT4= github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= @@ -268,7 +264,6 @@ github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -288,8 +283,6 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/editorconfig/editorconfig-core-go/v2 v2.3.9 h1:4vZN3UCLAUbT408wDutTKGZwOlgGMpV3vhahYufNbV8= github.com/editorconfig/editorconfig-core-go/v2 v2.3.9/go.mod h1:yoHDFR3nO8O5ssvhITSRsf0owQqIs0c9+nBTtarunPo= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= @@ -333,8 +326,8 @@ github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8= github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-chi/chi v1.5.1 h1:kfTK3Cxd/dkMu/rKs5ZceWYp+t5CtiE7vmaTv3LjC6w= -github.com/go-chi/chi v1.5.1/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k= +github.com/go-chi/chi v1.5.0 h1:2ZcJZozJ+rj6BA0c19ffBUGXEKAT/aOLOtQjD46vBRA= +github.com/go-chi/chi v1.5.0/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k= github.com/go-enry/go-enry/v2 v2.6.0 h1:nbGWQBpO+D+cJuRxNgSDFnFY9QWz3QM/CeZxU7VAH20= github.com/go-enry/go-enry/v2 v2.6.0/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= @@ -429,7 +422,6 @@ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDA github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= -github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= @@ -527,7 +519,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= @@ -880,8 +871,8 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= @@ -889,8 +880,6 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -988,6 +977,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -1096,8 +1086,6 @@ github.com/unknwon/i18n v0.0.0-20200823051745-09abd91c7f2c h1:679/gJXwrsHC3RATr0 github.com/unknwon/i18n v0.0.0-20200823051745-09abd91c7f2c/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ= github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae h1:ihaXiJkaca54IaCSnEXtE/uSZOmPxKZhDfVLrzZLFDs= github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae/go.mod h1:1fdkY6xxl6ExVs2QFv7R0F5IRZHKA8RahhB9fMC9RvM= -github.com/unrolled/render v1.0.3 h1:baO+NG1bZSF2WR4zwh+0bMWauWky7DVrTOfvE2w+aFo= -github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= @@ -1154,7 +1142,6 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1271,7 +1258,6 @@ golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo= golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 1f4b9ec5beeb5..16ea9f15e3cde 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -9,10 +9,13 @@ import ( "reflect" "strings" + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth/sso" "code.gitea.io/gitea/modules/validation" "gitea.com/macaron/binding" "gitea.com/macaron/macaron" + "gitea.com/macaron/session" "github.com/unknwon/com" ) @@ -21,6 +24,28 @@ func IsAPIPath(url string) bool { return strings.HasPrefix(url, "/api/") } +// SignedInUser returns the user object of signed user. +// It returns a bool value to indicate whether user uses basic auth or not. +func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) { + if !models.HasEngine { + return nil, false + } + + // Try to sign in with each of the enabled plugins + for _, ssoMethod := range sso.Methods() { + if !ssoMethod.IsEnabled() { + continue + } + user := ssoMethod.VerifyAuthData(ctx, sess) + if user != nil { + _, isBasic := ssoMethod.(*sso.Basic) + return user, isBasic + } + } + + return nil, false +} + // Form form binding interface type Form interface { binding.Validator diff --git a/modules/auth/sso/basic.go b/modules/auth/sso/basic.go index d2d25c6cece65..aab4eceebccdd 100644 --- a/modules/auth/sso/basic.go +++ b/modules/auth/sso/basic.go @@ -6,7 +6,6 @@ package sso import ( - "net/http" "strings" "code.gitea.io/gitea/models" @@ -14,6 +13,9 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" ) // Ensure the struct implements the interface. @@ -47,8 +49,8 @@ func (b *Basic) IsEnabled() bool { // "Authorization" header of the request and returns the corresponding user object for that // name/token on successful validation. // Returns nil if header is empty or validation fails. -func (b *Basic) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User { - baHead := req.Header.Get("Authorization") +func (b *Basic) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User { + baHead := ctx.Req.Header.Get("Authorization") if len(baHead) == 0 { return nil } @@ -73,7 +75,7 @@ func (b *Basic) VerifyAuthData(req *http.Request, w http.ResponseWriter, store D uid := CheckOAuthAccessToken(authToken) if uid != 0 { var err error - store.GetData()["IsApiToken"] = true + ctx.Data["IsApiToken"] = true u, err = models.GetUserByID(uid) if err != nil { @@ -106,7 +108,7 @@ func (b *Basic) VerifyAuthData(req *http.Request, w http.ResponseWriter, store D return nil } } else { - store.GetData()["IsApiToken"] = true + ctx.Data["IsApiToken"] = true } return u diff --git a/modules/auth/sso/interface.go b/modules/auth/sso/interface.go index c957fad02f186..89cc227e79393 100644 --- a/modules/auth/sso/interface.go +++ b/modules/auth/sso/interface.go @@ -5,22 +5,11 @@ package sso import ( - "net/http" - "code.gitea.io/gitea/models" -) - -// DataStore represents a data store -type DataStore interface { - GetData() map[string]interface{} -} -// SessionStore represents a session store -type SessionStore interface { - Get(interface{}) interface{} - Set(interface{}, interface{}) error - Delete(interface{}) error -} + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" +) // SingleSignOn represents a SSO authentication method (plugin) for HTTP requests. type SingleSignOn interface { @@ -40,5 +29,5 @@ type SingleSignOn interface { // or a new user object (with id = 0) populated with the information that was found // in the authentication data (username or email). // Returns nil if verification fails. - VerifyAuthData(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User + VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User } diff --git a/modules/auth/sso/oauth2.go b/modules/auth/sso/oauth2.go index fc22e27282cc4..3f530f036f256 100644 --- a/modules/auth/sso/oauth2.go +++ b/modules/auth/sso/oauth2.go @@ -6,13 +6,15 @@ package sso import ( - "net/http" "strings" "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" + + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" ) // Ensure the struct implements the interface. @@ -61,15 +63,15 @@ func (o *OAuth2) Free() error { } // userIDFromToken returns the user id corresponding to the OAuth token. -func (o *OAuth2) userIDFromToken(req *http.Request, store DataStore) int64 { +func (o *OAuth2) userIDFromToken(ctx *macaron.Context) int64 { // Check access token. - tokenSHA := req.Form.Get("token") + tokenSHA := ctx.Query("token") if len(tokenSHA) == 0 { - tokenSHA = req.Form.Get("access_token") + tokenSHA = ctx.Query("access_token") } if len(tokenSHA) == 0 { // Well, check with header again. - auHead := req.Header.Get("Authorization") + auHead := ctx.Req.Header.Get("Authorization") if len(auHead) > 0 { auths := strings.Fields(auHead) if len(auths) == 2 && (auths[0] == "token" || strings.ToLower(auths[0]) == "bearer") { @@ -85,7 +87,7 @@ func (o *OAuth2) userIDFromToken(req *http.Request, store DataStore) int64 { if strings.Contains(tokenSHA, ".") { uid := CheckOAuthAccessToken(tokenSHA) if uid != 0 { - store.GetData()["IsApiToken"] = true + ctx.Data["IsApiToken"] = true } return uid } @@ -100,7 +102,7 @@ func (o *OAuth2) userIDFromToken(req *http.Request, store DataStore) int64 { if err = models.UpdateAccessToken(t); err != nil { log.Error("UpdateAccessToken: %v", err) } - store.GetData()["IsApiToken"] = true + ctx.Data["IsApiToken"] = true return t.UID } @@ -114,16 +116,16 @@ func (o *OAuth2) IsEnabled() bool { // or the "Authorization" header and returns the corresponding user object for that ID. // If verification is successful returns an existing user object. // Returns nil if verification fails. -func (o *OAuth2) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User { +func (o *OAuth2) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User { if !models.HasEngine { return nil } - if isInternalPath(req) || !isAPIPath(req) && !isAttachmentDownload(req) { + if isInternalPath(ctx) || !isAPIPath(ctx) && !isAttachmentDownload(ctx) { return nil } - id := o.userIDFromToken(req, store) + id := o.userIDFromToken(ctx) if id <= 0 { return nil } diff --git a/modules/auth/sso/reverseproxy.go b/modules/auth/sso/reverseproxy.go index ca9450e71429d..1b543ce1046b9 100644 --- a/modules/auth/sso/reverseproxy.go +++ b/modules/auth/sso/reverseproxy.go @@ -6,13 +6,14 @@ package sso import ( - "net/http" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" gouuid "github.com/google/uuid" ) @@ -30,8 +31,8 @@ type ReverseProxy struct { } // getUserName extracts the username from the "setting.ReverseProxyAuthUser" header -func (r *ReverseProxy) getUserName(req *http.Request) string { - webAuthUser := strings.TrimSpace(req.Header.Get(setting.ReverseProxyAuthUser)) +func (r *ReverseProxy) getUserName(ctx *macaron.Context) string { + webAuthUser := strings.TrimSpace(ctx.Req.Header.Get(setting.ReverseProxyAuthUser)) if len(webAuthUser) == 0 { return "" } @@ -60,8 +61,8 @@ func (r *ReverseProxy) IsEnabled() bool { // If a username is available in the "setting.ReverseProxyAuthUser" header an existing // user object is returned (populated with username or email found in header). // Returns nil if header is empty. -func (r *ReverseProxy) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User { - username := r.getUserName(req) +func (r *ReverseProxy) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User { + username := r.getUserName(ctx) if len(username) == 0 { return nil } @@ -69,7 +70,7 @@ func (r *ReverseProxy) VerifyAuthData(req *http.Request, w http.ResponseWriter, user, err := models.GetUserByName(username) if err != nil { if models.IsErrUserNotExist(err) && r.isAutoRegisterAllowed() { - return r.newUser(req) + return r.newUser(ctx) } log.Error("GetUserByName: %v", err) return nil @@ -85,15 +86,15 @@ func (r *ReverseProxy) isAutoRegisterAllowed() bool { // newUser creates a new user object for the purpose of automatic registration // and populates its name and email with the information present in request headers. -func (r *ReverseProxy) newUser(req *http.Request) *models.User { - username := r.getUserName(req) +func (r *ReverseProxy) newUser(ctx *macaron.Context) *models.User { + username := r.getUserName(ctx) if len(username) == 0 { return nil } email := gouuid.New().String() + "@localhost" if setting.Service.EnableReverseProxyEmail { - webAuthEmail := req.Header.Get(setting.ReverseProxyAuthEmail) + webAuthEmail := ctx.Req.Header.Get(setting.ReverseProxyAuthEmail) if len(webAuthEmail) > 0 { email = webAuthEmail } diff --git a/modules/auth/sso/session.go b/modules/auth/sso/session.go index 7a546577d86ee..c9176b9c31661 100644 --- a/modules/auth/sso/session.go +++ b/modules/auth/sso/session.go @@ -5,9 +5,10 @@ package sso import ( - "net/http" - "code.gitea.io/gitea/models" + + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" ) // Ensure the struct implements the interface. @@ -39,7 +40,7 @@ func (s *Session) IsEnabled() bool { // VerifyAuthData checks if there is a user uid stored in the session and returns the user // object for that uid. // Returns nil if there is no user uid stored in the session. -func (s *Session) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User { +func (s *Session) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User { user := SessionUser(sess) if user != nil { return user diff --git a/modules/auth/sso/sso.go b/modules/auth/sso/sso.go index d54310168eb12..c2e36f3f5ebf2 100644 --- a/modules/auth/sso/sso.go +++ b/modules/auth/sso/sso.go @@ -7,14 +7,15 @@ package sso import ( "fmt" - "net/http" "reflect" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/middlewares" "code.gitea.io/gitea/modules/setting" + + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" ) // ssoMethods contains the list of SSO authentication plugins in the order they are expected to be @@ -72,7 +73,7 @@ func Free() { } // SessionUser returns the user object corresponding to the "uid" session variable. -func SessionUser(sess SessionStore) *models.User { +func SessionUser(sess session.Store) *models.User { // Get user ID uid := sess.Get("uid") if uid == nil { @@ -95,22 +96,22 @@ func SessionUser(sess SessionStore) *models.User { } // isAPIPath returns true if the specified URL is an API path -func isAPIPath(req *http.Request) bool { - return strings.HasPrefix(req.URL.Path, "/api/") +func isAPIPath(ctx *macaron.Context) bool { + return strings.HasPrefix(ctx.Req.URL.Path, "/api/") } // isInternalPath returns true if the specified URL is an internal API path -func isInternalPath(req *http.Request) bool { - return strings.HasPrefix(req.URL.Path, "/api/internal/") +func isInternalPath(ctx *macaron.Context) bool { + return strings.HasPrefix(ctx.Req.URL.Path, "/api/internal/") } // isAttachmentDownload check if request is a file download (GET) with URL to an attachment -func isAttachmentDownload(req *http.Request) bool { - return strings.HasPrefix(req.URL.Path, "/attachments/") && req.Method == "GET" +func isAttachmentDownload(ctx *macaron.Context) bool { + return strings.HasPrefix(ctx.Req.URL.Path, "/attachments/") && ctx.Req.Method == "GET" } // handleSignIn clears existing session variables and stores new ones for the specified user object -func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore, user *models.User) { +func handleSignIn(ctx *macaron.Context, sess session.Store, user *models.User) { _ = sess.Delete("openid_verified_uri") _ = sess.Delete("openid_signin_remember") _ = sess.Delete("openid_determined_email") @@ -131,16 +132,15 @@ func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore // Language setting of the user overwrites the one previously set // If the user does not have a locale set, we save the current one. if len(user.Language) == 0 { - lc := middlewares.Locale(resp, req) - user.Language = lc.Language() + user.Language = ctx.Locale.Language() if err := models.UpdateUserCols(user, "language"); err != nil { log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", user.ID, user.Language)) return } } - middlewares.SetCookie(resp, "lang", user.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + ctx.SetCookie("lang", user.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) // Clear whatever CSRF has right now, force to generate a new one - middlewares.SetCookie(resp, setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) } diff --git a/modules/auth/sso/sspi_windows.go b/modules/auth/sso/sspi_windows.go index 44dfa81aa1c37..62013737caac7 100644 --- a/modules/auth/sso/sspi_windows.go +++ b/modules/auth/sso/sspi_windows.go @@ -6,18 +6,19 @@ package sso import ( "errors" - "net/http" + "reflect" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" + + "gitea.com/macaron/macaron" + "gitea.com/macaron/session" gouuid "github.com/google/uuid" "github.com/quasoft/websspi" - "github.com/unrolled/render" ) const ( @@ -39,7 +40,6 @@ var ( // On successful authentication returns a valid user object. // Returns nil if authentication fails. type SSPI struct { - rnd *render.Render } // Init creates a new global websspi.Authenticator object @@ -47,18 +47,7 @@ func (s *SSPI) Init() error { config := websspi.NewConfig() var err error sspiAuth, err = websspi.New(config) - if err != nil { - return err - } - s.rnd = render.New(render.Options{ - Extensions: []string{".tmpl"}, - Directory: "templates", - Funcs: templates.NewFuncMap(), - Asset: templates.GetAsset, - AssetNames: templates.GetAssetNames, - IsDevelopment: setting.RunMode != "prod", - }) - return nil + return err } // Free releases resources used by the global websspi.Authenticator object @@ -75,8 +64,8 @@ func (s *SSPI) IsEnabled() bool { // If authentication is successful, returs the corresponding user object. // If negotiation should continue or authentication fails, immediately returns a 401 HTTP // response code, as required by the SPNEGO protocol. -func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User { - if !s.shouldAuthenticate(req) { +func (s *SSPI) VerifyAuthData(ctx *macaron.Context, sess session.Store) *models.User { + if !s.shouldAuthenticate(ctx) { return nil } @@ -86,29 +75,22 @@ func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store Da return nil } - userInfo, outToken, err := sspiAuth.Authenticate(req, w) + userInfo, outToken, err := sspiAuth.Authenticate(ctx.Req.Request, ctx.Resp) if err != nil { log.Warn("Authentication failed with error: %v\n", err) - sspiAuth.AppendAuthenticateHeader(w, outToken) + sspiAuth.AppendAuthenticateHeader(ctx.Resp, outToken) // Include the user login page in the 401 response to allow the user // to login with another authentication method if SSPI authentication // fails - store.GetData()["Flash"] = map[string]string{ - "ErrMsg": err.Error(), - } - store.GetData()["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn - store.GetData()["EnableSSPI"] = true - - err := s.rnd.HTML(w, 401, string(tplSignIn), templates.BaseVars().Merge(store.GetData())) - if err != nil { - log.Error("%v", err) - } - + addFlashErr(ctx, ctx.Tr("auth.sspi_auth_failed")) + ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn + ctx.Data["EnableSSPI"] = true + ctx.HTML(401, string(tplSignIn)) return nil } if outToken != "" { - sspiAuth.AppendAuthenticateHeader(w, outToken) + sspiAuth.AppendAuthenticateHeader(ctx.Resp, outToken) } username := sanitizeUsername(userInfo.Username, cfg) @@ -127,7 +109,7 @@ func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store Da log.Error("User '%s' not found", username) return nil } - user, err = s.newUser(username, cfg) + user, err = s.newUser(ctx, username, cfg) if err != nil { log.Error("CreateUser: %v", err) return nil @@ -135,8 +117,8 @@ func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store Da } // Make sure requests to API paths and PWA resources do not create a new session - if !isAPIPath(req) && !isAttachmentDownload(req) { - handleSignIn(w, req, sess, user) + if !isAPIPath(ctx) && !isAttachmentDownload(ctx) { + handleSignIn(ctx, sess, user) } return user @@ -157,18 +139,18 @@ func (s *SSPI) getConfig() (*models.SSPIConfig, error) { return sources[0].SSPI(), nil } -func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) { +func (s *SSPI) shouldAuthenticate(ctx *macaron.Context) (shouldAuth bool) { shouldAuth = false - path := strings.TrimSuffix(req.URL.Path, "/") + path := strings.TrimSuffix(ctx.Req.URL.Path, "/") if path == "/user/login" { - if req.FormValue("user_name") != "" && req.FormValue("password") != "" { + if ctx.Req.FormValue("user_name") != "" && ctx.Req.FormValue("password") != "" { shouldAuth = false - } else if req.FormValue("auth_with_sspi") == "1" { + } else if ctx.Req.FormValue("auth_with_sspi") == "1" { shouldAuth = true } - } else if isInternalPath(req) { + } else if isInternalPath(ctx) { shouldAuth = false - } else if isAPIPath(req) || isAttachmentDownload(req) { + } else if isAPIPath(ctx) || isAttachmentDownload(ctx) { shouldAuth = true } return @@ -176,7 +158,7 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) { // newUser creates a new user object for the purpose of automatic registration // and populates its name and email with the information present in request headers. -func (s *SSPI) newUser(username string, cfg *models.SSPIConfig) (*models.User, error) { +func (s *SSPI) newUser(ctx *macaron.Context, username string, cfg *models.SSPIConfig) (*models.User, error) { email := gouuid.New().String() + "@localhost.localdomain" user := &models.User{ Name: username, @@ -234,6 +216,20 @@ func sanitizeUsername(username string, cfg *models.SSPIConfig) string { return username } +// addFlashErr adds an error message to the Flash object mapped to a macaron.Context +func addFlashErr(ctx *macaron.Context, err string) { + fv := ctx.GetVal(reflect.TypeOf(&session.Flash{})) + if !fv.IsValid() { + return + } + flash, ok := fv.Interface().(*session.Flash) + if !ok { + return + } + flash.Error(err) + ctx.Data["Flash"] = flash +} + // init registers the SSPI auth method as the last method in the list. // The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation // fails (or if negotiation should continue), which would prevent other authentication methods diff --git a/modules/auth/sso/user.go b/modules/auth/sso/user.go deleted file mode 100644 index 48eebb1e915f0..0000000000000 --- a/modules/auth/sso/user.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package sso - -import ( - "net/http" - - "code.gitea.io/gitea/models" -) - -// SignedInUser returns the user object of signed user. -// It returns a bool value to indicate whether user uses basic auth or not. -func SignedInUser(req *http.Request, w http.ResponseWriter, ds DataStore, sess SessionStore) (*models.User, bool) { - if !models.HasEngine { - return nil, false - } - - // Try to sign in with each of the enabled plugins - for _, ssoMethod := range Methods() { - if !ssoMethod.IsEnabled() { - continue - } - user := ssoMethod.VerifyAuthData(req, w, ds, sess) - if user != nil { - _, isBasic := ssoMethod.(*Basic) - return user, isBasic - } - } - - return nil, false -} diff --git a/modules/context/context.go b/modules/context/context.go index 1ee31e0ebbac3..2e43088ff8339 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" - "code.gitea.io/gitea/modules/auth/sso" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -49,11 +48,6 @@ type Context struct { Org *Organization } -// GetData returns the data -func (ctx *Context) GetData() map[string]interface{} { - return ctx.Data -} - // IsUserSiteAdmin returns true if current user is a site admin func (ctx *Context) IsUserSiteAdmin() bool { return ctx.IsSigned && ctx.User.IsAdmin @@ -309,7 +303,7 @@ func Contexter() macaron.Handler { } // Get user from session if logged in. - ctx.User, ctx.IsBasicAuth = sso.SignedInUser(ctx.Req.Request, c.Resp, ctx, ctx.Session) + ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Context, ctx.Session) if ctx.User != nil { ctx.IsSigned = true diff --git a/modules/context/panic.go b/modules/context/panic.go new file mode 100644 index 0000000000000..e5ef233629039 --- /dev/null +++ b/modules/context/panic.go @@ -0,0 +1,41 @@ +// Copyright 2013 Martini Authors +// Copyright 2014 The Macaron Authors +// Copyright 2019 The Gitea Authors. All rights reserved. +// +// 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 context + +import ( + "fmt" + + "code.gitea.io/gitea/modules/log" + + "gitea.com/macaron/macaron" +) + +// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so. +// Although similar to macaron.Recovery() the main difference is that this error will be created +// with the gitea 500 page. +func Recovery() macaron.Handler { + return func(ctx *Context) { + defer func() { + if err := recover(); err != nil { + combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) + ctx.ServerError("PANIC:", combinedErr) + } + }() + + ctx.Next() + } +} diff --git a/modules/middlewares/cookie.go b/modules/middlewares/cookie.go deleted file mode 100644 index 80d0e3b453ef6..0000000000000 --- a/modules/middlewares/cookie.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package middlewares - -import ( - "net/http" - "net/url" - "time" - - "code.gitea.io/gitea/modules/setting" -) - -// NewCookie creates a cookie -func NewCookie(name, value string, maxAge int) *http.Cookie { - return &http.Cookie{ - Name: name, - Value: value, - HttpOnly: true, - Path: setting.SessionConfig.CookiePath, - Domain: setting.SessionConfig.Domain, - MaxAge: maxAge, - Secure: setting.SessionConfig.Secure, - } -} - -// SetCookie set the cookies -// TODO: Copied from gitea.com/macaron/macaron and should be improved after macaron removed. -func SetCookie(resp http.ResponseWriter, name string, value string, others ...interface{}) { - cookie := http.Cookie{} - cookie.Name = name - cookie.Value = url.QueryEscape(value) - - if len(others) > 0 { - switch v := others[0].(type) { - case int: - cookie.MaxAge = v - case int64: - cookie.MaxAge = int(v) - case int32: - cookie.MaxAge = int(v) - case func(*http.Cookie): - v(&cookie) - } - } - - cookie.Path = "/" - if len(others) > 1 { - if v, ok := others[1].(string); ok && len(v) > 0 { - cookie.Path = v - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 2 { - if v, ok := others[2].(string); ok && len(v) > 0 { - cookie.Domain = v - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 3 { - switch v := others[3].(type) { - case bool: - cookie.Secure = v - case func(*http.Cookie): - v(&cookie) - default: - if others[3] != nil { - cookie.Secure = true - } - } - } - - if len(others) > 4 { - if v, ok := others[4].(bool); ok && v { - cookie.HttpOnly = true - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 5 { - if v, ok := others[5].(time.Time); ok { - cookie.Expires = v - cookie.RawExpires = v.Format(time.UnixDate) - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 6 { - for _, other := range others[6:] { - if v, ok := other.(func(*http.Cookie)); ok { - v(&cookie) - } - } - } - - resp.Header().Add("Set-Cookie", cookie.String()) -} diff --git a/modules/middlewares/locale.go b/modules/middlewares/locale.go deleted file mode 100644 index 98af890cfd20c..0000000000000 --- a/modules/middlewares/locale.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package middlewares - -import ( - "net/http" - - "code.gitea.io/gitea/modules/translation" - - "github.com/unknwon/i18n" - "golang.org/x/text/language" -) - -// Locale handle locale -func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale { - hasCookie := false - - // 1. Check URL arguments. - lang := req.URL.Query().Get("lang") - - // 2. Get language information from cookies. - if len(lang) == 0 { - ck, _ := req.Cookie("lang") - lang = ck.Value - hasCookie = true - } - - // Check again in case someone modify by purpose. - if !i18n.IsExist(lang) { - lang = "" - hasCookie = false - } - - // 3. Get language information from 'Accept-Language'. - // The first element in the list is chosen to be the default language automatically. - if len(lang) == 0 { - tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language")) - tag, _, _ := translation.Match(tags...) - lang = tag.String() - } - - if !hasCookie { - req.AddCookie(NewCookie("lang", lang, 1<<31-1)) - } - - return translation.NewLocale(lang) -} diff --git a/modules/middlewares/redis.go b/modules/middlewares/redis.go deleted file mode 100644 index ced1c1ee81491..0000000000000 --- a/modules/middlewares/redis.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron Authors -// Copyright 2020 The Gitea Authors. All rights reserved. -// -// 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 middlewares - -import ( - "fmt" - "sync" - "time" - - "code.gitea.io/gitea/modules/nosql" - - "gitea.com/go-chi/session" - "github.com/go-redis/redis/v7" -) - -// RedisStore represents a redis session store implementation. -// TODO: copied from modules/session/redis.go and should remove that one until macaron removed. -type RedisStore struct { - c redis.UniversalClient - prefix, sid string - duration time.Duration - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewRedisStore creates and returns a redis session store. -func NewRedisStore(c redis.UniversalClient, prefix, sid string, dur time.Duration, kv map[interface{}]interface{}) *RedisStore { - return &RedisStore{ - c: c, - prefix: prefix, - sid: sid, - duration: dur, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *RedisStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *RedisStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *RedisStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *RedisStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *RedisStore) Release() error { - // Skip encoding if the data is empty - if len(s.data) == 0 { - return nil - } - - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - return s.c.Set(s.prefix+s.sid, string(data), s.duration).Err() -} - -// Flush deletes all session data. -func (s *RedisStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// RedisProvider represents a redis session provider implementation. -type RedisProvider struct { - c redis.UniversalClient - duration time.Duration - prefix string -} - -// Init initializes redis session provider. -// configs: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180,prefix=session; -func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) { - p.duration, err = time.ParseDuration(fmt.Sprintf("%ds", maxlifetime)) - if err != nil { - return err - } - - uri := nosql.ToRedisURI(configs) - - for k, v := range uri.Query() { - switch k { - case "prefix": - p.prefix = v[0] - } - } - - p.c = nosql.GetManager().GetRedisClient(uri.String()) - return p.c.Ping().Err() -} - -// Read returns raw session store by session ID. -func (p *RedisProvider) Read(sid string) (session.RawStore, error) { - psid := p.prefix + sid - if !p.Exist(sid) { - if err := p.c.Set(psid, "", p.duration).Err(); err != nil { - return nil, err - } - } - - var kv map[interface{}]interface{} - kvs, err := p.c.Get(psid).Result() - if err != nil { - return nil, err - } - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(kvs)) - if err != nil { - return nil, err - } - } - - return NewRedisStore(p.c, p.prefix, sid, p.duration, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *RedisProvider) Exist(sid string) bool { - v, err := p.c.Exists(p.prefix + sid).Result() - return err == nil && v == 1 -} - -// Destroy deletes a session by session ID. -func (p *RedisProvider) Destroy(sid string) error { - return p.c.Del(p.prefix + sid).Err() -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - poldsid := p.prefix + oldsid - psid := p.prefix + sid - - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } else if !p.Exist(oldsid) { - // Make a fake old session. - if err = p.c.Set(poldsid, "", p.duration).Err(); err != nil { - return nil, err - } - } - - if err = p.c.Rename(poldsid, psid).Err(); err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - kvs, err := p.c.Get(psid).Result() - if err != nil { - return nil, err - } - - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(kvs)) - if err != nil { - return nil, err - } - } - - return NewRedisStore(p.c, p.prefix, sid, p.duration, kv), nil -} - -// Count counts and returns number of sessions. -func (p *RedisProvider) Count() int { - return int(p.c.DBSize().Val()) -} - -// GC calls GC to clean expired sessions. -func (*RedisProvider) GC() {} - -func init() { - session.Register("redis", &RedisProvider{}) -} diff --git a/modules/middlewares/virtual.go b/modules/middlewares/virtual.go deleted file mode 100644 index 70d780d65d4f7..0000000000000 --- a/modules/middlewares/virtual.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package middlewares - -import ( - "encoding/json" - "fmt" - "sync" - - "gitea.com/go-chi/session" - couchbase "gitea.com/go-chi/session/couchbase" - memcache "gitea.com/go-chi/session/memcache" - mysql "gitea.com/go-chi/session/mysql" - postgres "gitea.com/go-chi/session/postgres" -) - -// VirtualSessionProvider represents a shadowed session provider implementation. -// TODO: copied from modules/session/redis.go and should remove that one until macaron removed. -type VirtualSessionProvider struct { - lock sync.RWMutex - provider session.Provider -} - -// Init initializes the cookie session provider with given root path. -func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error { - var opts session.Options - if err := json.Unmarshal([]byte(config), &opts); err != nil { - return err - } - // Note that these options are unprepared so we can't just use NewManager here. - // Nor can we access the provider map in session. - // So we will just have to do this by hand. - // This is only slightly more wrong than modules/setting/session.go:23 - switch opts.Provider { - case "memory": - o.provider = &session.MemProvider{} - case "file": - o.provider = &session.FileProvider{} - case "redis": - o.provider = &RedisProvider{} - case "mysql": - o.provider = &mysql.MysqlProvider{} - case "postgres": - o.provider = &postgres.PostgresProvider{} - case "couchbase": - o.provider = &couchbase.CouchbaseProvider{} - case "memcache": - o.provider = &memcache.MemcacheProvider{} - default: - return fmt.Errorf("VirtualSessionProvider: Unknown Provider: %s", opts.Provider) - } - return o.provider.Init(gclifetime, opts.ProviderConfig) -} - -// Read returns raw session store by session ID. -func (o *VirtualSessionProvider) Read(sid string) (session.RawStore, error) { - o.lock.RLock() - defer o.lock.RUnlock() - if o.provider.Exist(sid) { - return o.provider.Read(sid) - } - kv := make(map[interface{}]interface{}) - kv["_old_uid"] = "0" - return NewVirtualStore(o, sid, kv), nil -} - -// Exist returns true if session with given ID exists. -func (o *VirtualSessionProvider) Exist(sid string) bool { - return true -} - -// Destroy deletes a session by session ID. -func (o *VirtualSessionProvider) Destroy(sid string) error { - o.lock.Lock() - defer o.lock.Unlock() - return o.provider.Destroy(sid) -} - -// Regenerate regenerates a session store from old session ID to new one. -func (o *VirtualSessionProvider) Regenerate(oldsid, sid string) (session.RawStore, error) { - o.lock.Lock() - defer o.lock.Unlock() - return o.provider.Regenerate(oldsid, sid) -} - -// Count counts and returns number of sessions. -func (o *VirtualSessionProvider) Count() int { - o.lock.RLock() - defer o.lock.RUnlock() - return o.provider.Count() -} - -// GC calls GC to clean expired sessions. -func (o *VirtualSessionProvider) GC() { - o.provider.GC() -} - -func init() { - session.Register("VirtualSession", &VirtualSessionProvider{}) -} - -// VirtualStore represents a virtual session store implementation. -type VirtualStore struct { - p *VirtualSessionProvider - sid string - lock sync.RWMutex - data map[interface{}]interface{} - released bool -} - -// NewVirtualStore creates and returns a virtual session store. -func NewVirtualStore(p *VirtualSessionProvider, sid string, kv map[interface{}]interface{}) *VirtualStore { - return &VirtualStore{ - p: p, - sid: sid, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *VirtualStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *VirtualStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *VirtualStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *VirtualStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *VirtualStore) Release() error { - s.lock.Lock() - defer s.lock.Unlock() - // Now need to lock the provider - s.p.lock.Lock() - defer s.p.lock.Unlock() - if oldUID, ok := s.data["_old_uid"]; (ok && (oldUID != "0" || len(s.data) > 1)) || (!ok && len(s.data) > 0) { - // Now ensure that we don't exist! - realProvider := s.p.provider - - if !s.released && realProvider.Exist(s.sid) { - // This is an error! - return fmt.Errorf("new sid '%s' already exists", s.sid) - } - realStore, err := realProvider.Read(s.sid) - if err != nil { - return err - } - if err := realStore.Flush(); err != nil { - return err - } - for key, value := range s.data { - if err := realStore.Set(key, value); err != nil { - return err - } - } - err = realStore.Release() - if err == nil { - s.released = true - } - return err - } - return nil -} - -// Flush deletes all session data. -func (s *VirtualStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} diff --git a/modules/templates/base.go b/modules/templates/base.go deleted file mode 100644 index a9b6b2737c368..0000000000000 --- a/modules/templates/base.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package templates - -import ( - "os" - "strings" - "time" - - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" -) - -// Vars represents variables to be render in golang templates -type Vars map[string]interface{} - -// Merge merges another vars to the current, another Vars will override the current -func (vars Vars) Merge(another map[string]interface{}) Vars { - for k, v := range another { - vars[k] = v - } - return vars -} - -// BaseVars returns all basic vars -func BaseVars() Vars { - var startTime = time.Now() - return map[string]interface{}{ - "IsLandingPageHome": setting.LandingPageURL == setting.LandingPageHome, - "IsLandingPageExplore": setting.LandingPageURL == setting.LandingPageExplore, - "IsLandingPageOrganizations": setting.LandingPageURL == setting.LandingPageOrganizations, - - "ShowRegistrationButton": setting.Service.ShowRegistrationButton, - "ShowMilestonesDashboardPage": setting.Service.ShowMilestonesDashboardPage, - "ShowFooterBranding": setting.ShowFooterBranding, - "ShowFooterVersion": setting.ShowFooterVersion, - - "EnableSwagger": setting.API.EnableSwagger, - "EnableOpenIDSignIn": setting.Service.EnableOpenIDSignIn, - "PageStartTime": startTime, - "TmplLoadTimes": func() string { - return time.Since(startTime).String() - }, - } -} - -func getDirAssetNames(dir string) []string { - var tmpls []string - f, err := os.Stat(dir) - if err != nil { - if os.IsNotExist(err) { - return tmpls - } - log.Warn("Unable to check if templates dir %s is a directory. Error: %v", dir, err) - return tmpls - } - if !f.IsDir() { - log.Warn("Templates dir %s is a not directory.", dir) - return tmpls - } - - files, err := util.StatDir(dir) - if err != nil { - log.Warn("Failed to read %s templates dir. %v", dir, err) - return tmpls - } - for _, filePath := range files { - if strings.HasPrefix(filePath, "mail/") { - continue - } - - if !strings.HasSuffix(filePath, ".tmpl") { - continue - } - - tmpls = append(tmpls, "templates/"+filePath) - } - return tmpls -} diff --git a/modules/templates/dynamic.go b/modules/templates/dynamic.go index f7f05e9b7c170..7f1a36e0b7e50 100644 --- a/modules/templates/dynamic.go +++ b/modules/templates/dynamic.go @@ -9,9 +9,7 @@ package templates import ( "html/template" "io/ioutil" - "os" "path" - "path/filepath" "strings" texttmpl "text/template" @@ -27,25 +25,6 @@ var ( bodyTemplates = template.New("") ) -// GetAsset returns asset content via name -func GetAsset(name string) ([]byte, error) { - bs, err := ioutil.ReadFile(filepath.Join(setting.CustomPath, name)) - if err != nil && !os.IsNotExist(err) { - return nil, err - } else if err == nil { - return bs, nil - } - - return ioutil.ReadFile(filepath.Join(setting.StaticRootPath, name)) -} - -// GetAssetNames returns assets list -func GetAssetNames() []string { - tmpls := getDirAssetNames(filepath.Join(setting.CustomPath, "templates")) - tmpls2 := getDirAssetNames(filepath.Join(setting.StaticRootPath, "templates")) - return append(tmpls, tmpls2...) -} - // HTMLRenderer implements the macaron handler for serving HTML templates. func HTMLRenderer() macaron.Handler { return macaron.Renderer(macaron.RenderOptions{ diff --git a/modules/templates/static.go b/modules/templates/static.go index 1dd3d217fccc5..0c3d65ccf25da 100644 --- a/modules/templates/static.go +++ b/modules/templates/static.go @@ -12,9 +12,7 @@ import ( "html/template" "io" "io/ioutil" - "os" "path" - "path/filepath" "strings" texttmpl "text/template" @@ -48,30 +46,6 @@ func (templates templateFileSystem) Get(name string) (io.Reader, error) { return nil, fmt.Errorf("file '%s' not found", name) } -// GetAsset get a special asset, only for chi -func GetAsset(name string) ([]byte, error) { - bs, err := ioutil.ReadFile(filepath.Join(setting.CustomPath, name)) - if err != nil && !os.IsNotExist(err) { - return nil, err - } else if err == nil { - return bs, nil - } - return Asset(strings.TrimPrefix(name, "templates/")) -} - -// GetAssetNames only for chi -func GetAssetNames() []string { - realFS := Assets.(vfsgen۰FS) - var tmpls = make([]string, 0, len(realFS)) - for k := range realFS { - tmpls = append(tmpls, "templates/"+k[1:]) - } - - customDir := path.Join(setting.CustomPath, "templates") - customTmpls := getDirAssetNames(customDir) - return append(tmpls, customTmpls...) -} - func NewTemplateFileSystem() templateFileSystem { fs := templateFileSystem{} fs.files = make([]macaron.TemplateFile, 0, 10) diff --git a/modules/translation/translation.go b/modules/translation/translation.go deleted file mode 100644 index e39bf8b21352f..0000000000000 --- a/modules/translation/translation.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package translation - -import ( - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/setting" - - macaron_i18n "gitea.com/macaron/i18n" - "github.com/unknwon/i18n" - "golang.org/x/text/language" -) - -// Locale represents an interface to translation -type Locale interface { - Language() string - Tr(string, ...interface{}) string -} - -var ( - matcher language.Matcher -) - -// InitLocales loads the locales -func InitLocales() { - localeNames, err := options.Dir("locale") - - if err != nil { - log.Fatal("Failed to list locale files: %v", err) - } - localFiles := make(map[string][]byte) - - for _, name := range localeNames { - localFiles[name], err = options.Locale(name) - - if err != nil { - log.Fatal("Failed to load %s locale file. %v", name, err) - } - } - - // These codes will be used once macaron removed - /*tags := make([]language.Tag, len(setting.Langs)) - for i, lang := range setting.Langs { - tags[i] = language.Raw.Make(lang) - } - matcher = language.NewMatcher(tags) - for i, name := range setting.Names { - i18n.SetMessage(setting.Langs[i], localFiles[name]) - } - i18n.SetDefaultLang("en-US")*/ - - // To be compatible with macaron, we now have to use macaron i18n, once macaron - // removed, we can use i18n directly - macaron_i18n.I18n(macaron_i18n.Options{ - SubURL: setting.AppSubURL, - Files: localFiles, - Langs: setting.Langs, - Names: setting.Names, - DefaultLang: "en-US", - Redirect: false, - CookieDomain: setting.SessionConfig.Domain, - }) -} - -// Match matches accept languages -func Match(tags ...language.Tag) (tag language.Tag, index int, c language.Confidence) { - return matcher.Match(tags...) -} - -// locale represents the information of localization. -type locale struct { - Lang string -} - -// NewLocale return a locale -func NewLocale(lang string) Locale { - return &locale{ - Lang: lang, - } -} - -func (l *locale) Language() string { - return l.Lang -} - -// Tr translates content to target language. -func (l *locale) Tr(format string, args ...interface{}) string { - return i18n.Tr(l.Lang, format, args...) -} diff --git a/routers/init.go b/routers/init.go index ff2ddcc0b711c..ca8944bb2bf18 100644 --- a/routers/init.go +++ b/routers/init.go @@ -26,18 +26,19 @@ import ( "code.gitea.io/gitea/modules/markup/external" repo_migrations "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/notification" + "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/task" - "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/services/mailer" mirror_service "code.gitea.io/gitea/services/mirror" pull_service "code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/repository" "code.gitea.io/gitea/services/webhook" + "gitea.com/macaron/i18n" "gitea.com/macaron/macaron" ) @@ -92,6 +93,33 @@ func initDBEngine(ctx context.Context) (err error) { return nil } +// InitLocales loads the locales +func InitLocales() { + localeNames, err := options.Dir("locale") + + if err != nil { + log.Fatal("Failed to list locale files: %v", err) + } + localFiles := make(map[string][]byte) + + for _, name := range localeNames { + localFiles[name], err = options.Locale(name) + + if err != nil { + log.Fatal("Failed to load %s locale file. %v", name, err) + } + } + i18n.I18n(i18n.Options{ + SubURL: setting.AppSubURL, + Files: localFiles, + Langs: setting.Langs, + Names: setting.Names, + DefaultLang: "en-US", + Redirect: false, + CookieDomain: setting.SessionConfig.Domain, + }) +} + // PreInstallInit preloads the configuration to check if we need to run install func PreInstallInit(ctx context.Context) bool { setting.NewContext() @@ -101,7 +129,7 @@ func PreInstallInit(ctx context.Context) bool { log.Trace("Custom path: %s", setting.CustomPath) log.Trace("Log path: %s", setting.LogRootPath) log.Trace("Preparing to run install page") - translation.InitLocales() + InitLocales() if setting.EnableSQLite3 { log.Info("SQLite3 Supported") } @@ -142,7 +170,7 @@ func GlobalInit(ctx context.Context) { log.Trace("Log path: %s", setting.LogRootPath) // Setup i18n - translation.InitLocales() + InitLocales() NewServices() diff --git a/routers/routes/chi.go b/routers/routes/chi.go index c0ac88957ee2b..00689441b7829 100644 --- a/routers/routes/chi.go +++ b/routers/routes/chi.go @@ -24,7 +24,6 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/routers" - "gitea.com/go-chi/session" "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" "github.com/prometheus/client_golang/prometheus" @@ -38,7 +37,7 @@ type routerLoggerOptions struct { } // SignedUserName returns signed user's name via context -// FIXME currently no any data stored on chi.Context but macaron.Context, so this will +// FIXME currently no any data stored on gin.Context but macaron.Context, so this will // return "" before we remove macaron totally func SignedUserName(req *http.Request) string { if v, ok := req.Context().Value("SignedUserName").(string); ok { @@ -98,6 +97,24 @@ func LoggerHandler(level log.Level) func(next http.Handler) http.Handler { } } +// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so. +// Although similar to macaron.Recovery() the main difference is that this error will be created +// with the gitea 500 page. +func Recovery() func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + defer func() { + if err := recover(); err != nil { + combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) + http.Error(w, combinedErr, 500) + } + }() + + next.ServeHTTP(w, req) + }) + } +} + func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { if storageSetting.ServeDirect { @@ -185,17 +202,6 @@ func NewChi() chi.Router { c.Use(LoggerHandler(setting.RouterLogLevel)) } } - c.Use(session.Sessioner(session.Options{ - Provider: setting.SessionConfig.Provider, - ProviderConfig: setting.SessionConfig.ProviderConfig, - CookieName: setting.SessionConfig.CookieName, - CookiePath: setting.SessionConfig.CookiePath, - Gclifetime: setting.SessionConfig.Gclifetime, - Maxlifetime: setting.SessionConfig.Maxlifetime, - Secure: setting.SessionConfig.Secure, - Domain: setting.SessionConfig.Domain, - })) - c.Use(Recovery()) if setting.EnableAccessLog { setupAccessLogger(c) diff --git a/routers/routes/recovery.go b/routers/routes/recovery.go deleted file mode 100644 index cf4b1a8d8406d..0000000000000 --- a/routers/routes/recovery.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package routes - -import ( - "fmt" - "net/http" - - "code.gitea.io/gitea/modules/auth/sso" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/middlewares" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - - "gitea.com/go-chi/session" - "github.com/unrolled/render" -) - -type dataStore struct { - Data map[string]interface{} -} - -func (d *dataStore) GetData() map[string]interface{} { - return d.Data -} - -// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so. -// Although similar to macaron.Recovery() the main difference is that this error will be created -// with the gitea 500 page. -func Recovery() func(next http.Handler) http.Handler { - var isDevelopment = setting.RunMode != "prod" - return func(next http.Handler) http.Handler { - rnd := render.New(render.Options{ - Extensions: []string{".tmpl"}, - Directory: "templates", - Funcs: templates.NewFuncMap(), - Asset: templates.GetAsset, - AssetNames: templates.GetAssetNames, - IsDevelopment: isDevelopment, - }) - - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - defer func() { - // Why we need this? The first recover will try to render a beautiful - // error page for user, but the process can still panic again, then - // we have to just recover twice and send a simple error page that - // should not panic any more. - defer func() { - if err := recover(); err != nil { - combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) - log.Error(combinedErr) - if isDevelopment { - http.Error(w, combinedErr, 500) - } else { - http.Error(w, http.StatusText(500), 500) - } - } - }() - - if err := recover(); err != nil { - combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) - log.Error("%v", combinedErr) - - lc := middlewares.Locale(w, req) - sess := session.GetSession(req) - - var store = dataStore{ - Data: templates.Vars{ - "Language": lc.Language(), - "CurrentURL": setting.AppSubURL + req.URL.RequestURI(), - "i18n": lc, - }, - } - - // Get user from session if logged in. - user, _ := sso.SignedInUser(req, w, &store, sess) - if user != nil { - store.Data["IsSigned"] = true - store.Data["SignedUser"] = user - store.Data["SignedUserID"] = user.ID - store.Data["SignedUserName"] = user.Name - store.Data["IsAdmin"] = user.IsAdmin - } else { - store.Data["SignedUserID"] = int64(0) - store.Data["SignedUserName"] = "" - } - - w.Header().Set(`X-Frame-Options`, `SAMEORIGIN`) - - if setting.RunMode != "prod" { - store.Data["ErrMsg"] = combinedErr - } - err := rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store.Data)) - if err != nil { - log.Error("%v", err) - } - } - }() - - next.ServeHTTP(w, req) - }) - } -} diff --git a/vendor/gitea.com/go-chi/session/.drone.yml b/vendor/gitea.com/go-chi/session/.drone.yml deleted file mode 100644 index d941e57505d63..0000000000000 --- a/vendor/gitea.com/go-chi/session/.drone.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -kind: pipeline -name: test - -platform: - os: linux - arch: amd64 - -clone: - disable: true - -workspace: - base: /go - path: src/session113 - -steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: test - pull: default - image: golang:1.13 - environment: - GO111MODULE: on - GOPROXY: https://goproxy.cn - commands: - - go build -v - - go vet ./... - - go test -v -race -coverprofile=coverage.txt -covermode=atomic - when: - event: - - push - - pull_request \ No newline at end of file diff --git a/vendor/gitea.com/go-chi/session/.gitignore b/vendor/gitea.com/go-chi/session/.gitignore deleted file mode 100644 index 834722925c9ea..0000000000000 --- a/vendor/gitea.com/go-chi/session/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -ledis/tmp.db -nodb/tmp.db -/vendor -/.idea diff --git a/vendor/gitea.com/go-chi/session/LICENSE b/vendor/gitea.com/go-chi/session/LICENSE deleted file mode 100644 index 8405e89a0b120..0000000000000 --- a/vendor/gitea.com/go-chi/session/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -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: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -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 -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. \ No newline at end of file diff --git a/vendor/gitea.com/go-chi/session/README.md b/vendor/gitea.com/go-chi/session/README.md deleted file mode 100644 index ed3258fcef61d..0000000000000 --- a/vendor/gitea.com/go-chi/session/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Session - -Middleware session provides session management which copied from [Macaron Session](https://gitea.com/go-chi/session) for [go-chi](https://github.com/go-chi/chi). It can use many session providers, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Couchbase, Ledis and Nodb. - -## Installation - -``` -go get gitea.com/go-chi/session -``` - -## Credits - -This package is a modified version of [go-macaron/session](github.com/go-macaron/session). - -## License - -This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text. \ No newline at end of file diff --git a/vendor/gitea.com/go-chi/session/couchbase/couchbase.go b/vendor/gitea.com/go-chi/session/couchbase/couchbase.go deleted file mode 100644 index 31899a8574182..0000000000000 --- a/vendor/gitea.com/go-chi/session/couchbase/couchbase.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "strings" - "sync" - - "gitea.com/go-chi/session" - "github.com/couchbase/go-couchbase" -) - -// CouchbaseSessionStore represents a couchbase session store implementation. -type CouchbaseSessionStore struct { - b *couchbase.Bucket - sid string - lock sync.RWMutex - data map[interface{}]interface{} - maxlifetime int64 -} - -// Set sets value to given key in session. -func (s *CouchbaseSessionStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *CouchbaseSessionStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *CouchbaseSessionStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *CouchbaseSessionStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *CouchbaseSessionStore) Release() error { - defer s.b.Close() - - // Skip encoding if the data is empty - if len(s.data) == 0 { - return nil - } - - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - return s.b.Set(s.sid, int(s.maxlifetime), data) -} - -// Flush deletes all session data. -func (s *CouchbaseSessionStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// CouchbaseProvider represents a couchbase session provider implementation. -type CouchbaseProvider struct { - maxlifetime int64 - connStr string - pool string - bucket string - b *couchbase.Bucket -} - -func (cp *CouchbaseProvider) getBucket() *couchbase.Bucket { - c, err := couchbase.Connect(cp.connStr) - if err != nil { - return nil - } - - pool, err := c.GetPool(cp.pool) - if err != nil { - return nil - } - - bucket, err := pool.GetBucket(cp.bucket) - if err != nil { - return nil - } - - return bucket -} - -// Init initializes memory session provider. -// connStr is couchbase server REST/JSON URL -// e.g. http://host:port/, Pool, Bucket -func (p *CouchbaseProvider) Init(maxlifetime int64, connStr string) error { - p.maxlifetime = maxlifetime - configs := strings.Split(connStr, ",") - if len(configs) > 0 { - p.connStr = configs[0] - } - if len(configs) > 1 { - p.pool = configs[1] - } - if len(configs) > 2 { - p.bucket = configs[2] - } - - return nil -} - -// Read returns raw session store by session ID. -func (p *CouchbaseProvider) Read(sid string) (session.RawStore, error) { - p.b = p.getBucket() - - var doc []byte - - err := p.b.Get(sid, &doc) - var kv map[interface{}]interface{} - if doc == nil { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(doc) - if err != nil { - return nil, err - } - } - - cs := &CouchbaseSessionStore{b: p.b, sid: sid, data: kv, maxlifetime: p.maxlifetime} - return cs, nil -} - -// Exist returns true if session with given ID exists. -func (p *CouchbaseProvider) Exist(sid string) bool { - p.b = p.getBucket() - defer p.b.Close() - - var doc []byte - - if err := p.b.Get(sid, &doc); err != nil || doc == nil { - return false - } else { - return true - } -} - -// Destroy deletes a session by session ID. -func (p *CouchbaseProvider) Destroy(sid string) error { - p.b = p.getBucket() - defer p.b.Close() - - p.b.Delete(sid) - return nil -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *CouchbaseProvider) Regenerate(oldsid, sid string) (session.RawStore, error) { - p.b = p.getBucket() - - var doc []byte - if err := p.b.Get(oldsid, &doc); err != nil || doc == nil { - p.b.Set(sid, int(p.maxlifetime), "") - } else { - err := p.b.Delete(oldsid) - if err != nil { - return nil, err - } - _, _ = p.b.Add(sid, int(p.maxlifetime), doc) - } - - err := p.b.Get(sid, &doc) - if err != nil { - return nil, err - } - var kv map[interface{}]interface{} - if doc == nil { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(doc) - if err != nil { - return nil, err - } - } - - cs := &CouchbaseSessionStore{b: p.b, sid: sid, data: kv, maxlifetime: p.maxlifetime} - return cs, nil -} - -// Count counts and returns number of sessions. -func (p *CouchbaseProvider) Count() int { - // FIXME - return 0 -} - -// GC calls GC to clean expired sessions. -func (p *CouchbaseProvider) GC() {} - -func init() { - session.Register("couchbase", &CouchbaseProvider{}) -} diff --git a/vendor/gitea.com/go-chi/session/file.go b/vendor/gitea.com/go-chi/session/file.go deleted file mode 100644 index ce915344fb79f..0000000000000 --- a/vendor/gitea.com/go-chi/session/file.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "sync" - "time" - - "github.com/unknwon/com" -) - -// FileStore represents a file session store implementation. -type FileStore struct { - p *FileProvider - sid string - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewFileStore creates and returns a file session store. -func NewFileStore(p *FileProvider, sid string, kv map[interface{}]interface{}) *FileStore { - return &FileStore{ - p: p, - sid: sid, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *FileStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *FileStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *FileStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *FileStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *FileStore) Release() error { - s.p.lock.Lock() - defer s.p.lock.Unlock() - - // Skip encoding if the data is empty - if len(s.data) == 0 { - return nil - } - - data, err := EncodeGob(s.data) - if err != nil { - return err - } - - return ioutil.WriteFile(s.p.filepath(s.sid), data, 0600) -} - -// Flush deletes all session data. -func (s *FileStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// FileProvider represents a file session provider implementation. -type FileProvider struct { - lock sync.RWMutex - maxlifetime int64 - rootPath string -} - -// Init initializes file session provider with given root path. -func (p *FileProvider) Init(maxlifetime int64, rootPath string) error { - p.lock.Lock() - p.maxlifetime = maxlifetime - p.rootPath = rootPath - p.lock.Unlock() - return nil -} - -func (p *FileProvider) filepath(sid string) string { - return path.Join(p.rootPath, string(sid[0]), string(sid[1]), sid) -} - -// Read returns raw session store by session ID. -func (p *FileProvider) Read(sid string) (_ RawStore, err error) { - filename := p.filepath(sid) - if err = os.MkdirAll(path.Dir(filename), 0700); err != nil { - return nil, err - } - p.lock.RLock() - defer p.lock.RUnlock() - - var f *os.File - ok := false - if com.IsFile(filename) { - modTime, err := com.FileMTime(filename) - if err != nil { - return nil, err - } - ok = (modTime + p.maxlifetime) >= time.Now().Unix() - } - if ok { - f, err = os.OpenFile(filename, os.O_RDONLY, 0600) - } else { - f, err = os.Create(filename) - } - if err != nil { - return nil, err - } - defer f.Close() - - if err = os.Chtimes(filename, time.Now(), time.Now()); err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - data, err := ioutil.ReadAll(f) - if err != nil { - return nil, err - } - if len(data) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = DecodeGob(data) - if err != nil { - return nil, err - } - } - return NewFileStore(p, sid, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *FileProvider) Exist(sid string) bool { - p.lock.RLock() - defer p.lock.RUnlock() - return com.IsFile(p.filepath(sid)) -} - -// Destroy deletes a session by session ID. -func (p *FileProvider) Destroy(sid string) error { - p.lock.Lock() - defer p.lock.Unlock() - return os.Remove(p.filepath(sid)) -} - -func (p *FileProvider) regenerate(oldsid, sid string) (err error) { - p.lock.Lock() - defer p.lock.Unlock() - - filename := p.filepath(sid) - if com.IsExist(filename) { - return fmt.Errorf("new sid '%s' already exists", sid) - } - - oldname := p.filepath(oldsid) - if !com.IsFile(oldname) { - data, err := EncodeGob(make(map[interface{}]interface{})) - if err != nil { - return err - } - if err = os.MkdirAll(path.Dir(oldname), 0700); err != nil { - return err - } - if err = ioutil.WriteFile(oldname, data, 0600); err != nil { - return err - } - } - - if err = os.MkdirAll(path.Dir(filename), 0700); err != nil { - return err - } - if err = os.Rename(oldname, filename); err != nil { - return err - } - return nil -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *FileProvider) Regenerate(oldsid, sid string) (_ RawStore, err error) { - if err := p.regenerate(oldsid, sid); err != nil { - return nil, err - } - - return p.Read(sid) -} - -// Count counts and returns number of sessions. -func (p *FileProvider) Count() int { - count := 0 - if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if !fi.IsDir() { - count++ - } - return nil - }); err != nil { - log.Printf("error counting session files: %v", err) - return 0 - } - return count -} - -// GC calls GC to clean expired sessions. -func (p *FileProvider) GC() { - p.lock.RLock() - defer p.lock.RUnlock() - - if !com.IsExist(p.rootPath) { - return - } - - if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if !fi.IsDir() && - (fi.ModTime().Unix()+p.maxlifetime) < time.Now().Unix() { - return os.Remove(path) - } - return nil - }); err != nil { - log.Printf("error garbage collecting session files: %v", err) - } -} - -func init() { - Register("file", &FileProvider{}) -} diff --git a/vendor/gitea.com/go-chi/session/go.mod b/vendor/gitea.com/go-chi/session/go.mod deleted file mode 100644 index 66120800477c1..0000000000000 --- a/vendor/gitea.com/go-chi/session/go.mod +++ /dev/null @@ -1,26 +0,0 @@ -module gitea.com/go-chi/session - -go 1.11 - -require ( - github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 - github.com/couchbase/go-couchbase v0.0.0-20201026062457-7b3be89bbd89 - github.com/couchbase/gomemcached v0.1.1 // indirect - github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67 // indirect - github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect - github.com/edsrzf/mmap-go v1.0.0 // indirect - github.com/go-chi/chi v1.5.1 - github.com/go-redis/redis/v8 v8.4.0 - github.com/go-sql-driver/mysql v1.4.1 - github.com/lib/pq v1.2.0 - github.com/pelletier/go-toml v1.8.1 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect - github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 - github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect - github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 - github.com/syndtr/goleveldb v1.0.0 // indirect - github.com/unknwon/com v1.0.1 - google.golang.org/appengine v1.6.7 // indirect - gopkg.in/ini.v1 v1.62.0 -) diff --git a/vendor/gitea.com/go-chi/session/go.sum b/vendor/gitea.com/go-chi/session/go.sum deleted file mode 100644 index e2c174b0c76e8..0000000000000 --- a/vendor/gitea.com/go-chi/session/go.sum +++ /dev/null @@ -1,151 +0,0 @@ -github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= -github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/couchbase/go-couchbase v0.0.0-20201026062457-7b3be89bbd89 h1:uNLXQ6QO1TocD8BaN/KkRki0Xw0brCM1PKl/ZA5pgfs= -github.com/couchbase/go-couchbase v0.0.0-20201026062457-7b3be89bbd89/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A= -github.com/couchbase/gomemcached v0.1.1 h1:xCS8ZglJDhrlQg3jmK7Rn1V8f7bPjXABLC05CgLQauc= -github.com/couchbase/gomemcached v0.1.1/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= -github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67 h1:NCqJ6fwen6YP0WlV/IyibaT0kPt3JEI1rA62V/UPKT4= -github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= -github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ= -github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-chi/chi v1.5.1 h1:kfTK3Cxd/dkMu/rKs5ZceWYp+t5CtiE7vmaTv3LjC6w= -github.com/go-chi/chi v1.5.1/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k= -github.com/go-redis/redis/v8 v8.4.0 h1:J5NCReIgh3QgUJu398hUncxDExN4gMOHI11NVbVicGQ= -github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= -github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -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/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= -github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= -github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 h1:qvsJwGToa8rxb42cDRhkbKeX2H5N8BH+s2aUikGt8mI= -github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= -github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs= -github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= -github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= -github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= -github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= -github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= -go.opentelemetry.io/otel v0.14.0 h1:YFBEfjCk9MTjaytCNSUkp9Q8lF7QJezA06T71FbQxLQ= -go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/gitea.com/go-chi/session/memcache/memcache.go b/vendor/gitea.com/go-chi/session/memcache/memcache.go deleted file mode 100644 index ed08b915df038..0000000000000 --- a/vendor/gitea.com/go-chi/session/memcache/memcache.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "fmt" - "strings" - "sync" - - "gitea.com/go-chi/session" - "github.com/bradfitz/gomemcache/memcache" -) - -// MemcacheStore represents a memcache session store implementation. -type MemcacheStore struct { - c *memcache.Client - sid string - expire int32 - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewMemcacheStore creates and returns a memcache session store. -func NewMemcacheStore(c *memcache.Client, sid string, expire int32, kv map[interface{}]interface{}) *MemcacheStore { - return &MemcacheStore{ - c: c, - sid: sid, - expire: expire, - data: kv, - } -} - -func NewItem(sid string, data []byte, expire int32) *memcache.Item { - return &memcache.Item{ - Key: sid, - Value: data, - Expiration: expire, - } -} - -// Set sets value to given key in session. -func (s *MemcacheStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *MemcacheStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *MemcacheStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *MemcacheStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *MemcacheStore) Release() error { - // Skip encoding if the data is empty - if len(s.data) == 0 { - return nil - } - - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - return s.c.Set(NewItem(s.sid, data, s.expire)) -} - -// Flush deletes all session data. -func (s *MemcacheStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// MemcacheProvider represents a memcache session provider implementation. -type MemcacheProvider struct { - c *memcache.Client - expire int32 -} - -// Init initializes memcache session provider. -// connStrs: 127.0.0.1:9090;127.0.0.1:9091 -func (p *MemcacheProvider) Init(expire int64, connStrs string) error { - p.expire = int32(expire) - p.c = memcache.New(strings.Split(connStrs, ";")...) - return nil -} - -// Read returns raw session store by session ID. -func (p *MemcacheProvider) Read(sid string) (session.RawStore, error) { - if !p.Exist(sid) { - if err := p.c.Set(NewItem(sid, []byte(""), p.expire)); err != nil { - return nil, err - } - } - - var kv map[interface{}]interface{} - item, err := p.c.Get(sid) - if err != nil { - return nil, err - } - if len(item.Value) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(item.Value) - if err != nil { - return nil, err - } - } - - return NewMemcacheStore(p.c, sid, p.expire, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *MemcacheProvider) Exist(sid string) bool { - _, err := p.c.Get(sid) - return err == nil -} - -// Destroy deletes a session by session ID. -func (p *MemcacheProvider) Destroy(sid string) error { - return p.c.Delete(sid) -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *MemcacheProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } - - item := NewItem(sid, []byte(""), p.expire) - if p.Exist(oldsid) { - item, err = p.c.Get(oldsid) - if err != nil { - return nil, err - } else if err = p.c.Delete(oldsid); err != nil { - return nil, err - } - item.Key = sid - } - if err = p.c.Set(item); err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(item.Value) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(item.Value) - if err != nil { - return nil, err - } - } - - return NewMemcacheStore(p.c, sid, p.expire, kv), nil -} - -// Count counts and returns number of sessions. -func (p *MemcacheProvider) Count() int { - // FIXME: how come this library does not have Stats method? - return -1 -} - -// GC calls GC to clean expired sessions. -func (p *MemcacheProvider) GC() {} - -func init() { - session.Register("memcache", &MemcacheProvider{}) -} diff --git a/vendor/gitea.com/go-chi/session/memcache/memcache.goconvey b/vendor/gitea.com/go-chi/session/memcache/memcache.goconvey deleted file mode 100644 index 8485e986e458a..0000000000000 --- a/vendor/gitea.com/go-chi/session/memcache/memcache.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/gitea.com/go-chi/session/memory.go b/vendor/gitea.com/go-chi/session/memory.go deleted file mode 100644 index d3a623c672811..0000000000000 --- a/vendor/gitea.com/go-chi/session/memory.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "container/list" - "fmt" - "sync" - "time" -) - -// MemStore represents a in-memory session store implementation. -type MemStore struct { - sid string - lock sync.RWMutex - data map[interface{}]interface{} - lastAccess time.Time -} - -// NewMemStore creates and returns a memory session store. -func NewMemStore(sid string) *MemStore { - return &MemStore{ - sid: sid, - data: make(map[interface{}]interface{}), - lastAccess: time.Now(), - } -} - -// Set sets value to given key in session. -func (s *MemStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *MemStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete deletes a key from session. -func (s *MemStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *MemStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (*MemStore) Release() error { - return nil -} - -// Flush deletes all session data. -func (s *MemStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// MemProvider represents a in-memory session provider implementation. -type MemProvider struct { - lock sync.RWMutex - maxLifetime int64 - data map[string]*list.Element - // A priority list whose lastAccess newer gets higer priority. - list *list.List -} - -// Init initializes memory session provider. -func (p *MemProvider) Init(maxLifetime int64, _ string) error { - p.lock.Lock() - p.list = list.New() - p.data = make(map[string]*list.Element) - p.maxLifetime = maxLifetime - p.lock.Unlock() - return nil -} - -// update expands time of session store by given ID. -func (p *MemProvider) update(sid string) error { - p.lock.Lock() - defer p.lock.Unlock() - - if e, ok := p.data[sid]; ok { - e.Value.(*MemStore).lastAccess = time.Now() - p.list.MoveToFront(e) - return nil - } - return nil -} - -// Read returns raw session store by session ID. -func (p *MemProvider) Read(sid string) (_ RawStore, err error) { - p.lock.RLock() - e, ok := p.data[sid] - p.lock.RUnlock() - - // Only restore if the session is still alive. - if ok && (e.Value.(*MemStore).lastAccess.Unix()+p.maxLifetime) >= time.Now().Unix() { - if err = p.update(sid); err != nil { - return nil, err - } - return e.Value.(*MemStore), nil - } - - // Create a new session. - p.lock.Lock() - defer p.lock.Unlock() - if ok { - p.list.Remove(e) - delete(p.data, sid) - } - s := NewMemStore(sid) - p.data[sid] = p.list.PushBack(s) - return s, nil -} - -// Exist returns true if session with given ID exists. -func (p *MemProvider) Exist(sid string) bool { - p.lock.RLock() - defer p.lock.RUnlock() - - _, ok := p.data[sid] - return ok -} - -// Destroy deletes a session by session ID. -func (p *MemProvider) Destroy(sid string) error { - p.lock.Lock() - defer p.lock.Unlock() - - e, ok := p.data[sid] - if !ok { - return nil - } - - p.list.Remove(e) - delete(p.data, sid) - return nil -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *MemProvider) Regenerate(oldsid, sid string) (RawStore, error) { - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } - - s, err := p.Read(oldsid) - if err != nil { - return nil, err - } - - if err = p.Destroy(oldsid); err != nil { - return nil, err - } - - s.(*MemStore).sid = sid - - p.lock.Lock() - defer p.lock.Unlock() - p.data[sid] = p.list.PushBack(s) - return s, nil -} - -// Count counts and returns number of sessions. -func (p *MemProvider) Count() int { - return p.list.Len() -} - -// GC calls GC to clean expired sessions. -func (p *MemProvider) GC() { - p.lock.RLock() - for { - // No session in the list. - e := p.list.Back() - if e == nil { - break - } - - if (e.Value.(*MemStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() { - p.lock.RUnlock() - p.lock.Lock() - p.list.Remove(e) - delete(p.data, e.Value.(*MemStore).sid) - p.lock.Unlock() - p.lock.RLock() - } else { - break - } - } - p.lock.RUnlock() -} - -func init() { - Register("memory", &MemProvider{}) -} diff --git a/vendor/gitea.com/go-chi/session/mysql/mysql.go b/vendor/gitea.com/go-chi/session/mysql/mysql.go deleted file mode 100644 index 7ec647bf3abfb..0000000000000 --- a/vendor/gitea.com/go-chi/session/mysql/mysql.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "database/sql" - "fmt" - "log" - "sync" - "time" - - "gitea.com/go-chi/session" - _ "github.com/go-sql-driver/mysql" -) - -// MysqlStore represents a mysql session store implementation. -type MysqlStore struct { - c *sql.DB - sid string - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewMysqlStore creates and returns a mysql session store. -func NewMysqlStore(c *sql.DB, sid string, kv map[interface{}]interface{}) *MysqlStore { - return &MysqlStore{ - c: c, - sid: sid, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *MysqlStore) Set(key, val interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = val - return nil -} - -// Get gets value by given key in session. -func (s *MysqlStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *MysqlStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *MysqlStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *MysqlStore) Release() error { - // Skip encoding if the data is empty - if len(s.data) == 0 { - return nil - } - - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - _, err = s.c.Exec("UPDATE session SET data=?, expiry=? WHERE `key`=?", - data, time.Now().Unix(), s.sid) - return err -} - -// Flush deletes all session data. -func (s *MysqlStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// MysqlProvider represents a mysql session provider implementation. -type MysqlProvider struct { - c *sql.DB - expire int64 -} - -// Init initializes mysql session provider. -// connStr: username:password@protocol(address)/dbname?param=value -func (p *MysqlProvider) Init(expire int64, connStr string) (err error) { - p.expire = expire - - p.c, err = sql.Open("mysql", connStr) - if err != nil { - return err - } - return p.c.Ping() -} - -// Read returns raw session store by session ID. -func (p *MysqlProvider) Read(sid string) (session.RawStore, error) { - now := time.Now().Unix() - var data []byte - expiry := now - err := p.c.QueryRow("SELECT data, expiry FROM session WHERE `key`=?", sid).Scan(&data, &expiry) - if err == sql.ErrNoRows { - _, err = p.c.Exec("INSERT INTO session(`key`,data,expiry) VALUES(?,?,?)", - sid, "", now) - } - if err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(data) == 0 || expiry+p.expire <= now { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(data) - if err != nil { - return nil, err - } - } - - return NewMysqlStore(p.c, sid, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *MysqlProvider) Exist(sid string) bool { - var data []byte - err := p.c.QueryRow("SELECT data FROM session WHERE `key`=?", sid).Scan(&data) - if err != nil && err != sql.ErrNoRows { - panic("session/mysql: error checking existence: " + err.Error()) - } - return err != sql.ErrNoRows -} - -// Destroy deletes a session by session ID. -func (p *MysqlProvider) Destroy(sid string) error { - _, err := p.c.Exec("DELETE FROM session WHERE `key`=?", sid) - return err -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *MysqlProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } - - if !p.Exist(oldsid) { - if _, err = p.c.Exec("INSERT INTO session(`key`,data,expiry) VALUES(?,?,?)", - oldsid, "", time.Now().Unix()); err != nil { - return nil, err - } - } - - if _, err = p.c.Exec("UPDATE session SET `key`=? WHERE `key`=?", sid, oldsid); err != nil { - return nil, err - } - - return p.Read(sid) -} - -// Count counts and returns number of sessions. -func (p *MysqlProvider) Count() (total int) { - if err := p.c.QueryRow("SELECT COUNT(*) AS NUM FROM session").Scan(&total); err != nil { - panic("session/mysql: error counting records: " + err.Error()) - } - return total -} - -// GC calls GC to clean expired sessions. -func (p *MysqlProvider) GC() { - if _, err := p.c.Exec("DELETE FROM session WHERE expiry + ? <= UNIX_TIMESTAMP(NOW())", p.expire); err != nil { - log.Printf("session/mysql: error garbage collecting: %v", err) - } -} - -func init() { - session.Register("mysql", &MysqlProvider{}) -} diff --git a/vendor/gitea.com/go-chi/session/mysql/mysql.goconvey b/vendor/gitea.com/go-chi/session/mysql/mysql.goconvey deleted file mode 100644 index 8485e986e458a..0000000000000 --- a/vendor/gitea.com/go-chi/session/mysql/mysql.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/gitea.com/go-chi/session/postgres/postgres.go b/vendor/gitea.com/go-chi/session/postgres/postgres.go deleted file mode 100644 index 383906d8d7183..0000000000000 --- a/vendor/gitea.com/go-chi/session/postgres/postgres.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "database/sql" - "fmt" - "log" - "sync" - "time" - - "gitea.com/go-chi/session" - _ "github.com/lib/pq" -) - -// PostgresStore represents a postgres session store implementation. -type PostgresStore struct { - c *sql.DB - sid string - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewPostgresStore creates and returns a postgres session store. -func NewPostgresStore(c *sql.DB, sid string, kv map[interface{}]interface{}) *PostgresStore { - return &PostgresStore{ - c: c, - sid: sid, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *PostgresStore) Set(key, value interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data[key] = value - return nil -} - -// Get gets value by given key in session. -func (s *PostgresStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *PostgresStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *PostgresStore) ID() string { - return s.sid -} - -// save postgres session values to database. -// must call this method to save values to database. -func (s *PostgresStore) Release() error { - // Skip encoding if the data is empty - if len(s.data) == 0 { - return nil - } - - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - _, err = s.c.Exec("UPDATE session SET data=$1, expiry=$2 WHERE key=$3", - data, time.Now().Unix(), s.sid) - return err -} - -// Flush deletes all session data. -func (s *PostgresStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// PostgresProvider represents a postgres session provider implementation. -type PostgresProvider struct { - c *sql.DB - maxlifetime int64 -} - -// Init initializes postgres session provider. -// connStr: user=a password=b host=localhost port=5432 dbname=c sslmode=disable -func (p *PostgresProvider) Init(maxlifetime int64, connStr string) (err error) { - p.maxlifetime = maxlifetime - - p.c, err = sql.Open("postgres", connStr) - if err != nil { - return err - } - return p.c.Ping() -} - -// Read returns raw session store by session ID. -func (p *PostgresProvider) Read(sid string) (session.RawStore, error) { - now := time.Now().Unix() - var data []byte - expiry := now - err := p.c.QueryRow("SELECT data, expiry FROM session WHERE key=$1", sid).Scan(&data, &expiry) - if err == sql.ErrNoRows { - _, err = p.c.Exec("INSERT INTO session(key,data,expiry) VALUES($1,$2,$3)", - sid, "", now) - } - if err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(data) == 0 || expiry+p.maxlifetime <= now { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(data) - if err != nil { - return nil, err - } - } - - return NewPostgresStore(p.c, sid, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *PostgresProvider) Exist(sid string) bool { - var data []byte - err := p.c.QueryRow("SELECT data FROM session WHERE key=$1", sid).Scan(&data) - if err != nil && err != sql.ErrNoRows { - panic("session/postgres: error checking existence: " + err.Error()) - } - return err != sql.ErrNoRows -} - -// Destroy deletes a session by session ID. -func (p *PostgresProvider) Destroy(sid string) error { - _, err := p.c.Exec("DELETE FROM session WHERE key=$1", sid) - return err -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *PostgresProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } - - if !p.Exist(oldsid) { - if _, err = p.c.Exec("INSERT INTO session(key,data,expiry) VALUES($1,$2,$3)", - oldsid, "", time.Now().Unix()); err != nil { - return nil, err - } - } - - if _, err = p.c.Exec("UPDATE session SET key=$1 WHERE key=$2", sid, oldsid); err != nil { - return nil, err - } - - return p.Read(sid) -} - -// Count counts and returns number of sessions. -func (p *PostgresProvider) Count() (total int) { - if err := p.c.QueryRow("SELECT COUNT(*) AS NUM FROM session").Scan(&total); err != nil { - panic("session/postgres: error counting records: " + err.Error()) - } - return total -} - -// GC calls GC to clean expired sessions. -func (p *PostgresProvider) GC() { - if _, err := p.c.Exec("DELETE FROM session WHERE EXTRACT(EPOCH FROM NOW()) - expiry > $1", p.maxlifetime); err != nil { - log.Printf("session/postgres: error garbage collecting: %v", err) - } -} - -func init() { - session.Register("postgres", &PostgresProvider{}) -} diff --git a/vendor/gitea.com/go-chi/session/postgres/postgres.goconvey b/vendor/gitea.com/go-chi/session/postgres/postgres.goconvey deleted file mode 100644 index 8485e986e458a..0000000000000 --- a/vendor/gitea.com/go-chi/session/postgres/postgres.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/gitea.com/go-chi/session/secret.go b/vendor/gitea.com/go-chi/session/secret.go deleted file mode 100644 index e56a50615b820..0000000000000 --- a/vendor/gitea.com/go-chi/session/secret.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package session - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/sha256" - "encoding/base64" - "errors" - "io" -) - -// NewSecret creates a new secret -func NewSecret() (string, error) { - return NewSecretWithLength(32) -} - -// NewSecretWithLength creates a new secret for a given length -func NewSecretWithLength(length int64) (string, error) { - return randomString(length) -} - -func randomBytes(len int64) ([]byte, error) { - b := make([]byte, len) - if _, err := rand.Read(b); err != nil { - return nil, err - } - return b, nil -} - -func randomString(len int64) (string, error) { - b, err := randomBytes(len) - return base64.URLEncoding.EncodeToString(b), err -} - -// AesEncrypt encrypts text and given key with AES. -func AesEncrypt(key, text []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - b := base64.StdEncoding.EncodeToString(text) - ciphertext := make([]byte, aes.BlockSize+len(b)) - iv := ciphertext[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - cfb := cipher.NewCFBEncrypter(block, iv) - cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) - return ciphertext, nil -} - -// AesDecrypt decrypts text and given key with AES. -func AesDecrypt(key, text []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - if len(text) < aes.BlockSize { - return nil, errors.New("ciphertext too short") - } - iv := text[:aes.BlockSize] - text = text[aes.BlockSize:] - cfb := cipher.NewCFBDecrypter(block, iv) - cfb.XORKeyStream(text, text) - data, err := base64.StdEncoding.DecodeString(string(text)) - if err != nil { - return nil, err - } - return data, nil -} - -// EncryptSecret encrypts a string with given key into a hex string -func EncryptSecret(key string, str string) (string, error) { - keyHash := sha256.Sum256([]byte(key)) - plaintext := []byte(str) - ciphertext, err := AesEncrypt(keyHash[:], plaintext) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(ciphertext), nil -} - -// DecryptSecret decrypts a previously encrypted hex string -func DecryptSecret(key string, cipherhex string) (string, error) { - keyHash := sha256.Sum256([]byte(key)) - ciphertext, err := base64.StdEncoding.DecodeString(cipherhex) - if err != nil { - return "", err - } - plaintext, err := AesDecrypt(keyHash[:], ciphertext) - if err != nil { - return "", err - } - return string(plaintext), nil -} diff --git a/vendor/gitea.com/go-chi/session/session.go b/vendor/gitea.com/go-chi/session/session.go deleted file mode 100644 index 97eb5ad3651cb..0000000000000 --- a/vendor/gitea.com/go-chi/session/session.go +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session a middleware that provides the session management of Macaron. -package session - -import ( - "context" - "encoding/hex" - "errors" - "fmt" - "net/http" - "net/url" - "time" -) - -const version = "0.7.0" - -// Version returns the version -func Version() string { - return version -} - -// RawStore is the interface that operates the session data. -type RawStore interface { - // Set sets value to given key in session. - Set(interface{}, interface{}) error - // Get gets value by given key in session. - Get(interface{}) interface{} - // Delete deletes a key from session. - Delete(interface{}) error - // ID returns current session ID. - ID() string - // Release releases session resource and save data to provider. - Release() error - // Flush deletes all session data. - Flush() error -} - -// Store is the interface that contains all data for one session process with specific ID. -type Store interface { - RawStore - // Read returns raw session store by session ID. - Read(string) (RawStore, error) - // Destroy deletes a session. - Destroy(http.ResponseWriter, *http.Request) error - // RegenerateID regenerates a session store from old session ID to new one. - RegenerateID(http.ResponseWriter, *http.Request) (RawStore, error) - // Count counts and returns number of sessions. - Count() int - // GC calls GC to clean expired sessions. - GC() -} - -type store struct { - RawStore - *Manager -} - -var _ Store = &store{} - -// Options represents a struct for specifying configuration options for the session middleware. -type Options struct { - // Name of provider. Default is "memory". - Provider string - // Provider configuration, it's corresponding to provider. - ProviderConfig string - // Cookie name to save session ID. Default is "MacaronSession". - CookieName string - // Cookie path to store. Default is "/". - CookiePath string - // GC interval time in seconds. Default is 3600. - Gclifetime int64 - // Max life time in seconds. Default is whatever GC interval time is. - Maxlifetime int64 - // Use HTTPS only. Default is false. - Secure bool - // Cookie life time. Default is 0. - CookieLifeTime int - // SameSite set the cookie SameSite - SameSite http.SameSite - // Cookie domain name. Default is empty. - Domain string - // Session ID length. Default is 16. - IDLength int - // Ignore release for websocket. Default is false. - IgnoreReleaseForWebSocket bool - // FlashEncryptionKey sets the encryption key for flash messages - FlashEncryptionKey string -} - -func prepareOptions(options []Options) Options { - var opt Options - if len(options) > 0 { - opt = options[0] - } - - if len(opt.Provider) == 0 { - opt.Provider = "memory" - } - if len(opt.ProviderConfig) == 0 { - opt.ProviderConfig = "data/sessions" - } - if len(opt.CookieName) == 0 { - opt.CookieName = "MacaronSession" - } - if len(opt.CookiePath) == 0 { - opt.CookiePath = "/" - } - if opt.Gclifetime == 0 { - opt.Gclifetime = 3600 - } - if opt.Maxlifetime == 0 { - opt.Maxlifetime = opt.Gclifetime - } - if !opt.Secure { - opt.Secure = false - } - if opt.IDLength == 0 { - opt.IDLength = 16 - } - if len(opt.FlashEncryptionKey) == 0 { - opt.FlashEncryptionKey = "" - } - if len(opt.FlashEncryptionKey) == 0 { - opt.FlashEncryptionKey, _ = NewSecret() - } - - return opt -} - -// GetCookie returns given cookie value from request header. -func GetCookie(req *http.Request, name string) string { - cookie, err := req.Cookie(name) - if err != nil { - return "" - } - val, _ := url.QueryUnescape(cookie.Value) - return val -} - -// NewCookie creates cookie via given params and value. -// FIXME: IE support? http://golanghome.com/post/620#reply2 -func NewCookie(name string, value string, others ...interface{}) *http.Cookie { - cookie := http.Cookie{} - cookie.Name = name - cookie.Value = url.QueryEscape(value) - - if len(others) > 0 { - switch v := others[0].(type) { - case int: - cookie.MaxAge = v - case int64: - cookie.MaxAge = int(v) - case int32: - cookie.MaxAge = int(v) - case func(*http.Cookie): - v(&cookie) - } - } - - cookie.Path = "/" - if len(others) > 1 { - if v, ok := others[1].(string); ok && len(v) > 0 { - cookie.Path = v - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 2 { - if v, ok := others[2].(string); ok && len(v) > 0 { - cookie.Domain = v - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 3 { - switch v := others[3].(type) { - case bool: - cookie.Secure = v - case func(*http.Cookie): - v(&cookie) - default: - if others[3] != nil { - cookie.Secure = true - } - } - } - - if len(others) > 4 { - if v, ok := others[4].(bool); ok && v { - cookie.HttpOnly = true - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 5 { - if v, ok := others[5].(time.Time); ok { - cookie.Expires = v - cookie.RawExpires = v.Format(time.UnixDate) - } else if v, ok := others[1].(func(*http.Cookie)); ok { - v(&cookie) - } - } - - if len(others) > 6 { - for _, other := range others[6:] { - if v, ok := other.(func(*http.Cookie)); ok { - v(&cookie) - } - } - } - return &cookie -} - -// Sessioner is a middleware that maps a session.SessionStore service into the Macaron handler chain. -// An single variadic session.Options struct can be optionally provided to configure. -func Sessioner(options ...Options) func(next http.Handler) http.Handler { - opt := prepareOptions(options) - manager, err := NewManager(opt.Provider, opt) - if err != nil { - panic(err) - } - go manager.startGC() - - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - sess, err := manager.Start(w, req) - if err != nil { - panic("session(start): " + err.Error()) - } - - var s = store{ - RawStore: sess, - Manager: manager, - } - - req = req.WithContext(context.WithValue(req.Context(), interface{}("Session"), &s)) - - next.ServeHTTP(w, req) - - if manager.opt.IgnoreReleaseForWebSocket && req.Header.Get("Upgrade") == "websocket" { - return - } - - if err = sess.Release(); err != nil { - panic("session(release): " + err.Error()) - } - }) - } -} - -// GetSession returns session store -func GetSession(req *http.Request) Store { - sessCtx := req.Context().Value("Session") - sess, _ := sessCtx.(*store) - return sess -} - -// Provider is the interface that provides session manipulations. -type Provider interface { - // Init initializes session provider. - Init(gclifetime int64, config string) error - // Read returns raw session store by session ID. - Read(sid string) (RawStore, error) - // Exist returns true if session with given ID exists. - Exist(sid string) bool - // Destroy deletes a session by session ID. - Destroy(sid string) error - // Regenerate regenerates a session store from old session ID to new one. - Regenerate(oldsid, sid string) (RawStore, error) - // Count counts and returns number of sessions. - Count() int - // GC calls GC to clean expired sessions. - GC() -} - -var providers = make(map[string]Provider) - -// Register registers a provider. -func Register(name string, provider Provider) { - if provider == nil { - panic("session: cannot register provider with nil value") - } - if _, dup := providers[name]; dup { - panic(fmt.Errorf("session: cannot register provider '%s' twice", name)) - } - providers[name] = provider -} - -// _____ -// / \ _____ ____ _____ ____ ___________ -// / \ / \\__ \ / \\__ \ / ___\_/ __ \_ __ \ -// / Y \/ __ \| | \/ __ \_/ /_/ > ___/| | \/ -// \____|__ (____ /___| (____ /\___ / \___ >__| -// \/ \/ \/ \//_____/ \/ - -// Manager represents a struct that contains session provider and its configuration. -type Manager struct { - provider Provider - opt Options -} - -// NewManager creates and returns a new session manager by given provider name and configuration. -// It panics when given provider isn't registered. -func NewManager(name string, opt Options) (*Manager, error) { - p, ok := providers[name] - if !ok { - return nil, fmt.Errorf("session: unknown provider '%s'(forgotten import?)", name) - } - return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig) -} - -// sessionID generates a new session ID with rand string, unix nano time, remote addr by hash function. -func (m *Manager) sessionID() string { - return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2)) -} - -// validSessionID tests whether a provided session ID is a valid session ID. -func (m *Manager) validSessionID(sid string) (bool, error) { - if len(sid) != m.opt.IDLength { - return false, fmt.Errorf("invalid 'sid': %s %d != %d", sid, len(sid), m.opt.IDLength) - } - - for i := range sid { - switch { - case '0' <= sid[i] && sid[i] <= '9': - case 'a' <= sid[i] && sid[i] <= 'f': - default: - return false, errors.New("invalid 'sid': " + sid) - } - } - return true, nil -} - -// Start starts a session by generating new one -// or retrieve existence one by reading session ID from HTTP request if it's valid. -func (m *Manager) Start(resp http.ResponseWriter, req *http.Request) (RawStore, error) { - sid := GetCookie(req, m.opt.CookieName) - valid, _ := m.validSessionID(sid) - if len(sid) > 0 && valid && m.provider.Exist(sid) { - return m.provider.Read(sid) - } - - sid = m.sessionID() - sess, err := m.provider.Read(sid) - if err != nil { - return nil, err - } - - cookie := &http.Cookie{ - Name: m.opt.CookieName, - Value: sid, - Path: m.opt.CookiePath, - HttpOnly: true, - Secure: m.opt.Secure, - Domain: m.opt.Domain, - SameSite: m.opt.SameSite, - } - if m.opt.CookieLifeTime >= 0 { - cookie.MaxAge = m.opt.CookieLifeTime - } - http.SetCookie(resp, cookie) - req.AddCookie(cookie) - return sess, nil -} - -// Read returns raw session store by session ID. -func (m *Manager) Read(sid string) (RawStore, error) { - // Ensure we're trying to read a valid session ID - if _, err := m.validSessionID(sid); err != nil { - return nil, err - } - - return m.provider.Read(sid) -} - -// Destroy deletes a session by given ID. -func (m *Manager) Destroy(resp http.ResponseWriter, req *http.Request) error { - sid := GetCookie(req, m.opt.CookieName) - if len(sid) == 0 { - return nil - } - - if _, err := m.validSessionID(sid); err != nil { - return err - } - - if err := m.provider.Destroy(sid); err != nil { - return err - } - cookie := &http.Cookie{ - Name: m.opt.CookieName, - Path: m.opt.CookiePath, - HttpOnly: true, - Expires: time.Now(), - MaxAge: -1, - } - http.SetCookie(resp, cookie) - return nil -} - -// RegenerateID regenerates a session store from old session ID to new one. -func (m *Manager) RegenerateID(resp http.ResponseWriter, req *http.Request) (sess RawStore, err error) { - sid := m.sessionID() - oldsid := GetCookie(req, m.opt.CookieName) - _, err = m.validSessionID(oldsid) - if err != nil { - return nil, err - } - sess, err = m.provider.Regenerate(oldsid, sid) - if err != nil { - return nil, err - } - cookie := &http.Cookie{ - Name: m.opt.CookieName, - Value: sid, - Path: m.opt.CookiePath, - HttpOnly: true, - Secure: m.opt.Secure, - Domain: m.opt.Domain, - SameSite: m.opt.SameSite, - } - if m.opt.CookieLifeTime >= 0 { - cookie.MaxAge = m.opt.CookieLifeTime - } - http.SetCookie(resp, cookie) - req.AddCookie(cookie) - return sess, nil -} - -// Count counts and returns number of sessions. -func (m *Manager) Count() int { - return m.provider.Count() -} - -// GC starts GC job in a certain period. -func (m *Manager) GC() { - m.provider.GC() -} - -// startGC starts GC job in a certain period. -func (m *Manager) startGC() { - m.GC() - time.AfterFunc(time.Duration(m.opt.Gclifetime)*time.Second, func() { m.startGC() }) -} - -// SetSecure indicates whether to set cookie with HTTPS or not. -func (m *Manager) SetSecure(secure bool) { - m.opt.Secure = secure -} diff --git a/vendor/gitea.com/go-chi/session/utils.go b/vendor/gitea.com/go-chi/session/utils.go deleted file mode 100644 index 001bae6d9820d..0000000000000 --- a/vendor/gitea.com/go-chi/session/utils.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013 Beego Authors -// Copyright 2014 The Macaron 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 session - -import ( - "bytes" - "crypto/rand" - "encoding/gob" - "io" - - "github.com/unknwon/com" -) - -func init() { - gob.Register([]interface{}{}) - gob.Register(map[int]interface{}{}) - gob.Register(map[string]interface{}{}) - gob.Register(map[interface{}]interface{}{}) - gob.Register(map[string]string{}) - gob.Register(map[int]string{}) - gob.Register(map[int]int{}) - gob.Register(map[int]int64{}) -} - -// EncodeGob encodes obj with gob -func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) { - for _, v := range obj { - gob.Register(v) - } - buf := bytes.NewBuffer(nil) - err := gob.NewEncoder(buf).Encode(obj) - return buf.Bytes(), err -} - -// DecodeGob decodes bytes to obj -func DecodeGob(encoded []byte) (out map[interface{}]interface{}, err error) { - buf := bytes.NewBuffer(encoded) - err = gob.NewDecoder(buf).Decode(&out) - return out, err -} - -// NOTE: A local copy in case of underlying package change -var alphanum = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") - -// generateRandomKey creates a random key with the given strength. -func generateRandomKey(strength int) []byte { - k := make([]byte, strength) - if n, err := io.ReadFull(rand.Reader, k); n != strength || err != nil { - return com.RandomCreateBytes(strength, alphanum...) - } - return k -} diff --git a/vendor/github.com/couchbase/gomemcached/.gitignore b/vendor/github.com/couchbase/gomemcached/.gitignore index cd8acba17eaf8..f75d85a8413b2 100644 --- a/vendor/github.com/couchbase/gomemcached/.gitignore +++ b/vendor/github.com/couchbase/gomemcached/.gitignore @@ -4,4 +4,3 @@ *.swp /gocache/gocache c.out -.idea \ No newline at end of file diff --git a/vendor/github.com/couchbase/gomemcached/client/collections_filter.go b/vendor/github.com/couchbase/gomemcached/client/collections_filter.go index a34d353fec8d8..4da8b8f4260a7 100644 --- a/vendor/github.com/couchbase/gomemcached/client/collections_filter.go +++ b/vendor/github.com/couchbase/gomemcached/client/collections_filter.go @@ -17,7 +17,11 @@ type CollectionsFilter struct { ScopeId uint32 } -type nonStreamIdNonCollectionsMeta struct { +type nonStreamIdNonResumeScopeMeta struct { + ScopeId string `json:"scope"` +} + +type nonStreamIdResumeScopeMeta struct { ManifestId string `json:"uid"` } @@ -25,7 +29,7 @@ type nonStreamIdNonResumeCollectionsMeta struct { CollectionsList []string `json:"collections"` } -type nonStreamIdCollectionsMeta struct { +type nonStreamIdResumeCollectionsMeta struct { ManifestId string `json:"uid"` CollectionsList []string `json:"collections"` } @@ -95,19 +99,10 @@ func (c *CollectionsFilter) ToStreamReqBody() ([]byte, error) { case false: switch c.UseManifestUid { case true: - switch len(c.CollectionsList) > 0 { - case true: - filter := &nonStreamIdCollectionsMeta{ - ManifestId: fmt.Sprintf("%x", c.ManifestUid), - CollectionsList: c.outputCollectionsFilterColList(), - } - output = *filter - case false: - filter := &nonStreamIdNonCollectionsMeta{ - ManifestId: fmt.Sprintf("%x", c.ManifestUid), - } - output = *filter + filter := &nonStreamIdResumeScopeMeta{ + ManifestId: fmt.Sprintf("%x", c.ManifestUid), } + output = *filter case false: switch len(c.CollectionsList) > 0 { case true: @@ -116,7 +111,7 @@ func (c *CollectionsFilter) ToStreamReqBody() ([]byte, error) { } output = *filter case false: - return nil, fmt.Errorf("Specifying scopeID must require the use of streamId") + output = nonStreamIdNonResumeScopeMeta{ScopeId: c.outputScopeId()} } } } diff --git a/vendor/github.com/couchbase/gomemcached/client/mc.go b/vendor/github.com/couchbase/gomemcached/client/mc.go index 208bacdd98790..16dd2f8f7c6dc 100644 --- a/vendor/github.com/couchbase/gomemcached/client/mc.go +++ b/vendor/github.com/couchbase/gomemcached/client/mc.go @@ -375,25 +375,6 @@ func (c *Client) setCollection(req *gomemcached.MCRequest, context ...*ClientCon return nil } -// Sets collection info in extras -func (c *Client) setExtrasCollection(req *gomemcached.MCRequest, context ...*ClientContext) error { - collectionId := uint32(0) - if len(context) > 0 { - collectionId = context[0].CollId - } - - // if the optional collection is specified, it must be default for clients that haven't turned on collections - if atomic.LoadUint32(&c.collectionsEnabled) == 0 { - if collectionId != 0 { - return fmt.Errorf("Client does not use collections but a collection was specified") - } - } else { - req.Extras = make([]byte, 4) - binary.BigEndian.PutUint32(req.Extras, collectionId) - } - return nil -} - func (c *Client) setVbSeqnoContext(req *gomemcached.MCRequest, context ...*ClientContext) error { if len(context) == 0 || req == nil { return nil @@ -535,14 +516,9 @@ func (c *Client) Del(vb uint16, key string, context ...*ClientContext) (*gomemca // Get a random document func (c *Client) GetRandomDoc(context ...*ClientContext) (*gomemcached.MCResponse, error) { - req := &gomemcached.MCRequest{ + return c.Send(&gomemcached.MCRequest{ Opcode: 0xB6, - } - err := c.setExtrasCollection(req, context...) - if err != nil { - return nil, err - } - return c.Send(req) + }) } // AuthList lists SASL auth mechanisms. diff --git a/vendor/github.com/couchbase/gomemcached/client/upr_event.go b/vendor/github.com/couchbase/gomemcached/client/upr_event.go index 2d3454aecc128..7ede0a128dc98 100644 --- a/vendor/github.com/couchbase/gomemcached/client/upr_event.go +++ b/vendor/github.com/couchbase/gomemcached/client/upr_event.go @@ -83,8 +83,7 @@ type UprEvent struct { SystemEvent SystemEventType // Only valid if IsSystemEvent() is true SysEventVersion uint8 // Based on the version, the way Extra bytes is parsed is different ValueLen int // Cache it to avoid len() calls for performance - CollectionId uint32 // Valid if Collection is in use - StreamId *uint16 // Nil if not in use + CollectionId uint64 // Valid if Collection is in use } // FailoverLog containing vvuid and sequnce number @@ -104,7 +103,7 @@ func makeUprEvent(rq gomemcached.MCRequest, stream *UprStream, bytesReceivedFrom DataType: rq.DataType, ValueLen: len(rq.Body), SystemEvent: InvalidSysEvent, - CollectionId: math.MaxUint32, + CollectionId: math.MaxUint64, } event.PopulateFieldsBasedOnStreamType(rq, stream.StreamType) @@ -154,8 +153,6 @@ func makeUprEvent(rq gomemcached.MCRequest, stream *UprStream, bytesReceivedFrom event.PopulateEvent(rq.Extras) } else if event.IsSeqnoAdv() { event.PopulateSeqnoAdv(rq.Extras) - } else if event.IsOsoSnapshot() { - event.PopulateOso(rq.Extras) } return event @@ -163,15 +160,6 @@ func makeUprEvent(rq gomemcached.MCRequest, stream *UprStream, bytesReceivedFrom func (event *UprEvent) PopulateFieldsBasedOnStreamType(rq gomemcached.MCRequest, streamType DcpStreamType) { switch streamType { - case CollectionsStreamId: - for _, extra := range rq.FramingExtras { - streamId, streamIdErr := extra.GetStreamId() - if streamIdErr == nil { - event.StreamId = &streamId - } - } - // After parsing streamID, still need to populate regular collectionID - fallthrough case CollectionsNonStreamId: switch rq.Opcode { // Only these will have CID encoded within the key @@ -179,12 +167,15 @@ func (event *UprEvent) PopulateFieldsBasedOnStreamType(rq gomemcached.MCRequest, gomemcached.UPR_DELETION, gomemcached.UPR_EXPIRATION: uleb128 := Uleb128(rq.Key) - result, bytesShifted := uleb128.ToUint32(rq.Keylen) + result, bytesShifted := uleb128.ToUint64(rq.Keylen) event.CollectionId = result event.Key = rq.Key[bytesShifted:] default: event.Key = rq.Key } + case CollectionsStreamId: + // TODO - not implemented + fallthrough case NonCollectionStream: // Let default behavior be legacy stream type fallthrough @@ -217,10 +208,6 @@ func (event *UprEvent) IsSeqnoAdv() bool { return event.Opcode == gomemcached.DCP_SEQNO_ADV } -func (event *UprEvent) IsOsoSnapshot() bool { - return event.Opcode == gomemcached.DCP_OSO_SNAPSHOT -} - func (event *UprEvent) PopulateEvent(extras []byte) { if len(extras) < dcpSystemEventExtraLen { // Wrong length, don't parse @@ -242,14 +229,6 @@ func (event *UprEvent) PopulateSeqnoAdv(extras []byte) { event.Seqno = binary.BigEndian.Uint64(extras[:8]) } -func (event *UprEvent) PopulateOso(extras []byte) { - if len(extras) < dcpOsoExtraLen { - // Wrong length, don't parse - return - } - event.Flags = binary.BigEndian.Uint32(extras[:4]) -} - func (event *UprEvent) GetSystemEventName() (string, error) { switch event.SystemEvent { case CollectionCreate: @@ -366,32 +345,15 @@ func (event *UprEvent) GetMaxTTL() (uint32, error) { } } -// Only if error is nil: -// Returns true if event states oso begins -// Return false if event states oso ends -func (event *UprEvent) GetOsoBegin() (bool, error) { - if !event.IsOsoSnapshot() { - return false, ErrorInvalidOp - } - - if event.Flags == 1 { - return true, nil - } else if event.Flags == 2 { - return false, nil - } else { - return false, ErrorInvalidOp - } -} - type Uleb128 []byte -func (u Uleb128) ToUint32(cachedLen int) (result uint32, bytesShifted int) { +func (u Uleb128) ToUint64(cachedLen int) (result uint64, bytesShifted int) { var shift uint = 0 for curByte := 0; curByte < cachedLen; curByte++ { oneByte := u[curByte] last7Bits := 0x7f & oneByte - result |= uint32(last7Bits) << shift + result |= uint64(last7Bits) << shift bytesShifted++ if oneByte&0x80 == 0 { break diff --git a/vendor/github.com/couchbase/gomemcached/client/upr_feed.go b/vendor/github.com/couchbase/gomemcached/client/upr_feed.go index cdbed16bd37c6..be676aa71cde1 100644 --- a/vendor/github.com/couchbase/gomemcached/client/upr_feed.go +++ b/vendor/github.com/couchbase/gomemcached/client/upr_feed.go @@ -26,7 +26,6 @@ const opaqueOpen = 0xBEAF0001 const opaqueFailover = 0xDEADBEEF const opaqueGetSeqno = 0xDEADBEEF const uprDefaultNoopInterval = 120 -const dcpOsoExtraLen = 4 // Counter on top of opaqueOpen that others can draw from for open and control msgs var opaqueOpenCtrlWell uint32 = opaqueOpen @@ -118,7 +117,6 @@ type UprFeatures struct { DcpPriority PriorityType EnableExpiry bool EnableStreamId bool - EnableOso bool } /** @@ -603,20 +601,6 @@ func (feed *UprFeed) uprOpen(name string, sequence uint32, bufSize uint32, featu activatedFeatures.EnableStreamId = true } - if features.EnableOso { - rq := &gomemcached.MCRequest{ - Opcode: gomemcached.UPR_CONTROL, - Key: []byte("enable_out_of_order_snapshots"), - Body: []byte("true"), - Opaque: getUprOpenCtrlOpaque(), - } - err = sendMcRequestSync(feed.conn, rq) - if err != nil { - return - } - activatedFeatures.EnableOso = true - } - // everything is ok so far, set upr feed to open state feed.activatedFeatures = activatedFeatures feed.setOpen() @@ -992,12 +976,6 @@ loop: break loop } event = makeUprEvent(pkt, stream, bytes) - case gomemcached.DCP_OSO_SNAPSHOT: - if stream == nil { - logging.Infof("Stream not found for vb %d: %#v", vb, pkt) - break loop - } - event = makeUprEvent(pkt, stream, bytes) default: logging.Infof("Recived an unknown response for vbucket %d", vb) } diff --git a/vendor/github.com/couchbase/gomemcached/go.mod b/vendor/github.com/couchbase/gomemcached/go.mod deleted file mode 100644 index 3355d4ea75c26..0000000000000 --- a/vendor/github.com/couchbase/gomemcached/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/couchbase/gomemcached - -go 1.13 diff --git a/vendor/github.com/couchbase/gomemcached/mc_constants.go b/vendor/github.com/couchbase/gomemcached/mc_constants.go index 19741f5a0d9bc..1dfe2febf2650 100644 --- a/vendor/github.com/couchbase/gomemcached/mc_constants.go +++ b/vendor/github.com/couchbase/gomemcached/mc_constants.go @@ -104,7 +104,6 @@ const ( DCP_SYSTEM_EVENT = CommandCode(0x5f) // A system event has occurred DCP_SEQNO_ADV = CommandCode(0x64) // Sent when the vb seqno has advanced due to an unsubscribed event - DCP_OSO_SNAPSHOT = CommandCode(0x65) // Marks the begin and end of out-of-sequence-number stream ) // command codes that are counted toward DCP control buffer @@ -118,7 +117,6 @@ var BufferedCommandCodeMap = map[CommandCode]bool{ UPR_EXPIRATION: true, DCP_SYSTEM_EVENT: true, DCP_SEQNO_ADV: true, - DCP_OSO_SNAPSHOT: true, } // Status field for memcached response. @@ -158,9 +156,6 @@ const ( SUBDOC_PATH_NOT_FOUND = Status(0xc0) SUBDOC_BAD_MULTI = Status(0xcc) SUBDOC_MULTI_PATH_FAILURE_DELETED = Status(0xd3) - - // Not a Memcached status - UNKNOWN_STATUS = Status(0xffff) ) // for log redaction @@ -179,10 +174,6 @@ var isFatal = map[Status]bool{ EACCESS: true, ENOMEM: true, NOT_SUPPORTED: true, - - // consider statuses coming from outside couchbase (eg OS errors) as fatal for the connection - // as there might be unread data left over on the wire - UNKNOWN_STATUS: true, } // the producer/consumer bit in dcp flags diff --git a/vendor/github.com/couchbase/gomemcached/mc_res.go b/vendor/github.com/couchbase/gomemcached/mc_res.go index 1e89020de2b24..f6be989847e70 100644 --- a/vendor/github.com/couchbase/gomemcached/mc_res.go +++ b/vendor/github.com/couchbase/gomemcached/mc_res.go @@ -38,7 +38,7 @@ func (res *MCResponse) Error() string { } func errStatus(e error) Status { - status := UNKNOWN_STATUS + status := Status(0xffff) if res, ok := e.(*MCResponse); ok { status = res.Status } diff --git a/vendor/github.com/go-chi/chi/.travis.yml b/vendor/github.com/go-chi/chi/.travis.yml new file mode 100644 index 0000000000000..7b8e26bceecbc --- /dev/null +++ b/vendor/github.com/go-chi/chi/.travis.yml @@ -0,0 +1,20 @@ +language: go + +go: + - 1.10.x + - 1.11.x + - 1.12.x + - 1.13.x + - 1.14.x + +script: + - go get -d -t ./... + - go vet ./... + - go test ./... + - > + go_version=$(go version); + if [ ${go_version:13:4} = "1.12" ]; then + go get -u golang.org/x/tools/cmd/goimports; + goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || :; + fi + diff --git a/vendor/github.com/go-chi/chi/CHANGELOG.md b/vendor/github.com/go-chi/chi/CHANGELOG.md index 2e337506a4ac0..9a64a72eec760 100644 --- a/vendor/github.com/go-chi/chi/CHANGELOG.md +++ b/vendor/github.com/go-chi/chi/CHANGELOG.md @@ -1,66 +1,5 @@ # Changelog -## v1.5.1 (2020-12-06) - -- Performance improvement: removing 1 allocation by foregoing context.WithValue, thank you @bouk for - your contribution (https://github.com/go-chi/chi/pull/555). Note: new benchmarks posted in README. -- `middleware.CleanPath`: new middleware that clean's request path of double slashes -- deprecate & remove `chi.ServerBaseContext` in favour of stdlib `http.Server#BaseContext` -- plus other tiny improvements, see full commit history below -- History of changes: see https://github.com/go-chi/chi/compare/v4.1.2...v1.5.1 - - -## v1.5.0 (2020-11-12) - now with go.mod support - -`chi` dates back to 2016 with it's original implementation as one of the first routers to adopt the newly introduced -context.Context api to the stdlib -- set out to design a router that is faster, more modular and simpler than anything -else out there -- while not introducing any custom handler types or dependencies. Today, `chi` still has zero dependencies, -and in many ways is future proofed from changes, given it's minimal nature. Between versions, chi's iterations have been very -incremental, with the architecture and api being the same today as it was originally designed in 2016. For this reason it -makes chi a pretty easy project to maintain, as well thanks to the many amazing community contributions over the years -to who all help make chi better (total of 86 contributors to date -- thanks all!). - -Chi has been an labour of love, art and engineering, with the goals to offer beautiful ergonomics, flexibility, performance -and simplicity when building HTTP services with Go. I've strived to keep the router very minimal in surface area / code size, -and always improving the code wherever possible -- and as of today the `chi` package is just 1082 lines of code (not counting -middlewares, which are all optional). As well, I don't have the exact metrics, but from my analysis and email exchanges from -companies and developers, chi is used by thousands of projects around the world -- thank you all as there is no better form of -joy for me than to have art I had started be helpful and enjoyed by others. And of course I use chi in all of my own projects too :) - -For me, the asthetics of chi's code and usage are very important. With the introduction of Go's module support -(which I'm a big fan of), chi's past versioning scheme choice to v2, v3 and v4 would mean I'd require the import path -of "github.com/go-chi/chi/v4", leading to the lengthy discussion at https://github.com/go-chi/chi/issues/462. -Haha, to some, you may be scratching your head why I've spent > 1 year stalling to adopt "/vXX" convention in the import -path -- which isn't horrible in general -- but for chi, I'm unable to accept it as I strive for perfection in it's API design, -aesthetics and simplicity. It just doesn't feel good to me given chi's simple nature -- I do not foresee a "v5" or "v6", -and upgrading between versions in the future will also be just incremental. - -I do understand versioning is a part of the API design as well, which is why the solution for a while has been to "do nothing", -as Go supports both old and new import paths with/out go.mod. However, now that Go module support has had time to iron out kinks and -is adopted everywhere, it's time for chi to get with the times. Luckily, I've discovered a path forward that will make me happy, -while also not breaking anyone's app who adopted a prior versioning from tags in v2/v3/v4. I've made an experimental release of -v1.5.0 with go.mod silently, and tested it with new and old projects, to ensure the developer experience is preserved, and it's -largely unnoticed. Fortunately, Go's toolchain will check the tags of a repo and consider the "latest" tag the one with go.mod. -However, you can still request a specific older tag such as v4.1.2, and everything will "just work". But new users can just -`go get github.com/go-chi/chi` or `go get github.com/go-chi/chi@latest` and they will get the latest version which contains -go.mod support, which is v1.5.0+. `chi` will not change very much over the years, just like it hasn't changed much from 4 years ago. -Therefore, we will stay on v1.x from here on, starting from v1.5.0. Any breaking changes will bump a "minor" release and -backwards-compatible improvements/fixes will bump a "tiny" release. - -For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`, -which will get you on the go.mod version line (as Go's mod cache may still remember v4.x). Brand new systems can run -`go get -u github.com/go-chi/chi` or `go get -u github.com/go-chi/chi@latest` to install chi, which will install v1.5.0+ -built with go.mod support. - -My apologies to the developers who will disagree with the decisions above, but, hope you'll try it and see it's a very -minor request which is backwards compatible and won't break your existing installations. - -Cheers all, happy coding! - - ---- - - ## v4.1.2 (2020-06-02) - fix that handles MethodNotAllowed with path variables, thank you @caseyhadden for your contribution @@ -84,6 +23,7 @@ Cheers all, happy coding! - middleware.Recoverer: a bit prettier - History of changes: see https://github.com/go-chi/chi/compare/v4.0.4...v4.1.0 + ## v4.0.4 (2020-03-24) - middleware.Recoverer: new pretty stack trace printing (https://github.com/go-chi/chi/pull/496) diff --git a/vendor/github.com/go-chi/chi/README.md b/vendor/github.com/go-chi/chi/README.md index 1b96d360d72ec..3d53a61476b8d 100644 --- a/vendor/github.com/go-chi/chi/README.md +++ b/vendor/github.com/go-chi/chi/README.md @@ -15,8 +15,7 @@ public API service, which in turn powers all of our client-side applications. The key considerations of chi's design are: project structure, maintainability, standard http handlers (stdlib-only), developer productivity, and deconstructing a large system into many small parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also -included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) -and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too! +included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too! ## Install @@ -28,11 +27,10 @@ and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too! * **Lightweight** - cloc'd in ~1000 LOC for the chi router * **Fast** - yes, see [benchmarks](#benchmarks) * **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http` -* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and sub-router mounting +* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and subrouter mounting * **Context control** - built on new `context` package, providing value chaining, cancellations and timeouts * **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91)) * **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown -* **Go.mod support** - v1.x of chi (starting from v1.5.0), now has go.mod support (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support)) * **No external dependencies** - plain ol' Go stdlib + net/http @@ -336,12 +334,9 @@ with `net/http` can be used with chi's mux. ---------------------------------------------------------------------------------------------------- | chi/middleware Handler | description | | :--------------------- | :---------------------------------------------------------------------- | -| [AllowContentEncoding] | Enforces a whitelist of request Content-Encoding headers | | [AllowContentType] | Explicit whitelist of accepted request Content-Types | | [BasicAuth] | Basic HTTP authentication | | [Compress] | Gzip compression for clients that accept compressed responses | -| [ContentCharset] | Ensure charset for Content-Type request headers | -| [CleanPath] | Clean double slashes from request path | | [GetHead] | Automatically route undefined HEAD requests to GET handlers | | [Heartbeat] | Monitoring endpoint to check the servers pulse | | [Logger] | Logs the start and end of each request with the elapsed processing time | @@ -351,7 +346,6 @@ with `net/http` can be used with chi's mux. | [Recoverer] | Gracefully absorb panics and prints the stack trace | | [RequestID] | Injects a request ID into the context of each request | | [RedirectSlashes] | Redirect slashes on routing paths | -| [RouteHeaders] | Route handling for request headers | | [SetHeader] | Short-hand middleware to set a response header key/value | | [StripSlashes] | Strip slashes on routing paths | | [Throttle] | Puts a ceiling on the number of concurrent requests | @@ -365,19 +359,20 @@ with `net/http` can be used with chi's mux. [BasicAuth]: https://pkg.go.dev/github.com/go-chi/chi/middleware#BasicAuth [Compress]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compress [ContentCharset]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ContentCharset -[CleanPath]: https://pkg.go.dev/github.com/go-chi/chi/middleware#CleanPath [GetHead]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetHead [GetReqID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetReqID [Heartbeat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Heartbeat [Logger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Logger +[New]: https://pkg.go.dev/github.com/go-chi/chi/middleware#New +[NextRequestID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#NextRequestID [NoCache]: https://pkg.go.dev/github.com/go-chi/chi/middleware#NoCache +[PrintPrettyStack]: https://pkg.go.dev/github.com/go-chi/chi/middleware#PrintPrettyStack [Profiler]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Profiler [RealIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RealIP [Recoverer]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Recoverer [RedirectSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RedirectSlashes -[RequestLogger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestLogger [RequestID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestID -[RouteHeaders]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RouteHeaders +[RequestLogger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestLogger [SetHeader]: https://pkg.go.dev/github.com/go-chi/chi/middleware#SetHeader [StripSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#StripSlashes [Throttle]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Throttle @@ -395,6 +390,7 @@ with `net/http` can be used with chi's mux. [LogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogEntry [LogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogFormatter [LoggerInterface]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LoggerInterface +[Pattern]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Pattern [ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleOpts [WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WrapResponseWriter @@ -434,25 +430,25 @@ and.. The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark -Results as of Nov 29, 2020 with Go 1.15.5 on Linux AMD 3950x +Results as of Jan 9, 2019 with Go 1.11.4 on Linux X1 Carbon laptop ```shell -BenchmarkChi_Param 3075895 384 ns/op 400 B/op 2 allocs/op -BenchmarkChi_Param5 2116603 566 ns/op 400 B/op 2 allocs/op -BenchmarkChi_Param20 964117 1227 ns/op 400 B/op 2 allocs/op -BenchmarkChi_ParamWrite 2863413 420 ns/op 400 B/op 2 allocs/op -BenchmarkChi_GithubStatic 3045488 395 ns/op 400 B/op 2 allocs/op -BenchmarkChi_GithubParam 2204115 540 ns/op 400 B/op 2 allocs/op -BenchmarkChi_GithubAll 10000 113811 ns/op 81203 B/op 406 allocs/op -BenchmarkChi_GPlusStatic 3337485 359 ns/op 400 B/op 2 allocs/op -BenchmarkChi_GPlusParam 2825853 423 ns/op 400 B/op 2 allocs/op -BenchmarkChi_GPlus2Params 2471697 483 ns/op 400 B/op 2 allocs/op -BenchmarkChi_GPlusAll 194220 5950 ns/op 5200 B/op 26 allocs/op -BenchmarkChi_ParseStatic 3365324 356 ns/op 400 B/op 2 allocs/op -BenchmarkChi_ParseParam 2976614 404 ns/op 400 B/op 2 allocs/op -BenchmarkChi_Parse2Params 2638084 439 ns/op 400 B/op 2 allocs/op -BenchmarkChi_ParseAll 109567 11295 ns/op 10400 B/op 52 allocs/op -BenchmarkChi_StaticAll 16846 71308 ns/op 62802 B/op 314 allocs/op +BenchmarkChi_Param 3000000 475 ns/op 432 B/op 3 allocs/op +BenchmarkChi_Param5 2000000 696 ns/op 432 B/op 3 allocs/op +BenchmarkChi_Param20 1000000 1275 ns/op 432 B/op 3 allocs/op +BenchmarkChi_ParamWrite 3000000 505 ns/op 432 B/op 3 allocs/op +BenchmarkChi_GithubStatic 3000000 508 ns/op 432 B/op 3 allocs/op +BenchmarkChi_GithubParam 2000000 669 ns/op 432 B/op 3 allocs/op +BenchmarkChi_GithubAll 10000 134627 ns/op 87699 B/op 609 allocs/op +BenchmarkChi_GPlusStatic 3000000 402 ns/op 432 B/op 3 allocs/op +BenchmarkChi_GPlusParam 3000000 500 ns/op 432 B/op 3 allocs/op +BenchmarkChi_GPlus2Params 3000000 586 ns/op 432 B/op 3 allocs/op +BenchmarkChi_GPlusAll 200000 7237 ns/op 5616 B/op 39 allocs/op +BenchmarkChi_ParseStatic 3000000 408 ns/op 432 B/op 3 allocs/op +BenchmarkChi_ParseParam 3000000 488 ns/op 432 B/op 3 allocs/op +BenchmarkChi_Parse2Params 3000000 551 ns/op 432 B/op 3 allocs/op +BenchmarkChi_ParseAll 100000 13508 ns/op 11232 B/op 78 allocs/op +BenchmarkChi_StaticAll 20000 81933 ns/op 67826 B/op 471 allocs/op ``` Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc @@ -463,17 +459,6 @@ on the duplicated (alloc'd) request and returns it the new request object. This how setting context on a request in Go works. -## Go module support & note on chi's versioning - -* Go.mod support means we reset our versioning starting from v1.5 (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support)) -* All older tags are preserved, are backwards-compatible and will "just work" as they -* Brand new systems can run `go get -u github.com/go-chi/chi` as normal, or `go get -u github.com/go-chi/chi@latest` -to install chi, which will install v1.x+ built with go.mod support, starting from v1.5.0. -* For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`, -which will get you on the go.mod version line (as Go's mod cache may still remember v4.x). -* Any breaking changes will bump a "minor" release and backwards-compatible improvements/fixes will bump a "tiny" release. - - ## Credits * Carl Jackson for https://github.com/zenazn/goji diff --git a/vendor/github.com/go-chi/chi/context.go b/vendor/github.com/go-chi/chi/context.go index 7dec3f0c01e7e..26c609ea2c741 100644 --- a/vendor/github.com/go-chi/chi/context.go +++ b/vendor/github.com/go-chi/chi/context.go @@ -2,9 +2,9 @@ package chi import ( "context" + "net" "net/http" "strings" - "time" ) // URLParam returns the url parameter from a http.Request object. @@ -30,6 +30,26 @@ func RouteContext(ctx context.Context) *Context { return val } +// ServerBaseContext wraps an http.Handler to set the request context to the +// `baseCtx`. +func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler { + fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + baseCtx := baseCtx + + // Copy over default net/http server context keys + if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok { + baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v) + } + if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok { + baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v) + } + + h.ServeHTTP(w, r.WithContext(baseCtx)) + }) + return fn +} + // NewRouteContext returns a new routing Context object. func NewRouteContext() *Context { return &Context{} @@ -72,11 +92,6 @@ type Context struct { // methodNotAllowed hint methodNotAllowed bool - - // parentCtx is the parent of this one, for using Context as a - // context.Context directly. This is an optimization that saves - // 1 allocation. - parentCtx context.Context } // Reset a routing context to its initial state. @@ -92,7 +107,6 @@ func (x *Context) Reset() { x.routeParams.Keys = x.routeParams.Keys[:0] x.routeParams.Values = x.routeParams.Values[:0] x.methodNotAllowed = false - x.parentCtx = nil } // URLParam returns the corresponding URL parameter value from the request @@ -146,32 +160,6 @@ func (s *RouteParams) Add(key, value string) { s.Values = append(s.Values, value) } -// directContext provides direct access to the routing *Context object, -// while implementing the context.Context interface, thereby allowing -// us to saving 1 allocation during routing. -type directContext Context - -var _ context.Context = (*directContext)(nil) - -func (d *directContext) Deadline() (deadline time.Time, ok bool) { - return d.parentCtx.Deadline() -} - -func (d *directContext) Done() <-chan struct{} { - return d.parentCtx.Done() -} - -func (d *directContext) Err() error { - return d.parentCtx.Err() -} - -func (d *directContext) Value(key interface{}) interface{} { - if key == RouteCtxKey { - return (*Context)(d) - } - return d.parentCtx.Value(key) -} - // contextKey is a value for use with context.WithValue. It's used as // a pointer so it fits in an interface{} without allocation. This technique // for defining context keys was copied from Go 1.7's new use of context in net/http. diff --git a/vendor/github.com/go-chi/chi/middleware/basic_auth.go b/vendor/github.com/go-chi/chi/middleware/basic_auth.go index a546c9e9e8b60..87b2641a6ac3a 100644 --- a/vendor/github.com/go-chi/chi/middleware/basic_auth.go +++ b/vendor/github.com/go-chi/chi/middleware/basic_auth.go @@ -1,7 +1,6 @@ package middleware import ( - "crypto/subtle" "fmt" "net/http" ) @@ -17,7 +16,7 @@ func BasicAuth(realm string, creds map[string]string) func(next http.Handler) ht } credPass, credUserOk := creds[user] - if !credUserOk || subtle.ConstantTimeCompare([]byte(pass), []byte(credPass)) != 1 { + if !credUserOk || pass != credPass { basicAuthFailed(w, realm) return } diff --git a/vendor/github.com/go-chi/chi/middleware/clean_path.go b/vendor/github.com/go-chi/chi/middleware/clean_path.go deleted file mode 100644 index d42bf284578ea..0000000000000 --- a/vendor/github.com/go-chi/chi/middleware/clean_path.go +++ /dev/null @@ -1,28 +0,0 @@ -package middleware - -import ( - "net/http" - "path" - - "github.com/go-chi/chi" -) - -// CleanPath middleware will clean out double slash mistakes from a user's request path. -// For example, if a user requests /users//1 or //users////1 will both be treated as: /users/1 -func CleanPath(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - rctx := chi.RouteContext(r.Context()) - - routePath := rctx.RoutePath - if routePath == "" { - if r.URL.RawPath != "" { - routePath = r.URL.RawPath - } else { - routePath = r.URL.Path - } - rctx.RoutePath = path.Clean(routePath) - } - - next.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/go-chi/chi/middleware/content_type.go b/vendor/github.com/go-chi/chi/middleware/content_type.go index 023978fac0efc..ee4957874f9f4 100644 --- a/vendor/github.com/go-chi/chi/middleware/content_type.go +++ b/vendor/github.com/go-chi/chi/middleware/content_type.go @@ -19,9 +19,9 @@ func SetHeader(key, value string) func(next http.Handler) http.Handler { // AllowContentType enforces a whitelist of request Content-Types otherwise responds // with a 415 Unsupported Media Type status. func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler { - allowedContentTypes := make(map[string]struct{}, len(contentTypes)) - for _, ctype := range contentTypes { - allowedContentTypes[strings.TrimSpace(strings.ToLower(ctype))] = struct{}{} + cT := []string{} + for _, t := range contentTypes { + cT = append(cT, strings.ToLower(t)) } return func(next http.Handler) http.Handler { @@ -37,9 +37,11 @@ func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handl s = s[0:i] } - if _, ok := allowedContentTypes[s]; ok { - next.ServeHTTP(w, r) - return + for _, t := range cT { + if t == s { + next.ServeHTTP(w, r) + return + } } w.WriteHeader(http.StatusUnsupportedMediaType) diff --git a/vendor/github.com/go-chi/chi/middleware/logger.go b/vendor/github.com/go-chi/chi/middleware/logger.go index 66edc3dda8942..158a6a39052b4 100644 --- a/vendor/github.com/go-chi/chi/middleware/logger.go +++ b/vendor/github.com/go-chi/chi/middleware/logger.go @@ -6,7 +6,6 @@ import ( "log" "net/http" "os" - "runtime" "time" ) @@ -17,7 +16,7 @@ var ( // DefaultLogger is called by the Logger middleware handler to log each request. // Its made a package-level variable so that it can be reconfigured for custom // logging configurations. - DefaultLogger func(next http.Handler) http.Handler + DefaultLogger = RequestLogger(&DefaultLogFormatter{Logger: log.New(os.Stdout, "", log.LstdFlags), NoColor: false}) ) // Logger is a middleware that logs the start and end of each request, along @@ -28,16 +27,6 @@ var ( // // Alternatively, look at https://github.com/goware/httplog for a more in-depth // http logger with structured logging support. -// -// IMPORTANT NOTE: Logger should go before any other middleware that may change -// the response, such as `middleware.Recoverer`. Example: -// -// ```go -// r := chi.NewRouter() -// r.Use(middleware.Logger) // <--<< Logger should come before Recoverer -// r.Use(middleware.Recoverer) -// r.Get("/", handler) -// ``` func Logger(next http.Handler) http.Handler { return DefaultLogger(next) } @@ -164,11 +153,3 @@ func (l *defaultLogEntry) Write(status, bytes int, header http.Header, elapsed t func (l *defaultLogEntry) Panic(v interface{}, stack []byte) { PrintPrettyStack(v) } - -func init() { - color := true - if runtime.GOOS == "windows" { - color = false - } - DefaultLogger = RequestLogger(&DefaultLogFormatter{Logger: log.New(os.Stdout, "", log.LstdFlags), NoColor: !color}) -} diff --git a/vendor/github.com/go-chi/chi/middleware/strip.go b/vendor/github.com/go-chi/chi/middleware/strip.go index 1082d713efeef..2b8b1842ab71a 100644 --- a/vendor/github.com/go-chi/chi/middleware/strip.go +++ b/vendor/github.com/go-chi/chi/middleware/strip.go @@ -14,18 +14,13 @@ func StripSlashes(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { var path string rctx := chi.RouteContext(r.Context()) - if rctx != nil && rctx.RoutePath != "" { + if rctx.RoutePath != "" { path = rctx.RoutePath } else { path = r.URL.Path } if len(path) > 1 && path[len(path)-1] == '/' { - newPath := path[:len(path)-1] - if rctx == nil { - r.URL.Path = newPath - } else { - rctx.RoutePath = newPath - } + rctx.RoutePath = path[:len(path)-1] } next.ServeHTTP(w, r) } @@ -41,7 +36,7 @@ func RedirectSlashes(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { var path string rctx := chi.RouteContext(r.Context()) - if rctx != nil && rctx.RoutePath != "" { + if rctx.RoutePath != "" { path = rctx.RoutePath } else { path = r.URL.Path @@ -52,8 +47,7 @@ func RedirectSlashes(next http.Handler) http.Handler { } else { path = path[:len(path)-1] } - redirectUrl := fmt.Sprintf("//%s%s", r.Host, path) - http.Redirect(w, r, redirectUrl, 301) + http.Redirect(w, r, path, 301) return } next.ServeHTTP(w, r) diff --git a/vendor/github.com/go-chi/chi/middleware/url_format.go b/vendor/github.com/go-chi/chi/middleware/url_format.go index d8f04b7cb962d..5749e4f32b3a1 100644 --- a/vendor/github.com/go-chi/chi/middleware/url_format.go +++ b/vendor/github.com/go-chi/chi/middleware/url_format.go @@ -53,7 +53,7 @@ func URLFormat(next http.Handler) http.Handler { if strings.Index(path, ".") > 0 { base := strings.LastIndex(path, "/") - idx := strings.LastIndex(path[base:], ".") + idx := strings.Index(path[base:], ".") if idx > 0 { idx += base diff --git a/vendor/github.com/go-chi/chi/mux.go b/vendor/github.com/go-chi/chi/mux.go index c6fdb8a0f3663..52950e97b5be9 100644 --- a/vendor/github.com/go-chi/chi/mux.go +++ b/vendor/github.com/go-chi/chi/mux.go @@ -1,6 +1,7 @@ package chi import ( + "context" "fmt" "net/http" "strings" @@ -77,10 +78,9 @@ func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { rctx = mx.pool.Get().(*Context) rctx.Reset() rctx.Routes = mx - rctx.parentCtx = r.Context() - // NOTE: r.WithContext() causes 2 allocations - r = r.WithContext((*directContext)(rctx)) + // NOTE: r.WithContext() causes 2 allocations and context.WithValue() causes 1 allocation + r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx)) // Serve the request and once its done, put the request context back in the sync pool mx.handler.ServeHTTP(w, r) @@ -227,7 +227,7 @@ func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router { // Similarly as in handle(), we must build the mux handler once additional // middleware registration isn't allowed for this stack, like now. if !mx.inline && mx.handler == nil { - mx.updateRouteHandler() + mx.buildRouteHandler() } // Copy middlewares from parent inline muxs @@ -261,11 +261,10 @@ func (mx *Mux) Group(fn func(r Router)) Router { // along the `pattern` as a subrouter. Effectively, this is a short-hand // call to Mount. See _examples/. func (mx *Mux) Route(pattern string, fn func(r Router)) Router { - if fn == nil { - panic(fmt.Sprintf("chi: attempting to Route() a nil subrouter on '%s'", pattern)) - } subRouter := NewRouter() - fn(subRouter) + if fn != nil { + fn(subRouter) + } mx.Mount(pattern, subRouter) return subRouter } @@ -278,10 +277,6 @@ func (mx *Mux) Route(pattern string, fn func(r Router)) Router { // routing at the `handler`, which in most cases is another chi.Router. As a result, // if you define two Mount() routes on the exact same pattern the mount will panic. func (mx *Mux) Mount(pattern string, handler http.Handler) { - if handler == nil { - panic(fmt.Sprintf("chi: attempting to Mount() a nil handler on '%s'", pattern)) - } - // Provide runtime safety for ensuring a pattern isn't mounted on an existing // routing pattern. if mx.tree.findPattern(pattern+"*") || mx.tree.findPattern(pattern+"/*") { @@ -299,16 +294,7 @@ func (mx *Mux) Mount(pattern string, handler http.Handler) { mountHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rctx := RouteContext(r.Context()) - - // shift the url path past the previous subrouter rctx.RoutePath = mx.nextRoutePath(rctx) - - // reset the wildcard URLParam which connects the subrouter - n := len(rctx.URLParams.Keys) - 1 - if n >= 0 && rctx.URLParams.Keys[n] == "*" && len(rctx.URLParams.Values) > n { - rctx.URLParams.Values[n] = "" - } - handler.ServeHTTP(w, r) }) @@ -381,6 +367,14 @@ func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc { return methodNotAllowedHandler } +// buildRouteHandler builds the single mux handler that is a chain of the middleware +// stack, as defined by calls to Use(), and the tree router (Mux) itself. After this +// point, no other middlewares can be registered on this Mux's stack. But you can still +// compose additional middlewares via Group()'s or using a chained middleware handler. +func (mx *Mux) buildRouteHandler() { + mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP)) +} + // handle registers a http.Handler in the routing tree for a particular http method // and routing pattern. func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node { @@ -390,7 +384,7 @@ func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *n // Build the computed routing handler for this routing pattern. if !mx.inline && mx.handler == nil { - mx.updateRouteHandler() + mx.buildRouteHandler() } // Build endpoint handler with inline middlewares for the route @@ -464,14 +458,6 @@ func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) { } } -// updateRouteHandler builds the single mux handler that is a chain of the middleware -// stack, as defined by calls to Use(), and the tree router (Mux) itself. After this -// point, no other middlewares can be registered on this Mux's stack. But you can still -// compose additional middlewares via Group()'s or using a chained middleware handler. -func (mx *Mux) updateRouteHandler() { - mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP)) -} - // methodNotAllowedHandler is a helper function to respond with a 405, // method not allowed. func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) { diff --git a/vendor/github.com/unrolled/render/.gitignore b/vendor/github.com/unrolled/render/.gitignore deleted file mode 100644 index 05f4eaf615f7d..0000000000000 --- a/vendor/github.com/unrolled/render/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test - - -*.pem -.DS_Store diff --git a/vendor/github.com/unrolled/render/.travis.yml b/vendor/github.com/unrolled/render/.travis.yml deleted file mode 100644 index 9ec8d547fe360..0000000000000 --- a/vendor/github.com/unrolled/render/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go - -go: - - 1.11.x - - 1.12.x - - tip - -env: - - GO111MODULE=on - -install: - - go mod download - -script: - - go test -v -race -tags=integration diff --git a/vendor/github.com/unrolled/render/LICENSE b/vendor/github.com/unrolled/render/LICENSE deleted file mode 100644 index 9c62063ec1527..0000000000000 --- a/vendor/github.com/unrolled/render/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Cory Jacobsen - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/unrolled/render/README.md b/vendor/github.com/unrolled/render/README.md deleted file mode 100644 index 5ffa2a7c1cdda..0000000000000 --- a/vendor/github.com/unrolled/render/README.md +++ /dev/null @@ -1,508 +0,0 @@ -# Render [![GoDoc](http://godoc.org/github.com/unrolled/render?status.svg)](http://godoc.org/github.com/unrolled/render) [![Build Status](https://travis-ci.org/unrolled/render.svg)](https://travis-ci.org/unrolled/render) - -Render is a package that provides functionality for easily rendering JSON, XML, text, binary data, and HTML templates. This package is based on the [Martini](https://github.com/go-martini/martini) [render](https://github.com/martini-contrib/render) work. - -## Block Deprecation Notice -Go 1.6 introduces a new [block](https://github.com/golang/go/blob/release-branch.go1.6/src/html/template/example_test.go#L128) action. This conflicts with Render's included `block` template function. To provide an easy migration path, a new function was created called `partial`. It is a duplicate of the old `block` function. It is advised that all users of the `block` function update their code to avoid any issues in the future. Previous to Go 1.6, Render's `block` functionality will continue to work but a message will be logged urging you to migrate to the new `partial` function. - -## Usage -Render can be used with pretty much any web framework providing you can access the `http.ResponseWriter` from your handler. The rendering functions simply wraps Go's existing functionality for marshaling and rendering data. - -- HTML: Uses the [html/template](http://golang.org/pkg/html/template/) package to render HTML templates. -- JSON: Uses the [encoding/json](http://golang.org/pkg/encoding/json/) package to marshal data into a JSON-encoded response. -- XML: Uses the [encoding/xml](http://golang.org/pkg/encoding/xml/) package to marshal data into an XML-encoded response. -- Binary data: Passes the incoming data straight through to the `http.ResponseWriter`. -- Text: Passes the incoming string straight through to the `http.ResponseWriter`. - -~~~ go -// main.go -package main - -import ( - "encoding/xml" - "net/http" - - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -type ExampleXml struct { - XMLName xml.Name `xml:"example"` - One string `xml:"one,attr"` - Two string `xml:"two,attr"` -} - -func main() { - r := render.New() - mux := http.NewServeMux() - - mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - w.Write([]byte("Welcome, visit sub pages now.")) - }) - - mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) { - r.Data(w, http.StatusOK, []byte("Some binary data here.")) - }) - - mux.HandleFunc("/text", func(w http.ResponseWriter, req *http.Request) { - r.Text(w, http.StatusOK, "Plain text here") - }) - - mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) { - r.JSON(w, http.StatusOK, map[string]string{"hello": "json"}) - }) - - mux.HandleFunc("/jsonp", func(w http.ResponseWriter, req *http.Request) { - r.JSONP(w, http.StatusOK, "callbackName", map[string]string{"hello": "jsonp"}) - }) - - mux.HandleFunc("/xml", func(w http.ResponseWriter, req *http.Request) { - r.XML(w, http.StatusOK, ExampleXml{One: "hello", Two: "xml"}) - }) - - mux.HandleFunc("/html", func(w http.ResponseWriter, req *http.Request) { - // Assumes you have a template in ./templates called "example.tmpl" - // $ mkdir -p templates && echo "

Hello {{.}}.

" > templates/example.tmpl - r.HTML(w, http.StatusOK, "example", "World") - }) - - http.ListenAndServe("127.0.0.1:3000", mux) -} -~~~ - -~~~ html - -

Hello {{.}}.

-~~~ - -### Available Options -Render comes with a variety of configuration options _(Note: these are not the default option values. See the defaults below.)_: - -~~~ go -// ... -r := render.New(render.Options{ - Directory: "templates", // Specify what path to load the templates from. - FileSystem: &LocalFileSystem{}, // Specify filesystem from where files are loaded. - Asset: func(name string) ([]byte, error) { // Load from an Asset function instead of file. - return []byte("template content"), nil - }, - AssetNames: func() []string { // Return a list of asset names for the Asset function - return []string{"filename.tmpl"} - }, - Layout: "layout", // Specify a layout template. Layouts can call {{ yield }} to render the current template or {{ partial "css" }} to render a partial from the current template. - Extensions: []string{".tmpl", ".html"}, // Specify extensions to load for templates. - Funcs: []template.FuncMap{AppHelpers}, // Specify helper function maps for templates to access. - Delims: render.Delims{"{[{", "}]}"}, // Sets delimiters to the specified strings. - Charset: "UTF-8", // Sets encoding for content-types. Default is "UTF-8". - DisableCharset: true, // Prevents the charset from being appended to the content type header. - IndentJSON: true, // Output human readable JSON. - IndentXML: true, // Output human readable XML. - PrefixJSON: []byte(")]}',\n"), // Prefixes JSON responses with the given bytes. - PrefixXML: []byte(""), // Prefixes XML responses with the given bytes. - HTMLContentType: "application/xhtml+xml", // Output XHTML content type instead of default "text/html". - IsDevelopment: true, // Render will now recompile the templates on every HTML response. - UnEscapeHTML: true, // Replace ensure '&<>' are output correctly (JSON only). - StreamingJSON: true, // Streams the JSON response via json.Encoder. - RequirePartials: true, // Return an error if a template is missing a partial used in a layout. - DisableHTTPErrorRendering: true, // Disables automatic rendering of http.StatusInternalServerError when an error occurs. -}) -// ... -~~~ - -### Default Options -These are the preset options for Render: - -~~~ go -r := render.New() - -// Is the same as the default configuration options: - -r := render.New(render.Options{ - Directory: "templates", - FileSystem: &LocalFileSystem{}, - Asset: nil, - AssetNames: nil, - Layout: "", - Extensions: []string{".tmpl"}, - Funcs: []template.FuncMap{}, - Delims: render.Delims{"{{", "}}"}, - Charset: "UTF-8", - DisableCharset: false, - IndentJSON: false, - IndentXML: false, - PrefixJSON: []byte(""), - PrefixXML: []byte(""), - BinaryContentType: "application/octet-stream", - HTMLContentType: "text/html", - JSONContentType: "application/json", - JSONPContentType: "application/javascript", - TextContentType: "text/plain", - XMLContentType: "application/xhtml+xml", - IsDevelopment: false, - UnEscapeHTML: false, - StreamingJSON: false, - RequirePartials: false, - DisableHTTPErrorRendering: false, -}) -~~~ - -### JSON vs Streaming JSON -By default, Render does **not** stream JSON to the `http.ResponseWriter`. It instead marshalls your object into a byte array, and if no errors occurred, writes that byte array to the `http.ResponseWriter`. If you would like to use the built it in streaming functionality (`json.Encoder`), you can set the `StreamingJSON` setting to `true`. This will stream the output directly to the `http.ResponseWriter`. Also note that streaming is only implemented in `render.JSON` and not `render.JSONP`, and the `UnEscapeHTML` and `Indent` options are ignored when streaming. - -### Loading Templates -By default Render will attempt to load templates with a '.tmpl' extension from the "templates" directory. Templates are found by traversing the templates directory and are named by path and basename. For instance, the following directory structure: - -~~~ -templates/ - | - |__ admin/ - | | - | |__ index.tmpl - | | - | |__ edit.tmpl - | - |__ home.tmpl -~~~ - -Will provide the following templates: -~~~ -admin/index -admin/edit -home -~~~ - -You can also load templates from memory by providing the Asset and AssetNames options, -e.g. when generating an asset file using [go-bindata](https://github.com/jteeuwen/go-bindata). - -### Layouts -Render provides `yield` and `partial` functions for layouts to access: -~~~ go -// ... -r := render.New(render.Options{ - Layout: "layout", -}) -// ... -~~~ - -~~~ html - - - - My Layout - - {{ partial "css" }} - - - - {{ partial "header" }} - - {{ yield }} - - {{ partial "footer" }} - - -~~~ - -`current` can also be called to get the current template being rendered. -~~~ html - - - - My Layout - - - This is the {{ current }} page. - - -~~~ - -Partials are defined by individual templates as seen below. The partial template's -name needs to be defined as "{partial name}-{template name}". -~~~ html - -{{ define "header-home" }} -

Home

-{{ end }} - -{{ define "footer-home"}} -

The End

-{{ end }} -~~~ - -By default, the template is not required to define all partials referenced in the -layout. If you want an error to be returned when a template does not define a -partial, set `Options.RequirePartials = true`. - -### Character Encodings -Render will automatically set the proper Content-Type header based on which function you call. See below for an example of what the default settings would output (note that UTF-8 is the default, and binary data does not output the charset): -~~~ go -// main.go -package main - -import ( - "encoding/xml" - "net/http" - - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -type ExampleXml struct { - XMLName xml.Name `xml:"example"` - One string `xml:"one,attr"` - Two string `xml:"two,attr"` -} - -func main() { - r := render.New(render.Options{}) - mux := http.NewServeMux() - - // This will set the Content-Type header to "application/octet-stream". - // Note that this does not receive a charset value. - mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) { - r.Data(w, http.StatusOK, []byte("Some binary data here.")) - }) - - // This will set the Content-Type header to "application/json; charset=UTF-8". - mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) { - r.JSON(w, http.StatusOK, map[string]string{"hello": "json"}) - }) - - // This will set the Content-Type header to "text/xml; charset=UTF-8". - mux.HandleFunc("/xml", func(w http.ResponseWriter, req *http.Request) { - r.XML(w, http.StatusOK, ExampleXml{One: "hello", Two: "xml"}) - }) - - // This will set the Content-Type header to "text/plain; charset=UTF-8". - mux.HandleFunc("/text", func(w http.ResponseWriter, req *http.Request) { - r.Text(w, http.StatusOK, "Plain text here") - }) - - // This will set the Content-Type header to "text/html; charset=UTF-8". - mux.HandleFunc("/html", func(w http.ResponseWriter, req *http.Request) { - // Assumes you have a template in ./templates called "example.tmpl" - // $ mkdir -p templates && echo "

Hello {{.}}.

" > templates/example.tmpl - r.HTML(w, http.StatusOK, "example", "World") - }) - - http.ListenAndServe("127.0.0.1:3000", mux) -} -~~~ - -In order to change the charset, you can set the `Charset` within the `render.Options` to your encoding value: -~~~ go -// main.go -package main - -import ( - "encoding/xml" - "net/http" - - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -type ExampleXml struct { - XMLName xml.Name `xml:"example"` - One string `xml:"one,attr"` - Two string `xml:"two,attr"` -} - -func main() { - r := render.New(render.Options{ - Charset: "ISO-8859-1", - }) - mux := http.NewServeMux() - - // This will set the Content-Type header to "application/octet-stream". - // Note that this does not receive a charset value. - mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) { - r.Data(w, http.StatusOK, []byte("Some binary data here.")) - }) - - // This will set the Content-Type header to "application/json; charset=ISO-8859-1". - mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) { - r.JSON(w, http.StatusOK, map[string]string{"hello": "json"}) - }) - - // This will set the Content-Type header to "text/xml; charset=ISO-8859-1". - mux.HandleFunc("/xml", func(w http.ResponseWriter, req *http.Request) { - r.XML(w, http.StatusOK, ExampleXml{One: "hello", Two: "xml"}) - }) - - // This will set the Content-Type header to "text/plain; charset=ISO-8859-1". - mux.HandleFunc("/text", func(w http.ResponseWriter, req *http.Request) { - r.Text(w, http.StatusOK, "Plain text here") - }) - - // This will set the Content-Type header to "text/html; charset=ISO-8859-1". - mux.HandleFunc("/html", func(w http.ResponseWriter, req *http.Request) { - // Assumes you have a template in ./templates called "example.tmpl" - // $ mkdir -p templates && echo "

Hello {{.}}.

" > templates/example.tmpl - r.HTML(w, http.StatusOK, "example", "World") - }) - - http.ListenAndServe("127.0.0.1:3000", mux) -} -~~~ - -### Error Handling - -The rendering functions return any errors from the rendering engine. -By default, they will also write the error to the HTTP response and set the status code to 500. You can disable -this behavior so that you can handle errors yourself by setting -`Options.DisableHTTPErrorRendering: true`. - -~~~go -r := render.New(render.Options{ - DisableHTTPErrorRendering: true, -}) - -//... - -err := r.HTML(w, http.StatusOK, "example", "World") -if err != nil{ - http.Redirect(w, r, "/my-custom-500", http.StatusFound) -} -~~~ - -## Integration Examples - -### [Echo](https://github.com/labstack/echo) -~~~ go -// main.go -package main - -import ( - "io" - "net/http" - - "github.com/labstack/echo" - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -type RenderWrapper struct { // We need to wrap the renderer because we need a different signature for echo. - rnd *render.Render -} - -func (r *RenderWrapper) Render(w io.Writer, name string, data interface{},c echo.Context) error { - return r.rnd.HTML(w, 0, name, data) // The zero status code is overwritten by echo. -} - -func main() { - r := &RenderWrapper{render.New()} - - e := echo.New() - - e.Renderer = r - - e.GET("/", func(c echo.Context) error { - return c.Render(http.StatusOK, "TemplateName", "TemplateData") - }) - - e.Logger.Fatal(e.Start(":1323")) -} -~~~ - -### [Gin](https://github.com/gin-gonic/gin) -~~~ go -// main.go -package main - -import ( - "net/http" - - "github.com/gin-gonic/gin" - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -func main() { - r := render.New(render.Options{ - IndentJSON: true, - }) - - router := gin.Default() - - router.GET("/", func(c *gin.Context) { - r.JSON(c.Writer, http.StatusOK, map[string]string{"welcome": "This is rendered JSON!"}) - }) - - router.Run(":3000") -} -~~~ - -### [Goji](https://github.com/zenazn/goji) -~~~ go -// main.go -package main - -import ( - "net/http" - - "github.com/zenazn/goji" - "github.com/zenazn/goji/web" - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -func main() { - r := render.New(render.Options{ - IndentJSON: true, - }) - - goji.Get("/", func(c web.C, w http.ResponseWriter, req *http.Request) { - r.JSON(w, http.StatusOK, map[string]string{"welcome": "This is rendered JSON!"}) - }) - goji.Serve() // Defaults to ":8000". -} -~~~ - -### [Negroni](https://github.com/codegangsta/negroni) -~~~ go -// main.go -package main - -import ( - "net/http" - - "github.com/urfave/negroni" - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -func main() { - r := render.New(render.Options{ - IndentJSON: true, - }) - mux := http.NewServeMux() - - mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - r.JSON(w, http.StatusOK, map[string]string{"welcome": "This is rendered JSON!"}) - }) - - n := negroni.Classic() - n.UseHandler(mux) - n.Run(":3000") -} -~~~ - -### [Traffic](https://github.com/pilu/traffic) -~~~ go -// main.go -package main - -import ( - "net/http" - - "github.com/pilu/traffic" - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" -) - -func main() { - r := render.New(render.Options{ - IndentJSON: true, - }) - - router := traffic.New() - router.Get("/", func(w traffic.ResponseWriter, req *traffic.Request) { - r.JSON(w, http.StatusOK, map[string]string{"welcome": "This is rendered JSON!"}) - }) - - router.Run() -} -~~~ diff --git a/vendor/github.com/unrolled/render/buffer.go b/vendor/github.com/unrolled/render/buffer.go deleted file mode 100644 index cdc92ffbde281..0000000000000 --- a/vendor/github.com/unrolled/render/buffer.go +++ /dev/null @@ -1,46 +0,0 @@ -package render - -import "bytes" - -// bufPool represents a reusable buffer pool for executing templates into. -var bufPool *BufferPool - -// BufferPool implements a pool of bytes.Buffers in the form of a bounded channel. -// Pulled from the github.com/oxtoacart/bpool package (Apache licensed). -type BufferPool struct { - c chan *bytes.Buffer -} - -// NewBufferPool creates a new BufferPool bounded to the given size. -func NewBufferPool(size int) (bp *BufferPool) { - return &BufferPool{ - c: make(chan *bytes.Buffer, size), - } -} - -// Get gets a Buffer from the BufferPool, or creates a new one if none are -// available in the pool. -func (bp *BufferPool) Get() (b *bytes.Buffer) { - select { - case b = <-bp.c: - // reuse existing buffer - default: - // create new buffer - b = bytes.NewBuffer([]byte{}) - } - return -} - -// Put returns the given Buffer to the BufferPool. -func (bp *BufferPool) Put(b *bytes.Buffer) { - b.Reset() - select { - case bp.c <- b: - default: // Discard the buffer if the pool is full. - } -} - -// Initialize buffer pool for writing templates into. -func init() { - bufPool = NewBufferPool(64) -} diff --git a/vendor/github.com/unrolled/render/doc.go b/vendor/github.com/unrolled/render/doc.go deleted file mode 100644 index d3487ffba264b..0000000000000 --- a/vendor/github.com/unrolled/render/doc.go +++ /dev/null @@ -1,55 +0,0 @@ -/*Package render is a package that provides functionality for easily rendering JSON, XML, binary data, and HTML templates. - - package main - - import ( - "encoding/xml" - "net/http" - - "github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1" - ) - - type ExampleXml struct { - XMLName xml.Name `xml:"example"` - One string `xml:"one,attr"` - Two string `xml:"two,attr"` - } - - func main() { - r := render.New() - mux := http.NewServeMux() - - mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - w.Write([]byte("Welcome, visit sub pages now.")) - }) - - mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) { - r.Data(w, http.StatusOK, []byte("Some binary data here.")) - }) - - mux.HandleFunc("/text", func(w http.ResponseWriter, req *http.Request) { - r.Text(w, http.StatusOK, "Plain text here") - }) - - mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) { - r.JSON(w, http.StatusOK, map[string]string{"hello": "json"}) - }) - - mux.HandleFunc("/jsonp", func(w http.ResponseWriter, req *http.Request) { - r.JSONP(w, http.StatusOK, "callbackName", map[string]string{"hello": "jsonp"}) - }) - - mux.HandleFunc("/xml", func(w http.ResponseWriter, req *http.Request) { - r.XML(w, http.StatusOK, ExampleXml{One: "hello", Two: "xml"}) - }) - - mux.HandleFunc("/html", func(w http.ResponseWriter, req *http.Request) { - // Assumes you have a template in ./templates called "example.tmpl". - // $ mkdir -p templates && echo "

Hello HTML world.

" > templates/example.tmpl - r.HTML(w, http.StatusOK, "example", nil) - }) - - http.ListenAndServe("0.0.0.0:3000", mux) - } -*/ -package render diff --git a/vendor/github.com/unrolled/render/engine.go b/vendor/github.com/unrolled/render/engine.go deleted file mode 100644 index cdf1a1b16f477..0000000000000 --- a/vendor/github.com/unrolled/render/engine.go +++ /dev/null @@ -1,217 +0,0 @@ -package render - -import ( - "bytes" - "encoding/json" - "encoding/xml" - "html/template" - "io" - "net/http" -) - -// Engine is the generic interface for all responses. -type Engine interface { - Render(io.Writer, interface{}) error -} - -// Head defines the basic ContentType and Status fields. -type Head struct { - ContentType string - Status int -} - -// Data built-in renderer. -type Data struct { - Head -} - -// HTML built-in renderer. -type HTML struct { - Head - Name string - Templates *template.Template -} - -// JSON built-in renderer. -type JSON struct { - Head - Indent bool - UnEscapeHTML bool - Prefix []byte - StreamingJSON bool -} - -// JSONP built-in renderer. -type JSONP struct { - Head - Indent bool - Callback string -} - -// Text built-in renderer. -type Text struct { - Head -} - -// XML built-in renderer. -type XML struct { - Head - Indent bool - Prefix []byte -} - -// Write outputs the header content. -func (h Head) Write(w http.ResponseWriter) { - w.Header().Set(ContentType, h.ContentType) - w.WriteHeader(h.Status) -} - -// Render a data response. -func (d Data) Render(w io.Writer, v interface{}) error { - if hw, ok := w.(http.ResponseWriter); ok { - c := hw.Header().Get(ContentType) - if c != "" { - d.Head.ContentType = c - } - d.Head.Write(hw) - } - - w.Write(v.([]byte)) - return nil -} - -// Render a HTML response. -func (h HTML) Render(w io.Writer, binding interface{}) error { - // Retrieve a buffer from the pool to write to. - out := bufPool.Get() - err := h.Templates.ExecuteTemplate(out, h.Name, binding) - if err != nil { - return err - } - - if hw, ok := w.(http.ResponseWriter); ok { - h.Head.Write(hw) - } - out.WriteTo(w) - - // Return the buffer to the pool. - bufPool.Put(out) - return nil -} - -// Render a JSON response. -func (j JSON) Render(w io.Writer, v interface{}) error { - if j.StreamingJSON { - return j.renderStreamingJSON(w, v) - } - - var result []byte - var err error - - if j.Indent { - result, err = json.MarshalIndent(v, "", " ") - result = append(result, '\n') - } else { - result, err = json.Marshal(v) - } - if err != nil { - return err - } - - // Unescape HTML if needed. - if j.UnEscapeHTML { - result = bytes.Replace(result, []byte("\\u003c"), []byte("<"), -1) - result = bytes.Replace(result, []byte("\\u003e"), []byte(">"), -1) - result = bytes.Replace(result, []byte("\\u0026"), []byte("&"), -1) - } - - // JSON marshaled fine, write out the result. - if hw, ok := w.(http.ResponseWriter); ok { - j.Head.Write(hw) - } - if len(j.Prefix) > 0 { - w.Write(j.Prefix) - } - w.Write(result) - return nil -} - -func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error { - if hw, ok := w.(http.ResponseWriter); ok { - j.Head.Write(hw) - } - if len(j.Prefix) > 0 { - w.Write(j.Prefix) - } - - return json.NewEncoder(w).Encode(v) -} - -// Render a JSONP response. -func (j JSONP) Render(w io.Writer, v interface{}) error { - var result []byte - var err error - - if j.Indent { - result, err = json.MarshalIndent(v, "", " ") - } else { - result, err = json.Marshal(v) - } - if err != nil { - return err - } - - // JSON marshaled fine, write out the result. - if hw, ok := w.(http.ResponseWriter); ok { - j.Head.Write(hw) - } - w.Write([]byte(j.Callback + "(")) - w.Write(result) - w.Write([]byte(");")) - - // If indenting, append a new line. - if j.Indent { - w.Write([]byte("\n")) - } - return nil -} - -// Render a text response. -func (t Text) Render(w io.Writer, v interface{}) error { - if hw, ok := w.(http.ResponseWriter); ok { - c := hw.Header().Get(ContentType) - if c != "" { - t.Head.ContentType = c - } - t.Head.Write(hw) - } - - w.Write([]byte(v.(string))) - return nil -} - -// Render an XML response. -func (x XML) Render(w io.Writer, v interface{}) error { - var result []byte - var err error - - if x.Indent { - result, err = xml.MarshalIndent(v, "", " ") - result = append(result, '\n') - } else { - result, err = xml.Marshal(v) - } - if err != nil { - return err - } - - // XML marshaled fine, write out the result. - if hw, ok := w.(http.ResponseWriter); ok { - x.Head.Write(hw) - } - if len(x.Prefix) > 0 { - w.Write(x.Prefix) - } - w.Write(result) - return nil -} diff --git a/vendor/github.com/unrolled/render/fs.go b/vendor/github.com/unrolled/render/fs.go deleted file mode 100644 index 3e60776253125..0000000000000 --- a/vendor/github.com/unrolled/render/fs.go +++ /dev/null @@ -1,21 +0,0 @@ -package render - -import ( - "io/ioutil" - "path/filepath" -) - -type FileSystem interface { - Walk(root string, walkFn filepath.WalkFunc) error - ReadFile(filename string) ([]byte, error) -} - -type LocalFileSystem struct{} - -func (LocalFileSystem) Walk(root string, walkFn filepath.WalkFunc) error { - return filepath.Walk(root, walkFn) -} - -func (LocalFileSystem) ReadFile(filename string) ([]byte, error) { - return ioutil.ReadFile(filename) -} diff --git a/vendor/github.com/unrolled/render/go.mod b/vendor/github.com/unrolled/render/go.mod deleted file mode 100644 index 22d793cbcfb7d..0000000000000 --- a/vendor/github.com/unrolled/render/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/unrolled/render - -go 1.12 - -require github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 diff --git a/vendor/github.com/unrolled/render/go.sum b/vendor/github.com/unrolled/render/go.sum deleted file mode 100644 index 2199959075def..0000000000000 --- a/vendor/github.com/unrolled/render/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= diff --git a/vendor/github.com/unrolled/render/helpers.go b/vendor/github.com/unrolled/render/helpers.go deleted file mode 100644 index 699508a4910d0..0000000000000 --- a/vendor/github.com/unrolled/render/helpers.go +++ /dev/null @@ -1,21 +0,0 @@ -// +build go1.6 - -package render - -import ( - "fmt" - "html/template" -) - -// Included helper functions for use when rendering HTML. -var helperFuncs = template.FuncMap{ - "yield": func() (string, error) { - return "", fmt.Errorf("yield called with no layout defined") - }, - "partial": func() (string, error) { - return "", fmt.Errorf("block called with no layout defined") - }, - "current": func() (string, error) { - return "", nil - }, -} diff --git a/vendor/github.com/unrolled/render/helpers_pre16.go b/vendor/github.com/unrolled/render/helpers_pre16.go deleted file mode 100644 index 999d9af497a2e..0000000000000 --- a/vendor/github.com/unrolled/render/helpers_pre16.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build !go1.6 - -package render - -import ( - "fmt" - "html/template" -) - -// Included helper functions for use when rendering HTML. -var helperFuncs = template.FuncMap{ - "yield": func() (string, error) { - return "", fmt.Errorf("yield called with no layout defined") - }, - // `block` is deprecated! Use the `partial` below if you need this functionality still. - // Otherwise, checkout Go's `block` implementation introduced in 1.6 - "block": func() (string, error) { - return "", fmt.Errorf("block called with no layout defined") - }, - "partial": func() (string, error) { - return "", fmt.Errorf("block called with no layout defined") - }, - "current": func() (string, error) { - return "", nil - }, -} diff --git a/vendor/github.com/unrolled/render/render.go b/vendor/github.com/unrolled/render/render.go deleted file mode 100644 index 3259f620ebc08..0000000000000 --- a/vendor/github.com/unrolled/render/render.go +++ /dev/null @@ -1,480 +0,0 @@ -package render - -import ( - "bytes" - "fmt" - "html/template" - "io" - "log" - "net/http" - "os" - "path/filepath" - "strings" - "sync" -) - -const ( - // ContentBinary header value for binary data. - ContentBinary = "application/octet-stream" - // ContentHTML header value for HTML data. - ContentHTML = "text/html" - // ContentJSON header value for JSON data. - ContentJSON = "application/json" - // ContentJSONP header value for JSONP data. - ContentJSONP = "application/javascript" - // ContentLength header constant. - ContentLength = "Content-Length" - // ContentText header value for Text data. - ContentText = "text/plain" - // ContentType header constant. - ContentType = "Content-Type" - // ContentXHTML header value for XHTML data. - ContentXHTML = "application/xhtml+xml" - // ContentXML header value for XML data. - ContentXML = "text/xml" - // Default character encoding. - defaultCharset = "UTF-8" -) - -// helperFuncs had to be moved out. See helpers.go|helpers_pre16.go files. - -// Delims represents a set of Left and Right delimiters for HTML template rendering. -type Delims struct { - // Left delimiter, defaults to {{. - Left string - // Right delimiter, defaults to }}. - Right string -} - -// Options is a struct for specifying configuration options for the render.Render object. -type Options struct { - // Directory to load templates. Default is "templates". - Directory string - // FileSystem to access files - FileSystem FileSystem - // Asset function to use in place of directory. Defaults to nil. - Asset func(name string) ([]byte, error) - // AssetNames function to use in place of directory. Defaults to nil. - AssetNames func() []string - // Layout template name. Will not render a layout if blank (""). Defaults to blank (""). - Layout string - // Extensions to parse template files from. Defaults to [".tmpl"]. - Extensions []string - // Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Defaults to empty map. - Funcs []template.FuncMap - // Delims sets the action delimiters to the specified strings in the Delims struct. - Delims Delims - // Appends the given character set to the Content-Type header. Default is "UTF-8". - Charset string - // If DisableCharset is set to true, it will not append the above Charset value to the Content-Type header. Default is false. - DisableCharset bool - // Outputs human readable JSON. - IndentJSON bool - // Outputs human readable XML. Default is false. - IndentXML bool - // Prefixes the JSON output with the given bytes. Default is false. - PrefixJSON []byte - // Prefixes the XML output with the given bytes. - PrefixXML []byte - // Allows changing the binary content type. - BinaryContentType string - // Allows changing the HTML content type. - HTMLContentType string - // Allows changing the JSON content type. - JSONContentType string - // Allows changing the JSONP content type. - JSONPContentType string - // Allows changing the Text content type. - TextContentType string - // Allows changing the XML content type. - XMLContentType string - // If IsDevelopment is set to true, this will recompile the templates on every request. Default is false. - IsDevelopment bool - // Unescape HTML characters "&<>" to their original values. Default is false. - UnEscapeHTML bool - // Streams JSON responses instead of marshalling prior to sending. Default is false. - StreamingJSON bool - // Require that all partials executed in the layout are implemented in all templates using the layout. Default is false. - RequirePartials bool - // Deprecated: Use the above `RequirePartials` instead of this. As of Go 1.6, blocks are built in. Default is false. - RequireBlocks bool - // Disables automatic rendering of http.StatusInternalServerError when an error occurs. Default is false. - DisableHTTPErrorRendering bool - // Enables using partials without the current filename suffix which allows use of the same template in multiple files. e.g {{ partial "carosuel" }} inside the home template will match carosel-home or carosel. - // ***NOTE*** - This option should be named RenderPartialsWithoutSuffix as that is what it does. "Prefix" is a typo. Maintaining the existing name for backwards compatibility. - RenderPartialsWithoutPrefix bool -} - -// HTMLOptions is a struct for overriding some rendering Options for specific HTML call. -type HTMLOptions struct { - // Layout template name. Overrides Options.Layout. - Layout string - // Funcs added to Options.Funcs. - Funcs template.FuncMap -} - -// Render is a service that provides functions for easily writing JSON, XML, -// binary data, and HTML templates out to a HTTP Response. -type Render struct { - // Customize Secure with an Options struct. - opt Options - templates *template.Template - templatesLk sync.Mutex - compiledCharset string -} - -// New constructs a new Render instance with the supplied options. -func New(options ...Options) *Render { - var o Options - if len(options) > 0 { - o = options[0] - } - - r := Render{ - opt: o, - } - - r.prepareOptions() - r.compileTemplates() - - return &r -} - -func (r *Render) prepareOptions() { - // Fill in the defaults if need be. - if len(r.opt.Charset) == 0 { - r.opt.Charset = defaultCharset - } - if r.opt.DisableCharset == false { - r.compiledCharset = "; charset=" + r.opt.Charset - } - - if len(r.opt.Directory) == 0 { - r.opt.Directory = "templates" - } - if r.opt.FileSystem == nil { - r.opt.FileSystem = &LocalFileSystem{} - } - if len(r.opt.Extensions) == 0 { - r.opt.Extensions = []string{".tmpl"} - } - if len(r.opt.BinaryContentType) == 0 { - r.opt.BinaryContentType = ContentBinary - } - if len(r.opt.HTMLContentType) == 0 { - r.opt.HTMLContentType = ContentHTML - } - if len(r.opt.JSONContentType) == 0 { - r.opt.JSONContentType = ContentJSON - } - if len(r.opt.JSONPContentType) == 0 { - r.opt.JSONPContentType = ContentJSONP - } - if len(r.opt.TextContentType) == 0 { - r.opt.TextContentType = ContentText - } - if len(r.opt.XMLContentType) == 0 { - r.opt.XMLContentType = ContentXML - } -} - -func (r *Render) compileTemplates() { - if r.opt.Asset == nil || r.opt.AssetNames == nil { - r.compileTemplatesFromDir() - return - } - r.compileTemplatesFromAsset() -} - -func (r *Render) compileTemplatesFromDir() { - dir := r.opt.Directory - r.templates = template.New(dir) - r.templates.Delims(r.opt.Delims.Left, r.opt.Delims.Right) - - // Walk the supplied directory and compile any files that match our extension list. - r.opt.FileSystem.Walk(dir, func(path string, info os.FileInfo, err error) error { - // Fix same-extension-dirs bug: some dir might be named to: "users.tmpl", "local.html". - // These dirs should be excluded as they are not valid golang templates, but files under - // them should be treat as normal. - // If is a dir, return immediately (dir is not a valid golang template). - if info == nil || info.IsDir() { - return nil - } - - rel, err := filepath.Rel(dir, path) - if err != nil { - return err - } - - ext := "" - if strings.Index(rel, ".") != -1 { - ext = filepath.Ext(rel) - } - - for _, extension := range r.opt.Extensions { - if ext == extension { - buf, err := r.opt.FileSystem.ReadFile(path) - if err != nil { - panic(err) - } - - name := (rel[0 : len(rel)-len(ext)]) - tmpl := r.templates.New(filepath.ToSlash(name)) - - // Add our funcmaps. - for _, funcs := range r.opt.Funcs { - tmpl.Funcs(funcs) - } - - // Break out if this parsing fails. We don't want any silent server starts. - template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf))) - break - } - } - return nil - }) -} - -func (r *Render) compileTemplatesFromAsset() { - dir := r.opt.Directory - r.templates = template.New(dir) - r.templates.Delims(r.opt.Delims.Left, r.opt.Delims.Right) - - for _, path := range r.opt.AssetNames() { - if !strings.HasPrefix(path, dir) { - continue - } - - rel, err := filepath.Rel(dir, path) - if err != nil { - panic(err) - } - - ext := "" - if strings.Index(rel, ".") != -1 { - ext = "." + strings.Join(strings.Split(rel, ".")[1:], ".") - } - - for _, extension := range r.opt.Extensions { - if ext == extension { - - buf, err := r.opt.Asset(path) - if err != nil { - panic(err) - } - - name := (rel[0 : len(rel)-len(ext)]) - tmpl := r.templates.New(filepath.ToSlash(name)) - - // Add our funcmaps. - for _, funcs := range r.opt.Funcs { - tmpl.Funcs(funcs) - } - - // Break out if this parsing fails. We don't want any silent server starts. - template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf))) - break - } - } - } -} - -// TemplateLookup is a wrapper around template.Lookup and returns -// the template with the given name that is associated with t, or nil -// if there is no such template. -func (r *Render) TemplateLookup(t string) *template.Template { - return r.templates.Lookup(t) -} - -func (r *Render) execute(name string, binding interface{}) (*bytes.Buffer, error) { - buf := new(bytes.Buffer) - return buf, r.templates.ExecuteTemplate(buf, name, binding) -} - -func (r *Render) layoutFuncs(name string, binding interface{}) template.FuncMap { - return template.FuncMap{ - "yield": func() (template.HTML, error) { - buf, err := r.execute(name, binding) - // Return safe HTML here since we are rendering our own template. - return template.HTML(buf.String()), err - }, - "current": func() (string, error) { - return name, nil - }, - "block": func(partialName string) (template.HTML, error) { - log.Print("Render's `block` implementation is now depericated. Use `partial` as a drop in replacement.") - fullPartialName := fmt.Sprintf("%s-%s", partialName, name) - if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix { - fullPartialName = partialName - } - if r.opt.RequireBlocks || r.TemplateLookup(fullPartialName) != nil { - buf, err := r.execute(fullPartialName, binding) - // Return safe HTML here since we are rendering our own template. - return template.HTML(buf.String()), err - } - return "", nil - }, - "partial": func(partialName string) (template.HTML, error) { - fullPartialName := fmt.Sprintf("%s-%s", partialName, name) - if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix { - fullPartialName = partialName - } - if r.opt.RequirePartials || r.TemplateLookup(fullPartialName) != nil { - buf, err := r.execute(fullPartialName, binding) - // Return safe HTML here since we are rendering our own template. - return template.HTML(buf.String()), err - } - return "", nil - }, - } -} - -func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { - layout := r.opt.Layout - funcs := template.FuncMap{} - - for _, tmp := range r.opt.Funcs { - for k, v := range tmp { - funcs[k] = v - } - } - - if len(htmlOpt) > 0 { - opt := htmlOpt[0] - if len(opt.Layout) > 0 { - layout = opt.Layout - } - - for k, v := range opt.Funcs { - funcs[k] = v - } - } - - return HTMLOptions{ - Layout: layout, - Funcs: funcs, - } -} - -// Render is the generic function called by XML, JSON, Data, HTML, and can be called by custom implementations. -func (r *Render) Render(w io.Writer, e Engine, data interface{}) error { - err := e.Render(w, data) - if hw, ok := w.(http.ResponseWriter); err != nil && !r.opt.DisableHTTPErrorRendering && ok { - http.Error(hw, err.Error(), http.StatusInternalServerError) - } - return err -} - -// Data writes out the raw bytes as binary data. -func (r *Render) Data(w io.Writer, status int, v []byte) error { - head := Head{ - ContentType: r.opt.BinaryContentType, - Status: status, - } - - d := Data{ - Head: head, - } - - return r.Render(w, d, v) -} - -// HTML builds up the response from the specified template and bindings. -func (r *Render) HTML(w io.Writer, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) error { - r.templatesLk.Lock() - defer r.templatesLk.Unlock() - - // If we are in development mode, recompile the templates on every HTML request. - if r.opt.IsDevelopment { - r.compileTemplates() - } - - opt := r.prepareHTMLOptions(htmlOpt) - if tpl := r.templates.Lookup(name); tpl != nil { - if len(opt.Layout) > 0 { - tpl.Funcs(r.layoutFuncs(name, binding)) - name = opt.Layout - } - - if len(opt.Funcs) > 0 { - tpl.Funcs(opt.Funcs) - } - } - - head := Head{ - ContentType: r.opt.HTMLContentType + r.compiledCharset, - Status: status, - } - - h := HTML{ - Head: head, - Name: name, - Templates: r.templates, - } - - return r.Render(w, h, binding) -} - -// JSON marshals the given interface object and writes the JSON response. -func (r *Render) JSON(w io.Writer, status int, v interface{}) error { - head := Head{ - ContentType: r.opt.JSONContentType + r.compiledCharset, - Status: status, - } - - j := JSON{ - Head: head, - Indent: r.opt.IndentJSON, - Prefix: r.opt.PrefixJSON, - UnEscapeHTML: r.opt.UnEscapeHTML, - StreamingJSON: r.opt.StreamingJSON, - } - - return r.Render(w, j, v) -} - -// JSONP marshals the given interface object and writes the JSON response. -func (r *Render) JSONP(w io.Writer, status int, callback string, v interface{}) error { - head := Head{ - ContentType: r.opt.JSONPContentType + r.compiledCharset, - Status: status, - } - - j := JSONP{ - Head: head, - Indent: r.opt.IndentJSON, - Callback: callback, - } - - return r.Render(w, j, v) -} - -// Text writes out a string as plain text. -func (r *Render) Text(w io.Writer, status int, v string) error { - head := Head{ - ContentType: r.opt.TextContentType + r.compiledCharset, - Status: status, - } - - t := Text{ - Head: head, - } - - return r.Render(w, t, v) -} - -// XML marshals the given interface object and writes the XML response. -func (r *Render) XML(w io.Writer, status int, v interface{}) error { - head := Head{ - ContentType: r.opt.XMLContentType + r.compiledCharset, - Status: status, - } - - x := XML{ - Head: head, - Indent: r.opt.IndentXML, - Prefix: r.opt.PrefixXML, - } - - return r.Render(w, x, v) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 426b0dc9473a5..ee584932d2a0c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,13 +7,6 @@ code.gitea.io/gitea-vet/checks # code.gitea.io/sdk/gitea v0.13.1 ## explicit code.gitea.io/sdk/gitea -# gitea.com/go-chi/session v0.0.0-20201218134809-7209fa084f27 -## explicit -gitea.com/go-chi/session -gitea.com/go-chi/session/couchbase -gitea.com/go-chi/session/memcache -gitea.com/go-chi/session/mysql -gitea.com/go-chi/session/postgres # gitea.com/lunny/levelqueue v0.3.0 ## explicit gitea.com/lunny/levelqueue @@ -195,7 +188,7 @@ github.com/cespare/xxhash/v2 github.com/chris-ramon/douceur/parser # github.com/couchbase/go-couchbase v0.0.0-20201026062457-7b3be89bbd89 github.com/couchbase/go-couchbase -# github.com/couchbase/gomemcached v0.1.1 +# github.com/couchbase/gomemcached v0.1.0 github.com/couchbase/gomemcached github.com/couchbase/gomemcached/client # github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67 @@ -264,7 +257,7 @@ github.com/gliderlabs/ssh github.com/glycerine/go-unsnap-stream # github.com/go-asn1-ber/asn1-ber v1.5.1 github.com/go-asn1-ber/asn1-ber -# github.com/go-chi/chi v1.5.1 +# github.com/go-chi/chi v1.5.0 ## explicit github.com/go-chi/chi github.com/go-chi/chi/middleware @@ -637,6 +630,8 @@ github.com/oliamb/cutter github.com/olivere/elastic/v7 github.com/olivere/elastic/v7/config github.com/olivere/elastic/v7/uritemplates +# github.com/onsi/ginkgo v1.13.0 +## explicit # github.com/pelletier/go-toml v1.8.1 ## explicit github.com/pelletier/go-toml @@ -755,9 +750,6 @@ github.com/unknwon/i18n # github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae ## explicit github.com/unknwon/paginater -# github.com/unrolled/render v1.0.3 -## explicit -github.com/unrolled/render # github.com/urfave/cli v1.22.5 ## explicit github.com/urfave/cli @@ -924,6 +916,7 @@ golang.org/x/tools/internal/typesinternal golang.org/x/xerrors golang.org/x/xerrors/internal # google.golang.org/appengine v1.6.7 +## explicit google.golang.org/appengine google.golang.org/appengine/internal google.golang.org/appengine/internal/app_identity