module Webmachine::Decision::Flow

This module encapsulates all of the decisions in Webmachine’s flow-chart. These invoke {Webmachine::Resource::Callbacks} methods to determine the appropriate response code, headers, and body for the response.

This module is included into {FSM}, which drives the processing of the chart. @see

Constants

CONTENT
START

The first state in flow diagram

VERSION

Version of the flow diagram

Public Instance Methods

b10() click to toggle source

Method allowed?

# File lib/webmachine/decision/flow.rb, line 63
def b10
  if resource.allowed_methods.include?(request.method)
    :b9
  else
    response.headers['Allow'] = resource.allowed_methods.join(', ')
    405
  end
end
b11() click to toggle source

URI too long?

# File lib/webmachine/decision/flow.rb, line 58
def b11
  decision_test(resource.uri_too_long?(request.uri), 414, :b10)
end
b12() click to toggle source

Known method?

# File lib/webmachine/decision/flow.rb, line 53
def b12
  decision_test(resource.known_methods.include?(request.method), :b11, 501)
end
b13() click to toggle source

Service available?

# File lib/webmachine/decision/flow.rb, line 48
def b13
  decision_test(resource.service_available?, :b12, 503)
end
b3() click to toggle source

OPTIONS?

# File lib/webmachine/decision/flow.rb, line 140
def b3
  if request.options?
    response.headers.merge!(resource.options)
    200
  else
    :c3
  end
end
b4() click to toggle source

Req Entity Too Large?

# File lib/webmachine/decision/flow.rb, line 135
def b4
  decision_test(resource.valid_entity_length?(request.content_length), :b3, 413)
end
b5() click to toggle source

Known Content-Type?

# File lib/webmachine/decision/flow.rb, line 130
def b5
  decision_test(resource.known_content_type?(request.content_type), :b4, 415)
end
b6() click to toggle source

Okay Content-* Headers?

# File lib/webmachine/decision/flow.rb, line 125
def b6
  decision_test(resource.valid_content_headers?(request.headers.grep(CONTENT)), :b5, 501)
end
b7() click to toggle source

Forbidden?

# File lib/webmachine/decision/flow.rb, line 119
def b7
  decision_test(resource.forbidden?, 403, :b6)
end
b8() click to toggle source

Authorized?

# File lib/webmachine/decision/flow.rb, line 103
def b8
  result = resource.is_authorized?(request.authorization)
  case result
  when true
    :b7
  when Integer
    result
  when String
    response.headers['WWW-Authenticate'] = result
    401
  else
    401
  end
end
b9() click to toggle source

Content-MD5 present?

# File lib/webmachine/decision/flow.rb, line 73
def b9
  request.content_md5 ? :b9a : :b9b
end
b9a() click to toggle source

Content-MD5 valid?

# File lib/webmachine/decision/flow.rb, line 78
def b9a
  case valid = resource.validate_content_checksum
  when Integer
    valid
  when true
    :b9b
  when false
    response.body = 'Content-MD5 header does not match request body.'
    400
  else # not_validated
    if decode64(request.content_md5) == Digest::MD5.hexdigest(request.body)
      :b9b
    else
      response.body = 'Content-MD5 header does not match request body.'
      400
    end
  end
end
b9b() click to toggle source

Malformed?

# File lib/webmachine/decision/flow.rb, line 98
def b9b
  decision_test(resource.malformed_request?, 400, :b8)
end
c3() click to toggle source

Accept exists?

# File lib/webmachine/decision/flow.rb, line 150
def c3
  if !request.accept
    metadata[CONTENT_TYPE] = MediaType.parse(resource.content_types_provided.first.first)
    :d4
  else
    :c4
  end
end
c4() click to toggle source

Acceptable media type available?

# File lib/webmachine/decision/flow.rb, line 160
def c4
  types = resource.content_types_provided.map { |pair| pair.first }
  chosen_type = choose_media_type(types, request.accept)
  if !chosen_type
    406
  else
    metadata[CONTENT_TYPE] = chosen_type
    :d4
  end
end
d4() click to toggle source

Accept-Language exists?

# File lib/webmachine/decision/flow.rb, line 172
def d4
  if !request.accept_language
    if language = choose_language(resource.languages_provided, STAR)
      resource.language_chosen(language)
      :e5
    else
      406
    end
  else
    :d5
  end
end
d5() click to toggle source

Acceptable language available?

# File lib/webmachine/decision/flow.rb, line 186
def d5
  if language = choose_language(resource.languages_provided, request.accept_language)
    resource.language_chosen(language)
    :e5
  else
    406
  end
end
decision_test(test, iftrue, iffalse) click to toggle source

Handles standard decisions where halting is allowed

# File lib/webmachine/decision/flow.rb, line 36
def decision_test(test, iftrue, iffalse)
  case test
  when Integer # Allows callbacks to "halt" with a given response code
    test
  when Falsey
    iffalse
  else
    iftrue
  end
end
e5() click to toggle source

Accept-Charset exists?

# File lib/webmachine/decision/flow.rb, line 196
def e5
  if !request.accept_charset
    choose_charset(resource.charsets_provided, STAR) ? :f6 : 406
  else
    :e6
  end
end
e6() click to toggle source

Acceptable Charset available?

# File lib/webmachine/decision/flow.rb, line 205
def e6
  choose_charset(resource.charsets_provided, request.accept_charset) ? :f6 : 406
end
f6() click to toggle source

Accept-Encoding exists? (also, set content-type header here, now that charset is chosen)

# File lib/webmachine/decision/flow.rb, line 211
def f6
  chosen_type = metadata[CONTENT_TYPE]
  if chosen_charset = metadata[CHARSET]
    chosen_type.params['charset'] = chosen_charset
  end
  response.headers[CONTENT_TYPE] = chosen_type.to_s
  if !request.accept_encoding
    choose_encoding(resource.encodings_provided, 'identity;q=1.0,*;q=0.5') ? :g7 : 406
  else
    :f7
  end
end
f7() click to toggle source

Acceptable encoding available?

# File lib/webmachine/decision/flow.rb, line 225
def f7
  choose_encoding(resource.encodings_provided, request.accept_encoding) ? :g7 : 406
end
g11() click to toggle source

ETag in If-Match

# File lib/webmachine/decision/flow.rb, line 247
def g11
  request_etags = request.if_match.split(SPLIT_COMMA).map { |etag| ETag.new(etag) }
  request_etags.include?(ETag.new(resource.generate_etag)) ? :h10 : 412
end
g7() click to toggle source

Resource exists?

# File lib/webmachine/decision/flow.rb, line 230
def g7
  # This is the first place after all conneg, so set Vary here
  response.headers['Vary'] = variances.join(', ') if variances.any?
  decision_test(resource.resource_exists?, :g8, :h7)
end
g8() click to toggle source

If-Match exists?

# File lib/webmachine/decision/flow.rb, line 237
def g8
  request.if_match ? :g9 : :h10
end
g9() click to toggle source

If-Match: * exists?

# File lib/webmachine/decision/flow.rb, line 242
def g9
  (quote(request.if_match) == '"*"') ? :h10 : :g11
end
h10() click to toggle source

If-Unmodified-Since exists?

# File lib/webmachine/decision/flow.rb, line 258
def h10
  request.if_unmodified_since ? :h11 : :i12
end
h11() click to toggle source

If-Unmodified-Since is valid date?

# File lib/webmachine/decision/flow.rb, line 263
def h11
  date = Time.httpdate(request.if_unmodified_since)
  metadata['If-Unmodified-Since'] = date
rescue ArgumentError
  :i12
else
  :h12
end
h12() click to toggle source

Last-Modified > I-UM-S?

# File lib/webmachine/decision/flow.rb, line 273
def h12
  (resource.last_modified > metadata['If-Unmodified-Since']) ? 412 : :i12
end
h7() click to toggle source

If-Match exists?

# File lib/webmachine/decision/flow.rb, line 253
def h7
  (request.if_match && unquote(request.if_match) == STAR) ? 412 : :i7
end
i12() click to toggle source

If-none-match exists?

# File lib/webmachine/decision/flow.rb, line 296
def i12
  request.if_none_match ? :i13 : :l13
end
i13() click to toggle source

If-none-match: * exists?

# File lib/webmachine/decision/flow.rb, line 301
def i13
  (quote(request.if_none_match) == '"*"') ? :j18 : :k13
end
i4() click to toggle source

Moved permanently? (apply PUT to different URI)

# File lib/webmachine/decision/flow.rb, line 278
def i4
  case uri = resource.moved_permanently?
  when String, URI
    response.headers[LOCATION] = uri.to_s
    301
  when Integer
    uri
  else
    :p3
  end
end
i7() click to toggle source

PUT?

# File lib/webmachine/decision/flow.rb, line 291
def i7
  request.put? ? :i4 : :k7
end
j18() click to toggle source

GET or HEAD?

# File lib/webmachine/decision/flow.rb, line 306
def j18
  (request.get? || request.head?) ? 304 : 412
end
k13() click to toggle source

Etag in if-none-match?

# File lib/webmachine/decision/flow.rb, line 329
def k13
  request_etags = request.if_none_match.split(SPLIT_COMMA).map { |etag| ETag.new(etag) }
  resource_etag = resource.generate_etag
  if resource_etag && request_etags.include?(ETag.new(resource_etag))
    :j18
  else
    :l13
  end
end
k5() click to toggle source

Moved permanently?

# File lib/webmachine/decision/flow.rb, line 311
def k5
  case uri = resource.moved_permanently?
  when String, URI
    response.headers[LOCATION] = uri.to_s
    301
  when Integer
    uri
  else
    :l5
  end
end
k7() click to toggle source

Previously existed?

# File lib/webmachine/decision/flow.rb, line 324
def k7
  decision_test(resource.previously_existed?, :k5, :l7)
end
l13() click to toggle source

If-Modified-Since exists?

# File lib/webmachine/decision/flow.rb, line 358
def l13
  request.if_modified_since ? :l14 : :m16
end
l14() click to toggle source

IMS is valid date?

# File lib/webmachine/decision/flow.rb, line 363
def l14
  date = Time.httpdate(request.if_modified_since)
  metadata['If-Modified-Since'] = date
rescue ArgumentError
  :m16
else
  :l15
end
l15() click to toggle source

IMS > Now?

# File lib/webmachine/decision/flow.rb, line 373
def l15
  (metadata['If-Modified-Since'] > Time.now) ? :m16 : :l17
end
l17() click to toggle source

Last-Modified > IMS?

# File lib/webmachine/decision/flow.rb, line 378
def l17
  (resource.last_modified.nil? || resource.last_modified > metadata['If-Modified-Since']) ? :m16 : 304
end
l5() click to toggle source

Moved temporarily?

# File lib/webmachine/decision/flow.rb, line 340
def l5
  case uri = resource.moved_temporarily?
  when String, URI
    response.headers[LOCATION] = uri.to_s
    307
  when Integer
    uri
  else
    :m5
  end
end
l7() click to toggle source

POST?

# File lib/webmachine/decision/flow.rb, line 353
def l7
  request.post? ? :m7 : 404
end
m16() click to toggle source

DELETE?

# File lib/webmachine/decision/flow.rb, line 393
def m16
  request.delete? ? :m20 : :n16
end
m20() click to toggle source

DELETE enacted immediately? (Also where DELETE is forced.)

# File lib/webmachine/decision/flow.rb, line 398
def m20
  decision_test(resource.delete_resource, :m20b, 500)
end
m20b() click to toggle source

Did the DELETE complete?

# File lib/webmachine/decision/flow.rb, line 403
def m20b
  decision_test(resource.delete_completed?, :o20, 202)
end
m5() click to toggle source

POST?

# File lib/webmachine/decision/flow.rb, line 383
def m5
  request.post? ? :n5 : 410
end
m7() click to toggle source

Server allows POST to missing resource?

# File lib/webmachine/decision/flow.rb, line 388
def m7
  decision_test(resource.allow_missing_post?, :n11, 404)
end
n11() click to toggle source

Redirect?

# File lib/webmachine/decision/flow.rb, line 413
def n11
  # Stage1
  if resource.post_is_create?
    case uri = resource.create_path
    when nil
      raise InvalidResource, t('create_path_nil', class: resource.class)
    when URI, String
      base_uri = resource.base_uri || request.base_uri
      new_uri = URI.join(base_uri.to_s, uri)
      request.disp_path = new_uri.path
      response.headers[LOCATION] = new_uri.to_s
      result = accept_helper
      return result if Integer === result
    end
  else
    case result = resource.process_post
    when true
      encode_body_if_set
    when Integer
      return result
    else
      raise InvalidResource, t('process_post_invalid', result: result.inspect)
    end
  end
  if response.is_redirect?
    if response.headers[LOCATION]
      303
    else
      raise InvalidResource, t('do_redirect')
    end
  else
    :p11
  end
end
n16() click to toggle source

POST?

# File lib/webmachine/decision/flow.rb, line 449
def n16
  request.post? ? :n11 : :o16
end
n5() click to toggle source

Server allows POST to missing resource?

# File lib/webmachine/decision/flow.rb, line 408
def n5
  decision_test(resource.allow_missing_post?, :n11, 410)
end
o14() click to toggle source

Conflict?

# File lib/webmachine/decision/flow.rb, line 454
def o14
  if resource.is_conflict?
    409
  else
    res = accept_helper
    (Integer === res) ? res : :p11
  end
end
o16() click to toggle source

PUT?

# File lib/webmachine/decision/flow.rb, line 464
def o16
  request.put? ? :o14 : :o18
end
o18() click to toggle source

Multiple representations? Also where body generation for GET and HEAD is done.

# File lib/webmachine/decision/flow.rb, line 470
def o18
  if request.get? || request.head?
    add_caching_headers
    content_type = metadata[CONTENT_TYPE]
    handler = resource.content_types_provided.find { |ct, _| content_type.type_matches?(MediaType.parse(ct)) }.last
    result = resource.send(handler)
    if Integer === result
      result
    else
      response.body = result
      encode_body
      :o18b
    end
  else
    :o18b
  end
end
o18b() click to toggle source

Multiple choices?

# File lib/webmachine/decision/flow.rb, line 489
def o18b
  decision_test(resource.multiple_choices?, 300, 200)
end
o20() click to toggle source

Response includes an entity?

# File lib/webmachine/decision/flow.rb, line 494
def o20
  has_response_body? ? :o18 : 204
end
p11() click to toggle source

New resource?

# File lib/webmachine/decision/flow.rb, line 509
def p11
  (!response.headers[LOCATION]) ? :o20 : 201
end
p3() click to toggle source

Conflict?

# File lib/webmachine/decision/flow.rb, line 499
def p3
  if resource.is_conflict?
    409
  else
    res = accept_helper
    (Integer === res) ? res : :p11
  end
end