Repository: tauri-apps/tauri
File: crates/tauri/src/protocol/asset.rs (Rust)

Code before:
  let path = percent_encoding::percent_decode(&request.uri().path().as_bytes()[1..])
    .decode_utf8_lossy()
    .to_string();

  let mut resp = Response::builder().header("Access-Control-Allow-Origin", window_origin);

  if let Err(e) = SafePathBuf::new(path.clone().into()) {
    log::error!("asset protocol path \"{}\" is not valid: {}", path, e);
    return resp.status(403).body(Vec::new().into()).map_err(Into::into);
  }

  if !scope.is_allowed(&path) {
    log::error!("asset protocol not configured to allow the path: {}", path);
    return resp.status(403).body(Vec::new().into()).map_err(Into::into);
  }

  // Check if the file exists before trying to open it
  if !std::path::Path::new(&path).exists() {
    log::error!("File does not exist at path: {}", path);
    return resp.status(404).body(Vec::new().into()).map_err(Into::into);
  }
  
  // Check if we have read permissions
  if let Err(e) = std::fs::metadata(&path) {
    log::error!("Failed to get metadata for {}: {}", path, e);
    return resp.status(500).body(format!("Failed to access file metadata: {}", e).into_bytes().into()).map_err(Into::into);
  }

  let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move {
    let mut file = match File::open(&path).await {
      Ok(file) => file,
      Err(e) => {
        #[cfg(target_os = "android")]
        {
          if path.starts_with("/storage/emulated/0/Android/data/") {
            log::error!("Failed to open Android external storage file '{}': {}. This may be due to missing storage permissions or the file being inaccessible from the webview context.", path, e);
          }
        }
        return Err(e.into());
      }
    };

    // get file length
    let len = {
      let old_pos = file.stream_position().await?;
      let len = file.seek(SeekFrom::End(0)).await?;
      file.seek(SeekFrom::Start(old_pos)).await?;
      len
    };

    // get file mime type

Review comment (suggestion):
maybe we shouldn't use `500` here since that's our fallback on any kind of error. Any other ideas? 403 comes to mind but we already use that above 🤔 

Code after:
  let path = percent_encoding::percent_decode(&request.uri().path().as_bytes()[1..])
    .decode_utf8_lossy()
    .to_string();

  let mut resp = Response::builder().header("Access-Control-Allow-Origin", window_origin);

  if let Err(e) = SafePathBuf::new(path.clone().into()) {
    log::error!("asset protocol path \"{}\" is not valid: {}", path, e);
    return resp.status(403).body(Vec::new().into()).map_err(Into::into);
  }

  if !scope.is_allowed(&path) {
    log::error!("asset protocol not configured to allow the path: {}", path);
    return resp.status(403).body(Vec::new().into()).map_err(Into::into);
  }

  // Separate block for easier error handling
  let mut file = match crate::async_runtime::safe_block_on(File::open(path.clone())) {
    Ok(file) => file,
    Err(e) => {
      #[cfg(target_os = "android")]
      {
        if path.starts_with("/storage/emulated/0/Android/data/") {
          log::error!("Failed to open Android external storage file '{}': {}. This may be due to missing storage permissions.", path, e);
        }
      }
      return if e.kind() == std::io::ErrorKind::NotFound {
        log::error!("File does not exist at path: {}", path);
        return resp.status(404).body(Vec::new().into()).map_err(Into::into);
      } else if e.kind() == std::io::ErrorKind::PermissionDenied {
        log::error!("Missing OS permission to access path \"{}\": {}", path, e);
        return resp.status(403).body(Vec::new().into()).map_err(Into::into);
      } else {
        Err(e.into())
      };
    }
  };

  let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move {
    // get file length
    let len = {
      let old_pos = file.stream_position().await?;
      let len = file.seek(SeekFrom::End(0)).await?;
      file.seek(SeekFrom::Start(old_pos)).await?;
      len
    };

    // get file mime type
    let (mime_type, read_bytes) = {
      let nbytes = len.min(8192);
      let mut magic_buf = Vec::with_capacity(nbytes as usize);