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

Change ForceSSLHandler#secure? to use == instead of regex #1662

Merged
merged 1 commit into from
Feb 10, 2022

Conversation

grepsedawk
Copy link
Contributor

@grepsedawk grepsedawk commented Feb 9, 2022

It's more clear and way faster

Latest benchmark in commit message

@grepsedawk grepsedawk marked this pull request as draft February 9, 2022 03:44
@grepsedawk
Copy link
Contributor Author

Putting this into draft because, while the tests pass, the private method is not exactly the same.
The private method previous was a "#includes?" via regex not ==.

I'm going to run benchmarks and base my next approach based on those benchmarks.

Copy link
Member

@matthewmcgarvey matthewmcgarvey left a comment

Choose a reason for hiding this comment

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

I think it will be fine to do ==. Looking at rails, they delegate to Rack::Request#ssl? which if you look through the code branches does the same thing https://github.com/rack/rack/blob/a61c0b4fe7162df76cee617922c332b9b138d425/lib/rack/request.rb#L366-L368

@grepsedawk grepsedawk marked this pull request as ready for review February 9, 2022 04:00
@grepsedawk
Copy link
Contributor Author

Cool, asserting equality is faster and easier anyway
Rack also doesn't seem to downcase the header ever, it boils down to calling: https://github.com/rack/rack/blob/a61c0b4fe7162df76cee617922c332b9b138d425/lib/rack/request.rb#L79 via https://github.com/rack/rack/blob/a61c0b4fe7162df76cee617922c332b9b138d425/lib/rack/request.rb#L643

Unless @env is auto-downcased.

@@ -48,7 +48,7 @@ class Lucky::ForceSSLHandler
end

private def secure?(context) : Bool
!!(context.request.headers["X-Forwarded-Proto"]? =~ /https/i)
context.request.headers["X-Forwarded-Proto"]?.try &.downcase == "https"
Copy link
Contributor Author

@grepsedawk grepsedawk Feb 9, 2022

Choose a reason for hiding this comment

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

Do we need to downcase this?
It seems like other frameworks don't
I think it's like a 60x increase or so from the original regex if we can drop the case insensitivity altogether

Copy link
Member

Choose a reason for hiding this comment

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

Yep, i believe it's fine to remove the downcase 👍

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

oh wait.. that's just comparing two headers, and not their value... Ignore me, I'm still waking up lol

@robacarp
Copy link
Contributor

robacarp commented Feb 9, 2022

The benchmarks are hard to read because you have both the match and mismatch tests in the same group. Can you separate out the two match runs from the mismatch runs so that the fastest and nn x slower stuff is meaningful?

@robacarp
Copy link
Contributor

robacarp commented Feb 9, 2022

Re downcasing, I know http header names are supposed to be case insensitive but I don't think I know that about the values.

The Rack tests only seem to test that x-forwarded-proto works correctly when it's all lowercase. The internet wisdom about configuring haproxy seems to have decided on using a lowercase https but there's no reason for that to be necessarily true.

I think it's fine to remove the downcase.

It's more clear and 52x faster in majority of scenarios (matches) and
24x faster on redirects (mismatches)

It also does remove case insensitive searching, but it discussion on the
PR luckyframework#1662 stated this should be okay functionality to change

Benchmark:

```crystal
require "benchmark"

puts "Matches"
Benchmark.ips do |x|
  x.report("String ==") do
    "https" == "https"
  end

  x.report("!! String =~ /https/i") do
    !!("https" =~ /https/i)
  end
end

puts "\n\nMismatches"
Benchmark.ips do |x|
  x.report("String == mismatch") do
    "http" == "https"
  end

  x.report("!! String =~ /https/i mismatch") do
    !!("http" =~ /https/i)
  end
end
```

```plaintext
➜  tmp crystal build --release downcase-includes-vs-regex.cr && ./downcase-includes-vs-regex
Matches
            String == 897.53M (  1.11ns) (± 6.76%)   0.0B/op        fastest
!! String =~ /https/i  17.13M ( 58.36ns) (±16.32%)  16.0B/op  52.38× slower

Mismatches
            String == mismatch 881.32M (  1.13ns) (± 8.78%)   0.0B/op        fastest
!! String =~ /https/i mismatch  36.42M ( 27.46ns) (± 1.47%)  16.0B/op  24.20× slower
```
@grepsedawk grepsedawk changed the title Change ForceSSLHandler#secure? to use downcase == instead of regex Change ForceSSLHandler#secure? to use == instead of regex Feb 9, 2022
Copy link
Contributor

@robacarp robacarp left a comment

Choose a reason for hiding this comment

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

awesome 🎉

@matthewmcgarvey matthewmcgarvey merged commit 08da13c into luckyframework:master Feb 10, 2022
@grepsedawk grepsedawk deleted the 34-ns-is-34-ns branch February 10, 2022 06:39
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.

4 participants