Skip to content

Conversation

@VisualBean
Copy link
Contributor

@VisualBean VisualBean commented Oct 25, 2025

About the PR

There is a bug, where the Uri is relative and fails .Scheme throws and leaves us in the catch.

Related Issues

Summary by CodeRabbit

  • Bug Fixes

    • Improved stream loading to correctly distinguish absolute vs. relative paths and reliably handle supported URL schemes (file, http, https) in all cases.
    • Clarified and cleaned up error messages to provide clearer feedback when loading fails.
  • Refactor

    • Unified synchronous and asynchronous stream-loading behavior and error handling for more consistent and predictable results.

Signed-off-by: Alex Wichmann <VisualBean@users.noreply.github.com>
@coderabbitai
Copy link

coderabbitai bot commented Oct 25, 2025

Walkthrough

DefaultStreamLoader now checks Uri.IsAbsoluteUri and normalizes absolute-uri schemes to lowercase. Absolute URIs branch on scheme: "file" -> open LocalPath, "http"/"https" -> fetch via HttpClient, others throw. Non-absolute URIs open the path via uri.OriginalString. Logic mirrored for Load and LoadAsync.

Changes

Cohort / File(s) Change Summary
URI resolution and error handling
src/ByteBard.AsyncAPI.Readers/Services/DefaultStreamLoader.cs
Added explicit absolute-vs-relative Uri handling; normalized scheme with ToLowerInvariant() for branching; file uses uri.LocalPath, http/https use HttpClient.GetStreamAsync; non-absolute URIs use uri.OriginalString with File.OpenRead; adjusted exception message formatting; synchronized logic between Load and LoadAsync.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Caller
    participant Loader as DefaultStreamLoader
    participant FS as FileSystem
    participant HTTP as HttpClient

    Caller->>Loader: Load(uri) / LoadAsync(uri)
    Loader->>Loader: if uri.IsAbsoluteUri?
    alt Absolute URI
        Loader->>Loader: scheme = uri.Scheme.ToLowerInvariant()
        alt scheme == "file"
            Loader->>FS: File.OpenRead(uri.LocalPath)
            FS-->>Loader: Stream
            Loader-->>Caller: Stream / Task<Stream>
        else scheme == "http" or "https"
            Loader->>HTTP: GetStreamAsync(uri)
            HTTP-->>Loader: Stream
            Loader-->>Caller: Task<Stream>
        else other scheme
            Loader-->>Caller: throw NotSupportedException
        end
    else Relative URI
        Loader->>FS: File.OpenRead(uri.OriginalString)
        FS-->>Loader: Stream
        Loader-->>Caller: Stream / Task<Stream>
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Single-file change with duplicated sync/async branches.
  • Review focus: correctness of absolute vs relative handling, use of uri.LocalPath vs uri.OriginalString, scheme normalization, and updated exception text.

Poem

🐰 I sniffed the path both near and far,
Absolute I check the scheme by star,
Local files I open, HTTP I stream,
Relative trails return the home-team dream.
Hop—now references find their beam!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "fix: try read relative uri's as files." directly and accurately reflects the main change in the code. The implementation modifies DefaultStreamLoader to distinguish between absolute and relative URIs, treating relative URIs as file paths instead of attempting to access the Scheme property which throws an exception on relative URIs. The title is concise, specific, and clearly communicates the primary objective of fixing the handling of relative file references, which aligns with the issue being addressed.
Linked Issues Check ✅ Passed The code changes directly address the requirements in issue #20 by modifying the DefaultStreamLoader to properly handle relative URI paths as files. The implementation adds an explicit check for Uri.IsAbsoluteUri and treats non-absolute URIs (such as "./AsyncApiSchema_MessagePayload.yml") by opening them via File.OpenRead(uri.OriginalString), which resolves the core problem where accessing the Scheme property of relative URIs was throwing an exception. This fix enables the AsyncApiStreamReader to correctly locate and load external file references when ReferenceResolution is set to ResolveAllReferences.
Out of Scope Changes Check ✅ Passed All changes in this pull request are contained within the DefaultStreamLoader.cs file and are focused on the Load and LoadAsync methods, which directly address the issue of handling relative file references. The modifications distinguish between absolute and relative URIs, with relative paths being opened as files—this is precisely the scope required to fix issue #20. No public API signatures were altered, and no changes appear outside the necessary scope to resolve the reported bug.
Description Check ✅ Passed The pull request description includes the required "About the PR" and "Related Issues" sections from the template, with a clear explanation of the bug and the issue it closes. However, the description is missing the "Changelog" section specified in the template, which typically documents the additions and removals made by the PR. Despite this omission, the description is mostly complete and effectively communicates the essential information about what problem is being solved and which issue it addresses.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch alex/DefaultStreamLoaderFix

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as duplicate.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alex Wichmann <VisualBean@users.noreply.github.com>
Signed-off-by: Alex Wichmann <VisualBean@users.noreply.github.com>
Signed-off-by: Alex Wichmann <VisualBean@users.noreply.github.com>
Signed-off-by: Alex Wichmann <VisualBean@users.noreply.github.com>
coderabbitai[bot]

This comment was marked as duplicate.

Signed-off-by: Alex Wichmann <VisualBean@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/ByteBard.AsyncAPI.Readers/Services/DefaultStreamLoader.cs (1)

31-34: Relative URIs: resolve against base document and strip fragment/query.

Current code opens relative paths from the process working directory and includes any $ref fragment (e.g., "./file.yml#/components/..."), leading to false "file not found" errors. Relative references should resolve against the parent document’s location, and the loader must ignore URI fragment/query when opening the file. This is the core of issue #20 and remains unfixed in the relative branch. Based on relevant code snippet AsyncApiWorkspace.ToLocationUrl(string) returns UriKind.RelativeOrAbsolute, so relative inputs are expected here.

Minimum safe fix right now: strip fragment/query before File.OpenRead in both places.

-                    return File.OpenRead(uri.OriginalString);
+                    var path = uri.OriginalString;
+                    var hash = path.IndexOf('#');
+                    if (hash >= 0) path = path.Substring(0, hash);
+                    var qm = path.IndexOf('?');
+                    if (qm >= 0) path = path.Substring(0, qm);
+                    return File.OpenRead(path);

However, to fully resolve #20 across contexts, pass a base URI (the current document location) into the loader and resolve via new Uri(baseUri, uri) before branching:

  • Add an overload or extend IStreamLoader to accept a baseUri.
  • Resolve with: var resolved = uri.IsAbsoluteUri ? uri : new Uri(baseUri, uri);
  • Then reuse the absolute-URI switch.

I can draft a small refactor across IStreamLoader and call sites if you want.

Also applies to: 59-62

🧹 Nitpick comments (3)
src/ByteBard.AsyncAPI.Readers/Services/DefaultStreamLoader.cs (3)

18-29: Good guard and file-path fix; one follow-up for sync HTTP.

  • IsAbsoluteUri check and using uri.LocalPath are correct. Nice.
  • Consider the risk of blocking on HttpClient in Load(...) for http/https; this can deadlock under certain synchronization contexts and degrades throughput. Prefer steering callers to LoadAsync for network I/O or encapsulate the sync path behind a documented "may block" warning. Optionally, include the scheme in the "Unsupported scheme" error for easier diagnostics.

Example small tweak to improve the error text:

-                            throw new ArgumentException("Unsupported scheme");
+                            throw new ArgumentException($"Unsupported scheme '{uri.Scheme}'.")

46-58: Async path looks correct; consider CT and async-friendly file stream.

  • Switched to await HttpClient.GetStreamAsync — good.
  • Consider adding CancellationToken to LoadAsync and threading it through HTTP and file open.
  • Optionally, for very large files or remote FS, return a FileStream opened with FileOptions.Asynchronous to enable true async reads downstream.

Example (signature change shown for illustration):

public async Task<Stream> LoadAsync(Uri uri, CancellationToken ct = default)
{
    if (uri.IsAbsoluteUri)
    {
        switch (uri.Scheme.ToLowerInvariant())
        {
            case "file":
                return new FileStream(uri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous);
            case "http":
            case "https":
                return await HttpClient.GetStreamAsync(uri, ct);
        }
    }
    // relative path handling per the other comment (strip fragment/query and resolve with baseUri if available)
}

38-38: Make error details more actionable.

Include the resolved path/URI and inner exception type; helps users differentiate path resolution vs network errors.

-                throw new AsyncApiReaderException($"Something went wrong trying to fetch '{uri.OriginalString}'. {ex.Message}", ex);
+                throw new AsyncApiReaderException(
+                    $"Failed to load resource '{uri}'. {ex.GetType().Name}: {ex.Message}",
+                    ex);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69637b1 and 6020b66.

📒 Files selected for processing (1)
  • src/ByteBard.AsyncAPI.Readers/Services/DefaultStreamLoader.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/ByteBard.AsyncAPI.Readers/Services/DefaultStreamLoader.cs (1)
src/ByteBard.AsyncAPI/AsyncApiWorkspace.cs (1)
  • Uri (246-249)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: build (windows-latest)

@ByteBardOrg ByteBardOrg deleted a comment from coderabbitai bot Oct 25, 2025
@ByteBardOrg ByteBardOrg deleted a comment from coderabbitai bot Oct 25, 2025
@ByteBardOrg ByteBardOrg deleted a comment from coderabbitai bot Oct 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AsyncAPI.NET isn't able to load external file

2 participants