From cbd9d14cc4dd6595617226cc68dcbf6513384541 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 8 Jul 2013 23:38:38 -0700 Subject: [PATCH] Issue 27: feature request - Last-Modified header --- go/storage/needle.go | 18 +++++++++++------- go/storage/needle_read_write.go | 28 +++++++++++++++++++++++++--- go/weed/volume.go | 15 +++++++++++---- go/weed/volume_test.go | 11 +++++++++++ 4 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 go/weed/volume_test.go diff --git a/go/storage/needle.go b/go/storage/needle.go index 256a7c26a..9c0acc6b9 100644 --- a/go/storage/needle.go +++ b/go/storage/needle.go @@ -11,6 +11,7 @@ import ( "path" "strconv" "strings" + "time" ) const ( @@ -24,13 +25,14 @@ type Needle struct { Id uint64 `comment:"needle id"` Size uint32 `comment:"sum of DataSize,Data,NameSize,Name,MimeSize,Mime"` - DataSize uint32 `comment:"Data size"` //version2 - Data []byte `comment:"The actual file data"` - Flags byte `comment:"boolean flags"` //version2 - NameSize uint8 //version2 - Name []byte `comment:"maximum 256 characters"` //version2 - MimeSize uint8 //version2 - Mime []byte `comment:"maximum 256 characters"` //version2 + DataSize uint32 `comment:"Data size"` //version2 + Data []byte `comment:"The actual file data"` + Flags byte `comment:"boolean flags"` //version2 + NameSize uint8 //version2 + Name []byte `comment:"maximum 256 characters"` //version2 + MimeSize uint8 //version2 + Mime []byte `comment:"maximum 256 characters"` //version2 + LastModified uint64 //only store LastModifiedBytesLength bytes, which is 5 bytes to disk Checksum CRC `comment:"CRC32 to check integrity"` Padding []byte `comment:"Aligned to 8 bytes"` @@ -88,6 +90,8 @@ func NewNeedle(r *http.Request) (n *Needle, e error) { } n.SetHasName() } + n.LastModified = uint64(time.Now().Unix()) + n.SetHasLastModifiedDate() n.Data = data n.Checksum = NewCRC(data) diff --git a/go/storage/needle_read_write.go b/go/storage/needle_read_write.go index c5f27ea21..bcb93f57b 100644 --- a/go/storage/needle_read_write.go +++ b/go/storage/needle_read_write.go @@ -9,9 +9,11 @@ import ( ) const ( - FlagGzip = 0x01 - FlagHasName = 0x02 - FlagHasMime = 0x04 + FlagGzip = 0x01 + FlagHasName = 0x02 + FlagHasMime = 0x04 + FlagHasLastModifiedDate = 0x08 + LastModifiedBytesLength = 5 ) func (n *Needle) DiskSize() uint32 { @@ -64,6 +66,9 @@ func (n *Needle) Append(w io.Writer, version Version) (size uint32, err error) { if n.HasMime() { n.Size = n.Size + 1 + uint32(n.MimeSize) } + if n.HasLastModifiedDate() { + n.Size = n.Size + LastModifiedBytesLength + } } size = n.DataSize util.Uint32toBytes(header[12:16], n.Size) @@ -101,6 +106,12 @@ func (n *Needle) Append(w io.Writer, version Version) (size uint32, err error) { return } } + if n.HasLastModifiedDate() { + util.Uint64toBytes(header[0:8], n.LastModified) + if _, err = w.Write(header[8-LastModifiedBytesLength : 8]); err != nil { + return + } + } padding := NeedlePaddingSize - ((NeedleHeaderSize + n.Size + NeedleChecksumSize) % NeedlePaddingSize) util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value()) _, err = w.Write(header[0 : NeedleChecksumSize+padding]) @@ -172,6 +183,11 @@ func (n *Needle) readNeedleDataVersion2(bytes []byte) { n.MimeSize = uint8(bytes[index]) index = index + 1 n.Mime = bytes[index : index+int(n.MimeSize)] + index = index + int(n.MimeSize) + } + if index < lenBytes && n.HasLastModifiedDate() { + n.LastModified = util.BytesToUint64(bytes[index : index+LastModifiedBytesLength]) + index = index + LastModifiedBytesLength } } @@ -236,3 +252,9 @@ func (n *Needle) HasMime() bool { func (n *Needle) SetHasMime() { n.Flags = n.Flags | FlagHasMime } +func (n *Needle) HasLastModifiedDate() bool { + return n.Flags&FlagHasLastModifiedDate > 0 +} +func (n *Needle) SetHasLastModifiedDate() { + n.Flags = n.Flags | FlagHasLastModifiedDate +} diff --git a/go/weed/volume.go b/go/weed/volume.go index 6282b0bc8..039212793 100644 --- a/go/weed/volume.go +++ b/go/weed/volume.go @@ -145,6 +145,17 @@ func GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) w.WriteHeader(http.StatusNotFound) return } + if n.LastModified != 0 { + w.Header().Set("Last-Modified", time.Unix(int64(n.LastModified), 0).UTC().Format(http.TimeFormat)) + if r.Header.Get("If-Modified-Since") != "" { + if t, parseError := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); parseError == nil { + if t.Unix() <= int64(n.LastModified) { + w.WriteHeader(http.StatusNotModified) + return + } + } + } + } if n.NameSize > 0 { fname := string(n.Name) dotIndex := strings.LastIndex(fname, ".") @@ -165,10 +176,6 @@ func GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) if n.NameSize > 0 { w.Header().Set("Content-Disposition", "filename="+fileNameEscaper.Replace(string(n.Name))) } - if n.LastModified != 0 { - println("file time is", n.LastModified) - w.Header().Set("Last-Modified", time.Unix(int64(n.LastModified), 0).Format(http.TimeFormat)) - } if ext != ".gz" { if n.IsGzipped() { if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { diff --git a/go/weed/volume_test.go b/go/weed/volume_test.go new file mode 100644 index 000000000..09340910b --- /dev/null +++ b/go/weed/volume_test.go @@ -0,0 +1,11 @@ +package main + +import ( + "net/http" + "testing" + "time" +) + +func TestXYZ(t *testing.T) { + println("Last-Modified", time.Unix(int64(1373273596), 0).UTC().Format(http.TimeFormat)) +}