Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
httpd: Infer mime type of file blob in remaining raw handlers
Open did:key:z6MkkfM3...sVz5 opened 11 months ago
12 files changed +26 -99 fbb9dd64 15f5c98b
modified .github/workflows/check-build.yml
@@ -11,7 +11,7 @@ jobs:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
-
          node-version: "20.9.0"
+
          node-version: "22.12.0"
      - name: Install dependencies
        run: npm ci
      - name: Install Playwright Browsers
modified .github/workflows/check-http-client-unit-test.yml
@@ -10,7 +10,7 @@ jobs:
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
-
          node-version: "20.9.0"
+
          node-version: "22.12.0"
      - name: Checkout
        uses: actions/checkout@v4
      - run: npm ci
modified .github/workflows/check-radicle-httpd.yml
@@ -12,7 +12,7 @@ jobs:
        working-directory: ./radicle-httpd
    steps:
      - uses: actions/checkout@v4
-
      - uses: dtolnay/rust-toolchain@stable
+
      - uses: dtolnay/rust-toolchain@1.87
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: radicle-httpd -> target
@@ -30,7 +30,7 @@ jobs:
        working-directory: ./radicle-httpd
    steps:
      - uses: actions/checkout@v4
-
      - uses: dtolnay/rust-toolchain@stable
+
      - uses: dtolnay/rust-toolchain@1.87
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: radicle-httpd -> target
@@ -46,7 +46,9 @@ jobs:
        working-directory: ./radicle-httpd
    steps:
      - uses: actions/checkout@v4
-
      - uses: dtolnay/rust-toolchain@stable
+
      - uses: dtolnay/rust-toolchain@1.87
+
        with:
+
          components: rustfmt, clippy
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: radicle-httpd -> target
modified .github/workflows/check-unit-test.yml
@@ -10,7 +10,7 @@ jobs:
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
-
          node-version: "20.9.0"
+
          node-version: "22.12.0"
      - name: Checkout
        uses: actions/checkout@v4
      - run: npm ci
modified .github/workflows/check-visual.yml
@@ -27,7 +27,7 @@ jobs:

      - uses: actions/setup-node@v4
        with:
-
          node-version: "20.9.0"
+
          node-version: "22.12.0"

      - name: Install dependencies
        run: npm ci
modified .github/workflows/check.yml
@@ -10,7 +10,7 @@ jobs:
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
-
          node-version: "20.9.0"
+
          node-version: "22.12.0"
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run check
modified .nvmrc
@@ -1 +1 @@
-
20.9.0

\ No newline at end of file
+
22.12.0
modified .tool-versions
@@ -1 +1 @@
-
nodejs 20.9.0
+
nodejs 22.12.0
modified radicle-httpd/rust-toolchain
@@ -1 +1 @@
-
1.83

\ No newline at end of file
+
1.87
modified radicle-httpd/src/api.rs
@@ -42,6 +42,7 @@ impl Context {
        }
    }

+
    #[allow(clippy::result_large_err)]
    pub fn repo_info<R: ReadRepository + radicle::cob::Store>(
        &self,
        repo: &R,
@@ -98,6 +99,7 @@ impl Context {
    }

    /// Get a repository by RID, checking to make sure we're allowed to view it.
+
    #[allow(clippy::result_large_err)]
    pub fn repo(&self, rid: RepoId) -> Result<(Repository, DocAt), error::Error> {
        let repo = self.profile.storage.repository(rid)?;
        let doc = repo.identity_doc()?;
modified radicle-httpd/src/lib.rs
@@ -42,7 +42,7 @@ mod test;
mod tracing_extra;

/// Default cache HTTP size.
-
pub const DEFAULT_CACHE_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(100) };
+
pub const DEFAULT_CACHE_SIZE: NonZeroUsize = NonZeroUsize::new(100).unwrap();

#[derive(Debug, Clone)]
pub struct Options {
modified radicle-httpd/src/raw.rs
@@ -24,78 +24,6 @@ const MAX_BLOB_SIZE: usize = 10_485_760;

const ARCHIVE_SUFFIX: &str = ".tar.gz";

-
static MIMES: &[(&str, &str)] = &[
-
    ("3gp", "video/3gpp"),
-
    ("7z", "application/x-7z-compressed"),
-
    ("aac", "audio/aac"),
-
    ("avi", "video/x-msvideo"),
-
    ("bin", "application/octet-stream"),
-
    ("bmp", "image/bmp"),
-
    ("bz", "application/x-bzip"),
-
    ("bz2", "application/x-bzip2"),
-
    ("csh", "application/x-csh"),
-
    ("css", "text/css"),
-
    ("csv", "text/csv"),
-
    ("doc", "application/msword"),
-
    (
-
        "docx",
-
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
-
    ),
-
    ("epub", "application/epub+zip"),
-
    ("gz", "application/gzip"),
-
    ("gif", "image/gif"),
-
    ("htm", "text/html"),
-
    ("html", "text/html"),
-
    ("ico", "image/vnd.microsoft.icon"),
-
    ("jar", "application/java-archive"),
-
    ("jpeg", "image/jpeg"),
-
    ("jpg", "image/jpeg"),
-
    ("js", "text/javascript"),
-
    ("json", "application/json"),
-
    ("mjs", "text/javascript"),
-
    ("mp3", "audio/mpeg"),
-
    ("mp4", "video/mp4"),
-
    ("mpeg", "video/mpeg"),
-
    ("odp", "application/vnd.oasis.opendocument.presentation"),
-
    ("ods", "application/vnd.oasis.opendocument.spreadsheet"),
-
    ("odt", "application/vnd.oasis.opendocument.text"),
-
    ("oga", "audio/ogg"),
-
    ("ogv", "video/ogg"),
-
    ("ogx", "application/ogg"),
-
    ("otf", "font/otf"),
-
    ("png", "image/png"),
-
    ("pdf", "application/pdf"),
-
    ("php", "application/x-httpd-php"),
-
    ("ppt", "application/vnd.ms-powerpoint"),
-
    (
-
        "pptx",
-
        "application/vnd.openxmlformats-officedocument.presentationml.presentation",
-
    ),
-
    ("rar", "application/vnd.rar"),
-
    ("rtf", "application/rtf"),
-
    ("sh", "application/x-sh"),
-
    ("svg", "image/svg+xml"),
-
    ("tar", "application/x-tar"),
-
    ("tif", "image/tiff"),
-
    ("tiff", "image/tiff"),
-
    ("ttf", "font/ttf"),
-
    ("txt", "text/plain"),
-
    ("wav", "audio/wav"),
-
    ("weba", "audio/webm"),
-
    ("webm", "video/webm"),
-
    ("webp", "image/webp"),
-
    ("woff", "font/woff"),
-
    ("woff2", "font/woff2"),
-
    ("xhtml", "application/xhtml+xml"),
-
    ("xls", "application/vnd.ms-excel"),
-
    (
-
        "xlsx",
-
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
-
    ),
-
    ("xml", "application/xml"),
-
    ("zip", "application/zip"),
-
];
-

pub fn router(profile: Arc<Profile>) -> Router {
    Router::new()
        .route("/:rid/:sha", get(commit_handler))
@@ -146,7 +74,7 @@ async fn file_by_commit_handler(
    let repo: Repository = repo.backend.into();
    let blob = repo.blob(sha, &path)?;

-
    blob_response(blob, path)
+
    blob_response(blob)
}

async fn archive_by_refname_handler(
@@ -245,27 +173,22 @@ async fn file_by_canonical_head_handler(
    let repo: Repository = repo.backend.into();
    let blob = repo.blob(sha, &path)?;

-
    blob_response(blob, path)
+
    blob_response(blob)
}

-
fn blob_response(
-
    blob: Blob<BlobRef>,
-
    path: String,
-
) -> Result<(StatusCode, HeaderMap, Vec<u8>), Error> {
+
fn blob_response(blob: Blob<BlobRef>) -> Result<(StatusCode, HeaderMap, Vec<u8>), Error> {
    let mut response_headers = HeaderMap::new();
    if blob.size() > MAX_BLOB_SIZE {
        return Ok::<_, Error>((StatusCode::PAYLOAD_TOO_LARGE, response_headers, vec![]));
    }

-
    let mime = if let Some(ext) = path.split('.').last() {
-
        MIMES
-
            .binary_search_by(|(k, _)| k.cmp(&ext))
-
            .map(|k| MIMES[k].1)
-
            .unwrap_or("text/plain; charset=utf-8")
-
    } else {
-
        "application/octet-stream"
-
    };
-
    response_headers.insert(header::CONTENT_TYPE, HeaderValue::from_str(mime)?);
+
    let content = blob.content();
+
    let mime = infer::get(content).map(|i| i.mime_type().to_string());
+

+
    response_headers.insert(
+
        header::CONTENT_TYPE,
+
        HeaderValue::from_str(&mime.unwrap_or("application/octet-stream".to_string()))?,
+
    );

    Ok::<_, Error>((StatusCode::OK, response_headers, blob.content().to_owned()))
}