Apply Last-Modified time as mtime when saving URLs

When saving the contents of a URL to a local file, attempt to set mtime
based on the response's Last-Modified header, if there is one.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>

Closes: #58
Approved by: nalind
This commit is contained in:
Nalin Dahyabhai
2017-03-28 03:01:59 -04:00
committed by Atomic Bot
parent c72d2db65d
commit 19a7165783
5 changed files with 92 additions and 2 deletions

View File

@@ -11,4 +11,4 @@ before_install:
- sudo apt-get -qq install bats btrfs-tools libdevmapper-dev libgpgme11-dev
script:
- make
- cd tests; sudo ./test_runner.sh
- cd tests; sudo PATH="$PATH" ./test_runner.sh

14
add.go
View File

@@ -9,6 +9,7 @@ import (
"path"
"path/filepath"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/containers/storage/pkg/archive"
@@ -29,12 +30,23 @@ func addUrl(destination, srcurl string) error {
if err != nil {
return fmt.Errorf("error creating %q: %v", destination, err)
}
if last := resp.Header.Get("Last-Modified"); last != "" {
if mtime, err := time.Parse(time.RFC1123, last); err != nil {
logrus.Debugf("error parsing Last-Modified time %q: %v", last, err)
} else {
defer func() {
if err := os.Chtimes(destination, time.Now(), mtime); err != nil {
logrus.Debugf("error setting mtime to Last-Modified time %q: %v", last, err)
}
}()
}
}
defer f.Close()
n, err := io.Copy(f, resp.Body)
if resp.ContentLength >= 0 && n != resp.ContentLength {
return fmt.Errorf("error reading contents for %q: wrong length (%d != %d)", destination, n, resp.ContentLength)
}
if err := f.Chmod(0755); err != nil {
if err := f.Chmod(0600); err != nil {
return fmt.Errorf("error setting permissions on %q: %v", destination, err)
}
return nil

View File

@@ -86,3 +86,21 @@ load helpers
cmp ${TESTDIR}/randomfile $root/randomsubdir/randomfile
buildah rm $cid
}
@test "copy-url-mtime" {
createrandom ${TESTDIR}/randomfile
cid=$(buildah from --signature-policy ${TESTSDIR}/policy.json scratch)
buildah config --workingdir / $cid
starthttpd ${TESTDIR}
buildah copy $cid http://0.0.0.0:${HTTP_SERVER_PORT}/randomfile /urlfile
stophttpd
root=$(buildah mount $cid)
test -s $root/urlfile
cmp ${TESTDIR}/randomfile $root/urlfile
run test -nt ${TESTDIR}/randomfile $root/urlfile
[ "$status" -ne 0 ]
run test -ot ${TESTDIR}/randomfile $root/urlfile
[ "$status" -ne 0 ]
buildah rm $cid
}

View File

@@ -11,7 +11,27 @@ function setup() {
REPO=${TESTDIR}/root
}
function starthttpd() {
pushd ${2:-${BATS_TMPDIR}} > /dev/null
cp ${TESTSDIR}/serve.go .
go build serve.go
HTTP_SERVER_PORT=$((RANDOM+32768))
./serve ${HTTP_SERVER_PORT} ${1:-${BATS_TMPDIR}} &
HTTP_SERVER_PID=$!
popd > /dev/null
}
function stophttpd() {
if test -n "$HTTP_SERVER_PID" ; then
kill -HUP ${HTTP_SERVER_PID}
unset HTTP_SERVER_PID
unset HTTP_SERVER_PORT
fi
true
}
function teardown() {
stophttpd
rm -fr ${TESTDIR}
}

40
tests/serve.go Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"log"
"net/http"
"os"
"path/filepath"
)
func sendThatFile(basepath string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
filename := filepath.Join(basepath, filepath.Clean(string([]rune{filepath.Separator})+r.URL.Path))
f, err := os.Open(filename)
if err != nil {
if os.IsNotExist(err) {
http.NotFound(w, r)
return
}
http.Error(w, "whoops", http.StatusInternalServerError)
return
}
finfo, err := f.Stat()
if err != nil {
http.Error(w, "whoops", http.StatusInternalServerError)
return
}
http.ServeContent(w, r, filename, finfo.ModTime(), f)
}
}
func main() {
args := os.Args
if len(args) < 3 {
log.Fatal("requires listening port and subdirectory path")
}
port := args[1]
basedir := args[2]
http.HandleFunc("/", sendThatFile(basedir))
log.Fatal(http.ListenAndServe(":"+port, nil))
}