server_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. package guerrilla
  2. import (
  3. "testing"
  4. "bufio"
  5. "net/textproto"
  6. "strings"
  7. "sync"
  8. "crypto/tls"
  9. "fmt"
  10. "github.com/flashmob/go-guerrilla/backends"
  11. "github.com/flashmob/go-guerrilla/log"
  12. "github.com/flashmob/go-guerrilla/mail"
  13. "github.com/flashmob/go-guerrilla/mocks"
  14. "io/ioutil"
  15. "net"
  16. "os"
  17. )
  18. // getMockServerConfig gets a mock ServerConfig struct used for creating a new server
  19. func getMockServerConfig() *ServerConfig {
  20. sc := &ServerConfig{
  21. IsEnabled: true, // not tested here
  22. Hostname: "saggydimes.test.com",
  23. MaxSize: 1024, // smtp message max size
  24. TLS: ServerTLSConfig{
  25. PrivateKeyFile: "./tests/mail.guerrillamail.com.key.pem",
  26. PublicKeyFile: "./tests/mail.guerrillamail.com.cert.pem",
  27. StartTLSOn: true,
  28. AlwaysOn: false,
  29. },
  30. Timeout: 5,
  31. ListenInterface: "127.0.0.1:2529",
  32. MaxClients: 30, // not tested here
  33. LogFile: "./tests/testlog",
  34. }
  35. return sc
  36. }
  37. // getMockServerConn gets a new server using sc. Server will be using a mocked TCP connection
  38. // using the dummy backend
  39. // RCP TO command only allows test.com host
  40. func getMockServerConn(sc *ServerConfig, t *testing.T) (*mocks.Conn, *server) {
  41. var logOpenError error
  42. var mainlog log.Logger
  43. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  44. if logOpenError != nil {
  45. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  46. }
  47. backend, err := backends.New(
  48. backends.BackendConfig{"log_received_mails": true, "save_workers_size": 1},
  49. mainlog)
  50. if err != nil {
  51. t.Error("new dummy backend failed because:", err)
  52. }
  53. server, err := newServer(sc, backend, mainlog)
  54. if err != nil {
  55. //t.Error("new server failed because:", err)
  56. } else {
  57. server.setAllowedHosts([]string{"test.com"})
  58. }
  59. conn := mocks.NewConn()
  60. return conn, server
  61. }
  62. // test the RootCAs tls config setting
  63. var rootCAPK = `-----BEGIN CERTIFICATE-----
  64. MIIDqjCCApKgAwIBAgIJALh2TrsBR5MiMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV
  65. BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEhMB8G
  66. A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhv
  67. c3QwIBcNMTgwNTE4MDYzOTU2WhgPMjExODA0MjQwNjM5NTZaMGkxCzAJBgNVBAYT
  68. AlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEhMB8GA1UE
  69. CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3Qw
  70. ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCcb0ulYT1o5ysor5UtWYW
  71. q/ZY3PyK3/4YBZq5JoX4xk7GNQQ+3p/Km7QPoBXfgjFLZXEV2R0bE5hHMXfLa5Xb
  72. 64acb9VqCqDvPFXcaNP4rEdBKDVN2p0PEi917tcKBSrZn5Yl+iOhtcBpQDvhHgn/
  73. 9MdmIAKB3+yK+4l9YhT40XfDXCQqzfg4XcNaEgTzZHcDJz+KjWJuJChprcx27MTI
  74. Ndxs9nmFA2rK16rjgjtwjZ4t9dXsljdOcx59s6dIQ0GnEM8qdKxi/vEx4+M/hbGf
  75. v7H75LsuKRrVJINAmfy9fmc6VAXjFU0ZVxGK5eVnzsh/hY08TSSrlCCKAJpksjJz
  76. AgMBAAGjUzBRMB0GA1UdDgQWBBSZsYWs+8FYe4z4c6LLmFB4TeeV/jAfBgNVHSME
  77. GDAWgBSZsYWs+8FYe4z4c6LLmFB4TeeV/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
  78. SIb3DQEBCwUAA4IBAQAcXt/FaILkOCMj8bTUx42vi2N9ZTiEuRbYi24IyGOokbDR
  79. pSsIxiz+HDPUuX6/X/mHidl24aS9wdv5JTXMr44/BeGK1WC7gMueZBxAqONpaG1Q
  80. VU0e3q1YwXKcupKQ7kVWl0fuY3licv0+s4zBcTLKkmWAYqsb/n0KtCMyqewi+Rqa
  81. Zj5Z3OcWOq9Ad9fZWKcG8k/sgeTk9z0X1mZcEyWWxqsUmxvN+SdWLoug1xJVVbMN
  82. CipZ0vBIi9KOhQgzuIFhoTcd6myUtov52/EFqlX6UuFpY2gEWw/f/yu+SI08v4w9
  83. KwxgAKBkhx2JYZKtu1EsPIMDyS0aahcDnHqnrGAi
  84. -----END CERTIFICATE-----`
  85. var clientPrvKey = `-----BEGIN RSA PRIVATE KEY-----
  86. MIIEowIBAAKCAQEA5ZLmMBdKkVyVmN0VhDSFGvgKp24ejHPCv+wfuf3vlU9cwKfH
  87. R3vejleZAVRcidscfA0Jsub/Glsr0XwecagtpvTI+Fp1ik6sICOz+VW3958qaAi8
  88. TjbUMjcDHJeSLcjr725CH5uIvhRzR+daYaJQhAcL2MEt8M9WIF6AjtDZEH9R6oM8
  89. t5FkO0amImlnipYXNBFghmzkZzfGXXRQLw2A+u6keLcjCrn9h2BaofGIjQfYcu/3
  90. fH4cIFR4z/soGKameqnCUz7dWmbf4tAI+8QR0VXXBKhiHDm98tPSeH994hC52Uul
  91. rjEVcM5Uox5hazS2PK06oSc1YuFZONqeeGqj6wIDAQABAoIBADERzRHKaK3ZVEBw
  92. QQEZGLpC+kP/TZhHxgCvv7hJhsQrSnADbJzi5RcXsiSOm5j7tILvZntO1IgVpLAK
  93. D5fLkrZ069/pteXyGuhjuTw6DjBnXPEPrPAq2ABDse6SlzQiFgv/TTLkU74NMPbV
  94. hIQJ5ZvSxb12zRMDviz9Bg2ApmTX6k2iPjQBnEHgKzb64IdMcEb5HE1qNt0v0lRA
  95. sGBMZZKQWbt2m0pSbAbnB3S9GcpJkRgFFMdTaUScIWO6ICT2hBP2pw2/4M2Zrmlt
  96. bsyWu9uswBzhvu+/pg2E66V6mji0EzDMlXqjlO5jro6t7P33t1zkd/i/ykKmtDLp
  97. IpR94UECgYEA9Y4EIjOyaBWJ6TRQ6a/tehGPbwIOgvEiTYXRJqdU49qn/i4YZjSm
  98. F4iibJz+JeOIQXSwa9F7gRlaspIuHgIJoer7BrITMuhr+afqMLkxK0pijul/qAbm
  99. HdpFn8IxjpNu4/GoAENbEVy50SMST9yWh5ulEkHHftd4/NJKoJQ2PZ8CgYEA71bb
  100. lFVh1MFclxRKECmpyoqUAzwGlMoHJy/jaBYuWG4X7rzxqDRrgPH3as6gXpRiSZ+K
  101. 5fC+wcU7dKnHtJOkBDk6J5ev2+hbwg+yq3w4+l3bPDvf2TJyXjXjRDZo12pxFD58
  102. ybCOF6ItbIDXqT5pvo3PMjgMwu1Ycie+h6hA3jUCgYEAsq93XpQT/R2/T44cWxEE
  103. VFG2+GacvLhP5+26ttAJPA1/Nb3BT458Vp+84iCT6GpcWpVZU/wKTXVvxIYPPRLq
  104. g4MEzGiFBASRngiMqIv6ta/ZbHmJxXHPvmV5SLn9aezrQsA1KovZFxdMuF03FBpH
  105. B8NBKbnoO+r8Ra2ZVKTFm60CgYAZw8Dpi/N3IsWj4eRDLyj/C8H5Qyn2NHVmq4oQ
  106. d2rPzDI5Wg+tqs7z15hp4Ap1hAW8pTcfn7X5SBEpculzr/0VE1AGWRbuVmoiTuxN
  107. 95ZupVHnfw6O5BZZu/VWL4FDx0qbAksOrznso2G+b3RH3NcnUz69yjjddw1xZIPn
  108. OJ6bDQKBgDUcWYu/2amU18D5vJpppUgRq2084WPUeXsaniTbmWfOC8NAn8CKLY0N
  109. V4yGSu98apDuqEVqL0VFQEgqK+5KTvRdXXYi36XYRbbVUgV13xveq2YTvjNbPM60
  110. QWG9YmgH7hVYGusuh5nQeS0qiIpwyws2H5mBVrGXrQ1Xb0MLWj8/
  111. -----END RSA PRIVATE KEY-----`
  112. // signed using the Root (rootCAPK)
  113. var clientPubKey = `-----BEGIN CERTIFICATE-----
  114. MIIDWDCCAkACCQCHoh4OvUySOzANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJV
  115. UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxITAfBgNVBAoM
  116. GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MCAX
  117. DTE4MDUxODA2NDQ0NVoYDzMwMTcwOTE4MDY0NDQ1WjBxMQswCQYDVQQGEwJVUzET
  118. MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEhMB8G
  119. A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhv
  120. c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDlkuYwF0qRXJWY3RWE
  121. NIUa+Aqnbh6Mc8K/7B+5/e+VT1zAp8dHe96OV5kBVFyJ2xx8DQmy5v8aWyvRfB5x
  122. qC2m9Mj4WnWKTqwgI7P5Vbf3nypoCLxONtQyNwMcl5ItyOvvbkIfm4i+FHNH51ph
  123. olCEBwvYwS3wz1YgXoCO0NkQf1Hqgzy3kWQ7RqYiaWeKlhc0EWCGbORnN8ZddFAv
  124. DYD67qR4tyMKuf2HYFqh8YiNB9hy7/d8fhwgVHjP+ygYpqZ6qcJTPt1aZt/i0Aj7
  125. xBHRVdcEqGIcOb3y09J4f33iELnZS6WuMRVwzlSjHmFrNLY8rTqhJzVi4Vk42p54
  126. aqPrAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIQmlo8iCpyYggkbpfDmThBPHfy1
  127. cZcCi/tRFoFe1ccwn2ezLMIKmW38ZebiroawwqrZgU6AP+dMxVKLMjpyLPSrpFKa
  128. 3o/LbVF7qMfH8/y2q8t7javd6rxoENH9uxLyHhauzI1iWy0whoDWBNiZrPBTBCjq
  129. jDGZARZqGyrPeXi+RNe1cMvZCxAFy7gqEtWFLWWrp0gYNPvxkHhhQBrUcF+8T/Nf
  130. 9G4hKZSN/KAgC0CNBVuNrdyNc3l8H66BfwwL5X0+pesBYZM+MEfmBZOo+p7OWx2r
  131. ug8tR8eSL1vGleONtFRBUVG7NbtjhBf9FhvPZcSRR10od/vWHku9E01i4xg=
  132. -----END CERTIFICATE-----`
  133. func TestTLSConfig(t *testing.T) {
  134. if err := ioutil.WriteFile("rootca.test.pem", []byte(rootCAPK), 0644); err != nil {
  135. t.Fatal("couldn't create rootca.test.pem file.", err)
  136. return
  137. }
  138. if err := ioutil.WriteFile("client.test.key", []byte(clientPrvKey), 0644); err != nil {
  139. t.Fatal("couldn't create client.test.key file.", err)
  140. return
  141. }
  142. if err := ioutil.WriteFile("client.test.pem", []byte(clientPubKey), 0644); err != nil {
  143. t.Fatal("couldn't create client.test.pem file.", err)
  144. return
  145. }
  146. s := server{}
  147. s.setConfig(&ServerConfig{
  148. TLS: ServerTLSConfig{
  149. StartTLSOn: true,
  150. PrivateKeyFile: "client.test.key",
  151. PublicKeyFile: "client.test.pem",
  152. RootCAs: "rootca.test.pem",
  153. ClientAuthType: "NoClientCert",
  154. Curves: []string{"P521", "P384"},
  155. Ciphers: []string{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"},
  156. Protocols: []string{"tls1.0", "tls1.2"},
  157. },
  158. })
  159. s.configureSSL()
  160. c := s.tlsConfigStore.Load().(*tls.Config)
  161. if len(c.CurvePreferences) != 2 {
  162. t.Error("c.CurvePreferences should have two elements")
  163. } else if c.CurvePreferences[0] != tls.CurveP521 && c.CurvePreferences[1] != tls.CurveP384 {
  164. t.Error("c.CurvePreferences curves not setup")
  165. }
  166. if strings.Index(string(c.RootCAs.Subjects()[0]), "Mountain View") == -1 {
  167. t.Error("c.RootCAs not correctly set")
  168. }
  169. if c.ClientAuth != tls.NoClientCert {
  170. t.Error("c.ClientAuth should be tls.NoClientCert")
  171. }
  172. if len(c.CipherSuites) != 2 {
  173. t.Error("c.CipherSuites length should be 2")
  174. }
  175. if c.CipherSuites[0] != tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 && c.CipherSuites[1] != tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA {
  176. t.Error("c.CipherSuites not correctly set ")
  177. }
  178. if c.MinVersion != tls.VersionTLS10 {
  179. t.Error("c.MinVersion should be tls.VersionTLS10")
  180. }
  181. if c.MaxVersion != tls.VersionTLS12 {
  182. t.Error("c.MinVersion should be tls.VersionTLS10")
  183. }
  184. if c.PreferServerCipherSuites != false {
  185. t.Error("PreferServerCipherSuites should be false")
  186. }
  187. os.Remove("rootca.test.pem")
  188. os.Remove("client.test.key")
  189. os.Remove("client.test.pem")
  190. }
  191. func TestHandleClient(t *testing.T) {
  192. var mainlog log.Logger
  193. var logOpenError error
  194. sc := getMockServerConfig()
  195. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  196. if logOpenError != nil {
  197. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  198. }
  199. conn, server := getMockServerConn(sc, t)
  200. // call the serve.handleClient() func in a goroutine.
  201. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
  202. var wg sync.WaitGroup
  203. wg.Add(1)
  204. go func() {
  205. server.handleClient(client)
  206. wg.Done()
  207. }()
  208. // Wait for the greeting from the server
  209. r := textproto.NewReader(bufio.NewReader(conn.Client))
  210. line, _ := r.ReadLine()
  211. // fmt.Println(line)
  212. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  213. w.PrintfLine("HELO test.test.com")
  214. line, _ = r.ReadLine()
  215. //fmt.Println(line)
  216. w.PrintfLine("QUIT")
  217. line, _ = r.ReadLine()
  218. //fmt.Println("line is:", line)
  219. expected := "221 2.0.0 Bye"
  220. if strings.Index(line, expected) != 0 {
  221. t.Error("expected", expected, "but got:", line)
  222. }
  223. wg.Wait() // wait for handleClient to exit
  224. }
  225. func TestXClient(t *testing.T) {
  226. var mainlog log.Logger
  227. var logOpenError error
  228. sc := getMockServerConfig()
  229. sc.XClientOn = true
  230. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  231. if logOpenError != nil {
  232. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  233. }
  234. conn, server := getMockServerConn(sc, t)
  235. // call the serve.handleClient() func in a goroutine.
  236. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
  237. var wg sync.WaitGroup
  238. wg.Add(1)
  239. go func() {
  240. server.handleClient(client)
  241. wg.Done()
  242. }()
  243. // Wait for the greeting from the server
  244. r := textproto.NewReader(bufio.NewReader(conn.Client))
  245. line, _ := r.ReadLine()
  246. // fmt.Println(line)
  247. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  248. w.PrintfLine("HELO test.test.com")
  249. line, _ = r.ReadLine()
  250. //fmt.Println(line)
  251. w.PrintfLine("XCLIENT ADDR=212.96.64.216 NAME=[UNAVAILABLE]")
  252. line, _ = r.ReadLine()
  253. if client.RemoteIP != "212.96.64.216" {
  254. t.Error("client.RemoteIP should be 212.96.64.216, but got:", client.RemoteIP)
  255. }
  256. expected := "250 2.1.0 OK"
  257. if strings.Index(line, expected) != 0 {
  258. t.Error("expected", expected, "but got:", line)
  259. }
  260. // try malformed input
  261. w.PrintfLine("XCLIENT c")
  262. line, _ = r.ReadLine()
  263. expected = "250 2.1.0 OK"
  264. if strings.Index(line, expected) != 0 {
  265. t.Error("expected", expected, "but got:", line)
  266. }
  267. w.PrintfLine("QUIT")
  268. line, _ = r.ReadLine()
  269. wg.Wait() // wait for handleClient to exit
  270. }
  271. // The backend gateway should time out after 1 second because it sleeps for 2 sec.
  272. // The transaction should wait until finished, and then test to see if we can do
  273. // a second transaction
  274. func TestGatewayTimeout(t *testing.T) {
  275. bcfg := backends.BackendConfig{
  276. "save_workers_size": 1,
  277. "save_process": "HeadersParser|Debugger",
  278. "log_received_mails": true,
  279. "primary_mail_host": "example.com",
  280. "gw_save_timeout": "1s",
  281. "gw_val_rcpt_timeout": "1s",
  282. "sleep_seconds": 2,
  283. }
  284. cfg := &AppConfig{
  285. LogFile: log.OutputOff.String(),
  286. AllowedHosts: []string{"grr.la"},
  287. }
  288. cfg.BackendConfig = bcfg
  289. d := Daemon{Config: cfg}
  290. err := d.Start()
  291. if err != nil {
  292. t.Error("server didn't start")
  293. } else {
  294. conn, err := net.Dial("tcp", "127.0.0.1:2525")
  295. if err != nil {
  296. return
  297. }
  298. in := bufio.NewReader(conn)
  299. str, err := in.ReadString('\n')
  300. fmt.Fprint(conn, "HELO host\r\n")
  301. str, err = in.ReadString('\n')
  302. // perform 2 transactions
  303. // both should panic.
  304. for i := 0; i < 2; i++ {
  305. fmt.Fprint(conn, "MAIL FROM:<[email protected]>r\r\n")
  306. str, err = in.ReadString('\n')
  307. fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n")
  308. str, err = in.ReadString('\n')
  309. fmt.Fprint(conn, "DATA\r\n")
  310. str, err = in.ReadString('\n')
  311. fmt.Fprint(conn, "Subject: Test subject\r\n")
  312. fmt.Fprint(conn, "\r\n")
  313. fmt.Fprint(conn, "A an email body\r\n")
  314. fmt.Fprint(conn, ".\r\n")
  315. str, err = in.ReadString('\n')
  316. expect := "transaction timeout"
  317. if strings.Index(str, expect) == -1 {
  318. t.Error("Expected the reply to have'", expect, "'but got", str)
  319. }
  320. }
  321. _ = str
  322. d.Shutdown()
  323. }
  324. }
  325. // The processor will panic and gateway should recover from it
  326. func TestGatewayPanic(t *testing.T) {
  327. bcfg := backends.BackendConfig{
  328. "save_workers_size": 1,
  329. "save_process": "HeadersParser|Debugger",
  330. "log_received_mails": true,
  331. "primary_mail_host": "example.com",
  332. "gw_save_timeout": "2s",
  333. "gw_val_rcpt_timeout": "2s",
  334. "sleep_seconds": 1,
  335. }
  336. cfg := &AppConfig{
  337. LogFile: log.OutputOff.String(),
  338. AllowedHosts: []string{"grr.la"},
  339. }
  340. cfg.BackendConfig = bcfg
  341. d := Daemon{Config: cfg}
  342. err := d.Start()
  343. if err != nil {
  344. t.Error("server didn't start")
  345. } else {
  346. conn, err := net.Dial("tcp", "127.0.0.1:2525")
  347. if err != nil {
  348. return
  349. }
  350. in := bufio.NewReader(conn)
  351. str, err := in.ReadString('\n')
  352. fmt.Fprint(conn, "HELO host\r\n")
  353. str, err = in.ReadString('\n')
  354. // perform 2 transactions
  355. // both should timeout. The reason why 2 is because we want to make
  356. // sure that the client waits until processing finishes, and the
  357. // timeout event is captured.
  358. for i := 0; i < 2; i++ {
  359. fmt.Fprint(conn, "MAIL FROM:<[email protected]>r\r\n")
  360. str, err = in.ReadString('\n')
  361. fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n")
  362. str, err = in.ReadString('\n')
  363. fmt.Fprint(conn, "DATA\r\n")
  364. str, err = in.ReadString('\n')
  365. fmt.Fprint(conn, "Subject: Test subject\r\n")
  366. fmt.Fprint(conn, "\r\n")
  367. fmt.Fprint(conn, "A an email body\r\n")
  368. fmt.Fprint(conn, ".\r\n")
  369. str, err = in.ReadString('\n')
  370. expect := "storage failed"
  371. if strings.Index(str, expect) == -1 {
  372. t.Error("Expected the reply to have'", expect, "'but got", str)
  373. }
  374. }
  375. _ = str
  376. d.Shutdown()
  377. }
  378. }
  379. func TestAllowsHosts(t *testing.T) {
  380. s := server{}
  381. allowedHosts := []string{
  382. "spam4.me",
  383. "grr.la",
  384. "newhost.com",
  385. "example.*",
  386. "*.test",
  387. "wild*.card",
  388. "multiple*wild*cards.*",
  389. }
  390. s.setAllowedHosts(allowedHosts)
  391. testTable := map[string]bool{
  392. "spam4.me": true,
  393. "dont.match": false,
  394. "example.com": true,
  395. "another.example.com": false,
  396. "anything.test": true,
  397. "wild.card": true,
  398. "wild.card.com": false,
  399. "multipleXwildXcards.com": true,
  400. }
  401. for host, allows := range testTable {
  402. if res := s.allowsHost(host); res != allows {
  403. t.Error(host, ": expected", allows, "but got", res)
  404. }
  405. }
  406. // only wildcard - should match anything
  407. s.setAllowedHosts([]string{"*"})
  408. if !s.allowsHost("match.me") {
  409. t.Error("match.me: expected true but got false")
  410. }
  411. // turns off
  412. s.setAllowedHosts([]string{"."})
  413. if !s.allowsHost("match.me") {
  414. t.Error("match.me: expected true but got false")
  415. }
  416. // no wilcards
  417. s.setAllowedHosts([]string{"grr.la", "example.com"})
  418. }
  419. // TODO
  420. // - test github issue #44 and #42