Skip to content

Redirect walker followups: hostname/port match + RFC 303 test docstring - #1868

Open
jacalata wants to merge 2 commits into
developmentfrom
jac/redirect-followups
Open

Redirect walker followups: hostname/port match + RFC 303 test docstring#1868
jacalata wants to merge 2 commits into
developmentfrom
jac/redirect-followups

Conversation

@jacalata

Copy link
Copy Markdown
Contributor

Followup to #1848 (merged). Two small items from a post-merge
fresh-eyes review, kept off #1848 so the merged PR's approval + history
stayed clean.

Changes

  • endpoint.py: the http -> https address-promotion match now
    compares hostnames case-insensitively per RFC 3986 and normalizes
    http://host vs http://host:80 so the same-host check doesn't
    silently drop legitimate promotions. Rewritten as two comparisons:
    current vs next (same-host across schemes, hostname only), and
    old_address vs current (same-scheme, hostname+port with default-
    port normalization). Also expanded the auth-material comment to
    acknowledge that sign_in itself carries raw credentials (PAT
    secret or username+password) in the POST body, not only the
    issued token on subsequent calls.
  • test/test_redirect_handling.py: added a docstring on
    test_all_supported_redirect_codes_preserve_post_body naming the
    RFC 7231 6.4.4 deviation on 303, so a future refactor that
    "helpfully" converts 303 to GET fails this test with a clear
    intent statement.

Test plan

  • test/test_redirect_handling.py: 26 pass
  • mypy clean

Not addressed here (per fresh-eyes review)

  • sign_in namespace-detect hedge for pre-8.3 Tableau servers:
    dropped as theoretical. TSC's minimum_supported_server_version = 2.3 (Tableau 10.0, 2016) is eight years past the namespace
    change, and Proposed: Remove pre-8.3 XML namespace fallback #1863 removes the whole Namespace.detect subsystem
    anyway.
  • Streaming/file body replay on redirect: same limitation requests
    has; [tabcmd] fix: preserve POST body across 3xx redirects (#1127, #1828) #1848's walker doesn't rewind non-seekable data. Separate
    policy decision.
  • Progress indicator on redirect follow-up hops: hops go through
    _blocking_request directly, so the initial-request threaded
    progress indicator is lost. Separate refactor.

🤖 Generated with Claude Code

Two adjustments from a post-merge fresh-eyes pass:

- endpoint.py: the http -> https address-promotion match now compares
  hostnames case-insensitively (RFC 3986) and normalizes http://host
  vs http://host:80 so a same-host promotion doesn't silently drop.
  Split into two comparisons: current-vs-next is hostname-only
  (schemes differ so default port differs, comparing raw netloc
  would spuriously mismatch); old-address-vs-current is same-scheme
  and uses (hostname, effective port) so explicit-vs-implicit port
  compares equal. Expanded the auth-material comment to acknowledge
  that sign_in itself carries raw credentials in the POST body, not
  only the issued token on subsequent calls.

- test_redirect_handling.py: added a docstring on
  test_all_supported_redirect_codes_preserve_post_body naming the
  RFC 7231 6.4.4 deviation on 303 -- if a future refactor
  "helpfully" converts 303 to GET, the parametrized test fails
  with a clear intent statement.

Also considered a sign_in namespace-detect hedge for pre-8.3
Tableau responses (Copilot flagged this on #1848); dropped as
theoretical because TSC's minimum_supported_server_version = 2.3
(Tableau 10.0, 2016) is eight years past the namespace change,
and #1863 removes the whole subsystem anyway.
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tableauserverclient
   __init__.py50100% 
   config.py150100% 
   datetime_helpers.py2511 96%
   exponential_backoff.py200100% 
   filesys_helpers.py310100% 
   namespace.py2533 88%
tableauserverclient/bin
   __init__.py20100% 
   _version.py358212212 41%
tableauserverclient/helpers
   __init__.py10100% 
   logging.py20100% 
   strings.py3111 97%
tableauserverclient/models
   __init__.py460100% 
   collection_item.py4177 83%
   column_item.py553232 42%
   connection_credentials.py351111 69%
   connection_item.py941414 85%
   custom_view_item.py1442121 85%
   data_acceleration_report_item.py5411 98%
   data_alert_item.py15844 97%
   data_freshness_policy_item.py1551515 90%
   database_item.py2073636 83%
   datasource_item.py3001212 96%
   dqw_item.py10455 95%
   exceptions.py40100% 
   extensions_item.py13244 97%
   extract_item.py4444 91%
   favorites_item.py6988 88%
   fileupload_item.py190100% 
   flow_item.py1491010 93%
   flow_run_item.py710100% 
   group_item.py8966 93%
   groupset_item.py4977 86%
   interval_item.py1823232 82%
   job_item.py1921010 95%
   linked_tasks_item.py7911 99%
   location_item.py2922 93%
   metric_item.py1291313 90%
   oidc_item.py6333 95%
   pagination_item.py3411 97%
   permissions_item.py1111212 89%
   project_item.py2073131 85%
   property_decorators.py1001818 82%
   reference_item.py2622 92%
   revision_item.py5911 98%
   schedule_item.py20966 97%
   server_info_item.py3777 81%
   site_item.py6361313 98%
   subscription_item.py10122 98%
   table_item.py1191818 85%
   tableau_auth.py612525 59%
   tableau_types.py2711 96%
   tag_item.py150100% 
   target.py60100% 
   task_item.py5622 96%
   user_item.py3381717 95%
   view_item.py2201616 93%
   virtual_connection_item.py6488 88%
   webhook_item.py6911 99%
   workbook_item.py3621616 96%
tableauserverclient/server
   __init__.py90100% 
   exceptions.py40100% 
   filter.py2911 97%
   pager.py3311 97%
   query.py1431515 90%
   request_factory.py1335195195 85%
   request_options.py38655 99%
   server.py2492525 90%
   sort.py60100% 
tableauserverclient/server/endpoint
   __init__.py350100% 
   auth_endpoint.py731010 86%
   custom_views_endpoint.py1521212 92%
   data_acceleration_report_endpoint.py210100% 
   data_alert_endpoint.py942323 76%
   databases_endpoint.py1113030 73%
   datasources_endpoint.py3233333 90%
   default_permissions_endpoint.py4433 93%
   dqw_endpoint.py451616 64%
   endpoint.py2682525 91%
   exceptions.py7966 92%
   extensions_endpoint.py310100% 
   favorites_endpoint.py942222 77%
   fileuploads_endpoint.py510100% 
   flow_runs_endpoint.py6299 85%
   flow_task_endpoint.py2122 90%
   flows_endpoint.py1985353 73%
   groups_endpoint.py12699 93%
   groupsets_endpoint.py7277 90%
   jobs_endpoint.py6799 87%
   linked_tasks_endpoint.py370100% 
   metadata_endpoint.py881414 84%
   metrics_endpoint.py5566 89%
   oidc_endpoint.py4211 98%
   permissions_endpoint.py4433 93%
   projects_endpoint.py1782424 87%
   resource_tagger.py1273535 72%
   schedules_endpoint.py1191111 91%
   server_info_endpoint.py361010 72%
   sites_endpoint.py1302727 79%
   subscriptions_endpoint.py561414 75%
   tables_endpoint.py1103636 67%
   tasks_endpoint.py6366 90%
   users_endpoint.py17077 96%
   views_endpoint.py15099 94%
   virtual_connections_endpoint.py1131010 91%
   webhooks_endpoint.py5499 83%
   workbooks_endpoint.py3382222 93%
TOTAL12136142788% 

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Port promotion can persist an incorrect HTTPS endpoint, and unrestricted cross-host credential replay remains unsafe.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Refines manual redirect handling and documents intentional POST preservation for HTTP 303 responses.

Changes:

  • Normalizes hostname and port comparisons during HTTP-to-HTTPS promotion.
  • Expands documentation of credential forwarding across redirects.
  • Documents intentional RFC 7231 deviation for 303 responses.
File summaries
File Description
tableauserverclient/server/endpoint/endpoint.py Refines redirect address promotion and credential-policy comments.
test/test_redirect_handling.py Explains intentional POST preservation for 303 redirects.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tableauserverclient/server/endpoint/endpoint.py
Comment thread tableauserverclient/server/endpoint/endpoint.py
The same-host check correctly allowed cross-scheme redirects, but the
new_address was built by stripping "http://" off the old address, so the
target's port was silently dropped. Enterprise on-prem installs that run
HTTPS on a non-default port (e.g. 8443) ended up with a bogus stored
address after the first redirect. Build new_address from the redirect
target's hostname + port instead.

Adds regression tests covering explicit target port, default-port
normalization, and the unrelated-host non-promotion case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants