Fix source.dot.net proxied-index serving (500, .js, references, SolutionExplorer)#266
Merged
tannergooding merged 3 commits intoJul 19, 2026
Conversation
…es.js The index proxy threw on Convert.ToBase64String when a blob had no ContentHash (block-uploaded blobs lack one), returning HTTP 500 for larger files such as SolutionExplorer.html. Only emit Content-Md5 when present. Also serve the generated per-assembly A.files.js from blob so the new two-level symbol redirect resolves; previously only .html/.txt were proxied, so it 404'd and navigation fell through to the 'Don't use this page directly' page. Scope the change to .files.js specifically -- the only .js the index emits -- so chrome scripts.js keeps serving from wwwroot. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
tannergooding
force-pushed
the
tannergooding-investigate-azure-file-loading
branch
from
July 19, 2026 02:00
2ed7654 to
fbecca7
Compare
The per-symbol reference fragments (/{assembly}/R/{id}.html) were read
only from the local references.pack, so they 404'd on source.dot.net
where the index -- pack included -- is uploaded to blob rather than
shipped with the webapp.
Make ReferencePack blob-aware: read the small references.index into
memory once, then stream each fragment out of references.pack via a new
IFileSystem.CopyBytesToAsync, mirroring how IndexLoader falls back to
AzureBlobFileSystem. Fragments are streamed straight to the response
(ranged blob GET, or pooled chunked reads locally) rather than buffered,
so a heavily-referenced symbol's multi-MB fragment doesn't force a
large-object-heap allocation per request.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The nav frame redirects to /SolutionExplorer.html; the pipeline serves the generated one from the index (blob or local) and only falls through to wwwroot when it's absent. Ship a static placeholder there so that case shows a 'use search' note in the nav pane instead of a 404. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
tannergooding
enabled auto-merge (squash)
July 19, 2026 02:23
jeffhandley
approved these changes
Jul 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Several defects that break source.dot.net, all rooted in the same thing: it serves the index from Azure blob storage through the proxy layer (
SOURCE_BROWSER_INDEX_PROXY_URLset), where sites that serve the index from local disk (e.g. source.terrafx.dev, proxy disabled) never exercise the affected paths. That's why #264 surfaced them only on source.dot.net.SolutionExplorer.html-> HTTP 500Helpers.ProxyRequestAsynccalledConvert.ToBase64String(props.ContentHash)unconditionally. Azure does not guarantee a blob has aContent-MD5: block-uploaded blobs (the larger files, e.g. the ~2.8 MBSolutionExplorer.html) lack one, whereas smaller single-PutBlobuploads carry it.Convert.ToBase64String(null)threw, was rethrown asInvalidOperationException, and produced an empty-body 500. Every smaller proxied file returned 200 (with aContent-Md5), so only the large files broke.Fix: only append
Content-Md5whenContentHashis present.Symbol navigation shows "Don't use this page directly, pass #symbolId to get redirected."
#264 introduced a two-level symbol redirect where each
A.htmlloads a generated per-assemblyA.files.js. The proxy only served.html/.txt, so on a proxied deployment the.jsfell through to the static-file provider -- which does not have the index on local disk -- and 404'd, leaving the redirect stub. Confirmed live:.../a.html-> 200 (blob),.../A.files.js-> 404.Fix: also proxy that file, using the same
FileExistsfall-through. Scoped to the.files.jssuffix -- the only.jsthe generator emits into the index -- so chrome scripts (scripts.js) keep serving from wwwroot rather than being proxied.Reference fragments (
/{assembly}/R/{id}.html) -> 404The per-symbol reference fragments are packed into a single
references.pack(+references.index) served byReferencePackMiddleware, which read them via rawFile.*-- local disk only. On the proxied deployment the pack is uploaded to blob rather than shipped with the webapp, so every reference fragment 404'd. Confirmed live: a real source page linkingR/36a0ef01cb5d5107.htmletc., all 404.Fix: make
ReferencePackblob-aware, mirroring howIndexLoaderalready falls back toAzureBlobFileSystem. The smallreferences.indexis read into memory once; each fragment is then streamed straight to the response -- a ranged blob GET, or pooled chunked reads locally -- via a newIFileSystem.CopyBytesToAsync. Streaming rather than buffering means a heavily-referenced symbol's (multi-MB) fragment doesn't force a large-object-heap allocation per request. The local file-handle path is otherwise unchanged.Graceful
SolutionExplorer.htmlfallbackThe nav frame redirects to
/SolutionExplorer.html; the pipeline serves the generated one from the index (blob or local) and only falls through to wwwroot when it's absent. Added a static placeholder there -- matching the generated page's chrome, but with no tree and noonSolutionExplorerLoad()-- so an index without one shows a "use search" note in the nav pane instead of a 404.Verified
SourceIndexServerbuilds clean and the fallback is included onpublish. The blob paths can only be fully exercised against the live proxied deployment (private container), so a post-deploy check is warranted. This is the vendored SourceBrowser copy; the same fixes should also land upstream in tannergooding/SourceBrowser on the next re-vendor.