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