Module: Restless::Har
- Defined in:
- lib/restless/har.rb
Overview
CONTRACT.md section 7. Captured traffic rides inside a HAR 1.2 envelope.
Class Method Summary collapse
- .headers_to_list(headers) ⇒ Object
-
.parse_query_string(url) ⇒ Object
HAR-005.
-
.to_har_entry(captured) ⇒ Object
capturedis a hash with string keys: requestId, startedAt, duration, routePattern?, request: url, headers, body?, response: headers, body?.
Class Method Details
.headers_to_list(headers) ⇒ Object
43 44 45 |
# File 'lib/restless/har.rb', line 43 def headers_to_list(headers) headers.map { |name, value| { "name" => name, "value" => value } } end |
.parse_query_string(url) ⇒ Object
HAR-005. Parse the query into ordered name/value pairs.
Hand-rolled rather than delegating to a URI library so it shares the
exact decoding rule with redact_url, and so a port does not have to
reproduce WHATWG URL parsing to agree with us. Duplicate names are
preserved, which a hash-based parse would lose.
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 |
# File 'lib/restless/har.rb', line 17 def parse_query_string(url) q = url.index("?") return [] if q.nil? rest = url[(q + 1)..-1] || "" hash = rest.index("#") query = hash.nil? ? rest : rest[0, hash] return [] if query.empty? out = [] query.split("&", -1).each do |pair| next if pair.empty? eq = pair.index("=") if eq.nil? out << { "name" => Redact.percent_decode(pair), "value" => "" } else out << { "name" => Redact.percent_decode(pair[0, eq]), "value" => Redact.percent_decode(pair[(eq + 1)..-1] || "") } end end out end |
.to_har_entry(captured) ⇒ Object
captured is a hash with string keys:
requestId, startedAt, duration, routePattern?,
request: {method, url, headers, body?}, response: {status, headers, body?}
A nil body means "no body captured" and is distinct from an empty one: HAR-011 makes the first report -1 and the second 0.
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 80 81 82 83 84 85 86 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 |
# File 'lib/restless/har.rb', line 53 def to_har_entry(captured) request = captured["request"] || {} response = captured["response"] || {} request_headers = request["headers"] || {} response_headers = response["headers"] || {} request_body = request["body"] response_body = response["body"] req_content_type = request_headers["content-type"] req_content_type = "" if req_content_type.nil? || req_content_type == "" # HAR-007: mimeType falls back when the response has no content type. res_content_type = response_headers["content-type"] if res_content_type.nil? || res_content_type == "" res_content_type = "application/octet-stream" end duration = captured["duration"] || 0 har_request = { "method" => request["method"], "url" => request["url"], "httpVersion" => "HTTP/1.1", # HAR-003 (reserved) "headers" => headers_to_list(request_headers), # HAR-004 "queryString" => parse_query_string(request["url"].to_s) } # HAR-006: postData is present ONLY when a request body was captured. # The reference tests truthiness, so an empty-string body produces no # postData but still reports bodySize 0. unless request_body.nil? || request_body.empty? har_request["postData"] = { "mimeType" => req_content_type, "text" => request_body } end har_request["headersSize"] = -1 # HAR-012 har_request["bodySize"] = request_body.nil? ? -1 : Text.utf8_length(request_body) # HAR-010/011 { "startedDateTime" => captured["startedAt"], # HAR-001 "time" => duration, # HAR-002 "request" => har_request, "response" => { "status" => response["status"], "statusText" => "", # HAR-008 (reserved) "httpVersion" => "HTTP/1.1", "headers" => headers_to_list(response_headers), "content" => { "size" => response_body.nil? ? 0 : Text.utf8_length(response_body), "mimeType" => res_content_type, "text" => response_body.nil? ? "" : response_body }, "headersSize" => -1, "bodySize" => response_body.nil? ? -1 : Text.utf8_length(response_body) }, "timings" => { "send" => 0, "wait" => duration, "receive" => 0 } } end |