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.

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