Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve incorrect cyclic redirect detection logic #5548

Merged
merged 18 commits into from Apr 8, 2024

Conversation

moromin
Copy link
Contributor

@moromin moromin commented Mar 29, 2024

Motivation:

Current implements can detect only cyclic redirect which comes back to original URL like a --> b --> c --> a.
And cannot detect some cases, for example, partial cyclic one like a --> b --> c --> b , however it returns TooManyRedirectsException instead of CyclicRedirectsException.

This is caused because adding redirect info to Multimap to check the cyclic always returns true. (code)
And I think the reasons we couldn't notice was that test cases were insufficient and didn't validate the exception type.

To resolve the above problems, I add the following changes.

Modifications:

  • Add RedirectSignature class to store redirect information.
  • Use Set instead of Multimap to check cyclic redirections with the above class.
    • Set.add() returns false when the same data is added.
  • Add tests to verify some cases such as partial loop as mentioned in motivation.
    • Verify CyclicRedirectsException is thrown.

Result:

@CLAassistant
Copy link

CLAassistant commented Mar 29, 2024

CLA assistant check
All committers have signed the CLA.

Copy link

codecov bot commented Mar 29, 2024

Codecov Report

Attention: Patch coverage is 92.85714% with 3 lines in your changes are missing coverage. Please review.

Project coverage is 74.11%. Comparing base (db3973d) to head (8627b5c).
Report is 22 commits behind head on main.

❗ Current head 8627b5c differs from pull request most recent head 68c60ca. Consider uploading reports for the commit 68c60ca to get more accurate results

Files Patch % Lines
...com/linecorp/armeria/client/RedirectingClient.java 92.85% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5548      +/-   ##
============================================
+ Coverage     74.09%   74.11%   +0.02%     
- Complexity    20907    20974      +67     
============================================
  Files          1809     1818       +9     
  Lines         76940    77259     +319     
  Branches       9833     9860      +27     
============================================
+ Hits          57005    57259     +254     
- Misses        15291    15321      +30     
- Partials       4644     4679      +35     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines 274 to 275
// Minus 1 because the original signature is also included.
if (redirectSignatures.size() - 1 > maxRedirects) {
Copy link
Member

Choose a reason for hiding this comment

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

+1 for -1 😆

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

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

We're getting there :-) Nice!

if (redirectUris.size() > maxRedirects) {
final Set<RedirectSignature> redirectSignatures = redirectCtx.redirectSignatures();
// Plus 1 to maxRedirects because the original signature is also included.
if (redirectSignatures.size() > maxRedirects + 1) {
Copy link
Member

Choose a reason for hiding this comment

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

I'd recommend using -1 to avoid potential overflow. Imagine a user specifies Integer.MAX_VALUE for maxRedirects.

Comment on lines 643 to 646
return protocol.equals(that.protocol) &&
authority.equals(that.authority) &&
pathAndQuery.equals(that.pathAndQuery) &&
method == that.method;
Copy link
Member

Choose a reason for hiding this comment

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

How about ordering the comparison in more cost-effective way? For example, we could compare pathAndQuery and authority before others because they are more likely to change, although it may not always be the case.

import com.linecorp.armeria.client.RedirectingClient.RedirectSignature;
import com.linecorp.armeria.common.HttpMethod;

public class RedirectSignatureTest {
Copy link
Member

Choose a reason for hiding this comment

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

public is redundant in JUnit 5.

Suggested change
public class RedirectSignatureTest {
class RedirectSignatureTest {

new RedirectSignature(PROTOCOL, AUTHORITY, PATH_AND_QUERY, METHOD);

@Test
public void equalityWithSameObject() {
Copy link
Member

Choose a reason for hiding this comment

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

public is redundant in JUnit 5 test methods. Could you remove all public keywords where applicable?

@trustin trustin added defect sprint Issues for OSS Sprint participants labels Apr 2, 2024
@trustin trustin added this to the 1.28.0 milestone Apr 3, 2024
Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

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

Comment on lines 571 to 583
if (redirectSignatures == null) {
redirectSignatures = new LinkedHashSet<>();
}

if (!isAddedOriginalSignature) {
final String originalProtocol = ctx.sessionProtocol().isTls() ? "https" : "http";
final RedirectSignature originalSignature = new RedirectSignature(originalProtocol,
ctx.authority(),
request.headers().path(),
request.method());
redirectSignatures.add(originalSignature);
isAddedOriginalSignature = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Question) Could we add originalSignature as redirectSignatures is allocated?
For example:

Suggested change
if (redirectSignatures == null) {
redirectSignatures = new LinkedHashSet<>();
}
if (!isAddedOriginalSignature) {
final String originalProtocol = ctx.sessionProtocol().isTls() ? "https" : "http";
final RedirectSignature originalSignature = new RedirectSignature(originalProtocol,
ctx.authority(),
request.headers().path(),
request.method());
redirectSignatures.add(originalSignature);
isAddedOriginalSignature = true;
}
if (redirectSignatures == null) {
redirectSignatures = new LinkedHashSet<>();
final String originalProtocol = ctx.sessionProtocol().isTls() ? "https" : "http";
final RedirectSignature originalSignature = new RedirectSignature(originalProtocol,
ctx.authority(),
request.headers().path(),
request.method());
redirectSignatures.add(originalSignature);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, I will also remove isAddedOriginalSignature flag.

// Always called after addRedirectUri is called.
assert redirectUris != null;
return redirectUris;
public String uri() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public String uri() {
String uri() {

final boolean isCyclicRedirects =
!redirectCtx.addRedirectSignature(nextReqTarget,
newReqDuplicator.headers().method());
if (isCyclicRedirects) {
handleException(ctx, derivedCtx, reqDuplicator, responseFuture, response,
CyclicRedirectsException.of(redirectCtx.originalUri(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional) What do you think of raising either CyclicRedirectsException or TooManyRedirectsException by addRedirectSignature() which may streamline the code?

Copy link
Contributor Author

@moromin moromin Apr 3, 2024

Choose a reason for hiding this comment

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

I will try it 👍

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

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

Looks good to me 👍 Thanks @moromin ! 🙇 👍 🙇

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Looks great! Thanks a lot! 😄

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

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

Looks solid. Thanks, @moromin! 🙇‍♂️👍

@jrhee17 jrhee17 merged commit 6a1ea7a into line:main Apr 8, 2024
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
defect sprint Issues for OSS Sprint participants
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrect cycle detection logic in RedirectingClient
6 participants