1
0

http.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. package basic
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "strconv"
  7. "github.com/gorilla/websocket"
  8. "github.com/onsi/ginkgo/v2"
  9. "github.com/fatedier/frp/test/e2e/framework"
  10. "github.com/fatedier/frp/test/e2e/framework/consts"
  11. "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
  12. "github.com/fatedier/frp/test/e2e/pkg/request"
  13. )
  14. var _ = ginkgo.Describe("[Feature: HTTP]", func() {
  15. f := framework.NewDefaultFramework()
  16. getDefaultServerConf := func(vhostHTTPPort int) string {
  17. conf := consts.DefaultServerConfig + `
  18. vhostHTTPPort = %d
  19. `
  20. return fmt.Sprintf(conf, vhostHTTPPort)
  21. }
  22. newHTTPServer := func(port int, respContent string) *httpserver.Server {
  23. return httpserver.New(
  24. httpserver.WithBindPort(port),
  25. httpserver.WithHandler(framework.SpecifiedHTTPBodyHandler([]byte(respContent))),
  26. )
  27. }
  28. ginkgo.It("HTTP route by locations", func() {
  29. vhostHTTPPort := f.AllocPort()
  30. serverConf := getDefaultServerConf(vhostHTTPPort)
  31. fooPort := f.AllocPort()
  32. f.RunServer("", newHTTPServer(fooPort, "foo"))
  33. barPort := f.AllocPort()
  34. f.RunServer("", newHTTPServer(barPort, "bar"))
  35. clientConf := consts.DefaultClientConfig
  36. clientConf += fmt.Sprintf(`
  37. [[proxies]]
  38. name = "foo"
  39. type = "http"
  40. localPort = %d
  41. customDomains = ["normal.example.com"]
  42. locations = ["/","/foo"]
  43. [[proxies]]
  44. name = "bar"
  45. type = "http"
  46. localPort = %d
  47. customDomains = ["normal.example.com"]
  48. locations = ["/bar"]
  49. `, fooPort, barPort)
  50. f.RunProcesses([]string{serverConf}, []string{clientConf})
  51. tests := []struct {
  52. path string
  53. expectResp string
  54. desc string
  55. }{
  56. {path: "/foo", expectResp: "foo", desc: "foo path"},
  57. {path: "/bar", expectResp: "bar", desc: "bar path"},
  58. {path: "/other", expectResp: "foo", desc: "other path"},
  59. }
  60. for _, test := range tests {
  61. framework.NewRequestExpect(f).Explain(test.desc).Port(vhostHTTPPort).
  62. RequestModify(func(r *request.Request) {
  63. r.HTTP().HTTPHost("normal.example.com").HTTPPath(test.path)
  64. }).
  65. ExpectResp([]byte(test.expectResp)).
  66. Ensure()
  67. }
  68. })
  69. ginkgo.It("HTTP route by HTTP user", func() {
  70. vhostHTTPPort := f.AllocPort()
  71. serverConf := getDefaultServerConf(vhostHTTPPort)
  72. fooPort := f.AllocPort()
  73. f.RunServer("", newHTTPServer(fooPort, "foo"))
  74. barPort := f.AllocPort()
  75. f.RunServer("", newHTTPServer(barPort, "bar"))
  76. otherPort := f.AllocPort()
  77. f.RunServer("", newHTTPServer(otherPort, "other"))
  78. clientConf := consts.DefaultClientConfig
  79. clientConf += fmt.Sprintf(`
  80. [[proxies]]
  81. name = "foo"
  82. type = "http"
  83. localPort = %d
  84. customDomains = ["normal.example.com"]
  85. routeByHTTPUser = "user1"
  86. [[proxies]]
  87. name = "bar"
  88. type = "http"
  89. localPort = %d
  90. customDomains = ["normal.example.com"]
  91. routeByHTTPUser = "user2"
  92. [[proxies]]
  93. name = "catchAll"
  94. type = "http"
  95. localPort = %d
  96. customDomains = ["normal.example.com"]
  97. `, fooPort, barPort, otherPort)
  98. f.RunProcesses([]string{serverConf}, []string{clientConf})
  99. // user1
  100. framework.NewRequestExpect(f).Explain("user1").Port(vhostHTTPPort).
  101. RequestModify(func(r *request.Request) {
  102. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("user1", "")
  103. }).
  104. ExpectResp([]byte("foo")).
  105. Ensure()
  106. // user2
  107. framework.NewRequestExpect(f).Explain("user2").Port(vhostHTTPPort).
  108. RequestModify(func(r *request.Request) {
  109. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("user2", "")
  110. }).
  111. ExpectResp([]byte("bar")).
  112. Ensure()
  113. // other user
  114. framework.NewRequestExpect(f).Explain("other user").Port(vhostHTTPPort).
  115. RequestModify(func(r *request.Request) {
  116. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("user3", "")
  117. }).
  118. ExpectResp([]byte("other")).
  119. Ensure()
  120. })
  121. ginkgo.It("HTTP Basic Auth", func() {
  122. vhostHTTPPort := f.AllocPort()
  123. serverConf := getDefaultServerConf(vhostHTTPPort)
  124. clientConf := consts.DefaultClientConfig
  125. clientConf += fmt.Sprintf(`
  126. [[proxies]]
  127. name = "test"
  128. type = "http"
  129. localPort = {{ .%s }}
  130. customDomains = ["normal.example.com"]
  131. httpUser = "test"
  132. httpPassword = "test"
  133. `, framework.HTTPSimpleServerPort)
  134. f.RunProcesses([]string{serverConf}, []string{clientConf})
  135. // not set auth header
  136. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  137. RequestModify(func(r *request.Request) {
  138. r.HTTP().HTTPHost("normal.example.com")
  139. }).
  140. Ensure(framework.ExpectResponseCode(401))
  141. // set incorrect auth header
  142. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  143. RequestModify(func(r *request.Request) {
  144. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("test", "invalid")
  145. }).
  146. Ensure(framework.ExpectResponseCode(401))
  147. // set correct auth header
  148. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  149. RequestModify(func(r *request.Request) {
  150. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("test", "test")
  151. }).
  152. Ensure()
  153. })
  154. ginkgo.It("Wildcard domain", func() {
  155. vhostHTTPPort := f.AllocPort()
  156. serverConf := getDefaultServerConf(vhostHTTPPort)
  157. clientConf := consts.DefaultClientConfig
  158. clientConf += fmt.Sprintf(`
  159. [[proxies]]
  160. name = "test"
  161. type = "http"
  162. localPort = {{ .%s }}
  163. customDomains = ["*.example.com"]
  164. `, framework.HTTPSimpleServerPort)
  165. f.RunProcesses([]string{serverConf}, []string{clientConf})
  166. // not match host
  167. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  168. RequestModify(func(r *request.Request) {
  169. r.HTTP().HTTPHost("not-match.test.com")
  170. }).
  171. Ensure(framework.ExpectResponseCode(404))
  172. // test.example.com match *.example.com
  173. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  174. RequestModify(func(r *request.Request) {
  175. r.HTTP().HTTPHost("test.example.com")
  176. }).
  177. Ensure()
  178. // sub.test.example.com match *.example.com
  179. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  180. RequestModify(func(r *request.Request) {
  181. r.HTTP().HTTPHost("sub.test.example.com")
  182. }).
  183. Ensure()
  184. })
  185. ginkgo.It("Subdomain", func() {
  186. vhostHTTPPort := f.AllocPort()
  187. serverConf := getDefaultServerConf(vhostHTTPPort)
  188. serverConf += `
  189. subdomainHost = "example.com"
  190. `
  191. fooPort := f.AllocPort()
  192. f.RunServer("", newHTTPServer(fooPort, "foo"))
  193. barPort := f.AllocPort()
  194. f.RunServer("", newHTTPServer(barPort, "bar"))
  195. clientConf := consts.DefaultClientConfig
  196. clientConf += fmt.Sprintf(`
  197. [[proxies]]
  198. name = "foo"
  199. type = "http"
  200. localPort = %d
  201. subdomain = "foo"
  202. [[proxies]]
  203. name = "bar"
  204. type = "http"
  205. localPort = %d
  206. subdomain = "bar"
  207. `, fooPort, barPort)
  208. f.RunProcesses([]string{serverConf}, []string{clientConf})
  209. // foo
  210. framework.NewRequestExpect(f).Explain("foo subdomain").Port(vhostHTTPPort).
  211. RequestModify(func(r *request.Request) {
  212. r.HTTP().HTTPHost("foo.example.com")
  213. }).
  214. ExpectResp([]byte("foo")).
  215. Ensure()
  216. // bar
  217. framework.NewRequestExpect(f).Explain("bar subdomain").Port(vhostHTTPPort).
  218. RequestModify(func(r *request.Request) {
  219. r.HTTP().HTTPHost("bar.example.com")
  220. }).
  221. ExpectResp([]byte("bar")).
  222. Ensure()
  223. })
  224. ginkgo.It("Modify headers", func() {
  225. vhostHTTPPort := f.AllocPort()
  226. serverConf := getDefaultServerConf(vhostHTTPPort)
  227. localPort := f.AllocPort()
  228. localServer := httpserver.New(
  229. httpserver.WithBindPort(localPort),
  230. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  231. _, _ = w.Write([]byte(req.Header.Get("X-From-Where")))
  232. })),
  233. )
  234. f.RunServer("", localServer)
  235. clientConf := consts.DefaultClientConfig
  236. clientConf += fmt.Sprintf(`
  237. [[proxies]]
  238. name = "test"
  239. type = "http"
  240. localPort = %d
  241. customDomains = ["normal.example.com"]
  242. requestHeaders.set.x-from-where = "frp"
  243. `, localPort)
  244. f.RunProcesses([]string{serverConf}, []string{clientConf})
  245. // not set auth header
  246. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  247. RequestModify(func(r *request.Request) {
  248. r.HTTP().HTTPHost("normal.example.com")
  249. }).
  250. ExpectResp([]byte("frp")). // local http server will write this X-From-Where header to response body
  251. Ensure()
  252. })
  253. ginkgo.It("Host Header Rewrite", func() {
  254. vhostHTTPPort := f.AllocPort()
  255. serverConf := getDefaultServerConf(vhostHTTPPort)
  256. localPort := f.AllocPort()
  257. localServer := httpserver.New(
  258. httpserver.WithBindPort(localPort),
  259. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  260. _, _ = w.Write([]byte(req.Host))
  261. })),
  262. )
  263. f.RunServer("", localServer)
  264. clientConf := consts.DefaultClientConfig
  265. clientConf += fmt.Sprintf(`
  266. [[proxies]]
  267. name = "test"
  268. type = "http"
  269. localPort = %d
  270. customDomains = ["normal.example.com"]
  271. hostHeaderRewrite = "rewrite.example.com"
  272. `, localPort)
  273. f.RunProcesses([]string{serverConf}, []string{clientConf})
  274. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  275. RequestModify(func(r *request.Request) {
  276. r.HTTP().HTTPHost("normal.example.com")
  277. }).
  278. ExpectResp([]byte("rewrite.example.com")). // local http server will write host header to response body
  279. Ensure()
  280. })
  281. ginkgo.It("Websocket protocol", func() {
  282. vhostHTTPPort := f.AllocPort()
  283. serverConf := getDefaultServerConf(vhostHTTPPort)
  284. upgrader := websocket.Upgrader{}
  285. localPort := f.AllocPort()
  286. localServer := httpserver.New(
  287. httpserver.WithBindPort(localPort),
  288. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  289. c, err := upgrader.Upgrade(w, req, nil)
  290. if err != nil {
  291. return
  292. }
  293. defer c.Close()
  294. for {
  295. mt, message, err := c.ReadMessage()
  296. if err != nil {
  297. break
  298. }
  299. err = c.WriteMessage(mt, message)
  300. if err != nil {
  301. break
  302. }
  303. }
  304. })),
  305. )
  306. f.RunServer("", localServer)
  307. clientConf := consts.DefaultClientConfig
  308. clientConf += fmt.Sprintf(`
  309. [[proxies]]
  310. name = "test"
  311. type = "http"
  312. localPort = %d
  313. customDomains = ["127.0.0.1"]
  314. `, localPort)
  315. f.RunProcesses([]string{serverConf}, []string{clientConf})
  316. u := url.URL{Scheme: "ws", Host: "127.0.0.1:" + strconv.Itoa(vhostHTTPPort)}
  317. c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
  318. framework.ExpectNoError(err)
  319. err = c.WriteMessage(websocket.TextMessage, []byte(consts.TestString))
  320. framework.ExpectNoError(err)
  321. _, msg, err := c.ReadMessage()
  322. framework.ExpectNoError(err)
  323. framework.ExpectEqualValues(consts.TestString, string(msg))
  324. })
  325. })