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.

132 lines
2.9 KiB

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