Class: RackSessionManipulation::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/rack_session_manipulation/middleware.rb

Overview

Rack middleware that handles the accessing and modification of session state.

Instance Attribute Summary collapse

Action Handlers collapse

Standard Middleware Methods collapse

Request Handling Helpers collapse

Constructor Details

#initialize(app, opts = {}) ⇒ Middleware

Setup the middleware with the primary application passed in, anything we can’t handle will be passed to this application.

Parameters:

  • app (Object#call)

    A rack application that implements the #call method.

  • opts (Hash<Symbol=>Object>) (defaults to: {})

    Configuration options for the middleware.



81
82
83
84
85
86
87
88
89
# File 'lib/rack_session_manipulation/middleware.rb', line 81

def initialize(app, opts = {})
  @app = app
  @config = Config.new(opts)
  @routes = {
    'DELETE'  => :reset,
    'GET'     => :retrieve,
    'PUT'     => :update
  }
end

Instance Attribute Details

#appObject (readonly)

The core Rack application running on top of this middleware.

Returns:

  • (Object)

    the current value of app



11
12
13
# File 'lib/rack_session_manipulation/middleware.rb', line 11

def app
  @app
end

#configRackSessionManipulation::Config (readonly)

An instance of the configuration provided to this middleware.

Returns:



11
12
13
# File 'lib/rack_session_manipulation/middleware.rb', line 11

def config
  @config
end

#routesHash<String=>Symbol> (readonly)

Mapping of HTTP methods to local method handler.

Returns:

  • (Hash<String=>Symbol>)

    the current value of routes



11
12
13
# File 'lib/rack_session_manipulation/middleware.rb', line 11

def routes
  @routes
end

Instance Method Details

#call(env) ⇒ Array<Fixnum, Hash, String>

Primary entry point of this middleware. Every request that makes it this far into the stack will be parsed and when it matches something this middleware is designed to handle it will stop the chain and process it appropriately.

Parameters:

  • env (Hash)

    An environment hash containing everything about the client’s request.

Returns:

  • (Array<Fixnum, Hash, String>)

    A generated response to the client’s request.



67
68
69
70
71
72
# File 'lib/rack_session_manipulation/middleware.rb', line 67

def call(env)
  request = Rack::Request.new(env)

  action = get_action(request)
  action.nil? ? app.call(env) : safe_handle(action, request)
end

#extract_method(request) ⇒ String

Look up what HTTP method was used for this request. In the event the client doesn’t support all HTTP methods, the standard ‘_method’ parameter fall back is made available to override the method actually used.

Normally the ‘_method’ fall back is only accepted over the POST method, however, Capybara drivers are only required to implement GET method and so this does not require any particular method to support the override.

When a GET method was used to provide data, a subtle issue can crop up. URLs can’t exceed 1024 characters. Generally this results in them being truncated which in turn will cause a JSON parse error and no changes being made to the session.

Parameters:

  • request (Rack::Request)

    The request to analyze

Returns:

  • (String)

    The decided on HTTP method



109
110
111
112
# File 'lib/rack_session_manipulation/middleware.rb', line 109

def extract_method(request)
  return request.params['_method'].upcase if request.params['_method']
  request.request_method
end

#get_action(request) ⇒ Symbol, Nil

Considers the request and if it matches something this middleware handles return the symbol matching the name of the method that should handle the request.

Parameters:

  • request (Rack::Request)

    The request to assess

Returns:

  • (Symbol, Nil)

    Name of method to use or nil if this middleware should pass the request on to the app.



121
122
123
124
# File 'lib/rack_session_manipulation/middleware.rb', line 121

def get_action(request)
  return unless request.path == config.path
  routes[extract_method(request)]
end

#headers(length) ⇒ Hash

A helper mechanism to consistently generate common headers client will expect.

Parameters:

  • length (Fixnum)

    Byte size of the message body.

Returns:

  • (Hash)

    The common headers



131
132
133
134
135
136
# File 'lib/rack_session_manipulation/middleware.rb', line 131

def headers(length)
  {
    'Content-Length'  => length,
    'Content-Type'    => 'application/json; charset=utf-8'
  }
end

#reset(request) ⇒ Array<Fixnum, Hash, String>

Handle requests to entirely reset the session state.

Parameters:

  • request (Rack::Request)

Returns:

  • (Array<Fixnum, Hash, String>)


20
21
22
23
# File 'lib/rack_session_manipulation/middleware.rb', line 20

def reset(request)
  request.env['rack.session'].clear
  [204, headers(0), '']
end

#retrieve(request) ⇒ Array<Fixnum, Hash, String>

Retrieve the entire contents of the session and properly encode it before returning.

Parameters:

  • request (Rack::Request)

Returns:

  • (Array<Fixnum, Hash, String>)


30
31
32
33
34
35
# File 'lib/rack_session_manipulation/middleware.rb', line 30

def retrieve(request)
  session_hash = request.env['rack.session'].to_hash
  content = config.encoder.encode(session_hash)

  [200, headers(content.length), content]
end

#safe_handle(action, request) ⇒ void

Safely handle the middleware requests so we can properly handle errors in the middleware by returning the correct HTTP status code and message.

Parameters:

  • action (Symbol)

    The local method that will handle the request.

  • request (Rack::Request)

    The request that needs to be processed.



143
144
145
146
147
# File 'lib/rack_session_manipulation/middleware.rb', line 143

def safe_handle(action, request)
  send(action, request)
rescue => e
  [500, headers(e.message.length), e.message]
end

#update(request) ⇒ Array<Fixnum, Hash, String>

Update the current state of the session with the provided data. This works effectively like a hash merge on the current session only setting and overriding keys in the session data provided.

Parameters:

  • request (Rack::Request)

Returns:

  • (Array<Fixnum, Hash, String>)


43
44
45
46
47
48
49
50
51
52
53
# File 'lib/rack_session_manipulation/middleware.rb', line 43

def update(request)
  session_data = request.params['session_data']
  config.encoder.decode(session_data).each do |k, v|
    request.env['rack.session'][k] = v
  end

  loc_hdr = { 'Location' => config.path }
  [303, headers(0).merge(loc_hdr), '']
rescue JSON::ParserError
  [400, headers(0), '']
end