Skip to content

Repository get_contents() 302 redirect no longer functional b/c Github response headers no longer contain status #2125

@vchawla3

Description

@vchawla3

For the Get Content Repository endpoint: https://docs.github.com/en/rest/reference/repos#get-repository-content

When the the {path} on the endpoint ends with a trailing /, the api responds with a 302 Found and therefore PyGithub must then perform a GET on the url in location response header.

This currently is handled in the below code in PyGithub: https://github.com/PyGithub/PyGithub/blob/master/github/Repository.py#L1824-L1828

        # Handle 302 redirect response
        if headers.get("status") == "302 Found" and headers.get("location"):
            headers, data = self._requester.requestJsonAndCheck(
                "GET", headers["location"], parameters=url_parameters
            )

The issue I am facing with this now is that PyGithub expects there to be a status in the response headers, however the Github api no longer sends status as a response header.

I found this github support community post confirming this change: https://github.community/t/githubs-api-is-not-returning-status-in-its-response-header/160531

See the below cURL commands where I confirmed...

This request returns 200 when I send github as the path

{18:49}~ ➭ curl -I --request GET 'https://api.github.com/repos/PyGithub/PyGithub/contents/github' \
--header 'Authorization: Bearer <token redacted>'
HTTP/2 200
server: GitHub.com
date: Wed, 08 Dec 2021 23:49:06 GMT
content-type: application/json; charset=utf-8
content-length: 198400
cache-control: private, max-age=60, s-maxage=60
vary: Accept, Authorization, Cookie, X-GitHub-OTP
etag: "c4c07fd89012d914782b5cc0b5fc2028374d8a35"
last-modified: Wed, 08 Dec 2021 05:34:29 GMT
x-oauth-scopes: repo, user, workflow
x-accepted-oauth-scopes:
github-authentication-token-expiration: 2022-03-08 23:17:54 UTC
x-github-media-type: github.v3; format=json
x-ratelimit-limit: 5000
x-ratelimit-remaining: 4988
x-ratelimit-reset: 1639009499
x-ratelimit-used: 12
x-ratelimit-resource: core
access-control-expose-headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
access-control-allow-origin: *
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'
vary: Accept-Encoding, Accept, X-Requested-With
x-github-request-id: DB89:24AF:6CA656:10E89FA:61B14472

This request returns 302 when I send github/ as the path

{18:49}~ ➭ curl -I --request GET 'https://api.github.com/repos/PyGithub/PyGithub/contents/github/' \
--header 'Authorization: Bearer <token redacted>'
HTTP/2 302
server: GitHub.com
date: Wed, 08 Dec 2021 23:49:09 GMT
content-type: text/html;charset=utf-8
content-length: 0
location: https://api.github.com/repositories/3544490/contents/github
x-ratelimit-limit: 5000
x-ratelimit-remaining: 4987
x-ratelimit-reset: 1639009499
x-ratelimit-used: 13
x-ratelimit-resource: core
access-control-expose-headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
access-control-allow-origin: *
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'
vary: Accept-Encoding, Accept, X-Requested-With
x-github-request-id: DB8A:2115:129B94E:24BBC37:61B14475

In both of these cases, we can see there is no status header being returned by Github.

Therefore, when I replicate this function with the trailing / in the path with PyGithub, I get the following error b/c PyGithub fails to perform the necessary redirect since in the above if statement, headers.get("status") == "302 Found" does not return as True.

Python Code

from github import Github
from github import Repository

g = Github("<token redacted>")

repo = g.get_repo("PyGithub/PyGithub")

content = repo.get_contents("github/")

Output

Traceback (most recent call last):
  File "/Users/webbchawla/Documents/Projects/pygit_tst/main.py", line 10, in <module>
    content = repo.get_contents("github/")
  File "/Users/webbchawla/Documents/Projects/pygit_tst/.venv/lib/python3.9/site-packages/github/Repository.py", line 1810, in get_contents
    return github.ContentFile.ContentFile(
  File "/Users/webbchawla/Documents/Projects/pygit_tst/.venv/lib/python3.9/site-packages/github/GithubObject.py", line 283, in __init__
    super().__init__(requester, headers, attributes, completed)
  File "/Users/webbchawla/Documents/Projects/pygit_tst/.venv/lib/python3.9/site-packages/github/GithubObject.py", line 84, in __init__
    self._storeAndUseAttributes(headers, attributes)
  File "/Users/webbchawla/Documents/Projects/pygit_tst/.venv/lib/python3.9/site-packages/github/GithubObject.py", line 96, in _storeAndUseAttributes
    self._useAttributes(attributes)
  File "/Users/webbchawla/Documents/Projects/pygit_tst/.venv/lib/python3.9/site-packages/github/ContentFile.py", line 191, in _useAttributes
    if "content" in attributes:  # pragma no branch
TypeError: argument of type 'NoneType' is not iterable

For now, I am able to work around this issue by doing .rstrip("/") on the path before calling get_contents() but I figured it would be wise for PyGithub to handle the redirect case as well, however the maintainers feel is the best way.

Let me know if you need any more examples or clarification 😄

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions