zip.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * Rufs - Remote Union File System
  3. *
  4. * Copyright 2017 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package v1
  11. import (
  12. "archive/zip"
  13. "bytes"
  14. "encoding/json"
  15. "fmt"
  16. "net/http"
  17. "devt.de/krotik/rufs"
  18. "devt.de/krotik/rufs/api"
  19. )
  20. /*
  21. EndpointZip is the zip endpoint URL (rooted). Handles everything
  22. under zip/...
  23. */
  24. const EndpointZip = api.APIRoot + APIv1 + "/zip/"
  25. /*
  26. ZipEndpointInst creates a new endpoint handler.
  27. */
  28. func ZipEndpointInst() api.RestEndpointHandler {
  29. return &zipEndpoint{}
  30. }
  31. /*
  32. Handler object for zip operations.
  33. */
  34. type zipEndpoint struct {
  35. *api.DefaultEndpointHandler
  36. }
  37. /*
  38. HandlePOST handles a zip query REST call.
  39. */
  40. func (z *zipEndpoint) HandlePOST(w http.ResponseWriter, r *http.Request, resources []string) {
  41. var tree *rufs.Tree
  42. var data []string
  43. var ok bool
  44. var err error
  45. if !checkResources(w, resources, 1, 1, "Need a tree name") {
  46. return
  47. }
  48. if tree, ok, err = api.GetTree(resources[0]); err == nil && !ok {
  49. http.Error(w, fmt.Sprintf("Unknown tree: %v", resources[0]), http.StatusBadRequest)
  50. return
  51. }
  52. if err = r.ParseForm(); err == nil {
  53. files := r.Form["files"]
  54. if len(files) == 0 {
  55. err = fmt.Errorf("Field 'files' should be a list of files as JSON encoded string")
  56. } else {
  57. err = json.NewDecoder(bytes.NewBufferString(files[0])).Decode(&data)
  58. }
  59. }
  60. if err != nil {
  61. http.Error(w, fmt.Sprintf("Could not decode request body: %v", err.Error()),
  62. http.StatusBadRequest)
  63. return
  64. }
  65. w.Header().Set("content-type", "application/octet-stream")
  66. w.Header().Set("content-disposition", `attachment; filename="files.zip"`)
  67. // Go through the list of files and stream the zip file
  68. zipW := zip.NewWriter(w)
  69. for _, f := range data {
  70. writer, _ := zipW.Create(f)
  71. tree.ReadFileToBuffer(f, writer)
  72. }
  73. zipW.Close()
  74. }
  75. /*
  76. SwaggerDefs is used to describe the endpoint in swagger.
  77. */
  78. func (z *zipEndpoint) SwaggerDefs(s map[string]interface{}) {
  79. s["paths"].(map[string]interface{})["/v1/zip/{tree}"] = map[string]interface{}{
  80. "post": map[string]interface{}{
  81. "summary": "Create zip file from a list of files.",
  82. "description": "Combine a list of given files into a single zip file.",
  83. "produces": []string{
  84. "text/plain",
  85. },
  86. "consumes": []string{
  87. "application/x-www-form-urlencoded",
  88. },
  89. "parameters": []map[string]interface{}{
  90. {
  91. "name": "tree",
  92. "in": "path",
  93. "description": "Name of the tree.",
  94. "required": true,
  95. "type": "string",
  96. },
  97. {
  98. "name": "files",
  99. "in": "body",
  100. "description": "JSON encoded list of (full path) files which should be zipped up",
  101. "required": true,
  102. "schema": map[string]interface{}{
  103. "type": "array",
  104. "items": map[string]interface{}{
  105. "description": "File (with full path) which should be included in the zip file.",
  106. "type": "string",
  107. },
  108. },
  109. },
  110. },
  111. "responses": map[string]interface{}{
  112. "200": map[string]interface{}{
  113. "description": "Returns the content of the requested file.",
  114. },
  115. "default": map[string]interface{}{
  116. "description": "Error response",
  117. "schema": map[string]interface{}{
  118. "$ref": "#/definitions/Error",
  119. },
  120. },
  121. },
  122. },
  123. }
  124. }