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.

215 lines
6.4 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
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
  1. package weed_server
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io"
  6. "io/ioutil"
  7. "math/rand"
  8. "net/http"
  9. "net/url"
  10. "strconv"
  11. "strings"
  12. "github.com/chrislusf/weed-fs/go/glog"
  13. "github.com/chrislusf/weed-fs/go/operation"
  14. "github.com/chrislusf/weed-fs/go/util"
  15. "github.com/syndtr/goleveldb/leveldb"
  16. )
  17. func (fs *FilerServer) filerHandler(w http.ResponseWriter, r *http.Request) {
  18. switch r.Method {
  19. case "GET":
  20. fs.GetOrHeadHandler(w, r, true)
  21. case "HEAD":
  22. fs.GetOrHeadHandler(w, r, false)
  23. case "DELETE":
  24. fs.DeleteHandler(w, r)
  25. case "PUT":
  26. fs.PostHandler(w, r)
  27. case "POST":
  28. fs.PostHandler(w, r)
  29. }
  30. }
  31. func (fs *FilerServer) listDirectoryHandler(w http.ResponseWriter, r *http.Request) {
  32. if !strings.HasSuffix(r.URL.Path, "/") {
  33. return
  34. }
  35. dirlist, err := fs.filer.ListDirectories(r.URL.Path)
  36. if err == leveldb.ErrNotFound {
  37. glog.V(3).Infoln("Directory Not Found in db", r.URL.Path)
  38. w.WriteHeader(http.StatusNotFound)
  39. return
  40. }
  41. m := make(map[string]interface{})
  42. m["Directory"] = r.URL.Path
  43. m["Subdirectories"] = dirlist
  44. lastFileName := r.FormValue("lastFileName")
  45. limit, limit_err := strconv.Atoi(r.FormValue("limit"))
  46. if limit_err != nil {
  47. limit = 100
  48. }
  49. m["Files"], _ = fs.filer.ListFiles(r.URL.Path, lastFileName, limit)
  50. writeJsonQuiet(w, r, http.StatusOK, m)
  51. }
  52. func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) {
  53. if strings.HasSuffix(r.URL.Path, "/") {
  54. if fs.disableDirListing {
  55. w.WriteHeader(http.StatusMethodNotAllowed)
  56. return
  57. }
  58. fs.listDirectoryHandler(w, r)
  59. return
  60. }
  61. fileId, err := fs.filer.FindFile(r.URL.Path)
  62. if err == leveldb.ErrNotFound {
  63. glog.V(3).Infoln("Not found in db", r.URL.Path)
  64. w.WriteHeader(http.StatusNotFound)
  65. return
  66. }
  67. parts := strings.Split(fileId, ",")
  68. if len(parts) != 2 {
  69. glog.V(1).Infoln("Invalid fileId", fileId)
  70. w.WriteHeader(http.StatusNotFound)
  71. return
  72. }
  73. lookup, lookupError := operation.Lookup(fs.master, parts[0])
  74. if lookupError != nil {
  75. glog.V(1).Infoln("Invalid lookup", lookupError.Error())
  76. w.WriteHeader(http.StatusNotFound)
  77. return
  78. }
  79. if len(lookup.Locations) == 0 {
  80. glog.V(1).Infoln("Can not find location for volume", parts[0])
  81. w.WriteHeader(http.StatusNotFound)
  82. return
  83. }
  84. urlLocation := lookup.Locations[rand.Intn(len(lookup.Locations))].Url
  85. urlString := "http://" + urlLocation + "/" + fileId
  86. if fs.redirectOnRead {
  87. http.Redirect(w, r, urlString, http.StatusFound)
  88. return
  89. }
  90. u, _ := url.Parse(urlString)
  91. request := &http.Request{
  92. Method: r.Method,
  93. URL: u,
  94. Proto: r.Proto,
  95. ProtoMajor: r.ProtoMajor,
  96. ProtoMinor: r.ProtoMinor,
  97. Header: r.Header,
  98. Body: r.Body,
  99. Host: r.Host,
  100. ContentLength: r.ContentLength,
  101. }
  102. glog.V(3).Infoln("retrieving from", u)
  103. resp, do_err := util.Do(request)
  104. if do_err != nil {
  105. glog.V(0).Infoln("failing to connect to volume server", do_err.Error())
  106. writeJsonError(w, r, http.StatusInternalServerError, do_err)
  107. return
  108. }
  109. defer resp.Body.Close()
  110. for k, v := range resp.Header {
  111. w.Header()[k] = v
  112. }
  113. w.WriteHeader(resp.StatusCode)
  114. io.Copy(w, resp.Body)
  115. }
  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. assignResult, ae := operation.Assign(fs.master, 1, replication, fs.collection, query.Get("ttl"))
  123. if ae != nil {
  124. glog.V(0).Infoln("failing to assign a file id", ae.Error())
  125. writeJsonError(w, r, http.StatusInternalServerError, ae)
  126. return
  127. }
  128. u, _ := url.Parse("http://" + assignResult.Url + "/" + assignResult.Fid)
  129. glog.V(4).Infoln("post to", u)
  130. request := &http.Request{
  131. Method: r.Method,
  132. URL: u,
  133. Proto: r.Proto,
  134. ProtoMajor: r.ProtoMajor,
  135. ProtoMinor: r.ProtoMinor,
  136. Header: r.Header,
  137. Body: r.Body,
  138. Host: r.Host,
  139. ContentLength: r.ContentLength,
  140. }
  141. resp, do_err := util.Do(request)
  142. if do_err != nil {
  143. glog.V(0).Infoln("failing to connect to volume server", r.RequestURI, do_err.Error())
  144. writeJsonError(w, r, http.StatusInternalServerError, do_err)
  145. return
  146. }
  147. defer resp.Body.Close()
  148. resp_body, ra_err := ioutil.ReadAll(resp.Body)
  149. if ra_err != nil {
  150. glog.V(0).Infoln("failing to upload to volume server", r.RequestURI, ra_err.Error())
  151. writeJsonError(w, r, http.StatusInternalServerError, ra_err)
  152. return
  153. }
  154. glog.V(4).Infoln("post result", string(resp_body))
  155. var ret operation.UploadResult
  156. unmarshal_err := json.Unmarshal(resp_body, &ret)
  157. if unmarshal_err != nil {
  158. glog.V(0).Infoln("failing to read upload resonse", r.RequestURI, string(resp_body))
  159. writeJsonError(w, r, http.StatusInternalServerError, unmarshal_err)
  160. return
  161. }
  162. if ret.Error != "" {
  163. glog.V(0).Infoln("failing to post to volume server", r.RequestURI, ret.Error)
  164. writeJsonError(w, r, http.StatusInternalServerError, errors.New(ret.Error))
  165. return
  166. }
  167. path := r.URL.Path
  168. if strings.HasSuffix(path, "/") {
  169. if ret.Name != "" {
  170. path += ret.Name
  171. } else {
  172. operation.DeleteFile(fs.master, assignResult.Fid, fs.jwt(assignResult.Fid)) //clean up
  173. glog.V(0).Infoln("Can not to write to folder", path, "without a file name!")
  174. writeJsonError(w, r, http.StatusInternalServerError,
  175. errors.New("Can not to write to folder "+path+" without a file name"))
  176. return
  177. }
  178. }
  179. glog.V(4).Infoln("saving", path, "=>", assignResult.Fid)
  180. if db_err := fs.filer.CreateFile(path, assignResult.Fid); db_err != nil {
  181. operation.DeleteFile(fs.master, assignResult.Fid, fs.jwt(assignResult.Fid)) //clean up
  182. glog.V(0).Infof("failing to write %s to filer server : %v", path, db_err)
  183. writeJsonError(w, r, http.StatusInternalServerError, db_err)
  184. return
  185. }
  186. w.WriteHeader(http.StatusCreated)
  187. w.Write(resp_body)
  188. }
  189. // curl -X DELETE http://localhost:8888/path/to
  190. // curl -X DELETE http://localhost:8888/path/to?recursive=true
  191. func (fs *FilerServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
  192. var err error
  193. var fid string
  194. if strings.HasSuffix(r.URL.Path, "/") {
  195. isRecursive := r.FormValue("recursive") == "true"
  196. err = fs.filer.DeleteDirectory(r.URL.Path, isRecursive)
  197. } else {
  198. fid, err = fs.filer.DeleteFile(r.URL.Path)
  199. if err == nil {
  200. err = operation.DeleteFile(fs.master, fid, fs.jwt(fid))
  201. }
  202. }
  203. if err == nil {
  204. writeJsonQuiet(w, r, http.StatusAccepted, map[string]string{"error": ""})
  205. } else {
  206. glog.V(4).Infoln("deleting", r.URL.Path, ":", err.Error())
  207. writeJsonError(w, r, http.StatusInternalServerError, err)
  208. }
  209. }