Skip to content
Open
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
75 changes: 58 additions & 17 deletions src/FlareSolverrSharp/ClearanceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class ClearanceHandler : DelegatingHandler
{
private readonly HttpClient _client;
private readonly string _flareSolverrApiUrl;
private readonly IFlaresolverrResponseStorage _responseStorage;
private FlareSolverr _flareSolverr;
private string _userAgent;

Expand All @@ -42,6 +43,17 @@ public class ClearanceHandler : DelegatingHandler
/// <param name="flareSolverrApiUrl">FlareSolverr API URL. If null or empty it will detect the challenges, but
/// they will not be solved. Example: "http://localhost:8191/"</param>
public ClearanceHandler(string flareSolverrApiUrl)
: this(flareSolverrApiUrl, new DefaultFlaresolverrResponseStorage())
{
}

/// <summary>
/// Creates a new instance of the <see cref="ClearanceHandler"/>.
/// </summary>
/// <param name="flareSolverrApiUrl">FlareSolverr API URL. If null or empty it will detect the challenges, but
/// they will not be solved. Example: "http://localhost:8191/"</param>
/// <param name="responseStorage">Storage to persist challenge responses.</param>
public ClearanceHandler(string flareSolverrApiUrl, IFlaresolverrResponseStorage responseStorage)
: base(new HttpClientHandler())
{
// Validate URI
Expand All @@ -50,6 +62,7 @@ public ClearanceHandler(string flareSolverrApiUrl)
throw new FlareSolverrException("FlareSolverr URL is malformed: " + flareSolverrApiUrl);

_flareSolverrApiUrl = flareSolverrApiUrl;
_responseStorage = responseStorage;

_client = new HttpClient(new HttpClientHandler
{
Expand Down Expand Up @@ -84,36 +97,64 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Detect if there is a challenge in the response
if (ChallengeDetector.IsClearanceRequired(response))
if (!ChallengeDetector.IsClearanceRequired(response))
{
if (_flareSolverr == null)
throw new FlareSolverrException("Challenge detected but FlareSolverr is not configured");
return response;
}

// Resolve the challenge using FlareSolverr API
var flareSolverrResponse = await _flareSolverr.Solve(request);
if (_flareSolverr == null)
throw new FlareSolverrException("Challenge detected but FlareSolverr is not configured");

// Check if saved response exists.
var flareSolverrResponse = await _responseStorage.LoadAsync();

// Save the FlareSolverr User-Agent for the following requests
var flareSolverUserAgent = flareSolverrResponse.Solution.UserAgent;
if (flareSolverUserAgent != null && !flareSolverUserAgent.Equals(request.Headers.UserAgent.ToString()))
if (flareSolverrResponse != null)
{
// Set user agent
if (flareSolverrResponse.Solution.UserAgent != null &&
!flareSolverrResponse.Solution.UserAgent.Equals(request.Headers.UserAgent.ToString()))
{
_userAgent = flareSolverUserAgent;

// Set the User-Agent if required
_userAgent = flareSolverrResponse.Solution.UserAgent;
SetUserAgentHeader(request);
}

// Change the cookies in the original request with the cookies provided by FlareSolverr
// Retry request with saved response
InjectCookies(request, flareSolverrResponse);
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Detect if there is a challenge in the response
if (ChallengeDetector.IsClearanceRequired(response))
throw new FlareSolverrException("The cookies provided by FlareSolverr are not valid");
if (!ChallengeDetector.IsClearanceRequired(response))
{
// Success with saved response.
InjectSetCookieHeader(response, flareSolverrResponse);
return response;
}
}

// Resolve the challenge using FlareSolverr API
flareSolverrResponse = await _flareSolverr.Solve(request);

// Save the FlareSolverr User-Agent for the following requests
var flareSolverUserAgent = flareSolverrResponse.Solution.UserAgent;
if (flareSolverUserAgent != null && !flareSolverUserAgent.Equals(request.Headers.UserAgent.ToString()))
{
_userAgent = flareSolverUserAgent;

// Add the "Set-Cookie" header in the response with the cookies provided by FlareSolverr
InjectSetCookieHeader(response, flareSolverrResponse);
// Set the User-Agent if required
SetUserAgentHeader(request);
}

// Change the cookies in the original request with the cookies provided by FlareSolverr
InjectCookies(request, flareSolverrResponse);
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Detect if there is a challenge in the response
if (ChallengeDetector.IsClearanceRequired(response))
throw new FlareSolverrException("The cookies provided by FlareSolverr are not valid");

// Add the "Set-Cookie" header in the response with the cookies provided by FlareSolverr
InjectSetCookieHeader(response, flareSolverrResponse);
await _responseStorage.SaveAsync(flareSolverrResponse);

return response;
}

Expand Down
24 changes: 24 additions & 0 deletions src/FlareSolverrSharp/FlaresolverrResponseStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Threading.Tasks;
using FlareSolverrSharp.Types;

namespace FlareSolverrSharp
{
public interface IFlaresolverrResponseStorage
{
Task SaveAsync(FlareSolverrResponse result);
Task<FlareSolverrResponse> LoadAsync();
}

public class DefaultFlaresolverrResponseStorage : IFlaresolverrResponseStorage
{
public Task<FlareSolverrResponse> LoadAsync()
{
return Task.FromResult<FlareSolverrResponse>(null);
}

public Task SaveAsync(FlareSolverrResponse result)
{
return Task.CompletedTask;
}
}
}