Class: Tep::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/tep/parser.rb

Class Method Summary collapse

Class Method Details

.parse(blob) ⇒ Object

Returns a fully-populated Request, or nil if the blob is malformed.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/tep/parser.rb', line 7

def self.parse(blob)
  # Note: Spinel's String#index returns -1 (not nil) when not found.
  end_of_headers = Tep.str_find(blob, "\r\n\r\n", 0)
  if end_of_headers < 0
    return nil
  end
  headers_blob = blob[0, end_of_headers]
  lines = headers_blob.split("\r\n")
  if lines.length == 0
    return nil
  end

  first = lines[0]
  first_parts = first.split(" ")
  if first_parts.length < 3
    return nil
  end

  req = Request.new
  req.verb         = first_parts[0]
  req.raw_path     = first_parts[1]
  req.http_version = first_parts[2]

  qmark = Tep.str_find(req.raw_path, "?", 0)
  if qmark < 0
    req.path = req.raw_path
  else
    req.path  = req.raw_path[0, qmark]
    qstring   = req.raw_path[qmark + 1, req.raw_path.length - qmark - 1]
    req.query = Url.parse_query(qstring)
  end

  i = 1
  while i < lines.length
    line = lines[i]
    colon = Tep.str_find(line, ":", 0)
    if colon >= 0
      name  = line[0, colon].downcase
      value = line[colon + 1, line.length - colon - 1].strip
      req.req_headers[name] = value
    end
    i += 1
  end

  # Pre-merge query into params; path captures will be folded in
  # by the router on a successful match.
  req.query.each do |k, v|
    req.params[k] = v
  end

  # Parse Cookie header into req.cookies. Format: "k=v; k2=v2; ...".
  # Whitespace around `;` is allowed and stripped.
  cookie_blob = req.req_headers["cookie"]
  if cookie_blob.length > 0
    cookie_blob.split(";").each do |pair|
      eq = Tep.str_find(pair, "=", 0)
      if eq > 0
        cname  = pair[0, eq].strip
        cvalue = pair[eq + 1, pair.length - eq - 1].strip
        req.cookies[cname] = Url.unescape(cvalue)
      end
    end
  end

  # Carry over any body bytes already in the blob (the C helper
  # may have read more than just the headers in one recv()).
  body_start = end_of_headers + 4
  if body_start < blob.length
    req.raw_body = blob[body_start, blob.length - body_start]
  end

  req
end