Module: EventMachine::HttpEncoding

Included in:
HttpClient, MockHttpRequest
Defined in:
lib/em-http/client.rb

Overview

Methods for building HTTP requests

Constant Summary collapse

HTTP_REQUEST_HEADER =
"%s %s HTTP/1.1\r\n"
FIELD_ENCODING =
"%s: %s\r\n"

Instance Method Summary collapse

Instance Method Details

#bytesize(string) ⇒ Object



98
99
100
# File 'lib/em-http/client.rb', line 98

def bytesize(string)
  string.bytesize
end

#encode_auth(k, v) ⇒ Object

Encode basic auth in an HTTP header In: Array ([user, pass]) - for basic auth

String - custom auth string (OAuth, etc)


164
165
166
167
168
169
170
# File 'lib/em-http/client.rb', line 164

def encode_auth(k,v)
  if v.is_a? Array
    FIELD_ENCODING % [k, ["Basic", Base64.encode64(v.join(":")).chomp].join(" ")]
  else
    encode_field(k,v)
  end
end


185
186
187
188
189
190
191
# File 'lib/em-http/client.rb', line 185

def encode_cookie(cookie)
  if cookie.is_a? Hash
    cookie.inject('') { |result, (k, v)| result <<  encode_param(k, v) + ";" }
  else
    cookie
  end
end

#encode_field(k, v) ⇒ Object

Encode a field in an HTTP header



157
158
159
# File 'lib/em-http/client.rb', line 157

def encode_field(k, v)
  FIELD_ENCODING % [k, v]
end

#encode_headers(head) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/em-http/client.rb', line 172

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

#encode_hostObject

HTTP is kind of retarded that you have to specify a Host header, but if you include port 80 then further redirects will tack on the :80 which is annoying.



115
116
117
118
119
120
121
# File 'lib/em-http/client.rb', line 115

def encode_host
  if @uri.port == 80 || @uri.port == 443
    return @uri.host
  else
    @uri.host + ":#{@uri.port}"
  end
end

#encode_param(k, v) ⇒ Object

URL encodes query parameters: single k=v, or a URL encoded array, if v is an array of values



148
149
150
151
152
153
154
# File 'lib/em-http/client.rb', line 148

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

#encode_query(uri, query) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/em-http/client.rb', line 133

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.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

#encode_request(method, uri, query, proxy) ⇒ Object



123
124
125
126
127
128
129
130
131
# File 'lib/em-http/client.rb', line 123

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 && proxy[:type] != :socks && !proxy[:use_connect]

  HTTP_REQUEST_HEADER % [method.to_s.upcase, query]
end

#escape(s) ⇒ Object

Escapes a URI.



84
85
86
87
88
# File 'lib/em-http/client.rb', line 84

def escape(s)
  s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
    '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
  }.tr(' ', '+')
end

#munge_header_keys(head) ⇒ Object

Map all header keys to a downcased string version



108
109
110
# File 'lib/em-http/client.rb', line 108

def munge_header_keys(head)
  head.inject({}) { |h, (k, v)| h[k.to_s.downcase] = v; h }
end

#unescape(s) ⇒ Object

Unescapes a URI escaped string.



91
92
93
94
95
# File 'lib/em-http/client.rb', line 91

def unescape(s)
  s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
    [$1.delete('%')].pack('H*')
  }
end