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.

112 lines
2.9 KiB

  1. package weed_server
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "mime/multipart"
  8. "net/http"
  9. "net/textproto"
  10. "strings"
  11. "github.com/chrislusf/seaweedfs/weed/glog"
  12. "github.com/chrislusf/seaweedfs/weed/storage"
  13. )
  14. var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
  15. func escapeQuotes(s string) string {
  16. return quoteEscaper.Replace(s)
  17. }
  18. func createFormFile(writer *multipart.Writer, fieldname, filename, mime string) (io.Writer, error) {
  19. h := make(textproto.MIMEHeader)
  20. h.Set("Content-Disposition",
  21. fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
  22. escapeQuotes(fieldname), escapeQuotes(filename)))
  23. if len(mime) == 0 {
  24. mime = "application/octet-stream"
  25. }
  26. h.Set("Content-Type", mime)
  27. return writer.CreatePart(h)
  28. }
  29. func makeFormData(filename, mimeType string, content io.Reader) (formData io.Reader, contentType string, err error) {
  30. buf := new(bytes.Buffer)
  31. writer := multipart.NewWriter(buf)
  32. defer writer.Close()
  33. part, err := createFormFile(writer, "file", filename, mimeType)
  34. if err != nil {
  35. glog.V(0).Infoln(err)
  36. return
  37. }
  38. _, err = io.Copy(part, content)
  39. if err != nil {
  40. glog.V(0).Infoln(err)
  41. return
  42. }
  43. formData = buf
  44. contentType = writer.FormDataContentType()
  45. return
  46. }
  47. func (fs *FilerServer) multipartUploadAnalyzer(w http.ResponseWriter, r *http.Request, replication, collection string) (fileId, urlLocation string, err error) {
  48. //Default handle way for http multipart
  49. if r.Method == "PUT" {
  50. buf, _ := ioutil.ReadAll(r.Body)
  51. r.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
  52. fileName, _, _, _, _, _, _, _, pe := storage.ParseUpload(r)
  53. if pe != nil {
  54. glog.V(0).Infoln("failing to parse post body", pe.Error())
  55. writeJsonError(w, r, http.StatusInternalServerError, pe)
  56. err = pe
  57. return
  58. }
  59. //reconstruct http request body for following new request to volume server
  60. r.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
  61. path := r.URL.Path
  62. if strings.HasSuffix(path, "/") {
  63. if fileName != "" {
  64. path += fileName
  65. }
  66. }
  67. fileId, urlLocation, err = fs.queryFileInfoByPath(w, r, path)
  68. } else {
  69. fileId, urlLocation, err = fs.assignNewFileInfo(w, r, replication, collection)
  70. }
  71. return
  72. }
  73. func multipartHttpBodyBuilder(w http.ResponseWriter, r *http.Request, fileName string) (err error) {
  74. body, contentType, te := makeFormData(fileName, r.Header.Get("Content-Type"), r.Body)
  75. if te != nil {
  76. glog.V(0).Infoln("S3 protocol to raw seaweed protocol failed", te.Error())
  77. writeJsonError(w, r, http.StatusInternalServerError, te)
  78. err = te
  79. return
  80. }
  81. if body != nil {
  82. switch v := body.(type) {
  83. case *bytes.Buffer:
  84. r.ContentLength = int64(v.Len())
  85. case *bytes.Reader:
  86. r.ContentLength = int64(v.Len())
  87. case *strings.Reader:
  88. r.ContentLength = int64(v.Len())
  89. }
  90. }
  91. r.Header.Set("Content-Type", contentType)
  92. rc, ok := body.(io.ReadCloser)
  93. if !ok && body != nil {
  94. rc = ioutil.NopCloser(body)
  95. }
  96. r.Body = rc
  97. return
  98. }