1 2 3 4 5 6 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 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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
module EventMachine
module HttpEncoding
HTTP_REQUEST_HEADER="%s %s HTTP/1.1\r\n"
FIELD_ENCODING = "%s: %s\r\n"
def escape(s)
if defined?(EscapeUtils)
EscapeUtils.escape_url(s.to_s)
else
s.to_s.gsub(/([^a-zA-Z0-9_.-]+)/) {
'%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
}
end
end
def unescape(s)
if defined?(EscapeUtils)
EscapeUtils.unescape_url(s.to_s)
else
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) {
[$1.delete('%')].pack('H*')
}
end
end
if ''.respond_to?(:bytesize)
def bytesize(string)
string.bytesize
end
else
def bytesize(string)
string.size
end
end
# Map all header keys to a downcased string version
def munge_header_keys(head)
head.inject({}) { |h, (k, v)| h[k.to_s.downcase] = v; h }
end
def encode_host
if @req.uri.port.nil? || @req.uri.port == 80 || @req.uri.port == 443
return @req.uri.host
else
@req.uri.host + ":#{@req.uri.port}"
end
end
def encode_request(method, uri, query, proxy)
query = encode_query(uri, query)
# Non CONNECT proxies require that you provide the full request
# uri in request header, as opposed to a relative path.
query = uri.join(query) if proxy
HTTP_REQUEST_HEADER % [method.to_s.upcase, query]
end
def encode_query(uri, query)
encoded_query = if query.kind_of?(Hash)
query.map { |k, v| encode_param(k, v) }.join('&')
else
query.to_s
end
if uri && !uri.query.to_s.empty?
encoded_query = [encoded_query, uri.query].reject {|part| part.empty?}.join("&")
end
encoded_query.to_s.empty? ? uri.path : "#{uri.path}?#{encoded_query}"
end
# URL encodes query parameters:
# single k=v, or a URL encoded array, if v is an array of values
def encode_param(k, v)
if v.is_a?(Array)
v.map { |e| escape(k) + "[]=" + escape(e) }.join("&")
else
escape(k) + "=" + escape(v)
end
end
def form_encode_body(obj)
pairs = []
recursive = Proc.new do |h, prefix|
h.each do |k,v|
key = prefix == '' ? escape(k) : "#{prefix}[#{escape(k)}]"
if v.is_a? Array
nh = Hash.new
v.size.times { |t| nh[t] = v[t] }
recursive.call(nh, key)
elsif v.is_a? Hash
recursive.call(v, key)
else
pairs << "#{key}=#{escape(v)}"
end
end
end
recursive.call(obj, '')
return pairs.join('&')
end
# Encode a field in an HTTP header
def encode_field(k, v)
FIELD_ENCODING % [k, v]
end
# Encode basic auth in an HTTP header
# In: Array ([user, pass]) - for basic auth
# String - custom auth string (OAuth, etc)
def encode_auth(k,v)
if v.is_a? Array
FIELD_ENCODING % [k, ["Basic", Base64.encode64(v.join(":")).split.join].join(" ")]
else
encode_field(k,v)
end
end
def encode_headers(head)
head.inject('') do |result, (key, value)|
# Munge keys from foo-bar-baz to Foo-Bar-Baz
key = key.split('-').map { |k| k.to_s.capitalize }.join('-')
result << case key
when 'Authorization', 'Proxy-Authorization'
encode_auth(key, value)
else
encode_field(key, value)
end
end
end
def encode_cookie(cookie)
if cookie.is_a? Hash
cookie.inject('') { |result, (k, v)| result << encode_param(k, v) + ";" }
else
cookie
end
end
end
end
|