Module: Syntropy::RequestInfoClassMethods

Included in:
Request
Defined in:
lib/syntropy/request/request_info.rb

Overview

Request info class methods

Constant Summary collapse

PARAMETER_RE =
/^([^=]+)(?:=(.*))?$/.freeze
MAX_PARAMETER_NAME_SIZE =
256
MAX_PARAMETER_VALUE_SIZE =

1MB

2**20

Instance Method Summary collapse

Instance Method Details

#parse_form_data(body, headers) ⇒ Hash

Parses form data into a hash

Parameters:

  • body (String)
  • headers (Hash)

Returns:

  • (Hash)


249
250
251
252
253
254
255
256
257
258
259
# File 'lib/syntropy/request/request_info.rb', line 249

def parse_form_data(body, headers)
  case (content_type = headers['content-type'])
  when /^multipart\/form\-data; boundary=([^\s]+)/
    boundary = "--#{Regexp.last_match(1)}"
    parse_multipart_form_data(body, boundary)
  when /^application\/x-www-form-urlencoded/
    parse_urlencoded_form_data(body)
  else
    raise BadRequestError, "Unsupported form data content type: #{content_type}"
  end
end

#parse_multipart_form_data(body, boundary) ⇒ Hash

Parses a multipart form body.

Parameters:

  • body (String)
  • boundary (String)

Returns:

  • (Hash)

Raises:



266
267
268
269
270
271
272
273
274
275
276
# File 'lib/syntropy/request/request_info.rb', line 266

def parse_multipart_form_data(body, boundary)
  parts = body.split(boundary)
  raise BadRequestError, 'Invalid form data' if parts.size < 2
  parts.each_with_object({}) do |p, h|
    next if p.empty? || p == "--\r\n"

    # remove post-boundary \r\n
    p.slice!(0, 2)
    parse_multipart_form_data_part(p, h)
  end
end

#parse_multipart_form_data_part(part, hash) ⇒ void

This method returns an undefined value.

Parses a multipart form data part.

Parameters:

  • body (String)
  • hash (Hash)

    output hash



283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/syntropy/request/request_info.rb', line 283

def parse_multipart_form_data_part(part, hash)
  body, headers = parse_multipart_form_data_part_headers(part)
  disposition = headers['content-disposition'] || ''

  name = (disposition =~ /name="([^"]+)"/) ? Regexp.last_match(1) : nil
  filename = (disposition =~ /filename="([^"]+)"/) ? Regexp.last_match(1) : nil

  if filename
    hash[name] = { filename: filename, content_type: headers['content-type'], data: body }
  else
    hash[name] = body
  end
end

#parse_multipart_form_data_part_headers(part) ⇒ Hash

Parses a multipart form data part headers.

Parameters:

  • part (String)

Returns:

  • (Hash)


301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/syntropy/request/request_info.rb', line 301

def parse_multipart_form_data_part_headers(part)
  headers = {}
  while true
    idx = part.index("\r\n")
    break unless idx

    header = part[0, idx]
    part.slice!(0, idx + 2)
    break if header.empty?

    next unless header =~ /^([^\:]+)\:\s?(.+)$/

    headers[Regexp.last_match(1).downcase] = Regexp.last_match(2)
  end
  # remove trailing \r\n
  part.slice!(part.size - 2, 2)
  [part, headers]
end

#parse_urlencoded_form_data(body) ⇒ Hash

Parses a URL-encoded form.

Parameters:

  • body (String)

Returns:

  • (Hash)


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/syntropy/request/request_info.rb', line 328

def parse_urlencoded_form_data(body)
  return {} unless body

  body.force_encoding(Encoding::UTF_8) unless body.encoding == Encoding::UTF_8
  body.split('&').each_with_object({}) do |i, m|
    raise BadRequestError, 'Invalid parameter format' unless i =~ PARAMETER_RE

    k = Regexp.last_match(1)
    raise BadRequestError, 'Invalid parameter size' if k.size > MAX_PARAMETER_NAME_SIZE

    v = Regexp.last_match(2)
    raise BadRequestError, 'Invalid parameter size' if v && v.size > MAX_PARAMETER_VALUE_SIZE

    m[URI.decode_www_form_component(k)] = v ? URI.decode_www_form_component(v) : true
  end
end