http.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. package basic
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "strconv"
  7. "github.com/fatedier/frp/test/e2e/framework"
  8. "github.com/fatedier/frp/test/e2e/framework/consts"
  9. "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
  10. "github.com/fatedier/frp/test/e2e/pkg/request"
  11. "github.com/fatedier/frp/test/e2e/pkg/utils"
  12. "github.com/gorilla/websocket"
  13. . "github.com/onsi/ginkgo"
  14. )
  15. var _ = Describe("[Feature: HTTP]", func() {
  16. f := framework.NewDefaultFramework()
  17. getDefaultServerConf := func(vhostHTTPPort int) string {
  18. conf := consts.DefaultServerConfig + `
  19. vhost_http_port = %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. 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. [foo]
  39. type = http
  40. local_port = %d
  41. custom_domains = normal.example.com
  42. locations = /,/foo
  43. [bar]
  44. type = http
  45. local_port = %d
  46. custom_domains = normal.example.com
  47. locations = /bar
  48. `, fooPort, barPort)
  49. f.RunProcesses([]string{serverConf}, []string{clientConf})
  50. // foo path
  51. framework.NewRequestExpect(f).Explain("foo path").Port(vhostHTTPPort).
  52. RequestModify(func(r *request.Request) {
  53. r.HTTP().HTTPHost("normal.example.com").HTTPPath("/foo")
  54. }).
  55. ExpectResp([]byte("foo")).
  56. Ensure()
  57. // bar path
  58. framework.NewRequestExpect(f).Explain("bar path").Port(vhostHTTPPort).
  59. RequestModify(func(r *request.Request) {
  60. r.HTTP().HTTPHost("normal.example.com").HTTPPath("/bar")
  61. }).
  62. ExpectResp([]byte("bar")).
  63. Ensure()
  64. // other path
  65. framework.NewRequestExpect(f).Explain("other path").Port(vhostHTTPPort).
  66. RequestModify(func(r *request.Request) {
  67. r.HTTP().HTTPHost("normal.example.com").HTTPPath("/other")
  68. }).
  69. ExpectResp([]byte("foo")).
  70. Ensure()
  71. })
  72. It("HTTP Basic Auth", func() {
  73. vhostHTTPPort := f.AllocPort()
  74. serverConf := getDefaultServerConf(vhostHTTPPort)
  75. clientConf := consts.DefaultClientConfig
  76. clientConf += fmt.Sprintf(`
  77. [test]
  78. type = http
  79. local_port = {{ .%s }}
  80. custom_domains = normal.example.com
  81. http_user = test
  82. http_pwd = test
  83. `, framework.HTTPSimpleServerPort)
  84. f.RunProcesses([]string{serverConf}, []string{clientConf})
  85. // not set auth header
  86. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  87. RequestModify(func(r *request.Request) {
  88. r.HTTP().HTTPHost("normal.example.com")
  89. }).
  90. Ensure(framework.ExpectResponseCode(401))
  91. // set incorrect auth header
  92. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  93. RequestModify(func(r *request.Request) {
  94. r.HTTP().HTTPHost("normal.example.com").HTTPHeaders(map[string]string{
  95. "Authorization": utils.BasicAuth("test", "invalid"),
  96. })
  97. }).
  98. Ensure(framework.ExpectResponseCode(401))
  99. // set correct auth header
  100. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  101. RequestModify(func(r *request.Request) {
  102. r.HTTP().HTTPHost("normal.example.com").HTTPHeaders(map[string]string{
  103. "Authorization": utils.BasicAuth("test", "test"),
  104. })
  105. }).
  106. Ensure()
  107. })
  108. It("Wildcard domain", func() {
  109. vhostHTTPPort := f.AllocPort()
  110. serverConf := getDefaultServerConf(vhostHTTPPort)
  111. clientConf := consts.DefaultClientConfig
  112. clientConf += fmt.Sprintf(`
  113. [test]
  114. type = http
  115. local_port = {{ .%s }}
  116. custom_domains = *.example.com
  117. `, framework.HTTPSimpleServerPort)
  118. f.RunProcesses([]string{serverConf}, []string{clientConf})
  119. // not match host
  120. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  121. RequestModify(func(r *request.Request) {
  122. r.HTTP().HTTPHost("not-match.test.com")
  123. }).
  124. Ensure(framework.ExpectResponseCode(404))
  125. // test.example.com match *.example.com
  126. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  127. RequestModify(func(r *request.Request) {
  128. r.HTTP().HTTPHost("test.example.com")
  129. }).
  130. Ensure()
  131. // sub.test.example.com match *.example.com
  132. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  133. RequestModify(func(r *request.Request) {
  134. r.HTTP().HTTPHost("sub.test.example.com")
  135. }).
  136. Ensure()
  137. })
  138. It("Subdomain", func() {
  139. vhostHTTPPort := f.AllocPort()
  140. serverConf := getDefaultServerConf(vhostHTTPPort)
  141. serverConf += `
  142. subdomain_host = example.com
  143. `
  144. fooPort := f.AllocPort()
  145. f.RunServer("", newHTTPServer(fooPort, "foo"))
  146. barPort := f.AllocPort()
  147. f.RunServer("", newHTTPServer(barPort, "bar"))
  148. clientConf := consts.DefaultClientConfig
  149. clientConf += fmt.Sprintf(`
  150. [foo]
  151. type = http
  152. local_port = %d
  153. subdomain = foo
  154. [bar]
  155. type = http
  156. local_port = %d
  157. subdomain = bar
  158. `, fooPort, barPort)
  159. f.RunProcesses([]string{serverConf}, []string{clientConf})
  160. // foo
  161. framework.NewRequestExpect(f).Explain("foo subdomain").Port(vhostHTTPPort).
  162. RequestModify(func(r *request.Request) {
  163. r.HTTP().HTTPHost("foo.example.com")
  164. }).
  165. ExpectResp([]byte("foo")).
  166. Ensure()
  167. // bar
  168. framework.NewRequestExpect(f).Explain("bar subdomain").Port(vhostHTTPPort).
  169. RequestModify(func(r *request.Request) {
  170. r.HTTP().HTTPHost("bar.example.com")
  171. }).
  172. ExpectResp([]byte("bar")).
  173. Ensure()
  174. })
  175. It("Modify headers", func() {
  176. vhostHTTPPort := f.AllocPort()
  177. serverConf := getDefaultServerConf(vhostHTTPPort)
  178. localPort := f.AllocPort()
  179. localServer := httpserver.New(
  180. httpserver.WithBindPort(localPort),
  181. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  182. w.Write([]byte(req.Header.Get("X-From-Where")))
  183. })),
  184. )
  185. f.RunServer("", localServer)
  186. clientConf := consts.DefaultClientConfig
  187. clientConf += fmt.Sprintf(`
  188. [test]
  189. type = http
  190. local_port = %d
  191. custom_domains = normal.example.com
  192. header_X-From-Where = frp
  193. `, localPort)
  194. f.RunProcesses([]string{serverConf}, []string{clientConf})
  195. // not set auth header
  196. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  197. RequestModify(func(r *request.Request) {
  198. r.HTTP().HTTPHost("normal.example.com")
  199. }).
  200. ExpectResp([]byte("frp")). // local http server will write this X-From-Where header to response body
  201. Ensure()
  202. })
  203. It("Host Header Rewrite", func() {
  204. vhostHTTPPort := f.AllocPort()
  205. serverConf := getDefaultServerConf(vhostHTTPPort)
  206. localPort := f.AllocPort()
  207. localServer := httpserver.New(
  208. httpserver.WithBindPort(localPort),
  209. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  210. w.Write([]byte(req.Host))
  211. })),
  212. )
  213. f.RunServer("", localServer)
  214. clientConf := consts.DefaultClientConfig
  215. clientConf += fmt.Sprintf(`
  216. [test]
  217. type = http
  218. local_port = %d
  219. custom_domains = normal.example.com
  220. host_header_rewrite = rewrite.example.com
  221. `, localPort)
  222. f.RunProcesses([]string{serverConf}, []string{clientConf})
  223. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  224. RequestModify(func(r *request.Request) {
  225. r.HTTP().HTTPHost("normal.example.com")
  226. }).
  227. ExpectResp([]byte("rewrite.example.com")). // local http server will write host header to response body
  228. Ensure()
  229. })
  230. It("Websocket protocol", func() {
  231. vhostHTTPPort := f.AllocPort()
  232. serverConf := getDefaultServerConf(vhostHTTPPort)
  233. upgrader := websocket.Upgrader{}
  234. localPort := f.AllocPort()
  235. localServer := httpserver.New(
  236. httpserver.WithBindPort(localPort),
  237. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  238. c, err := upgrader.Upgrade(w, req, nil)
  239. if err != nil {
  240. return
  241. }
  242. defer c.Close()
  243. for {
  244. mt, message, err := c.ReadMessage()
  245. if err != nil {
  246. break
  247. }
  248. err = c.WriteMessage(mt, message)
  249. if err != nil {
  250. break
  251. }
  252. }
  253. })),
  254. )
  255. f.RunServer("", localServer)
  256. clientConf := consts.DefaultClientConfig
  257. clientConf += fmt.Sprintf(`
  258. [test]
  259. type = http
  260. local_port = %d
  261. custom_domains = 127.0.0.1
  262. `, localPort)
  263. f.RunProcesses([]string{serverConf}, []string{clientConf})
  264. u := url.URL{Scheme: "ws", Host: "127.0.0.1:" + strconv.Itoa(vhostHTTPPort)}
  265. c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
  266. framework.ExpectNoError(err)
  267. err = c.WriteMessage(websocket.TextMessage, []byte(consts.TestString))
  268. framework.ExpectNoError(err)
  269. _, msg, err := c.ReadMessage()
  270. framework.ExpectNoError(err)
  271. framework.ExpectEqualValues(consts.TestString, string(msg))
  272. })
  273. })