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.

159 lines
3.9 KiB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
  1. package storage
  2. import (
  3. "code.google.com/p/weed-fs/go/util"
  4. "encoding/hex"
  5. "io/ioutil"
  6. "code.google.com/p/weed-fs/go/glog"
  7. "mime"
  8. "net/http"
  9. "path"
  10. "strconv"
  11. "strings"
  12. "time"
  13. )
  14. const (
  15. NeedleHeaderSize = 16 //should never change this
  16. NeedlePaddingSize = 8
  17. NeedleChecksumSize = 4
  18. )
  19. type Needle struct {
  20. Cookie uint32 `comment:"random number to mitigate brute force lookups"`
  21. Id uint64 `comment:"needle id"`
  22. Size uint32 `comment:"sum of DataSize,Data,NameSize,Name,MimeSize,Mime"`
  23. DataSize uint32 `comment:"Data size"` //version2
  24. Data []byte `comment:"The actual file data"`
  25. Flags byte `comment:"boolean flags"` //version2
  26. NameSize uint8 //version2
  27. Name []byte `comment:"maximum 256 characters"` //version2
  28. MimeSize uint8 //version2
  29. Mime []byte `comment:"maximum 256 characters"` //version2
  30. LastModified uint64 //only store LastModifiedBytesLength bytes, which is 5 bytes to disk
  31. Checksum CRC `comment:"CRC32 to check integrity"`
  32. Padding []byte `comment:"Aligned to 8 bytes"`
  33. }
  34. func ParseUpload(r *http.Request) (fileName string, data []byte, mimeType string, isGzipped bool, modifiedTime uint64, e error) {
  35. form, fe := r.MultipartReader()
  36. if fe != nil {
  37. glog.V(0).Infoln("MultipartReader [ERROR]", fe)
  38. e = fe
  39. return
  40. }
  41. part, fe := form.NextPart()
  42. if fe != nil {
  43. glog.V(0).Infoln("Reading Multi part [ERROR]", fe)
  44. e = fe
  45. return
  46. }
  47. fileName = part.FileName()
  48. if fileName != "" {
  49. fileName = path.Base(fileName)
  50. }
  51. data, e = ioutil.ReadAll(part)
  52. if e != nil {
  53. glog.V(0).Infoln("Reading Content [ERROR]", e)
  54. return
  55. }
  56. dotIndex := strings.LastIndex(fileName, ".")
  57. ext, mtype := "", ""
  58. if dotIndex > 0 {
  59. ext = strings.ToLower(fileName[dotIndex:])
  60. mtype = mime.TypeByExtension(ext)
  61. }
  62. contentType := part.Header.Get("Content-Type")
  63. if contentType != "" && mtype != contentType {
  64. mimeType = contentType //only return mime type if not deductable
  65. mtype = contentType
  66. }
  67. if part.Header.Get("Content-Encoding") == "gzip" {
  68. isGzipped = true
  69. } else if IsGzippable(ext, mtype) {
  70. if data, e = GzipData(data); e != nil {
  71. return
  72. }
  73. isGzipped = true
  74. }
  75. if ext == ".gz" {
  76. isGzipped = true
  77. }
  78. if strings.HasSuffix(fileName, ".gz") {
  79. fileName = fileName[:len(fileName)-3]
  80. }
  81. modifiedTime, _ = strconv.ParseUint(r.FormValue("ts"), 10, 64)
  82. return
  83. }
  84. func NewNeedle(r *http.Request) (n *Needle, e error) {
  85. fname, mimeType, isGzipped := "", "", false
  86. n = new(Needle)
  87. fname, n.Data, mimeType, isGzipped, n.LastModified, e = ParseUpload(r)
  88. if e != nil {
  89. return
  90. }
  91. if len(fname) < 256 {
  92. n.Name = []byte(fname)
  93. n.SetHasName()
  94. }
  95. if len(mimeType) < 256 {
  96. n.Mime = []byte(mimeType)
  97. n.SetHasMime()
  98. }
  99. if isGzipped {
  100. n.SetGzipped()
  101. }
  102. if n.LastModified == 0 {
  103. n.LastModified = uint64(time.Now().Unix())
  104. n.SetHasLastModifiedDate()
  105. }
  106. n.Checksum = NewCRC(n.Data)
  107. commaSep := strings.LastIndex(r.URL.Path, ",")
  108. dotSep := strings.LastIndex(r.URL.Path, ".")
  109. fid := r.URL.Path[commaSep+1:]
  110. if dotSep > 0 {
  111. fid = r.URL.Path[commaSep+1 : dotSep]
  112. }
  113. n.ParsePath(fid)
  114. return
  115. }
  116. func (n *Needle) ParsePath(fid string) {
  117. length := len(fid)
  118. if length <= 8 {
  119. if length > 0 {
  120. glog.V(0).Infoln("Invalid fid", fid, "length", length)
  121. }
  122. return
  123. }
  124. delta := ""
  125. deltaIndex := strings.LastIndex(fid, "_")
  126. if deltaIndex > 0 {
  127. fid, delta = fid[0:deltaIndex], fid[deltaIndex+1:]
  128. }
  129. n.Id, n.Cookie = ParseKeyHash(fid)
  130. if delta != "" {
  131. d, e := strconv.ParseUint(delta, 10, 64)
  132. if e == nil {
  133. n.Id += d
  134. }
  135. }
  136. }
  137. func ParseKeyHash(key_hash_string string) (uint64, uint32) {
  138. key_hash_bytes, khe := hex.DecodeString(key_hash_string)
  139. key_hash_len := len(key_hash_bytes)
  140. if khe != nil || key_hash_len <= 4 {
  141. glog.V(0).Infoln("Invalid key_hash", key_hash_string, "length:", key_hash_len, "error", khe)
  142. return 0, 0
  143. }
  144. key := util.BytesToUint64(key_hash_bytes[0 : key_hash_len-4])
  145. hash := util.BytesToUint32(key_hash_bytes[key_hash_len-4 : key_hash_len])
  146. return key, hash
  147. }