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.

239 lines
7.4 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("replicationType"))
  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"), ", replicationType =", r.FormValue("replicationType"), ", 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. return
  90. }
  91. err = n.ParsePath(fid)
  92. if err != nil {
  93. glog.V(2).Infoln("parsing fid error:", err, r.URL.Path)
  94. return
  95. }
  96. glog.V(2).Infoln("volume", volumeId, "reading", n)
  97. if !vs.store.HasVolume(volumeId) {
  98. lookupResult, err := operation.Lookup(vs.masterNode, volumeId)
  99. glog.V(2).Infoln("volume", volumeId, "found on", lookupResult, "error", err)
  100. if err == nil {
  101. http.Redirect(w, r, "http://"+lookupResult.Locations[0].PublicUrl+r.URL.Path, http.StatusMovedPermanently)
  102. } else {
  103. glog.V(2).Infoln("lookup error:", err, r.URL.Path)
  104. w.WriteHeader(http.StatusNotFound)
  105. }
  106. return
  107. }
  108. cookie := n.Cookie
  109. count, e := vs.store.Read(volumeId, n)
  110. glog.V(2).Infoln("read bytes", count, "error", e)
  111. if e != nil || count <= 0 {
  112. glog.V(0).Infoln("read error:", e, r.URL.Path)
  113. w.WriteHeader(http.StatusNotFound)
  114. return
  115. }
  116. if n.Cookie != cookie {
  117. glog.V(0).Infoln("request with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent())
  118. w.WriteHeader(http.StatusNotFound)
  119. return
  120. }
  121. if n.LastModified != 0 {
  122. w.Header().Set("Last-Modified", time.Unix(int64(n.LastModified), 0).UTC().Format(http.TimeFormat))
  123. if r.Header.Get("If-Modified-Since") != "" {
  124. if t, parseError := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); parseError == nil {
  125. if t.Unix() >= int64(n.LastModified) {
  126. w.WriteHeader(http.StatusNotModified)
  127. return
  128. }
  129. }
  130. }
  131. }
  132. if n.NameSize > 0 && filename == "" {
  133. filename = string(n.Name)
  134. dotIndex := strings.LastIndex(filename, ".")
  135. if dotIndex > 0 {
  136. ext = filename[dotIndex:]
  137. }
  138. }
  139. mtype := ""
  140. if ext != "" {
  141. mtype = mime.TypeByExtension(ext)
  142. }
  143. if n.MimeSize > 0 {
  144. mtype = string(n.Mime)
  145. }
  146. if mtype != "" {
  147. w.Header().Set("Content-Type", mtype)
  148. }
  149. if filename != "" {
  150. w.Header().Set("Content-Disposition", "filename="+fileNameEscaper.Replace(filename))
  151. }
  152. if ext != ".gz" {
  153. if n.IsGzipped() {
  154. if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
  155. w.Header().Set("Content-Encoding", "gzip")
  156. } else {
  157. if n.Data, err = storage.UnGzipData(n.Data); err != nil {
  158. glog.V(0).Infoln("lookup error:", err, r.URL.Path)
  159. }
  160. }
  161. }
  162. }
  163. w.Header().Set("Content-Length", strconv.Itoa(len(n.Data)))
  164. if isGetMethod {
  165. if _, e = w.Write(n.Data); e != nil {
  166. glog.V(0).Infoln("response write error:", e)
  167. }
  168. }
  169. }
  170. func (vs *VolumeServer) PostHandler(w http.ResponseWriter, r *http.Request) {
  171. m := make(map[string]interface{})
  172. if e := r.ParseForm(); e != nil {
  173. glog.V(0).Infoln("form parse error:", e)
  174. writeJsonError(w, r, e)
  175. return
  176. }
  177. vid, _, _, _, _ := parseURLPath(r.URL.Path)
  178. volumeId, ve := storage.NewVolumeId(vid)
  179. if ve != nil {
  180. glog.V(0).Infoln("NewVolumeId error:", ve)
  181. writeJsonError(w, r, ve)
  182. return
  183. }
  184. needle, ne := storage.NewNeedle(r)
  185. if ne != nil {
  186. writeJsonError(w, r, ne)
  187. return
  188. }
  189. ret, errorStatus := replication.ReplicatedWrite(vs.masterNode, vs.store, volumeId, needle, r)
  190. if errorStatus == "" {
  191. w.WriteHeader(http.StatusCreated)
  192. } else {
  193. w.WriteHeader(http.StatusInternalServerError)
  194. m["error"] = errorStatus
  195. }
  196. m["size"] = ret
  197. writeJsonQuiet(w, r, m)
  198. }
  199. func (vs *VolumeServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
  200. n := new(storage.Needle)
  201. vid, fid, _, _, _ := parseURLPath(r.URL.Path)
  202. volumeId, _ := storage.NewVolumeId(vid)
  203. n.ParsePath(fid)
  204. glog.V(2).Infoln("deleting", n)
  205. cookie := n.Cookie
  206. count, ok := vs.store.Read(volumeId, n)
  207. if ok != nil {
  208. m := make(map[string]uint32)
  209. m["size"] = 0
  210. writeJsonQuiet(w, r, m)
  211. return
  212. }
  213. if n.Cookie != cookie {
  214. glog.V(0).Infoln("delete with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent())
  215. return
  216. }
  217. n.Size = 0
  218. ret := replication.ReplicatedDelete(vs.masterNode, vs.store, volumeId, n, r)
  219. if ret != 0 {
  220. w.WriteHeader(http.StatusAccepted)
  221. } else {
  222. w.WriteHeader(http.StatusInternalServerError)
  223. }
  224. m := make(map[string]uint32)
  225. m["size"] = uint32(count)
  226. writeJsonQuiet(w, r, m)
  227. }