package attach import ( "io" "net/http" "net/http/httptest" "testing" "gocloud.dev/blob" "gocloud.dev/blob/memblob" ) func TestStaticHandler(t *testing.T) { ctx := t.Context() bucket := memblob.OpenBucket(nil) t.Cleanup(func() { _ = bucket.Close() }) diskName := "abc123xyz.jpg" key := BlobKey(diskName) body := []byte("cover-bytes") if err := bucket.WriteAll(ctx, key, body, &blob.WriterOptions{ContentType: "image/jpeg"}); err != nil { t.Fatal(err) } h := StaticHandler(bucket, "/storage/uploads") srv := httptest.NewServer(h) t.Cleanup(srv.Close) res, err := http.Get(srv.URL + "/storage/uploads/abc/123/xyz/abc123xyz.jpg") if err != nil { t.Fatal(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { t.Fatalf("status = %d", res.StatusCode) } if ct := res.Header.Get("Content-Type"); ct != "image/jpeg" { t.Fatalf("Content-Type = %q, want image/jpeg", ct) } got, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } if string(got) != string(body) { t.Fatalf("body = %q", got) } missing, err := http.Get(srv.URL + "/storage/uploads/mis/sin/g.j/missing.jpg") if err != nil { t.Fatal(err) } defer missing.Body.Close() if missing.StatusCode != http.StatusNotFound { t.Fatalf("missing status = %d, want 404", missing.StatusCode) } for _, path := range []string{ "/storage/uploads/abc/123/xyz/../abc123xyz.jpg", "/storage/uploads/abc/123/xyz//abc123xyz.jpg", "/storage/uploads/foo/bar/baz/abc123xyz.jpg", "/storage/uploads/abc/123/xyz/abc123xyz.jpg/extra", "/storage/uploads", } { rr := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, path, nil) h.ServeHTTP(rr, req) if rr.Code != http.StatusNotFound { t.Fatalf("path %q status = %d, want 404", path, rr.Code) } } } func TestStaticHandlerServesThumbURL(t *testing.T) { ctx := t.Context() bucket := memblob.OpenBucket(nil) t.Cleanup(func() { _ = bucket.Close() }) f := &File{ID: 42, DiskName: "abc123xyz.jpg"} if err := bucket.WriteAll(ctx, BlobKey(f.DiskName), testJPEG(t), &blob.WriterOptions{ContentType: "image/jpeg"}); err != nil { t.Fatal(err) } thumbURL, err := f.Thumb(ctx, bucket, 200, 200, "crop") if err != nil { t.Fatal(err) } const wantURL = "/storage/uploads/abc/123/xyz/thumb_42_200_200_0_0_crop.jpg" if thumbURL != wantURL { t.Fatalf("Thumb URL = %q, want %q", thumbURL, wantURL) } h := StaticHandler(bucket, "/storage/uploads") srv := httptest.NewServer(h) t.Cleanup(srv.Close) res, err := http.Get(srv.URL + thumbURL) if err != nil { t.Fatal(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { t.Fatalf("thumb GET status = %d, want 200", res.StatusCode) } body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } if len(body) == 0 { t.Fatal("thumb body is empty") } mismatch := httptest.NewRecorder() h.ServeHTTP(mismatch, httptest.NewRequest(http.MethodGet, "/storage/uploads/foo/bar/baz/abc123xyz.jpg", nil)) if mismatch.Code != http.StatusNotFound { t.Fatalf("mismatched original partition status = %d, want 404", mismatch.Code) } }