class Safrano::Request

Support for OData multipart $batch Requests

monkey patch deactivate Rack/multipart because it does not work on simple OData $batch requests when the content-length is not passed

Constants

DATASERVICEVERSION_RGX

input is the DataServiceVersion request header string, eg. '2.0;blabla' —> Version -> 2

DTSV_PARSE_ERROR
HEADER_PARAM
HEADER_VAL_RAW
HEADER_VAL_WITH_PAR
MAX_DTSV_PARSE_ERROR
MAX_LT_MIN_DTSV_ERROR
MIN_DTSV_PARSE_ERROR
ON_CGST_ERROR

Attributes

content_id[RW]

content_id of request in a $batch changeset

content_id_references[RW]

content-id references map

in_changeset[RW]

request is part of a $batch changeset

service[RW]
service_base[RW]

OData extension

walker[RW]

Public Instance Methods

accept() click to toggle source
# File lib/safrano/request.rb, line 106
def accept
  @env['safrano.accept'] ||= begin
    if @env.include?('HTTP_ACCEPT') && (@env['HTTP_ACCEPT'].to_s != '')
      @env['HTTP_ACCEPT'].to_s.scan(HEADER_VAL_WITH_PAR)
                         .map! { |e| AcceptEntry.new(e) }.sort
    else
      [AcceptEntry.new('*/*')]
    end
  end
end
accept?(type) click to toggle source
# File lib/safrano/request.rb, line 117
def accept?(type)
  preferred_type(type).to_s.include?(type)
end
create_batch_app() click to toggle source
# File lib/odata/batch.rb, line 11
def create_batch_app
  Batch::MyOApp.new(self)
end
create_odata_walker() click to toggle source
# File lib/safrano/request.rb, line 99
def create_odata_walker
  @env['safrano.walker'] = @walker = Walker.new(@service,
                                                path_info,
                                                self,
                                                @content_id_references)
end
get_maxversion() click to toggle source
# File lib/safrano/request.rb, line 173
def get_maxversion
  if (rqv = env['HTTP_MAXDATASERVICEVERSION'])
    if (m = DATASERVICEVERSION_RGX.match(rqv))
      # client request an too old version --> 501
      if (maxv = m[1]) < Safrano::MIN_DATASERVICE_VERSION
        Safrano::VersionNotImplementedError
      else
        Contract.valid(maxv)
      end
    else
      MAX_DTSV_PARSE_ERROR
    end
  else
    # not provided in request header --> take ours
    Safrano::CV_MAX_DATASERVICE_VERSION
  end
end
get_minversion() click to toggle source
# File lib/safrano/request.rb, line 216
def get_minversion
  if (rqv = env['HTTP_MINDATASERVICEVERSION'])
    if (m = DATASERVICEVERSION_RGX.match(rqv))
      # client request an too new version --> 501
      if (minv = m[1]) > Safrano::MAX_DATASERVICE_VERSION
        Safrano::VersionNotImplementedError
      else
        Contract.valid(minv)
      end
    else
      MIN_DTSV_PARSE_ERROR
    end
  else
    # not provided in request header --> take ours
    Safrano::CV_MIN_DATASERVICE_VERSION
  end
end
get_version() click to toggle source
# File lib/safrano/request.rb, line 194
def get_version
  if (rqv = env['HTTP_DATASERVICEVERSION'])
    if (m = DATASERVICEVERSION_RGX.match(rqv))
      # client request an too new version --> 501
      if ((v = m[1]) > Safrano::MAX_DATASERVICE_VERSION) ||
         (v < Safrano::MIN_DATASERVICE_VERSION)
        Safrano::VersionNotImplementedError
      else
        Contract.valid(v)
      end
    else
      DTSV_PARSE_ERROR
    end
  else
    # not provided in request header --> take our maxv
    Safrano::CV_MAX_DATASERVICE_VERSION
  end
end
negotiate_service_version() click to toggle source
# File lib/safrano/request.rb, line 237
def negotiate_service_version
  get_maxversion.if_valid do |maxv|
    get_minversion.if_valid do |minv|
      return MAX_LT_MIN_DTSV_ERROR if minv > maxv

      get_version.if_valid do |v|
        @service = nil
        @service = case maxv
                   when '1'
                     @service_base.v1
                   when '2', '3', '4'
                     @service_base.v2
                   else
                     return Safrano::VersionNotImplementedError
                   end

        Contract::OK
      end # valid get_version
    end # valid get_minversion
  end # valid get_maxversion
end
parse_multipart() click to toggle source
# File lib/odata/batch.rb, line 15
def parse_multipart
  @mimep = MIME::Media::Parser.new
  @boundary = media_type_params['boundary']
  @mimep.hook_multipart(media_type, @boundary)
  @mimep.parse_str(body)
end
parseable_data?() click to toggle source

original coding:

# The set of media-types. Requests that do not indicate
# one of the media types presents in this list will not be eligible
# for param parsing like soap attachments or generic multiparts
PARSEABLE_DATA_MEDIA_TYPES = [
  'multipart/related',
  'multipart/mixed'
]
# Determine whether the request body contains data by checking
# the request media_type against registered parse-data media-types
def parseable_data?
  PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
end
# File lib/safrano/request.rb, line 72
def parseable_data?
  false
end
preferred_type(*types) click to toggle source
# File lib/safrano/request.rb, line 121
def preferred_type(*types)
  accepts = accept # just evaluate once
  return accepts.first if types.empty?

  types.flatten!
  return types.first if accepts.empty?

  accepts.detect do |pattern|
    type = types.detect { |t| File.fnmatch(pattern, t) }
    return type if type
  end
end
register_content_id_ref(new_entity) click to toggle source

stores the newly created entity for the current content-id of the processed request

# File lib/safrano/request.rb, line 92
def register_content_id_ref(new_entity)
  return unless @in_changeset
  return unless @content_id

  @content_id_references[@content_id] = new_entity
end
with_media_data() { |env, split(';').first, decode| ... } click to toggle source
# File lib/safrano/request.rb, line 134
def with_media_data
  if (filename = @env['HTTP_SLUG'])

    yield @env['rack.input'],
           content_type.split(';').first,
           Rfc2047.decode(filename)

  else
    ON_CGST_ERROR.call(self)
    [400, EMPTY_HASH, ['File upload error: Missing SLUG']]
  end
end
with_parsed_data() { |data| ... } click to toggle source
# File lib/safrano/request.rb, line 147
def with_parsed_data
  if content_type == APPJSON
    # Parse json payload
    begin
      data = JSON.parse(body.read)
    rescue JSON::ParserError => e
      ON_CGST_ERROR.call(self)
      return [400, EMPTY_HASH, ['JSON Parser Error while parsing payload : ',
                                e.message]]
    end

    yield data

  else # TODO: other formats

    [415, EMPTY_HASH, EMPTY_ARRAY]
  end
end