diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2020-08-20 18:31:30 +0300 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2020-08-21 11:32:06 +0300 |
commit | f59aec9d526f05bde08f5c90cc4a1c4c1d8766eb (patch) | |
tree | b7a1d8562e54a62261390f14d6f6bd99fea44863 /internal/vfs/zip/http_range/resource.go | |
parent | 71a39de011a7b2d19470c32ed8f73afc372636bf (diff) |
Refactor ZIP support to be more OOMzip-using-vfs
Diffstat (limited to 'internal/vfs/zip/http_range/resource.go')
-rw-r--r-- | internal/vfs/zip/http_range/resource.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/vfs/zip/http_range/resource.go b/internal/vfs/zip/http_range/resource.go new file mode 100644 index 00000000..d35563b0 --- /dev/null +++ b/internal/vfs/zip/http_range/resource.go @@ -0,0 +1,70 @@ +package http_range + +import ( + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "strconv" + "strings" +) + +type Resource struct { + URL string + Etag string + LastModified string + Size int64 +} + +func NewResource(ctx context.Context, URL string) (*Resource, error) { + // the `h.URL` is likely presigned only for GET + req, err := http.NewRequest("GET", URL, nil) + if err != nil { + return nil, err + } + + req = req.WithContext(ctx) + + // we fetch a single byte and ensure that range requests is additionally supported + req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", 0, 0)) + res, err := httpClient.Do(req) + if err != nil { + return nil, err + } + defer io.Copy(ioutil.Discard, res.Body) + defer res.Body.Close() + + resource := &Resource{ + URL: URL, + Etag: res.Header.Get("ETag"), + LastModified: res.Header.Get("Last-Modified"), + } + + switch res.StatusCode { + case http.StatusOK: + resource.Size = res.ContentLength + println(resource.URL, resource.Etag, resource.LastModified, resource.Size) + return resource, nil + + case http.StatusPartialContent: + contentRange := res.Header.Get("Content-Range") + ranges := strings.SplitN(contentRange, "/", 2) + if len(ranges) != 2 { + return nil, fmt.Errorf("invalid `Content-Range`: %q", contentRange) + } + + resource.Size, err = strconv.ParseInt(ranges[1], 0, 64) + if err != nil { + return nil, err + } + + return resource, nil + + case http.StatusRequestedRangeNotSatisfiable: + return nil, ErrRangeRequestsNotSupported + + default: + return nil, fmt.Errorf("failed with %d: %q", res.StatusCode, res.Status) + } +} |