http_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. // +build integration
  7. package integration
  8. import (
  9. "bytes"
  10. "encoding/json"
  11. "io/ioutil"
  12. "net/http"
  13. "strings"
  14. "testing"
  15. )
  16. var jsonEndpoints = []string{
  17. "/rest/completion?device=I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU&folder=default",
  18. "/rest/config",
  19. "/rest/config/sync",
  20. "/rest/connections",
  21. "/rest/errors",
  22. "/rest/events",
  23. "/rest/lang",
  24. "/rest/model?folder=default",
  25. "/rest/need",
  26. "/rest/deviceid?id=I6KAH7666SLLLB5PFXSOAUFJCDZCYAOMLEKCP2GB32BV5RQST3PSROAU",
  27. "/rest/report",
  28. "/rest/system",
  29. }
  30. func TestGetIndex(t *testing.T) {
  31. st := syncthingProcess{
  32. argv: []string{"-home", "h2"},
  33. port: 8082,
  34. instance: "2",
  35. }
  36. err := st.start()
  37. if err != nil {
  38. t.Fatal(err)
  39. }
  40. defer st.stop()
  41. res, err := st.get("/index.html")
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. if res.StatusCode != 200 {
  46. t.Errorf("Status %d != 200", res.StatusCode)
  47. }
  48. bs, err := ioutil.ReadAll(res.Body)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. if len(bs) < 1024 {
  53. t.Errorf("Length %d < 1024", len(bs))
  54. }
  55. if !bytes.Contains(bs, []byte("</html>")) {
  56. t.Error("Incorrect response")
  57. }
  58. if res.Header.Get("Set-Cookie") == "" {
  59. t.Error("No set-cookie header")
  60. }
  61. res.Body.Close()
  62. res, err = st.get("/")
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. if res.StatusCode != 200 {
  67. t.Errorf("Status %d != 200", res.StatusCode)
  68. }
  69. bs, err = ioutil.ReadAll(res.Body)
  70. if err != nil {
  71. t.Fatal(err)
  72. }
  73. if len(bs) < 1024 {
  74. t.Errorf("Length %d < 1024", len(bs))
  75. }
  76. if !bytes.Contains(bs, []byte("</html>")) {
  77. t.Error("Incorrect response")
  78. }
  79. if res.Header.Get("Set-Cookie") == "" {
  80. t.Error("No set-cookie header")
  81. }
  82. res.Body.Close()
  83. }
  84. func TestGetIndexAuth(t *testing.T) {
  85. st := syncthingProcess{
  86. argv: []string{"-home", "h1"},
  87. port: 8081,
  88. instance: "1",
  89. apiKey: "abc123",
  90. }
  91. err := st.start()
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. defer st.stop()
  96. // Without auth should give 401
  97. res, err := http.Get("http://127.0.0.1:8081/")
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. res.Body.Close()
  102. if res.StatusCode != 401 {
  103. t.Errorf("Status %d != 401", res.StatusCode)
  104. }
  105. // With wrong username/password should give 401
  106. req, err := http.NewRequest("GET", "http://127.0.0.1:8081/", nil)
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. req.SetBasicAuth("testuser", "wrongpass")
  111. res, err = http.DefaultClient.Do(req)
  112. if err != nil {
  113. t.Fatal(err)
  114. }
  115. res.Body.Close()
  116. if res.StatusCode != 401 {
  117. t.Fatalf("Status %d != 401", res.StatusCode)
  118. }
  119. // With correct username/password should succeed
  120. req, err = http.NewRequest("GET", "http://127.0.0.1:8081/", nil)
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. req.SetBasicAuth("testuser", "testpass")
  125. res, err = http.DefaultClient.Do(req)
  126. if err != nil {
  127. t.Fatal(err)
  128. }
  129. res.Body.Close()
  130. if res.StatusCode != 200 {
  131. t.Fatalf("Status %d != 200", res.StatusCode)
  132. }
  133. }
  134. func TestGetJSON(t *testing.T) {
  135. st := syncthingProcess{
  136. argv: []string{"-home", "h2"},
  137. port: 8082,
  138. instance: "2",
  139. }
  140. err := st.start()
  141. if err != nil {
  142. t.Fatal(err)
  143. }
  144. defer st.stop()
  145. for _, path := range jsonEndpoints {
  146. res, err := st.get(path)
  147. if err != nil {
  148. t.Error(err)
  149. }
  150. if ct := res.Header.Get("Content-Type"); ct != "application/json; charset=utf-8" {
  151. t.Errorf("Incorrect Content-Type %q for %q", ct, path)
  152. }
  153. var intf interface{}
  154. err = json.NewDecoder(res.Body).Decode(&intf)
  155. res.Body.Close()
  156. if err != nil {
  157. t.Error(err)
  158. }
  159. }
  160. }
  161. func TestPOSTWithoutCSRF(t *testing.T) {
  162. st := syncthingProcess{
  163. argv: []string{"-home", "h2"},
  164. port: 8082,
  165. instance: "2",
  166. }
  167. err := st.start()
  168. if err != nil {
  169. t.Fatal(err)
  170. }
  171. defer st.stop()
  172. // Should fail without CSRF
  173. req, err := http.NewRequest("POST", "http://127.0.0.1:8082/rest/error/clear", nil)
  174. if err != nil {
  175. t.Fatal(err)
  176. }
  177. res, err := http.DefaultClient.Do(req)
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. res.Body.Close()
  182. if res.StatusCode != 403 {
  183. t.Fatalf("Status %d != 403 for POST", res.StatusCode)
  184. }
  185. // Get CSRF
  186. req, err = http.NewRequest("GET", "http://127.0.0.1:8082/", nil)
  187. if err != nil {
  188. t.Fatal(err)
  189. }
  190. res, err = http.DefaultClient.Do(req)
  191. if err != nil {
  192. t.Fatal(err)
  193. }
  194. res.Body.Close()
  195. hdr := res.Header.Get("Set-Cookie")
  196. if !strings.Contains(hdr, "CSRF-Token") {
  197. t.Error("Missing CSRF-Token in", hdr)
  198. }
  199. // Should succeed with CSRF
  200. req, err = http.NewRequest("POST", "http://127.0.0.1:8082/rest/error/clear", nil)
  201. if err != nil {
  202. t.Fatal(err)
  203. }
  204. req.Header.Set("X-CSRF-Token", hdr[len("CSRF-Token="):])
  205. res, err = http.DefaultClient.Do(req)
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. res.Body.Close()
  210. if res.StatusCode != 200 {
  211. t.Fatalf("Status %d != 200 for POST", res.StatusCode)
  212. }
  213. // Should fail with incorrect CSRF
  214. req, err = http.NewRequest("POST", "http://127.0.0.1:8082/rest/error/clear", nil)
  215. if err != nil {
  216. t.Fatal(err)
  217. }
  218. req.Header.Set("X-CSRF-Token", hdr[len("CSRF-Token="):]+"X")
  219. res, err = http.DefaultClient.Do(req)
  220. if err != nil {
  221. t.Fatal(err)
  222. }
  223. res.Body.Close()
  224. if res.StatusCode != 403 {
  225. t.Fatalf("Status %d != 403 for POST", res.StatusCode)
  226. }
  227. }