Expand description
The plain-HTTP view: one file, one link, no client.
Every other view in gfeh speaks to software. This one speaks to whoever was sent
the URL – a browser, curl, a <video> element, something embedded in a mail
client – so its correctness is measured entirely in headers.
§What it serves
A published file at /f/{token}, and nothing else. There is no directory listing,
no upload, no path traversal surface, and no way to name an object except by a token
somebody deliberately minted for it. That is the whole point of the design: an
opaque token is not a path, so a link cannot be edited into a link to something
else, and a rename does not break a URL already in circulation.
§The headers that matter
Last-Modifiedis an HTTP-date, never ISO 8601. Sending the wrong one made an S3 object visible in a listing and unreadable by the AWS SDK for Go. Both formats live ingfeh_corenow so there is one implementation to get right.Rangein all three forms, includingbytes=-100meaning the last hundred bytes. Reading that as “from byte 100” hands a video player the opening credits when it asked for the index at the end of the file.416carriesContent-Range: bytes */len, which is how a client that asked for too much learns how much there is.ETagandIf-None-Match, answered before the object is opened – the point of a conditional request is not to move the bytes.If-Modified-Since, for the clients that revalidate on a date because that is all they were given. The entity tag wins when both arrive, as RFC 9110 requires: an HTTP-date has one-second resolution, so two writes inside one second share aLast-Modifiedand a client holding the first would be told it is current.Content-Dispositionwith a sanitized filename, because a name is user-controlled and a header injection here would be one in every response.
§A link is not a login
Requests run as the public principal with Perm::READ
and nothing else, so the enforcement layer below still has the final say. A revoked
link answers 404 rather than 403: telling the holder that the token is real but
switched off is information they should not have.
§Example
use gfeh_core::{Disposition, NodeKind, NodeRef, ObjectStore, OpCtx};
use gfeh_http::{Exposed, HttpView, StaticExposures};
use gfeh_store::MemStore;
use std::sync::Arc;
let store = Arc::new(MemStore::new());
let cx = OpCtx::system("example");
let mut handle = store
.create(&cx, &store.root(), "report.pdf", NodeKind::File, Disposition::CreateNew)
.await?;
handle.write_at(0, bytes::Bytes::from_static(b"%PDF-1.7")).await?;
let meta = handle.close().await?;
let exposures = StaticExposures::new().with(
"s3cr3t-token",
Exposed {
node: NodeRef::Id(store.partition(), meta.id),
filename: None,
enabled: true,
},
);
let view = HttpView::builder(store, Arc::new(exposures)).start().await?;
let body = reqwest::get(view.url_for("s3cr3t-token")).await?.text().await?;
assert_eq!(body, "%PDF-1.7");Modules§
- conformance
- The suite this view must satisfy over every store it can be given.
Structs§
- Exposed
- A file published under a token.
- Http
Builder - Assembles an
HttpView. - Http
View - A running HTTP view.
- Static
Exposures - An in-memory exposure table.
Traits§
- Exposures
- Resolves published tokens.