Class: Rackful::Request

Inherits:
Rack::Request
  • Object
show all
Defined in:
gems/rackful-0.1.1/lib/rackful_request.rb,
gems/rackful-0.1.1.orig/lib/rackful_request.rb

Overview

Subclass of Rack::Request, augmented for Rackful requests.

Since:

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Request) initialize(resource_factory, *args)

A new instance of Request

Since:

  • 0.0.1



50
51
52
53
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 50

def initialize resource_factory, *args
  super( *args )
  self.env['rackful.resource_factory'] = resource_factory
end

Class Method Details

+ (Request) current

The request currently being processed in the current thread.

In a multi-threaded server, multiple requests can be handled at one time. This method returns the request object, created (and registered) by Server#call!

Returns:

Since:

  • 0.0.1



65
66
67
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 65

def self.current
  Thread.current[:rackful_request]
end

Instance Method Details

- (Hash{media_type => quality}) accept

Hash of acceptable media types and their qualities.

This method parses the HTTP/1.1 `Accept:` header. If no acceptable media types are provided, an empty Hash is returned.

Returns:

  • (Hash{media_type => quality})

Since:

  • 0.0.1



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 150

def accept
  @env['rackful.accept'] ||= begin
    Hash[
      @env['HTTP_ACCEPT'].to_s.split(',').collect do
        |entry|
        type, *options = entry.delete(' ').split(';')
        quality = 1
        options.each { |e|
          quality = e[2..-1].to_f if e.start_with? 'q='
        }
        [type, quality]
      end
    ]
  rescue
    {}
  end
end

- assert_if_headers(resource)

TODO:

Implement support for the `If-Range:` header.

This method returns an undefined value.

Assert all If-* request headers.

Raises:

See Also:

Since:

  • 0.0.1



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 87

def assert_if_headers resource
  #raise HTTP501NotImplemented, 'If-Range: request header is not supported.' \
  #  if @env.key? 'HTTP_IF_RANGE'
  empty = resource.empty?
  etag =
    if ! empty && resource.respond_to?(:get_etag)
      resource.get_etag
    else
      nil
    end
  last_modified =
    if ! empty && resource.respond_to?(:get_last_modified)
      resource.get_last_modified
    else
      nil
    end
  cond = {
    :match => self.if_match,
    :none_match => self.if_none_match,
    :modified_since => self.if_modified_since,
    :unmodified_since => self.if_unmodified_since
  }
  allow_weak = ['GET', 'HEAD'].include? self.request_method
  if empty
    if cond[:match]
      raise HTTP412PreconditionFailed, 'If-Match'
    elsif cond[:unmodified_since]
      raise HTTP412PreconditionFailed, 'If-Unmodified-Since'
    elsif cond[:modified_since]
      raise HTTP404NotFound
    end
  else
    if cond[:none_match] && self.validate_etag( etag, cond[:none_match] )
      raise HTTP412PreconditionFailed, 'If-None-Match'
    elsif cond[:match] && ! self.validate_etag( etag, cond[:match] )
      raise HTTP412PreconditionFailed, 'If-Match'
    elsif cond[:unmodified_since]
      if ! last_modified || cond[:unmodified_since] < last_modified[0]
        raise HTTP412PreconditionFailed, 'If-Unmodified-Since'
      elsif last_modified && ! last_modified[1] && ! allow_weak &&
            cond[:unmodified_since] == last_modified[0]
        raise HTTP412PreconditionFailed, 'If-Unmodified-Since'
      end
    elsif cond[:modified_since]
      if ! last_modified || cond[:modified_since] >= last_modified[0]
        raise HTTP304NotModified
      elsif last_modified && ! last_modified[1] && !allow_weak &&
            cond[:modified_since] == last_modified[0]
        raise HTTP412PreconditionFailed, 'If-Modified-Since'
      end
    end
  end
end

- (void) base_path

Since:

  • 0.0.1



23
24
25
26
27
28
29
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 23

def base_path
  self.env['rackful.base_path'] ||= begin
    r = self.content_path.dup
    r[%r{[^/]*\z}] = ''
    r
  end
end

- (Path) content_path

Similar to the HTTP/1.1 `Content-Location:` header. Contains the canonical path to the requested resource, which may differ from #path

Returns:

Since:

  • 0.1.0



36
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 36

def content_path; self.env['rackful.content_path'] ||= self.path; end

- (Path) content_path=(bp)

Set by Server#call!

Returns:

Since:

  • 0.1.0



42
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 42

def content_path= bp; self.env['rackful.content_path'] = bp.to_path; end

- (nil, Array<String>) if_match

Parses the HTTP/1.1 `If-Match:` header.

Returns:

Raises:

See Also:

Since:

  • 0.0.1



177
178
179
180
181
182
183
184
185
186
187
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 177

def if_match none = false
  header = @env["HTTP_IF_#{ none ? 'NONE_' : '' }MATCH"]
  return nil unless header
  envkey = "rackful.if_#{ none ? 'none_' : '' }match"
  if %r{\A\s*\*\s*\z} === header
    return [ '*' ]
  elsif %r{\A(\s*(W/)?"([^"\\]|\\.)*"\s*,)+\z}m === ( header + ',' )
    return header.scan( %r{(?:W/)?"(?:[^"\\]|\\.)*"}m )
  end
  raise HTTP400BadRequest, "Couldn't parse If-#{ none ? 'None-' : '' }Match: #{header}"
end

- (nil, Time) if_modified_since

Returns:

  • (nil, Time)

See Also:

Since:

  • 0.0.1



209
210
211
212
213
214
215
216
217
218
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 209

def if_modified_since unmodified = false
  header = @env["HTTP_IF_#{ unmodified ? 'UN' : '' }MODIFIED_SINCE"]
  return nil unless header
  begin
    header = Time.httpdate( header )
  rescue ArgumentError
    raise HTTP400BadRequest, "Couldn't parse If-#{ unmodified ? 'Unmodified' : 'Modified' }-Since: #{header}"
  end
  header
end

- (nil, Array<String>) if_none_match

Parses the HTTP/1.1 `If-None-Match:` header.

Returns:

See Also:

Since:

  • 0.0.1



197
198
199
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 197

def if_none_match
  self.if_match true
end

- (nil, Time) if_unmodified_since

Returns:

  • (nil, Time)

See Also:

Since:

  • 0.0.1



227
228
229
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 227

def if_unmodified_since
  self.if_modified_since true
end

- (Path) path

Returns:

Since:

  • 0.1.0



47
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 47

def path; super.to_path; end

- (#[]) resource_factory

The resource factory for the current request.

Returns:

  • (#[])

See Also:

Since:

  • 0.0.1



22
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 22

def resource_factory; self.env['rackful.resource_factory']; end

- (Boolean) validate_etag(etag, etags)

Does any of the tags in `etags` match `etag`?

Examples:

etag = '"foo"'
etags = [ 'W/"foo"', '"bar"' ]
validate_etag etag, etags
#> true

Parameters:

  • etag (#to_s)
  • etags (#to_a)

Returns:

  • (Boolean)

See Also:

Since:

  • 0.0.1



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'gems/rackful-0.1.1/lib/rackful_request.rb', line 246

def validate_etag etag, etags
  etag = etag.to_s
  match = etags.to_a.detect do
    |tag|
    tag = tag.to_s
    tag == '*' or
    tag == etag or
    'W/' +  tag == etag or
    'W/' + etag ==  tag
  end
  if  match and
      '*' != match and
      'W/' == etag[0,2] || 'W/' == match[0,2] and
      ! [ 'HEAD', 'GET' ].include? self.request_method
    raise HTTP400BadRequest, "Weak validators are only allowed for GET and HEAD requests."
  end
  !!match
end