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.

265 lines
7.7 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
  1. package weed_server
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "io"
  7. "io/ioutil"
  8. "net/http"
  9. "net/url"
  10. "strconv"
  11. "strings"
  12. "github.com/chrislusf/seaweedfs/go/glog"
  13. "github.com/chrislusf/seaweedfs/go/operation"
  14. "github.com/chrislusf/seaweedfs/go/storage"
  15. "github.com/chrislusf/seaweedfs/go/util"
  16. "github.com/syndtr/goleveldb/leveldb"
  17. )
  18. func (fs *FilerServer) filerHandler(w http.ResponseWriter, r *http.Request) {
  19. switch r.Method {
  20. case "GET":
  21. fs.GetOrHeadHandler(w, r, true)
  22. case "HEAD":
  23. fs.GetOrHeadHandler(w, r, false)
  24. case "DELETE":
  25. fs.DeleteHandler(w, r)
  26. case "PUT":
  27. fs.PostHandler(w, r)
  28. case "POST":
  29. fs.PostHandler(w, r)
  30. }
  31. }
  32. // listDirectoryHandler lists directories and folers under a directory
  33. // files are sorted by name and paginated via "lastFileName" and "limit".
  34. // sub directories are listed on the first page, when "lastFileName"
  35. // is empty.
  36. func (fs *FilerServer) listDirectoryHandler(w http.ResponseWriter, r *http.Request) {
  37. if !strings.HasSuffix(r.URL.Path, "/") {
  38. return
  39. }
  40. dirlist, err := fs.filer.ListDirectories(r.URL.Path)
  41. if err == leveldb.ErrNotFound {
  42. glog.V(3).Infoln("Directory Not Found in db", r.URL.Path)
  43. w.WriteHeader(http.StatusNotFound)
  44. return
  45. }
  46. m := make(map[string]interface{})
  47. m["Directory"] = r.URL.Path
  48. lastFileName := r.FormValue("lastFileName")
  49. if lastFileName == "" {
  50. m["Subdirectories"] = dirlist
  51. }
  52. limit, limit_err := strconv.Atoi(r.FormValue("limit"))
  53. if limit_err != nil {
  54. limit = 100
  55. }
  56. m["Files"], _ = fs.filer.ListFiles(r.URL.Path, lastFileName, limit)
  57. writeJsonQuiet(w, r, http.StatusOK, m)
  58. }
  59. func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) {
  60. if strings.HasSuffix(r.URL.Path, "/") {
  61. if fs.disableDirListing {
  62. w.WriteHeader(http.StatusMethodNotAllowed)
  63. return
  64. }
  65. fs.listDirectoryHandler(w, r)
  66. return
  67. }
  68. fileId, err := fs.filer.FindFile(r.URL.Path)
  69. if err == leveldb.ErrNotFound {
  70. glog.V(3).Infoln("Not found in db", r.URL.Path)
  71. w.WriteHeader(http.StatusNotFound)
  72. return
  73. }
  74. urlLocation, err := operation.LookupFileId(fs.master, fileId)
  75. if err != nil {
  76. glog.V(1).Infoln("operation LookupFileId %s failed, err is %s", fileId, err.Error())
  77. w.WriteHeader(http.StatusNotFound)
  78. return
  79. }
  80. urlString := urlLocation
  81. if fs.redirectOnRead {
  82. http.Redirect(w, r, urlString, http.StatusFound)
  83. return
  84. }
  85. u, _ := url.Parse(urlString)
  86. request := &http.Request{
  87. Method: r.Method,
  88. URL: u,
  89. Proto: r.Proto,
  90. ProtoMajor: r.ProtoMajor,
  91. ProtoMinor: r.ProtoMinor,
  92. Header: r.Header,
  93. Body: r.Body,
  94. Host: r.Host,
  95. ContentLength: r.ContentLength,
  96. }
  97. glog.V(3).Infoln("retrieving from", u)
  98. resp, do_err := util.Do(request)
  99. if do_err != nil {
  100. glog.V(0).Infoln("failing to connect to volume server", do_err.Error())
  101. writeJsonError(w, r, http.StatusInternalServerError, do_err)
  102. return
  103. }
  104. defer resp.Body.Close()
  105. for k, v := range resp.Header {
  106. w.Header()[k] = v
  107. }
  108. w.WriteHeader(resp.StatusCode)
  109. io.Copy(w, resp.Body)
  110. }
  111. type analogueReader struct {
  112. *bytes.Buffer
  113. }
  114. // So that it implements the io.ReadCloser interface
  115. func (m analogueReader) Close() error { return nil }
  116. func (fs *FilerServer) PostHandler(w http.ResponseWriter, r *http.Request) {
  117. query := r.URL.Query()
  118. replication := query.Get("replication")
  119. if replication == "" {
  120. replication = fs.defaultReplication
  121. }
  122. collection := query.Get("collection")
  123. if collection == "" {
  124. collection = fs.collection
  125. }
  126. var fileId string
  127. var err error
  128. var urlLocation string
  129. if r.Method == "PUT" {
  130. buf, _ := ioutil.ReadAll(r.Body)
  131. r.Body = analogueReader{bytes.NewBuffer(buf)}
  132. fileName, _, _, _, _, _, _, pe := storage.ParseUpload(r)
  133. if pe != nil {
  134. glog.V(0).Infoln("failing to parse post body", pe.Error())
  135. writeJsonError(w, r, http.StatusInternalServerError, pe)
  136. return
  137. }
  138. //reconstruct http request body for following new request to volume server
  139. r.Body = analogueReader{bytes.NewBuffer(buf)}
  140. path := r.URL.Path
  141. if strings.HasSuffix(path, "/") {
  142. if fileName != "" {
  143. path += fileName
  144. }
  145. }
  146. if fileId, err = fs.filer.FindFile(path); err != nil && err != leveldb.ErrNotFound {
  147. glog.V(0).Infoln("failing to find path in filer store", path, err.Error())
  148. writeJsonError(w, r, http.StatusInternalServerError, err)
  149. return
  150. } else if fileId != "" && err == nil {
  151. var le error
  152. urlLocation, le = operation.LookupFileId(fs.master, fileId)
  153. if le != nil {
  154. glog.V(1).Infoln("operation LookupFileId %s failed, err is %s", fileId, le.Error())
  155. w.WriteHeader(http.StatusNotFound)
  156. return
  157. }
  158. }
  159. } else {
  160. assignResult, ae := operation.Assign(fs.master, 1, replication, collection, query.Get("ttl"))
  161. if ae != nil {
  162. glog.V(0).Infoln("failing to assign a file id", ae.Error())
  163. writeJsonError(w, r, http.StatusInternalServerError, ae)
  164. return
  165. }
  166. fileId = assignResult.Fid
  167. urlLocation = "http://" + assignResult.Url + "/" + assignResult.Fid
  168. }
  169. u, _ := url.Parse(urlLocation)
  170. glog.V(4).Infoln("post to", u)
  171. request := &http.Request{
  172. Method: r.Method,
  173. URL: u,
  174. Proto: r.Proto,
  175. ProtoMajor: r.ProtoMajor,
  176. ProtoMinor: r.ProtoMinor,
  177. Header: r.Header,
  178. Body: r.Body,
  179. Host: r.Host,
  180. ContentLength: r.ContentLength,
  181. }
  182. resp, do_err := util.Do(request)
  183. if do_err != nil {
  184. glog.V(0).Infoln("failing to connect to volume server", r.RequestURI, do_err.Error())
  185. writeJsonError(w, r, http.StatusInternalServerError, do_err)
  186. return
  187. }
  188. defer resp.Body.Close()
  189. resp_body, ra_err := ioutil.ReadAll(resp.Body)
  190. if ra_err != nil {
  191. glog.V(0).Infoln("failing to upload to volume server", r.RequestURI, ra_err.Error())
  192. writeJsonError(w, r, http.StatusInternalServerError, ra_err)
  193. return
  194. }
  195. glog.V(4).Infoln("post result", string(resp_body))
  196. var ret operation.UploadResult
  197. unmarshal_err := json.Unmarshal(resp_body, &ret)
  198. if unmarshal_err != nil {
  199. glog.V(0).Infoln("failing to read upload resonse", r.RequestURI, string(resp_body))
  200. writeJsonError(w, r, http.StatusInternalServerError, unmarshal_err)
  201. return
  202. }
  203. if ret.Error != "" {
  204. glog.V(0).Infoln("failing to post to volume server", r.RequestURI, ret.Error)
  205. writeJsonError(w, r, http.StatusInternalServerError, errors.New(ret.Error))
  206. return
  207. }
  208. path := r.URL.Path
  209. if strings.HasSuffix(path, "/") {
  210. if ret.Name != "" {
  211. path += ret.Name
  212. } else {
  213. operation.DeleteFile(fs.master, fileId, fs.jwt(fileId)) //clean up
  214. glog.V(0).Infoln("Can not to write to folder", path, "without a file name!")
  215. writeJsonError(w, r, http.StatusInternalServerError,
  216. errors.New("Can not to write to folder "+path+" without a file name"))
  217. return
  218. }
  219. }
  220. glog.V(4).Infoln("saving", path, "=>", fileId)
  221. if db_err := fs.filer.CreateFile(path, fileId); db_err != nil {
  222. operation.DeleteFile(fs.master, fileId, fs.jwt(fileId)) //clean up
  223. glog.V(0).Infof("failing to write %s to filer server : %v", path, db_err)
  224. writeJsonError(w, r, http.StatusInternalServerError, db_err)
  225. return
  226. }
  227. w.WriteHeader(http.StatusCreated)
  228. w.Write(resp_body)
  229. }
  230. // curl -X DELETE http://localhost:8888/path/to
  231. // curl -X DELETE http://localhost:8888/path/to?recursive=true
  232. func (fs *FilerServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
  233. var err error
  234. var fid string
  235. if strings.HasSuffix(r.URL.Path, "/") {
  236. isRecursive := r.FormValue("recursive") == "true"
  237. err = fs.filer.DeleteDirectory(r.URL.Path, isRecursive)
  238. } else {
  239. fid, err = fs.filer.DeleteFile(r.URL.Path)
  240. if err == nil && fid != "" {
  241. err = operation.DeleteFile(fs.master, fid, fs.jwt(fid))
  242. }
  243. }
  244. if err == nil {
  245. writeJsonQuiet(w, r, http.StatusAccepted, map[string]string{"error": ""})
  246. } else {
  247. glog.V(4).Infoln("deleting", r.URL.Path, ":", err.Error())
  248. writeJsonError(w, r, http.StatusInternalServerError, err)
  249. }
  250. }