You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2090 lines
67 KiB

  1. /*
  2. * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package cmd
  17. import (
  18. "bufio"
  19. "bytes"
  20. "crypto/hmac"
  21. "crypto/sha1"
  22. "crypto/tls"
  23. "encoding/base64"
  24. "encoding/hex"
  25. "encoding/json"
  26. "errors"
  27. "fmt"
  28. "io"
  29. "io/ioutil"
  30. "math/rand"
  31. "net"
  32. "net/http"
  33. "net/http/httptest"
  34. "net/url"
  35. "os"
  36. "reflect"
  37. "sort"
  38. "strconv"
  39. "strings"
  40. "sync"
  41. "testing"
  42. "time"
  43. "github.com/fatih/color"
  44. router "github.com/gorilla/mux"
  45. )
  46. // Tests should initNSLock only once.
  47. func init() {
  48. // Initialize name space lock.
  49. isDist := false
  50. initNSLock(isDist)
  51. // Disable printing console messages during tests.
  52. color.Output = ioutil.Discard
  53. }
  54. func prepareFS() (ObjectLayer, string, error) {
  55. fsDirs, err := getRandomDisks(1)
  56. if err != nil {
  57. return nil, "", err
  58. }
  59. endpoints, err := parseStorageEndpoints(fsDirs)
  60. if err != nil {
  61. return nil, "", err
  62. }
  63. obj, _, err := initObjectLayer(endpoints, nil)
  64. if err != nil {
  65. removeRoots(fsDirs)
  66. return nil, "", err
  67. }
  68. return obj, fsDirs[0], nil
  69. }
  70. func prepareXL() (ObjectLayer, []string, error) {
  71. nDisks := 16
  72. fsDirs, err := getRandomDisks(nDisks)
  73. if err != nil {
  74. return nil, nil, err
  75. }
  76. endpoints, err := parseStorageEndpoints(fsDirs)
  77. if err != nil {
  78. return nil, nil, err
  79. }
  80. obj, _, err := initObjectLayer(endpoints, nil)
  81. if err != nil {
  82. removeRoots(fsDirs)
  83. return nil, nil, err
  84. }
  85. return obj, fsDirs, nil
  86. }
  87. // TestErrHandler - Golang Testing.T and Testing.B, and gocheck.C satisfy this interface.
  88. // This makes it easy to run the TestServer from any of the tests.
  89. // Using this interface, functionalities to be used in tests can be made generalized, and can be integrated in benchmarks/unit tests/go check suite tests.
  90. type TestErrHandler interface {
  91. Error(args ...interface{})
  92. Errorf(format string, args ...interface{})
  93. Failed() bool
  94. Fatal(args ...interface{})
  95. Fatalf(format string, args ...interface{})
  96. }
  97. const (
  98. // FSTestStr is the string which is used as notation for Single node ObjectLayer in the unit tests.
  99. FSTestStr string = "FS"
  100. // XLTestStr is the string which is used as notation for XL ObjectLayer in the unit tests.
  101. XLTestStr string = "XL"
  102. )
  103. const letterBytes = "abcdefghijklmnopqrstuvwxyz01234569"
  104. const (
  105. letterIdxBits = 6 // 6 bits to represent a letter index
  106. letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
  107. letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
  108. )
  109. // Random number state.
  110. // We generate random temporary file names so that there's a good
  111. // chance the file doesn't exist yet.
  112. var randN uint32
  113. var randmu sync.Mutex
  114. // reseed - returns a new seed every time the function is called.
  115. func reseed() uint32 {
  116. return uint32(time.Now().UnixNano() + int64(os.Getpid()))
  117. }
  118. // nextSuffix - provides a new unique suffix every time the function is called.
  119. func nextSuffix() string {
  120. randmu.Lock()
  121. r := randN
  122. // Initial seed required, generate one.
  123. if r == 0 {
  124. r = reseed()
  125. }
  126. // constants from Numerical Recipes
  127. r = r*1664525 + 1013904223
  128. randN = r
  129. randmu.Unlock()
  130. return strconv.Itoa(int(1e9 + r%1e9))[1:]
  131. }
  132. // isSameType - compares two object types via reflect.TypeOf
  133. func isSameType(obj1, obj2 interface{}) bool {
  134. return reflect.TypeOf(obj1) == reflect.TypeOf(obj2)
  135. }
  136. // TestServer encapsulates an instantiation of a Minio instance with a temporary backend.
  137. // Example usage:
  138. // s := StartTestServer(t,"XL")
  139. // defer s.Stop()
  140. type TestServer struct {
  141. Root string
  142. Disks []*url.URL
  143. AccessKey string
  144. SecretKey string
  145. Server *httptest.Server
  146. Obj ObjectLayer
  147. SrvCmdCfg serverCmdConfig
  148. }
  149. func UnstartedTestServer(t TestErrHandler, instanceType string) TestServer {
  150. // create an instance of TestServer.
  151. testServer := TestServer{}
  152. // create temporary backend for the test server.
  153. nDisks := 16
  154. disks, err := getRandomDisks(nDisks)
  155. if err != nil {
  156. t.Fatal("Failed to create disks for the backend")
  157. }
  158. root, err := newTestConfig("us-east-1")
  159. if err != nil {
  160. t.Fatalf("%s", err)
  161. }
  162. // Test Server needs to start before formatting of disks.
  163. // Get credential.
  164. credentials := serverConfig.GetCredential()
  165. testServer.Root = root
  166. testServer.Disks, err = parseStorageEndpoints(disks)
  167. if err != nil {
  168. t.Fatalf("Unexpected error %s", err)
  169. }
  170. testServer.AccessKey = credentials.AccessKeyID
  171. testServer.SecretKey = credentials.SecretAccessKey
  172. objLayer, storageDisks, err := initObjectLayer(testServer.Disks, nil)
  173. if err != nil {
  174. t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err)
  175. }
  176. srvCmdCfg := serverCmdConfig{
  177. endpoints: testServer.Disks,
  178. storageDisks: storageDisks,
  179. }
  180. httpHandler, err := configureServerHandler(
  181. srvCmdCfg,
  182. )
  183. if err != nil {
  184. t.Fatalf("Failed to configure one of the RPC services <ERROR> %s", err)
  185. }
  186. // Run TestServer.
  187. testServer.Server = httptest.NewUnstartedServer(httpHandler)
  188. srvCmdCfg.serverAddr = testServer.Server.Listener.Addr().String()
  189. testServer.Obj = objLayer
  190. globalObjLayerMutex.Lock()
  191. globalObjectAPI = objLayer
  192. globalObjLayerMutex.Unlock()
  193. // initialize peer rpc
  194. host, port, err := net.SplitHostPort(srvCmdCfg.serverAddr)
  195. if err != nil {
  196. t.Fatal("Early setup error:", err)
  197. }
  198. globalMinioHost = host
  199. globalMinioPort = port
  200. globalMinioAddr = getLocalAddress(srvCmdCfg)
  201. endpoints, err := parseStorageEndpoints(disks)
  202. if err != nil {
  203. t.Fatal("Early setup error:", err)
  204. }
  205. initGlobalS3Peers(endpoints)
  206. return testServer
  207. }
  208. // Starts the test server and returns the TestServer with TLS configured instance.
  209. func StartTestTLSServer(t TestErrHandler, instanceType string) TestServer {
  210. serverKey := []byte(`-----BEGIN RSA PRIVATE KEY-----
  211. MIIEpAIBAAKCAQEAwD0kEmvtaHx+M0qJAY8zFEn6UpCIbZshNIoXOOr2S3XBEar9
  212. gtvTGpL73rPJroVcaTJxavsQJx6iD8E38t85rTsrlxEomAk5eKVK3WyplcUuqBgm
  213. +KMYyyWxMXgYA3+AumEHiDg1SMIgrWFka2x+dSsqRb64tzWtD3LLy/Amq4cdiO1v
  214. /v1rNEdqj+9G7G8leZSd8TNWZqebOwBPA4JiVtDDubemk4Qr4qYt3ChwNQiwq7Bt
  215. RFR7EokO2an9XfT1NS71evikmGduhBLz3T+3QinxZDwb6SmNouYJkdqy6oPcWt0z
  216. OXDgSPmY1NVlrujJ5JhtQTQxOs6mFVZ/82mn7wIDAQABAoIBAQCWiIoRntAGLM5J
  217. 7cjBHthZv+Az/RfH9F0ZHjU3Dc6VonzwD9x6NxbkzUpLxq9caPPHMIfdxQGOEI/J
  218. FH1yQtiQTTBCGF6YR0jor06jey6EqCZz3I3Pzy9gDIDnguoS+ynbSJW0VodrFRCv
  219. k/8lm4yexZFRkhpk5LRCz5rEdKZjU4kBgTBzeD6P1JbYKfAs49A99x9L42hExwfv
  220. ppX/7ECbdMTQRVgDytOJpQR+mrrEHq30lxNZg0XngGm/4Rby8Ga6cfxmQbUrj5of
  221. uA9TsQ6CAmTy6OqagLK4Rr9tSd4cjbBm2MCs2bDMYhzkhsveoFidsF1A9S3zSo/z
  222. VJlqFtXpAoGBAP2ewImNRpaa0D1TWk/559XZJ64MMd4J0VK4cGzXPeBZ8WGVJxqF
  223. PLl74AXG7/Iu18EWMHqTuMxlrkTKpF6KF9G5RCmAFi+UzVVspj9uvAk8SrFUA5P7
  224. c7Ahnmz44isD7OJ6sHUOP1d88dehODQdRAp5hX0h+rsTH3L6g3QRnEEdAoGBAMIK
  225. 8DJMsl2dmuuV4WPrgoqdnDnSmuC5YqxibJPJnZpgp19IxlIYRYtuUZjHIYx7OM/r
  226. 1X/dIvNqpFbvTnT9XFHWSyYMqal1+OY1Sg9i9E6YKuPAW2wccf3svhzehc98vJ0j
  227. d7S81UpfKKWY+uD/wvOJdV1Pw7SoSvs5pmbFuKt7AoGAUY7ClblDsNy6CG6MhVl0
  228. 7zT06KhtRNzdXn+HT8jr0gC6ecnwGDwuaetnABSYRsY/hY0wK8rjS3+LSf3sW6aG
  229. wF+Whs301HpCiaz1zUI737BuyJWezPC4pDQ7cQmcGX8apz4TDqF1Rxob316t5zxe
  230. DAxGHBZYPd6JZ30d1q5vFBUCgYEAvnaOHlE6Irm4ftW3TqS0lerulbMrYrmVKS/S
  231. 851KnWWR4+1C/QHmAV5fqV6Mh5/LvAr4nXEqBVP/y3VJxXuLSqjVSpvTTQsHLK/R
  232. 6hhvRVYHg1YkZpHlMiFW2m9xWKBPYs6ViUpw8XdGJoVqe7+QVAvwr47DwmgOcVm9
  233. A9O/2FECgYAgttnwo3gBxY0DJdfXBuqZCAa1MMErIxCaKw2Gm9JccnQW0fcuUcb3
  234. WSHJPyJ74ktk/QZGEmtKzAxVZ73t14dwHNNDid5CN2FyTIMCeWG5b2vM5NJe8KuQ
  235. 6cJePZj7ZkSvm2tkREdR37Oh2eZqGtaIbj6VTplvKUByWa/TEozMpQ==
  236. -----END RSA PRIVATE KEY-----`)
  237. serverPem := []byte(`-----BEGIN CERTIFICATE-----
  238. MIID2zCCAsOgAwIBAgIJALPniQGEq3KtMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD
  239. VQQGEwJJTjESMBAGA1UECAwJS2FybmF0YWthMRIwEAYDVQQHDAlCZW5nYWx1cnUx
  240. FzAVBgNVBAoMDk1pbmlvVW5pdFRlc3RzMREwDwYDVQQLDAhTU0xUZXN0czEgMB4G
  241. CSqGSIb3DQEJARYRc3NsdGVzdHNAbWluaW8uaW8wHhcNMTYxMDI0MDk1ODQzWhcN
  242. MjYxMDIyMDk1ODQzWjCBgzELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUthcm5hdGFr
  243. YTESMBAGA1UEBwwJQmVuZ2FsdXJ1MRcwFQYDVQQKDA5NaW5pb1VuaXRUZXN0czER
  244. MA8GA1UECwwIU1NMVGVzdHMxIDAeBgkqhkiG9w0BCQEWEXNzbHRlc3RzQG1pbmlv
  245. LmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwD0kEmvtaHx+M0qJ
  246. AY8zFEn6UpCIbZshNIoXOOr2S3XBEar9gtvTGpL73rPJroVcaTJxavsQJx6iD8E3
  247. 8t85rTsrlxEomAk5eKVK3WyplcUuqBgm+KMYyyWxMXgYA3+AumEHiDg1SMIgrWFk
  248. a2x+dSsqRb64tzWtD3LLy/Amq4cdiO1v/v1rNEdqj+9G7G8leZSd8TNWZqebOwBP
  249. A4JiVtDDubemk4Qr4qYt3ChwNQiwq7BtRFR7EokO2an9XfT1NS71evikmGduhBLz
  250. 3T+3QinxZDwb6SmNouYJkdqy6oPcWt0zOXDgSPmY1NVlrujJ5JhtQTQxOs6mFVZ/
  251. 82mn7wIDAQABo1AwTjAdBgNVHQ4EFgQUv++gaIEUL0sboDER+4KPpiU27FMwHwYD
  252. VR0jBBgwFoAUv++gaIEUL0sboDER+4KPpiU27FMwDAYDVR0TBAUwAwEB/zANBgkq
  253. hkiG9w0BAQsFAAOCAQEAHumbrFEBhN0EWsjZZB/VkArE/owBg7djvNetYE/rEWSV
  254. /dwysQgkTpGrCyfmzSwhsX++gr5a5qh+HAF0Ygufd5OIk/kn9X3pz66Kaq4TYdFO
  255. hc/DUD7wwY3/Mfi9lhT6lKSfMu69D3FuiI+xtUJ7CU8Fhr2ua6UB7e/2inYzsJDN
  256. WYMzrkLMasQNzNWiz3Tditxj1WuuRe9mgXbbBHT03udUyuLi+4ZiOuw6CiJL4Pfk
  257. PAKMo7QWaxAectHZsxvcfH9uYOIuv1AwDUQBA+jhADvLh55epFq0DdJ057+QKItL
  258. vtKIzIB9HcGDFfBvIq+WlxYlQPSIkeq2z1iZaTl11g==
  259. -----END CERTIFICATE-----`)
  260. // Fetch TLS key and pem files from test-data/ directory.
  261. // dir, _ := os.Getwd()
  262. // testDataDir := filepath.Join(filepath.Dir(dir), "test-data")
  263. //
  264. // pemFile := filepath.Join(testDataDir, "server.pem")
  265. // keyFile := filepath.Join(testDataDir, "server.key")
  266. cer, err := tls.X509KeyPair(serverPem, serverKey)
  267. if err != nil {
  268. t.Fatalf("Failed to load certificate: %v", err)
  269. }
  270. config := &tls.Config{Certificates: []tls.Certificate{cer}}
  271. testServer := UnstartedTestServer(t, instanceType)
  272. testServer.Server.TLS = config
  273. testServer.Server.StartTLS()
  274. return testServer
  275. }
  276. // Starts the test server and returns the TestServer instance.
  277. func StartTestServer(t TestErrHandler, instanceType string) TestServer {
  278. // create an instance of TestServer.
  279. testServer := UnstartedTestServer(t, instanceType)
  280. testServer.Server.Start()
  281. return testServer
  282. }
  283. // Initializes storage RPC endpoints.
  284. // The object Layer will be a temp back used for testing purpose.
  285. func initTestStorageRPCEndPoint(srvCmdConfig serverCmdConfig) http.Handler {
  286. // Initialize router.
  287. muxRouter := router.NewRouter()
  288. registerStorageRPCRouters(muxRouter, srvCmdConfig)
  289. return muxRouter
  290. }
  291. // StartTestStorageRPCServer - Creates a temp XL/FS backend and initializes storage RPC end points,
  292. // then starts a test server with those storage RPC end points registered.
  293. func StartTestStorageRPCServer(t TestErrHandler, instanceType string, diskN int) TestServer {
  294. // create temporary backend for the test server.
  295. disks, err := getRandomDisks(diskN)
  296. if err != nil {
  297. t.Fatal("Failed to create disks for the backend")
  298. }
  299. endpoints, err := parseStorageEndpoints(disks)
  300. if err != nil {
  301. t.Fatalf("%s", err)
  302. }
  303. root, err := newTestConfig("us-east-1")
  304. if err != nil {
  305. t.Fatalf("%s", err)
  306. }
  307. // Create an instance of TestServer.
  308. testRPCServer := TestServer{}
  309. // Get credential.
  310. credentials := serverConfig.GetCredential()
  311. testRPCServer.Root = root
  312. testRPCServer.Disks = endpoints
  313. testRPCServer.AccessKey = credentials.AccessKeyID
  314. testRPCServer.SecretKey = credentials.SecretAccessKey
  315. // Run TestServer.
  316. testRPCServer.Server = httptest.NewServer(initTestStorageRPCEndPoint(serverCmdConfig{
  317. endpoints: endpoints,
  318. }))
  319. return testRPCServer
  320. }
  321. // Sets up a Peers RPC test server.
  322. func StartTestPeersRPCServer(t TestErrHandler, instanceType string) TestServer {
  323. // create temporary backend for the test server.
  324. nDisks := 16
  325. disks, err := getRandomDisks(nDisks)
  326. if err != nil {
  327. t.Fatal("Failed to create disks for the backend")
  328. }
  329. endpoints, err := parseStorageEndpoints(disks)
  330. if err != nil {
  331. t.Fatalf("%s", err)
  332. }
  333. root, err := newTestConfig("us-east-1")
  334. if err != nil {
  335. t.Fatalf("%s", err)
  336. }
  337. // create an instance of TestServer.
  338. testRPCServer := TestServer{}
  339. // Get credential.
  340. credentials := serverConfig.GetCredential()
  341. testRPCServer.Root = root
  342. testRPCServer.Disks = endpoints
  343. testRPCServer.AccessKey = credentials.AccessKeyID
  344. testRPCServer.SecretKey = credentials.SecretAccessKey
  345. // create temporary backend for the test server.
  346. objLayer, storageDisks, err := initObjectLayer(endpoints, nil)
  347. if err != nil {
  348. t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err)
  349. }
  350. globalObjLayerMutex.Lock()
  351. globalObjectAPI = objLayer
  352. testRPCServer.Obj = objLayer
  353. globalObjLayerMutex.Unlock()
  354. srvCfg := serverCmdConfig{
  355. endpoints: endpoints,
  356. storageDisks: storageDisks,
  357. }
  358. mux := router.NewRouter()
  359. // need storage layer for bucket config storage.
  360. registerStorageRPCRouters(mux, srvCfg)
  361. // need API layer to send requests, etc.
  362. registerAPIRouter(mux)
  363. // module being tested is Peer RPCs router.
  364. registerS3PeerRPCRouter(mux)
  365. // Run TestServer.
  366. testRPCServer.Server = httptest.NewServer(mux)
  367. // Set as non-distributed.
  368. globalIsDistXL = false
  369. // initialize remainder of serverCmdConfig
  370. testRPCServer.SrvCmdCfg = srvCfg
  371. return testRPCServer
  372. }
  373. // Initializes control RPC endpoints.
  374. // The object Layer will be a temp back used for testing purpose.
  375. func initTestControlRPCEndPoint(srvCmdConfig serverCmdConfig) http.Handler {
  376. // Initialize router.
  377. muxRouter := router.NewRouter()
  378. registerControlRPCRouter(muxRouter, srvCmdConfig)
  379. return muxRouter
  380. }
  381. // StartTestControlRPCServer - Creates a temp XL/FS backend and initializes control RPC end points,
  382. // then starts a test server with those control RPC end points registered.
  383. func StartTestControlRPCServer(t TestErrHandler, instanceType string) TestServer {
  384. // create temporary backend for the test server.
  385. nDisks := 16
  386. disks, err := getRandomDisks(nDisks)
  387. if err != nil {
  388. t.Fatal("Failed to create disks for the backend")
  389. }
  390. endpoints, err := parseStorageEndpoints(disks)
  391. if err != nil {
  392. t.Fatalf("%s", err)
  393. }
  394. root, err := newTestConfig("us-east-1")
  395. if err != nil {
  396. t.Fatalf("%s", err)
  397. }
  398. // create an instance of TestServer.
  399. testRPCServer := TestServer{}
  400. // Get credential.
  401. credentials := serverConfig.GetCredential()
  402. testRPCServer.Root = root
  403. testRPCServer.Disks = endpoints
  404. testRPCServer.AccessKey = credentials.AccessKeyID
  405. testRPCServer.SecretKey = credentials.SecretAccessKey
  406. // create temporary backend for the test server.
  407. objLayer, storageDisks, err := initObjectLayer(endpoints, nil)
  408. if err != nil {
  409. t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err)
  410. }
  411. globalObjLayerMutex.Lock()
  412. globalObjectAPI = objLayer
  413. globalObjLayerMutex.Unlock()
  414. // Run TestServer.
  415. testRPCServer.Server = httptest.NewServer(initTestControlRPCEndPoint(serverCmdConfig{
  416. storageDisks: storageDisks,
  417. }))
  418. return testRPCServer
  419. }
  420. // Configure the server for the test run.
  421. func newTestConfig(bucketLocation string) (rootPath string, err error) {
  422. // Get test root.
  423. rootPath, err = getTestRoot()
  424. if err != nil {
  425. return "", err
  426. }
  427. // Do this only once here.
  428. setGlobalConfigPath(rootPath)
  429. // Initialize server config.
  430. if _, err = initConfig(); err != nil {
  431. return "", err
  432. }
  433. // Set a default region.
  434. serverConfig.SetRegion(bucketLocation)
  435. // Save config.
  436. if err = serverConfig.Save(); err != nil {
  437. return "", err
  438. }
  439. // Return root path.
  440. return rootPath, nil
  441. }
  442. // Deleting the temporary backend and stopping the server.
  443. func (testServer TestServer) Stop() {
  444. removeAll(testServer.Root)
  445. for _, disk := range testServer.Disks {
  446. removeAll(disk.Path)
  447. }
  448. testServer.Server.Close()
  449. }
  450. // Truncate request to simulate unexpected EOF for a request signed using streaming signature v4.
  451. func truncateChunkByHalfSigv4(req *http.Request) (*http.Request, error) {
  452. bufReader := bufio.NewReader(req.Body)
  453. hexChunkSize, chunkSignature, err := readChunkLine(bufReader)
  454. if err != nil {
  455. return nil, err
  456. }
  457. newChunkHdr := []byte(fmt.Sprintf("%s"+s3ChunkSignatureStr+"%s\r\n",
  458. hexChunkSize, chunkSignature))
  459. newChunk, err := ioutil.ReadAll(bufReader)
  460. if err != nil {
  461. return nil, err
  462. }
  463. newReq := req
  464. newReq.Body = ioutil.NopCloser(
  465. bytes.NewReader(bytes.Join([][]byte{newChunkHdr, newChunk[:len(newChunk)/2]},
  466. []byte(""))),
  467. )
  468. return newReq, nil
  469. }
  470. // Malform data given a request signed using streaming signature V4.
  471. func malformDataSigV4(req *http.Request, newByte byte) (*http.Request, error) {
  472. bufReader := bufio.NewReader(req.Body)
  473. hexChunkSize, chunkSignature, err := readChunkLine(bufReader)
  474. if err != nil {
  475. return nil, err
  476. }
  477. newChunkHdr := []byte(fmt.Sprintf("%s"+s3ChunkSignatureStr+"%s\r\n",
  478. hexChunkSize, chunkSignature))
  479. newChunk, err := ioutil.ReadAll(bufReader)
  480. if err != nil {
  481. return nil, err
  482. }
  483. newChunk[0] = newByte
  484. newReq := req
  485. newReq.Body = ioutil.NopCloser(
  486. bytes.NewReader(bytes.Join([][]byte{newChunkHdr, newChunk},
  487. []byte(""))),
  488. )
  489. return newReq, nil
  490. }
  491. // Malform chunk size given a request signed using streaming signatureV4.
  492. func malformChunkSizeSigV4(req *http.Request, badSize int64) (*http.Request, error) {
  493. bufReader := bufio.NewReader(req.Body)
  494. _, chunkSignature, err := readChunkLine(bufReader)
  495. if err != nil {
  496. return nil, err
  497. }
  498. n := badSize
  499. newHexChunkSize := []byte(fmt.Sprintf("%x", n))
  500. newChunkHdr := []byte(fmt.Sprintf("%s"+s3ChunkSignatureStr+"%s\r\n",
  501. newHexChunkSize, chunkSignature))
  502. newChunk, err := ioutil.ReadAll(bufReader)
  503. if err != nil {
  504. return nil, err
  505. }
  506. newReq := req
  507. newReq.Body = ioutil.NopCloser(
  508. bytes.NewReader(bytes.Join([][]byte{newChunkHdr, newChunk},
  509. []byte(""))),
  510. )
  511. return newReq, nil
  512. }
  513. // Sign given request using Signature V4.
  514. func signStreamingRequest(req *http.Request, accessKey, secretKey string, currTime time.Time) (string, error) {
  515. // Get hashed payload.
  516. hashedPayload := req.Header.Get("x-amz-content-sha256")
  517. if hashedPayload == "" {
  518. return "", fmt.Errorf("Invalid hashed payload.")
  519. }
  520. // Set x-amz-date.
  521. req.Header.Set("x-amz-date", currTime.Format(iso8601Format))
  522. // Get header map.
  523. headerMap := make(map[string][]string)
  524. for k, vv := range req.Header {
  525. // If request header key is not in ignored headers, then add it.
  526. if _, ok := ignoredStreamingHeaders[http.CanonicalHeaderKey(k)]; !ok {
  527. headerMap[strings.ToLower(k)] = vv
  528. }
  529. }
  530. // Get header keys.
  531. headers := []string{"host"}
  532. for k := range headerMap {
  533. headers = append(headers, k)
  534. }
  535. sort.Strings(headers)
  536. // Get canonical headers.
  537. var buf bytes.Buffer
  538. for _, k := range headers {
  539. buf.WriteString(k)
  540. buf.WriteByte(':')
  541. switch {
  542. case k == "host":
  543. buf.WriteString(req.URL.Host)
  544. fallthrough
  545. default:
  546. for idx, v := range headerMap[k] {
  547. if idx > 0 {
  548. buf.WriteByte(',')
  549. }
  550. buf.WriteString(v)
  551. }
  552. buf.WriteByte('\n')
  553. }
  554. }
  555. canonicalHeaders := buf.String()
  556. // Get signed headers.
  557. signedHeaders := strings.Join(headers, ";")
  558. // Get canonical query string.
  559. req.URL.RawQuery = strings.Replace(req.URL.Query().Encode(), "+", "%20", -1)
  560. // Get canonical URI.
  561. canonicalURI := getURLEncodedName(req.URL.Path)
  562. // Get canonical request.
  563. // canonicalRequest =
  564. // <HTTPMethod>\n
  565. // <CanonicalURI>\n
  566. // <CanonicalQueryString>\n
  567. // <CanonicalHeaders>\n
  568. // <SignedHeaders>\n
  569. // <HashedPayload>
  570. //
  571. canonicalRequest := strings.Join([]string{
  572. req.Method,
  573. canonicalURI,
  574. req.URL.RawQuery,
  575. canonicalHeaders,
  576. signedHeaders,
  577. hashedPayload,
  578. }, "\n")
  579. // Get scope.
  580. scope := strings.Join([]string{
  581. currTime.Format(yyyymmdd),
  582. "us-east-1",
  583. "s3",
  584. "aws4_request",
  585. }, "/")
  586. stringToSign := "AWS4-HMAC-SHA256" + "\n" + currTime.Format(iso8601Format) + "\n"
  587. stringToSign = stringToSign + scope + "\n"
  588. stringToSign = stringToSign + hex.EncodeToString(sum256([]byte(canonicalRequest)))
  589. date := sumHMAC([]byte("AWS4"+secretKey), []byte(currTime.Format(yyyymmdd)))
  590. region := sumHMAC(date, []byte("us-east-1"))
  591. service := sumHMAC(region, []byte("s3"))
  592. signingKey := sumHMAC(service, []byte("aws4_request"))
  593. signature := hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign)))
  594. // final Authorization header
  595. parts := []string{
  596. "AWS4-HMAC-SHA256" + " Credential=" + accessKey + "/" + scope,
  597. "SignedHeaders=" + signedHeaders,
  598. "Signature=" + signature,
  599. }
  600. auth := strings.Join(parts, ", ")
  601. req.Header.Set("Authorization", auth)
  602. return signature, nil
  603. }
  604. // Returns new HTTP request object.
  605. func newTestStreamingRequest(method, urlStr string, dataLength, chunkSize int64, body io.ReadSeeker) (*http.Request, error) {
  606. if method == "" {
  607. method = "POST"
  608. }
  609. req, err := http.NewRequest(method, urlStr, nil)
  610. if err != nil {
  611. return nil, err
  612. }
  613. if body == nil {
  614. // this is added to avoid panic during ioutil.ReadAll(req.Body).
  615. // th stack trace can be found here https://github.com/minio/minio/pull/2074 .
  616. // This is very similar to https://github.com/golang/go/issues/7527.
  617. req.Body = ioutil.NopCloser(bytes.NewReader([]byte("")))
  618. }
  619. contentLength := calculateStreamContentLength(dataLength, chunkSize)
  620. req.Header.Set("x-amz-content-sha256", "STREAMING-AWS4-HMAC-SHA256-PAYLOAD")
  621. req.Header.Set("content-encoding", "aws-chunked")
  622. req.Header.Set("x-amz-decoded-content-length", strconv.FormatInt(dataLength, 10))
  623. req.Header.Set("content-length", strconv.FormatInt(contentLength, 10))
  624. // Seek back to beginning.
  625. body.Seek(0, 0)
  626. // Add body
  627. req.Body = ioutil.NopCloser(body)
  628. req.ContentLength = contentLength
  629. return req, nil
  630. }
  631. func assembleStreamingChunks(req *http.Request, body io.ReadSeeker, chunkSize int64,
  632. secretKey, signature string, currTime time.Time) (*http.Request, error) {
  633. regionStr := serverConfig.GetRegion()
  634. var stream []byte
  635. var buffer []byte
  636. body.Seek(0, 0)
  637. for {
  638. buffer = make([]byte, chunkSize)
  639. n, err := body.Read(buffer)
  640. if err != nil && err != io.EOF {
  641. return nil, err
  642. }
  643. // Get scope.
  644. scope := strings.Join([]string{
  645. currTime.Format(yyyymmdd),
  646. regionStr,
  647. "s3",
  648. "aws4_request",
  649. }, "/")
  650. stringToSign := "AWS4-HMAC-SHA256-PAYLOAD" + "\n"
  651. stringToSign = stringToSign + currTime.Format(iso8601Format) + "\n"
  652. stringToSign = stringToSign + scope + "\n"
  653. stringToSign = stringToSign + signature + "\n"
  654. stringToSign = stringToSign + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + "\n" // hex(sum256(""))
  655. stringToSign = stringToSign + hex.EncodeToString(sum256(buffer[:n]))
  656. date := sumHMAC([]byte("AWS4"+secretKey), []byte(currTime.Format(yyyymmdd)))
  657. region := sumHMAC(date, []byte(regionStr))
  658. service := sumHMAC(region, []byte("s3"))
  659. signingKey := sumHMAC(service, []byte("aws4_request"))
  660. signature = hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign)))
  661. stream = append(stream, []byte(fmt.Sprintf("%x", n)+";chunk-signature="+signature+"\r\n")...)
  662. stream = append(stream, buffer[:n]...)
  663. stream = append(stream, []byte("\r\n")...)
  664. if n <= 0 {
  665. break
  666. }
  667. }
  668. req.Body = ioutil.NopCloser(bytes.NewReader(stream))
  669. return req, nil
  670. }
  671. func newTestStreamingSignedBadChunkDateRequest(method, urlStr string, contentLength, chunkSize int64, body io.ReadSeeker, accessKey, secretKey string) (*http.Request, error) {
  672. req, err := newTestStreamingRequest(method, urlStr, contentLength, chunkSize, body)
  673. if err != nil {
  674. return nil, err
  675. }
  676. currTime := time.Now().UTC()
  677. signature, err := signStreamingRequest(req, accessKey, secretKey, currTime)
  678. if err != nil {
  679. return nil, err
  680. }
  681. // skew the time between the chunk signature calculation and seed signature.
  682. currTime = currTime.Add(1 * time.Second)
  683. req, err = assembleStreamingChunks(req, body, chunkSize, secretKey, signature, currTime)
  684. return req, err
  685. }
  686. // Returns new HTTP request object signed with streaming signature v4.
  687. func newTestStreamingSignedRequest(method, urlStr string, contentLength, chunkSize int64, body io.ReadSeeker, accessKey, secretKey string) (*http.Request, error) {
  688. req, err := newTestStreamingRequest(method, urlStr, contentLength, chunkSize, body)
  689. if err != nil {
  690. return nil, err
  691. }
  692. currTime := time.Now().UTC()
  693. signature, err := signStreamingRequest(req, accessKey, secretKey, currTime)
  694. if err != nil {
  695. return nil, err
  696. }
  697. req, err = assembleStreamingChunks(req, body, chunkSize, secretKey, signature, currTime)
  698. return req, err
  699. }
  700. // Replaces any occurring '/' in string, into its encoded
  701. // representation.
  702. func percentEncodeSlash(s string) string {
  703. return strings.Replace(s, "/", "%2F", -1)
  704. }
  705. // queryEncode - encodes query values in their URL encoded form. In
  706. // addition to the percent encoding performed by getURLEncodedName()
  707. // used here, it also percent encodes '/' (forward slash)
  708. func queryEncode(v url.Values) string {
  709. if v == nil {
  710. return ""
  711. }
  712. var buf bytes.Buffer
  713. keys := make([]string, 0, len(v))
  714. for k := range v {
  715. keys = append(keys, k)
  716. }
  717. sort.Strings(keys)
  718. for _, k := range keys {
  719. vs := v[k]
  720. prefix := percentEncodeSlash(getURLEncodedName(k)) + "="
  721. for _, v := range vs {
  722. if buf.Len() > 0 {
  723. buf.WriteByte('&')
  724. }
  725. buf.WriteString(prefix)
  726. buf.WriteString(percentEncodeSlash(getURLEncodedName(v)))
  727. }
  728. }
  729. return buf.String()
  730. }
  731. // preSignV2 - presign the request in following style.
  732. // https://${S3_BUCKET}.s3.amazonaws.com/${S3_OBJECT}?AWSAccessKeyId=${S3_ACCESS_KEY}&Expires=${TIMESTAMP}&Signature=${SIGNATURE}.
  733. func preSignV2(req *http.Request, accessKeyID, secretAccessKey string, expires int64) error {
  734. // Presign is not needed for anonymous credentials.
  735. if accessKeyID == "" || secretAccessKey == "" {
  736. return errors.New("Presign cannot be generated without access and secret keys")
  737. }
  738. d := time.Now().UTC()
  739. // Find epoch expires when the request will expire.
  740. epochExpires := d.Unix() + expires
  741. // Add expires header if not present.
  742. expiresStr := req.Header.Get("Expires")
  743. if expiresStr == "" {
  744. expiresStr = strconv.FormatInt(epochExpires, 10)
  745. req.Header.Set("Expires", expiresStr)
  746. }
  747. // url.RawPath will be valid if path has any encoded characters, if not it will
  748. // be empty - in which case we need to consider url.Path (bug in net/http?)
  749. encodedResource := req.URL.RawPath
  750. encodedQuery := req.URL.RawQuery
  751. if encodedResource == "" {
  752. splits := strings.Split(req.URL.Path, "?")
  753. if len(splits) > 0 {
  754. encodedResource = splits[0]
  755. }
  756. }
  757. // Get presigned string to sign.
  758. stringToSign := presignV2STS(req.Method, encodedResource, encodedQuery, req.Header, expiresStr)
  759. hm := hmac.New(sha1.New, []byte(secretAccessKey))
  760. hm.Write([]byte(stringToSign))
  761. // Calculate signature.
  762. signature := base64.StdEncoding.EncodeToString(hm.Sum(nil))
  763. query := req.URL.Query()
  764. // Handle specially for Google Cloud Storage.
  765. query.Set("AWSAccessKeyId", accessKeyID)
  766. // Fill in Expires for presigned query.
  767. query.Set("Expires", strconv.FormatInt(epochExpires, 10))
  768. // Encode query and save.
  769. req.URL.RawQuery = queryEncode(query)
  770. // Save signature finally.
  771. req.URL.RawQuery += "&Signature=" + getURLEncodedName(signature)
  772. // Success.
  773. return nil
  774. }
  775. // Sign given request using Signature V2.
  776. func signRequestV2(req *http.Request, accessKey, secretKey string) error {
  777. // Initial time.
  778. d := time.Now().UTC()
  779. // Add date if not present.
  780. if date := req.Header.Get("Date"); date == "" {
  781. req.Header.Set("Date", d.Format(http.TimeFormat))
  782. }
  783. // url.RawPath will be valid if path has any encoded characters, if not it will
  784. // be empty - in which case we need to consider url.Path (bug in net/http?)
  785. encodedResource := req.URL.RawPath
  786. encodedQuery := req.URL.RawQuery
  787. if encodedResource == "" {
  788. splits := strings.Split(req.URL.Path, "?")
  789. if len(splits) > 0 {
  790. encodedResource = splits[0]
  791. }
  792. }
  793. // Calculate HMAC for secretAccessKey.
  794. stringToSign := signV2STS(req.Method, encodedResource, encodedQuery, req.Header)
  795. hm := hmac.New(sha1.New, []byte(secretKey))
  796. hm.Write([]byte(stringToSign))
  797. // Prepare auth header.
  798. authHeader := new(bytes.Buffer)
  799. authHeader.WriteString(fmt.Sprintf("%s %s:", signV2Algorithm, accessKey))
  800. encoder := base64.NewEncoder(base64.StdEncoding, authHeader)
  801. encoder.Write(hm.Sum(nil))
  802. encoder.Close()
  803. // Set Authorization header.
  804. req.Header.Set("Authorization", authHeader.String())
  805. return nil
  806. }
  807. // Sign given request using Signature V4.
  808. func signRequestV4(req *http.Request, accessKey, secretKey string) error {
  809. // Get hashed payload.
  810. hashedPayload := req.Header.Get("x-amz-content-sha256")
  811. if hashedPayload == "" {
  812. return fmt.Errorf("Invalid hashed payload.")
  813. }
  814. currTime := time.Now().UTC()
  815. // Set x-amz-date.
  816. req.Header.Set("x-amz-date", currTime.Format(iso8601Format))
  817. // Get header map.
  818. headerMap := make(map[string][]string)
  819. for k, vv := range req.Header {
  820. // If request header key is not in ignored headers, then add it.
  821. if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; !ok {
  822. headerMap[strings.ToLower(k)] = vv
  823. }
  824. }
  825. // Get header keys.
  826. headers := []string{"host"}
  827. for k := range headerMap {
  828. headers = append(headers, k)
  829. }
  830. sort.Strings(headers)
  831. region := serverConfig.GetRegion()
  832. // Get canonical headers.
  833. var buf bytes.Buffer
  834. for _, k := range headers {
  835. buf.WriteString(k)
  836. buf.WriteByte(':')
  837. switch {
  838. case k == "host":
  839. buf.WriteString(req.URL.Host)
  840. fallthrough
  841. default:
  842. for idx, v := range headerMap[k] {
  843. if idx > 0 {
  844. buf.WriteByte(',')
  845. }
  846. buf.WriteString(v)
  847. }
  848. buf.WriteByte('\n')
  849. }
  850. }
  851. canonicalHeaders := buf.String()
  852. // Get signed headers.
  853. signedHeaders := strings.Join(headers, ";")
  854. // Get canonical query string.
  855. req.URL.RawQuery = strings.Replace(req.URL.Query().Encode(), "+", "%20", -1)
  856. // Get canonical URI.
  857. canonicalURI := getURLEncodedName(req.URL.Path)
  858. // Get canonical request.
  859. // canonicalRequest =
  860. // <HTTPMethod>\n
  861. // <CanonicalURI>\n
  862. // <CanonicalQueryString>\n
  863. // <CanonicalHeaders>\n
  864. // <SignedHeaders>\n
  865. // <HashedPayload>
  866. //
  867. canonicalRequest := strings.Join([]string{
  868. req.Method,
  869. canonicalURI,
  870. req.URL.RawQuery,
  871. canonicalHeaders,
  872. signedHeaders,
  873. hashedPayload,
  874. }, "\n")
  875. // Get scope.
  876. scope := strings.Join([]string{
  877. currTime.Format(yyyymmdd),
  878. region,
  879. "s3",
  880. "aws4_request",
  881. }, "/")
  882. stringToSign := "AWS4-HMAC-SHA256" + "\n" + currTime.Format(iso8601Format) + "\n"
  883. stringToSign = stringToSign + scope + "\n"
  884. stringToSign = stringToSign + hex.EncodeToString(sum256([]byte(canonicalRequest)))
  885. date := sumHMAC([]byte("AWS4"+secretKey), []byte(currTime.Format(yyyymmdd)))
  886. regionHMAC := sumHMAC(date, []byte(region))
  887. service := sumHMAC(regionHMAC, []byte("s3"))
  888. signingKey := sumHMAC(service, []byte("aws4_request"))
  889. signature := hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign)))
  890. // final Authorization header
  891. parts := []string{
  892. "AWS4-HMAC-SHA256" + " Credential=" + accessKey + "/" + scope,
  893. "SignedHeaders=" + signedHeaders,
  894. "Signature=" + signature,
  895. }
  896. auth := strings.Join(parts, ", ")
  897. req.Header.Set("Authorization", auth)
  898. return nil
  899. }
  900. // getCredential generate a credential string.
  901. func getCredential(accessKeyID, location string, t time.Time) string {
  902. return accessKeyID + "/" + getScope(t, location)
  903. }
  904. // Returns new HTTP request object.
  905. func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeeker) (*http.Request, error) {
  906. if method == "" {
  907. method = "POST"
  908. }
  909. req, err := http.NewRequest(method, urlStr, nil)
  910. if err != nil {
  911. return nil, err
  912. }
  913. // Add Content-Length
  914. req.ContentLength = contentLength
  915. // Save for subsequent use
  916. var hashedPayload string
  917. switch {
  918. case body == nil:
  919. hashedPayload = hex.EncodeToString(sum256([]byte{}))
  920. default:
  921. payloadBytes, err := ioutil.ReadAll(body)
  922. if err != nil {
  923. return nil, err
  924. }
  925. hashedPayload = hex.EncodeToString(sum256(payloadBytes))
  926. md5Base64 := base64.StdEncoding.EncodeToString(sumMD5(payloadBytes))
  927. req.Header.Set("Content-Md5", md5Base64)
  928. }
  929. req.Header.Set("x-amz-content-sha256", hashedPayload)
  930. // Seek back to beginning.
  931. if body != nil {
  932. body.Seek(0, 0)
  933. // Add body
  934. req.Body = ioutil.NopCloser(body)
  935. } else {
  936. // this is added to avoid panic during ioutil.ReadAll(req.Body).
  937. // th stack trace can be found here https://github.com/minio/minio/pull/2074 .
  938. // This is very similar to https://github.com/golang/go/issues/7527.
  939. req.Body = ioutil.NopCloser(bytes.NewReader([]byte("")))
  940. }
  941. return req, nil
  942. }
  943. // Various signature types we are supporting, currently
  944. // two main signature types.
  945. type signerType int
  946. const (
  947. signerV2 signerType = iota
  948. signerV4
  949. )
  950. func newTestSignedRequest(method, urlStr string, contentLength int64, body io.ReadSeeker, accessKey, secretKey string, signer signerType) (*http.Request, error) {
  951. if signer == signerV2 {
  952. return newTestSignedRequestV2(method, urlStr, contentLength, body, accessKey, secretKey)
  953. }
  954. return newTestSignedRequestV4(method, urlStr, contentLength, body, accessKey, secretKey)
  955. }
  956. // Returns new HTTP request object signed with signature v2.
  957. func newTestSignedRequestV2(method, urlStr string, contentLength int64, body io.ReadSeeker, accessKey, secretKey string) (*http.Request, error) {
  958. req, err := newTestRequest(method, urlStr, contentLength, body)
  959. if err != nil {
  960. return nil, err
  961. }
  962. req.Header.Del("x-amz-content-sha256")
  963. // Anonymous request return quickly.
  964. if accessKey == "" || secretKey == "" {
  965. return req, nil
  966. }
  967. err = signRequestV2(req, accessKey, secretKey)
  968. if err != nil {
  969. return nil, err
  970. }
  971. return req, nil
  972. }
  973. // Returns new HTTP request object signed with signature v4.
  974. func newTestSignedRequestV4(method, urlStr string, contentLength int64, body io.ReadSeeker, accessKey, secretKey string) (*http.Request, error) {
  975. req, err := newTestRequest(method, urlStr, contentLength, body)
  976. if err != nil {
  977. return nil, err
  978. }
  979. // Anonymous request return quickly.
  980. if accessKey == "" || secretKey == "" {
  981. return req, nil
  982. }
  983. err = signRequestV4(req, accessKey, secretKey)
  984. if err != nil {
  985. return nil, err
  986. }
  987. return req, nil
  988. }
  989. // Return new WebRPC request object.
  990. func newWebRPCRequest(methodRPC, authorization string, body io.ReadSeeker) (*http.Request, error) {
  991. req, err := http.NewRequest("POST", "/minio/webrpc", nil)
  992. if err != nil {
  993. return nil, err
  994. }
  995. req.Header.Set("Content-Type", "application/json")
  996. if authorization != "" {
  997. req.Header.Set("Authorization", "Bearer "+authorization)
  998. }
  999. // Seek back to beginning.
  1000. if body != nil {
  1001. body.Seek(0, 0)
  1002. // Add body
  1003. req.Body = ioutil.NopCloser(body)
  1004. } else {
  1005. // this is added to avoid panic during ioutil.ReadAll(req.Body).
  1006. // th stack trace can be found here https://github.com/minio/minio/pull/2074 .
  1007. // This is very similar to https://github.com/golang/go/issues/7527.
  1008. req.Body = ioutil.NopCloser(bytes.NewReader([]byte("")))
  1009. }
  1010. return req, nil
  1011. }
  1012. // Marshal request and return a new HTTP request object to call the webrpc
  1013. func newTestWebRPCRequest(rpcMethod string, authorization string, data interface{}) (*http.Request, error) {
  1014. type genericJSON struct {
  1015. JSONRPC string `json:"jsonrpc"`
  1016. ID string `json:"id"`
  1017. Method string `json:"method"`
  1018. Params interface{} `json:"params"`
  1019. }
  1020. encapsulatedData := genericJSON{JSONRPC: "2.0", ID: "1", Method: rpcMethod, Params: data}
  1021. jsonData, err := json.Marshal(encapsulatedData)
  1022. if err != nil {
  1023. return nil, err
  1024. }
  1025. req, err := newWebRPCRequest(rpcMethod, authorization, bytes.NewReader(jsonData))
  1026. if err != nil {
  1027. return nil, err
  1028. }
  1029. return req, nil
  1030. }
  1031. type ErrWebRPC struct {
  1032. Code int `json:"code"`
  1033. Message string `json:"message"`
  1034. Data interface{} `json:"data"`
  1035. }
  1036. // Unmarshal response and return the webrpc response
  1037. func getTestWebRPCResponse(resp *httptest.ResponseRecorder, data interface{}) error {
  1038. type rpcReply struct {
  1039. ID string `json:"id"`
  1040. JSONRPC string `json:"jsonrpc"`
  1041. Result interface{} `json:"result"`
  1042. Error *ErrWebRPC `json:"error"`
  1043. }
  1044. reply := &rpcReply{Result: &data}
  1045. err := json.NewDecoder(resp.Body).Decode(reply)
  1046. if err != nil {
  1047. return err
  1048. }
  1049. // For the moment, web handlers errors code are not meaningful
  1050. // Return only the error message
  1051. if reply.Error != nil {
  1052. return errors.New(reply.Error.Message)
  1053. }
  1054. return nil
  1055. }
  1056. var src = rand.NewSource(time.Now().UTC().UnixNano())
  1057. // Function to generate random string for bucket/object names.
  1058. func randString(n int) string {
  1059. b := make([]byte, n)
  1060. // A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
  1061. for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
  1062. if remain == 0 {
  1063. cache, remain = src.Int63(), letterIdxMax
  1064. }
  1065. if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
  1066. b[i] = letterBytes[idx]
  1067. i--
  1068. }
  1069. cache >>= letterIdxBits
  1070. remain--
  1071. }
  1072. return string(b)
  1073. }
  1074. // generate random object name.
  1075. func getRandomObjectName() string {
  1076. return randString(16)
  1077. }
  1078. // generate random bucket name.
  1079. func getRandomBucketName() string {
  1080. return randString(60)
  1081. }
  1082. // TruncateWriter - Writes `n` bytes, then returns with number of bytes written.
  1083. // differs from iotest.TruncateWriter, the difference is commented in the Write method.
  1084. func TruncateWriter(w io.Writer, n int64) io.Writer {
  1085. return &truncateWriter{w, n}
  1086. }
  1087. type truncateWriter struct {
  1088. w io.Writer
  1089. n int64
  1090. }
  1091. func (t *truncateWriter) Write(p []byte) (n int, err error) {
  1092. if t.n <= 0 {
  1093. return len(p), nil
  1094. }
  1095. // real write
  1096. n = len(p)
  1097. if int64(n) > t.n {
  1098. n = int(t.n)
  1099. }
  1100. n, err = t.w.Write(p[0:n])
  1101. t.n -= int64(n)
  1102. // Removed from iotest.TruncateWriter.
  1103. // Need the Write method to return truncated number of bytes written, not the size of the buffer requested to be written.
  1104. // if err == nil {
  1105. // n = len(p)
  1106. // }
  1107. return
  1108. }
  1109. // NewEOFWriter returns a Writer that writes to w,
  1110. // but returns EOF error after writing n bytes.
  1111. func NewEOFWriter(w io.Writer, n int64) io.Writer {
  1112. return &EOFWriter{w, n}
  1113. }
  1114. type EOFWriter struct {
  1115. w io.Writer
  1116. n int64
  1117. }
  1118. // io.Writer implementation designed to error out with io.EOF after reading `n` bytes.
  1119. func (t *EOFWriter) Write(p []byte) (n int, err error) {
  1120. if t.n <= 0 {
  1121. return -1, io.EOF
  1122. }
  1123. // real write
  1124. n = len(p)
  1125. if int64(n) > t.n {
  1126. n = int(t.n)
  1127. }
  1128. n, err = t.w.Write(p[0:n])
  1129. t.n -= int64(n)
  1130. if err == nil {
  1131. n = len(p)
  1132. }
  1133. return
  1134. }
  1135. // construct URL for http requests for bucket operations.
  1136. func makeTestTargetURL(endPoint, bucketName, objectName string, queryValues url.Values) string {
  1137. urlStr := endPoint + "/"
  1138. if bucketName != "" {
  1139. urlStr = urlStr + bucketName + "/"
  1140. }
  1141. if objectName != "" {
  1142. urlStr = urlStr + getURLEncodedName(objectName)
  1143. }
  1144. if len(queryValues) > 0 {
  1145. urlStr = urlStr + "?" + queryEncode(queryValues)
  1146. }
  1147. return urlStr
  1148. }
  1149. // return URL for uploading object into the bucket.
  1150. func getPutObjectURL(endPoint, bucketName, objectName string) string {
  1151. return makeTestTargetURL(endPoint, bucketName, objectName, url.Values{})
  1152. }
  1153. func getPutObjectPartURL(endPoint, bucketName, objectName, uploadID, partNumber string) string {
  1154. queryValues := url.Values{}
  1155. queryValues.Set("uploadId", uploadID)
  1156. queryValues.Set("partNumber", partNumber)
  1157. return makeTestTargetURL(endPoint, bucketName, objectName, queryValues)
  1158. }
  1159. // return URL for fetching object from the bucket.
  1160. func getGetObjectURL(endPoint, bucketName, objectName string) string {
  1161. return makeTestTargetURL(endPoint, bucketName, objectName, url.Values{})
  1162. }
  1163. // return URL for deleting the object from the bucket.
  1164. func getDeleteObjectURL(endPoint, bucketName, objectName string) string {
  1165. return makeTestTargetURL(endPoint, bucketName, objectName, url.Values{})
  1166. }
  1167. // return URL for deleting multiple objects from a bucket.
  1168. func getMultiDeleteObjectURL(endPoint, bucketName string) string {
  1169. queryValue := url.Values{}
  1170. queryValue.Set("delete", "")
  1171. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1172. }
  1173. // return URL for HEAD on the object.
  1174. func getHeadObjectURL(endPoint, bucketName, objectName string) string {
  1175. return makeTestTargetURL(endPoint, bucketName, objectName, url.Values{})
  1176. }
  1177. // return url to be used while copying the object.
  1178. func getCopyObjectURL(endPoint, bucketName, objectName string) string {
  1179. return makeTestTargetURL(endPoint, bucketName, objectName, url.Values{})
  1180. }
  1181. // return URL for inserting bucket notification.
  1182. func getPutNotificationURL(endPoint, bucketName string) string {
  1183. queryValue := url.Values{}
  1184. queryValue.Set("notification", "")
  1185. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1186. }
  1187. // return URL for fetching bucket notification.
  1188. func getGetNotificationURL(endPoint, bucketName string) string {
  1189. queryValue := url.Values{}
  1190. queryValue.Set("notification", "")
  1191. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1192. }
  1193. // return URL for inserting bucket policy.
  1194. func getPutPolicyURL(endPoint, bucketName string) string {
  1195. queryValue := url.Values{}
  1196. queryValue.Set("policy", "")
  1197. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1198. }
  1199. // return URL for fetching bucket policy.
  1200. func getGetPolicyURL(endPoint, bucketName string) string {
  1201. queryValue := url.Values{}
  1202. queryValue.Set("policy", "")
  1203. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1204. }
  1205. // return URL for deleting bucket policy.
  1206. func getDeletePolicyURL(endPoint, bucketName string) string {
  1207. queryValue := url.Values{}
  1208. queryValue.Set("policy", "")
  1209. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1210. }
  1211. // return URL for creating the bucket.
  1212. func getMakeBucketURL(endPoint, bucketName string) string {
  1213. return makeTestTargetURL(endPoint, bucketName, "", url.Values{})
  1214. }
  1215. // return URL for listing buckets.
  1216. func getListBucketURL(endPoint string) string {
  1217. return makeTestTargetURL(endPoint, "", "", url.Values{})
  1218. }
  1219. // return URL for HEAD on the bucket.
  1220. func getHEADBucketURL(endPoint, bucketName string) string {
  1221. return makeTestTargetURL(endPoint, bucketName, "", url.Values{})
  1222. }
  1223. // return URL for deleting the bucket.
  1224. func getDeleteBucketURL(endPoint, bucketName string) string {
  1225. return makeTestTargetURL(endPoint, bucketName, "", url.Values{})
  1226. }
  1227. // return URL For fetching location of the bucket.
  1228. func getBucketLocationURL(endPoint, bucketName string) string {
  1229. queryValue := url.Values{}
  1230. queryValue.Set("location", "")
  1231. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1232. }
  1233. // return URL for listing objects in the bucket with V1 legacy API.
  1234. func getListObjectsV1URL(endPoint, bucketName string, maxKeys string) string {
  1235. queryValue := url.Values{}
  1236. if maxKeys != "" {
  1237. queryValue.Set("max-keys", maxKeys)
  1238. }
  1239. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1240. }
  1241. // return URL for listing objects in the bucket with V2 API.
  1242. func getListObjectsV2URL(endPoint, bucketName string, maxKeys string, fetchOwner string) string {
  1243. queryValue := url.Values{}
  1244. queryValue.Set("list-type", "2") // Enables list objects V2 URL.
  1245. if maxKeys != "" {
  1246. queryValue.Set("max-keys", maxKeys)
  1247. }
  1248. if fetchOwner != "" {
  1249. queryValue.Set("fetch-owner", fetchOwner)
  1250. }
  1251. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1252. }
  1253. // return URL for a new multipart upload.
  1254. func getNewMultipartURL(endPoint, bucketName, objectName string) string {
  1255. queryValue := url.Values{}
  1256. queryValue.Set("uploads", "")
  1257. return makeTestTargetURL(endPoint, bucketName, objectName, queryValue)
  1258. }
  1259. // return URL for a new multipart upload.
  1260. func getPartUploadURL(endPoint, bucketName, objectName, uploadID, partNumber string) string {
  1261. queryValues := url.Values{}
  1262. queryValues.Set("uploadId", uploadID)
  1263. queryValues.Set("partNumber", partNumber)
  1264. return makeTestTargetURL(endPoint, bucketName, objectName, queryValues)
  1265. }
  1266. // return URL for aborting multipart upload.
  1267. func getAbortMultipartUploadURL(endPoint, bucketName, objectName, uploadID string) string {
  1268. queryValue := url.Values{}
  1269. queryValue.Set("uploadId", uploadID)
  1270. return makeTestTargetURL(endPoint, bucketName, objectName, queryValue)
  1271. }
  1272. // return URL for a listing pending multipart uploads.
  1273. func getListMultipartURL(endPoint, bucketName string) string {
  1274. queryValue := url.Values{}
  1275. queryValue.Set("uploads", "")
  1276. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1277. }
  1278. // return URL for listing pending multipart uploads with parameters.
  1279. func getListMultipartUploadsURLWithParams(endPoint, bucketName, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads string) string {
  1280. queryValue := url.Values{}
  1281. queryValue.Set("uploads", "")
  1282. queryValue.Set("prefix", prefix)
  1283. queryValue.Set("delimiter", delimiter)
  1284. queryValue.Set("key-marker", keyMarker)
  1285. queryValue.Set("upload-id-marker", uploadIDMarker)
  1286. queryValue.Set("max-uploads", maxUploads)
  1287. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1288. }
  1289. // return URL for a listing parts on a given upload id.
  1290. func getListMultipartURLWithParams(endPoint, bucketName, objectName, uploadID, maxParts, partNumberMarker, encoding string) string {
  1291. queryValues := url.Values{}
  1292. queryValues.Set("uploadId", uploadID)
  1293. queryValues.Set("max-parts", maxParts)
  1294. if partNumberMarker != "" {
  1295. queryValues.Set("part-number-marker", partNumberMarker)
  1296. }
  1297. return makeTestTargetURL(endPoint, bucketName, objectName, queryValues)
  1298. }
  1299. // return URL for completing multipart upload.
  1300. // complete multipart upload request is sent after all parts are uploaded.
  1301. func getCompleteMultipartUploadURL(endPoint, bucketName, objectName, uploadID string) string {
  1302. queryValue := url.Values{}
  1303. queryValue.Set("uploadId", uploadID)
  1304. return makeTestTargetURL(endPoint, bucketName, objectName, queryValue)
  1305. }
  1306. // return URL for put bucket notification.
  1307. func getPutBucketNotificationURL(endPoint, bucketName string) string {
  1308. return getGetBucketNotificationURL(endPoint, bucketName)
  1309. }
  1310. // return URL for get bucket notification.
  1311. func getGetBucketNotificationURL(endPoint, bucketName string) string {
  1312. queryValue := url.Values{}
  1313. queryValue.Set("notification", "")
  1314. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1315. }
  1316. // return URL for listen bucket notification.
  1317. func getListenBucketNotificationURL(endPoint, bucketName string, prefixes, suffixes, events []string) string {
  1318. queryValue := url.Values{}
  1319. queryValue["prefix"] = prefixes
  1320. queryValue["suffix"] = suffixes
  1321. queryValue["events"] = events
  1322. return makeTestTargetURL(endPoint, bucketName, "", queryValue)
  1323. }
  1324. // returns temp root directory. `
  1325. func getTestRoot() (string, error) {
  1326. return ioutil.TempDir(os.TempDir(), "api-")
  1327. }
  1328. // getRandomDisks - Creates a slice of N random disks, each of the form - minio-XXX
  1329. func getRandomDisks(N int) ([]string, error) {
  1330. var erasureDisks []string
  1331. for i := 0; i < N; i++ {
  1332. path, err := ioutil.TempDir(os.TempDir(), "minio-")
  1333. if err != nil {
  1334. // Remove directories created so far.
  1335. removeRoots(erasureDisks)
  1336. return nil, err
  1337. }
  1338. erasureDisks = append(erasureDisks, path)
  1339. }
  1340. return erasureDisks, nil
  1341. }
  1342. // initObjectLayer - Instantiates object layer and returns it.
  1343. func initObjectLayer(endpoints, ignoredEndpoints []*url.URL) (ObjectLayer, []StorageAPI, error) {
  1344. storageDisks, err := initStorageDisks(endpoints, ignoredEndpoints)
  1345. if err != nil {
  1346. return nil, nil, err
  1347. }
  1348. err = waitForFormatDisks(true, endpoints, storageDisks)
  1349. if err != nil {
  1350. return nil, nil, err
  1351. }
  1352. objLayer, err := newObjectLayer(storageDisks)
  1353. if err != nil {
  1354. return nil, nil, err
  1355. }
  1356. // Disabling the cache for integration tests.
  1357. // Should use the object layer tests for validating cache.
  1358. if xl, ok := objLayer.(xlObjects); ok {
  1359. xl.objCacheEnabled = false
  1360. }
  1361. // Success.
  1362. return objLayer, storageDisks, nil
  1363. }
  1364. // removeRoots - Cleans up initialized directories during tests.
  1365. func removeRoots(roots []string) {
  1366. for _, root := range roots {
  1367. removeAll(root)
  1368. }
  1369. }
  1370. //removeDiskN - removes N disks from supplied disk slice.
  1371. func removeDiskN(disks []string, n int) {
  1372. if n > len(disks) {
  1373. n = len(disks)
  1374. }
  1375. for _, disk := range disks[:n] {
  1376. removeAll(disk)
  1377. }
  1378. }
  1379. // Makes a entire new copy of a StorageAPI slice.
  1380. func deepCopyStorageDisks(storageDisks []StorageAPI) []StorageAPI {
  1381. newStorageDisks := make([]StorageAPI, len(storageDisks))
  1382. for i, disk := range storageDisks {
  1383. newStorageDisks[i] = disk
  1384. }
  1385. return newStorageDisks
  1386. }
  1387. // Initializes storage disks with 'N' errored disks, N disks return 'err' for each disk access.
  1388. func prepareNErroredDisks(storageDisks []StorageAPI, offline int, err error, t *testing.T) []StorageAPI {
  1389. if offline > len(storageDisks) {
  1390. t.Fatal("Requested more offline disks than supplied storageDisks slice", offline, len(storageDisks))
  1391. }
  1392. for i := 0; i < offline; i++ {
  1393. d := storageDisks[i].(*posix)
  1394. storageDisks[i] = &naughtyDisk{disk: d, defaultErr: err}
  1395. }
  1396. return storageDisks
  1397. }
  1398. // Initializes storage disks with 'N' offline disks, N disks returns 'errDiskNotFound' for each disk access.
  1399. func prepareNOfflineDisks(storageDisks []StorageAPI, offline int, t *testing.T) []StorageAPI {
  1400. return prepareNErroredDisks(storageDisks, offline, errDiskNotFound, t)
  1401. }
  1402. // Initializes backend storage disks.
  1403. func prepareXLStorageDisks(t *testing.T) ([]StorageAPI, []string) {
  1404. nDisks := 16
  1405. fsDirs, err := getRandomDisks(nDisks)
  1406. if err != nil {
  1407. t.Fatal("Unexpected error: ", err)
  1408. }
  1409. endpoints, err := parseStorageEndpoints(fsDirs)
  1410. if err != nil {
  1411. t.Fatal("Unexpected error: ", err)
  1412. }
  1413. _, storageDisks, err := initObjectLayer(endpoints, nil)
  1414. if err != nil {
  1415. removeRoots(fsDirs)
  1416. t.Fatal("Unable to initialize storage disks", err)
  1417. }
  1418. return storageDisks, fsDirs
  1419. }
  1420. // creates a bucket for the tests and returns the bucket name.
  1421. // initializes the specified API endpoints for the tests.
  1422. // initialies the root and returns its path.
  1423. // return credentials.
  1424. func initAPIHandlerTest(obj ObjectLayer, endpoints []string) (bucketName string, apiRouter http.Handler, err error) {
  1425. // get random bucket name.
  1426. bucketName = getRandomBucketName()
  1427. // Create bucket.
  1428. err = obj.MakeBucket(bucketName)
  1429. if err != nil {
  1430. // failed to create newbucket, return err.
  1431. return "", nil, err
  1432. }
  1433. // Register the API end points with XL/FS object layer.
  1434. // Registering only the GetObject handler.
  1435. apiRouter = initTestAPIEndPoints(obj, endpoints)
  1436. return bucketName, apiRouter, nil
  1437. }
  1438. // ExecObjectLayerAPIAnonTest - Helper function to validate object Layer API handler
  1439. // response for anonymous/unsigned and unknown signature type HTTP request.
  1440. // Here is the brief description of some of the arguments to the function below.
  1441. // apiRouter - http.Handler with the relevant API endPoint (API endPoint under test) registered.
  1442. // anonReq - unsigned *http.Request to invoke the handler's response for anonymous requests.
  1443. // policyFunc - function to return bucketPolicy statement which would permit the anonymous request to be served.
  1444. // The test works in 2 steps, here is the description of the steps.
  1445. // STEP 1: Call the handler with the unsigned HTTP request (anonReq), assert for the `ErrAccessDenied` error response.
  1446. // STEP 2: Set the policy to allow the unsigned request, use the policyFunc to obtain the relevant statement and call
  1447. // the handler again to verify its success.
  1448. func ExecObjectLayerAPIAnonTest(t *testing.T, testName, bucketName, objectName, instanceType string, apiRouter http.Handler,
  1449. anonReq *http.Request, policyFunc func(string, string) policyStatement) {
  1450. anonTestStr := "Anonymous HTTP request test"
  1451. unknownSignTestStr := "Unknown HTTP signature test"
  1452. // simple function which ends the test by printing the common message which gives the context of the test
  1453. // and then followed by the the actual error message.
  1454. failTest := func(testType, failMsg string) {
  1455. t.Fatalf("Minio %s: %s fail for \"%s\": \n<Error> %s.", instanceType, testType, testName, failMsg)
  1456. }
  1457. // httptest Recorder to capture all the response by the http handler.
  1458. rec := httptest.NewRecorder()
  1459. // reading the body to preserve it so that it can be used again for second attempt of sending unsigned HTTP request.
  1460. // If the body is read in the handler the same request cannot be made use of.
  1461. buf, err := ioutil.ReadAll(anonReq.Body)
  1462. if err != nil {
  1463. failTest(anonTestStr, err.Error())
  1464. }
  1465. // creating 2 read closer (to set as request body) from the body content.
  1466. readerOne := ioutil.NopCloser(bytes.NewBuffer(buf))
  1467. readerTwo := ioutil.NopCloser(bytes.NewBuffer(buf))
  1468. readerThree := ioutil.NopCloser(bytes.NewBuffer(buf))
  1469. anonReq.Body = readerOne
  1470. // call the HTTP handler.
  1471. apiRouter.ServeHTTP(rec, anonReq)
  1472. // expected error response when the unsigned HTTP request is not permitted.
  1473. accesDeniedHTTPStatus := getAPIError(ErrAccessDenied).HTTPStatusCode
  1474. if rec.Code != accesDeniedHTTPStatus {
  1475. failTest(anonTestStr, fmt.Sprintf("Object API Nil Test expected to fail with %d, but failed with %d.", accesDeniedHTTPStatus, rec.Code))
  1476. }
  1477. // expected error response in bytes when objectLayer is not initialized, or set to `nil`.
  1478. expectedErrResponse := encodeResponse(getAPIErrorResponse(getAPIError(ErrAccessDenied), getGetObjectURL("", bucketName, objectName)))
  1479. // HEAD HTTTP request doesn't contain response body.
  1480. if anonReq.Method != "HEAD" {
  1481. // read the response body.
  1482. actualContent, err := ioutil.ReadAll(rec.Body)
  1483. if err != nil {
  1484. failTest(anonTestStr, fmt.Sprintf("Failed parsing response body: <ERROR> %v", err))
  1485. }
  1486. // verify whether actual error response (from the response body), matches the expected error response.
  1487. if !bytes.Equal(expectedErrResponse, actualContent) {
  1488. failTest(anonTestStr, "error response content differs from expected value")
  1489. }
  1490. }
  1491. // Set write only policy on bucket to allow anonymous HTTP request for the operation under test.
  1492. // request to go through.
  1493. policy := bucketPolicy{
  1494. Version: "1.0",
  1495. Statements: []policyStatement{policyFunc(bucketName, "")},
  1496. }
  1497. globalBucketPolicies.SetBucketPolicy(bucketName, policyChange{false, &policy})
  1498. // now call the handler again with the unsigned/anonymous request, it should be accepted.
  1499. rec = httptest.NewRecorder()
  1500. anonReq.Body = readerTwo
  1501. apiRouter.ServeHTTP(rec, anonReq)
  1502. var expectedHTTPStatus int
  1503. // expectedHTTPStatus returns 204 (http.StatusNoContent) on success.
  1504. if testName == "TestAPIDeleteObjectHandler" {
  1505. expectedHTTPStatus = http.StatusNoContent
  1506. } else if strings.Contains(testName, "BucketPolicyHandler") || testName == "ListBucketsHandler" {
  1507. // BucketPolicyHandlers and `ListBucketsHandler` doesn't support anonymous request, policy changes should allow unsigned requests.
  1508. expectedHTTPStatus = http.StatusForbidden
  1509. } else {
  1510. // other API handlers return 200OK on success.
  1511. expectedHTTPStatus = http.StatusOK
  1512. }
  1513. // compare the HTTP response status code with the expected one.
  1514. if rec.Code != expectedHTTPStatus {
  1515. failTest(anonTestStr, fmt.Sprintf("Expected the anonymous HTTP request to be served after the policy changes\n,Expected response HTTP status code to be %d, got %d.",
  1516. expectedHTTPStatus, rec.Code))
  1517. }
  1518. // test for unknown auth case.
  1519. anonReq.Body = readerThree
  1520. // Setting the `Authorization` header to a random value so that the signature falls into unknown auth case.
  1521. anonReq.Header.Set("Authorization", "nothingElse")
  1522. // initialize new response recorder.
  1523. rec = httptest.NewRecorder()
  1524. // call the handler using the HTTP Request.
  1525. apiRouter.ServeHTTP(rec, anonReq)
  1526. // verify the response body for `ErrAccessDenied` message =.
  1527. if anonReq.Method != "HEAD" {
  1528. // read the response body.
  1529. actualContent, err := ioutil.ReadAll(rec.Body)
  1530. if err != nil {
  1531. failTest(unknownSignTestStr, fmt.Sprintf("Failed parsing response body: <ERROR> %v", err))
  1532. }
  1533. // verify whether actual error response (from the response body), matches the expected error response.
  1534. if !bytes.Equal(expectedErrResponse, actualContent) {
  1535. fmt.Println(string(expectedErrResponse))
  1536. fmt.Println(string(actualContent))
  1537. failTest(unknownSignTestStr, "error response content differs from expected value")
  1538. }
  1539. }
  1540. if rec.Code != accesDeniedHTTPStatus {
  1541. failTest(unknownSignTestStr, fmt.Sprintf("Object API Unknow auth test for \"%s\", expected to fail with %d, but failed with %d.", testName, accesDeniedHTTPStatus, rec.Code))
  1542. }
  1543. }
  1544. // ExecObjectLayerAPINilTest - Sets the object layer to `nil`, and calls rhe registered object layer API endpoint, and assert the error response.
  1545. // The purpose is to validate the API handlers response when the object layer is uninitialized.
  1546. // Usage hint: Should be used at the end of the API end points tests (ex: check the last few lines of `testAPIListObjectPartsHandler`), need a sample HTTP request
  1547. // to be sent as argument so that the relevant handler is called,
  1548. // the handler registration is expected to be done since its called from within the API handler tests,
  1549. // the reference to the registered HTTP handler has to be sent as an argument.
  1550. func ExecObjectLayerAPINilTest(t TestErrHandler, bucketName, objectName, instanceType string, apiRouter http.Handler, req *http.Request) {
  1551. // httptest Recorder to capture all the response by the http handler.
  1552. rec := httptest.NewRecorder()
  1553. // The API handler gets the referece to the object layer via the global object Layer,
  1554. // setting it to `nil` in order test for handlers response for uninitialized object layer.
  1555. globalObjLayerMutex.Lock()
  1556. globalObjectAPI = nil
  1557. globalObjLayerMutex.Unlock()
  1558. // call the HTTP handler.
  1559. apiRouter.ServeHTTP(rec, req)
  1560. // expected error response when the API handler is called before the object layer is initialized,
  1561. // or when objectLayer is `nil`.
  1562. serverNotInitializedErr := getAPIError(ErrServerNotInitialized).HTTPStatusCode
  1563. if rec.Code != serverNotInitializedErr {
  1564. t.Errorf("Object API Nil Test expected to fail with %d, but failed with %d.", serverNotInitializedErr, rec.Code)
  1565. }
  1566. // expected error response in bytes when objectLayer is not initialized, or set to `nil`.
  1567. expectedErrResponse := encodeResponse(getAPIErrorResponse(getAPIError(ErrServerNotInitialized), getGetObjectURL("", bucketName, objectName)))
  1568. // HEAD HTTP Request doesn't contain body in its response,
  1569. // for other type of HTTP requests compare the response body content with the expected one.
  1570. if req.Method != "HEAD" {
  1571. // read the response body.
  1572. actualContent, err := ioutil.ReadAll(rec.Body)
  1573. if err != nil {
  1574. t.Fatalf("Minio %s: Failed parsing response body: <ERROR> %v.", instanceType, err)
  1575. }
  1576. // verify whether actual error response (from the response body), matches the expected error response.
  1577. if !bytes.Equal(expectedErrResponse, actualContent) {
  1578. t.Errorf("Minio %s: Object content differs from expected value.", instanceType)
  1579. }
  1580. }
  1581. }
  1582. // ExecObjectLayerAPITest - executes object layer API tests.
  1583. // Creates single node and XL ObjectLayer instance, registers the specified API end points and runs test for both the layers.
  1584. func ExecObjectLayerAPITest(t *testing.T, objAPITest objAPITestType, endpoints []string) {
  1585. // initialize the server and obtain the credentials and root.
  1586. // credentials are necessary to sign the HTTP request.
  1587. rootPath, err := newTestConfig("us-east-1")
  1588. if err != nil {
  1589. t.Fatalf("Unable to initialize server config. %s", err)
  1590. }
  1591. objLayer, fsDir, err := prepareFS()
  1592. if err != nil {
  1593. t.Fatalf("Initialization of object layer failed for single node setup: %s", err)
  1594. }
  1595. bucketFS, fsAPIRouter, err := initAPIHandlerTest(objLayer, endpoints)
  1596. if err != nil {
  1597. t.Fatalf("Initialzation of API handler tests failed: <ERROR> %s", err)
  1598. }
  1599. credentials := serverConfig.GetCredential()
  1600. // Executing the object layer tests for single node setup.
  1601. objAPITest(objLayer, FSTestStr, bucketFS, fsAPIRouter, credentials, t)
  1602. objLayer, xlDisks, err := prepareXL()
  1603. if err != nil {
  1604. t.Fatalf("Initialization of object layer failed for XL setup: %s", err)
  1605. }
  1606. bucketXL, xlAPIRouter, err := initAPIHandlerTest(objLayer, endpoints)
  1607. if err != nil {
  1608. t.Fatalf("Initialzation of API handler tests failed: <ERROR> %s", err)
  1609. }
  1610. credentials = serverConfig.GetCredential()
  1611. // Executing the object layer tests for XL.
  1612. objAPITest(objLayer, XLTestStr, bucketXL, xlAPIRouter, credentials, t)
  1613. // clean up the temporary test backend.
  1614. removeRoots(append(xlDisks, fsDir, rootPath))
  1615. }
  1616. // function to be passed to ExecObjectLayerAPITest, for executing object layr API handler tests.
  1617. type objAPITestType func(obj ObjectLayer, instanceType string, bucketName string,
  1618. apiRouter http.Handler, credentials credential, t *testing.T)
  1619. // Regular object test type.
  1620. type objTestType func(obj ObjectLayer, instanceType string, t TestErrHandler)
  1621. // Special object test type for disk not found situations.
  1622. type objTestDiskNotFoundType func(obj ObjectLayer, instanceType string, dirs []string, t *testing.T)
  1623. // ExecObjectLayerTest - executes object layer tests.
  1624. // Creates single node and XL ObjectLayer instance and runs test for both the layers.
  1625. func ExecObjectLayerTest(t TestErrHandler, objTest objTestType) {
  1626. // initialize the server and obtain the credentials and root.
  1627. // credentials are necessary to sign the HTTP request.
  1628. rootPath, err := newTestConfig("us-east-1")
  1629. if err != nil {
  1630. t.Fatal("Unexpected error", err)
  1631. }
  1632. defer removeAll(rootPath)
  1633. objLayer, fsDir, err := prepareFS()
  1634. if err != nil {
  1635. t.Fatalf("Initialization of object layer failed for single node setup: %s", err)
  1636. }
  1637. // Executing the object layer tests for single node setup.
  1638. objTest(objLayer, FSTestStr, t)
  1639. objLayer, fsDirs, err := prepareXL()
  1640. if err != nil {
  1641. t.Fatalf("Initialization of object layer failed for XL setup: %s", err)
  1642. }
  1643. // Executing the object layer tests for XL.
  1644. objTest(objLayer, XLTestStr, t)
  1645. defer removeRoots(append(fsDirs, fsDir))
  1646. }
  1647. // ExecObjectLayerDiskAlteredTest - executes object layer tests while altering
  1648. // disks in between tests. Creates XL ObjectLayer instance and runs test for XL layer.
  1649. func ExecObjectLayerDiskAlteredTest(t *testing.T, objTest objTestDiskNotFoundType) {
  1650. objLayer, fsDirs, err := prepareXL()
  1651. if err != nil {
  1652. t.Fatalf("Initialization of object layer failed for XL setup: %s", err)
  1653. }
  1654. // Executing the object layer tests for XL.
  1655. objTest(objLayer, XLTestStr, fsDirs, t)
  1656. defer removeRoots(fsDirs)
  1657. }
  1658. // Special object test type for stale files situations.
  1659. type objTestStaleFilesType func(obj ObjectLayer, instanceType string, dirs []string, t *testing.T)
  1660. // ExecObjectLayerStaleFilesTest - executes object layer tests those leaves stale
  1661. // files/directories under .minio/tmp. Creates XL ObjectLayer instance and runs test for XL layer.
  1662. func ExecObjectLayerStaleFilesTest(t *testing.T, objTest objTestStaleFilesType) {
  1663. nDisks := 16
  1664. erasureDisks, err := getRandomDisks(nDisks)
  1665. if err != nil {
  1666. t.Fatalf("Initialization of disks for XL setup: %s", err)
  1667. }
  1668. endpoints, err := parseStorageEndpoints(erasureDisks)
  1669. if err != nil {
  1670. t.Fatalf("Initialization of disks for XL setup: %s", err)
  1671. }
  1672. objLayer, _, err := initObjectLayer(endpoints, nil)
  1673. if err != nil {
  1674. t.Fatalf("Initialization of object layer failed for XL setup: %s", err)
  1675. }
  1676. // Executing the object layer tests for XL.
  1677. objTest(objLayer, XLTestStr, erasureDisks, t)
  1678. defer removeRoots(erasureDisks)
  1679. }
  1680. func registerBucketLevelFunc(bucket *router.Router, api objectAPIHandlers, apiFunctions ...string) {
  1681. for _, apiFunction := range apiFunctions {
  1682. switch apiFunction {
  1683. case "PostPolicy":
  1684. // Register PostPolicy handler.
  1685. bucket.Methods("POST").HeadersRegexp("Content-Type", "multipart/form-data*").HandlerFunc(api.PostPolicyBucketHandler)
  1686. // Register GetObject handler.
  1687. case "GetObject":
  1688. bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(api.GetObjectHandler)
  1689. // Register PutObject handler.
  1690. case "PutObject":
  1691. bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectHandler)
  1692. // Register Delete Object handler.
  1693. case "DeleteObject":
  1694. bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(api.DeleteObjectHandler)
  1695. // Register Copy Object handler.
  1696. case "CopyObject":
  1697. bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(api.CopyObjectHandler)
  1698. // Register PutBucket Policy handler.
  1699. case "PutBucketPolicy":
  1700. bucket.Methods("PUT").HandlerFunc(api.PutBucketPolicyHandler).Queries("policy", "")
  1701. // Register Delete bucket HTTP policy handler.
  1702. case "DeleteBucketPolicy":
  1703. bucket.Methods("DELETE").HandlerFunc(api.DeleteBucketPolicyHandler).Queries("policy", "")
  1704. // Register Get Bucket policy HTTP Handler.
  1705. case "GetBucketPolicy":
  1706. bucket.Methods("GET").HandlerFunc(api.GetBucketPolicyHandler).Queries("policy", "")
  1707. // Register GetBucketLocation handler.
  1708. case "GetBucketLocation":
  1709. bucket.Methods("GET").HandlerFunc(api.GetBucketLocationHandler).Queries("location", "")
  1710. // Register HeadBucket handler.
  1711. case "HeadBucket":
  1712. bucket.Methods("HEAD").HandlerFunc(api.HeadBucketHandler)
  1713. // Register New Multipart upload handler.
  1714. case "NewMultipart":
  1715. bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.NewMultipartUploadHandler).Queries("uploads", "")
  1716. // Register PutObjectPart handler.
  1717. case "PutObjectPart":
  1718. bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
  1719. // Register ListObjectParts handler.
  1720. case "ListObjectParts":
  1721. bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(api.ListObjectPartsHandler).Queries("uploadId", "{uploadId:.*}")
  1722. // Register ListMultipartUploads handler.
  1723. case "ListMultipartUploads":
  1724. bucket.Methods("GET").HandlerFunc(api.ListMultipartUploadsHandler).Queries("uploads", "")
  1725. // Register Complete Multipart Upload handler.
  1726. case "CompleteMultipart":
  1727. bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.CompleteMultipartUploadHandler).Queries("uploadId", "{uploadId:.*}")
  1728. // Register GetBucketNotification Handler.
  1729. case "GetBucketNotification":
  1730. bucket.Methods("GET").HandlerFunc(api.GetBucketNotificationHandler).Queries("notification", "")
  1731. // Register PutBucketNotification Handler.
  1732. case "PutBucketNotification":
  1733. bucket.Methods("PUT").HandlerFunc(api.PutBucketNotificationHandler).Queries("notification", "")
  1734. // Register ListenBucketNotification Handler.
  1735. case "ListenBucketNotification":
  1736. bucket.Methods("GET").HandlerFunc(api.ListenBucketNotificationHandler).Queries("events", "{events:.*}")
  1737. }
  1738. }
  1739. }
  1740. // registerAPIFunctions helper function to add API functions identified by name to the routers.
  1741. func registerAPIFunctions(muxRouter *router.Router, objLayer ObjectLayer, apiFunctions ...string) {
  1742. if len(apiFunctions) == 0 {
  1743. // Register all api endpoints by default.
  1744. registerAPIRouter(muxRouter)
  1745. return
  1746. }
  1747. // API Router.
  1748. apiRouter := muxRouter.NewRoute().PathPrefix("/").Subrouter()
  1749. // Bucket router.
  1750. bucketRouter := apiRouter.PathPrefix("/{bucket}").Subrouter()
  1751. // All object storage operations are registered as HTTP handlers on `objectAPIHandlers`.
  1752. // When the handlers get a HTTP request they use the underlyting ObjectLayer to perform operations.
  1753. globalObjLayerMutex.Lock()
  1754. globalObjectAPI = objLayer
  1755. globalObjLayerMutex.Unlock()
  1756. api := objectAPIHandlers{
  1757. ObjectAPI: newObjectLayerFn,
  1758. }
  1759. // Register ListBuckets handler.
  1760. apiRouter.Methods("GET").HandlerFunc(api.ListBucketsHandler)
  1761. // Register all bucket level handlers.
  1762. registerBucketLevelFunc(bucketRouter, api, apiFunctions...)
  1763. }
  1764. // Takes in XL/FS object layer, and the list of API end points to be tested/required, registers the API end points and returns the HTTP handler.
  1765. // Need isolated registration of API end points while writing unit tests for end points.
  1766. // All the API end points are registered only for the default case.
  1767. func initTestAPIEndPoints(objLayer ObjectLayer, apiFunctions []string) http.Handler {
  1768. // initialize a new mux router.
  1769. // goriilla/mux is the library used to register all the routes and handle them.
  1770. muxRouter := router.NewRouter()
  1771. if len(apiFunctions) > 0 {
  1772. // Iterate the list of API functions requested for and register them in mux HTTP handler.
  1773. registerAPIFunctions(muxRouter, objLayer, apiFunctions...)
  1774. return muxRouter
  1775. }
  1776. registerAPIRouter(muxRouter)
  1777. return muxRouter
  1778. }
  1779. // Initialize Web RPC Handlers for testing
  1780. func initTestWebRPCEndPoint(objLayer ObjectLayer) http.Handler {
  1781. globalObjLayerMutex.Lock()
  1782. globalObjectAPI = objLayer
  1783. globalObjLayerMutex.Unlock()
  1784. // Initialize router.
  1785. muxRouter := router.NewRouter()
  1786. registerWebRouter(muxRouter)
  1787. return muxRouter
  1788. }
  1789. // Initialize browser RPC endpoint.
  1790. func initTestBrowserPeerRPCEndPoint() http.Handler {
  1791. // Initialize router.
  1792. muxRouter := router.NewRouter()
  1793. registerBrowserPeerRPCRouter(muxRouter)
  1794. return muxRouter
  1795. }
  1796. func StartTestBrowserPeerRPCServer(t TestErrHandler, instanceType string) TestServer {
  1797. root, err := newTestConfig("us-east-1")
  1798. if err != nil {
  1799. t.Fatalf("%s", err)
  1800. }
  1801. // Create an instance of TestServer.
  1802. testRPCServer := TestServer{}
  1803. // Fetch credentials for the test server.
  1804. credentials := serverConfig.GetCredential()
  1805. testRPCServer.Root = root
  1806. testRPCServer.AccessKey = credentials.AccessKeyID
  1807. testRPCServer.SecretKey = credentials.SecretAccessKey
  1808. // Initialize and run the TestServer.
  1809. testRPCServer.Server = httptest.NewServer(initTestBrowserPeerRPCEndPoint())
  1810. return testRPCServer
  1811. }