Skip to content

Repository resources fetch the wrong content when a file name contains "%" #3614

Open

Description

@jaeminbird

Describe the bug

repo:// resource reads build the raw.githubusercontent.com URL from the decoded file path, so a file name containing % fetches the wrong content. For docs/100%.txt, resources/read on repo://owner/repo/contents/docs/100%25.txt (the URI get_file_contents emits) returns github.com's homepage HTML as the file's text; for a file named %41.txt it returns the contents of A.txt. Spaces, #, ? and unicode are encoded correctly.

Affected version

main @ latest-release-9-g84f423e

Steps to reproduce the behavior

c, _ := raw.NewClient(gh, mustParse("https://raw.githubusercontent.com/"))
c.URLFromOpts(nil, "o", "r", "100%.txt") // "https://raw.githubusercontent.com/"
c.URLFromOpts(nil, "o", "r", "%41.txt")  // ".../o/r/HEAD/%41.txt", served as A.txt

https://raw.githubusercontent.com/ redirects (301) to github.com and comes back as 200 text/html, which the resource handler treats as a successful text read.

Expected vs actual behavior

Expected: the file named 100%.txt / %41.txt is returned. Actual: GitHub's homepage HTML / the contents of A.txt.

Root cause and suggested fix

pkg/raw/raw.go:95 and :113 pass decoded path text to url.URL.JoinPath, which treats its arguments as already escaped: a literal %xx is decoded a second time, and an invalid escape makes JoinPath drop its internal error and keep the base URL. repository_resource.go:192 passes the path already decoded by uritemplate.

url.PathEscape each /-separated segment of owner/repo/ref/path before JoinPath (the .. rejection stays as is). One existing test, benign percent-encoded filename allowed, expects %2ehidden to pass through unescaped, which actually requests .hidden; with the fix it becomes %252ehidden. I have a patch with regression tests (raw URL cases and a resources/read handler test) and can open a PR if the approach sounds right. Related: #3437.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions