Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions src/RestSharp/Options/RedirectOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) .NET Foundation and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

namespace RestSharp;

/// <summary>
/// Options for controlling redirect behavior when RestSharp handles redirects.
/// </summary>
public class RedirectOptions {
/// <summary>
/// Whether to follow redirects. Default is true.
/// </summary>
public bool FollowRedirects { get; set; } = true;

/// <summary>
/// Whether to follow redirects from HTTPS to HTTP (insecure). Default is false.
/// </summary>
public bool FollowRedirectsToInsecure { get; set; }

/// <summary>
/// Whether to forward request headers on redirect. Default is true.
/// </summary>
public bool ForwardHeaders { get; set; } = true;

/// <summary>
/// Whether to forward the Authorization header on same-host redirects. Default is false.
/// Even when enabled, Authorization is stripped on cross-host redirects unless
/// <see cref="ForwardAuthorizationToExternalHost"/> is also set to true.
/// </summary>
public bool ForwardAuthorization { get; set; }

/// <summary>
/// Whether to forward the Authorization header when redirecting to a different host. Default is false.
/// Only applies when <see cref="ForwardAuthorization"/> is true. Enabling this can expose credentials
/// to unintended hosts if a redirect points to a third-party server.
/// </summary>
public bool ForwardAuthorizationToExternalHost { get; set; }

/// <summary>
/// Whether to forward cookies on redirect. Default is true.
/// Cookies from Set-Cookie headers are always stored in the CookieContainer regardless of this setting.
/// </summary>
public bool ForwardCookies { get; set; } = true;

/// <summary>
/// Whether to forward the request body on redirect when the HTTP verb is preserved. Default is true.
/// Body is always dropped when the verb changes to GET.
/// </summary>
public bool ForwardBody { get; set; } = true;

/// <summary>
/// Whether to forward original query string parameters on redirect. Default is true.
/// </summary>
public bool ForwardQuery { get; set; } = true;

/// <summary>
/// Maximum number of redirects to follow. Default is 50.
/// </summary>
public int MaxRedirects { get; set; } = 50;

/// <summary>
/// HTTP status codes that are considered redirects.
/// </summary>
public IReadOnlyList<HttpStatusCode> RedirectStatusCodes { get; set; } = [
HttpStatusCode.MovedPermanently, // 301
HttpStatusCode.Found, // 302
HttpStatusCode.SeeOther, // 303
HttpStatusCode.TemporaryRedirect, // 307
(HttpStatusCode)308, // 308 Permanent Redirect
];
}
23 changes: 20 additions & 3 deletions src/RestSharp/Options/RestClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,19 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba
#endif

/// <summary>
/// Set the maximum number of redirects to follow
/// Set the maximum number of redirects to follow.
/// This is a convenience property that delegates to <see cref="RedirectOptions"/>.MaxRedirects.
/// </summary>
#if NET
[UnsupportedOSPlatform("browser")]
#endif
public int? MaxRedirects { get; set; }
[Exclude]
public int? MaxRedirects {
get => RedirectOptions.MaxRedirects;
set {
if (value.HasValue) RedirectOptions.MaxRedirects = value.Value;
}
}

/// <summary>
/// X509CertificateCollection to be sent with request
Expand Down Expand Up @@ -141,8 +148,18 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba

/// <summary>
/// Instruct the client to follow redirects. Default is true.
/// This is a convenience property that delegates to <see cref="RedirectOptions"/>.FollowRedirects.
/// </summary>
[Exclude]
public bool FollowRedirects {
get => RedirectOptions.FollowRedirects;
set => RedirectOptions.FollowRedirects = value;
}

/// <summary>
/// Options for controlling redirect behavior.
/// </summary>
public bool FollowRedirects { get; set; } = true;
public RedirectOptions RedirectOptions { get; set; } = new();

/// <summary>
/// Gets or sets a value that indicates if the <see langword="Expect" /> header for an HTTP request contains Continue.
Expand Down
6 changes: 6 additions & 0 deletions src/RestSharp/Request/RequestHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public RequestHeaders AddAcceptHeader(string[] acceptedContentTypes) {
return this;
}

public RequestHeaders RemoveHeader(string name) {
Parameters.RemoveAll(p => string.Equals(p.Name, name, StringComparison.InvariantCultureIgnoreCase));
return this;
}

// Add Cookie header from the cookie container
public RequestHeaders AddCookieHeaders(Uri uri, CookieContainer? cookieContainer) {
if (cookieContainer == null) return this;
Expand All @@ -48,6 +53,7 @@ public RequestHeaders AddCookieHeaders(Uri uri, CookieContainer? cookieContainer

if (existing?.Value != null) {
newCookies = newCookies.Union(SplitHeader(existing.Value!));
Parameters.Remove(existing);
}

Parameters.Add(new(KnownHeaders.Cookie, string.Join("; ", newCookies)));
Expand Down
Loading
Loading