http.go 9.9 KB

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