Skip to main content

Crate gfeh_http

Crate gfeh_http 

Source
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-Modified is 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 in gfeh_core now so there is one implementation to get right.
  • Range in all three forms, including bytes=-100 meaning 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.
  • 416 carries Content-Range: bytes */len, which is how a client that asked for too much learns how much there is.
  • ETag and If-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 a Last-Modified and a client holding the first would be told it is current.
  • Content-Disposition with a sanitized filename, because a name is user-controlled and a header injection here would be one in every response.

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.
HttpBuilder
Assembles an HttpView.
HttpView
A running HTTP view.
StaticExposures
An in-memory exposure table.

Traits§

Exposures
Resolves published tokens.