Merge pull request #234 from dopessoa/ISSUE-229

Add X-Remaining-Downloads and X-Remaining-Days headers to HEAD and GET responses
This commit is contained in:
Andrea Spacca 2019-06-23 09:23:48 +02:00 committed by GitHub
commit 14c48cb4d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -564,6 +564,14 @@ func getURL(r *http.Request) *url.URL {
return u return u
} }
func calcRemainingLimits(metadata Metadata) (int, int) {
remainingDownloads := metadata.MaxDownloads - metadata.Downloads
timeDifference := metadata.MaxDate.Sub(time.Now())
remainingDays := int(timeDifference.Hours()/24) + 1
return remainingDownloads, remainingDays
}
func (s *Server) Lock(token, filename string) error { func (s *Server) Lock(token, filename string) error {
key := path.Join(token, filename) key := path.Join(token, filename)
@ -583,7 +591,7 @@ func (s *Server) Unlock(token, filename string) error {
return nil return nil
} }
func (s *Server) CheckMetadata(token, filename string) error { func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (Metadata, error) {
s.Lock(token, filename) s.Lock(token, filename)
defer s.Unlock(token, filename) defer s.Unlock(token, filename)
@ -591,34 +599,36 @@ func (s *Server) CheckMetadata(token, filename string) error {
r, _, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename)) r, _, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
if s.storage.IsNotExist(err) { if s.storage.IsNotExist(err) {
return nil return metadata, nil
} else if err != nil { } else if err != nil {
return err return metadata, err
} }
defer r.Close() defer r.Close()
if err := json.NewDecoder(r).Decode(&metadata); err != nil { if err := json.NewDecoder(r).Decode(&metadata); err != nil {
return err return metadata, err
} else if metadata.Downloads >= metadata.MaxDownloads { } else if metadata.Downloads >= metadata.MaxDownloads {
return errors.New("MaxDownloads expired.") return metadata, errors.New("MaxDownloads expired.")
} else if time.Now().After(metadata.MaxDate) { } else if time.Now().After(metadata.MaxDate) {
return errors.New("MaxDate expired.") return metadata, errors.New("MaxDate expired.")
} else { } else {
// todo(nl5887): mutex? // todo(nl5887): mutex?
// update number of downloads // update number of downloads
if increaseDownload {
metadata.Downloads++ metadata.Downloads++
}
buffer := &bytes.Buffer{} buffer := &bytes.Buffer{}
if err := json.NewEncoder(buffer).Encode(metadata); err != nil { if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
return errors.New("Could not encode metadata") return metadata, errors.New("Could not encode metadata")
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil { } else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
return errors.New("Could not save metadata") return metadata, errors.New("Could not save metadata")
} }
} }
return nil return metadata, nil
} }
func (s *Server) CheckDeletionToken(deletionToken, token, filename string) error { func (s *Server) CheckDeletionToken(deletionToken, token, filename string) error {
@ -688,7 +698,7 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
token := strings.Split(key, "/")[0] token := strings.Split(key, "/")[0]
filename := sanitize(strings.Split(key, "/")[1]) filename := sanitize(strings.Split(key, "/")[1])
if err := s.CheckMetadata(token, filename); err != nil { if _, err := s.CheckMetadata(token, filename, true); err != nil {
log.Printf("Error metadata: %s", err.Error()) log.Printf("Error metadata: %s", err.Error())
continue continue
} }
@ -760,7 +770,7 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
token := strings.Split(key, "/")[0] token := strings.Split(key, "/")[0]
filename := sanitize(strings.Split(key, "/")[1]) filename := sanitize(strings.Split(key, "/")[1])
if err := s.CheckMetadata(token, filename); err != nil { if _, err := s.CheckMetadata(token, filename, true); err != nil {
log.Printf("Error metadata: %s", err.Error()) log.Printf("Error metadata: %s", err.Error())
continue continue
} }
@ -819,7 +829,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
token := strings.Split(key, "/")[0] token := strings.Split(key, "/")[0]
filename := strings.Split(key, "/")[1] filename := strings.Split(key, "/")[1]
if err := s.CheckMetadata(token, filename); err != nil { if _, err := s.CheckMetadata(token, filename, true); err != nil {
log.Printf("Error metadata: %s", err.Error()) log.Printf("Error metadata: %s", err.Error())
continue continue
} }
@ -864,7 +874,9 @@ func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {
token := vars["token"] token := vars["token"]
filename := vars["filename"] filename := vars["filename"]
if err := s.CheckMetadata(token, filename); err != nil { metadata, err := s.CheckMetadata(token, filename, false)
if err != nil {
log.Printf("Error metadata: %s", err.Error()) log.Printf("Error metadata: %s", err.Error())
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return return
@ -880,9 +892,13 @@ func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
remainingDownloads, remainingDays := calcRemainingLimits(metadata)
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10)) w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
w.Header().Set("Connection", "close") w.Header().Set("Connection", "close")
w.Header().Set("X-Remaining-Downloads", strconv.Itoa(remainingDownloads))
w.Header().Set("X-Remaining-Days", strconv.Itoa(remainingDays))
} }
func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) { func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
@ -892,7 +908,9 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
token := vars["token"] token := vars["token"]
filename := vars["filename"] filename := vars["filename"]
if err := s.CheckMetadata(token, filename); err != nil { metadata, err := s.CheckMetadata(token, filename, true)
if err != nil {
log.Printf("Error metadata: %s", err.Error()) log.Printf("Error metadata: %s", err.Error())
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return return
@ -918,10 +936,14 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
disposition = "attachment" disposition = "attachment"
} }
remainingDownloads, remainingDays := calcRemainingLimits(metadata)
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10)) w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"", disposition, filename)) w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"", disposition, filename))
w.Header().Set("Connection", "keep-alive") w.Header().Set("Connection", "keep-alive")
w.Header().Set("X-Remaining-Downloads", strconv.Itoa(remainingDownloads))
w.Header().Set("X-Remaining-Days", strconv.Itoa(remainingDays))
if w.Header().Get("Range") == "" { if w.Header().Get("Range") == "" {
if _, err = io.Copy(w, reader); err != nil { if _, err = io.Copy(w, reader); err != nil {