Capture: robots.txt is read only on the first host, and a robots.txt that redirects counts as allowing everything #364
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#364
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, reading the page-fetching code and runningrobots_allowagainst a mock transport.Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atplugins/fetching.py:100-136(robots_allow) and:163-194(fetch_page, with the robots check at:171).fetch_pageasksrobots_allowonce, for the URL it was given, with the client it opened withfollow_redirects=False. Arobots.txtthat answers with a redirect (http to https, the bare domain towww., both very common) therefore comes back as a 301 or 302, and every status other than 200 means "allowed". And when the posting URL itself redirects to another host, that host'srobots.txtis never read. The module docstring says "robots.txtis honoured", and the Server settings page offers "Ignore robots.txt when capturing" as though it were.plugins/fetching.py:144-180(robots_allow:if response.status_code != 200: return True);plugins/fetching.py:208-239(fetch_page: the client is opened withfollow_redirects=False, and the robots check at:216sits before thefor _hop in range(MAX_REDIRECTS + 1)loop, which changescurrentto another host without checking again).https://example.org/robots.txtanswering301 Location: https://www.example.org/robots.txt, and that file disallowing/careers,robots_allow("https://example.org/careers/1", client=…)returnsTrueafter one request; the redirect target is never fetched. In the same way, a posting athttps://short.example/123that redirects tohttps://jobs.example.com/careers/123is fetched withoutjobs.example.com/robots.txtbeing consulted.robots.txt, and an administrator who leaves "Ignore robots.txt" off is relying on that; on many real sites the check never reads the file at all. RFC 9309 §2.3.1.2 asks a client to follow at least five redirects forrobots.txt. Therobots_allowdocstring also says a missing, unreachable or unparseable file means yes "which is what the standard says"; RFC 9309 §2.3.1.4 says the opposite for a server error (5xx): assume complete disallow. Either follow it or stop citing the standard for that case.robots_allow, follow up toMAX_REDIRECTSredirects forrobots.txtby hand through the same guarded client (each hop goes through the public-only hook already), and parse the final 200. Infetch_page, when a redirect changes the scheme, host or port, callrobots_allowagain for the new URL before requesting it. Correct the docstring's claim about the standard, or treat 5xx as disallow.Done when
tests/test_capture.pyhas a test whererobots.txtredirects to a file that disallows the path androbots_allowreturnsFalse, and a test where the posting redirects to a second host whoserobots.txtdisallows it andfetch_pageraisesRobotsDisallowed.