diff --git a/Makefile b/Makefile index 2222594..c6acda1 100644 --- a/Makefile +++ b/Makefile @@ -34,13 +34,13 @@ gotest: go test -v --cover ./server/... go test -v --cover ./pkg/... -ci: - go test -count=1 -p=1 -v ./tests/... - e2e: ./hack/run-e2e.sh -alltest: gotest ci e2e +e2e-trace: + DEBUG=true LOG_LEVEL=trace ./hack/run-e2e.sh + +alltest: gotest e2e clean: rm -f ./bin/frpc diff --git a/go.mod b/go.mod index fb459f7..b2915fb 100644 --- a/go.mod +++ b/go.mod @@ -8,16 +8,18 @@ require ( github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb github.com/fatedier/golib v0.1.1-0.20200901083111-1f870741e185 github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible - github.com/google/uuid v1.1.1 - github.com/gorilla/mux v1.7.3 - github.com/gorilla/websocket v1.4.0 + github.com/go-playground/validator/v10 v10.6.1 + github.com/google/uuid v1.2.0 + github.com/gorilla/mux v1.8.0 + github.com/gorilla/websocket v1.4.2 github.com/hashicorp/yamux v0.0.0-20210316155119-a95892c5f864 github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/klauspost/cpuid v1.2.0 // indirect github.com/klauspost/reedsolomon v1.9.1 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect - github.com/onsi/ginkgo v1.12.3 - github.com/onsi/gomega v1.10.1 + github.com/onsi/ginkgo v1.16.4 + github.com/onsi/gomega v1.13.0 github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect github.com/prometheus/client_golang v1.4.1 @@ -25,15 +27,16 @@ require ( github.com/rodaine/table v1.0.0 github.com/smartystreets/goconvey v1.6.4 // indirect github.com/spf13/cobra v0.0.3 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.6.1 github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047 // indirect github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554 // indirect github.com/tjfoc/gmsm v0.0.0-20171124023159-98aa888b79d8 // indirect github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect - golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 + golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 + golang.org/x/tools v0.1.3 // indirect gopkg.in/ini.v1 v1.62.0 gopkg.in/square/go-jose.v2 v2.4.1 // indirect k8s.io/apimachinery v0.18.3 diff --git a/go.sum b/go.sum index e7c5f4c..8447925 100644 --- a/go.sum +++ b/go.sum @@ -44,7 +44,17 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I= +github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -57,26 +67,30 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x 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/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/yamux v0.0.0-20210316155119-a95892c5f864 h1:Y4V+SFe7d3iH+9pJCoeWIOS5/xBJIFsltS7E+KJSsJY= github.com/hashicorp/yamux v0.0.0-20210316155119-a95892c5f864/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= @@ -102,6 +116,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -114,19 +131,22 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.12.3 h1:+RYp9QczoWz9zfUyLP/5SLXQVhfr6gZOoKGfQqHuLZQ= -github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/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 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc h1:lNOt1SMsgHXTdpuGw+RpnJtzUcCb/oRKZP65pBy9pr8= github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc/go.mod h1:6/gX3+E/IYGa0wMORlSMla999awQFdbaeQCHjSMKIzY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -170,8 +190,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +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/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047 h1:K+jtWCOuZgCra7eXZ/VWn2FbJmrA/D058mTXhh2rq+8= github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554 h1:pexgSe+JCFuxG+uoMZLO+ce8KHtdHGhst4cs6rw3gmk= @@ -180,10 +202,16 @@ github.com/tjfoc/gmsm v0.0.0-20171124023159-98aa888b79d8 h1:6CNSDqI1wiE+JqyOy5Qt github.com/tjfoc/gmsm v0.0.0-20171124023159-98aa888b79d8/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -191,21 +219,30 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190422165155-953cdadca894/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= @@ -213,21 +250,37 @@ golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/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-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -235,8 +288,10 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ 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= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -255,8 +310,11 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +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= k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk= k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= diff --git a/hack/run-e2e.sh b/hack/run-e2e.sh index 0932b2c..16a6e54 100755 --- a/hack/run-e2e.sh +++ b/hack/run-e2e.sh @@ -12,4 +12,9 @@ debug=false if [ x${DEBUG} == x"true" ]; then debug=true fi -ginkgo -nodes=4 ${ROOT}/test/e2e -- -frpc-path=${ROOT}/bin/frpc -frps-path=${ROOT}/bin/frps -log-level=debug -debug=${debug} +logLevel=debug +if [ x${LOG_LEVEL} != x"" ]; then + logLevel=${LOG_LEVEL} +fi + +ginkgo -nodes=5 -slowSpecThreshold=10 ${ROOT}/test/e2e -- -frpc-path=${ROOT}/bin/frpc -frps-path=${ROOT}/bin/frps -log-level=${logLevel} -debug=${debug} diff --git a/pkg/config/server.go b/pkg/config/server.go index a5af0fa..8e7f7ad 100644 --- a/pkg/config/server.go +++ b/pkg/config/server.go @@ -22,6 +22,7 @@ import ( plugin "github.com/fatedier/frp/pkg/plugin/server" "github.com/fatedier/frp/pkg/util/util" + "github.com/go-playground/validator/v10" "gopkg.in/ini.v1" ) @@ -36,31 +37,31 @@ type ServerCommonConf struct { BindAddr string `ini:"bind_addr" json:"bind_addr"` // BindPort specifies the port that the server listens on. By default, this // value is 7000. - BindPort int `ini:"bind_port" json:"bind_port"` + BindPort int `ini:"bind_port" json:"bind_port" validate:"gte=0,lte=65535"` // BindUDPPort specifies the UDP port that the server listens on. If this // value is 0, the server will not listen for UDP connections. By default, // this value is 0 - BindUDPPort int `ini:"bind_udp_port" json:"bind_udp_port"` + BindUDPPort int `ini:"bind_udp_port" json:"bind_udp_port" validate:"gte=0,lte=65535"` // KCPBindPort specifies the KCP port that the server listens on. If this // value is 0, the server will not listen for KCP connections. By default, // this value is 0. - KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port"` + KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port" validate:"gte=0,lte=65535"` // ProxyBindAddr specifies the address that the proxy binds to. This value // may be the same as BindAddr. ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"` // VhostHTTPPort specifies the port that the server listens for HTTP Vhost // requests. If this value is 0, the server will not listen for HTTP // requests. By default, this value is 0. - VhostHTTPPort int `ini:"vhost_http_port" json:"vhost_http_port"` + VhostHTTPPort int `ini:"vhost_http_port" json:"vhost_http_port" validate:"gte=0,lte=65535"` // VhostHTTPSPort specifies the port that the server listens for HTTPS // Vhost requests. If this value is 0, the server will not listen for HTTPS // requests. By default, this value is 0. - VhostHTTPSPort int `ini:"vhost_https_port" json:"vhost_https_port"` + VhostHTTPSPort int `ini:"vhost_https_port" json:"vhost_https_port" validate:"gte=0,lte=65535"` // TCPMuxHTTPConnectPort specifies the port that the server listens for TCP // HTTP CONNECT requests. If the value is 0, the server will not multiplex TCP // requests on one single port. If it's not - it will listen on this value for // HTTP CONNECT requests. By default, this value is 0. - TCPMuxHTTPConnectPort int `ini:"tcpmux_httpconnect_port" json:"tcpmux_httpconnect_port"` + TCPMuxHTTPConnectPort int `ini:"tcpmux_httpconnect_port" json:"tcpmux_httpconnect_port" validate:"gte=0,lte=65535"` // VhostHTTPTimeout specifies the response header timeout for the Vhost // HTTP server, in seconds. By default, this value is 60. VhostHTTPTimeout int64 `ini:"vhost_http_timeout" json:"vhost_http_timeout"` @@ -70,7 +71,7 @@ type ServerCommonConf struct { // DashboardPort specifies the port that the dashboard listens on. If this // value is 0, the dashboard will not be started. By default, this value is // 0. - DashboardPort int `ini:"dashboard_port" json:"dashboard_port"` + DashboardPort int `ini:"dashboard_port" json:"dashboard_port" validate:"gte=0,lte=65535"` // DashboardUser specifies the username that the dashboard will use for // login. DashboardUser string `ini:"dashboard_user" json:"dashboard_user"` @@ -281,7 +282,7 @@ func (cfg *ServerCommonConf) Complete() { } func (cfg *ServerCommonConf) Validate() error { - return nil + return validator.New().Struct(cfg) } func loadHTTPPluginOpt(section *ini.Section) (*plugin.HTTPPluginOptions, error) { diff --git a/test/e2e/basic/basic.go b/test/e2e/basic/basic.go index 3c18b94..5569f35 100644 --- a/test/e2e/basic/basic.go +++ b/test/e2e/basic/basic.go @@ -6,7 +6,7 @@ import ( "github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework/consts" - "github.com/fatedier/frp/test/e2e/mock/server" + "github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/pkg/port" "github.com/fatedier/frp/test/e2e/pkg/request" @@ -81,7 +81,7 @@ var _ = Describe("[Feature: Basic]", func() { for _, test := range tests { framework.NewRequestExpect(f). - RequestModify(framework.SetRequestProtocol(protocol)). + Protocol(protocol). PortName(test.portName). Explain(test.proxyName). Ensure() @@ -90,6 +90,88 @@ var _ = Describe("[Feature: Basic]", func() { } }) + Describe("HTTP", func() { + It("proxy to HTTP server", func() { + serverConf := consts.DefaultServerConfig + vhostHTTPPort := f.AllocPort() + serverConf += fmt.Sprintf(` + vhost_http_port = %d + `, vhostHTTPPort) + + clientConf := consts.DefaultClientConfig + + getProxyConf := func(proxyName string, customDomains string, extra string) string { + return fmt.Sprintf(` + [%s] + type = http + local_port = {{ .%s }} + custom_domains = %s + `+extra, proxyName, framework.HTTPSimpleServerPort, customDomains) + } + + tests := []struct { + proxyName string + customDomains string + extraConfig string + }{ + { + proxyName: "normal", + }, + { + proxyName: "with-encryption", + extraConfig: "use_encryption = true", + }, + { + proxyName: "with-compression", + extraConfig: "use_compression = true", + }, + { + proxyName: "with-encryption-and-compression", + extraConfig: ` + use_encryption = true + use_compression = true + `, + }, + { + proxyName: "multiple-custom-domains", + customDomains: "a.example.com, b.example.com", + }, + } + + // build all client config + for i, test := range tests { + if tests[i].customDomains == "" { + tests[i].customDomains = test.proxyName + ".example.com" + } + clientConf += getProxyConf(test.proxyName, tests[i].customDomains, test.extraConfig) + "\n" + } + // run frps and frpc + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + for _, test := range tests { + for _, domain := range strings.Split(test.customDomains, ",") { + domain = strings.TrimSpace(domain) + framework.NewRequestExpect(f). + Explain(test.proxyName + "-" + domain). + Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost(domain) + }). + Ensure() + } + } + + // not exist host + framework.NewRequestExpect(f). + Explain("not exist host"). + Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("not-exist.example.com") + }). + Ensure(framework.ExpectResponseCode(404)) + }) + }) + Describe("STCP && SUDP", func() { types := []string{"stcp", "sudp"} for _, t := range types { @@ -186,12 +268,11 @@ var _ = Describe("[Feature: Basic]", func() { for _, test := range tests { framework.NewRequestExpect(f). - RequestModify(framework.SetRequestProtocol(protocol)). + Protocol(protocol). PortName(test.bindPortName). Explain(test.proxyName). ExpectError(test.expectError). Ensure() - } }) } @@ -245,7 +326,7 @@ var _ = Describe("[Feature: Basic]", func() { for _, test := range tests { clientConf += getProxyConf(test.proxyName, test.extraConfig) + "\n" - localServer := server.New(server.TCP, server.WithBindPort(f.AllocPort()), server.WithRespContent([]byte(test.proxyName))) + localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(f.AllocPort()), streamserver.WithRespContent([]byte(test.proxyName))) f.RunServer(port.GenName(test.proxyName), localServer) } @@ -262,13 +343,13 @@ var _ = Describe("[Feature: Basic]", func() { proxyURL := fmt.Sprintf("http://127.0.0.1:%d", f.PortByName(tcpmuxHTTPConnectPortName)) // Request with incorrect connect hostname framework.NewRequestExpect(f).RequestModify(func(r *request.Request) { - r.Proxy(proxyURL, "invalid") + r.Addr("invalid").Proxy(proxyURL) }).ExpectError(true).Explain("request without HTTP connect expect error").Ensure() // Request with correct connect hostname for _, test := range tests { framework.NewRequestExpect(f).RequestModify(func(r *request.Request) { - r.Proxy(proxyURL, test.proxyName) + r.Addr(test.proxyName).Proxy(proxyURL) }).ExpectResp([]byte(test.proxyName)).Explain(test.proxyName).Ensure() } }) diff --git a/test/e2e/basic/chaos.go b/test/e2e/basic/chaos.go new file mode 100644 index 0000000..ad32811 --- /dev/null +++ b/test/e2e/basic/chaos.go @@ -0,0 +1,65 @@ +package basic + +import ( + "fmt" + "time" + + "github.com/fatedier/frp/test/e2e/framework" + + . "github.com/onsi/ginkgo" +) + +var _ = Describe("[Feature: Chaos]", func() { + f := framework.NewDefaultFramework() + + It("reconnect after frps restart", func() { + serverPort := f.AllocPort() + serverConfigPath := f.GenerateConfigFile(fmt.Sprintf(` + [common] + bind_addr = 0.0.0.0 + bind_port = %d + `, serverPort)) + + remotePort := f.AllocPort() + clientConfigPath := f.GenerateConfigFile(fmt.Sprintf(` + [common] + server_port = %d + log_level = trace + + [tcp] + type = tcp + local_port = %d + remote_port = %d + `, serverPort, f.PortByName(framework.TCPEchoServerPort), remotePort)) + + // 1. start frps and frpc, expect request success + ps, _, err := f.RunFrps("-c", serverConfigPath) + framework.ExpectNoError(err) + + pc, _, err := f.RunFrpc("-c", clientConfigPath) + framework.ExpectNoError(err) + framework.NewRequestExpect(f).Port(remotePort).Ensure() + + // 2. stop frps, expect request failed + ps.Stop() + time.Sleep(200 * time.Millisecond) + framework.NewRequestExpect(f).Port(remotePort).ExpectError(true).Ensure() + + // 3. restart frps, expect request success + _, _, err = f.RunFrps("-c", serverConfigPath) + framework.ExpectNoError(err) + time.Sleep(2 * time.Second) + framework.NewRequestExpect(f).Port(remotePort).Ensure() + + // 4. stop frpc, expect request failed + pc.Stop() + time.Sleep(200 * time.Millisecond) + framework.NewRequestExpect(f).Port(remotePort).ExpectError(true).Ensure() + + // 5. restart frpc, expect request success + _, _, err = f.RunFrpc("-c", clientConfigPath) + framework.ExpectNoError(err) + time.Sleep(time.Second) + framework.NewRequestExpect(f).Port(remotePort).Ensure() + }) +}) diff --git a/test/e2e/basic/client.go b/test/e2e/basic/client.go new file mode 100644 index 0000000..2436355 --- /dev/null +++ b/test/e2e/basic/client.go @@ -0,0 +1,78 @@ +package basic + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/fatedier/frp/test/e2e/framework" + "github.com/fatedier/frp/test/e2e/framework/consts" + clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client" + + . "github.com/onsi/ginkgo" +) + +var _ = Describe("[Feature: ClientManage]", func() { + f := framework.NewDefaultFramework() + + It("Update && Reload API", func() { + serverConf := consts.DefaultServerConfig + + adminPort := f.AllocPort() + + p1Port := f.AllocPort() + p2Port := f.AllocPort() + p3Port := f.AllocPort() + + clientConf := consts.DefaultClientConfig + fmt.Sprintf(` + admin_port = %d + + [p1] + type = tcp + local_port = {{ .%s }} + remote_port = %d + + [p2] + type = tcp + local_port = {{ .%s }} + remote_port = %d + + [p3] + type = tcp + local_port = {{ .%s }} + remote_port = %d + `, adminPort, + framework.TCPEchoServerPort, p1Port, + framework.TCPEchoServerPort, p2Port, + framework.TCPEchoServerPort, p3Port) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + framework.NewRequestExpect(f).Port(p1Port).Ensure() + framework.NewRequestExpect(f).Port(p2Port).Ensure() + framework.NewRequestExpect(f).Port(p3Port).Ensure() + + client := clientsdk.New("127.0.0.1", adminPort) + conf, err := client.GetConfig() + framework.ExpectNoError(err) + + newP2Port := f.AllocPort() + // change p2 port and remove p3 proxy + newClientConf := strings.ReplaceAll(conf, strconv.Itoa(p2Port), strconv.Itoa(newP2Port)) + p3Index := strings.Index(newClientConf, "[p3]") + newClientConf = newClientConf[:p3Index] + + err = client.UpdateConfig(newClientConf) + framework.ExpectNoError(err) + + err = client.Reload() + framework.ExpectNoError(err) + time.Sleep(time.Second) + + framework.NewRequestExpect(f).Port(p1Port).Explain("p1 port").Ensure() + framework.NewRequestExpect(f).Port(p2Port).Explain("original p2 port").ExpectError(true).Ensure() + framework.NewRequestExpect(f).Port(newP2Port).Explain("new p2 port").Ensure() + framework.NewRequestExpect(f).Port(p3Port).Explain("p3 port").ExpectError(true).Ensure() + }) +}) diff --git a/test/e2e/basic/client_server.go b/test/e2e/basic/client_server.go index 97b97fc..bc2431b 100644 --- a/test/e2e/basic/client_server.go +++ b/test/e2e/basic/client_server.go @@ -49,7 +49,7 @@ func defineClientServerTest(desc string, f *framework.Framework, configures *gen f.RunProcesses([]string{serverConf}, []string{clientConf}) framework.NewRequestExpect(f).PortName(tcpPortName).ExpectError(configures.expectError).Explain("tcp proxy").Ensure() - framework.NewRequestExpect(f).RequestModify(framework.SetRequestProtocol("udp")). + framework.NewRequestExpect(f).Protocol("udp"). PortName(udpPortName).ExpectError(configures.expectError).Explain("udp proxy").Ensure() }) } diff --git a/test/e2e/basic/cmd.go b/test/e2e/basic/cmd.go new file mode 100644 index 0000000..562310f --- /dev/null +++ b/test/e2e/basic/cmd.go @@ -0,0 +1,113 @@ +package basic + +import ( + "fmt" + "strconv" + "strings" + + "github.com/fatedier/frp/test/e2e/framework" + "github.com/fatedier/frp/test/e2e/pkg/request" + + . "github.com/onsi/ginkgo" +) + +const ( + ConfigValidStr = "syntax is ok" +) + +var _ = Describe("[Feature: Cmd]", func() { + f := framework.NewDefaultFramework() + + Describe("Verify", func() { + It("frps valid", func() { + path := f.GenerateConfigFile(` + [common] + bind_addr = 0.0.0.0 + bind_port = 7000 + `) + _, output, err := f.RunFrps("verify", "-c", path) + framework.ExpectNoError(err) + framework.ExpectTrue(strings.Contains(output, ConfigValidStr), "output: %s", output) + }) + It("frps invalid", func() { + path := f.GenerateConfigFile(` + [common] + bind_addr = 0.0.0.0 + bind_port = 70000 + `) + _, output, err := f.RunFrps("verify", "-c", path) + framework.ExpectNoError(err) + framework.ExpectTrue(!strings.Contains(output, ConfigValidStr), "output: %s", output) + }) + It("frpc valid", func() { + path := f.GenerateConfigFile(` + [common] + server_addr = 0.0.0.0 + server_port = 7000 + `) + _, output, err := f.RunFrpc("verify", "-c", path) + framework.ExpectNoError(err) + framework.ExpectTrue(strings.Contains(output, ConfigValidStr), "output: %s", output) + }) + It("frpc invalid", func() { + path := f.GenerateConfigFile(` + [common] + server_addr = 0.0.0.0 + server_port = 7000 + protocol = invalid + `) + _, output, err := f.RunFrpc("verify", "-c", path) + framework.ExpectNoError(err) + framework.ExpectTrue(!strings.Contains(output, ConfigValidStr), "output: %s", output) + }) + }) + + Describe("Single proxy", func() { + It("TCP", func() { + serverPort := f.AllocPort() + _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort)) + framework.ExpectNoError(err) + + localPort := f.PortByName(framework.TCPEchoServerPort) + remotePort := f.AllocPort() + _, _, err = f.RunFrpc("tcp", "-s", fmt.Sprintf("127.0.0.1:%d", serverPort), "-t", "123", "-u", "test", + "-l", strconv.Itoa(localPort), "-r", strconv.Itoa(remotePort), "-n", "tcp_test") + framework.ExpectNoError(err) + + framework.NewRequestExpect(f).Port(remotePort).Ensure() + }) + + It("UDP", func() { + serverPort := f.AllocPort() + _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort)) + framework.ExpectNoError(err) + + localPort := f.PortByName(framework.UDPEchoServerPort) + remotePort := f.AllocPort() + _, _, err = f.RunFrpc("udp", "-s", fmt.Sprintf("127.0.0.1:%d", serverPort), "-t", "123", "-u", "test", + "-l", strconv.Itoa(localPort), "-r", strconv.Itoa(remotePort), "-n", "udp_test") + framework.ExpectNoError(err) + + framework.NewRequestExpect(f).Protocol("udp"). + Port(remotePort).Ensure() + }) + + It("HTTP", func() { + serverPort := f.AllocPort() + vhostHTTPPort := f.AllocPort() + _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort), "--vhost_http_port", strconv.Itoa(vhostHTTPPort)) + framework.ExpectNoError(err) + + _, _, err = f.RunFrpc("http", "-s", "127.0.0.1:"+strconv.Itoa(serverPort), "-t", "123", "-u", "test", + "-n", "udp_test", "-l", strconv.Itoa(f.PortByName(framework.HTTPSimpleServerPort)), + "--custom_domain", "test.example.com") + framework.ExpectNoError(err) + + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("test.example.com") + }). + Ensure() + }) + }) +}) diff --git a/test/e2e/basic/config.go b/test/e2e/basic/config.go new file mode 100644 index 0000000..d21bc57 --- /dev/null +++ b/test/e2e/basic/config.go @@ -0,0 +1,83 @@ +package basic + +import ( + "fmt" + + "github.com/fatedier/frp/test/e2e/framework" + "github.com/fatedier/frp/test/e2e/framework/consts" + "github.com/fatedier/frp/test/e2e/pkg/port" + + . "github.com/onsi/ginkgo" +) + +var _ = Describe("[Feature: Config]", func() { + f := framework.NewDefaultFramework() + + Describe("Template", func() { + It("render by env", func() { + serverConf := consts.DefaultServerConfig + clientConf := consts.DefaultClientConfig + + portName := port.GenName("TCP") + serverConf += fmt.Sprintf(` + token = {{ %s{{ .Envs.FRP_TOKEN }}%s }} + `, "`", "`") + + clientConf += fmt.Sprintf(` + token = {{ %s{{ .Envs.FRP_TOKEN }}%s }} + + [tcp] + type = tcp + local_port = {{ .%s }} + remote_port = {{ .%s }} + `, "`", "`", framework.TCPEchoServerPort, portName) + + f.SetEnvs([]string{"FRP_TOKEN=123"}) + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + framework.NewRequestExpect(f).PortName(portName).Ensure() + }) + }) + + Describe("Includes", func() { + It("split tcp proxies into different files", func() { + serverPort := f.AllocPort() + serverConfigPath := f.GenerateConfigFile(fmt.Sprintf(` + [common] + bind_addr = 0.0.0.0 + bind_port = %d + `, serverPort)) + + remotePort := f.AllocPort() + proxyConfigPath := f.GenerateConfigFile(fmt.Sprintf(` + [tcp] + type = tcp + local_port = %d + remote_port = %d + `, f.PortByName(framework.TCPEchoServerPort), remotePort)) + + remotePort2 := f.AllocPort() + proxyConfigPath2 := f.GenerateConfigFile(fmt.Sprintf(` + [tcp2] + type = tcp + local_port = %d + remote_port = %d + `, f.PortByName(framework.TCPEchoServerPort), remotePort2)) + + clientConfigPath := f.GenerateConfigFile(fmt.Sprintf(` + [common] + server_port = %d + includes = %s,%s + `, serverPort, proxyConfigPath, proxyConfigPath2)) + + _, _, err := f.RunFrps("-c", serverConfigPath) + framework.ExpectNoError(err) + + _, _, err = f.RunFrpc("-c", clientConfigPath) + framework.ExpectNoError(err) + + framework.NewRequestExpect(f).Port(remotePort).Ensure() + framework.NewRequestExpect(f).Port(remotePort2).Ensure() + }) + }) +}) diff --git a/test/e2e/basic/group.go b/test/e2e/basic/group.go new file mode 100644 index 0000000..423977d --- /dev/null +++ b/test/e2e/basic/group.go @@ -0,0 +1,238 @@ +package basic + +import ( + "fmt" + "strconv" + "sync" + "time" + + "github.com/fatedier/frp/test/e2e/framework" + "github.com/fatedier/frp/test/e2e/framework/consts" + "github.com/fatedier/frp/test/e2e/mock/server/httpserver" + "github.com/fatedier/frp/test/e2e/mock/server/streamserver" + "github.com/fatedier/frp/test/e2e/pkg/request" + + . "github.com/onsi/ginkgo" +) + +var _ = Describe("[Feature: Group]", func() { + f := framework.NewDefaultFramework() + + newHTTPServer := func(port int, respContent string) *httpserver.Server { + return httpserver.New( + httpserver.WithBindPort(port), + httpserver.WithHandler(framework.SpecifiedHTTPBodyHandler([]byte(respContent))), + ) + } + + validateFooBarResponse := func(resp *request.Response) bool { + if string(resp.Content) == "foo" || string(resp.Content) == "bar" { + return true + } + return false + } + + doFooBarHTTPRequest := func(vhostPort int, host string) []string { + results := []string{} + var wait sync.WaitGroup + var mu sync.Mutex + expectFn := func() { + framework.NewRequestExpect(f).Port(vhostPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost(host) + }). + Ensure(validateFooBarResponse, func(resp *request.Response) bool { + mu.Lock() + defer mu.Unlock() + results = append(results, string(resp.Content)) + return true + }) + } + for i := 0; i < 10; i++ { + wait.Add(1) + go func() { + defer wait.Done() + expectFn() + }() + } + + wait.Wait() + return results + } + + Describe("Load Balancing", func() { + It("TCP", func() { + serverConf := consts.DefaultServerConfig + clientConf := consts.DefaultClientConfig + + fooPort := f.AllocPort() + fooServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(fooPort), streamserver.WithRespContent([]byte("foo"))) + f.RunServer("", fooServer) + + barPort := f.AllocPort() + barServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(barPort), streamserver.WithRespContent([]byte("bar"))) + f.RunServer("", barServer) + + remotePort := f.AllocPort() + clientConf += fmt.Sprintf(` + [foo] + type = tcp + local_port = %d + remote_port = %d + group = test + group_key = 123 + + [bar] + type = tcp + local_port = %d + remote_port = %d + group = test + group_key = 123 + `, fooPort, remotePort, barPort, remotePort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + fooCount := 0 + barCount := 0 + for i := 0; i < 10; i++ { + framework.NewRequestExpect(f).Explain("times " + strconv.Itoa(i)).Port(remotePort).Ensure(func(resp *request.Response) bool { + switch string(resp.Content) { + case "foo": + fooCount++ + case "bar": + barCount++ + default: + return false + } + return true + }) + } + + framework.ExpectTrue(fooCount > 1 && barCount > 1, "fooCount: %d, barCount: %d", fooCount, barCount) + }) + }) + + Describe("Health Check", func() { + It("TCP", func() { + serverConf := consts.DefaultServerConfig + clientConf := consts.DefaultClientConfig + + fooPort := f.AllocPort() + fooServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(fooPort), streamserver.WithRespContent([]byte("foo"))) + f.RunServer("", fooServer) + + barPort := f.AllocPort() + barServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(barPort), streamserver.WithRespContent([]byte("bar"))) + f.RunServer("", barServer) + + remotePort := f.AllocPort() + clientConf += fmt.Sprintf(` + [foo] + type = tcp + local_port = %d + remote_port = %d + group = test + group_key = 123 + health_check_type = tcp + health_check_interval_s = 1 + + [bar] + type = tcp + local_port = %d + remote_port = %d + group = test + group_key = 123 + health_check_type = tcp + health_check_interval_s = 1 + `, fooPort, remotePort, barPort, remotePort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // check foo and bar is ok + results := []string{} + for i := 0; i < 10; i++ { + framework.NewRequestExpect(f).Port(remotePort).Ensure(validateFooBarResponse, func(resp *request.Response) bool { + results = append(results, string(resp.Content)) + return true + }) + } + framework.ExpectContainElements(results, []string{"foo", "bar"}) + + // close bar server, check foo is ok + barServer.Close() + time.Sleep(2 * time.Second) + for i := 0; i < 10; i++ { + framework.NewRequestExpect(f).Port(remotePort).ExpectResp([]byte("foo")).Ensure() + } + + // resume bar server, check foo and bar is ok + f.RunServer("", barServer) + time.Sleep(2 * time.Second) + results = []string{} + for i := 0; i < 10; i++ { + framework.NewRequestExpect(f).Port(remotePort).Ensure(validateFooBarResponse, func(resp *request.Response) bool { + results = append(results, string(resp.Content)) + return true + }) + } + framework.ExpectContainElements(results, []string{"foo", "bar"}) + }) + + It("HTTP", func() { + vhostPort := f.AllocPort() + serverConf := consts.DefaultServerConfig + fmt.Sprintf(` + vhost_http_port = %d + `, vhostPort) + clientConf := consts.DefaultClientConfig + + fooPort := f.AllocPort() + fooServer := newHTTPServer(fooPort, "foo") + f.RunServer("", fooServer) + + barPort := f.AllocPort() + barServer := newHTTPServer(barPort, "bar") + f.RunServer("", barServer) + + clientConf += fmt.Sprintf(` + [foo] + type = http + local_port = %d + custom_domains = example.com + group = test + group_key = 123 + health_check_type = http + health_check_interval_s = 1 + health_check_url = /healthz + + [bar] + type = http + local_port = %d + custom_domains = example.com + group = test + group_key = 123 + health_check_type = http + health_check_interval_s = 1 + health_check_url = /healthz + `, fooPort, barPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // check foo and bar is ok + results := doFooBarHTTPRequest(vhostPort, "example.com") + framework.ExpectContainElements(results, []string{"foo", "bar"}) + + // close bar server, check foo is ok + barServer.Close() + time.Sleep(2 * time.Second) + results = doFooBarHTTPRequest(vhostPort, "example.com") + framework.ExpectContainElements(results, []string{"foo"}) + framework.ExpectNotContainElements(results, []string{"bar"}) + + // resume bar server, check foo and bar is ok + f.RunServer("", barServer) + time.Sleep(2 * time.Second) + results = doFooBarHTTPRequest(vhostPort, "example.com") + framework.ExpectContainElements(results, []string{"foo", "bar"}) + }) + }) +}) diff --git a/test/e2e/basic/http.go b/test/e2e/basic/http.go new file mode 100644 index 0000000..f94c004 --- /dev/null +++ b/test/e2e/basic/http.go @@ -0,0 +1,326 @@ +package basic + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + + "github.com/fatedier/frp/test/e2e/framework" + "github.com/fatedier/frp/test/e2e/framework/consts" + "github.com/fatedier/frp/test/e2e/mock/server/httpserver" + "github.com/fatedier/frp/test/e2e/pkg/request" + "github.com/fatedier/frp/test/e2e/pkg/utils" + + "github.com/gorilla/websocket" + . "github.com/onsi/ginkgo" +) + +var _ = Describe("[Feature: HTTP]", func() { + f := framework.NewDefaultFramework() + + getDefaultServerConf := func(vhostHTTPPort int) string { + conf := consts.DefaultServerConfig + ` + vhost_http_port = %d + ` + return fmt.Sprintf(conf, vhostHTTPPort) + } + newHTTPServer := func(port int, respContent string) *httpserver.Server { + return httpserver.New( + httpserver.WithBindPort(port), + httpserver.WithHandler(framework.SpecifiedHTTPBodyHandler([]byte(respContent))), + ) + } + + It("HTTP route by locations", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + + fooPort := f.AllocPort() + f.RunServer("", newHTTPServer(fooPort, "foo")) + + barPort := f.AllocPort() + f.RunServer("", newHTTPServer(barPort, "bar")) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [foo] + type = http + local_port = %d + custom_domains = normal.example.com + locations = /,/foo + + [bar] + type = http + local_port = %d + custom_domains = normal.example.com + locations = /bar + `, fooPort, barPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // foo path + framework.NewRequestExpect(f).Explain("foo path").Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com").HTTPPath("/foo") + }). + ExpectResp([]byte("foo")). + Ensure() + + // bar path + framework.NewRequestExpect(f).Explain("bar path").Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com").HTTPPath("/bar") + }). + ExpectResp([]byte("bar")). + Ensure() + + // other path + framework.NewRequestExpect(f).Explain("other path").Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com").HTTPPath("/other") + }). + ExpectResp([]byte("foo")). + Ensure() + }) + + It("HTTP Basic Auth", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [test] + type = http + local_port = {{ .%s }} + custom_domains = normal.example.com + http_user = test + http_pwd = test + `, framework.HTTPSimpleServerPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // not set auth header + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com") + }). + Ensure(framework.ExpectResponseCode(401)) + + // set incorrect auth header + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com").HTTPHeaders(map[string]string{ + "Authorization": utils.BasicAuth("test", "invalid"), + }) + }). + Ensure(framework.ExpectResponseCode(401)) + + // set correct auth header + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com").HTTPHeaders(map[string]string{ + "Authorization": utils.BasicAuth("test", "test"), + }) + }). + Ensure() + }) + + It("Wildcard domain", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [test] + type = http + local_port = {{ .%s }} + custom_domains = *.example.com + `, framework.HTTPSimpleServerPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // not match host + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("not-match.test.com") + }). + Ensure(framework.ExpectResponseCode(404)) + + // test.example.com match *.example.com + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("test.example.com") + }). + Ensure() + + // sub.test.example.com match *.example.com + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("sub.test.example.com") + }). + Ensure() + }) + + It("Subdomain", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + serverConf += ` + subdomain_host = example.com + ` + + fooPort := f.AllocPort() + f.RunServer("", newHTTPServer(fooPort, "foo")) + + barPort := f.AllocPort() + f.RunServer("", newHTTPServer(barPort, "bar")) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [foo] + type = http + local_port = %d + subdomain = foo + + [bar] + type = http + local_port = %d + subdomain = bar + `, fooPort, barPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // foo + framework.NewRequestExpect(f).Explain("foo subdomain").Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("foo.example.com") + }). + ExpectResp([]byte("foo")). + Ensure() + + // bar + framework.NewRequestExpect(f).Explain("bar subdomain").Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("bar.example.com") + }). + ExpectResp([]byte("bar")). + Ensure() + }) + + It("Modify headers", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + + localPort := f.AllocPort() + localServer := httpserver.New( + httpserver.WithBindPort(localPort), + httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(req.Header.Get("X-From-Where"))) + })), + ) + f.RunServer("", localServer) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [test] + type = http + local_port = %d + custom_domains = normal.example.com + header_X-From-Where = frp + `, localPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // not set auth header + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com") + }). + ExpectResp([]byte("frp")). // local http server will write this X-From-Where header to response body + Ensure() + }) + + It("Host Header Rewrite", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + + localPort := f.AllocPort() + localServer := httpserver.New( + httpserver.WithBindPort(localPort), + httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(req.Host)) + })), + ) + f.RunServer("", localServer) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [test] + type = http + local_port = %d + custom_domains = normal.example.com + host_header_rewrite = rewrite.example.com + `, localPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + framework.NewRequestExpect(f).Port(vhostHTTPPort). + RequestModify(func(r *request.Request) { + r.HTTP().HTTPHost("normal.example.com") + }). + ExpectResp([]byte("rewrite.example.com")). // local http server will write host header to response body + Ensure() + }) + + It("websocket", func() { + vhostHTTPPort := f.AllocPort() + serverConf := getDefaultServerConf(vhostHTTPPort) + + upgrader := websocket.Upgrader{} + + localPort := f.AllocPort() + localServer := httpserver.New( + httpserver.WithBindPort(localPort), + httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + c, err := upgrader.Upgrade(w, req, nil) + if err != nil { + return + } + defer c.Close() + for { + mt, message, err := c.ReadMessage() + if err != nil { + break + } + err = c.WriteMessage(mt, message) + if err != nil { + break + } + } + })), + ) + + f.RunServer("", localServer) + + clientConf := consts.DefaultClientConfig + clientConf += fmt.Sprintf(` + [test] + type = http + local_port = %d + custom_domains = 127.0.0.1 + `, localPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + u := url.URL{Scheme: "ws", Host: "127.0.0.1:" + strconv.Itoa(vhostHTTPPort)} + c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) + framework.ExpectNoError(err) + + err = c.WriteMessage(websocket.TextMessage, []byte(consts.TestString)) + framework.ExpectNoError(err) + + _, msg, err := c.ReadMessage() + framework.ExpectNoError(err) + framework.ExpectEqualValues(consts.TestString, string(msg)) + }) +}) diff --git a/test/e2e/basic/server.go b/test/e2e/basic/server.go index ed979c5..34d4b5d 100644 --- a/test/e2e/basic/server.go +++ b/test/e2e/basic/server.go @@ -2,11 +2,14 @@ package basic import ( "fmt" + "net" + "strconv" "github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/pkg/port" "github.com/fatedier/frp/test/e2e/pkg/request" + clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client" . "github.com/onsi/ginkgo" ) @@ -19,10 +22,10 @@ var _ = Describe("[Feature: Server Manager]", func() { clientConf := consts.DefaultClientConfig serverConf += ` - allow_ports = 10000-20000,20002,30000-50000 + allow_ports = 20000-25000,25002,30000-50000 ` - tcpPortName := port.GenName("TCP", port.WithRangePorts(10000, 20000)) + tcpPortName := port.GenName("TCP", port.WithRangePorts(20000, 25000)) udpPortName := port.GenName("UDP", port.WithRangePorts(30000, 50000)) clientConf += fmt.Sprintf(` [tcp-allowded-in-range] @@ -62,18 +65,62 @@ var _ = Describe("[Feature: Server Manager]", func() { framework.NewRequestExpect(f).PortName(tcpPortName).Ensure() // Not Allowed - framework.NewRequestExpect(f).RequestModify(framework.SetRequestPort(20001)).ExpectError(true).Ensure() + framework.NewRequestExpect(f).Port(25003).ExpectError(true).Ensure() // Unavailable, already bind by frps framework.NewRequestExpect(f).PortName(consts.PortServerName).ExpectError(true).Ensure() // UDP // Allowed in range - framework.NewRequestExpect(f).RequestModify(framework.SetRequestProtocol("udp")).PortName(udpPortName).Ensure() + framework.NewRequestExpect(f).Protocol("udp").PortName(udpPortName).Ensure() // Not Allowed framework.NewRequestExpect(f).RequestModify(func(r *request.Request) { - r.UDP().Port(20003) + r.UDP().Port(25003) }).ExpectError(true).Ensure() }) + + It("Alloc Random Port", func() { + serverConf := consts.DefaultServerConfig + clientConf := consts.DefaultClientConfig + + adminPort := f.AllocPort() + clientConf += fmt.Sprintf(` + admin_port = %d + + [tcp] + type = tcp + local_port = {{ .%s }} + + [udp] + type = udp + local_port = {{ .%s }} + `, adminPort, framework.TCPEchoServerPort, framework.UDPEchoServerPort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + client := clientsdk.New("127.0.0.1", adminPort) + + // tcp random port + status, err := client.GetProxyStatus("tcp") + framework.ExpectNoError(err) + + _, portStr, err := net.SplitHostPort(status.RemoteAddr) + framework.ExpectNoError(err) + port, err := strconv.Atoi(portStr) + framework.ExpectNoError(err) + + framework.NewRequestExpect(f).Port(port).Ensure() + + // udp random port + status, err = client.GetProxyStatus("udp") + framework.ExpectNoError(err) + + _, portStr, err = net.SplitHostPort(status.RemoteAddr) + framework.ExpectNoError(err) + port, err = strconv.Atoi(portStr) + framework.ExpectNoError(err) + + framework.NewRequestExpect(f).Protocol("udp").Port(port).Ensure() + }) }) diff --git a/test/e2e/examples.go b/test/e2e/examples.go index 7512e14..6423aec 100644 --- a/test/e2e/examples.go +++ b/test/e2e/examples.go @@ -5,7 +5,6 @@ import ( "github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework/consts" - "github.com/fatedier/frp/test/e2e/pkg/port" . "github.com/onsi/ginkgo" ) @@ -18,17 +17,17 @@ var _ = Describe("[Feature: Example]", func() { serverConf := consts.DefaultServerConfig clientConf := consts.DefaultClientConfig - portName := port.GenName("TCP") + remotePort := f.AllocPort() clientConf += fmt.Sprintf(` [tcp] type = tcp local_port = {{ .%s }} - remote_port = {{ .%s }} - `, framework.TCPEchoServerPort, portName) + remote_port = %d + `, framework.TCPEchoServerPort, remotePort) f.RunProcesses([]string{serverConf}, []string{clientConf}) - framework.NewRequestExpect(f).PortName(portName).Ensure() + framework.NewRequestExpect(f).Port(remotePort).Ensure() }) }) }) diff --git a/test/e2e/framework/expect.go b/test/e2e/framework/expect.go index d2058e7..dab6da7 100644 --- a/test/e2e/framework/expect.go +++ b/test/e2e/framework/expect.go @@ -14,6 +14,10 @@ func ExpectEqualValues(actual interface{}, extra interface{}, explain ...interfa gomega.ExpectWithOffset(1, actual).To(gomega.BeEquivalentTo(extra), explain...) } +func ExpectEqualValuesWithOffset(offset int, actual interface{}, extra interface{}, explain ...interface{}) { + gomega.ExpectWithOffset(1+offset, actual).To(gomega.BeEquivalentTo(extra), explain...) +} + // ExpectNotEqual expects the specified two are not the same, otherwise an exception raises func ExpectNotEqual(actual interface{}, extra interface{}, explain ...interface{}) { gomega.ExpectWithOffset(1, actual).NotTo(gomega.Equal(extra), explain...) @@ -24,6 +28,10 @@ func ExpectError(err error, explain ...interface{}) { gomega.ExpectWithOffset(1, err).To(gomega.HaveOccurred(), explain...) } +func ExpectErrorWithOffset(offset int, err error, explain ...interface{}) { + gomega.ExpectWithOffset(1+offset, err).To(gomega.HaveOccurred(), explain...) +} + // ExpectNoError checks if "err" is set, and if so, fails assertion while logging the error. func ExpectNoError(err error, explain ...interface{}) { ExpectNoErrorWithOffset(1, err, explain...) @@ -40,6 +48,14 @@ func ExpectConsistOf(actual interface{}, extra interface{}, explain ...interface gomega.ExpectWithOffset(1, actual).To(gomega.ConsistOf(extra), explain...) } +func ExpectContainElements(actual interface{}, extra interface{}, explain ...interface{}) { + gomega.ExpectWithOffset(1, actual).To(gomega.ContainElements(extra), explain...) +} + +func ExpectNotContainElements(actual interface{}, extra interface{}, explain ...interface{}) { + gomega.ExpectWithOffset(1, actual).NotTo(gomega.ContainElements(extra), explain...) +} + // ExpectHaveKey expects the actual map has the key in the keyset func ExpectHaveKey(actual interface{}, key interface{}, explain ...interface{}) { gomega.ExpectWithOffset(1, actual).To(gomega.HaveKey(key), explain...) @@ -53,3 +69,7 @@ func ExpectEmpty(actual interface{}, explain ...interface{}) { func ExpectTrue(actual interface{}, explain ...interface{}) { gomega.ExpectWithOffset(1, actual).Should(gomega.BeTrue(), explain...) } + +func ExpectTrueWithOffset(offset int, actual interface{}, explain ...interface{}) { + gomega.ExpectWithOffset(1+offset, actual).Should(gomega.BeTrue(), explain...) +} diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index ed1bfe6..c5a7b52 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -30,6 +30,9 @@ type Framework struct { // ports used in this framework indexed by port name. usedPorts map[string]int + // record ports alloced by this framework and release them after each test + allocedPorts []int + // portAllocator to alloc port for this test case. portAllocator *port.Allocator @@ -50,7 +53,13 @@ type Framework struct { clientProcesses []*process.Process // Manual registered mock servers. - servers []*server.Server + servers []server.Server + + // used to generate unique config file name. + configFileIndex int64 + + // envs used to start processes, the form is `key=value`. + osEnvs []string } func NewDefaultFramework() *Framework { @@ -80,7 +89,7 @@ func (f *Framework) BeforeEach() { f.cleanupHandle = AddCleanupAction(f.AfterEach) - dir, err := ioutil.TempDir(os.TempDir(), "frpe2e-test-*") + dir, err := ioutil.TempDir(os.TempDir(), "frp-e2e-test-*") ExpectNoError(err) f.TempDirectory = dir @@ -88,6 +97,14 @@ func (f *Framework) BeforeEach() { if err := f.mockServers.Run(); err != nil { Failf("%v", err) } + + params := f.mockServers.GetTemplateParams() + for k, v := range params { + switch t := v.(type) { + case int: + f.usedPorts[k] = int(t) + } + } } func (f *Framework) AfterEach() { @@ -126,14 +143,23 @@ func (f *Framework) AfterEach() { // clean directory os.RemoveAll(f.TempDirectory) f.TempDirectory = "" - f.serverConfPaths = nil - f.clientConfPaths = nil + f.serverConfPaths = []string{} + f.clientConfPaths = []string{} // release used ports for _, port := range f.usedPorts { f.portAllocator.Release(port) } f.usedPorts = make(map[string]int) + + // release alloced ports + for _, port := range f.allocedPorts { + f.portAllocator.Release(port) + } + f.allocedPorts = make([]int, 0) + + // clear os envs + f.osEnvs = make([]string, 0) } var portRegex = regexp.MustCompile(`{{ \.Port.*? }}`) @@ -210,6 +236,7 @@ func (f *Framework) PortByName(name string) int { func (f *Framework) AllocPort() int { port := f.portAllocator.Get() ExpectTrue(port > 0, "alloc port failed") + f.allocedPorts = append(f.allocedPorts, port) return port } @@ -217,11 +244,15 @@ func (f *Framework) ReleasePort(port int) { f.portAllocator.Release(port) } -func (f *Framework) RunServer(portName string, s *server.Server) { +func (f *Framework) RunServer(portName string, s server.Server) { f.servers = append(f.servers, s) - if s.BindPort() > 0 { + if s.BindPort() > 0 && portName != "" { f.usedPorts[portName] = s.BindPort() } err := s.Run() - ExpectNoError(err, portName) + ExpectNoError(err, "RunServer: with PortName %s", portName) +} + +func (f *Framework) SetEnvs(envs []string) { + f.osEnvs = envs } diff --git a/test/e2e/framework/mockservers.go b/test/e2e/framework/mockservers.go index 1935a2b..e6a2cd4 100644 --- a/test/e2e/framework/mockservers.go +++ b/test/e2e/framework/mockservers.go @@ -2,35 +2,45 @@ package framework import ( "fmt" + "net/http" "os" + "github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/mock/server" + "github.com/fatedier/frp/test/e2e/mock/server/httpserver" + "github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/pkg/port" ) const ( - TCPEchoServerPort = "TCPEchoServerPort" - UDPEchoServerPort = "UDPEchoServerPort" - UDSEchoServerAddr = "UDSEchoServerAddr" + TCPEchoServerPort = "TCPEchoServerPort" + UDPEchoServerPort = "UDPEchoServerPort" + UDSEchoServerAddr = "UDSEchoServerAddr" + HTTPSimpleServerPort = "HTTPSimpleServerPort" ) type MockServers struct { - tcpEchoServer *server.Server - udpEchoServer *server.Server - udsEchoServer *server.Server + tcpEchoServer server.Server + udpEchoServer server.Server + udsEchoServer server.Server + httpSimpleServer server.Server } func NewMockServers(portAllocator *port.Allocator) *MockServers { s := &MockServers{} tcpPort := portAllocator.Get() udpPort := portAllocator.Get() - s.tcpEchoServer = server.New(server.TCP, server.WithBindPort(tcpPort), server.WithEchoMode(true)) - s.udpEchoServer = server.New(server.UDP, server.WithBindPort(udpPort), server.WithEchoMode(true)) + httpPort := portAllocator.Get() + s.tcpEchoServer = streamserver.New(streamserver.TCP, streamserver.WithBindPort(tcpPort), streamserver.WithEchoMode(true)) + s.udpEchoServer = streamserver.New(streamserver.UDP, streamserver.WithBindPort(udpPort), streamserver.WithEchoMode(true)) + s.httpSimpleServer = httpserver.New(httpserver.WithBindPort(httpPort), httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(consts.TestString)) + }))) udsIndex := portAllocator.Get() udsAddr := fmt.Sprintf("%s/frp_echo_server_%d.sock", os.TempDir(), udsIndex) os.Remove(udsAddr) - s.udsEchoServer = server.New(server.Unix, server.WithBindAddr(udsAddr), server.WithEchoMode(true)) + s.udsEchoServer = streamserver.New(streamserver.Unix, streamserver.WithBindAddr(udsAddr), streamserver.WithEchoMode(true)) return s } @@ -44,6 +54,9 @@ func (m *MockServers) Run() error { if err := m.udsEchoServer.Run(); err != nil { return err } + if err := m.httpSimpleServer.Run(); err != nil { + return err + } return nil } @@ -51,6 +64,7 @@ func (m *MockServers) Close() { m.tcpEchoServer.Close() m.udpEchoServer.Close() m.udsEchoServer.Close() + m.httpSimpleServer.Close() os.Remove(m.udsEchoServer.BindAddr()) } @@ -59,6 +73,7 @@ func (m *MockServers) GetTemplateParams() map[string]interface{} { ret[TCPEchoServerPort] = m.tcpEchoServer.BindPort() ret[UDPEchoServerPort] = m.udpEchoServer.BindPort() ret[UDSEchoServerAddr] = m.udsEchoServer.BindAddr() + ret[HTTPSimpleServerPort] = m.httpSimpleServer.BindPort() return ret } diff --git a/test/e2e/framework/process.go b/test/e2e/framework/process.go index 40df9c9..6a98864 100644 --- a/test/e2e/framework/process.go +++ b/test/e2e/framework/process.go @@ -10,10 +10,6 @@ import ( "github.com/fatedier/frp/test/e2e/pkg/process" ) -func GenerateConfigFile(path string, content string) error { - return ioutil.WriteFile(path, []byte(content), 0666) -} - // RunProcesses run multiple processes from templates. // The first template should always be frps. func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []string) { @@ -37,7 +33,8 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str err = ioutil.WriteFile(path, []byte(outs[i]), 0666) ExpectNoError(err) flog.Trace("[%s] %s", path, outs[i]) - p := process.New(TestContext.FRPServerPath, []string{"-c", path}) + + p := process.NewWithEnvs(TestContext.FRPServerPath, []string{"-c", path}, f.osEnvs) f.serverConfPaths = append(f.serverConfPaths, path) f.serverProcesses = append(f.serverProcesses, p) err = p.Start() @@ -51,7 +48,8 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str err = ioutil.WriteFile(path, []byte(outs[index]), 0666) ExpectNoError(err) flog.Trace("[%s] %s", path, outs[index]) - p := process.New(TestContext.FRPClientPath, []string{"-c", path}) + + p := process.NewWithEnvs(TestContext.FRPClientPath, []string{"-c", path}, f.osEnvs) f.clientConfPaths = append(f.clientConfPaths, path) f.clientProcesses = append(f.clientProcesses, p) err = p.Start() @@ -60,3 +58,34 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str } time.Sleep(500 * time.Millisecond) } + +func (f *Framework) RunFrps(args ...string) (*process.Process, string, error) { + p := process.NewWithEnvs(TestContext.FRPServerPath, args, f.osEnvs) + f.serverProcesses = append(f.serverProcesses, p) + err := p.Start() + if err != nil { + return p, p.StdOutput(), err + } + // sleep for a while to get std output + time.Sleep(500 * time.Millisecond) + return p, p.StdOutput(), nil +} + +func (f *Framework) RunFrpc(args ...string) (*process.Process, string, error) { + p := process.NewWithEnvs(TestContext.FRPClientPath, args, f.osEnvs) + f.clientProcesses = append(f.clientProcesses, p) + err := p.Start() + if err != nil { + return p, p.StdOutput(), err + } + time.Sleep(500 * time.Millisecond) + return p, p.StdOutput(), nil +} + +func (f *Framework) GenerateConfigFile(content string) string { + f.configFileIndex++ + path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-config-%d", f.configFileIndex)) + err := ioutil.WriteFile(path, []byte(content), 0666) + ExpectNoError(err) + return path +} diff --git a/test/e2e/framework/request.go b/test/e2e/framework/request.go index 847f1aa..fd677a1 100644 --- a/test/e2e/framework/request.go +++ b/test/e2e/framework/request.go @@ -1,38 +1,35 @@ package framework import ( + "bytes" + "net/http" + + flog "github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/pkg/request" ) -func SetRequestProtocol(protocol string) func(*request.Request) { - return func(r *request.Request) { - r.Protocol(protocol) +func SpecifiedHTTPBodyHandler(body []byte) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + w.Write(body) } } -func SetRequestPort(port int) func(*request.Request) { - return func(r *request.Request) { - r.Port(port) +func ExpectResponseCode(code int) EnsureFunc { + return func(resp *request.Response) bool { + return resp.Code == code } } -// NewRequest return a default TCP request with default timeout and content. +// NewRequest return a default request with default timeout and content. func NewRequest() *request.Request { return request.New(). Timeout(consts.DefaultTimeout). Body([]byte(consts.TestString)) } -func ExpectResponse(req *request.Request, expectResp []byte, explain ...interface{}) { - ret, err := req.Do() - ExpectNoError(err, explain...) - ExpectEqualValues(expectResp, ret, explain...) -} - -func ExpectResponseError(req *request.Request, explain ...interface{}) { - _, err := req.Do() - ExpectError(err, explain...) +func NewHTTPRequest() *request.Request { + return request.New().HTTP().HTTPParams("GET", "", "/", nil) } type RequestExpect struct { @@ -59,6 +56,11 @@ func (e *RequestExpect) RequestModify(f func(r *request.Request)) *RequestExpect return e } +func (e *RequestExpect) Protocol(protocol string) *RequestExpect { + e.req.Protocol(protocol) + return e +} + func (e *RequestExpect) PortName(name string) *RequestExpect { if e.f != nil { e.req.Port(e.f.PortByName(name)) @@ -66,6 +68,13 @@ func (e *RequestExpect) PortName(name string) *RequestExpect { return e } +func (e *RequestExpect) Port(port int) *RequestExpect { + if e.f != nil { + e.req.Port(port) + } + return e +} + func (e *RequestExpect) ExpectResp(resp []byte) *RequestExpect { e.expectResp = resp return e @@ -81,10 +90,32 @@ func (e *RequestExpect) Explain(explain ...interface{}) *RequestExpect { return e } -func (e *RequestExpect) Ensure() { +type EnsureFunc func(*request.Response) bool + +func (e *RequestExpect) Ensure(fns ...EnsureFunc) { + ret, err := e.req.Do() if e.expectError { - ExpectResponseError(e.req, e.explain...) + ExpectErrorWithOffset(1, err, e.explain...) + return + } + ExpectNoErrorWithOffset(1, err, e.explain...) + + if len(fns) == 0 { + if !bytes.Equal(e.expectResp, ret.Content) { + flog.Trace("Response info: %+v", ret) + } + ExpectEqualValuesWithOffset(1, e.expectResp, ret.Content, e.explain...) } else { - ExpectResponse(e.req, e.expectResp, e.explain...) + for _, fn := range fns { + ok := fn(ret) + if !ok { + flog.Trace("Response info: %+v", ret) + } + ExpectTrueWithOffset(1, ok, e.explain...) + } } } + +func (e *RequestExpect) Do() (*request.Response, error) { + return e.req.Do() +} diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index 5f99a89..841288c 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -9,6 +9,5 @@ import ( var RunID string func init() { - uuid, _ := uuid.NewUUID() - RunID = uuid.String() + RunID = uuid.NewString() } diff --git a/test/e2e/mock/server/httpserver/server.go b/test/e2e/mock/server/httpserver/server.go new file mode 100644 index 0000000..0550f6d --- /dev/null +++ b/test/e2e/mock/server/httpserver/server.go @@ -0,0 +1,86 @@ +package httpserver + +import ( + "fmt" + "net" + "net/http" + "strconv" +) + +type Server struct { + bindAddr string + bindPort int + hanlder http.Handler + + l net.Listener + hs *http.Server +} + +type Option func(*Server) *Server + +func New(options ...Option) *Server { + s := &Server{ + bindAddr: "127.0.0.1", + } + + for _, option := range options { + s = option(s) + } + return s +} + +func WithBindAddr(addr string) Option { + return func(s *Server) *Server { + s.bindAddr = addr + return s + } +} + +func WithBindPort(port int) Option { + return func(s *Server) *Server { + s.bindPort = port + return s + } +} + +func WithHandler(h http.Handler) Option { + return func(s *Server) *Server { + s.hanlder = h + return s + } +} + +func (s *Server) Run() error { + if err := s.initListener(); err != nil { + return err + } + + addr := net.JoinHostPort(s.bindAddr, strconv.Itoa(s.bindPort)) + hs := &http.Server{ + Addr: addr, + Handler: s.hanlder, + } + s.hs = hs + go hs.Serve(s.l) + return nil +} + +func (s *Server) Close() error { + if s.hs != nil { + return s.hs.Close() + } + return nil +} + +func (s *Server) initListener() (err error) { + s.l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.bindAddr, s.bindPort)) + return +} + +func (s *Server) BindAddr() string { + return s.bindAddr +} + +func (s *Server) BindPort() int { + return s.bindPort +} diff --git a/test/e2e/mock/server/interface.go b/test/e2e/mock/server/interface.go new file mode 100644 index 0000000..f1f320a --- /dev/null +++ b/test/e2e/mock/server/interface.go @@ -0,0 +1,8 @@ +package server + +type Server interface { + Run() error + Close() error + BindAddr() string + BindPort() int +} diff --git a/test/e2e/mock/server/server.go b/test/e2e/mock/server/streamserver/server.go similarity index 91% rename from test/e2e/mock/server/server.go rename to test/e2e/mock/server/streamserver/server.go index 5ce7307..1714721 100644 --- a/test/e2e/mock/server/server.go +++ b/test/e2e/mock/server/streamserver/server.go @@ -1,4 +1,4 @@ -package server +package streamserver import ( "fmt" @@ -7,16 +7,16 @@ import ( libnet "github.com/fatedier/frp/pkg/util/net" ) -type ServerType string +type Type string const ( - TCP ServerType = "tcp" - UDP ServerType = "udp" - Unix ServerType = "unix" + TCP Type = "tcp" + UDP Type = "udp" + Unix Type = "unix" ) type Server struct { - netType ServerType + netType Type bindAddr string bindPort int respContent []byte @@ -29,7 +29,7 @@ type Server struct { type Option func(*Server) *Server -func New(netType ServerType, options ...Option) *Server { +func New(netType Type, options ...Option) *Server { s := &Server{ netType: netType, bindAddr: "127.0.0.1", diff --git a/test/e2e/pkg/port/port.go b/test/e2e/pkg/port/port.go index 1812e90..dc9e101 100644 --- a/test/e2e/pkg/port/port.go +++ b/test/e2e/pkg/port/port.go @@ -22,6 +22,7 @@ func NewAllocator(from int, to int, mod int, index int) *Allocator { reserved: sets.NewInt(), used: sets.NewInt(), } + for i := from; i <= to; i++ { if i%mod == index { pa.reserved.Insert(i) @@ -50,7 +51,7 @@ func (pa *Allocator) GetByName(portName string) int { pa.mu.Lock() defer pa.mu.Unlock() - for i := 0; i < 10; i++ { + for i := 0; i < 20; i++ { port := pa.getByRange(builder.rangePortFrom, builder.rangePortTo) if port == 0 { return 0 diff --git a/test/e2e/pkg/process/process.go b/test/e2e/pkg/process/process.go index 6417276..e6721e1 100644 --- a/test/e2e/pkg/process/process.go +++ b/test/e2e/pkg/process/process.go @@ -13,11 +13,17 @@ type Process struct { stdOutput *bytes.Buffer beforeStopHandler func() + stopped bool } func New(path string, params []string) *Process { + return NewWithEnvs(path, params, nil) +} + +func NewWithEnvs(path string, params []string, envs []string) *Process { ctx, cancel := context.WithCancel(context.Background()) cmd := exec.CommandContext(ctx, path, params...) + cmd.Env = envs p := &Process{ cmd: cmd, cancel: cancel, @@ -34,6 +40,12 @@ func (p *Process) Start() error { } func (p *Process) Stop() error { + if p.stopped { + return nil + } + defer func() { + p.stopped = true + }() if p.beforeStopHandler != nil { p.beforeStopHandler() } diff --git a/test/e2e/pkg/request/request.go b/test/e2e/pkg/request/request.go index 4b25bf5..68a5572 100644 --- a/test/e2e/pkg/request/request.go +++ b/test/e2e/pkg/request/request.go @@ -1,26 +1,44 @@ package request import ( + "bytes" "fmt" + "io" + "io/ioutil" "net" + "net/http" + "net/url" + "strconv" "time" libnet "github.com/fatedier/golib/net" ) type Request struct { - protocol string - addr string - port int - body []byte - timeout time.Duration - proxyURL string - proxyHost string + protocol string + + // for all protocol + addr string + port int + body []byte + timeout time.Duration + + // for http + method string + host string + path string + headers map[string]string + + proxyURL string } func New() *Request { return &Request{ protocol: "tcp", + addr: "127.0.0.1", + + method: "GET", + path: "/", } } @@ -39,9 +57,13 @@ func (r *Request) UDP() *Request { return r } -func (r *Request) Proxy(url, host string) *Request { +func (r *Request) HTTP() *Request { + r.protocol = "http" + return r +} + +func (r *Request) Proxy(url string) *Request { r.proxyURL = url - r.proxyHost = host return r } @@ -55,6 +77,29 @@ func (r *Request) Port(port int) *Request { return r } +func (r *Request) HTTPParams(method, host, path string, headers map[string]string) *Request { + r.method = method + r.host = host + r.path = path + r.headers = headers + return r +} + +func (r *Request) HTTPHost(host string) *Request { + r.host = host + return r +} + +func (r *Request) HTTPPath(path string) *Request { + r.path = path + return r +} + +func (r *Request) HTTPHeaders(headers map[string]string) *Request { + r.headers = headers + return r +} + func (r *Request) Timeout(timeout time.Duration) *Request { r.timeout = timeout return r @@ -65,28 +110,34 @@ func (r *Request) Body(content []byte) *Request { return r } -func (r *Request) Do() ([]byte, error) { +func (r *Request) Do() (*Response, error) { var ( conn net.Conn err error ) + + addr := net.JoinHostPort(r.addr, strconv.Itoa(r.port)) + // for protocol http + if r.protocol == "http" { + return sendHTTPRequest(r.method, fmt.Sprintf("http://%s%s", addr, r.path), + r.host, r.headers, r.proxyURL, r.body) + } + + // for protocol tcp and udp if len(r.proxyURL) > 0 { if r.protocol != "tcp" { return nil, fmt.Errorf("only tcp protocol is allowed for proxy") } - conn, err = libnet.DialTcpByProxy(r.proxyURL, r.proxyHost) + conn, err = libnet.DialTcpByProxy(r.proxyURL, addr) if err != nil { return nil, err } } else { - if r.addr == "" { - r.addr = fmt.Sprintf("127.0.0.1:%d", r.port) - } switch r.protocol { case "tcp": - conn, err = net.Dial("tcp", r.addr) + conn, err = net.Dial("tcp", addr) case "udp": - conn, err = net.Dial("udp", r.addr) + conn, err = net.Dial("udp", addr) default: return nil, fmt.Errorf("invalid protocol") } @@ -99,29 +150,63 @@ func (r *Request) Do() ([]byte, error) { if r.timeout > 0 { conn.SetDeadline(time.Now().Add(r.timeout)) } - return sendRequestByConn(conn, r.body) + buf, err := sendRequestByConn(conn, r.body) + if err != nil { + return nil, err + } + return &Response{Content: buf}, nil } -func SendTCPRequest(port int, content []byte, timeout time.Duration) ([]byte, error) { - c, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port)) - if err != nil { - return nil, fmt.Errorf("connect to tcp server error: %v", err) - } - defer c.Close() - - c.SetDeadline(time.Now().Add(timeout)) - return sendRequestByConn(c, content) +type Response struct { + Code int + Header http.Header + Content []byte } -func SendUDPRequest(port int, content []byte, timeout time.Duration) ([]byte, error) { - c, err := net.Dial("udp", fmt.Sprintf("127.0.0.1:%d", port)) - if err != nil { - return nil, fmt.Errorf("connect to udp server error: %v", err) +func sendHTTPRequest(method, urlstr string, host string, headers map[string]string, proxy string, body []byte) (*Response, error) { + var inBody io.Reader + if len(body) != 0 { + inBody = bytes.NewReader(body) + } + req, err := http.NewRequest(method, urlstr, inBody) + if err != nil { + return nil, err + } + if host != "" { + req.Host = host + } + for k, v := range headers { + req.Header.Set(k, v) + } + tr := &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } + if len(proxy) != 0 { + tr.Proxy = func(req *http.Request) (*url.URL, error) { + return url.Parse(proxy) + } + } + client := http.Client{Transport: tr} + resp, err := client.Do(req) + if err != nil { + return nil, err } - defer c.Close() - c.SetDeadline(time.Now().Add(timeout)) - return sendRequestByConn(c, content) + ret := &Response{Code: resp.StatusCode, Header: resp.Header} + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + ret.Content = buf + return ret, nil } func sendRequestByConn(c net.Conn, content []byte) ([]byte, error) { diff --git a/test/e2e/pkg/sdk/client/client.go b/test/e2e/pkg/sdk/client/client.go new file mode 100644 index 0000000..b708d60 --- /dev/null +++ b/test/e2e/pkg/sdk/client/client.go @@ -0,0 +1,133 @@ +package client + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "strconv" + "strings" + + "github.com/fatedier/frp/client" + "github.com/fatedier/frp/test/e2e/pkg/utils" +) + +type Client struct { + address string + authUser string + authPwd string +} + +func New(host string, port int) *Client { + return &Client{ + address: net.JoinHostPort(host, strconv.Itoa(port)), + } +} + +func (c *Client) SetAuth(user, pwd string) { + c.authUser = user + c.authPwd = pwd +} + +func (c *Client) GetProxyStatus(name string) (*client.ProxyStatusResp, error) { + req, err := http.NewRequest("GET", "http://"+c.address+"/api/status", nil) + if err != nil { + return nil, err + } + content, err := c.do(req) + if err != nil { + return nil, err + } + allStatus := &client.StatusResp{} + if err = json.Unmarshal([]byte(content), &allStatus); err != nil { + return nil, fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(content)) + } + for _, s := range allStatus.TCP { + if s.Name == name { + return &s, nil + } + } + for _, s := range allStatus.UDP { + if s.Name == name { + return &s, nil + } + } + for _, s := range allStatus.HTTP { + if s.Name == name { + return &s, nil + } + } + for _, s := range allStatus.HTTPS { + if s.Name == name { + return &s, nil + } + } + for _, s := range allStatus.STCP { + if s.Name == name { + return &s, nil + } + } + for _, s := range allStatus.XTCP { + if s.Name == name { + return &s, nil + } + } + for _, s := range allStatus.SUDP { + if s.Name == name { + return &s, nil + } + } + return nil, fmt.Errorf("no proxy status found") +} + +func (c *Client) Reload() error { + req, err := http.NewRequest("GET", "http://"+c.address+"/api/reload", nil) + if err != nil { + return err + } + _, err = c.do(req) + return err +} + +func (c *Client) GetConfig() (string, error) { + req, err := http.NewRequest("GET", "http://"+c.address+"/api/config", nil) + if err != nil { + return "", err + } + return c.do(req) +} + +func (c *Client) UpdateConfig(content string) error { + req, err := http.NewRequest("PUT", "http://"+c.address+"/api/config", strings.NewReader(content)) + if err != nil { + return err + } + _, err = c.do(req) + return err +} + +func (c *Client) setAuthHeader(req *http.Request) { + if c.authUser != "" || c.authPwd != "" { + req.Header.Set("Authorization", utils.BasicAuth(c.authUser, c.authPwd)) + } +} + +func (c *Client) do(req *http.Request) (string, error) { + c.setAuthHeader(req) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + return "", fmt.Errorf("api status code [%d]", resp.StatusCode) + } + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(buf), nil +} diff --git a/test/e2e/pkg/utils/utils.go b/test/e2e/pkg/utils/utils.go new file mode 100644 index 0000000..7b177e1 --- /dev/null +++ b/test/e2e/pkg/utils/utils.go @@ -0,0 +1,10 @@ +package utils + +import ( + "encoding/base64" +) + +func BasicAuth(username, passwd string) string { + auth := username + ":" + passwd + return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) +} diff --git a/test/e2e/plugin/client_plugins.go b/test/e2e/plugin/client_plugins.go index 21851f9..2b7c7a8 100644 --- a/test/e2e/plugin/client_plugins.go +++ b/test/e2e/plugin/client_plugins.go @@ -2,10 +2,12 @@ package plugin import ( "fmt" + "strconv" "github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/pkg/port" + "github.com/fatedier/frp/test/e2e/pkg/request" . "github.com/onsi/ginkgo" ) @@ -65,12 +67,40 @@ var _ = Describe("[Feature: Client-Plugins]", func() { f.RunProcesses([]string{serverConf}, []string{clientConf}) for _, test := range tests { - framework.ExpectResponse( - framework.NewRequest().Port(f.PortByName(test.portName)), - []byte(consts.TestString), - test.proxyName, - ) + framework.NewRequestExpect(f).Port(f.PortByName(test.portName)).Ensure() } }) }) + + It("plugin http_proxy", func() { + serverConf := consts.DefaultServerConfig + clientConf := consts.DefaultClientConfig + + remotePort := f.AllocPort() + clientConf += fmt.Sprintf(` + [tcp] + type = tcp + remote_port = %d + plugin = http_proxy + plugin_http_user = abc + plugin_http_passwd = 123 + `, remotePort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + // http proxy, no auth info + framework.NewRequestExpect(f).PortName(framework.HTTPSimpleServerPort).RequestModify(func(r *request.Request) { + r.HTTP().Proxy("http://127.0.0.1:" + strconv.Itoa(remotePort)) + }).Ensure(framework.ExpectResponseCode(407)) + + // http proxy, correct auth + framework.NewRequestExpect(f).PortName(framework.HTTPSimpleServerPort).RequestModify(func(r *request.Request) { + r.HTTP().Proxy("http://abc:123@127.0.0.1:" + strconv.Itoa(remotePort)) + }).Ensure() + + // connect TCP server by CONNECT method + framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) { + r.TCP().Proxy("http://abc:123@127.0.0.1:" + strconv.Itoa(remotePort)) + }) + }) }) diff --git a/tests/ci/auto_test_frpc.ini b/tests/ci/auto_test_frpc.ini deleted file mode 100644 index e99704b..0000000 --- a/tests/ci/auto_test_frpc.ini +++ /dev/null @@ -1,204 +0,0 @@ -[common] -server_addr = 127.0.0.1 -server_port = 10700 -log_file = console -log_level = trace -token = 123456 -admin_port = 10600 -admin_user = abc -admin_pwd = abc - -[tcp_normal] -type = tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 10801 - -[tcp_ec] -type = tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 10901 -use_encryption = true -use_compression = true - -[tcp_group1] -type = tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 10802 -group = test1 -group_key = 123 - -[tcp_group2] -type = tcp -local_ip = 127.0.0.1 -local_port = 10702 -remote_port = 10802 -group = test1 -group_key = 123 - -[udp_normal] -type = udp -local_ip = 127.0.0.1 -local_port = 10702 -remote_port = 10802 - -[udp_ec] -type = udp -local_ip = 127.0.0.1 -local_port = 10702 -remote_port = 10902 -use_encryption = true -use_compression = true - -[unix_domain] -type = tcp -remote_port = 10803 -plugin = unix_domain_socket -plugin_unix_path = /tmp/frp_echo_server.sock - -[stcp] -type = stcp -sk = abcdefg -local_ip = 127.0.0.1 -local_port = 10701 - -[stcp_ec] -type = stcp -sk = abc -local_ip = 127.0.0.1 -local_port = 10701 -use_encryption = true -use_compression = true - -[sudp] -type = sudp -sk = abcdefg -local_ip = 127.0.0.1 -local_port = 10702 - -[web01] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = 127.0.0.1 - -[web02] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = test2.frp.com -host_header_rewrite = test2.frp.com -use_encryption = true -use_compression = true - -[web03] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = test3.frp.com -use_encryption = true -use_compression = true -host_header_rewrite = test3.frp.com -locations = /,/foo - -[web04] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = test3.frp.com -use_encryption = true -use_compression = true -host_header_rewrite = test3.frp.com -locations = /bar - -[web05] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = test5.frp.com -host_header_rewrite = test5.frp.com -use_encryption = true -use_compression = true -http_user = test -http_user = test - -[web06] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = test6.frp.com -host_header_rewrite = test6.frp.com -header_X-From-Where = frp - -[wildcard_http] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -custom_domains = *.frp1.com - -[subhost01] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -subdomain = test01 - -[subhost02] -type = http -local_ip = 127.0.0.1 -local_port = 10704 -subdomain = test02 - -[tcp_port_not_allowed] -type = tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 20001 - -[tcp_port_unavailable] -type =tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 10700 - -[tcp_port_normal] -type = tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 20002 - -[tcp_random_port] -type = tcp -local_ip = 127.0.0.1 -local_port = 10701 -remote_port = 0 - -[udp_port_not_allowed] -type = udp -local_ip = 127.0.0.1 -local_port = 10702 -remote_port = 20001 - -[udp_port_normal] -type = udp -local_ip = 127.0.0.1 -local_port = 10702 -remote_port = 20002 - -[udp_random_port] -type = udp -local_ip = 127.0.0.1 -local_port = 10702 -remote_port = 0 - -[http_proxy] -type = tcp -plugin = http_proxy -remote_port = 0 - -[range:range_tcp] -type = tcp -local_ip = 127.0.0.1 -local_port = 30000-30001,30003 -remote_port = 30000-30001,30003 diff --git a/tests/ci/auto_test_frpc_visitor.ini b/tests/ci/auto_test_frpc_visitor.ini deleted file mode 100644 index 2ed3af5..0000000 --- a/tests/ci/auto_test_frpc_visitor.ini +++ /dev/null @@ -1,34 +0,0 @@ -[common] -server_addr = 0.0.0.0 -server_port = 10700 -log_file = console -# debug, info, warn, error -log_level = debug -token = 123456 - -[stcp_visitor] -type = stcp -role = visitor -server_name = stcp -sk = abcdefg -bind_addr = 127.0.0.1 -bind_port = 10805 - -[stcp_ec_visitor] -type = stcp -role = visitor -server_name = stcp_ec -sk = abc -bind_addr = 127.0.0.1 -bind_port = 10905 -use_encryption = true -use_compression = true - - -[sudp_visitor] -type = sudp -role = visitor -server_name = sudp -sk = abcdefg -bind_addr = 127.0.0.1 -bind_port = 10816 diff --git a/tests/ci/auto_test_frps.ini b/tests/ci/auto_test_frps.ini deleted file mode 100644 index 25f7d13..0000000 --- a/tests/ci/auto_test_frps.ini +++ /dev/null @@ -1,9 +0,0 @@ -[common] -bind_addr = 0.0.0.0 -bind_port = 10700 -vhost_http_port = 10804 -tcpmux_httpconnect_port = 10806 -log_level = trace -token = 123456 -allow_ports = 10000-20000,20002,30000-50000 -subdomain_host = sub.com diff --git a/tests/ci/cmd_test.go b/tests/ci/cmd_test.go deleted file mode 100644 index 4a98c44..0000000 --- a/tests/ci/cmd_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package ci - -import ( - "testing" - "time" - - "github.com/fatedier/frp/tests/consts" - "github.com/fatedier/frp/tests/util" - - "github.com/stretchr/testify/assert" -) - -func TestCmdTCP(t *testing.T) { - assert := assert.New(t) - - var err error - s := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-t", "123", "-p", "20000"}) - err = s.Start() - if assert.NoError(err) { - defer s.Stop() - } - time.Sleep(500 * time.Millisecond) - - c := util.NewProcess(consts.FRPC_BIN_PATH, []string{"tcp", "-s", "127.0.0.1:20000", "-t", "123", "-u", "test", - "-l", "10701", "-r", "20801", "-n", "tcp_test"}) - err = c.Start() - if assert.NoError(err) { - defer c.Stop() - } - time.Sleep(500 * time.Millisecond) - - res, err := util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) -} - -func TestCmdUDP(t *testing.T) { - assert := assert.New(t) - - var err error - s := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-t", "123", "-p", "20000"}) - err = s.Start() - if assert.NoError(err) { - defer s.Stop() - } - time.Sleep(500 * time.Millisecond) - - c := util.NewProcess(consts.FRPC_BIN_PATH, []string{"udp", "-s", "127.0.0.1:20000", "-t", "123", "-u", "test", - "-l", "10702", "-r", "20802", "-n", "udp_test"}) - err = c.Start() - if assert.NoError(err) { - defer c.Stop() - } - time.Sleep(500 * time.Millisecond) - - res, err := util.SendUDPMsg("127.0.0.1:20802", consts.TEST_UDP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_UDP_ECHO_STR, res) -} - -func TestCmdHTTP(t *testing.T) { - assert := assert.New(t) - - var err error - s := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-t", "123", "-p", "20000", "--vhost_http_port", "20001"}) - err = s.Start() - if assert.NoError(err) { - defer s.Stop() - } - time.Sleep(500 * time.Millisecond) - - c := util.NewProcess(consts.FRPC_BIN_PATH, []string{"http", "-s", "127.0.0.1:20000", "-t", "123", "-u", "test", - "-n", "udp_test", "-l", "10704", "--custom_domain", "127.0.0.1"}) - err = c.Start() - if assert.NoError(err) { - defer c.Stop() - } - time.Sleep(500 * time.Millisecond) - - code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:20001", "", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } -} diff --git a/tests/ci/health/health_test.go b/tests/ci/health/health_test.go deleted file mode 100644 index 102511a..0000000 --- a/tests/ci/health/health_test.go +++ /dev/null @@ -1,309 +0,0 @@ -package health - -import ( - "net/http" - "os" - "strings" - "sync" - "testing" - "time" - - "github.com/fatedier/frp/tests/config" - "github.com/fatedier/frp/tests/consts" - "github.com/fatedier/frp/tests/mock" - "github.com/fatedier/frp/tests/util" - - "github.com/stretchr/testify/assert" -) - -const FRPS_CONF = ` -[common] -bind_addr = 0.0.0.0 -bind_port = 14000 -vhost_http_port = 14000 -log_file = console -log_level = debug -token = 123456 -` - -const FRPC_CONF = ` -[common] -server_addr = 127.0.0.1 -server_port = 14000 -log_file = console -log_level = debug -token = 123456 - -[tcp1] -type = tcp -local_port = 15001 -remote_port = 15000 -group = test -group_key = 123 -health_check_type = tcp -health_check_interval_s = 1 - -[tcp2] -type = tcp -local_port = 15002 -remote_port = 15000 -group = test -group_key = 123 -health_check_type = tcp -health_check_interval_s = 1 - -[http1] -type = http -local_port = 15003 -custom_domains = test1.com -health_check_type = http -health_check_interval_s = 1 -health_check_url = /health - -[http2] -type = http -local_port = 15004 -custom_domains = test2.com -health_check_type = http -health_check_interval_s = 1 -health_check_url = /health - -[http3] -type = http -local_port = 15005 -custom_domains = test.balancing.com -group = test-balancing -group_key = 123 - -[http4] -type = http -local_port = 15006 -custom_domains = test.balancing.com -group = test-balancing -group_key = 123 -` - -func TestHealthCheck(t *testing.T) { - assert := assert.New(t) - - // ****** start background services ****** - echoSvc1 := mock.NewEchoServer(15001, 1, "echo1") - err := echoSvc1.Start() - if assert.NoError(err) { - defer echoSvc1.Stop() - } - - echoSvc2 := mock.NewEchoServer(15002, 1, "echo2") - err = echoSvc2.Start() - if assert.NoError(err) { - defer echoSvc2.Stop() - } - - var healthMu sync.RWMutex - svc1Health := true - svc2Health := true - httpSvc1 := mock.NewHTTPServer(15003, func(w http.ResponseWriter, r *http.Request) { - if strings.Contains(r.URL.Path, "health") { - healthMu.RLock() - defer healthMu.RUnlock() - if svc1Health { - w.WriteHeader(200) - } else { - w.WriteHeader(500) - } - } else { - w.Write([]byte("http1")) - } - }) - err = httpSvc1.Start() - if assert.NoError(err) { - defer httpSvc1.Stop() - } - - httpSvc2 := mock.NewHTTPServer(15004, func(w http.ResponseWriter, r *http.Request) { - if strings.Contains(r.URL.Path, "health") { - healthMu.RLock() - defer healthMu.RUnlock() - if svc2Health { - w.WriteHeader(200) - } else { - w.WriteHeader(500) - } - } else { - w.Write([]byte("http2")) - } - }) - err = httpSvc2.Start() - if assert.NoError(err) { - defer httpSvc2.Stop() - } - - httpSvc3 := mock.NewHTTPServer(15005, func(w http.ResponseWriter, r *http.Request) { - time.Sleep(time.Second) - w.Write([]byte("http3")) - }) - err = httpSvc3.Start() - if assert.NoError(err) { - defer httpSvc3.Stop() - } - - httpSvc4 := mock.NewHTTPServer(15006, func(w http.ResponseWriter, r *http.Request) { - time.Sleep(time.Second) - w.Write([]byte("http4")) - }) - err = httpSvc4.Start() - if assert.NoError(err) { - defer httpSvc4.Stop() - } - - time.Sleep(200 * time.Millisecond) - - // ****** start frps and frpc ****** - frpsCfgPath, err := config.GenerateConfigFile(consts.FRPS_NORMAL_CONFIG, FRPS_CONF) - if assert.NoError(err) { - defer os.Remove(frpsCfgPath) - } - - frpcCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_CONF) - if assert.NoError(err) { - defer os.Remove(frpcCfgPath) - } - - frpsProcess := util.NewProcess(consts.FRPS_SUB_BIN_PATH, []string{"-c", frpsCfgPath}) - err = frpsProcess.Start() - if assert.NoError(err) { - defer frpsProcess.Stop() - } - - time.Sleep(500 * time.Millisecond) - - frpcProcess := util.NewProcess(consts.FRPC_SUB_BIN_PATH, []string{"-c", frpcCfgPath}) - err = frpcProcess.Start() - if assert.NoError(err) { - defer frpcProcess.Stop() - } - time.Sleep(1000 * time.Millisecond) - - // ****** healcheck type tcp ****** - // echo1 and echo2 is ok - result := make([]string, 0) - res, err := util.SendTCPMsg("127.0.0.1:15000", "echo") - assert.NoError(err) - result = append(result, res) - - res, err = util.SendTCPMsg("127.0.0.1:15000", "echo") - assert.NoError(err) - result = append(result, res) - - assert.Contains(result, "echo1") - assert.Contains(result, "echo2") - - // close echo2 server, echo1 is work - echoSvc2.Stop() - time.Sleep(1200 * time.Millisecond) - - result = make([]string, 0) - res, err = util.SendTCPMsg("127.0.0.1:15000", "echo") - assert.NoError(err) - result = append(result, res) - - res, err = util.SendTCPMsg("127.0.0.1:15000", "echo") - assert.NoError(err) - result = append(result, res) - - assert.NotContains(result, "echo2") - - // resume echo2 server, all services are ok - echoSvc2 = mock.NewEchoServer(15002, 1, "echo2") - err = echoSvc2.Start() - if assert.NoError(err) { - defer echoSvc2.Stop() - } - - time.Sleep(1200 * time.Millisecond) - - result = make([]string, 0) - res, err = util.SendTCPMsg("127.0.0.1:15000", "echo") - assert.NoError(err) - result = append(result, res) - - res, err = util.SendTCPMsg("127.0.0.1:15000", "echo") - assert.NoError(err) - result = append(result, res) - - assert.Contains(result, "echo1") - assert.Contains(result, "echo2") - - // ****** healcheck type http ****** - // http1 and http2 is ok - code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test1.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - assert.Equal("http1", body) - - code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test2.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - assert.Equal("http2", body) - - // http2 health check error - healthMu.Lock() - svc2Health = false - healthMu.Unlock() - time.Sleep(1200 * time.Millisecond) - - code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test1.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - assert.Equal("http1", body) - - code, _, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test2.com", nil, "") - assert.NoError(err) - assert.Equal(404, code) - - // resume http2 service, http1 and http2 are ok - healthMu.Lock() - svc2Health = true - healthMu.Unlock() - time.Sleep(1200 * time.Millisecond) - - code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test1.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - assert.Equal("http1", body) - - code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test2.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - assert.Equal("http2", body) - - // ****** load balancing type http ****** - result = make([]string, 0) - var wait sync.WaitGroup - var mu sync.Mutex - wait.Add(2) - - go func() { - defer wait.Done() - code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - mu.Lock() - result = append(result, body) - mu.Unlock() - }() - - go func() { - defer wait.Done() - code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "") - assert.NoError(err) - assert.Equal(200, code) - mu.Lock() - result = append(result, body) - mu.Unlock() - }() - wait.Wait() - - assert.Contains(result, "http3") - assert.Contains(result, "http4") -} diff --git a/tests/ci/normal_test.go b/tests/ci/normal_test.go deleted file mode 100644 index f304321..0000000 --- a/tests/ci/normal_test.go +++ /dev/null @@ -1,250 +0,0 @@ -package ci - -import ( - "fmt" - "net/http" - "net/url" - "os" - "testing" - "time" - - "github.com/gorilla/websocket" - "github.com/stretchr/testify/assert" - - "github.com/fatedier/frp/client/proxy" - "github.com/fatedier/frp/tests/consts" - "github.com/fatedier/frp/tests/mock" - "github.com/fatedier/frp/tests/util" - - gnet "github.com/fatedier/golib/net" -) - -func TestMain(m *testing.M) { - var err error - tcpEcho1 := mock.NewEchoServer(consts.TEST_TCP_PORT, 1, "") - tcpEcho2 := mock.NewEchoServer(consts.TEST_TCP2_PORT, 2, "") - - if err = tcpEcho1.Start(); err != nil { - panic(err) - } - if err = tcpEcho2.Start(); err != nil { - panic(err) - } - - go mock.StartUDPEchoServer(consts.TEST_UDP_PORT) - go mock.StartUnixDomainServer(consts.TEST_UNIX_DOMAIN_ADDR) - go mock.StartHTTPServer(consts.TEST_HTTP_PORT) - - p1 := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-c", "./auto_test_frps.ini"}) - if err = p1.Start(); err != nil { - panic(err) - } - - time.Sleep(500 * time.Millisecond) - p2 := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", "./auto_test_frpc.ini"}) - if err = p2.Start(); err != nil { - panic(err) - } - - p3 := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", "./auto_test_frpc_visitor.ini"}) - if err = p3.Start(); err != nil { - panic(err) - } - time.Sleep(500 * time.Millisecond) - - exitCode := m.Run() - p1.Stop() - p2.Stop() - p3.Stop() - os.Exit(exitCode) -} - -func TestHTTP(t *testing.T) { - assert := assert.New(t) - // web01 - code, body, _, err := util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } - - // web02 - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test2.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } - - // error host header - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "errorhost.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(404, code) - } - - // web03 - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test3.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } - - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d/foo", consts.TEST_HTTP_FRP_PORT), "test3.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_FOO_STR, body) - } - - // web04 - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d/bar", consts.TEST_HTTP_FRP_PORT), "test3.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_BAR_STR, body) - } - - // web05 - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test5.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(401, code) - } - - headers := make(map[string]string) - headers["Authorization"] = util.BasicAuth("test", "test") - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test5.frp.com", headers, "") - if assert.NoError(err) { - assert.Equal(401, code) - } - - // web06 - var header http.Header - code, body, header, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test6.frp.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - assert.Equal("true", header.Get("X-Header-Set")) - } - - // wildcard_http - // test.frp1.com match *.frp1.com - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test.frp1.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } - - // new.test.frp1.com also match *.frp1.com - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "new.test.frp1.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } - - // subhost01 - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test01.sub.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal("test01.sub.com", body) - } - - // subhost02 - code, body, _, err = util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), "test02.sub.com", nil, "") - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal("test02.sub.com", body) - } -} - -func TestWebSocket(t *testing.T) { - assert := assert.New(t) - - u := url.URL{Scheme: "ws", Host: fmt.Sprintf("%s:%d", "127.0.0.1", consts.TEST_HTTP_FRP_PORT), Path: "/ws"} - c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) - assert.NoError(err) - defer c.Close() - - err = c.WriteMessage(websocket.TextMessage, []byte(consts.TEST_HTTP_NORMAL_STR)) - assert.NoError(err) - - _, msg, err := c.ReadMessage() - assert.NoError(err) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, string(msg)) -} - -func TestRandomPort(t *testing.T) { - assert := assert.New(t) - // tcp - status, err := util.GetProxyStatus(consts.ADMIN_ADDR, consts.ADMIN_USER, consts.ADMIN_PWD, consts.ProxyTCPRandomPort) - if assert.NoError(err) { - addr := status.RemoteAddr - res, err := util.SendTCPMsg(addr, consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - } - - // udp - status, err = util.GetProxyStatus(consts.ADMIN_ADDR, consts.ADMIN_USER, consts.ADMIN_PWD, consts.ProxyUDPRandomPort) - if assert.NoError(err) { - addr := status.RemoteAddr - res, err := util.SendUDPMsg(addr, consts.TEST_UDP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_UDP_ECHO_STR, res) - } -} - -func TestPluginHTTPProxy(t *testing.T) { - assert := assert.New(t) - status, err := util.GetProxyStatus(consts.ADMIN_ADDR, consts.ADMIN_USER, consts.ADMIN_PWD, consts.ProxyHTTPProxy) - if assert.NoError(err) { - assert.Equal(proxy.ProxyPhaseRunning, status.Status) - - // http proxy - addr := status.RemoteAddr - code, body, _, err := util.SendHTTPMsg("GET", fmt.Sprintf("http://127.0.0.1:%d", consts.TEST_HTTP_FRP_PORT), - "", nil, "http://"+addr) - if assert.NoError(err) { - assert.Equal(200, code) - assert.Equal(consts.TEST_HTTP_NORMAL_STR, body) - } - - // connect method - conn, err := gnet.DialTcpByProxy("http://"+addr, fmt.Sprintf("127.0.0.1:%d", consts.TEST_TCP_FRP_PORT)) - if assert.NoError(err) { - res, err := util.SendTCPMsgByConn(conn, consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - } - } -} - -func TestRangePortsMapping(t *testing.T) { - assert := assert.New(t) - - for i := 0; i < 3; i++ { - name := fmt.Sprintf("%s_%d", consts.ProxyRangeTCPPrefix, i) - status, err := util.GetProxyStatus(consts.ADMIN_ADDR, consts.ADMIN_USER, consts.ADMIN_PWD, name) - if assert.NoError(err) { - assert.Equal(proxy.ProxyPhaseRunning, status.Status) - } - } -} - -func TestGroup(t *testing.T) { - assert := assert.New(t) - - var ( - p1 int - p2 int - ) - addr := fmt.Sprintf("127.0.0.1:%d", consts.TEST_TCP2_FRP_PORT) - - for i := 0; i < 6; i++ { - res, err := util.SendTCPMsg(addr, consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - switch res { - case consts.TEST_TCP_ECHO_STR: - p1++ - case consts.TEST_TCP_ECHO_STR + consts.TEST_TCP_ECHO_STR: - p2++ - } - } - assert.True(p1 > 0 && p2 > 0, "group proxies load balancing") -} diff --git a/tests/ci/reconnect_test.go b/tests/ci/reconnect_test.go deleted file mode 100644 index 6455347..0000000 --- a/tests/ci/reconnect_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package ci - -import ( - "os" - "testing" - "time" - - "github.com/fatedier/frp/tests/config" - "github.com/fatedier/frp/tests/consts" - "github.com/fatedier/frp/tests/util" - - "github.com/stretchr/testify/assert" -) - -const FRPS_RECONNECT_CONF = ` -[common] -bind_addr = 0.0.0.0 -bind_port = 20000 -log_file = console -log_level = debug -token = 123456 -` - -const FRPC_RECONNECT_CONF = ` -[common] -server_addr = 127.0.0.1 -server_port = 20000 -log_file = console -log_level = debug -token = 123456 -admin_port = 21000 -admin_user = abc -admin_pwd = abc - -[tcp] -type = tcp -local_port = 10701 -remote_port = 20801 -` - -func TestReconnect(t *testing.T) { - assert := assert.New(t) - frpsCfgPath, err := config.GenerateConfigFile(consts.FRPS_NORMAL_CONFIG, FRPS_RECONNECT_CONF) - if assert.NoError(err) { - defer os.Remove(frpsCfgPath) - } - - frpcCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_RECONNECT_CONF) - if assert.NoError(err) { - defer os.Remove(frpcCfgPath) - } - - frpsProcess := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-c", frpsCfgPath}) - err = frpsProcess.Start() - if assert.NoError(err) { - defer frpsProcess.Stop() - } - - time.Sleep(500 * time.Millisecond) - - frpcProcess := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", frpcCfgPath}) - err = frpcProcess.Start() - if assert.NoError(err) { - defer frpcProcess.Stop() - } - time.Sleep(500 * time.Millisecond) - - // test tcp - res, err := util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // stop frpc - frpcProcess.Stop() - time.Sleep(200 * time.Millisecond) - - // test tcp, expect failed - _, err = util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.Error(err) - - // restart frpc - newFrpcProcess := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", frpcCfgPath}) - err = newFrpcProcess.Start() - if assert.NoError(err) { - defer newFrpcProcess.Stop() - } - time.Sleep(500 * time.Millisecond) - - // test tcp - res, err = util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // stop frps - frpsProcess.Stop() - time.Sleep(200 * time.Millisecond) - - // test tcp, expect failed - _, err = util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.Error(err) - - // restart frps - newFrpsProcess := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-c", frpsCfgPath}) - err = newFrpsProcess.Start() - if assert.NoError(err) { - defer newFrpsProcess.Stop() - } - - time.Sleep(2 * time.Second) - - // test tcp - res, err = util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) -} diff --git a/tests/ci/reload_test.go b/tests/ci/reload_test.go deleted file mode 100644 index ac160fa..0000000 --- a/tests/ci/reload_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package ci - -import ( - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/fatedier/frp/tests/config" - "github.com/fatedier/frp/tests/consts" - "github.com/fatedier/frp/tests/util" -) - -const FRPS_RELOAD_CONF = ` -[common] -bind_addr = 0.0.0.0 -bind_port = 20000 -log_file = console -# debug, info, warn, error -log_level = debug -token = 123456 -` - -const FRPC_RELOAD_CONF_1 = ` -[common] -server_addr = 127.0.0.1 -server_port = 20000 -log_file = console -# debug, info, warn, error -log_level = debug -token = 123456 -admin_port = 21000 -admin_user = abc -admin_pwd = abc - -[tcp] -type = tcp -local_port = 10701 -remote_port = 20801 - -# change remote port -[tcp2] -type = tcp -local_port = 10701 -remote_port = 20802 - -# delete -[tcp3] -type = tcp -local_port = 10701 -remote_port = 20803 -` - -const FRPC_RELOAD_CONF_2 = ` -[common] -server_addr = 127.0.0.1 -server_port = 20000 -log_file = console -# debug, info, warn, error -log_level = debug -token = 123456 -admin_port = 21000 -admin_user = abc -admin_pwd = abc - -[tcp] -type = tcp -local_port = 10701 -remote_port = 20801 - -[tcp2] -type = tcp -local_port = 10701 -remote_port = 20902 -` - -func TestReload(t *testing.T) { - assert := assert.New(t) - frpsCfgPath, err := config.GenerateConfigFile(consts.FRPS_NORMAL_CONFIG, FRPS_RELOAD_CONF) - if assert.NoError(err) { - defer os.Remove(frpsCfgPath) - } - - frpcCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_RELOAD_CONF_1) - if assert.NoError(err) { - rmFile1 := frpcCfgPath - defer os.Remove(rmFile1) - } - - frpsProcess := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-c", frpsCfgPath}) - err = frpsProcess.Start() - if assert.NoError(err) { - defer frpsProcess.Stop() - } - - time.Sleep(500 * time.Millisecond) - - frpcProcess := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", frpcCfgPath}) - err = frpcProcess.Start() - if assert.NoError(err) { - defer frpcProcess.Stop() - } - - time.Sleep(500 * time.Millisecond) - - // test tcp1 - res, err := util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // test tcp2 - res, err = util.SendTCPMsg("127.0.0.1:20802", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // test tcp3 - res, err = util.SendTCPMsg("127.0.0.1:20803", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // reload frpc config - frpcCfgPath, err = config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_RELOAD_CONF_2) - if assert.NoError(err) { - rmFile2 := frpcCfgPath - defer os.Remove(rmFile2) - } - err = util.ReloadConf("127.0.0.1:21000", "abc", "abc") - assert.NoError(err) - - time.Sleep(time.Second) - - // test tcp1 - res, err = util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // test origin tcp2, expect failed - res, err = util.SendTCPMsg("127.0.0.1:20802", consts.TEST_TCP_ECHO_STR) - assert.Error(err) - - // test new origin tcp2 with different port - res, err = util.SendTCPMsg("127.0.0.1:20902", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) - - // test tcp3, expect failed - res, err = util.SendTCPMsg("127.0.0.1:20803", consts.TEST_TCP_ECHO_STR) - assert.Error(err) -} diff --git a/tests/ci/template_test.go b/tests/ci/template_test.go deleted file mode 100644 index 0c843cd..0000000 --- a/tests/ci/template_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package ci - -import ( - "os" - "testing" - "time" - - "github.com/fatedier/frp/tests/config" - "github.com/fatedier/frp/tests/consts" - "github.com/fatedier/frp/tests/util" - - "github.com/stretchr/testify/assert" -) - -const FRPS_TEMPLATE_CONF = ` -[common] -bind_addr = 0.0.0.0 -bind_port = {{ .Envs.SERVER_PORT }} -log_file = console -# debug, info, warn, error -log_level = debug -token = 123456 -` - -const FRPC_TEMPLATE_CONF = ` -[common] -server_addr = 127.0.0.1 -server_port = 20000 -log_file = console -# debug, info, warn, error -log_level = debug -token = {{ .Envs.FRP_TOKEN }} - -[tcp] -type = tcp -local_port = 10701 -remote_port = {{ .Envs.TCP_REMOTE_PORT }} -` - -func TestConfTemplate(t *testing.T) { - assert := assert.New(t) - frpsCfgPath, err := config.GenerateConfigFile(consts.FRPS_NORMAL_CONFIG, FRPS_TEMPLATE_CONF) - if assert.NoError(err) { - defer os.Remove(frpsCfgPath) - } - - frpcCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_TEMPLATE_CONF) - if assert.NoError(err) { - defer os.Remove(frpcCfgPath) - } - - frpsProcess := util.NewProcess("env", []string{"SERVER_PORT=20000", consts.FRPS_BIN_PATH, "-c", frpsCfgPath}) - err = frpsProcess.Start() - if assert.NoError(err) { - defer frpsProcess.Stop() - } - - time.Sleep(500 * time.Millisecond) - - frpcProcess := util.NewProcess("env", []string{"FRP_TOKEN=123456", "TCP_REMOTE_PORT=20801", consts.FRPC_BIN_PATH, "-c", frpcCfgPath}) - err = frpcProcess.Start() - if assert.NoError(err) { - defer frpcProcess.Stop() - } - - time.Sleep(500 * time.Millisecond) - - // test tcp1 - res, err := util.SendTCPMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR) - assert.NoError(err) - assert.Equal(consts.TEST_TCP_ECHO_STR, res) -} diff --git a/tests/config/config.go b/tests/config/config.go deleted file mode 100644 index ac09446..0000000 --- a/tests/config/config.go +++ /dev/null @@ -1,13 +0,0 @@ -package config - -import ( - "io/ioutil" - "os" - "path/filepath" -) - -func GenerateConfigFile(path string, content string) (realPath string, err error) { - realPath = filepath.Join(os.TempDir(), path) - err = ioutil.WriteFile(realPath, []byte(content), 0666) - return realPath, err -} diff --git a/tests/consts/consts.go b/tests/consts/consts.go deleted file mode 100644 index ebe00c1..0000000 --- a/tests/consts/consts.go +++ /dev/null @@ -1,76 +0,0 @@ -package consts - -import "path/filepath" - -var ( - FRPS_BIN_PATH = "../../bin/frps" - FRPC_BIN_PATH = "../../bin/frpc" - - FRPS_SUB_BIN_PATH = "../../../bin/frps" - FRPC_SUB_BIN_PATH = "../../../bin/frpc" - - FRPS_NORMAL_CONFIG = "./auto_test_frps.ini" - FRPC_NORMAL_CONFIG = "./auto_test_frpc.ini" - - SERVER_ADDR = "127.0.0.1" - ADMIN_ADDR = "127.0.0.1:10600" - ADMIN_USER = "abc" - ADMIN_PWD = "abc" - - TEST_STR = "frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet." - TEST_TCP_PORT int = 10701 - TEST_TCP2_PORT int = 10702 - TEST_TCP_FRP_PORT int = 10801 - TEST_TCP2_FRP_PORT int = 10802 - TEST_TCP_EC_FRP_PORT int = 10901 - TEST_TCP_ECHO_STR string = "tcp type:" + TEST_STR - - TEST_UDP_PORT int = 10702 - TEST_UDP_FRP_PORT int = 10802 - TEST_UDP_EC_FRP_PORT int = 10902 - TEST_UDP_ECHO_STR string = "udp type:" + TEST_STR - - TEST_UNIX_DOMAIN_ADDR string = "/tmp/frp_echo_server.sock" - TEST_UNIX_DOMAIN_FRP_PORT int = 10803 - TEST_UNIX_DOMAIN_STR string = "unix domain type:" + TEST_STR - - TEST_HTTP_PORT int = 10704 - TEST_HTTP_FRP_PORT int = 10804 - TEST_HTTP_NORMAL_STR string = "http normal string: " + TEST_STR - TEST_HTTP_FOO_STR string = "http foo string: " + TEST_STR - TEST_HTTP_BAR_STR string = "http bar string: " + TEST_STR - - TEST_TCP_MUX_FRP_PORT int = 10806 - - TEST_STCP_FRP_PORT int = 10805 - TEST_STCP_EC_FRP_PORT int = 10905 - TEST_STCP_ECHO_STR string = "stcp type:" + TEST_STR - - TEST_SUDP_FRP_PORT int = 10816 - TEST_SUDP_ECHO_STR string = "sudp type:" + TEST_STR - - ProxyTCPPortNotAllowed string = "tcp_port_not_allowed" - ProxyTCPPortUnavailable string = "tcp_port_unavailable" - ProxyTCPPortNormal string = "tcp_port_normal" - ProxyTCPRandomPort string = "tcp_random_port" - ProxyUDPPortNotAllowed string = "udp_port_not_allowed" - ProxyUDPPortNormal string = "udp_port_normal" - ProxyUDPRandomPort string = "udp_random_port" - ProxyHTTPProxy string = "http_proxy" - - ProxyRangeTCPPrefix string = "range_tcp" -) - -func init() { - if path, err := filepath.Abs(FRPS_BIN_PATH); err != nil { - panic(err) - } else { - FRPS_BIN_PATH = path - } - - if path, err := filepath.Abs(FRPC_BIN_PATH); err != nil { - panic(err) - } else { - FRPC_BIN_PATH = path - } -} diff --git a/tests/mock/echo_server.go b/tests/mock/echo_server.go deleted file mode 100644 index 20ee183..0000000 --- a/tests/mock/echo_server.go +++ /dev/null @@ -1,120 +0,0 @@ -package mock - -import ( - "fmt" - "io" - "net" - "os" - "syscall" - - frpNet "github.com/fatedier/frp/pkg/util/net" -) - -type EchoServer struct { - l net.Listener - - port int - repeatedNum int - specifyStr string -} - -func NewEchoServer(port int, repeatedNum int, specifyStr string) *EchoServer { - if repeatedNum <= 0 { - repeatedNum = 1 - } - return &EchoServer{ - port: port, - repeatedNum: repeatedNum, - specifyStr: specifyStr, - } -} - -func (es *EchoServer) Start() error { - l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", es.port)) - if err != nil { - fmt.Printf("echo server listen error: %v\n", err) - return err - } - es.l = l - - go func() { - for { - c, err := l.Accept() - if err != nil { - return - } - - go echoWorker(c, es.repeatedNum, es.specifyStr) - } - }() - return nil -} - -func (es *EchoServer) Stop() { - es.l.Close() -} - -func StartUDPEchoServer(port int) { - l, err := frpNet.ListenUDP("127.0.0.1", port) - if err != nil { - fmt.Printf("udp echo server listen error: %v\n", err) - return - } - - for { - c, err := l.Accept() - if err != nil { - fmt.Printf("udp echo server accept error: %v\n", err) - return - } - - go echoWorker(c, 1, "") - } -} - -func StartUnixDomainServer(unixPath string) { - os.Remove(unixPath) - syscall.Umask(0) - l, err := net.Listen("unix", unixPath) - if err != nil { - fmt.Printf("unix domain server listen error: %v\n", err) - return - } - - for { - c, err := l.Accept() - if err != nil { - fmt.Printf("unix domain server accept error: %v\n", err) - return - } - - go echoWorker(c, 1, "") - } -} - -func echoWorker(c net.Conn, repeatedNum int, specifyStr string) { - buf := make([]byte, 2048) - - for { - n, err := c.Read(buf) - if err != nil { - if err == io.EOF { - c.Close() - break - } else { - fmt.Printf("echo server read error: %v\n", err) - return - } - } - - if specifyStr != "" { - c.Write([]byte(specifyStr)) - } else { - var w []byte - for i := 0; i < repeatedNum; i++ { - w = append(w, buf[:n]...) - } - c.Write(w) - } - } -} diff --git a/tests/mock/http_server.go b/tests/mock/http_server.go deleted file mode 100644 index 56fb51c..0000000 --- a/tests/mock/http_server.go +++ /dev/null @@ -1,110 +0,0 @@ -package mock - -import ( - "fmt" - "log" - "net" - "net/http" - "regexp" - "strings" - - "github.com/fatedier/frp/tests/consts" - - "github.com/gorilla/websocket" -) - -type HTTPServer struct { - l net.Listener - - port int - handler http.HandlerFunc -} - -func NewHTTPServer(port int, handler http.HandlerFunc) *HTTPServer { - return &HTTPServer{ - port: port, - handler: handler, - } -} - -func (hs *HTTPServer) Start() error { - l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", hs.port)) - if err != nil { - fmt.Printf("http server listen error: %v\n", err) - return err - } - hs.l = l - - go http.Serve(l, http.HandlerFunc(hs.handler)) - return nil -} - -func (hs *HTTPServer) Stop() { - hs.l.Close() -} - -var upgrader = websocket.Upgrader{} - -func StartHTTPServer(port int) { - http.HandleFunc("/", handleHTTP) - http.HandleFunc("/ws", handleWebSocket) - http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", port), nil) -} - -func handleWebSocket(w http.ResponseWriter, r *http.Request) { - c, err := upgrader.Upgrade(w, r, nil) - if err != nil { - log.Print("upgrade:", err) - return - } - defer c.Close() - for { - mt, message, err := c.ReadMessage() - if err != nil { - break - } - err = c.WriteMessage(mt, message) - if err != nil { - log.Println("write:", err) - break - } - } -} - -func handleHTTP(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("X-From-Where") == "frp" { - w.Header().Set("X-Header-Set", "true") - } - - match, err := regexp.Match(`.*\.sub\.com`, []byte(r.Host)) - if err != nil { - w.WriteHeader(500) - return - } - - if match { - w.WriteHeader(200) - w.Write([]byte(r.Host)) - return - } - - if strings.HasPrefix(r.Host, "127.0.0.1") || strings.HasPrefix(r.Host, "test2.frp.com") || - strings.HasPrefix(r.Host, "test5.frp.com") || strings.HasPrefix(r.Host, "test6.frp.com") || - strings.HasPrefix(r.Host, "test.frp1.com") || strings.HasPrefix(r.Host, "new.test.frp1.com") { - - w.WriteHeader(200) - w.Write([]byte(consts.TEST_HTTP_NORMAL_STR)) - } else if strings.Contains(r.Host, "test3.frp.com") { - w.WriteHeader(200) - if strings.Contains(r.URL.Path, "foo") { - w.Write([]byte(consts.TEST_HTTP_FOO_STR)) - } else if strings.Contains(r.URL.Path, "bar") { - w.Write([]byte(consts.TEST_HTTP_BAR_STR)) - } else { - w.Write([]byte(consts.TEST_HTTP_NORMAL_STR)) - } - } else { - w.WriteHeader(404) - } - return -} diff --git a/tests/util/process.go b/tests/util/process.go deleted file mode 100644 index e707846..0000000 --- a/tests/util/process.go +++ /dev/null @@ -1,47 +0,0 @@ -package util - -import ( - "bytes" - "context" - "os/exec" -) - -type Process struct { - cmd *exec.Cmd - cancel context.CancelFunc - errorOutput *bytes.Buffer - - beforeStopHandler func() -} - -func NewProcess(path string, params []string) *Process { - ctx, cancel := context.WithCancel(context.Background()) - cmd := exec.CommandContext(ctx, path, params...) - p := &Process{ - cmd: cmd, - cancel: cancel, - } - p.errorOutput = bytes.NewBufferString("") - cmd.Stderr = p.errorOutput - return p -} - -func (p *Process) Start() error { - return p.cmd.Start() -} - -func (p *Process) Stop() error { - if p.beforeStopHandler != nil { - p.beforeStopHandler() - } - p.cancel() - return p.cmd.Wait() -} - -func (p *Process) ErrorOutput() string { - return p.errorOutput.String() -} - -func (p *Process) SetBeforeStopHandler(fn func()) { - p.beforeStopHandler = fn -} diff --git a/tests/util/util.go b/tests/util/util.go deleted file mode 100644 index 377965c..0000000 --- a/tests/util/util.go +++ /dev/null @@ -1,210 +0,0 @@ -package util - -import ( - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "strings" - "time" - - "github.com/fatedier/frp/client" -) - -func GetProxyStatus(statusAddr string, user string, passwd string, name string) (status *client.ProxyStatusResp, err error) { - req, err := http.NewRequest("GET", "http://"+statusAddr+"/api/status", nil) - if err != nil { - return status, err - } - - authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+passwd)) - req.Header.Add("Authorization", authStr) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return status, err - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return status, fmt.Errorf("admin api status code [%d]", resp.StatusCode) - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return status, err - } - allStatus := &client.StatusResp{} - err = json.Unmarshal(body, &allStatus) - if err != nil { - return status, fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body))) - } - for _, s := range allStatus.TCP { - if s.Name == name { - return &s, nil - } - } - for _, s := range allStatus.UDP { - if s.Name == name { - return &s, nil - } - } - for _, s := range allStatus.HTTP { - if s.Name == name { - return &s, nil - } - } - for _, s := range allStatus.HTTPS { - if s.Name == name { - return &s, nil - } - } - for _, s := range allStatus.STCP { - if s.Name == name { - return &s, nil - } - } - for _, s := range allStatus.XTCP { - if s.Name == name { - return &s, nil - } - } - for _, s := range allStatus.SUDP { - if s.Name == name { - return &s, nil - } - } - - return status, errors.New("no proxy status found") -} - -func ReloadConf(reloadAddr string, user string, passwd string) error { - req, err := http.NewRequest("GET", "http://"+reloadAddr+"/api/reload", nil) - if err != nil { - return err - } - - authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+passwd)) - req.Header.Add("Authorization", authStr) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("admin api status code [%d]", resp.StatusCode) - } - io.Copy(ioutil.Discard, resp.Body) - return nil -} - -func SendTCPMsg(addr string, msg string) (res string, err error) { - c, err := net.Dial("tcp", addr) - if err != nil { - err = fmt.Errorf("connect to tcp server error: %v", err) - return - } - defer c.Close() - return SendTCPMsgByConn(c, msg) -} - -func SendTCPMsgByConn(c net.Conn, msg string) (res string, err error) { - timer := time.Now().Add(5 * time.Second) - c.SetDeadline(timer) - c.Write([]byte(msg)) - - buf := make([]byte, 2048) - n, errRet := c.Read(buf) - if errRet != nil { - err = fmt.Errorf("read from tcp server error: %v", errRet) - return - } - return string(buf[:n]), nil -} - -func SendUDPMsg(addr string, msg string) (res string, err error) { - udpAddr, errRet := net.ResolveUDPAddr("udp", addr) - if errRet != nil { - err = fmt.Errorf("resolve udp addr error: %v", err) - return - } - conn, errRet := net.DialUDP("udp", nil, udpAddr) - if errRet != nil { - err = fmt.Errorf("dial udp server error: %v", err) - return - } - defer conn.Close() - _, err = conn.Write([]byte(msg)) - if err != nil { - err = fmt.Errorf("write to udp server error: %v", err) - return - } - - conn.SetReadDeadline(time.Now().Add(10 * time.Second)) - buf := make([]byte, 2048) - n, errRet := conn.Read(buf) - if errRet != nil { - err = fmt.Errorf("read from udp server error: %v", err) - return - } - return string(buf[:n]), nil -} - -func SendHTTPMsg(method, urlStr string, host string, headers map[string]string, proxy string) (code int, body string, header http.Header, err error) { - req, errRet := http.NewRequest(method, urlStr, nil) - if errRet != nil { - err = errRet - return - } - - if host != "" { - req.Host = host - } - for k, v := range headers { - req.Header.Set(k, v) - } - - tr := &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - } - - if len(proxy) != 0 { - tr.Proxy = func(req *http.Request) (*url.URL, error) { - return url.Parse(proxy) - } - } - client := http.Client{ - Transport: tr, - } - - resp, errRet := client.Do(req) - if errRet != nil { - err = errRet - return - } - code = resp.StatusCode - header = resp.Header - buf, errRet := ioutil.ReadAll(resp.Body) - if errRet != nil { - err = errRet - return - } - body = string(buf) - return -} - -func BasicAuth(username, passwd string) string { - auth := username + ":" + passwd - return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) -}