cmd/coordinator: verify snapshot before using it

We were creating corrupt snapshots before (golang/go#12671), so
double-check them before use, for now. We can relax this in the future
(see TODO).

Fixes golang/go#12671

Change-Id: I10b7929d4b78c717f29c67a0ce495ecd435a1d26
Reviewed-on: https://go-review.googlesource.com/14772
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/coordinator/coordinator.go b/cmd/coordinator/coordinator.go
index 3c94dfd..d21c1e9 100644
--- a/cmd/coordinator/coordinator.go
+++ b/cmd/coordinator/coordinator.go
@@ -1451,9 +1451,46 @@
 	return nil
 }
 
+// snapshotExists reports whether the snapshot exists and isn't corrupt.
+// Unfortunately we put some corrupt ones in for awhile, so this check is
+// now more paranoid than it used to be.
 func (br *builderRev) snapshotExists() bool {
-	resp, err := http.Head(br.snapshotURL())
-	return err == nil && resp.StatusCode == http.StatusOK
+	// TODO(bradfitz): clean up the repo and revert this to what
+	// it was before, maybe based on the date of the file. The old
+	// code was just:
+	// resp, err := http.Head(br.snapshotURL())
+	// return err == nil && resp.StatusCode == http.StatusOK
+
+	resp, err := http.Get(br.snapshotURL())
+	if err != nil {
+		return false
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != 200 {
+		return false
+	}
+	// Verify the .tar.gz is valid.
+	gz, err := gzip.NewReader(resp.Body)
+	if err != nil {
+		log.Printf("corrupt snapshot? %s gzip.NewReader: %v", br.snapshotURL(), err)
+		return false
+	}
+	tr := tar.NewReader(gz)
+	for {
+		hdr, err := tr.Next()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			log.Printf("corrupt snapshot? %s tar.Next: %v", br.snapshotURL(), err)
+			return false
+		}
+		if _, err := io.Copy(ioutil.Discard, tr); err != nil {
+			log.Printf("corrupt snapshot? %s reading contents of %s: %v", br.snapshotURL(), hdr.Name, err)
+			return false
+		}
+	}
+	return gz.Close() == nil
 }
 
 func (st *buildStatus) writeGoSource() error {