sevenwire-http_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,159 @@
1
+ = HTTP Client -- simple DSL for accessing HTTP resources
2
+
3
+ A simple HTTP client for Ruby, inspired by the Sinatra's microframework style
4
+ of specifying actions: get, put, post, delete.
5
+
6
+ == Usage: Raw URL
7
+
8
+ require 'http_client'
9
+
10
+ HttpClient.get 'http://example.com/resource'
11
+ HttpClient.get 'https://user:password@example.com/private/resource'
12
+
13
+ HttpClient.post 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' }
14
+
15
+ HttpClient.delete 'http://example.com/resource'
16
+
17
+ See HttpClient module docs for details.
18
+
19
+ == Usage: ActiveResource-Style
20
+
21
+ resource = HttpClient::Resource.new 'http://example.com/resource'
22
+ resource.get
23
+
24
+ private_resource = HttpClient::Resource.new 'https://example.com/private/resource', :user => 'adam', :password => 'secret', :timeout => 20, :open_timeout => 5
25
+ private_resource.put File.read('pic.jpg'), :content_type => 'image/jpg'
26
+
27
+ See HttpClient::Resource module docs for details.
28
+
29
+ == Usage: Resource Nesting
30
+
31
+ site = HttpClient::Resource.new('http://example.com')
32
+ site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
33
+
34
+ See HttpClient::Resource docs for details.
35
+
36
+ == Shell
37
+
38
+ The http_client shell command gives an IRB session with HttpClient already loaded:
39
+
40
+ $ http_client
41
+ >> HttpClient.get 'http://example.com'
42
+
43
+ Specify a URL argument for get/post/put/delete on that resource:
44
+
45
+ $ http_client http://example.com
46
+ >> put '/resource', 'data'
47
+
48
+ Add a user and password for authenticated resources:
49
+
50
+ $ http_client https://example.com user pass
51
+ >> delete '/private/resource'
52
+
53
+ Create ~/.http_client for named sessions:
54
+
55
+ sinatra:
56
+ url: http://localhost:4567
57
+ rack:
58
+ url: http://localhost:9292
59
+ private_site:
60
+ url: http://example.com
61
+ username: user
62
+ password: pass
63
+
64
+ Then invoke:
65
+
66
+ $ http_client private_site
67
+
68
+ Use as a one-off, curl-style:
69
+
70
+ $ http_client get http://example.com/resource > output_body
71
+
72
+ $ http_client put http://example.com/resource < input_body
73
+
74
+ == Logging
75
+
76
+ Write calls to a log filename (can also be "stdout" or "stderr"):
77
+
78
+ HttpClient.log = '/tmp/http_client.log'
79
+
80
+ Or set an environment variable to avoid modifying the code:
81
+
82
+ $ HTTPCLIENT_LOG=stdout path/to/my/program
83
+
84
+ Either produces logs like this:
85
+
86
+ HttpClient.get "http://some/resource"
87
+ # => 200 OK | text/html 250 bytes
88
+ HttpClient.put "http://some/resource", "payload"
89
+ # => 401 Unauthorized | application/xml 340 bytes
90
+
91
+ Note that these logs are valid Ruby, so you can paste them into the http_client
92
+ shell or a script to replay your sequence of http calls.
93
+
94
+ == Proxy
95
+
96
+ All calls to HttpClient, including Resources, will use the proxy specified by
97
+ HttpClient.proxy:
98
+
99
+ HttpClient.proxy = "http://proxy.example.com/"
100
+ HttpClient.get "http://some/resource"
101
+ # => response from some/resource as proxied through proxy.example.com
102
+
103
+ Often the proxy url is set in an environment variable, so you can do this to
104
+ use whatever proxy the system is configured to use:
105
+
106
+ HttpClient.proxy = ENV['http_proxy']
107
+
108
+ == Cookies
109
+
110
+ Request and Response objects know about HTTP cookies, and will automatically
111
+ extract and set headers for them as needed:
112
+
113
+ response = HttpClient.get 'http://example.com/action_which_sets_session_id'
114
+ response.cookies
115
+ # => {"_applicatioN_session_id" => "1234"}
116
+
117
+ response2 = HttpClient.post(
118
+ 'http://localhost:3000/',
119
+ {:param1 => "foo"},
120
+ {:cookies => {:session_id => "1234"}}
121
+ )
122
+ # ...response body
123
+
124
+ == SSL Client Certificates
125
+
126
+ HttpClient::Resource.new(
127
+ 'https://example.com',
128
+ :ssl_client_cert => OpenSSL::X509::Certificate.new(File.read("cert.pem")),
129
+ :ssl_client_key => OpenSSL::PKey::RSA.new(File.read("key.pem"), "passphrase, if any"),
130
+ :ssl_ca_file => "ca_certificate.pem",
131
+ :verify_ssl => OpenSSL::SSL::VERIFY_PEER
132
+ ).get
133
+
134
+ Self-signed certificates can be generated with the openssl command-line tool.
135
+
136
+ == Meta
137
+
138
+ This library began its life as RestClient. Due to some changes and the desire
139
+ to not conflict with the original library, Sevenwire forked and renamed it.
140
+
141
+ RestClient was written by Adam Wiggins (adam at heroku dot com)
142
+
143
+ RestClient Patches contributed by: Chris Anderson, Greg Borenstein, Ardekantur, Pedro
144
+ Belo, Rafael Souza, Rick Olson, Aman Gupta, Blake Mizerany, Brian Donovan, Ivan
145
+ Makfinsky, Marc-André Cournoyer, Coda Hale, Tetsuo Watanabe, Dusty Doris,
146
+ Lennon Day-Reynolds, James Edward Gray II, Cyril Rohr, Juan Alvarez, and Adam
147
+ Jacob
148
+
149
+ Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
150
+
151
+ RestClient can be found at:
152
+
153
+ http://rest-client.heroku.com
154
+
155
+ http://github.com/adamwiggins/rest-client
156
+
157
+ HttpClient can be found at:
158
+
159
+ http://github.com/sevenwire/http-client
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "http_client"
8
+ gem.summary = %Q{Simple HTTP/REST client for Ruby, inspired by microframework syntax for specifying actions. Forked from RestClient http://rest-client.heroku.com see README for reasons}
9
+ gem.email = "nate@sevenwire.com"
10
+ gem.homepage = "http://github.com/sevenwire/http_client"
11
+ gem.authors = ["Adam Wiggins", "Nate Sutton"]
12
+
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'spec/rake/spectask'
20
+ Spec::Rake::SpecTask.new(:spec) do |spec|
21
+ spec.libs << 'lib' << 'spec'
22
+ spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+
32
+ task :default => :spec
33
+
34
+ require 'rake/rdoctask'
35
+ Rake::RDocTask.new do |rdoc|
36
+ if File.exist?('VERSION.yml')
37
+ config = YAML.load(File.read('VERSION.yml'))
38
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
39
+ else
40
+ version = ""
41
+ end
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "http-client #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
data/bin/http_client ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../lib"
4
+ require 'http_client'
5
+
6
+ require "yaml"
7
+
8
+ def usage(why = nil)
9
+ puts "failed for reason: #{why}" if why
10
+ puts "usage: http_client [get|put|post|delete] url|name [username] [password]"
11
+ puts " The verb is optional, if you leave it off you'll get an interactive shell."
12
+ puts " put and post both take the input body on stdin."
13
+ exit(1)
14
+ end
15
+
16
+ if %w(get put post delete).include? ARGV.first
17
+ @verb = ARGV.shift
18
+ else
19
+ @verb = nil
20
+ end
21
+
22
+ @url = ARGV.shift || 'http://localhost:4567'
23
+
24
+ config = YAML.load(File.read(ENV['HOME'] + "/.http_client")) rescue {}
25
+
26
+ @url, @username, @password = if c = config[@url]
27
+ [c['url'], c['username'], c['password']]
28
+ else
29
+ [@url, *ARGV]
30
+ end
31
+
32
+ usage("invalid url '#{@url}") unless @url =~ /^https?/
33
+ usage("too few args") unless ARGV.size < 3
34
+
35
+ def r
36
+ @r ||= HttpClient::Resource.new(@url, @username, @password)
37
+ end
38
+
39
+ r # force rc to load
40
+
41
+ if @verb
42
+ begin
43
+ if %w(put post).include? @verb
44
+ puts r.send(@verb, STDIN.read)
45
+ else
46
+ puts r.send(@verb)
47
+ end
48
+ exit 0
49
+ rescue HttpClient::Exception => e
50
+ puts e.response.body if e.respond_to? :response
51
+ raise
52
+ end
53
+ end
54
+
55
+ %w(get post put delete).each do |m|
56
+ eval <<-end_eval
57
+ def #{m}(path, *args, &b)
58
+ r[path].#{m}(*args, &b)
59
+ end
60
+ end_eval
61
+ end
62
+
63
+ def method_missing(s, *args, &b)
64
+ super unless r.respond_to?(s)
65
+ r.send(s, *args, &b)
66
+ end
67
+
68
+ require 'irb'
69
+ require 'irb/completion'
70
+
71
+ if File.exists? ".irbrc"
72
+ ENV['IRBRC'] = ".irbrc"
73
+ end
74
+
75
+ if File.exists?(rcfile = "~/.http_clientrc")
76
+ load(rcfile)
77
+ end
78
+
79
+ ARGV.clear
80
+
81
+ IRB.start
82
+ exit!
@@ -0,0 +1,93 @@
1
+ require 'uri'
2
+ require 'net/https'
3
+ require 'zlib'
4
+ require 'stringio'
5
+
6
+ require File.dirname(__FILE__) + '/http_client/request'
7
+ require File.dirname(__FILE__) + '/http_client/mixin/response'
8
+ require File.dirname(__FILE__) + '/http_client/response'
9
+ require File.dirname(__FILE__) + '/http_client/raw_response'
10
+ require File.dirname(__FILE__) + '/http_client/resource'
11
+ require File.dirname(__FILE__) + '/http_client/exceptions'
12
+
13
+ # This module's static methods are the entry point for using the HTTP client.
14
+ #
15
+ # # GET
16
+ # xml = HttpClient.get 'http://example.com/resource'
17
+ # jpg = HttpClient.get 'http://example.com/resource', :accept => 'image/jpg'
18
+ #
19
+ # # authentication and SSL
20
+ # HttpClient.get 'https://user:password@example.com/private/resource'
21
+ #
22
+ # # POST or PUT with a hash sends parameters as a urlencoded form body
23
+ # HttpClient.post 'http://example.com/resource', :param1 => 'one'
24
+ #
25
+ # # nest hash parameters
26
+ # HttpClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
27
+ #
28
+ # # POST and PUT with raw payloads
29
+ # HttpClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
30
+ # HttpClient.post 'http://example.com/resource.xml', xml_doc
31
+ # HttpClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
32
+ #
33
+ # # DELETE
34
+ # HttpClient.delete 'http://example.com/resource'
35
+ #
36
+ # # retreive the response http code and headers
37
+ # res = HttpClient.get 'http://example.com/some.jpg'
38
+ # res.code # => 200
39
+ # res.headers[:content_type] # => 'image/jpg'
40
+ #
41
+ # # HEAD
42
+ # HttpClient.head('http://example.com').headers
43
+ #
44
+ # To use with a proxy, just set HttpClient.proxy to the proper http proxy:
45
+ #
46
+ # HttpClient.proxy = "http://proxy.example.com/"
47
+ #
48
+ # Or inherit the proxy from the environment:
49
+ #
50
+ # HttpClient.proxy = ENV['http_proxy']
51
+ #
52
+ # For live tests of HttpClient, try using http://http-test.heroku.com, which echoes back information about the http call:
53
+ #
54
+ # >> HttpClient.put 'http://http-test.heroku.com/resource', :foo => 'baz'
55
+ # => "PUT http://http-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
56
+ #
57
+ module HttpClient
58
+ def self.get(url, headers={})
59
+ Request.execute(:method => :get, :url => url, :headers => headers)
60
+ end
61
+
62
+ def self.post(url, payload, headers={})
63
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers)
64
+ end
65
+
66
+ def self.put(url, payload, headers={})
67
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers)
68
+ end
69
+
70
+ def self.delete(url, headers={})
71
+ Request.execute(:method => :delete, :url => url, :headers => headers)
72
+ end
73
+
74
+ def self.head(url, headers={})
75
+ Request.execute(:method => :head, :url => url, :headers => headers)
76
+ end
77
+
78
+ class << self
79
+ attr_accessor :proxy
80
+ end
81
+
82
+ # Print log of HttpClient calls. Value can be stdout, stderr, or a filename.
83
+ # You can also configure logging by the environment variable HTTPCLIENT_LOG.
84
+ def self.log=(log)
85
+ @@log = log
86
+ end
87
+
88
+ def self.log # :nodoc:
89
+ return ENV['HTTPCLIENT_LOG'] if ENV['HTTPCLIENT_LOG']
90
+ return @@log if defined? @@log
91
+ nil
92
+ end
93
+ end
@@ -0,0 +1,39 @@
1
+ module HttpClient
2
+ # This is the base HttpClient exception class. Rescue it if you want to
3
+ # catch any exception that your request might raise
4
+ class Exception < StandardError
5
+ def message(default=nil)
6
+ self.class::ErrorMessage
7
+ end
8
+ end
9
+
10
+ # Base HttpClient exception when there's a response available
11
+ class ExceptionWithResponse < Exception
12
+ attr_accessor :response
13
+
14
+ def initialize(response=nil)
15
+ @response = response
16
+ end
17
+
18
+ def http_code
19
+ @response.code.to_i if @response
20
+ end
21
+ end
22
+
23
+ # The server broke the connection prior to the request completing. Usually
24
+ # this means it crashed, or sometimes that your network connection was
25
+ # severed before it could complete.
26
+ class ServerBrokeConnection < Exception
27
+ ErrorMessage = 'Server broke connection'
28
+ end
29
+
30
+ # The server took too long to respond.
31
+ class RequestTimeout < Exception
32
+ ErrorMessage = 'Request timed out'
33
+ end
34
+
35
+ # The server refused the connection
36
+ class ConnectionRefused < Exception
37
+ ErrorMessage = 'Server refused connection'
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ module HttpClient
2
+ module Mixin
3
+ module Response
4
+ attr_reader :net_http_res
5
+
6
+ # HTTP status code, always 200 since HttpClient throws exceptions for
7
+ # other codes.
8
+ def code
9
+ @code ||= @net_http_res.code.to_i
10
+ end
11
+
12
+ # A hash of the headers, beautified with symbols and underscores.
13
+ # e.g. "Content-type" will become :content_type.
14
+ def headers
15
+ @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
16
+ end
17
+
18
+ # Hash of cookies extracted from response headers
19
+ def cookies
20
+ @cookies ||= (self.headers[:set_cookie] || "").split('; ').inject({}) do |out, raw_c|
21
+ key, val = raw_c.split('=')
22
+ unless %w(expires domain path secure).member?(key)
23
+ out[key] = val
24
+ end
25
+ out
26
+ end
27
+ end
28
+
29
+ def self.included(receiver)
30
+ receiver.extend(HttpClient::Mixin::Response::ClassMethods)
31
+ end
32
+
33
+ module ClassMethods
34
+ def beautify_headers(headers)
35
+ headers.inject({}) do |out, (key, value)|
36
+ out[key.gsub(/-/, '_').to_sym] = value.first
37
+ out
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end