Class: SimpleHttp

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

Overview

Wrapper around ruby’s standard net/http classes. Currently, only GET and POST https methods are supported. SimpleHttp provides class methods get and post to handle basic functionality. In case more complicated requests need to be made or default settings need to be overriden, it’s possible to instantiate SimpleHttp and use instance methods get and put.

Features:

  • Handles Redirects automatically

  • Proxy used transparently if http_proxy environment variable is set.

  • SSL handled automatically

  • fault tolerant uri, e.g. all of these would work:

www.example.com”, “www.example.com/”, “www.example.com

Some usage examples: # plain GET (using class methods) SimpleHttp.get “www.example.com

# POST using the instance methods uri = URI.parse “www.example.com/index.html” sh = SimpleHttp uri sh.set_proxy “my.proxy”, “8080” sh.post => “query_data”

# POST using class methods. binaryData = getImage SimpleData.post binaryData, “image/png”

# GET requst with a custom request_header sh = SimpleHttp.new “www.example.com” sh.request_headers= ‘X-Special-Http-Header’=>‘my-value’ sh.get

Constant Summary collapse

VERSION =
'0.1.3'
RESPONSE_HANDLERS =
{
  Net::HTTPResponse => lambda { |request, response, http| 
    response.each_header {|key, value|
      http.response_headers[key]=value 
    }
    raise "#{response.to_s} : #{response.code} : #{http.uri}"
  },
  Net::HTTPSuccess => lambda { |request, response, http|
    response.each_header {|key, value|
      http.response_headers[key]=value 
    }
    #http.cookies += response.cookies
    if request.class == Net::HTTP::Head || request.class == Net::HTTP::Options
      return http.response_headers 
    end
    return response.body
  },
  Net::HTTPRedirection =>  lambda { |request, response, http|
    raise "too many redirects!" unless http.follow_num_redirects > 0  
    # create a new SimpleHttp for the location
    # refered to decreasing the remaining redirects
    # by one.
    
    if (location = response['location']) !~ /^https?:\/\//
      new_location = "#{http.uri.scheme}://#{http.uri.host}"
      if location =~ /^\//
        new_location += location
      else
        new_location += "/#{http.uri.path}/#{location}"
      end
      location = new_location  
    end

    sh = SimpleHttp.new location 
    #STDERR.puts location 
    sh.follow_num_redirects = http.follow_num_redirects-1

    # copy the response handlers used in the current
    # request in case they were non standard.
    sh.response_handlers = http.response_handlers

    # copy the request headers
    sh.request_headers=http.request_headers
    sh.response_headers=http.response_headers
    #sh.cookies+=http.cookies

    # copy host and port
    sh.uri.host = http.uri.host
    sh.uri.port = http.uri.port

    # HTTP doesn't permit redirects for methods other than
    # GET or HEAD. The exception is 303 redirects, which
    # should automatically follow the redirect URI using a
    # GET method regardless of the initial method. For
    # other classes of redirection, the client is required
    # to prompt the user before redirection occurs. Because
    # that's not a feasible action for this library, all
    # 3xx redirect URIs are followed using a GET method. 
    #
    # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

    case request
    when  Net::HTTP::Get, 
      Net::HTTP::Head,
      Net::HTTP::Options
      
      sh.get
    when Net::HTTP::Post
      sh.request_headers['content-length']=nil
      sh.get
      else 
        raise "Not a valid HTTP method for redirection: #{request.class}"
    end

  }

}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri) ⇒ SimpleHttp

SimpleHttp can either be used directly through the get and post class methods or be instantiated, in case you need to to add custom behaviour to the requests.

Example: http = SimpleHttp.new(URI.parse(“www.example.com”)) http = SimpleHttp.new “www.example.com” http = SimpleHttp.new “usr:[email protected]:1234

Parameters:

  • may

    be a URI or a String.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/simplehttp.rb', line 140

def initialize uri
  set_proxy ENV['http_proxy'] if ENV['http_proxy']
          
  if uri.class == String

    unless uri =~ /^https?:\/\//
      uri = "http://#{uri}"
    end

    uri = URI.parse uri

  end
  @uri = uri
  if !@uri.path || "" == @uri.path.strip
    @uri.path="/"
  end


  @request_headers={}
  @response_headers={}
  @cookies=[]
  @response_handlers=RESPONSE_HANDLERS.clone
  @follow_num_redirects=5

  if @uri.user
    basic_authentication @uri.user, @uri.password
  end

end

Instance Attribute Details

#follow_num_redirectsObject

Returns the value of attribute follow_num_redirects.



51
52
53
# File 'lib/simplehttp.rb', line 51

def follow_num_redirects
  @follow_num_redirects
end

#proxy_hostObject

Returns the value of attribute proxy_host.



51
52
53
# File 'lib/simplehttp.rb', line 51

def proxy_host
  @proxy_host
end

#proxy_portObject

Returns the value of attribute proxy_port.



51
52
53
# File 'lib/simplehttp.rb', line 51

def proxy_port
  @proxy_port
end

#proxy_pwdObject

Returns the value of attribute proxy_pwd.



51
52
53
# File 'lib/simplehttp.rb', line 51

def proxy_pwd
  @proxy_pwd
end

#proxy_userObject

Returns the value of attribute proxy_user.



51
52
53
# File 'lib/simplehttp.rb', line 51

def proxy_user
  @proxy_user
end

#request_headersObject

Returns the value of attribute request_headers.



51
52
53
# File 'lib/simplehttp.rb', line 51

def request_headers
  @request_headers
end

#response_handlersObject

Returns the value of attribute response_handlers.



51
52
53
# File 'lib/simplehttp.rb', line 51

def response_handlers
  @response_handlers
end

#response_headersObject

Returns the value of attribute response_headers.



51
52
53
# File 'lib/simplehttp.rb', line 51

def response_headers
  @response_headers
end

#uriObject

Returns the value of attribute uri.



51
52
53
# File 'lib/simplehttp.rb', line 51

def uri
  @uri
end

Class Method Details

.get(uri, query = nil) ⇒ Object

Make a simple GET request to the provided URI.

Example: puts(SimpleHttp.get(“www.example.com”))



338
339
340
341
# File 'lib/simplehttp.rb', line 338

def self.get uri, query=nil
  http = SimpleHttp.new uri
  http.get query 
end

.head(uri, query = nil) ⇒ Object



343
344
345
346
# File 'lib/simplehttp.rb', line 343

def self.head uri, query=nil
  http = SimpleHttp.new uri
  http.head query
end

.options(uri) ⇒ Object



348
349
350
351
# File 'lib/simplehttp.rb', line 348

def self.options uri
  http = SimpleHttp.new uri
  http.options 
end

.post(uri, query = nil, content_type = 'application/x-www-form-urlencoded') ⇒ Object

Make a POST request to the provided URI.

Example: puts(SimpleHttp.post(“www.example.com”, “query”=>“my_query”))

Alternatively, you can post any sort of data, but will have to set the appriate content_type:

SimpleHttp.post(“www.example.com/”, binary_data, “img/png”)



368
369
370
371
# File 'lib/simplehttp.rb', line 368

def self.post uri, query=nil, content_type='application/x-www-form-urlencoded'
  http = SimpleHttp.new uri
  http.post query, content_type
end

.trace(uri) ⇒ Object



353
354
355
356
# File 'lib/simplehttp.rb', line 353

def self.trace uri
  http = SimpleHttp.new uri
  http.trace
end

Instance Method Details

#basic_authentication(usr, pwd) ⇒ Object

Provides facilities to perform http basic authentication. You don’t need to provide usr and pwd if they are already included in the uri, i.e. user:[email protected]/



176
177
178
179
180
# File 'lib/simplehttp.rb', line 176

def basic_authentication usr, pwd
  str = Base64.encode64("#{usr}:#{pwd}")
  str = "Basic #{str}"
  @request_headers["Authorization"]=str
end

#do_http(request) ⇒ Object

internal



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/simplehttp.rb', line 310

def do_http request
  response = nil

  http = Net::HTTP.new(@uri.host, @uri.port, @proxy_host,
    @proxy_port, @proxy_user, @proxy_pwd)
  http.use_ssl = @uri.scheme == 'https'

  # add custom request headers.
  
  @request_headers.each {|key,value|
    request[key]=value;
  }

  handle_response(request, http.request(request));
end

#get(query = nil) ⇒ Object

Call the get method as an instance method if you need to modify the default behaviour of the library, or set special headers:

http = SimpleHttp.new “www.example.comhttp.request_headers=“whatever” str = http.get



380
381
382
383
384
385
386
387
388
389
# File 'lib/simplehttp.rb', line 380

def get query = nil
  if (query = make_query query)
    @uri.query = @uri.query ? @uri.query+"&"+query : query
  end
  full_path = @uri.path + (@uri.query ? "?#{@uri.query}" : "")
    
  req = Net::HTTP::Get.new(full_path)
  # puts Net::HTTP::Proxy(@proxy_host, @proxy_port, @proxy_user, @proxy_pwd).get(@uri)
  do_http req
end

#handle_response(http_request, http_response) ⇒ Object

interal Takes a HTTPResponse (or subclass) and determines how to handle the response. Default behaviour is:

HTTPSuccess : return the body of the response HTTPRedirection : follow the redirect until success. default : raise the HTTPResponse.

the default behaviour can be overidden by registering a response handler using the register_response_handler method.



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/simplehttp.rb', line 287

def handle_response http_request, http_response
  raise "Not a Net::HTTPResponse" unless http_response.is_a? Net::HTTPResponse
  
  c = http_response.class
  while c!=Object
    # the response_handlers hash contains a handler
    # for the specific response class.
    if @response_handlers[c]
    #STDERR.puts "!#{http_response.class}"
    #STDERR.puts "!#{@response_handlers[c]}"
      return @response_handlers[c].call(http_request, http_response, self)
    end

    c=c.superclass
  end  

  # if we reached this place, no handler was registered
  # for this response. default is to return the response.
  
  return http_response
end

#head(query = nil) ⇒ Object

Call the head method as an instance method.



393
394
395
396
397
398
399
400
401
402
# File 'lib/simplehttp.rb', line 393

def head query = nil
  if (query = make_query query)
    @uri.query = @uri.query ? @uri.query+"&"+query : query
  end
  full_path = @uri.path + (@uri.query ? "?#{@uri.query}" : "")
    
  req = Net::HTTP::Head.new(full_path)
  # puts Net::HTTP::Proxy(@proxy_host, @proxy_port, @proxy_user, @proxy_pwd).get(@uri)
  do_http req
end

#make_query(query) ⇒ Object

internal



327
328
329
330
331
332
# File 'lib/simplehttp.rb', line 327

def make_query query
  return query unless query && query.class == Hash
  query.inject([]) do |s, (key, value)|
    s << CGI::escape(key) + "=" + CGI::escape(value)
  end.join('&')
end

#optionsObject

Call http options method. Returns the response



405
406
407
408
409
# File 'lib/simplehttp.rb', line 405

def options
  # we don't support sending a payload in options' body.
  req = Net::HTTP::Options.new(@uri.path)
  do_http req
end

#post(query = nil, content_type = 'application/x-www-form-urlencoded') ⇒ Object

Post the query data to the url. The body of the request remains empty if query=nil. In case query is a Hash, it’s assumed that we are sending a form. In case query is a String, it’s also assumed that a form is being sent, UNLESS the content_type parameter is set.



426
427
428
429
430
431
432
433
434
# File 'lib/simplehttp.rb', line 426

def post query=nil, content_type='application/x-www-form-urlencoded'
  req = Net::HTTP::Post.new(@uri.path)

  req.body= make_query query if query
  req.content_type=content_type if query
  req.content_length=query ? req.body.length : 0

  do_http req
end

#register_response_handler(clazz, &block) ⇒ Object

this method can be used to register response handlers for specific http responses in case you need to override the default behaviour. Defaults are:

HTTPSuccess : return the body of the response HTTPRedirection : follow the redirection until success Others : raise an exception

clazz is the subclass of HTTPResponse (or HTTPResponse in case you want to define “default” behaviour) that you are registering the handler for.

block is the handler itself, if a response of the appropriate class is received, block is called with three parameters: the the Net::HTTPRequest, the actual HTTPResponse object that was received and a reference to the instance of SimpleHttp that is executing the call.

example:

# to override the default action of following a HTTP # redirect, you could register the folllowing handler:

sh = SimpleHttp “www.example.com” sh.register_response_handler Net::HTTPRedirection {|request, response, shttp| response }



212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/simplehttp.rb', line 212

def register_response_handler clazz, &block
  c = clazz
        while c != Object
    # completely unnecessary sanity check to make sure parameter
    # `clazz` is in fact a HTTPResponse ...
    if c == Net::HTTPResponse
      @response_handlers[clazz]=block 
      return
    end
    c = c.superclass
  end

  raise "Trying to register a response handler for non-response class: #{clazz}" 
end

#set_proxy(proxy, port = nil, user = nil, pwd = nil) ⇒ Object



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/simplehttp.rb', line 248

def set_proxy proxy, port=nil, user=nil, pwd=nil
  
  
  if !proxy  
    @proxy_host=@proxy_port=@proxy_user=@proxy_pwd=nil 
    return
  end

  if proxy.class == String 
    if !port && !user && !pwd
      proxy = URI.parse(proxy)
    else 
      @proxy_host= host
      @proxy_port= port
      @proxy_user= user
      @proxy_pwd = pwd
    end
  end
  
  if proxy.class == URI::HTTP 
    @proxy_host= proxy.host
    @proxy_port= proxy.port
    @proxy_user= proxy.user
    @proxy_pwd = proxy.password
  end
end

#traceObject



411
412
413
414
415
# File 'lib/simplehttp.rb', line 411

def trace
  # payload? 
  req = Net::HTTP::Trace.new(@uri.path)
  do_http req
end