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

Added Signed Cookie and optionally used it in Session - Other Speedups #148

Merged
merged 6 commits into from
Jul 28, 2017

Conversation

elorest
Copy link
Member

@elorest elorest commented Jul 25, 2017

Description of the Change

Added Signed Cookies. Small cleanups and speed optimizations while staying true to @eliasjpr vision for cookies and session stores. 😓

  • Added signed cookie.
  • Cleaned up some duplicate code and extra string manipulations.
  • Added logic to only save sessions if they've changed.
  • Added Signed Store with options to choose on configuration: :store => [:signed_cookie, :encrypted_cookie, :redis]
  • Optimized encryption but cutting out a few extra base64 encodes. The encrypted data as still base64 encoded and signed.
  • Changed signature digest to base64 because it's slightly faster and decently smaller than hex. Signature data is the same.
  • Added tests to verify that a signed cookie with an empty signature is ignored.

Alternate Designs

Currently different types of cookie store are passed into session cookie store which then handles everything exactly the same. This could be broken out into a completely new session cookie store but literally every line would be duplicate (NOT DRY). I think this way is a better approach. In the future it would probably be better to configure the Session Pipe with session settings instead of the Server it's self.

Why Should This Be In Core?

Sessions are important. This keeps all of the improvements from @eliasjpr session while bringing the speed really close to what it was with the older session.

Benefits

Here are benchmarks. Index sets cookie and show page reads it. Text rendered is index => "session set" and show => "session works and is good!"

Benchmarks are shown in order of fastest to slowest.

No pipes enabled

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.17ms  382.17us  10.57ms   86.89%
    Req/Sec    23.20k     1.60k   24.96k    91.00%
  692576 requests in 10.00s, 48.88MB read
Requests/sec:  69244.31
Transfer/sec:      4.89MB

Old session without flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000     
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.59ms  465.06us  13.29ms   81.58%
    Req/Sec    13.99k   540.62    14.48k    93.40%
  421581 requests in 10.10s, 89.66MB read
Requests/sec:  41734.71
Transfer/sec:      8.88MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.17ms  514.62us  11.87ms   73.81%
    Req/Sec    23.19k     1.49k   26.63k    79.54%
  698958 requests in 10.10s, 48.66MB read
Requests/sec:  69191.42
Transfer/sec:      4.82MB

Modified New Signed Session without Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000     
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.32ms  459.25us  12.32ms   81.18%
    Req/Sec    15.12k   771.93    15.70k    95.71%
  455917 requests in 10.10s, 85.65MB read
Requests/sec:  45132.26
Transfer/sec:      8.48MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.51ms  670.93us  14.57ms   83.29%
    Req/Sec    20.07k     1.39k   21.61k    84.16%
  604814 requests in 10.10s, 47.30MB read
Requests/sec:  59874.54
Transfer/sec:      4.68MB

Modified New Encrypted Session without Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.75ms  732.86us  25.66ms   77.30%
    Req/Sec    10.60k   635.01    11.04k    96.37%
  319410 requests in 10.10s, 86.21MB read
Requests/sec:  31620.10
Transfer/sec:      8.53MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.51ms  646.00us  12.12ms   85.63%
    Req/Sec    20.01k     1.22k   21.53k    84.16%
  603078 requests in 10.10s, 47.16MB read
Requests/sec:  59701.45
Transfer/sec:      4.67MB

Modified New Signed Session with Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000                                    
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.93ms  780.84us  23.45ms   94.50%
    Req/Sec    10.22k   836.21    10.73k    94.06%
  308100 requests in 10.10s, 81.98MB read
Requests/sec:  30498.25
Transfer/sec:      8.11MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.64ms  621.82us  17.78ms   90.67%
    Req/Sec    10.84k   645.89    11.28k    95.05%
  326780 requests in 10.10s, 71.37MB read
Requests/sec:  32350.65
Transfer/sec:      7.07MB

Old Session and Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/                                      
Running 10s test @ http://localhost:3000/
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.40ms  574.91us  17.05ms   84.96%
    Req/Sec     9.30k   434.86     9.57k    95.00%
  277772 requests in 10.01s, 79.47MB read
Requests/sec:  27759.71
Transfer/sec:      7.94MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.71ms  441.08us  13.87ms   91.34%
    Req/Sec    13.55k   753.14    14.05k    95.05%
  408475 requests in 10.10s, 58.43MB read
Requests/sec:  40432.85
Transfer/sec:      5.78MB

New Encryped Session without Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000     
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.41ms  625.74us  15.71ms   75.30%
    Req/Sec     9.28k   472.10     9.59k    92.74%
  279863 requests in 10.10s, 80.87MB read
Requests/sec:  27702.86
Transfer/sec:      8.01MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.05ms  632.83us  17.57ms   75.18%
    Req/Sec     9.95k   512.93    10.29k    92.74%
  299992 requests in 10.10s, 74.67MB read
Requests/sec:  29696.46
Transfer/sec:      7.39MB

Modified New Encryption Session with Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000     
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.33ms  819.35us  19.85ms   78.24%
    Req/Sec     7.94k   493.60     8.27k    94.00%
  236896 requests in 10.00s, 82.46MB read
Requests/sec:  23680.40
Transfer/sec:      8.24MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.04ms    1.12ms  27.75ms   95.37%
    Req/Sec     8.35k   682.04     8.73k    95.05%
  251888 requests in 10.10s, 74.71MB read
Requests/sec:  24932.52
Transfer/sec:      7.39MB

New Encrypted Session With Flash

~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000
Running 10s test @ http://localhost:3000
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.82ms  664.18us  19.71ms   91.60%
    Req/Sec     6.43k   290.59     6.66k    96.04%
  193639 requests in 10.10s, 82.55MB read
Requests/sec:  19166.78
Transfer/sec:      8.17MB
~/workspace/session_benchmark (master) ᐅ  wrk -t3 -d10 -c150 http://localhost:3000/show
Running 10s test @ http://localhost:3000/show
  3 threads and 150 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.11ms  721.82us  20.40ms   87.18%
    Req/Sec     7.06k   372.87     7.34k    96.70%
  213003 requests in 10.10s, 75.77MB read
Requests/sec:  21084.32
Transfer/sec:      7.50MB

added signed cookie
made session take advantage of signed or encrypted cookies.
only save code on changed? conditional
added comment with store options
@elorest elorest requested a review from drujensen July 25, 2017 17:41
@elorest elorest changed the title WIP - Added Signed Cookie and optionally used it in Session - Other Speedups Added Signed Cookie and optionally used it in Session - Other Speedups Jul 25, 2017
Copy link
Member

@drujensen drujensen 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! only minor cosmetic changes.


# protected getter flash : Amber::Router::Flash::FlashStore?
# protected getter cookies : Amber::Router::Cookies::Store?
# protected getter session : Amber::Router::Session::AbstractStore?
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 Author

Choose a reason for hiding this comment

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

Yeah I should definitely cut that.

raise Exceptions::CookieOverflow.new if cookie.value.bytesize > MAX_COOKIE_SIZE
@store[name] = cookie
end

private def decrypt_and_verify(encrypted_message)
private def verify_and_decrypt(encrypted_message)
String.new(@encryptor.decrypt_and_verify(encrypted_message))
Copy link
Member

Choose a reason for hiding this comment

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

kinda weird that the method is called verify_and_decrypt and then it calls @encryptor.decrypt_and_verify

String.new(@encryptor.decrypt_and_verify(encrypted_message))
rescue e
"{\"value\":\"\"}"
rescue e # TODO: This should probably actually raise the exception instead of rescueing from it.
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 Author

Choose a reason for hiding this comment

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

You think I should remove the TODO?

@@ -24,7 +24,7 @@ module Amber::Router
end

def cookie
Session::CookieStore.new(cookies, session[:key].to_s, session[:expires].to_i, session[:secret].to_s)
Session::CookieStore.new((session[:store] == :encrypted_cookie) ? cookies.encrypted : cookies.signed, session[:key].to_s, session[:expires].to_i, session[:secret].to_s, )
Copy link
Member

Choose a reason for hiding this comment

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

line too long

Copy link
Member Author

Choose a reason for hiding this comment

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

Fair enough.

@@ -25,15 +26,15 @@ module Amber::Controller
end

def cookies
@cookies ||= context.cookies
context.cookies
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
Contributor

@fridgerator fridgerator left a comment

Choose a reason for hiding this comment

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

nice work, looks good to me 👍

@elorest elorest merged commit 84aead1 into master Jul 28, 2017
@eliasjpr eliasjpr mentioned this pull request Jul 28, 2017
2 tasks
@eliasjpr eliasjpr deleted the is/sessionfixup branch July 28, 2017 23:18
@eliasjpr
Copy link
Contributor

issue #141

marksiemers pushed a commit to marksiemers/amber that referenced this pull request Oct 28, 2017
amberframework#148)

* ran a bunch of tests, fixed some issues and cleaned up the code.
added signed cookie
made session take advantage of signed or encrypted cookies.
only save code on changed? conditional
added comment with store options

* added test to prove that cookies with no signature return empty values

* the deep magic before the dawn of time.

* cleaned up store initialization at @drujensen's request

* added delete and mark as changed when it delete
elorest added a commit that referenced this pull request Nov 17, 2017
#148)

* ran a bunch of tests, fixed some issues and cleaned up the code.
added signed cookie
made session take advantage of signed or encrypted cookies.
only save code on changed? conditional
added comment with store options

* added test to prove that cookies with no signature return empty values

* the deep magic before the dawn of time.

* cleaned up store initialization at @drujensen's request

* added delete and mark as changed when it delete
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