diff options
| author | Gibheer <gibheer@gmail.com> | 2013-10-28 14:37:24 +0100 | 
|---|---|---|
| committer | Gibheer <gibheer@gmail.com> | 2013-10-28 14:37:24 +0100 | 
| commit | a0422c10546b2e0dea252e68d1870f362095cdab (patch) | |
| tree | 1574d6466c5b0895911bfb3055cea88d02a5d670 /lib | |
| parent | 290165c440caceb53fd12ad6aa460069852a26ec (diff) | |
add cookie support to response
This commit adds support for response cookies. Response now has a method
cookie to fetch the current cookie. One cookie has multiple crumbs which
represent a key value pair. For each crumb multiple options can be set
according to the specs.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/zero/response.rb | 26 | ||||
| -rw-r--r-- | lib/zero/response/cookie.rb | 105 | 
2 files changed, 125 insertions, 6 deletions
| diff --git a/lib/zero/response.rb b/lib/zero/response.rb index ab4acde..cb58cfe 100644 --- a/lib/zero/response.rb +++ b/lib/zero/response.rb @@ -1,3 +1,5 @@ +require 'zero/response/cookie' +  module Zero    # This is the representation of a response    class Response @@ -10,18 +12,17 @@ module Zero      # Constructor      # Sets default status code to 200. -    #      def initialize        @status = 200        @header = {}        @body   = [] +      @cookies = {}      end      # Sets the status.      # Also converts every input directly to an integer.      #      # @param [Integer] status The status code -    #      def status=(status)        @status = status.to_i      end @@ -53,8 +54,8 @@ module Zero      # Removes Content-Type, Content-Length and body on status code 204 and 304.      #      # @return [Array] Usable by webservers -    #      def to_a +      add_cookie_headers        # Remove content length and body, on status 204 and 304        if status == 204 or status == 304          header.delete('Content-Length') @@ -72,7 +73,6 @@ module Zero      # Sets the content length header to the current length of the body      # Also creates one, if it does not exists -    #      def content_length        self.header['Content-Length'] = body.join.bytesize.to_s      end @@ -81,7 +81,6 @@ module Zero      # Also creates it, if it does not exists      #      # @param [String] value Content-Type tp set -    #      def content_type=(value)        self.header['Content-Type'] = value      end @@ -89,10 +88,25 @@ module Zero      # Sets the Location header to the given URL and the status code to 302.      #       # @param [String] location Redirect URL -    #      def redirect(location, status = 302)        self.status = status        self.header['Location'] = location      end + +    # get the cookie for the response +    # +    # This returns the cookie holding all crumbs for the response. +    # @response [Cookie] the cookie with crumbs holding the information +    def cookie +      @cookie ||= Cookie.new +    end + +    private + +    # merge the cookie header into the other headers +    def add_cookie_headers +      return unless @cookie +      header.merge!(cookie.to_header) +    end    end  end diff --git a/lib/zero/response/cookie.rb b/lib/zero/response/cookie.rb new file mode 100644 index 0000000..45ef65f --- /dev/null +++ b/lib/zero/response/cookie.rb @@ -0,0 +1,105 @@ +module Zero +  class Response +    class Cookie +      # initialize an empty cookie +      def initialize +        @crumbs = {} +      end + +      # add a new crumb +      # +      # This adds a new crumb to the cookie specified through the key. +      # @param key [String] the identifier for the crumb +      # @param value [String] the value for the crumb +      # @param options [Hash] hash with further options for the crumb +      # @option options [Time]   :expire the time when the crumb should expire +      # @option options [String] :domain the domain the crumb should be sent to +      # @option options [String] :path   path when the crumb should be sent +      # @option options [Array]  :flags set flags for :secure or :http_only +      def add_crumb(key, value, options = {:flags => []}) +        @crumbs[key] = Crumb.new(key, value, options) +      end + +      # get the crumb for the key +      # +      # This method returns the crumb for the specified key. The crumb holds all +      # information, like the expire time and domain and so on. +      # @param key [String] the key to return +      # @returns [Cookie::Crumb] a cookie crumb or nil when the key +      #                             does not exist +      def get_crumb(key) +        @crumbs[key] +      end + +      # merge all crumbs to one header line +      # +      # This merges all crumbs together to a header line, where each cookie is +      # separated by the `Set-Cookie` header. +      # @returns [Hash] a key value pair to merge with the headers +      def to_header +        {'Set-Cookie' => @crumbs.map{|key, crumb| crumb}.join("\nSet-Cookie: ")} +      end +       +      private + +      class Crumb +        attr_reader :key, :secure, :http_only +        attr_accessor :domain, :path, :expire, :value + +        def initialize(key, value, options = {}) +          options[:flags] ||= [] +          @key       = key +          @value     = value +          @domain    = options[:domain] +          @expire    = options[:expire] +          @path      = options[:path] +          @secure    = options[:flags].include?(:secure) +          @http_only = options[:flags].include?(:http_only) +        end + +        # set the `http_only` flag +        # +        # This method sets the flag to only allow modifications from the +        # server and makes the browser not allow modifications through +        # javascript. +        def deny_client_side_modification! +          @http_only = true +        end + +        # remove the `http_only` flag +        # +        # This removes the `http_only` flag to allow modifications of the +        # crumb through javascript. +        def allow_client_side_modification! +          @http_only = false +        end + +        # set the `secure` flag +        # +        # This sets the `secure` flag on the crumb which tells the browser to +        # only send it through secure channels, like https. +        # Keep in mind, that this does not encrypt the content of the Crumb! +        def secure! +          @secure = true +        end + +        # unset the `secure` flag +        # +        # This unsets the `secure` flag which tells the browser, that it can +        # send the crumb over unsecure channel too, like plain http. +        def unsecure! +          @secure = false +        end + +        def to_s +          "#{@key}=#{@value}" + +            (@expire ? "; Expires=#{@expire.rfc2822}" : '') + +            (@path   ? "; Path=#{@path}" : '') + +            (@domain ? "; Domain=#{domain}" : '') + +            (@http_only ? '; HttpOnly' : '') + +            (@secure    ? '; Secure' : '') +        end +      end +    end +  end +end | 
