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.

241 lines
7.5 KiB

  1. package weed_server
  2. import (
  3. "code.google.com/p/weed-fs/go/glog"
  4. "code.google.com/p/weed-fs/go/operation"
  5. "code.google.com/p/weed-fs/go/replication"
  6. "code.google.com/p/weed-fs/go/storage"
  7. "mime"
  8. "net/http"
  9. "strconv"
  10. "strings"
  11. "time"
  12. )
  13. var fileNameEscaper = strings.NewReplacer("\\", "\\\\", "\"", "\\\"")
  14. func (vs *VolumeServer) statusHandler(w http.ResponseWriter, r *http.Request) {
  15. m := make(map[string]interface{})
  16. m["Version"] = vs.version
  17. m["Volumes"] = vs.store.Status()
  18. writeJsonQuiet(w, r, m)
  19. }
  20. func (vs *VolumeServer) assignVolumeHandler(w http.ResponseWriter, r *http.Request) {
  21. err := vs.store.AddVolume(r.FormValue("volume"), r.FormValue("collection"), r.FormValue("replication"))
  22. if err == nil {
  23. writeJsonQuiet(w, r, map[string]string{"error": ""})
  24. } else {
  25. writeJsonQuiet(w, r, map[string]string{"error": err.Error()})
  26. }
  27. glog.V(2).Infoln("assign volume =", r.FormValue("volume"), ", collection =", r.FormValue("collection"), ", replication =", r.FormValue("replication"), ", error =", err)
  28. }
  29. func (vs *VolumeServer) vacuumVolumeCheckHandler(w http.ResponseWriter, r *http.Request) {
  30. err, ret := vs.store.CheckCompactVolume(r.FormValue("volume"), r.FormValue("garbageThreshold"))
  31. if err == nil {
  32. writeJsonQuiet(w, r, map[string]interface{}{"error": "", "result": ret})
  33. } else {
  34. writeJsonQuiet(w, r, map[string]interface{}{"error": err.Error(), "result": false})
  35. }
  36. glog.V(2).Infoln("checked compacting volume =", r.FormValue("volume"), "garbageThreshold =", r.FormValue("garbageThreshold"), "vacuum =", ret)
  37. }
  38. func (vs *VolumeServer) vacuumVolumeCompactHandler(w http.ResponseWriter, r *http.Request) {
  39. err := vs.store.CompactVolume(r.FormValue("volume"))
  40. if err == nil {
  41. writeJsonQuiet(w, r, map[string]string{"error": ""})
  42. } else {
  43. writeJsonQuiet(w, r, map[string]string{"error": err.Error()})
  44. }
  45. glog.V(2).Infoln("compacted volume =", r.FormValue("volume"), ", error =", err)
  46. }
  47. func (vs *VolumeServer) vacuumVolumeCommitHandler(w http.ResponseWriter, r *http.Request) {
  48. err := vs.store.CommitCompactVolume(r.FormValue("volume"))
  49. if err == nil {
  50. writeJsonQuiet(w, r, map[string]interface{}{"error": ""})
  51. } else {
  52. writeJsonQuiet(w, r, map[string]string{"error": err.Error()})
  53. }
  54. glog.V(2).Infoln("commit compact volume =", r.FormValue("volume"), ", error =", err)
  55. }
  56. func (vs *VolumeServer) freezeVolumeHandler(w http.ResponseWriter, r *http.Request) {
  57. //TODO: notify master that this volume will be read-only
  58. err := vs.store.FreezeVolume(r.FormValue("volume"))
  59. if err == nil {
  60. writeJsonQuiet(w, r, map[string]interface{}{"error": ""})
  61. } else {
  62. writeJsonQuiet(w, r, map[string]string{"error": err.Error()})
  63. }
  64. glog.V(2).Infoln("freeze volume =", r.FormValue("volume"), ", error =", err)
  65. }
  66. func (vs *VolumeServer) submitFromVolumeServerHandler(w http.ResponseWriter, r *http.Request) {
  67. submitForClientHandler(w, r, vs.masterNode)
  68. }
  69. func (vs *VolumeServer) storeHandler(w http.ResponseWriter, r *http.Request) {
  70. switch r.Method {
  71. case "GET":
  72. vs.GetOrHeadHandler(w, r, true)
  73. case "HEAD":
  74. vs.GetOrHeadHandler(w, r, false)
  75. case "DELETE":
  76. secure(vs.whiteList, vs.DeleteHandler)(w, r)
  77. case "PUT":
  78. secure(vs.whiteList, vs.PostHandler)(w, r)
  79. case "POST":
  80. secure(vs.whiteList, vs.PostHandler)(w, r)
  81. }
  82. }
  83. func (vs *VolumeServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) {
  84. n := new(storage.Needle)
  85. vid, fid, filename, ext, _ := parseURLPath(r.URL.Path)
  86. volumeId, err := storage.NewVolumeId(vid)
  87. if err != nil {
  88. glog.V(2).Infoln("parsing error:", err, r.URL.Path)
  89. w.WriteHeader(http.StatusBadRequest)
  90. return
  91. }
  92. err = n.ParsePath(fid)
  93. if err != nil {
  94. glog.V(2).Infoln("parsing fid error:", err, r.URL.Path)
  95. w.WriteHeader(http.StatusBadRequest)
  96. return
  97. }
  98. glog.V(2).Infoln("volume", volumeId, "reading", n)
  99. if !vs.store.HasVolume(volumeId) {
  100. lookupResult, err := operation.Lookup(vs.masterNode, volumeId.String())
  101. glog.V(2).Infoln("volume", volumeId, "found on", lookupResult, "error", err)
  102. if err == nil && len(lookupResult.Locations) > 0 {
  103. http.Redirect(w, r, "http://"+lookupResult.Locations[0].PublicUrl+r.URL.Path, http.StatusMovedPermanently)
  104. } else {
  105. glog.V(2).Infoln("lookup error:", err, r.URL.Path)
  106. w.WriteHeader(http.StatusNotFound)
  107. }
  108. return
  109. }
  110. cookie := n.Cookie
  111. count, e := vs.store.Read(volumeId, n)
  112. glog.V(2).Infoln("read bytes", count, "error", e)
  113. if e != nil || count <= 0 {
  114. glog.V(0).Infoln("read error:", e, r.URL.Path)
  115. w.WriteHeader(http.StatusNotFound)
  116. return
  117. }
  118. if n.Cookie != cookie {
  119. glog.V(0).Infoln("request with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent())
  120. w.WriteHeader(http.StatusNotFound)
  121. return
  122. }
  123. if n.LastModified != 0 {
  124. w.Header().Set("Last-Modified", time.Unix(int64(n.LastModified), 0).UTC().Format(http.TimeFormat))
  125. if r.Header.Get("If-Modified-Since") != "" {
  126. if t, parseError := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); parseError == nil {
  127. if t.Unix() >= int64(n.LastModified) {
  128. w.WriteHeader(http.StatusNotModified)
  129. return
  130. }
  131. }
  132. }
  133. }
  134. if n.NameSize > 0 && filename == "" {
  135. filename = string(n.Name)
  136. dotIndex := strings.LastIndex(filename, ".")
  137. if dotIndex > 0 {
  138. ext = filename[dotIndex:]
  139. }
  140. }
  141. mtype := ""
  142. if ext != "" {
  143. mtype = mime.TypeByExtension(ext)
  144. }
  145. if n.MimeSize > 0 {
  146. mtype = string(n.Mime)
  147. }
  148. if mtype != "" {
  149. w.Header().Set("Content-Type", mtype)
  150. }
  151. if filename != "" {
  152. w.Header().Set("Content-Disposition", "filename="+fileNameEscaper.Replace(filename))
  153. }
  154. if ext != ".gz" {
  155. if n.IsGzipped() {
  156. if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
  157. w.Header().Set("Content-Encoding", "gzip")
  158. } else {
  159. if n.Data, err = storage.UnGzipData(n.Data); err != nil {
  160. glog.V(0).Infoln("lookup error:", err, r.URL.Path)
  161. }
  162. }
  163. }
  164. }
  165. w.Header().Set("Content-Length", strconv.Itoa(len(n.Data)))
  166. if isGetMethod {
  167. if _, e = w.Write(n.Data); e != nil {
  168. glog.V(0).Infoln("response write error:", e)
  169. }
  170. }
  171. }
  172. func (vs *VolumeServer) PostHandler(w http.ResponseWriter, r *http.Request) {
  173. m := make(map[string]interface{})
  174. if e := r.ParseForm(); e != nil {
  175. glog.V(0).Infoln("form parse error:", e)
  176. writeJsonError(w, r, e)
  177. return
  178. }
  179. vid, _, _, _, _ := parseURLPath(r.URL.Path)
  180. volumeId, ve := storage.NewVolumeId(vid)
  181. if ve != nil {
  182. glog.V(0).Infoln("NewVolumeId error:", ve)
  183. writeJsonError(w, r, ve)
  184. return
  185. }
  186. needle, ne := storage.NewNeedle(r)
  187. if ne != nil {
  188. writeJsonError(w, r, ne)
  189. return
  190. }
  191. ret, errorStatus := replication.ReplicatedWrite(vs.masterNode, vs.store, volumeId, needle, r)
  192. if errorStatus == "" {
  193. w.WriteHeader(http.StatusCreated)
  194. } else {
  195. w.WriteHeader(http.StatusInternalServerError)
  196. m["error"] = errorStatus
  197. }
  198. m["size"] = ret
  199. writeJsonQuiet(w, r, m)
  200. }
  201. func (vs *VolumeServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
  202. n := new(storage.Needle)
  203. vid, fid, _, _, _ := parseURLPath(r.URL.Path)
  204. volumeId, _ := storage.NewVolumeId(vid)
  205. n.ParsePath(fid)
  206. glog.V(2).Infoln("deleting", n)
  207. cookie := n.Cookie
  208. count, ok := vs.store.Read(volumeId, n)
  209. if ok != nil {
  210. m := make(map[string]uint32)
  211. m["size"] = 0
  212. writeJsonQuiet(w, r, m)
  213. return
  214. }
  215. if n.Cookie != cookie {
  216. glog.V(0).Infoln("delete with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent())
  217. return
  218. }
  219. n.Size = 0
  220. ret := replication.ReplicatedDelete(vs.masterNode, vs.store, volumeId, n, r)
  221. if ret != 0 {
  222. w.WriteHeader(http.StatusAccepted)
  223. } else {
  224. w.WriteHeader(http.StatusInternalServerError)
  225. }
  226. m := make(map[string]uint32)
  227. m["size"] = uint32(count)
  228. writeJsonQuiet(w, r, m)
  229. }