http.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. package basic
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "strconv"
  7. "time"
  8. "github.com/gorilla/websocket"
  9. "github.com/onsi/ginkgo/v2"
  10. "github.com/fatedier/frp/test/e2e/framework"
  11. "github.com/fatedier/frp/test/e2e/framework/consts"
  12. "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
  13. "github.com/fatedier/frp/test/e2e/pkg/request"
  14. )
  15. var _ = ginkgo.Describe("[Feature: HTTP]", func() {
  16. f := framework.NewDefaultFramework()
  17. getDefaultServerConf := func(vhostHTTPPort int) string {
  18. conf := consts.DefaultServerConfig + `
  19. vhostHTTPPort = %d
  20. `
  21. return fmt.Sprintf(conf, vhostHTTPPort)
  22. }
  23. newHTTPServer := func(port int, respContent string) *httpserver.Server {
  24. return httpserver.New(
  25. httpserver.WithBindPort(port),
  26. httpserver.WithHandler(framework.SpecifiedHTTPBodyHandler([]byte(respContent))),
  27. )
  28. }
  29. ginkgo.It("HTTP route by locations", func() {
  30. vhostHTTPPort := f.AllocPort()
  31. serverConf := getDefaultServerConf(vhostHTTPPort)
  32. fooPort := f.AllocPort()
  33. f.RunServer("", newHTTPServer(fooPort, "foo"))
  34. barPort := f.AllocPort()
  35. f.RunServer("", newHTTPServer(barPort, "bar"))
  36. clientConf := consts.DefaultClientConfig
  37. clientConf += fmt.Sprintf(`
  38. [[proxies]]
  39. name = "foo"
  40. type = "http"
  41. localPort = %d
  42. customDomains = ["normal.example.com"]
  43. locations = ["/","/foo"]
  44. [[proxies]]
  45. name = "bar"
  46. type = "http"
  47. localPort = %d
  48. customDomains = ["normal.example.com"]
  49. locations = ["/bar"]
  50. `, fooPort, barPort)
  51. f.RunProcesses([]string{serverConf}, []string{clientConf})
  52. tests := []struct {
  53. path string
  54. expectResp string
  55. desc string
  56. }{
  57. {path: "/foo", expectResp: "foo", desc: "foo path"},
  58. {path: "/bar", expectResp: "bar", desc: "bar path"},
  59. {path: "/other", expectResp: "foo", desc: "other path"},
  60. }
  61. for _, test := range tests {
  62. framework.NewRequestExpect(f).Explain(test.desc).Port(vhostHTTPPort).
  63. RequestModify(func(r *request.Request) {
  64. r.HTTP().HTTPHost("normal.example.com").HTTPPath(test.path)
  65. }).
  66. ExpectResp([]byte(test.expectResp)).
  67. Ensure()
  68. }
  69. })
  70. ginkgo.It("HTTP route by HTTP user", func() {
  71. vhostHTTPPort := f.AllocPort()
  72. serverConf := getDefaultServerConf(vhostHTTPPort)
  73. fooPort := f.AllocPort()
  74. f.RunServer("", newHTTPServer(fooPort, "foo"))
  75. barPort := f.AllocPort()
  76. f.RunServer("", newHTTPServer(barPort, "bar"))
  77. otherPort := f.AllocPort()
  78. f.RunServer("", newHTTPServer(otherPort, "other"))
  79. clientConf := consts.DefaultClientConfig
  80. clientConf += fmt.Sprintf(`
  81. [[proxies]]
  82. name = "foo"
  83. type = "http"
  84. localPort = %d
  85. customDomains = ["normal.example.com"]
  86. routeByHTTPUser = "user1"
  87. [[proxies]]
  88. name = "bar"
  89. type = "http"
  90. localPort = %d
  91. customDomains = ["normal.example.com"]
  92. routeByHTTPUser = "user2"
  93. [[proxies]]
  94. name = "catchAll"
  95. type = "http"
  96. localPort = %d
  97. customDomains = ["normal.example.com"]
  98. `, fooPort, barPort, otherPort)
  99. f.RunProcesses([]string{serverConf}, []string{clientConf})
  100. // user1
  101. framework.NewRequestExpect(f).Explain("user1").Port(vhostHTTPPort).
  102. RequestModify(func(r *request.Request) {
  103. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("user1", "")
  104. }).
  105. ExpectResp([]byte("foo")).
  106. Ensure()
  107. // user2
  108. framework.NewRequestExpect(f).Explain("user2").Port(vhostHTTPPort).
  109. RequestModify(func(r *request.Request) {
  110. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("user2", "")
  111. }).
  112. ExpectResp([]byte("bar")).
  113. Ensure()
  114. // other user
  115. framework.NewRequestExpect(f).Explain("other user").Port(vhostHTTPPort).
  116. RequestModify(func(r *request.Request) {
  117. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("user3", "")
  118. }).
  119. ExpectResp([]byte("other")).
  120. Ensure()
  121. })
  122. ginkgo.It("HTTP Basic Auth", func() {
  123. vhostHTTPPort := f.AllocPort()
  124. serverConf := getDefaultServerConf(vhostHTTPPort)
  125. clientConf := consts.DefaultClientConfig
  126. clientConf += fmt.Sprintf(`
  127. [[proxies]]
  128. name = "test"
  129. type = "http"
  130. localPort = {{ .%s }}
  131. customDomains = ["normal.example.com"]
  132. httpUser = "test"
  133. httpPassword = "test"
  134. `, framework.HTTPSimpleServerPort)
  135. f.RunProcesses([]string{serverConf}, []string{clientConf})
  136. // not set auth header
  137. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  138. RequestModify(func(r *request.Request) {
  139. r.HTTP().HTTPHost("normal.example.com")
  140. }).
  141. Ensure(framework.ExpectResponseCode(401))
  142. // set incorrect auth header
  143. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  144. RequestModify(func(r *request.Request) {
  145. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("test", "invalid")
  146. }).
  147. Ensure(framework.ExpectResponseCode(401))
  148. // set correct auth header
  149. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  150. RequestModify(func(r *request.Request) {
  151. r.HTTP().HTTPHost("normal.example.com").HTTPAuth("test", "test")
  152. }).
  153. Ensure()
  154. })
  155. ginkgo.It("Wildcard domain", func() {
  156. vhostHTTPPort := f.AllocPort()
  157. serverConf := getDefaultServerConf(vhostHTTPPort)
  158. clientConf := consts.DefaultClientConfig
  159. clientConf += fmt.Sprintf(`
  160. [[proxies]]
  161. name = "test"
  162. type = "http"
  163. localPort = {{ .%s }}
  164. customDomains = ["*.example.com"]
  165. `, framework.HTTPSimpleServerPort)
  166. f.RunProcesses([]string{serverConf}, []string{clientConf})
  167. // not match host
  168. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  169. RequestModify(func(r *request.Request) {
  170. r.HTTP().HTTPHost("not-match.test.com")
  171. }).
  172. Ensure(framework.ExpectResponseCode(404))
  173. // test.example.com match *.example.com
  174. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  175. RequestModify(func(r *request.Request) {
  176. r.HTTP().HTTPHost("test.example.com")
  177. }).
  178. Ensure()
  179. // sub.test.example.com match *.example.com
  180. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  181. RequestModify(func(r *request.Request) {
  182. r.HTTP().HTTPHost("sub.test.example.com")
  183. }).
  184. Ensure()
  185. })
  186. ginkgo.It("Subdomain", func() {
  187. vhostHTTPPort := f.AllocPort()
  188. serverConf := getDefaultServerConf(vhostHTTPPort)
  189. serverConf += `
  190. subdomainHost = "example.com"
  191. `
  192. fooPort := f.AllocPort()
  193. f.RunServer("", newHTTPServer(fooPort, "foo"))
  194. barPort := f.AllocPort()
  195. f.RunServer("", newHTTPServer(barPort, "bar"))
  196. clientConf := consts.DefaultClientConfig
  197. clientConf += fmt.Sprintf(`
  198. [[proxies]]
  199. name = "foo"
  200. type = "http"
  201. localPort = %d
  202. subdomain = "foo"
  203. [[proxies]]
  204. name = "bar"
  205. type = "http"
  206. localPort = %d
  207. subdomain = "bar"
  208. `, fooPort, barPort)
  209. f.RunProcesses([]string{serverConf}, []string{clientConf})
  210. // foo
  211. framework.NewRequestExpect(f).Explain("foo subdomain").Port(vhostHTTPPort).
  212. RequestModify(func(r *request.Request) {
  213. r.HTTP().HTTPHost("foo.example.com")
  214. }).
  215. ExpectResp([]byte("foo")).
  216. Ensure()
  217. // bar
  218. framework.NewRequestExpect(f).Explain("bar subdomain").Port(vhostHTTPPort).
  219. RequestModify(func(r *request.Request) {
  220. r.HTTP().HTTPHost("bar.example.com")
  221. }).
  222. ExpectResp([]byte("bar")).
  223. Ensure()
  224. })
  225. ginkgo.It("Modify request headers", func() {
  226. vhostHTTPPort := f.AllocPort()
  227. serverConf := getDefaultServerConf(vhostHTTPPort)
  228. localPort := f.AllocPort()
  229. localServer := httpserver.New(
  230. httpserver.WithBindPort(localPort),
  231. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  232. _, _ = w.Write([]byte(req.Header.Get("X-From-Where")))
  233. })),
  234. )
  235. f.RunServer("", localServer)
  236. clientConf := consts.DefaultClientConfig
  237. clientConf += fmt.Sprintf(`
  238. [[proxies]]
  239. name = "test"
  240. type = "http"
  241. localPort = %d
  242. customDomains = ["normal.example.com"]
  243. requestHeaders.set.x-from-where = "frp"
  244. `, localPort)
  245. f.RunProcesses([]string{serverConf}, []string{clientConf})
  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("Modify response headers", 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.WriteHeader(200)
  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. responseHeaders.set.x-from-where = "frp"
  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. Ensure(func(res *request.Response) bool {
  279. return res.Header.Get("X-From-Where") == "frp"
  280. })
  281. })
  282. ginkgo.It("Host Header Rewrite", func() {
  283. vhostHTTPPort := f.AllocPort()
  284. serverConf := getDefaultServerConf(vhostHTTPPort)
  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. _, _ = w.Write([]byte(req.Host))
  290. })),
  291. )
  292. f.RunServer("", localServer)
  293. clientConf := consts.DefaultClientConfig
  294. clientConf += fmt.Sprintf(`
  295. [[proxies]]
  296. name = "test"
  297. type = "http"
  298. localPort = %d
  299. customDomains = ["normal.example.com"]
  300. hostHeaderRewrite = "rewrite.example.com"
  301. `, localPort)
  302. f.RunProcesses([]string{serverConf}, []string{clientConf})
  303. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  304. RequestModify(func(r *request.Request) {
  305. r.HTTP().HTTPHost("normal.example.com")
  306. }).
  307. ExpectResp([]byte("rewrite.example.com")). // local http server will write host header to response body
  308. Ensure()
  309. })
  310. ginkgo.It("Websocket protocol", func() {
  311. vhostHTTPPort := f.AllocPort()
  312. serverConf := getDefaultServerConf(vhostHTTPPort)
  313. upgrader := websocket.Upgrader{}
  314. localPort := f.AllocPort()
  315. localServer := httpserver.New(
  316. httpserver.WithBindPort(localPort),
  317. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  318. c, err := upgrader.Upgrade(w, req, nil)
  319. if err != nil {
  320. return
  321. }
  322. defer c.Close()
  323. for {
  324. mt, message, err := c.ReadMessage()
  325. if err != nil {
  326. break
  327. }
  328. err = c.WriteMessage(mt, message)
  329. if err != nil {
  330. break
  331. }
  332. }
  333. })),
  334. )
  335. f.RunServer("", localServer)
  336. clientConf := consts.DefaultClientConfig
  337. clientConf += fmt.Sprintf(`
  338. [[proxies]]
  339. name = "test"
  340. type = "http"
  341. localPort = %d
  342. customDomains = ["127.0.0.1"]
  343. `, localPort)
  344. f.RunProcesses([]string{serverConf}, []string{clientConf})
  345. u := url.URL{Scheme: "ws", Host: "127.0.0.1:" + strconv.Itoa(vhostHTTPPort)}
  346. c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
  347. framework.ExpectNoError(err)
  348. err = c.WriteMessage(websocket.TextMessage, []byte(consts.TestString))
  349. framework.ExpectNoError(err)
  350. _, msg, err := c.ReadMessage()
  351. framework.ExpectNoError(err)
  352. framework.ExpectEqualValues(consts.TestString, string(msg))
  353. })
  354. ginkgo.It("vhostHTTPTimeout", func() {
  355. vhostHTTPPort := f.AllocPort()
  356. serverConf := getDefaultServerConf(vhostHTTPPort)
  357. serverConf += `
  358. vhostHTTPTimeout = 2
  359. `
  360. delayDuration := 0 * time.Second
  361. localPort := f.AllocPort()
  362. localServer := httpserver.New(
  363. httpserver.WithBindPort(localPort),
  364. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  365. time.Sleep(delayDuration)
  366. _, _ = w.Write([]byte(req.Host))
  367. })),
  368. )
  369. f.RunServer("", localServer)
  370. clientConf := consts.DefaultClientConfig
  371. clientConf += fmt.Sprintf(`
  372. [[proxies]]
  373. name = "test"
  374. type = "http"
  375. localPort = %d
  376. customDomains = ["normal.example.com"]
  377. `, localPort)
  378. f.RunProcesses([]string{serverConf}, []string{clientConf})
  379. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  380. RequestModify(func(r *request.Request) {
  381. r.HTTP().HTTPHost("normal.example.com").HTTP().Timeout(time.Second)
  382. }).
  383. ExpectResp([]byte("normal.example.com")).
  384. Ensure()
  385. delayDuration = 3 * time.Second
  386. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  387. RequestModify(func(r *request.Request) {
  388. r.HTTP().HTTPHost("normal.example.com").HTTP().Timeout(5 * time.Second)
  389. }).
  390. Ensure(framework.ExpectResponseCode(504))
  391. })
  392. })