cmd/golangorg: make zip contents seekable
https://golang.org/misc/cgo/stdio/testdata/fib.go fails right now
because the http.FileServer wants to use Seek to find out the file size.
Make that work by introducing an FS wrapper that enables seeking
in an in-memory copy of the file content.
Fixes golang/go#46809.
Change-Id: I353905310dc74594e54e0181dc821a97992b8da7
Reviewed-on: https://go-review.googlesource.com/c/website/+/329249
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Russ Cox <rsc@golang.org>
diff --git a/cmd/golangorg/server.go b/cmd/golangorg/server.go
index 182bd4a..d1e48f2 100644
--- a/cmd/golangorg/server.go
+++ b/cmd/golangorg/server.go
@@ -6,12 +6,14 @@
package main
import (
+ "bytes"
"context"
"encoding/json"
"flag"
"fmt"
"go/format"
"io"
+ "io/ioutil"
"log"
"net/http"
"os"
@@ -125,8 +127,7 @@
if err != nil {
log.Fatal(err)
}
- defer z.Close()
- gorootFS = z
+ gorootFS = &seekableFS{z}
} else {
gorootFS = osfs.DirFS(goroot)
}
@@ -382,3 +383,47 @@
}
return nil, errOut
}
+
+// A seekableFS is an FS wrapper that makes every file seekable
+// by reading it entirely into memory when it is opened and then
+// serving read operations (including seek) from the memory copy.
+type seekableFS struct {
+ fs fs.FS
+}
+
+func (s *seekableFS) Open(name string) (fs.File, error) {
+ f, err := s.fs.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ info, err := f.Stat()
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ if info.IsDir() {
+ return f, nil
+ }
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ var sf seekableFile
+ sf.File = f
+ sf.Reset(data)
+ return &sf, nil
+}
+
+// A seekableFile is a fs.File augmented by an in-memory copy of the file data to allow use of Seek.
+type seekableFile struct {
+ bytes.Reader
+ fs.File
+}
+
+// Read calls f.Reader.Read.
+// Both f.Reader and f.File have Read methods - a conflict - so f inherits neither.
+// This method calls the one we want.
+func (f *seekableFile) Read(b []byte) (int, error) {
+ return f.Reader.Read(b)
+}