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.

237 lines
6.7 KiB

9 years ago
6 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
6 years ago
9 years ago
9 years ago
9 years ago
6 years ago
9 years ago
9 years ago
  1. package weed_server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "io/ioutil"
  7. "mime"
  8. "net/http"
  9. "net/url"
  10. "os"
  11. filenamePath "path"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "github.com/chrislusf/seaweedfs/weed/filer2"
  16. "github.com/chrislusf/seaweedfs/weed/glog"
  17. "github.com/chrislusf/seaweedfs/weed/operation"
  18. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  19. "github.com/chrislusf/seaweedfs/weed/security"
  20. "github.com/chrislusf/seaweedfs/weed/util"
  21. )
  22. var (
  23. OS_UID = uint32(os.Getuid())
  24. OS_GID = uint32(os.Getgid())
  25. )
  26. type FilerPostResult struct {
  27. Name string `json:"name,omitempty"`
  28. Size uint32 `json:"size,omitempty"`
  29. Error string `json:"error,omitempty"`
  30. Fid string `json:"fid,omitempty"`
  31. Url string `json:"url,omitempty"`
  32. }
  33. func (fs *FilerServer) assignNewFileInfo(w http.ResponseWriter, r *http.Request, replication, collection string, dataCenter string) (fileId, urlLocation string, auth security.EncodedJwt, err error) {
  34. ar := &operation.VolumeAssignRequest{
  35. Count: 1,
  36. Replication: replication,
  37. Collection: collection,
  38. Ttl: r.URL.Query().Get("ttl"),
  39. DataCenter: dataCenter,
  40. }
  41. var altRequest *operation.VolumeAssignRequest
  42. if dataCenter != "" {
  43. altRequest = &operation.VolumeAssignRequest{
  44. Count: 1,
  45. Replication: replication,
  46. Collection: collection,
  47. Ttl: r.URL.Query().Get("ttl"),
  48. DataCenter: "",
  49. }
  50. }
  51. assignResult, ae := operation.Assign(fs.filer.GetMaster(), fs.grpcDialOption, ar, altRequest)
  52. if ae != nil {
  53. glog.Errorf("failing to assign a file id: %v", ae)
  54. writeJsonError(w, r, http.StatusInternalServerError, ae)
  55. err = ae
  56. return
  57. }
  58. fileId = assignResult.Fid
  59. urlLocation = "http://" + assignResult.Url + "/" + assignResult.Fid
  60. auth = assignResult.Auth
  61. return
  62. }
  63. func (fs *FilerServer) PostHandler(w http.ResponseWriter, r *http.Request) {
  64. ctx := context.Background()
  65. query := r.URL.Query()
  66. replication := query.Get("replication")
  67. if replication == "" {
  68. replication = fs.option.DefaultReplication
  69. }
  70. collection := query.Get("collection")
  71. if collection == "" {
  72. collection = fs.option.Collection
  73. }
  74. dataCenter := query.Get("dataCenter")
  75. if dataCenter == "" {
  76. dataCenter = fs.option.DataCenter
  77. }
  78. if autoChunked := fs.autoChunk(ctx, w, r, replication, collection, dataCenter); autoChunked {
  79. return
  80. }
  81. fileId, urlLocation, auth, err := fs.assignNewFileInfo(w, r, replication, collection, dataCenter)
  82. if err != nil || fileId == "" || urlLocation == "" {
  83. glog.V(0).Infof("fail to allocate volume for %s, collection:%s, datacenter:%s", r.URL.Path, collection, dataCenter)
  84. return
  85. }
  86. glog.V(4).Infof("write %s to %v", r.URL.Path, urlLocation)
  87. u, _ := url.Parse(urlLocation)
  88. // This allows a client to generate a chunk manifest and submit it to the filer -- it is a little off
  89. // because they need to provide FIDs instead of file paths...
  90. cm, _ := strconv.ParseBool(query.Get("cm"))
  91. if cm {
  92. q := u.Query()
  93. q.Set("cm", "true")
  94. u.RawQuery = q.Encode()
  95. }
  96. glog.V(4).Infoln("post to", u)
  97. // send request to volume server
  98. request := &http.Request{
  99. Method: r.Method,
  100. URL: u,
  101. Proto: r.Proto,
  102. ProtoMajor: r.ProtoMajor,
  103. ProtoMinor: r.ProtoMinor,
  104. Header: r.Header,
  105. Body: r.Body,
  106. Host: r.Host,
  107. ContentLength: r.ContentLength,
  108. }
  109. if auth != "" {
  110. request.Header.Set("Authorization", "BEARER "+string(auth))
  111. }
  112. resp, do_err := util.Do(request)
  113. if do_err != nil {
  114. glog.Errorf("failing to connect to volume server %s: %v, %+v", r.RequestURI, do_err, r.Method)
  115. writeJsonError(w, r, http.StatusInternalServerError, do_err)
  116. return
  117. }
  118. defer resp.Body.Close()
  119. etag := resp.Header.Get("ETag")
  120. resp_body, ra_err := ioutil.ReadAll(resp.Body)
  121. if ra_err != nil {
  122. glog.V(0).Infoln("failing to upload to volume server", r.RequestURI, ra_err.Error())
  123. writeJsonError(w, r, http.StatusInternalServerError, ra_err)
  124. return
  125. }
  126. glog.V(4).Infoln("post result", string(resp_body))
  127. var ret operation.UploadResult
  128. unmarshal_err := json.Unmarshal(resp_body, &ret)
  129. if unmarshal_err != nil {
  130. glog.V(0).Infoln("failing to read upload resonse", r.RequestURI, string(resp_body))
  131. writeJsonError(w, r, http.StatusInternalServerError, unmarshal_err)
  132. return
  133. }
  134. if ret.Error != "" {
  135. glog.V(0).Infoln("failing to post to volume server", r.RequestURI, ret.Error)
  136. writeJsonError(w, r, http.StatusInternalServerError, errors.New(ret.Error))
  137. return
  138. }
  139. // find correct final path
  140. path := r.URL.Path
  141. if strings.HasSuffix(path, "/") {
  142. if ret.Name != "" {
  143. path += ret.Name
  144. } else {
  145. fs.filer.DeleteFileByFileId(fileId)
  146. glog.V(0).Infoln("Can not to write to folder", path, "without a file name!")
  147. writeJsonError(w, r, http.StatusInternalServerError,
  148. errors.New("Can not to write to folder "+path+" without a file name"))
  149. return
  150. }
  151. }
  152. // update metadata in filer store
  153. existingEntry, err := fs.filer.FindEntry(ctx, filer2.FullPath(path))
  154. crTime := time.Now()
  155. if err == nil && existingEntry != nil {
  156. // glog.V(4).Infof("existing %s => %+v", path, existingEntry)
  157. if existingEntry.IsDirectory() {
  158. path += "/" + ret.Name
  159. } else {
  160. crTime = existingEntry.Crtime
  161. }
  162. }
  163. entry := &filer2.Entry{
  164. FullPath: filer2.FullPath(path),
  165. Attr: filer2.Attr{
  166. Mtime: time.Now(),
  167. Crtime: crTime,
  168. Mode: 0660,
  169. Uid: OS_UID,
  170. Gid: OS_GID,
  171. Replication: replication,
  172. Collection: collection,
  173. TtlSec: int32(util.ParseInt(r.URL.Query().Get("ttl"), 0)),
  174. },
  175. Chunks: []*filer_pb.FileChunk{{
  176. FileId: fileId,
  177. Size: uint64(ret.Size),
  178. Mtime: time.Now().UnixNano(),
  179. ETag: etag,
  180. }},
  181. }
  182. if ext := filenamePath.Ext(path); ext != "" {
  183. entry.Attr.Mime = mime.TypeByExtension(ext)
  184. }
  185. // glog.V(4).Infof("saving %s => %+v", path, entry)
  186. if db_err := fs.filer.CreateEntry(ctx, entry); db_err != nil {
  187. fs.filer.DeleteFileByFileId(fileId)
  188. glog.V(0).Infof("failing to write %s to filer server : %v", path, db_err)
  189. writeJsonError(w, r, http.StatusInternalServerError, db_err)
  190. return
  191. }
  192. // send back post result
  193. reply := FilerPostResult{
  194. Name: ret.Name,
  195. Size: ret.Size,
  196. Error: ret.Error,
  197. Fid: fileId,
  198. Url: urlLocation,
  199. }
  200. setEtag(w, etag)
  201. writeJsonQuiet(w, r, http.StatusCreated, reply)
  202. }
  203. // curl -X DELETE http://localhost:8888/path/to
  204. // curl -X DELETE http://localhost:8888/path/to?recursive=true
  205. func (fs *FilerServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
  206. isRecursive := r.FormValue("recursive") == "true"
  207. err := fs.filer.DeleteEntryMetaAndData(context.Background(), filer2.FullPath(r.URL.Path), isRecursive, true)
  208. if err != nil {
  209. glog.V(1).Infoln("deleting", r.URL.Path, ":", err.Error())
  210. writeJsonError(w, r, http.StatusInternalServerError, err)
  211. return
  212. }
  213. w.WriteHeader(http.StatusNoContent)
  214. }