rest-client-1.6.7/0000755000004100000410000000000011632430106014002 5ustar www-datawww-datarest-client-1.6.7/README.rdoc0000644000004100000410000002201011632430106015603 0ustar www-datawww-data= REST Client -- simple DSL for accessing HTTP and REST resources A simple HTTP and REST client for Ruby, inspired by the Sinatra's microframework style of specifying actions: get, put, post, delete. * Main page: http://github.com/archiloque/rest-client * Mailing list: rest.client@librelist.com (send a mail to subscribe). == Usage: Raw URL require 'rest_client' RestClient.get 'http://example.com/resource' RestClient.get 'http://example.com/resource', {:params => {:id => 50, 'foo' => 'bar'}} RestClient.get 'https://user:password@example.com/private/resource', {:accept => :json} RestClient.post 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' } RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json RestClient.delete 'http://example.com/resource' response = RestClient.get 'http://example.com/resource' response.code ➔ 200 response.cookies ➔ {"Foo"=>"BAR", "QUUX"=>"QUUUUX"} response.headers ➔ {:content_type=>"text/html; charset=utf-8", :cache_control=>"private" ... response.to_str ➔ \n\n\n { :path => '/foo/bar', :owner => 'that_guy', :group => 'those_guys' }, :upload => { :file => File.new(path, 'rb') } }) == Multipart Yeah, that's right! This does multipart sends for you! RestClient.post '/data', :myfile => File.new("/path/to/image.jpg", 'rb') This does two things for you: * Auto-detects that you have a File value sends it as multipart * Auto-detects the mime of the file and sets it in the HEAD of the payload for each entry If you are sending params that do not contain a File object but the payload needs to be multipart then: RestClient.post '/data', :foo => 'bar', :multipart => true == Usage: ActiveResource-Style resource = RestClient::Resource.new 'http://example.com/resource' resource.get private_resource = RestClient::Resource.new 'https://example.com/private/resource', 'user', 'pass' private_resource.put File.read('pic.jpg'), :content_type => 'image/jpg' See RestClient::Resource module docs for details. == Usage: Resource Nesting site = RestClient::Resource.new('http://example.com') site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain' See RestClient::Resource docs for details. == Exceptions (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) * for results code between 200 and 207 a RestClient::Response will be returned * for results code 301, 302 or 307 the redirection will be followed if the request is a get or a head * for result code 303 the redirection will be followed and the request transformed into a get * for other cases a RestClient::Exception holding the Response will be raised, a specific exception class will be thrown for know error codes RestClient.get 'http://example.com/resource' ➔ RestClient::ResourceNotFound: RestClient::ResourceNotFound begin RestClient.get 'http://example.com/resource' rescue => e e.response end ➔ 404 Resource Not Found | text/html 282 bytes == Result handling A block can be passed to the RestClient method, this block will then be called with the Response. Response.return! can be called to invoke the default response's behavior. # Don't raise exceptions but return the response RestClient.get('http://example.com/resource'){|response, request, result| response } ➔ 404 Resource Not Found | text/html 282 bytes # Manage a specific error code RestClient.get('http://my-rest-service.com/resource'){ |response, request, result, &block| case response.code when 200 p "It worked !" response when 423 raise SomeCustomExceptionIfYouWant else response.return!(request, result, &block) end } # Follow redirections for all request types and not only for get and head # RFC : "If the 301, 302 or 307 status code is received in response to a request other than GET or HEAD, # the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, # since this might change the conditions under which the request was issued." RestClient.get('http://my-rest-service.com/resource'){ |response, request, result, &block| if [301, 302, 307].include? response.code response.follow_redirection(request, result, &block) else response.return!(request, result, &block) end } == Non-normalized URIs. If you want to use non-normalized URIs, you can normalize them with the addressable gem (http://addressable.rubyforge.org/api/). require 'addressable/uri' RestClient.get(Addressable::URI.parse("http://www.詹姆斯.com/").normalize.to_str) == Lower-level access For cases not covered by the general API, you can use the RestClient::Request class which provide a lower-level API. You can: * specify ssl parameters * override cookies * manually handle the response (so you can operate on the response stream than reading it fully in memory) see the class' rdoc for more information. == Shell The restclient shell command gives an IRB session with RestClient already loaded: $ restclient >> RestClient.get 'http://example.com' Specify a URL argument for get/post/put/delete on that resource: $ restclient http://example.com >> put '/resource', 'data' Add a user and password for authenticated resources: $ restclient https://example.com user pass >> delete '/private/resource' Create ~/.restclient for named sessions: sinatra: url: http://localhost:4567 rack: url: http://localhost:9292 private_site: url: http://example.com username: user password: pass Then invoke: $ restclient private_site Use as a one-off, curl-style: $ restclient get http://example.com/resource > output_body $ restclient put http://example.com/resource < input_body == Logging To enable logging you can * set RestClient.log with a ruby Logger * or set an environment variable to avoid modifying the code (in this case you can use a file name, "stdout" or "stderr"): $ RESTCLIENT_LOG=stdout path/to/my/program Either produces logs like this: RestClient.get "http://some/resource" # => 200 OK | text/html 250 bytes RestClient.put "http://some/resource", "payload" # => 401 Unauthorized | application/xml 340 bytes Note that these logs are valid Ruby, so you can paste them into the restclient shell or a script to replay your sequence of rest calls. == Proxy All calls to RestClient, including Resources, will use the proxy specified by RestClient.proxy: RestClient.proxy = "http://proxy.example.com/" RestClient.get "http://some/resource" # => response from some/resource as proxied through proxy.example.com Often the proxy url is set in an environment variable, so you can do this to use whatever proxy the system is configured to use: RestClient.proxy = ENV['http_proxy'] == Query parameters Request objects know about query parameters and will automatically add them to the url for GET, HEAD and DELETE requests and escape the keys and values as needed: RestClient.get 'http://example.com/resource', :params => {:foo => 'bar', :baz => 'qux'} # will GET http://example.com/resource?foo=bar&baz=qux == Cookies Request and Response objects know about HTTP cookies, and will automatically extract and set headers for them as needed: response = RestClient.get 'http://example.com/action_which_sets_session_id' response.cookies # => {"_applicatioN_session_id" => "1234"} response2 = RestClient.post( 'http://localhost:3000/', {:param1 => "foo"}, {:cookies => {:session_id => "1234"}} ) # ...response body == SSL Client Certificates RestClient::Resource.new( 'https://example.com', :ssl_client_cert => OpenSSL::X509::Certificate.new(File.read("cert.pem")), :ssl_client_key => OpenSSL::PKey::RSA.new(File.read("key.pem"), "passphrase, if any"), :ssl_ca_file => "ca_certificate.pem", :verify_ssl => OpenSSL::SSL::VERIFY_PEER ).get Self-signed certificates can be generated with the openssl command-line tool. == Hook RestClient.add_before_execution_proc add a Proc to be called before each execution, it's handy if you need a direct access to the http request. Example: # Add oath support using the oauth gem require 'oauth' access_token = ... RestClient.add_before_execution_proc do |req, params| access_token.sign! req end RestClient.get 'http://example.com' == More Need caching, more advanced logging or any ability provided by a rack middleware ? Have a look at rest-client-components http://github.com/crohr/rest-client-components == Meta Written by Adam Wiggins, major modifications by Blake Mizerany, maintained by Julien Kirch Patches contributed by many, including Chris Anderson, Greg Borenstein, Ardekantur, Pedro Belo, Rafael Souza, Rick Olson, Aman Gupta, François Beausoleil and Nick Plante. Released under the MIT License: http://www.opensource.org/licenses/mit-license.php rest-client-1.6.7/Rakefile0000644000004100000410000000401711632430106015451 0ustar www-datawww-datarequire 'rake' require 'jeweler' Jeweler::Tasks.new do |s| s.name = "rest-client" s.description = "A simple HTTP and REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete." s.summary = "Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions." s.authors = ["Adam Wiggins", "Julien Kirch"] s.email = "rest.client@librelist.com" s.homepage = "http://github.com/archiloque/rest-client" s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"] s.test_files = FileList["{spec}/**/*"] s.add_runtime_dependency("mime-types", ">= 1.16") s.add_development_dependency("webmock", ">= 0.9.1") s.add_development_dependency("rspec") s.extra_rdoc_files = [ 'README.rdoc', 'history.md'] end ############################ require 'spec/rake/spectask' desc "Run all specs" task :spec => ["spec:unit", "spec:integration"] desc "Run unit specs" Spec::Rake::SpecTask.new('spec:unit') do |t| t.spec_opts = ['--colour --format progress --loadby mtime --reverse'] t.spec_files = FileList['spec/*_spec.rb'] end desc "Run integration specs" Spec::Rake::SpecTask.new('spec:integration') do |t| t.spec_opts = ['--colour --format progress --loadby mtime --reverse'] t.spec_files = FileList['spec/integration/*_spec.rb'] end desc "Print specdocs" Spec::Rake::SpecTask.new(:doc) do |t| t.spec_opts = ["--format", "specdoc", "--dry-run"] t.spec_files = FileList['spec/*_spec.rb'] end desc "Run all examples with RCov" Spec::Rake::SpecTask.new('rcov') do |t| t.spec_files = FileList['spec/*_spec.rb'] t.rcov = true t.rcov_opts = ['--exclude', 'examples'] end task :default => :spec ############################ require 'rake/rdoctask' Rake::RDocTask.new do |t| t.rdoc_dir = 'rdoc' t.title = "rest-client, fetch RESTful resources effortlessly" t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object' t.options << '--charset' << 'utf-8' t.rdoc_files.include('README.rdoc') t.rdoc_files.include('lib/*.rb') end rest-client-1.6.7/spec/0000755000004100000410000000000011632430106014734 5ustar www-datawww-datarest-client-1.6.7/spec/restclient_spec.rb0000644000004100000410000000460411632430106020453 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') describe RestClient do describe "API" do it "GET" do RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {}) RestClient.get('http://some/resource') end it "POST" do RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'payload', :headers => {}) RestClient.post('http://some/resource', 'payload') end it "PUT" do RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'payload', :headers => {}) RestClient.put('http://some/resource', 'payload') end it "PATCH" do RestClient::Request.should_receive(:execute).with(:method => :patch, :url => 'http://some/resource', :payload => 'payload', :headers => {}) RestClient.patch('http://some/resource', 'payload') end it "DELETE" do RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {}) RestClient.delete('http://some/resource') end it "HEAD" do RestClient::Request.should_receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {}) RestClient.head('http://some/resource') end it "OPTIONS" do RestClient::Request.should_receive(:execute).with(:method => :options, :url => 'http://some/resource', :headers => {}) RestClient.options('http://some/resource') end end describe "logging" do after do RestClient.log = nil end it "uses << if the log is not a string" do log = RestClient.log = [] log.should_receive(:<<).with('xyz') RestClient.log << 'xyz' end it "displays the log to stdout" do RestClient.log = 'stdout' STDOUT.should_receive(:puts).with('xyz') RestClient.log << 'xyz' end it "displays the log to stderr" do RestClient.log = 'stderr' STDERR.should_receive(:puts).with('xyz') RestClient.log << 'xyz' end it "append the log to the requested filename" do RestClient.log = '/tmp/restclient.log' f = mock('file handle') File.should_receive(:open).with('/tmp/restclient.log', 'a').and_yield(f) f.should_receive(:puts).with('xyz') RestClient.log << 'xyz' end end end rest-client-1.6.7/spec/request2_spec.rb0000644000004100000410000000403611632430106020050 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') require 'webmock/rspec' include WebMock describe RestClient::Request do it "manage params for get requests" do stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200) RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}).body.should == 'foo' stub_request(:get, 'http://some/resource').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar', 'params' => 'a'}).to_return(:body => 'foo', :status => 200) RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => :a}).body.should == 'foo' end it "can use a block to process response" do response_value = nil block = Proc.new do |http_response| response_value = http_response.body end stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200) RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}, :block_response => block) response_value.should == "foo" end it 'closes payload if not nil' do test_file = File.new(File.join( File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg')) initial_count = tmp_count stub_request(:post, 'http://some/resource').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).to_return(:body => 'foo', :status => 200) RestClient::Request.execute(:url => 'http://some/resource', :method => :post, :payload => {:file => test_file}) tmp_count.should == initial_count end end def tmp_count Dir.glob(Dir::tmpdir + "/*").size endrest-client-1.6.7/spec/base.rb0000644000004100000410000000047311632430106016177 0ustar www-datawww-datadef is_ruby_19? RUBY_VERSION == '1.9.1' or RUBY_VERSION == '1.9.2' end Encoding.default_internal = Encoding.default_external = "ASCII-8BIT" if is_ruby_19? require 'rubygems' require 'spec' begin require "ruby-debug" rescue LoadError # NOP, ignore end require File.dirname(__FILE__) + '/../lib/restclient' rest-client-1.6.7/spec/master_shake.jpg0000644000004100000410000005402111632430106020106 0ustar www-datawww-dataJFIF,,C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222_"S  !1AQa"2qBR#3Dbr$4CSTUsE&56c%t)!1AQ"a2B# ?aB2Zy)ucٜܲk|f5Ǎճ*-Vknh Fzڀ4uZF4##ˉ.caozb:Z!î]]L\w,C祫Eåգ"VXܛ]R~KJ25F,L  i߀ i[& ўrD|0}㧅68CM4)KUgAv< S bLa q?H)^ߧbYAV51 rScʝR?ui_<1NiAu|q_x>(^g}81n[~Kpm #\1t!18TsC޳n RQeJ;X;՚Q̧c73,Q]cm"h 'U\CD &L~ ɻ\2ןc`\28n/\MOmT)j쎐vf xwٸqC־s#L?r8 hWT6܍WB 7)1G `^w+*;-ʒ^NSS)be*j scaKJ{ Q-uLFi;.-AZg|B>NC c#,gܑ&4sWЏe][GOy|zxҥo&851 ,ssGz*|JSS+QCQ5sݜUtIHbХiu|Ҟ6%G8%sdqOQ_,6tmKiagym5Q?EW9}v#.(tY?KRPd\ѻh[ZHrUtGJ/hd7|.Xύb3H$h.+ .Ӽ)ƈ"Ppó2B j&ct@ ᧮Zju)}"hHy>~3Ě9gN:X*f#H)46xPFZJUQhau\_ ؜u<@^vN.h_n_Sg尪{{z/#Ȟ'y"otojΩxr]^eBrhmOG#H\oϣbgqx$Rl)RsVui0Cė}WͿ'bD1*|? @{R umkAA=uY])!WJK|pۓ(&:8Aܗ]+جSC\bU٩zU8&xYR`8KFɏ4Ye~UHH(}C#_>~tb`(~kVɞbx9,ѧg4$pH 2-o^82* Xe+ i'r}2 魍pNuJJ?Js/Hf>(jc hbZ0 6kw<ܞ#?,)oh%yCq3 ѱ F7j5(l5N m27$51gqF)R(TyOU>Ytc)05)"j]o w{/}}E9gXTkC%}N=EJH&rURS+ۊ=?2Xt(~sQ;h*j^AHZy[OGH5,n&Xz37NOSh nIJ#cBlU ^6X&'?X֔VY툠loǂԧ8j}]PKgξn/sckw sVȩq)3NEdqaMmX'tku!TKn"e#稐e(517{{d#EGopC'{w B%1&%08wT É:?ALfV&mHEWD |׌jcvZF[“Ѿy+A,e0(Fmy{I@#wleG,%v[RrsQԵ;ʻהPU_2#%(eaY(yn#K,;LHe)ea'N*%'@.Zqρ'8;K 8,.o`jpF-+!SQHɈ ʜ (ŰՒK%d#:Uc0c#P, UGꫠe;%F74eǻ3eՕ_W dγXƓ]d1fJJRs8_p:CPYݾ{zJiOAݢ> Jh0YXrcZl4sVrά(SG]Cn>*Kq{Xw޽CUYME(Z7NÌqz$n j/[31##n:Eԥjv⭕ NN`^FlLmB/_N*$t#DG.5;yq8Qz C tԲBH񆞵Xf.:uy[lo%qj}rp:ZO$p]ufM#=[apU5|3RGn ! 7M旼w$KH#ےO`3;v6w )nvQM618Ɵ)р714wڊAH m8=Ncm3I|pjZE%x/$} .q IUs9FW؎E{;djfvr 63OMeyWl8wc;Z~ճfeN*w{ lăQupe˾ж\ d&'5iӒg+nAX4!J9|x&IӀKpV'̘ 9cI& fp3f3hq Y<[ ]l3Ki5=ڮG{? ]hH%XM/j$9rH."kFM'1XDoUd 0}d#ޔzy lj⏩q⦜"=DCH5l@GԴ%0YԎj1G&!> '@V;dEII#l2=?H{MuN0s5ct]H&c٪$n|cs^kewC(,TT t 6jP^#&8h lu. #{cx^ {z/:dYek8ztS#ڼJlfr_aisz蔴quTA=A'"j';ίf/=sνDd6V%} 0PS ~.0PQlxmQgcm|8$nqiP vLStXVz;okϩzsHpx:'i_ 6p7 ijxEZu#t٧=RI4t0콐kab( V\*&itr7[C$hG|}kgm:٧p-s7jP89XOnXdhԧJ qۼzp<[-y`dEY[ޙH2; Ghi([f#召Ījp6lmeo,t1:q.6cGzNN EF+U5&n:-j1rDܯGأllh-`qJ+)9= 9ZImRц(+j1,dKKjl6wd37E&xùuh AA&3ѲF{AAsog6Xmyq3OP .C=mL=ݶ!zש υm 1l5й\< <.BIVAZښHd~f 'fb[p Sq$y_ 4 /,틿.S9ybZzN6T``P_bU5k/It-W4\Mp]%IQ'ROM)ٖݾYps؎|umeX3iQܱ%y k֋0mvÉ1(s}#UƱ>S1eҽ <(ۊI cG*_a6û^%E2.$wcbĄ٭4-vZJ!Z/+v%䨫vw01k@@KtDM+ӧF8<%{eFOjW G^fX8(iefe` GԿ$//S d}޵S%f H!ZѺ&jKi,D)䔃Q)SX(܃1^dǚ75n˄#.,Eucb2 K?i&`9rS4t:m5 v[UK=ǡRv.snfzLf-K1+/S= UGLoVGީ}B4Ǥ[G:<[B]ޒGxlI?j:YcGޠ7oʨ$4@ wU/OvL{/à&6UҶ+Ytt6J`y?5&=K֛^'%0<ۧ% m @A h{i\JُцO^B+8yQ8RgZ\iM=UfܡlqLbU2/Ӱ܄U{UT&H&FXκ2]4ݚzG9>YtF887ϫ3JYBAYpAAA#A4@4#AAAAAN WH؝I7ҳ*GVT8GF]7*t=tzm5*g+ۼ{, M䜲zcMPbjxBț!d ț#VTRbțY %F#3dnnNheKl5b{"B2 Y O!,aP2Lc5KϥEit7HoeϦ}8P/hhV]97B{'0o-m)%@ 3Lߒzݲ#HGQh4]'kO\׊ eN;IV-az3uܸm[]EvHGҸLmH}ғy<]bNQ#V~2uhLd抚bn59z5LZ|Im7,ѺƺA)sΚA         " .6~ї]r6C}aeo[WacqҿcokVPV0Z˻brgӓqGF5DkH,s2VTyJ$?%$Jx;R,,_1'֍ߤ> >R)HuR;K`eqI51*Pv}73c{%v$5kRMsbJ7OI}6j<  @` &'Dzrn>t}NJaウecfI#+ğD5%t"7 c?qF)j |TѺ/]J함́xkO.m%-uG8-S㧣|5aKim cm_&=fl?k[A53~n^Q:F " r<&spIDC  \^ 8x6)D)q7d-29O ɌBXN@#}oѾ&!1i[uB@}L[~}о 1CX7ݼ ׸dfoR5s}_gE'e*;dztryh(][R7ƶWLR܃r}.t̺芰d ]บ*[ڛ;%,d ]ɕ3bG %AAAB!dAU۱::r>LJb2l$*sQ\26cY v3Wuk)Q6KP_-oI4+mb ݢ:v3O7v׃H5MG.ya6 ?mGR-~*<OOoZ6¦'-h ~%cXsMP$pN-aYxU 4xGm1F͒t/Uө%E3VnᯃKy%8'܇oQ CԝʆT^*w"agM>!FMdj~JVǻ> $!m;׈>v#d4k ^MZ׵=\ w̺}3oНo x"69+oG~AOҖM{Tuw,C?&0J@Ii'߉Lge_:yŰru3Lkg?Ix7ס,4_UF#4$9u]-`ԣԲtΊ띈ty{>C -!m+t)_M`v`jq83H漼Q=e2.])d6   K\5\-  3 4| $sn@,{o+1H%m@f\E|NsY-sGWe| jGۇuzll֢p{~Żj<qjMqW-鮡V`;d=xj$Sq-iFF>nN]mh!//rpK >&Ƭ,5+" ۹Zl܆TDEbSB2-rʞX eB^'4d2#*R0qCg49CI`Q$+* #dc/ur OW{ި]5n3!OWSMDZsCAxg8.lG,ɉW46LǴ{QQes~Qh,YKfV9֡9`urG&Ogv:ڪXKÏد%g䐻ܬ^|,|Q58Yɬ2 j4hcäP- u#sg=VR:j{:.>(NK\UxIYvrqn?tї:ϱr ~ έKmqUU8<~'3Ý q w&Ama6/'$qt5'|N.30S7Xve^֖@Zyc Q;XI^4mz[u(MWbmq {B7;@5!;WJ}B<9N4m+TYaһ + C_q {}@Pu]PXV-7-vW07%摕 3vJy=:W(QAmt{O=SnXA     0Ze08U4PG&fkâS  IHJx& y]u ZڦJzVxpI]: UH=Q0ܝh)8X%ݝq-MgT)oƝ sROHw:.G#vs+HzOHvG F% ˦72 o$].qZO-7:X^.UIDGrX"k+vx޵N;rT'sQK 9:fP4)>)Z*SjL8n;đKJ8gmSHĬN0/->Q?'B5GDE49{nDᩎa)O %σIG8P:J9ceȵJAW6Mʼ=[JM0z jXֿz bu|xd3lur G0^zf4_O8^vүe⪡tyM<2\կ+iFUgZ3%.Ix>F}4.o"eºFqR@eȵZ}WwJLtMvl_k|q5YUjٞ)כ\Oh!gz%0]E]$mCXڽ_EO82A(pmhY;{IcWQ;4m<՗AF4@@@@@@@8Nyncoq]KVĶ?-&;7X|h`ͮR,Dp%e,]MDG+"pgQ-U6We~>OI% u _O'r7+Tk,zr򊱻TVCZ 6_UZ5bRX ʲ6VK GnȬ { !dDy; ءH6PȞʆT aeOX!f@l3 ohz'rO4ou :,#^YJr-yhvgub^4`lܸzh,s}$_޴V#cJXZuk؛}A};,F8,Ն(]V K3D5=j$Iۊ/#6Tb(/7.ܑ˥o) %t%6xΈ9q L$\ux -:^Ύ>7Yݽhp6ɥ7'[f(sxBI  G9= QSA ̱ 9USNa _hlH%OE،9fIzۀ/oش_$27fζSRATJ;[rAhmH6vML{n7W͸5{qr!;{_]B׽dȉW^ugOab_b< Oho_{˟cVM R!`'GSqrI 5QӸp~ʮcd2 8r6 Ή(m w~=8}|'֡d.,AAAAAAAhIM'mf*FGNr \ovM>lw\?Gto9 BjN|xzL™YVDLUTŅGX;\-bVVD|f+m3 [ *Mâ;1 ua?T.WEr2e<-*v@%3$ѾV ww c '8dkb} ((m5$GC WqUb-SQbV}rXw8.XoP:yDk} U-laѐ{MZ,mwY9K\܂#\y#Z M͠ %?{s|җշH?d4e;No$yKGccJxFi5# GrFmls(Lx'*Qs()9PGl7_ KI<#QZCTlAs,qe{u]>R+Rg$ۖ_z* qV-ß$}:خᤵeУ*RdZ7p*lY%+/UUD!F֝I+;v")AZxbQ 8K+W=EG)͐[N|9-kn`qJin8<5T_vf?j0g*JNab-/GUTEII%L68rWi*NI-,J6jmמrAKְpmQ_l5.9\?4nZȨ1]⫱zوʼnuB(4-~V+%?_Sk 8=6QҬOj2zNfۏ2E3T7ԢadoR|<ӕ^fy/"c7R(OOfDlw\ck1hQSb#~vSu/Fjт%mWJx˅2)typ9,XeMC*qZ:l(40::8׊ss8w=JsxKET iʙ vE%G˖W6Y+x2huǞKd:k,mcuqn9pUJqNRT7^jD~.YQ)1UaECƇlcB$e!Vc4ƺ8ܡa89WMՎ-hu]\GoETW4g|P oGzkNIE܏ֻQ?,z 'btsǫ)?L'$l8OЋO_ܟ/j}04[L?z䃰t|*$uJLXgŵzםP6prt}*'ԏAjŸNAK:?\$j͆d0<=V #DkQ?pdk~܋x?2xqGh橆 =Po$b"ەo4>(~ q\l’y2-1:@,)M:nmϽPxUJ]{h ĽOu`y{KE&E009*G诰Nq|> cg>Z6RLyE,+Hh>#)) cÛcs{%4a# :%%͎Y.fշ£E ,u7*[޵c>|Gumޢ6,V`-) #ujdpt}Vґ,(! Δ툎fW4{}./-{H M^0gꪤEX'{]7K;Mڕ'.$]llR)bzCnPSm5udIdR3^ Q5lVI ZjεPtҹ37rGO& P1l5gVu\yC9"lhVqגRS6&MqOžI7TN.j|~v ʲgS9i.?$L_}qwq+YIE@17))}6ЕY?%$4(1ZŮauF@LٮYSrk^H!+n0H/5F2g1GVx9EN3en1 [}y,v;e'Nԣ13ռS0LNK%KI*hb{o<1ʈw0Ph.it,u=6˚ Z:xִ$GE.|I;VX~0(Qu2+io]]ܩqYPG>VhޯUbC&nuCj%:y>pl/Ut Qٜ3%o-bj:xA=wMËA, .PyUr5eDn5u`n#@}JvUmhc}{gm-V#1]֋ JZ(Fqi[P$ W<\z.mCJؘ-,t\ژw2ZQEK#i[ lUUEH>`8hT|s뤢(DءtB)]QOB:cyׇLűjFһB;CCXKaݬ ys-(7:KQQCI2|78[Q{@7?5ђ6+o J!Mƿhv뒔p\GˣQ26w?HlCv~g{Gvػ(fI";3[;l7E5s3[͞I;5\>g觺 n=g}.7 ~Sd"?6cs\UȬ]uum7J.ИdJ XrzO#\hX8n[_EU+pt:&8p܄ȸZVW+mԪ1ΉX]U$30]DSDIϝMZq\KZ>&:a;s}}ʶaBKH47]ж8$~yUTu2#&dj3;datnhʈRU>l%'@烨 4pWOETښV5m{WOTFXu2+7#50TyXn QQLc r[8B\l<7WO n lՌnsx~H5ԕb8X.L 8raRASΏ=}i偆C;E!,?)7Un-oO yQ0*F*.& {a ׶` zEXQ5&n9C5mPb7=+TXg?tH&WV |I"ĺ1GHm{Gi*Iy#atU]i(NXϔδp_u5 rbn5U٩؛4/7[-=ѤhdQ`[?MnKkB`i}^Ks f,۴Ct~CϢ`@J620Xn7;ɬ$q*'51ȵ!9vp8.)}/Ze.';DhCa~JaQ&1Z,⑺zsD#m٧fJhń߽G#XöStNkᘹֹ)gg괎Y"gyMg·mZeFRIjr*z,o`E]GNj; YHd|N )(Δ x(h2:+ B#gȄJ^2TG,+~d|Utr"|Wgu5-MΣkH׽AeoASbmspku'06 j3N*1ZA2(`kECH];8Vu,&_R񳘈!]u4iE`hbEYu/K= o}.>8Kx{XY󺚶t#Ν>6gV@w.~w0|`/KN%퀘w #ɐ:,pkXܦ@Eoj+:f 1<ʹ'a* W!i>NtT.ik\xF:{Իp[xEMيG5GꋩQ4 ,+74} |NQKjQI.qȧR;ibF dgHB("|i]%;8$o.kfӹ8&SN;K+bG .7L5G}pq A_\$KhSDͷ#t:1_\"8U ,ŏ#FlKm*)0q}`XqW@&3֋Øp?ZDY]8?ZI 1؀h;MSXQI;WkT2'f}CA,QIO=h bJ b,Fw/a|,[Jmx'r9#hzSEh ?9+;>CR?=~ I(\2ı^wDp|0e *W/>Y')eRiG$a1VI9Zya+Ʉ5"ngʫkڏڌk)>WW|R|!'/j$a*j1Hv5_w?5&-4bU^JUb#܏lŢSFiqzcI5=db옏Ow&|"HxE5-Pd*~yɉ|w~kN$CMv1Uw!|jwfGkjhJUgb~w`Of$uwV|U}w~? ;Po-h*WC5_w(."Hهma5dU~<U(E#i).gvj#( HA ߀~~'~#Tw/<xB@w#f.ƺq?W_ڈ/F}q?LPQ?(xBN^!'/j6bCg?2z?I#x{Qmf9 >w% |L,OiDK5PT.'4F^g֖d=BO}ien55rs>FK_1FXhZ:/}AATv>qA<rest-client-1.6.7/spec/integration_spec.rb0000644000004100000410000000232611632430106020621 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') require 'webmock/rspec' include WebMock describe RestClient do it "a simple request" do body = 'abc' stub_request(:get, "www.example.com").to_return(:body => body, :status => 200) response = RestClient.get "www.example.com" response.code.should == 200 response.body.should == body end it "a simple request with gzipped content" do stub_request(:get, "www.example.com").with(:headers => { 'Accept-Encoding' => 'gzip, deflate' }).to_return(:body => "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000", :status => 200, :headers => { 'Content-Encoding' => 'gzip' } ) response = RestClient.get "www.example.com" response.code.should == 200 response.body.should == "i'm gziped\n" end it "a 404" do body = "Ho hai ! I'm not here !" stub_request(:get, "www.example.com").to_return(:body => body, :status => 404) begin RestClient.get "www.example.com" raise rescue RestClient::ResourceNotFound => e e.http_code.should == 404 e.response.code.should == 404 e.response.body.should == body e.http_body.should == body end end endrest-client-1.6.7/spec/raw_response_spec.rb0000644000004100000410000000072311632430106021004 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') describe RestClient::RawResponse do before do @tf = mock("Tempfile", :read => "the answer is 42", :open => true) @net_http_res = mock('net http response') @response = RestClient::RawResponse.new(@tf, @net_http_res, {}) end it "behaves like string" do @response.to_s.should == 'the answer is 42' end it "exposes a Tempfile" do @response.file.should == @tf end end rest-client-1.6.7/spec/payload_spec.rb0000644000004100000410000001773311632430106017737 0ustar www-datawww-datarequire File.join(File.dirname(File.expand_path(__FILE__)), 'base') describe RestClient::Payload do context "A regular Payload" do it "should use standard enctype as default content-type" do RestClient::Payload::UrlEncoded.new({}).headers['Content-Type']. should == 'application/x-www-form-urlencoded' end it "should form properly encoded params" do RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s. should == "foo=bar" ["foo=bar&baz=qux", "baz=qux&foo=bar"].should include( RestClient::Payload::UrlEncoded.new({:foo => 'bar', :baz => 'qux'}).to_s) end it "should escape parameters" do RestClient::Payload::UrlEncoded.new({'foo ' => 'bar'}).to_s. should == "foo%20=bar" end it "should properly handle hashes as parameter" do RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s. should == "foo[bar]=baz" RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s. should == "foo[bar][baz]=qux" end it "should handle many attributes inside a hash" do parameters = RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz', :baz => 'qux'}}).to_s parameters.should include("foo[bar]=baz", "foo[baz]=qux") end it "should handle attributes inside a an array inside an hash" do parameters = RestClient::Payload::UrlEncoded.new({"foo" => [{"bar" => 'baz'}, {"bar" => 'qux'}]}).to_s parameters.should include("foo[bar]=baz", "foo[bar]=qux") end it "should handle attributes inside a an array inside an array inside an hash" do parameters = RestClient::Payload::UrlEncoded.new({"foo" => [[{"bar" => 'baz'}, {"bar" => 'qux'}]]}).to_s parameters.should include("foo[bar]=baz", "foo[bar]=qux") end it "should form properly use symbols as parameters" do RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s. should == "foo=bar" RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s. should == "foo[bar]=baz" end it "should properly handle arrays as repeated parameters" do RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s. should == "foo[]=bar" RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s. should == "foo[]=bar&foo[]=baz" end it 'should not close if stream already closed' do p = RestClient::Payload::UrlEncoded.new({'foo ' => 'bar'}) 3.times {p.close} end end context "A multipart Payload" do it "should use standard enctype as default content-type" do m = RestClient::Payload::Multipart.new({}) m.stub!(:boundary).and_return(123) m.headers['Content-Type'].should == 'multipart/form-data; boundary=123' end it 'should not error on close if stream already closed' do m = RestClient::Payload::Multipart.new(:file => File.new(File.join(File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg'))) 3.times {m.close} end it "should form properly separated multipart data" do m = RestClient::Payload::Multipart.new([[:bar, "baz"], [:foo, "bar"]]) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; name="bar"\r \r baz\r --#{m.boundary}\r Content-Disposition: form-data; name="foo"\r \r bar\r --#{m.boundary}--\r EOS end it "should not escape parameters names" do m = RestClient::Payload::Multipart.new([["bar ", "baz"]]) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; name="bar "\r \r baz\r --#{m.boundary}--\r EOS end it "should form properly separated multipart data" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") m = RestClient::Payload::Multipart.new({:foo => f}) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; name="foo"; filename="master_shake.jpg"\r Content-Type: image/jpeg\r \r #{IO.read(f.path)}\r --#{m.boundary}--\r EOS end it "should ignore the name attribute when it's not set" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") m = RestClient::Payload::Multipart.new({nil => f}) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; filename="master_shake.jpg"\r Content-Type: image/jpeg\r \r #{IO.read(f.path)}\r --#{m.boundary}--\r EOS end it "should detect optional (original) content type and filename" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") f.instance_eval "def content_type; 'text/plain'; end" f.instance_eval "def original_filename; 'foo.txt'; end" m = RestClient::Payload::Multipart.new({:foo => f}) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; name="foo"; filename="foo.txt"\r Content-Type: text/plain\r \r #{IO.read(f.path)}\r --#{m.boundary}--\r EOS end it "should handle hash in hash parameters" do m = RestClient::Payload::Multipart.new({:bar => {:baz => "foo"}}) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; name="bar[baz]"\r \r foo\r --#{m.boundary}--\r EOS f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") f.instance_eval "def content_type; 'text/plain'; end" f.instance_eval "def original_filename; 'foo.txt'; end" m = RestClient::Payload::Multipart.new({:foo => {:bar => f}}) m.to_s.should == <<-EOS --#{m.boundary}\r Content-Disposition: form-data; name="foo[bar]"; filename="foo.txt"\r Content-Type: text/plain\r \r #{IO.read(f.path)}\r --#{m.boundary}--\r EOS end end context "streamed payloads" do it "should properly determine the size of file payloads" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") payload = RestClient::Payload.generate(f) payload.size.should == 22_545 payload.length.should == 22_545 end it "should properly determine the size of other kinds of streaming payloads" do s = StringIO.new 'foo' payload = RestClient::Payload.generate(s) payload.size.should == 3 payload.length.should == 3 begin f = Tempfile.new "rest-client" f.write 'foo bar' payload = RestClient::Payload.generate(f) payload.size.should == 7 payload.length.should == 7 ensure f.close end end end context "Payload generation" do it "should recognize standard urlencoded params" do RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded) end it "should recognize multipart params" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") RestClient::Payload.generate({"foo" => f}).should be_kind_of(RestClient::Payload::Multipart) end it "should be multipart if forced" do RestClient::Payload.generate({"foo" => "bar", :multipart => true}).should be_kind_of(RestClient::Payload::Multipart) end it "should return data if no of the above" do RestClient::Payload.generate("data").should be_kind_of(RestClient::Payload::Base) end it "should recognize nested multipart payloads in hashes" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") RestClient::Payload.generate({"foo" => {"file" => f}}).should be_kind_of(RestClient::Payload::Multipart) end it "should recognize nested multipart payloads in arrays" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") RestClient::Payload.generate({"foo" => [f]}).should be_kind_of(RestClient::Payload::Multipart) end it "should recognize file payloads that can be streamed" do f = File.new(File.dirname(__FILE__) + "/master_shake.jpg") RestClient::Payload.generate(f).should be_kind_of(RestClient::Payload::Streamed) end it "should recognize other payloads that can be streamed" do RestClient::Payload.generate(StringIO.new('foo')).should be_kind_of(RestClient::Payload::Streamed) end end end rest-client-1.6.7/spec/response_spec.rb0000644000004100000410000002267511632430106020145 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') require 'webmock/rspec' include WebMock describe RestClient::Response do before do @net_http_res = mock('net http response', :to_hash => {"Status" => ["200 OK"]}, :code => 200) @request = mock('http request', :user => nil, :password => nil) @response = RestClient::Response.create('abc', @net_http_res, {}) end it "behaves like string" do @response.should.to_s == 'abc' @response.to_str.should == 'abc' @response.to_i.should == 200 end it "accepts nil strings and sets it to empty for the case of HEAD" do RestClient::Response.create(nil, @net_http_res, {}).should.to_s == "" end it "test headers and raw headers" do @response.raw_headers["Status"][0].should == "200 OK" @response.headers[:status].should == "200 OK" end describe "cookie processing" do it "should correctly deal with one Set-Cookie header with one cookie inside" do net_http_res = mock('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT"]}) response = RestClient::Response.create('abc', net_http_res, {}) response.headers[:set_cookie].should == ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT"] response.cookies.should == { "main_page" => "main_page_no_rewrite" } end it "should correctly deal with multiple cookies [multiple Set-Cookie headers]" do net_http_res = mock('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT", "remember_me=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT", "user=somebody; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"]}) response = RestClient::Response.create('abc', net_http_res, {}) response.headers[:set_cookie].should == ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT", "remember_me=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT", "user=somebody; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"] response.cookies.should == { "main_page" => "main_page_no_rewrite", "remember_me" => "", "user" => "somebody" } end it "should correctly deal with multiple cookies [one Set-Cookie header with multiple cookies]" do net_http_res = mock('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT, remember_me=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT, user=somebody; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"]}) response = RestClient::Response.create('abc', net_http_res, {}) response.cookies.should == { "main_page" => "main_page_no_rewrite", "remember_me" => "", "user" => "somebody" } end end describe "exceptions processing" do it "should return itself for normal codes" do (200..206).each do |code| net_http_res = mock('net http response', :code => '200') response = RestClient::Response.create('abc', net_http_res, {}) response.return! @request end end it "should throw an exception for other codes" do RestClient::Exceptions::EXCEPTIONS_MAP.each_key do |code| unless (200..207).include? code net_http_res = mock('net http response', :code => code.to_i) response = RestClient::Response.create('abc', net_http_res, {}) lambda { response.return!}.should raise_error end end end end describe "redirection" do it "follows a redirection when the request is a get" do stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'}) stub_request(:get, 'http://new/resource').to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :get).body.should == 'Foo' end it "follows a redirection and keep the parameters" do stub_request(:get, 'http://foo:bar@some/resource').with(:headers => {'Accept' => 'application/json'}).to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'}) stub_request(:get, 'http://foo:bar@new/resource').with(:headers => {'Accept' => 'application/json'}).to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :user => 'foo', :password => 'bar', :headers => {:accept => :json}).body.should == 'Foo' end it "follows a redirection and keep the cookies" do stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Set-Cookie' => CGI::Cookie.new('Foo', 'Bar'), 'Location' => 'http://new/resource', }) stub_request(:get, 'http://new/resource').with(:headers => {'Cookie' => 'Foo=Bar'}).to_return(:body => 'Qux') RestClient::Request.execute(:url => 'http://some/resource', :method => :get).body.should == 'Qux' end it "doesn't follow a 301 when the request is a post" do net_http_res = mock('net http response', :code => 301) response = RestClient::Response.create('abc', net_http_res, {:method => :post}) lambda { response.return!(@request)}.should raise_error(RestClient::MovedPermanently) end it "doesn't follow a 302 when the request is a post" do net_http_res = mock('net http response', :code => 302) response = RestClient::Response.create('abc', net_http_res, {:method => :post}) lambda { response.return!(@request)}.should raise_error(RestClient::Found) end it "doesn't follow a 307 when the request is a post" do net_http_res = mock('net http response', :code => 307) response = RestClient::Response.create('abc', net_http_res, {:method => :post}) lambda { response.return!(@request)}.should raise_error(RestClient::TemporaryRedirect) end it "doesn't follow a redirection when the request is a put" do net_http_res = mock('net http response', :code => 301) response = RestClient::Response.create('abc', net_http_res, {:method => :put}) lambda { response.return!(@request)}.should raise_error(RestClient::MovedPermanently) end it "follows a redirection when the request is a post and result is a 303" do stub_request(:put, 'http://some/resource').to_return(:body => '', :status => 303, :headers => {'Location' => 'http://new/resource'}) stub_request(:get, 'http://new/resource').to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :put).body.should == 'Foo' end it "follows a redirection when the request is a head" do stub_request(:head, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'}) stub_request(:head, 'http://new/resource').to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :head).body.should == 'Foo' end it "handles redirects with relative paths" do stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'index'}) stub_request(:get, 'http://some/index').to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :get).body.should == 'Foo' end it "handles redirects with relative path and query string" do stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'index?q=1'}) stub_request(:get, 'http://some/index?q=1').to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :get).body.should == 'Foo' end it "follow a redirection when the request is a get and the response is in the 30x range" do stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'}) stub_request(:get, 'http://new/resource').to_return(:body => 'Foo') RestClient::Request.execute(:url => 'http://some/resource', :method => :get).body.should == 'Foo' end it "follows no more than 10 redirections before raising error" do stub_request(:get, 'http://some/redirect-1').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'}) stub_request(:get, 'http://some/redirect-2').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'}) lambda { RestClient::Request.execute(:url => 'http://some/redirect-1', :method => :get) }.should raise_error(RestClient::MaxRedirectsReached) WebMock.should have_requested(:get, 'http://some/redirect-2').times(10) end it "follows no more than max_redirects redirections, if specified" do stub_request(:get, 'http://some/redirect-1').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'}) stub_request(:get, 'http://some/redirect-2').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'}) lambda { RestClient::Request.execute(:url => 'http://some/redirect-1', :method => :get, :max_redirects => 5) }.should raise_error(RestClient::MaxRedirectsReached) WebMock.should have_requested(:get, 'http://some/redirect-2').times(5) end end end rest-client-1.6.7/spec/resource_spec.rb0000644000004100000410000001252211632430106020124 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') require 'webmock/rspec' include WebMock describe RestClient::Resource do before do @resource = RestClient::Resource.new('http://some/resource', :user => 'jane', :password => 'mypass', :headers => {'X-Something' => '1'}) end context "Resource delegation" do it "GET" do RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass') @resource.get end it "HEAD" do RestClient::Request.should_receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass') @resource.head end it "POST" do RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass') @resource.post 'abc', :content_type => 'image/jpg' end it "PUT" do RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass') @resource.put 'abc', :content_type => 'image/jpg' end it "PATCH" do RestClient::Request.should_receive(:execute).with(:method => :patch, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass') @resource.patch 'abc', :content_type => 'image/jpg' end it "DELETE" do RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass') @resource.delete end it "overrides resource headers" do RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '2'}, :user => 'jane', :password => 'mypass') @resource.get 'X-Something' => '2' end end it "can instantiate with no user/password" do @resource = RestClient::Resource.new('http://some/resource') end it "is backwards compatible with previous constructor" do @resource = RestClient::Resource.new('http://some/resource', 'user', 'pass') @resource.user.should == 'user' @resource.password.should == 'pass' end it "concatenates urls, inserting a slash when it needs one" do @resource.concat_urls('http://example.com', 'resource').should == 'http://example.com/resource' end it "concatenates urls, using no slash if the first url ends with a slash" do @resource.concat_urls('http://example.com/', 'resource').should == 'http://example.com/resource' end it "concatenates urls, using no slash if the second url starts with a slash" do @resource.concat_urls('http://example.com', '/resource').should == 'http://example.com/resource' end it "concatenates even non-string urls, :posts + 1 => 'posts/1'" do @resource.concat_urls(:posts, 1).should == 'posts/1' end it "offers subresources via []" do parent = RestClient::Resource.new('http://example.com') parent['posts'].url.should == 'http://example.com/posts' end it "transports options to subresources" do parent = RestClient::Resource.new('http://example.com', :user => 'user', :password => 'password') parent['posts'].user.should == 'user' parent['posts'].password.should == 'password' end it "passes a given block to subresources" do block = Proc.new{|r| r} parent = RestClient::Resource.new('http://example.com', &block) parent['posts'].block.should == block end it "the block should be overrideable" do block1 = Proc.new{|r| r} block2 = Proc.new{|r| r} parent = RestClient::Resource.new('http://example.com', &block1) # parent['posts', &block2].block.should == block2 # ruby 1.9 syntax parent.send(:[], 'posts', &block2).block.should == block2 end it "the block should be overrideable in ruby 1.9 syntax" do block = Proc.new{|r| r} parent = RestClient::Resource.new('http://example.com', &block) r19_syntax = %q{ parent['posts', &->(r){r}].block.should_not == block } if is_ruby_19? eval(r19_syntax) end end it "prints its url with to_s" do RestClient::Resource.new('x').to_s.should == 'x' end describe 'block' do it 'can use block when creating the resource' do stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404) resource = RestClient::Resource.new('www.example.com') { |response, request| 'foo' } resource.get.should == 'foo' end it 'can use block when executing the resource' do stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404) resource = RestClient::Resource.new('www.example.com') resource.get { |response, request| 'foo' }.should == 'foo' end it 'execution block override resource block' do stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404) resource = RestClient::Resource.new('www.example.com') { |response, request| 'foo' } resource.get { |response, request| 'bar' }.should == 'bar' end end end rest-client-1.6.7/spec/abstract_response_spec.rb0000644000004100000410000000603311632430106022016 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') describe RestClient::AbstractResponse do class MyAbstractResponse include RestClient::AbstractResponse attr_accessor :size def initialize net_http_res, args @net_http_res = net_http_res @args = args end end before do @net_http_res = mock('net http response') @response = MyAbstractResponse.new(@net_http_res, {}) end it "fetches the numeric response code" do @net_http_res.should_receive(:code).and_return('200') @response.code.should == 200 end it "has a nice description" do @net_http_res.should_receive(:to_hash).and_return({'Content-Type' => ['application/pdf']}) @net_http_res.should_receive(:code).and_return('200') @response.description == '200 OK | application/pdf bytes\n' end it "beautifies the headers by turning the keys to symbols" do h = RestClient::AbstractResponse.beautify_headers('content-type' => [ 'x' ]) h.keys.first.should == :content_type end it "beautifies the headers by turning the values to strings instead of one-element arrays" do h = RestClient::AbstractResponse.beautify_headers('x' => [ 'text/html' ] ) h.values.first.should == 'text/html' end it "fetches the headers" do @net_http_res.should_receive(:to_hash).and_return('content-type' => [ 'text/html' ]) @response.headers.should == { :content_type => 'text/html' } end it "extracts cookies from response headers" do @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/']) @response.cookies.should == { 'session_id' => '1' } end it "extract strange cookies" do @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/']) @response.cookies.should == { 'session_id' => 'ZJ%2FHQVH6YE+rVkTpn0zvTQ%3D%3D' } end it "doesn't escape cookies" do @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/']) @response.cookies.should == { 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' } end it "can access the net http result directly" do @response.net_http_res.should == @net_http_res end describe "#return!" do it "should return the response itself on 200-codes" do @net_http_res.should_receive(:code).and_return('200') @response.return!.should be_equal(@response) end it "should raise RequestFailed on unknown codes" do @net_http_res.should_receive(:code).and_return('1000') lambda { @response.return! }.should raise_error RestClient::RequestFailed end it "should raise an error on a redirection after non-GET/HEAD requests" do @net_http_res.should_receive(:code).and_return('301') @response.args.merge(:method => :put) lambda { @response.return! }.should raise_error RestClient::RequestFailed end end end rest-client-1.6.7/spec/integration/0000755000004100000410000000000011632430106017257 5ustar www-datawww-datarest-client-1.6.7/spec/integration/certs/0000755000004100000410000000000011632430106020377 5ustar www-datawww-datarest-client-1.6.7/spec/integration/certs/equifax.crt0000644000004100000410000000216711632430106022561 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 -----END CERTIFICATE----- rest-client-1.6.7/spec/integration/certs/verisign.crt0000644000004100000410000000150211632430106022735 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k -----END CERTIFICATE----- rest-client-1.6.7/spec/integration/request_spec.rb0000644000004100000410000000161411632430106022310 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), '../base') describe RestClient::Request do describe "ssl verification" do it "is successful with the correct ca_file" do request = RestClient::Request.new( :method => :get, :url => 'https://www.mozilla.com', :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "equifax.crt") ) expect { request.execute }.to_not raise_error end it "is unsuccessful with an incorrect ca_file" do request = RestClient::Request.new( :method => :get, :url => 'https://www.mozilla.com', :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt") ) expect { request.execute }.to raise_error(RestClient::SSLCertificateNotVerified) end end end rest-client-1.6.7/spec/request_spec.rb0000644000004100000410000005013511632430106017767 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') require 'webmock/rspec' include WebMock describe RestClient::Request do before do @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload') @uri = mock("uri") @uri.stub!(:request_uri).and_return('/resource') @uri.stub!(:host).and_return('some') @uri.stub!(:port).and_return(80) @net = mock("net::http base") @http = mock("net::http connection") Net::HTTP.stub!(:new).and_return(@net) @net.stub!(:start).and_yield(@http) @net.stub!(:use_ssl=) @net.stub!(:verify_mode=) RestClient.log = nil end it "accept */* mimetype, preferring xml" do @request.default_headers[:accept].should == '*/*; q=0.5, application/xml' end describe "compression" do it "decodes an uncompressed result body by passing it straight through" do RestClient::Request.decode(nil, 'xyz').should == 'xyz' end it "doesn't fail for nil bodies" do RestClient::Request.decode('gzip', nil).should be_nil end it "decodes a gzip body" do RestClient::Request.decode('gzip', "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000").should == "i'm gziped\n" end it "ingores gzip for empty bodies" do RestClient::Request.decode('gzip', '').should be_empty end it "decodes a deflated body" do RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363").should == "some deflated text" end end it "processes a successful result" do res = mock("result") res.stub!(:code).and_return("200") res.stub!(:body).and_return('body') res.stub!(:[]).with('content-encoding').and_return(nil) @request.process_result(res).body.should == 'body' @request.process_result(res).to_s.should == 'body' end it "doesn't classify successful requests as failed" do 203.upto(207) do |code| res = mock("result") res.stub!(:code).and_return(code.to_s) res.stub!(:body).and_return("") res.stub!(:[]).with('content-encoding').and_return(nil) @request.process_result(res).should be_empty end end it "parses a url into a URI object" do URI.should_receive(:parse).with('http://example.com/resource') @request.parse_url('http://example.com/resource') end it "adds http:// to the front of resources specified in the syntax example.com/resource" do URI.should_receive(:parse).with('http://example.com/resource') @request.parse_url('example.com/resource') end describe "user - password" do it "extracts the username and password when parsing http://user:password@example.com/" do URI.stub!(:parse).and_return(mock('uri', :user => 'joe', :password => 'pass1')) @request.parse_url_with_auth('http://joe:pass1@example.com/resource') @request.user.should == 'joe' @request.password.should == 'pass1' end it "extracts with escaping the username and password when parsing http://user:password@example.com/" do URI.stub!(:parse).and_return(mock('uri', :user => 'joe%20', :password => 'pass1')) @request.parse_url_with_auth('http://joe%20:pass1@example.com/resource') @request.user.should == 'joe ' @request.password.should == 'pass1' end it "doesn't overwrite user and password (which may have already been set by the Resource constructor) if there is no user/password in the url" do URI.stub!(:parse).and_return(mock('uri', :user => nil, :password => nil)) @request = RestClient::Request.new(:method => 'get', :url => 'example.com', :user => 'beth', :password => 'pass2') @request.parse_url_with_auth('http://example.com/resource') @request.user.should == 'beth' @request.password.should == 'pass2' end end it "correctly formats cookies provided to the constructor" do URI.stub!(:parse).and_return(mock('uri', :user => nil, :password => nil)) @request = RestClient::Request.new(:method => 'get', :url => 'example.com', :cookies => {:session_id => '1', :user_id => "someone" }) @request.should_receive(:default_headers).and_return({'Foo' => 'bar'}) @request.make_headers({}).should == { 'Foo' => 'bar', 'Cookie' => 'session_id=1; user_id=someone'} end it "determines the Net::HTTP class to instantiate by the method name" do @request.net_http_request_class(:put).should == Net::HTTP::Put end describe "user headers" do it "merges user headers with the default headers" do @request.should_receive(:default_headers).and_return({ :accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate' }) headers = @request.make_headers("Accept" => "application/json", :accept_encoding => 'gzip') headers.should have_key "Accept-Encoding" headers["Accept-Encoding"].should == "gzip" headers.should have_key "Accept" headers["Accept"].should == "application/json" end it "prefers the user header when the same header exists in the defaults" do @request.should_receive(:default_headers).and_return({ '1' => '2' }) headers = @request.make_headers('1' => '3') headers.should have_key('1') headers['1'].should == '3' end end describe "header symbols" do it "converts header symbols from :content_type to 'Content-Type'" do @request.should_receive(:default_headers).and_return({}) headers = @request.make_headers(:content_type => 'abc') headers.should have_key('Content-Type') headers['Content-Type'].should == 'abc' end it "converts content-type from extension to real content-type" do @request.should_receive(:default_headers).and_return({}) headers = @request.make_headers(:content_type => 'json') headers.should have_key('Content-Type') headers['Content-Type'].should == 'application/json' end it "converts accept from extension(s) to real content-type(s)" do @request.should_receive(:default_headers).and_return({}) headers = @request.make_headers(:accept => 'json, mp3') headers.should have_key('Accept') headers['Accept'].should == 'application/json, audio/mpeg' @request.should_receive(:default_headers).and_return({}) headers = @request.make_headers(:accept => :json) headers.should have_key('Accept') headers['Accept'].should == 'application/json' end it "only convert symbols in header" do @request.should_receive(:default_headers).and_return({}) headers = @request.make_headers({:foo_bar => 'value', "bar_bar" => 'value'}) headers['Foo-Bar'].should == 'value' headers['bar_bar'].should == 'value' end it "converts header values to strings" do @request.make_headers('A' => 1)['A'].should == '1' end end it "executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do @request.should_receive(:parse_url_with_auth).with('http://some/resource').and_return(@uri) klass = mock("net:http class") @request.should_receive(:net_http_request_class).with(:put).and_return(klass) klass.should_receive(:new).and_return('result') @request.should_receive(:transmit).with(@uri, 'result', kind_of(RestClient::Payload::Base)) @request.execute end it "transmits the request with Net::HTTP" do @http.should_receive(:request).with('req', 'payload') @request.should_receive(:process_result) @request.transmit(@uri, 'req', 'payload') end describe "payload" do it "sends nil payloads" do @http.should_receive(:request).with('req', nil) @request.should_receive(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', nil) end it "passes non-hash payloads straight through" do @request.process_payload("x").should == "x" end it "converts a hash payload to urlencoded data" do @request.process_payload(:a => 'b c+d').should == "a=b%20c%2Bd" end it "accepts nested hashes in payload" do payload = @request.process_payload(:user => { :name => 'joe', :location => { :country => 'USA', :state => 'CA' }}) payload.should include('user[name]=joe') payload.should include('user[location][country]=USA') payload.should include('user[location][state]=CA') end end it "set urlencoded content_type header on hash payloads" do @request.process_payload(:a => 1) @request.headers[:content_type].should == 'application/x-www-form-urlencoded' end describe "credentials" do it "sets up the credentials prior to the request" do @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.stub!(:user).and_return('joe') @request.stub!(:password).and_return('mypass') @request.should_receive(:setup_credentials).with('req') @request.transmit(@uri, 'req', nil) end it "does not attempt to send any credentials if user is nil" do @request.stub!(:user).and_return(nil) req = mock("request") req.should_not_receive(:basic_auth) @request.setup_credentials(req) end it "setup credentials when there's a user" do @request.stub!(:user).and_return('joe') @request.stub!(:password).and_return('mypass') req = mock("request") req.should_receive(:basic_auth).with('joe', 'mypass') @request.setup_credentials(req) end end it "catches EOFError and shows the more informative ServerBrokeConnection" do @http.stub!(:request).and_raise(EOFError) lambda { @request.transmit(@uri, 'req', nil) }.should raise_error(RestClient::ServerBrokeConnection) end it "class method execute wraps constructor" do req = mock("rest request") RestClient::Request.should_receive(:new).with(1 => 2).and_return(req) req.should_receive(:execute) RestClient::Request.execute(1 => 2) end describe "exception" do it "raises Unauthorized when the response is 401" do res = mock('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' ) lambda { @request.process_result(res) }.should raise_error(RestClient::Unauthorized) end it "raises ResourceNotFound when the response is 404" do res = mock('response', :code => '404', :[] => ['content-encoding' => ''], :body => '' ) lambda { @request.process_result(res) }.should raise_error(RestClient::ResourceNotFound) end it "raises RequestFailed otherwise" do res = mock('response', :code => '500', :[] => ['content-encoding' => ''], :body => '' ) lambda { @request.process_result(res) }.should raise_error(RestClient::InternalServerError) end end describe "block usage" do it "returns what asked to" do res = mock('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' ) @request.process_result(res){|response, request| "foo"}.should == "foo" end end describe "proxy" do it "creates a proxy class if a proxy url is given" do RestClient.stub!(:proxy).and_return("http://example.com/") @request.net_http_class.should include(Net::HTTP::ProxyDelta) end it "creates a non-proxy class if a proxy url is not given" do @request.net_http_class.should_not include(Net::HTTP::ProxyDelta) end end describe "logging" do it "logs a get request" do log = RestClient.log = [] RestClient::Request.new(:method => :get, :url => 'http://url').log_request log[0].should == %Q{RestClient.get "http://url", "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate"\n} end it "logs a post request with a small payload" do log = RestClient.log = [] RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').log_request log[0].should == %Q{RestClient.post "http://url", "foo", "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"3"\n} end it "logs a post request with a large payload" do log = RestClient.log = [] RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).log_request log[0].should == %Q{RestClient.post "http://url", 1000 byte(s) length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"1000"\n} end it "logs input headers as a hash" do log = RestClient.log = [] RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' }).log_request log[0].should == %Q{RestClient.get "http://url", "Accept"=>"text/plain", "Accept-Encoding"=>"gzip, deflate"\n} end it "logs a response including the status code, content type, and result body size in bytes" do log = RestClient.log = [] res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd') res.stub!(:[]).with('Content-type').and_return('text/html') @request.log_response res log[0].should == "# => 200 OK | text/html 4 bytes\n" end it "logs a response with a nil Content-type" do log = RestClient.log = [] res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd') res.stub!(:[]).with('Content-type').and_return(nil) @request.log_response res log[0].should == "# => 200 OK | 4 bytes\n" end it "logs a response with a nil body" do log = RestClient.log = [] res = mock('result', :code => '200', :class => Net::HTTPOK, :body => nil) res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8') @request.log_response res log[0].should == "# => 200 OK | text/html 0 bytes\n" end end it "strips the charset from the response content type" do log = RestClient.log = [] res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd') res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8') @request.log_response res log[0].should == "# => 200 OK | text/html 4 bytes\n" end describe "timeout" do it "set read_timeout" do @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123) @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @net.should_receive(:read_timeout=).with(123) @request.transmit(@uri, 'req', nil) end it "set open_timeout" do @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :open_timeout => 123) @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @net.should_receive(:open_timeout=).with(123) @request.transmit(@uri, 'req', nil) end end describe "ssl" do it "uses SSL when the URI refers to a https address" do @uri.stub!(:is_a?).with(URI::HTTPS).and_return(true) @net.should_receive(:use_ssl=).with(true) @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should default to not verifying ssl certificates" do @request.verify_ssl.should == false end it "should set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is false" do @net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE) @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should not set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is true" do @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true) @net.should_not_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE) @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should set net.verify_mode to the passed value if verify_ssl is an OpenSSL constant" do mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => mode ) @net.should_receive(:verify_mode=).with(mode) @net.should_receive(:verify_callback=) @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should default to not having an ssl_client_cert" do @request.ssl_client_cert.should be(nil) end it "should set the ssl_client_cert if provided" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload', :ssl_client_cert => "whatsupdoc!" ) @net.should_receive(:cert=).with("whatsupdoc!") @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should not set the ssl_client_cert if it is not provided" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload' ) @net.should_not_receive(:cert=).with("whatsupdoc!") @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should default to not having an ssl_client_key" do @request.ssl_client_key.should be(nil) end it "should set the ssl_client_key if provided" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload', :ssl_client_key => "whatsupdoc!" ) @net.should_receive(:key=).with("whatsupdoc!") @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should not set the ssl_client_key if it is not provided" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload' ) @net.should_not_receive(:key=).with("whatsupdoc!") @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should default to not having an ssl_ca_file" do @request.ssl_ca_file.should be(nil) end it "should set the ssl_ca_file if provided" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload', :ssl_ca_file => "Certificate Authority File" ) @net.should_receive(:ca_file=).with("Certificate Authority File") @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end it "should not set the ssl_ca_file if it is not provided" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload' ) @net.should_not_receive(:ca_file=).with("Certificate Authority File") @http.stub!(:request) @request.stub!(:process_result) @request.stub!(:response_log) @request.transmit(@uri, 'req', 'payload') end end it "should still return a response object for 204 No Content responses" do @request = RestClient::Request.new( :method => :put, :url => 'https://some/resource', :payload => 'payload' ) net_http_res = Net::HTTPNoContent.new("", "204", "No Content") net_http_res.stub!(:read_body).and_return(nil) @http.should_receive(:request).and_return(@request.fetch_body(net_http_res)) response = @request.transmit(@uri, 'req', 'payload') response.should_not be_nil response.code.should == 204 end end rest-client-1.6.7/spec/exceptions_spec.rb0000644000004100000410000000601711632430106020460 0ustar www-datawww-datarequire File.join( File.dirname(File.expand_path(__FILE__)), 'base') require 'webmock/rspec' include WebMock describe RestClient::Exception do it "returns a 'message' equal to the class name if the message is not set, because 'message' should not be nil" do e = RestClient::Exception.new e.message.should == "RestClient::Exception" end it "returns the 'message' that was set" do e = RestClient::Exception.new message = "An explicitly set message" e.message = message e.message.should == message end it "sets the exception message to ErrorMessage" do RestClient::ResourceNotFound.new.message.should == 'Resource Not Found' end it "contains exceptions in RestClient" do RestClient::Unauthorized.new.should be_a_kind_of(RestClient::Exception) RestClient::ServerBrokeConnection.new.should be_a_kind_of(RestClient::Exception) end end describe RestClient::ServerBrokeConnection do it "should have a default message of 'Server broke connection'" do e = RestClient::ServerBrokeConnection.new e.message.should == 'Server broke connection' end end describe RestClient::RequestFailed do before do @response = mock('HTTP Response', :code => '502') end it "stores the http response on the exception" do response = "response" begin raise RestClient::RequestFailed, response rescue RestClient::RequestFailed => e e.response.should == response end end it "http_code convenience method for fetching the code as an integer" do RestClient::RequestFailed.new(@response).http_code.should == 502 end it "http_body convenience method for fetching the body (decoding when necessary)" do RestClient::RequestFailed.new(@response).http_code.should == 502 RestClient::RequestFailed.new(@response).message.should == 'HTTP status code 502' end it "shows the status code in the message" do RestClient::RequestFailed.new(@response).to_s.should match(/502/) end end describe RestClient::ResourceNotFound do it "also has the http response attached" do response = "response" begin raise RestClient::ResourceNotFound, response rescue RestClient::ResourceNotFound => e e.response.should == response end end end describe "backwards compatibility" do it "alias RestClient::Request::Redirect to RestClient::Redirect" do RestClient::Request::Redirect.should == RestClient::Redirect end it "alias RestClient::Request::Unauthorized to RestClient::Unauthorized" do RestClient::Request::Unauthorized.should == RestClient::Unauthorized end it "alias RestClient::Request::RequestFailed to RestClient::RequestFailed" do RestClient::Request::RequestFailed.should == RestClient::RequestFailed end it "make the exception's response act like an Net::HTTPResponse" do body = "body" stub_request(:get, "www.example.com").to_return(:body => body, :status => 404) begin RestClient.get "www.example.com" raise rescue RestClient::ResourceNotFound => e e.response.body.should == body end end end rest-client-1.6.7/VERSION0000644000004100000410000000000611632430106015046 0ustar www-datawww-data1.6.6 rest-client-1.6.7/bin/0000755000004100000410000000000011632430106014552 5ustar www-datawww-datarest-client-1.6.7/bin/restclient0000755000004100000410000000341011632430106016652 0ustar www-datawww-data#!/usr/bin/env ruby $:.unshift File.dirname(__FILE__) + "/../lib" require 'rubygems' require 'restclient' require 'yaml' def usage(why = nil) puts "failed for reason: #{why}" if why puts "usage: restclient [get|put|post|delete] url|name [username] [password]" puts " The verb is optional, if you leave it off you'll get an interactive shell." puts " put and post both take the input body on stdin." exit(1) end POSSIBLE_VERBS = ['get', 'put', 'post', 'delete'] if POSSIBLE_VERBS.include? ARGV.first @verb = ARGV.shift else @verb = nil end @url = ARGV.shift || 'http://localhost:4567' config = YAML.load(File.read(ENV['HOME'] + "/.restclient")) rescue {} @url, @username, @password = if c = config[@url] [c['url'], c['username'], c['password']] else [@url, * ARGV] end usage("invalid url '#{@url}") unless @url =~ /^https?/ usage("too few args") unless ARGV.size < 3 def r @r ||= RestClient::Resource.new(@url, @username, @password) end r # force rc to load if @verb begin if %w( put post ).include? @verb puts r.send(@verb, STDIN.read) else puts r.send(@verb) end exit 0 rescue RestClient::Exception => e puts e.response.body if e.respond_to? :response raise end end POSSIBLE_VERBS.each do |m| eval <<-end_eval def #{m}(path, *args, &b) r[path].#{m}(*args, &b) end end_eval end def method_missing(s, * args, & b) if POSSIBLE_VERBS.include? s begin r.send(s, *args, & b) rescue RestClient::RequestFailed => e print STDERR, e.response.body raise e end else super end end require 'irb' require 'irb/completion' if File.exists? ".irbrc" ENV['IRBRC'] = ".irbrc" end if File.exists?(File.expand_path(rcfile = "~/.restclientrc")) load(rcfile) end ARGV.clear IRB.start exit! rest-client-1.6.7/metadata.yml0000644000004100000410000000667111632430106016317 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: rest-client version: !ruby/object:Gem::Version hash: 1 prerelease: segments: - 1 - 6 - 7 version: 1.6.7 platform: ruby authors: - Adam Wiggins - Julien Kirch autorequire: bindir: bin cert_chain: [] date: 2011-08-24 00:00:00 Z dependencies: - !ruby/object:Gem::Dependency name: mime-types prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 47 segments: - 1 - 16 version: "1.16" type: :runtime version_requirements: *id001 - !ruby/object:Gem::Dependency name: webmock prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 57 segments: - 0 - 9 - 1 version: 0.9.1 type: :development version_requirements: *id002 - !ruby/object:Gem::Dependency name: rspec prerelease: false requirement: &id003 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id003 description: "A simple HTTP and REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete." email: rest.client@librelist.com executables: - restclient extensions: [] extra_rdoc_files: - README.rdoc - history.md files: - README.rdoc - Rakefile - VERSION - bin/restclient - lib/rest-client.rb - lib/rest_client.rb - lib/restclient.rb - lib/restclient/abstract_response.rb - lib/restclient/exceptions.rb - lib/restclient/net_http_ext.rb - lib/restclient/payload.rb - lib/restclient/raw_response.rb - lib/restclient/request.rb - lib/restclient/resource.rb - lib/restclient/response.rb - spec/abstract_response_spec.rb - spec/base.rb - spec/exceptions_spec.rb - spec/integration/certs/equifax.crt - spec/integration/certs/verisign.crt - spec/integration/request_spec.rb - spec/integration_spec.rb - spec/master_shake.jpg - spec/payload_spec.rb - spec/raw_response_spec.rb - spec/request2_spec.rb - spec/request_spec.rb - spec/resource_spec.rb - spec/response_spec.rb - spec/restclient_spec.rb - history.md homepage: http://github.com/archiloque/rest-client licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: rubygems_version: 1.8.5 signing_key: specification_version: 3 summary: Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions. test_files: - spec/abstract_response_spec.rb - spec/base.rb - spec/exceptions_spec.rb - spec/integration/certs/equifax.crt - spec/integration/certs/verisign.crt - spec/integration/request_spec.rb - spec/integration_spec.rb - spec/master_shake.jpg - spec/payload_spec.rb - spec/raw_response_spec.rb - spec/request2_spec.rb - spec/request_spec.rb - spec/resource_spec.rb - spec/response_spec.rb - spec/restclient_spec.rb rest-client-1.6.7/lib/0000755000004100000410000000000011632430106014550 5ustar www-datawww-datarest-client-1.6.7/lib/restclient/0000755000004100000410000000000011632430106016724 5ustar www-datawww-datarest-client-1.6.7/lib/restclient/raw_response.rb0000644000004100000410000000150011632430106021754 0ustar www-datawww-datamodule RestClient # The response from RestClient on a raw request looks like a string, but is # actually one of these. 99% of the time you're making a rest call all you # care about is the body, but on the occassion you want to fetch the # headers you can: # # RestClient.get('http://example.com').headers[:content_type] # # In addition, if you do not use the response as a string, you can access # a Tempfile object at res.file, which contains the path to the raw # downloaded request body. class RawResponse include AbstractResponse attr_reader :file def initialize tempfile, net_http_res, args @net_http_res = net_http_res @args = args @file = tempfile end def to_s @file.open @file.read end def size File.size file end end end rest-client-1.6.7/lib/restclient/net_http_ext.rb0000644000004100000410000000315311632430106021760 0ustar www-datawww-datamodule Net class HTTP # Adding the patch method if it doesn't exist (rest-client issue: https://github.com/archiloque/rest-client/issues/79) if !defined?(Net::HTTP::Patch) # Code taken from this commit: https://github.com/ruby/ruby/commit/ab70e53ac3b5102d4ecbe8f38d4f76afad29d37d#lib/net/http.rb class Protocol # Sends a PATCH request to the +path+ and gets a response, # as an HTTPResponse object. def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ send_entity(path, data, initheader, dest, Patch, &block) end # Executes a request which uses a representation # and returns its body. def send_entity(path, data, initheader, dest, type, &block) res = nil request(type.new(path, initheader), data) {|r| r.read_body dest, &block res = r } unless @newimpl res.value return res, res.body end res end end class Patch < HTTPRequest METHOD = 'PATCH' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end end # # Replace the request method in Net::HTTP to sniff the body type # and set the stream if appropriate # # Taken from: # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/ alias __request__ request def request(req, body=nil, &block) if body != nil && body.respond_to?(:read) req.body_stream = body return __request__(req, nil, &block) else return __request__(req, body, &block) end end end end rest-client-1.6.7/lib/restclient/payload.rb0000644000004100000410000001277411632430106020715 0ustar www-datawww-datarequire 'tempfile' require 'stringio' require 'mime/types' module RestClient module Payload extend self def generate(params) if params.is_a?(String) Base.new(params) elsif params.respond_to?(:read) Streamed.new(params) elsif params if params.delete(:multipart) == true || has_file?(params) Multipart.new(params) else UrlEncoded.new(params) end else nil end end def has_file?(params) params.any? do |_, v| case v when Hash has_file?(v) when Array has_file_array?(v) else v.respond_to?(:path) && v.respond_to?(:read) end end end def has_file_array?(params) params.any? do |v| case v when Hash has_file?(v) when Array has_file_array?(v) else v.respond_to?(:path) && v.respond_to?(:read) end end end class Base def initialize(params) build_stream(params) end def build_stream(params) @stream = StringIO.new(params) @stream.seek(0) end def read(bytes=nil) @stream.read(bytes) end alias :to_s :read # Flatten parameters by converting hashes of hashes to flat hashes # {keys1 => {keys2 => value}} will be transformed into [keys1[key2], value] def flatten_params(params, parent_key = nil) result = [] params.each do |key, value| calculated_key = parent_key ? "#{parent_key}[#{handle_key(key)}]" : handle_key(key) if value.is_a? Hash result += flatten_params(value, calculated_key) elsif value.is_a? Array result += flatten_params_array(value, calculated_key) else result << [calculated_key, value] end end result end def flatten_params_array value, calculated_key result = [] value.each do |elem| if elem.is_a? Hash result += flatten_params(elem, calculated_key) elsif elem.is_a? Array result += flatten_params_array(elem, calculated_key) else result << ["#{calculated_key}[]", elem] end end result end def headers {'Content-Length' => size.to_s} end def size @stream.size end alias :length :size def close @stream.close unless @stream.closed? end def inspect result = to_s.inspect @stream.seek(0) result end def short_inspect (size > 500 ? "#{size} byte(s) length" : inspect) end end class Streamed < Base def build_stream(params = nil) @stream = params end def size if @stream.respond_to?(:size) @stream.size elsif @stream.is_a?(IO) @stream.stat.size end end alias :length :size end class UrlEncoded < Base def build_stream(params = nil) @stream = StringIO.new(flatten_params(params).collect do |entry| "#{entry[0]}=#{handle_key(entry[1])}" end.join("&")) @stream.seek(0) end # for UrlEncoded escape the keys def handle_key key URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) end def headers super.merge({'Content-Type' => 'application/x-www-form-urlencoded'}) end end class Multipart < Base EOL = "\r\n" def build_stream(params) b = "--#{boundary}" @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}") @stream.binmode @stream.write(b + EOL) if params.is_a? Hash x = flatten_params(params) else x = params end last_index = x.length - 1 x.each_with_index do |a, index| k, v = * a if v.respond_to?(:read) && v.respond_to?(:path) create_file_field(@stream, k, v) else create_regular_field(@stream, k, v) end @stream.write(EOL + b) @stream.write(EOL) unless last_index == index end @stream.write('--') @stream.write(EOL) @stream.seek(0) end def create_regular_field(s, k, v) s.write("Content-Disposition: form-data; name=\"#{k}\"") s.write(EOL) s.write(EOL) s.write(v) end def create_file_field(s, k, v) begin s.write("Content-Disposition: form-data;") s.write(" name=\"#{k}\";") unless (k.nil? || k=='') s.write(" filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}") s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}") s.write(EOL) while data = v.read(8124) s.write(data) end ensure v.close if v.respond_to?(:close) end end def mime_for(path) mime = MIME::Types.type_for path mime.empty? ? 'text/plain' : mime[0].content_type end def boundary @boundary ||= rand(1_000_000).to_s end # for Multipart do not escape the keys def handle_key key key end def headers super.merge({'Content-Type' => %Q{multipart/form-data; boundary=#{boundary}}}) end def close @stream.close! end end end end rest-client-1.6.7/lib/restclient/request.rb0000644000004100000410000002447011632430106020750 0ustar www-datawww-datarequire 'tempfile' require 'mime/types' require 'cgi' module RestClient # This class is used internally by RestClient to send the request, but you can also # call it directly if you'd like to use a method not supported by the # main API. For example: # # RestClient::Request.execute(:method => :head, :url => 'http://example.com') # # Mandatory parameters: # * :method # * :url # Optional parameters (have a look at ssl and/or uri for some explanations): # * :headers a hash containing the request headers # * :cookies will replace possible cookies in the :headers # * :user and :password for basic auth, will be replaced by a user/password available in the :url # * :block_response call the provided block with the HTTPResponse as parameter # * :raw_response return a low-level RawResponse instead of a Response # * :max_redirects maximum number of redirections (default to 10) # * :verify_ssl enable ssl verification, possible values are constants from OpenSSL::SSL # * :timeout and :open_timeout passing in -1 will disable the timeout by setting the corresponding net timeout values to nil # * :ssl_client_cert, :ssl_client_key, :ssl_ca_file class Request attr_reader :method, :url, :headers, :cookies, :payload, :user, :password, :timeout, :max_redirects, :open_timeout, :raw_response, :verify_ssl, :ssl_client_cert, :ssl_client_key, :ssl_ca_file, :processed_headers, :args def self.execute(args, & block) new(args).execute(& block) end def initialize args @method = args[:method] or raise ArgumentError, "must pass :method" @headers = args[:headers] || {} if args[:url] @url = process_url_params(args[:url], headers) else raise ArgumentError, "must pass :url" end @cookies = @headers.delete(:cookies) || args[:cookies] || {} @payload = Payload.generate(args[:payload]) @user = args[:user] @password = args[:password] @timeout = args[:timeout] @open_timeout = args[:open_timeout] @block_response = args[:block_response] @raw_response = args[:raw_response] || false @verify_ssl = args[:verify_ssl] || false @ssl_client_cert = args[:ssl_client_cert] || nil @ssl_client_key = args[:ssl_client_key] || nil @ssl_ca_file = args[:ssl_ca_file] || nil @tf = nil # If you are a raw request, this is your tempfile @max_redirects = args[:max_redirects] || 10 @processed_headers = make_headers headers @args = args end def execute & block uri = parse_url_with_auth(url) transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload, & block ensure payload.close if payload end # Extract the query parameters and append them to the url def process_url_params url, headers url_params = {} headers.delete_if do |key, value| if 'params' == key.to_s.downcase && value.is_a?(Hash) url_params.merge! value true else false end end unless url_params.empty? query_string = url_params.collect { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&') url + "?#{query_string}" else url end end def make_headers user_headers unless @cookies.empty? user_headers[:cookie] = @cookies.map { |(key, val)| "#{key.to_s}=#{CGI::unescape(val)}" }.sort.join('; ') end headers = stringify_headers(default_headers).merge(stringify_headers(user_headers)) headers.merge!(@payload.headers) if @payload headers end def net_http_class if RestClient.proxy proxy_uri = URI.parse(RestClient.proxy) Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password) else Net::HTTP end end def net_http_request_class(method) Net::HTTP.const_get(method.to_s.capitalize) end def parse_url(url) url = "http://#{url}" unless url.match(/^http/) URI.parse(url) end def parse_url_with_auth(url) uri = parse_url(url) @user = CGI.unescape(uri.user) if uri.user @password = CGI.unescape(uri.password) if uri.password uri end def process_payload(p=nil, parent_key=nil) unless p.is_a?(Hash) p else @headers[:content_type] ||= 'application/x-www-form-urlencoded' p.keys.map do |k| key = parent_key ? "#{parent_key}[#{k}]" : k if p[k].is_a? Hash process_payload(p[k], key) else value = URI.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) "#{key}=#{value}" end end.join("&") end end def transmit uri, req, payload, & block setup_credentials req net = net_http_class.new(uri.host, uri.port) net.use_ssl = uri.is_a?(URI::HTTPS) if (@verify_ssl == false) || (@verify_ssl == OpenSSL::SSL::VERIFY_NONE) net.verify_mode = OpenSSL::SSL::VERIFY_NONE elsif @verify_ssl.is_a? Integer net.verify_mode = @verify_ssl net.verify_callback = lambda do |preverify_ok, ssl_context| if (!preverify_ok) || ssl_context.error != 0 err_msg = "SSL Verification failed -- Preverify: #{preverify_ok}, Error: #{ssl_context.error_string} (#{ssl_context.error})" raise SSLCertificateNotVerified.new(err_msg) end true end end net.cert = @ssl_client_cert if @ssl_client_cert net.key = @ssl_client_key if @ssl_client_key net.ca_file = @ssl_ca_file if @ssl_ca_file net.read_timeout = @timeout if @timeout net.open_timeout = @open_timeout if @open_timeout # disable the timeout if the timeout value is -1 net.read_timeout = nil if @timeout == -1 net.out_timeout = nil if @open_timeout == -1 RestClient.before_execution_procs.each do |before_proc| before_proc.call(req, args) end log_request net.start do |http| if @block_response http.request(req, payload ? payload.to_s : nil, & @block_response) else res = http.request(req, payload ? payload.to_s : nil) { |http_response| fetch_body(http_response) } log_response res process_result res, & block end end rescue EOFError raise RestClient::ServerBrokeConnection rescue Timeout::Error raise RestClient::RequestTimeout end def setup_credentials(req) req.basic_auth(user, password) if user end def fetch_body(http_response) if @raw_response # Taken from Chef, which as in turn... # Stolen from http://www.ruby-forum.com/topic/166423 # Kudos to _why! @tf = Tempfile.new("rest-client") size, total = 0, http_response.header['Content-Length'].to_i http_response.read_body do |chunk| @tf.write chunk size += chunk.size if RestClient.log if size == 0 RestClient.log << "#{@method} #{@url} done (0 length file\n)" elsif total == 0 RestClient.log << "#{@method} #{@url} (zero content length)\n" else RestClient.log << "#{@method} #{@url} %d%% done (%d of %d)\n" % [(size * 100) / total, size, total] end end end @tf.close @tf else http_response.read_body end http_response end def process_result res, & block if @raw_response # We don't decode raw requests response = RawResponse.new(@tf, res, args) else response = Response.create(Request.decode(res['content-encoding'], res.body), res, args) end if block_given? block.call(response, self, res, & block) else response.return!(self, res, & block) end end def self.decode content_encoding, body if (!body) || body.empty? body elsif content_encoding == 'gzip' Zlib::GzipReader.new(StringIO.new(body)).read elsif content_encoding == 'deflate' begin Zlib::Inflate.new.inflate body rescue Zlib::DataError # No luck with Zlib decompression. Let's try with raw deflate, # like some broken web servers do. Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate body end else body end end def log_request if RestClient.log out = [] out << "RestClient.#{method} #{url.inspect}" out << payload.short_inspect if payload out << processed_headers.to_a.sort.map { |(k, v)| [k.inspect, v.inspect].join("=>") }.join(", ") RestClient.log << out.join(', ') + "\n" end end def log_response res if RestClient.log size = @raw_response ? File.size(@tf.path) : (res.body.nil? ? 0 : res.body.size) RestClient.log << "# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes\n" end end # Return a hash of headers whose keys are capitalized strings def stringify_headers headers headers.inject({}) do |result, (key, value)| if key.is_a? Symbol key = key.to_s.split(/_/).map { |w| w.capitalize }.join('-') end if 'CONTENT-TYPE' == key.upcase target_value = value.to_s result[key] = MIME::Types.type_for_extension target_value elsif 'ACCEPT' == key.upcase # Accept can be composed of several comma-separated values if value.is_a? Array target_values = value else target_values = value.to_s.split ',' end result[key] = target_values.map { |ext| MIME::Types.type_for_extension(ext.to_s.strip) }.join(', ') else result[key] = value.to_s end result end end def default_headers {:accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate'} end end end module MIME class Types # Return the first found content-type for a value considered as an extension or the value itself def type_for_extension ext candidates = @extension_index[ext] candidates.empty? ? ext : candidates[0].content_type end class << self def type_for_extension ext @__types__.type_for_extension ext end end end end rest-client-1.6.7/lib/restclient/resource.rb0000644000004100000410000001220111632430106021074 0ustar www-datawww-datamodule RestClient # A class that can be instantiated for access to a RESTful resource, # including authentication. # # Example: # # resource = RestClient::Resource.new('http://some/resource') # jpg = resource.get(:accept => 'image/jpg') # # With HTTP basic authentication: # # resource = RestClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password') # resource.delete # # With a timeout (seconds): # # RestClient::Resource.new('http://slow', :timeout => 10) # # With an open timeout (seconds): # # RestClient::Resource.new('http://behindfirewall', :open_timeout => 10) # # You can also use resources to share common headers. For headers keys, # symbols are converted to strings. Example: # # resource = RestClient::Resource.new('http://some/resource', :headers => { :client_version => 1 }) # # This header will be transported as X-Client-Version (notice the X prefix, # capitalization and hyphens) # # Use the [] syntax to allocate subresources: # # site = RestClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd') # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain' # class Resource attr_reader :url, :options, :block def initialize(url, options={}, backwards_compatibility=nil, &block) @url = url @block = block if options.class == Hash @options = options else # compatibility with previous versions @options = { :user => options, :password => backwards_compatibility } end end def get(additional_headers={}, &block) headers = (options[:headers] || {}).merge(additional_headers) Request.execute(options.merge( :method => :get, :url => url, :headers => headers), &(block || @block)) end def head(additional_headers={}, &block) headers = (options[:headers] || {}).merge(additional_headers) Request.execute(options.merge( :method => :head, :url => url, :headers => headers), &(block || @block)) end def post(payload, additional_headers={}, &block) headers = (options[:headers] || {}).merge(additional_headers) Request.execute(options.merge( :method => :post, :url => url, :payload => payload, :headers => headers), &(block || @block)) end def put(payload, additional_headers={}, &block) headers = (options[:headers] || {}).merge(additional_headers) Request.execute(options.merge( :method => :put, :url => url, :payload => payload, :headers => headers), &(block || @block)) end def patch(payload, additional_headers={}, &block) headers = (options[:headers] || {}).merge(additional_headers) Request.execute(options.merge( :method => :patch, :url => url, :payload => payload, :headers => headers), &(block || @block)) end def delete(additional_headers={}, &block) headers = (options[:headers] || {}).merge(additional_headers) Request.execute(options.merge( :method => :delete, :url => url, :headers => headers), &(block || @block)) end def to_s url end def user options[:user] end def password options[:password] end def headers options[:headers] || {} end def timeout options[:timeout] end def open_timeout options[:open_timeout] end # Construct a subresource, preserving authentication. # # Example: # # site = RestClient::Resource.new('http://example.com', 'adam', 'mypasswd') # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain' # # This is especially useful if you wish to define your site in one place and # call it in multiple locations: # # def orders # RestClient::Resource.new('http://example.com/orders', 'admin', 'mypasswd') # end # # orders.get # GET http://example.com/orders # orders['1'].get # GET http://example.com/orders/1 # orders['1/items'].delete # DELETE http://example.com/orders/1/items # # Nest resources as far as you want: # # site = RestClient::Resource.new('http://example.com') # posts = site['posts'] # first_post = posts['1'] # comments = first_post['comments'] # comments.post 'Hello', :content_type => 'text/plain' # def [](suburl, &new_block) case when block_given? then self.class.new(concat_urls(url, suburl), options, &new_block) when block then self.class.new(concat_urls(url, suburl), options, &block) else self.class.new(concat_urls(url, suburl), options) end end def concat_urls(url, suburl) # :nodoc: url = url.to_s suburl = suburl.to_s if url.slice(-1, 1) == '/' or suburl.slice(0, 1) == '/' url + suburl else "#{url}/#{suburl}" end end end end rest-client-1.6.7/lib/restclient/abstract_response.rb0000644000004100000410000000614611632430106023001 0ustar www-datawww-datarequire 'cgi' module RestClient module AbstractResponse attr_reader :net_http_res, :args # HTTP status code def code @code ||= @net_http_res.code.to_i end # A hash of the headers, beautified with symbols and underscores. # e.g. "Content-type" will become :content_type. def headers @headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash) end # The raw headers. def raw_headers @raw_headers ||= @net_http_res.to_hash end # Hash of cookies extracted from response headers def cookies @cookies ||= (self.headers[:set_cookie] || {}).inject({}) do |out, cookie_content| out.merge parse_cookie(cookie_content) end end # Return the default behavior corresponding to the response code: # the response itself for code in 200..206, redirection for 301, 302 and 307 in get and head cases, redirection for 303 and an exception in other cases def return! request = nil, result = nil, & block if (200..207).include? code self elsif [301, 302, 307].include? code unless [:get, :head].include? args[:method] raise Exceptions::EXCEPTIONS_MAP[code].new(self, code) else follow_redirection(request, result, & block) end elsif code == 303 args[:method] = :get args.delete :payload follow_redirection(request, result, & block) elsif Exceptions::EXCEPTIONS_MAP[code] raise Exceptions::EXCEPTIONS_MAP[code].new(self, code) else raise RequestFailed.new(self, code) end end def to_i code end def description "#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n" end # Follow a redirection def follow_redirection request = nil, result = nil, & block url = headers[:location] if url !~ /^http/ url = URI.parse(args[:url]).merge(url).to_s end args[:url] = url if request if request.max_redirects == 0 raise MaxRedirectsReached end args[:password] = request.password args[:user] = request.user args[:headers] = request.headers args[:max_redirects] = request.max_redirects - 1 # pass any cookie set in the result if result && result['set-cookie'] args[:headers][:cookies] = (args[:headers][:cookies] || {}).merge(parse_cookie(result['set-cookie'])) end end Request.execute args, &block end def AbstractResponse.beautify_headers(headers) headers.inject({}) do |out, (key, value)| out[key.gsub(/-/, '_').downcase.to_sym] = %w{ set-cookie }.include?(key.downcase) ? value : value.first out end end private # Parse a cookie value and return its content in an Hash def parse_cookie cookie_content out = {} CGI::Cookie::parse(cookie_content).each do |key, cookie| unless ['expires', 'path'].include? key out[CGI::escape(key)] = cookie.value[0] ? (CGI::escape(cookie.value[0]) || '') : '' end end out end end end rest-client-1.6.7/lib/restclient/response.rb0000644000004100000410000000067511632430106021117 0ustar www-datawww-datamodule RestClient # A Response from RestClient, you can access the response body, the code or the headers. # module Response include AbstractResponse attr_accessor :args, :body, :net_http_res def body self end def Response.create body, net_http_res, args result = body || '' result.extend Response result.net_http_res = net_http_res result.args = args result end end end rest-client-1.6.7/lib/restclient/exceptions.rb0000644000004100000410000001343611632430106021441 0ustar www-datawww-datamodule RestClient STATUSES = {100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', #WebDAV 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', # http/1.1 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', #WebDAV 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', # http/1.1 304 => 'Not Modified', 305 => 'Use Proxy', # http/1.1 306 => 'Switch Proxy', # no longer used 307 => 'Temporary Redirect', # http/1.1 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Resource Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m A Teapot', 421 => 'Too Many Connections From This IP', 422 => 'Unprocessable Entity', #WebDAV 423 => 'Locked', #WebDAV 424 => 'Failed Dependency', #WebDAV 425 => 'Unordered Collection', #WebDAV 426 => 'Upgrade Required', 449 => 'Retry With', #Microsoft 450 => 'Blocked By Windows Parental Controls', #Microsoft 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', #WebDAV 509 => 'Bandwidth Limit Exceeded', #Apache 510 => 'Not Extended'} # Compatibility : make the Response act like a Net::HTTPResponse when needed module ResponseForException def method_missing symbol, *args if net_http_res.respond_to? symbol warn "[warning] The response contained in an RestClient::Exception is now a RestClient::Response instead of a Net::HTTPResponse, please update your code" net_http_res.send symbol, *args else super end end end # This is the base RestClient exception class. Rescue it if you want to # catch any exception that your request might raise # You can get the status code by e.http_code, or see anything about the # response via e.response. # For example, the entire result body (which is # probably an HTML error page) is e.response. class Exception < RuntimeError attr_accessor :response attr_writer :message def initialize response = nil, initial_response_code = nil @response = response @initial_response_code = initial_response_code # compatibility: this make the exception behave like a Net::HTTPResponse response.extend ResponseForException if response end def http_code # return integer for compatibility if @response @response.code.to_i else @initial_response_code end end def http_body @response.body if @response end def inspect "#{message}: #{http_body}" end def to_s inspect end def message @message || self.class.name end end # Compatibility class ExceptionWithResponse < Exception end # The request failed with an error code not managed by the code class RequestFailed < ExceptionWithResponse def message "HTTP status code #{http_code}" end def to_s message end end # We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html module Exceptions # Map http status codes to the corresponding exception class EXCEPTIONS_MAP = {} end STATUSES.each_pair do |code, message| # Compatibility superclass = ([304, 401, 404].include? code) ? ExceptionWithResponse : RequestFailed klass = Class.new(superclass) do send(:define_method, :message) {"#{http_code ? "#{http_code} " : ''}#{message}"} end klass_constant = const_set message.delete(' \-\''), klass Exceptions::EXCEPTIONS_MAP[code] = klass_constant end # A redirect was encountered; caught by execute to retry with the new url. class Redirect < Exception message = 'Redirect' attr_accessor :url def initialize(url) @url = url end end class MaxRedirectsReached < Exception message = 'Maximum number of redirect reached' end # The server broke the connection prior to the request completing. Usually # this means it crashed, or sometimes that your network connection was # severed before it could complete. class ServerBrokeConnection < Exception def initialize(message = 'Server broke connection') super nil, nil self.message = message end end class SSLCertificateNotVerified < Exception def initialize(message) super nil, nil self.message = message end end end # backwards compatibility class RestClient::Request Redirect = RestClient::Redirect Unauthorized = RestClient::Unauthorized RequestFailed = RestClient::RequestFailed end rest-client-1.6.7/lib/restclient.rb0000644000004100000410000001261311632430106017254 0ustar www-datawww-datarequire 'uri' require 'zlib' require 'stringio' begin require 'net/https' rescue LoadError => e raise e unless RUBY_PLATFORM =~ /linux/ raise LoadError, "no such file to load -- net/https. Try running apt-get install libopenssl-ruby" end require File.dirname(__FILE__) + '/restclient/exceptions' require File.dirname(__FILE__) + '/restclient/request' require File.dirname(__FILE__) + '/restclient/abstract_response' require File.dirname(__FILE__) + '/restclient/response' require File.dirname(__FILE__) + '/restclient/raw_response' require File.dirname(__FILE__) + '/restclient/resource' require File.dirname(__FILE__) + '/restclient/payload' require File.dirname(__FILE__) + '/restclient/net_http_ext' # This module's static methods are the entry point for using the REST client. # # # GET # xml = RestClient.get 'http://example.com/resource' # jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg' # # # authentication and SSL # RestClient.get 'https://user:password@example.com/private/resource' # # # POST or PUT with a hash sends parameters as a urlencoded form body # RestClient.post 'http://example.com/resource', :param1 => 'one' # # # nest hash parameters # RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' } # # # POST and PUT with raw payloads # RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain' # RestClient.post 'http://example.com/resource.xml', xml_doc # RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf' # # # DELETE # RestClient.delete 'http://example.com/resource' # # # retreive the response http code and headers # res = RestClient.get 'http://example.com/some.jpg' # res.code # => 200 # res.headers[:content_type] # => 'image/jpg' # # # HEAD # RestClient.head('http://example.com').headers # # To use with a proxy, just set RestClient.proxy to the proper http proxy: # # RestClient.proxy = "http://proxy.example.com/" # # Or inherit the proxy from the environment: # # RestClient.proxy = ENV['http_proxy'] # # For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call: # # >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz' # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}" # module RestClient def self.get(url, headers={}, &block) Request.execute(:method => :get, :url => url, :headers => headers, &block) end def self.post(url, payload, headers={}, &block) Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block) end def self.patch(url, payload, headers={}, &block) Request.execute(:method => :patch, :url => url, :payload => payload, :headers => headers, &block) end def self.put(url, payload, headers={}, &block) Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block) end def self.delete(url, headers={}, &block) Request.execute(:method => :delete, :url => url, :headers => headers, &block) end def self.head(url, headers={}, &block) Request.execute(:method => :head, :url => url, :headers => headers, &block) end def self.options(url, headers={}, &block) Request.execute(:method => :options, :url => url, :headers => headers, &block) end class << self attr_accessor :proxy end # Setup the log for RestClient calls. # Value should be a logger but can can be stdout, stderr, or a filename. # You can also configure logging by the environment variable RESTCLIENT_LOG. def self.log= log @@log = create_log log end def self.version version_path = File.dirname(__FILE__) + "/../VERSION" return File.read(version_path).chomp if File.file?(version_path) "0.0.0" end # Create a log that respond to << like a logger # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it) def self.create_log param if param if param.is_a? String if param == 'stdout' stdout_logger = Class.new do def << obj STDOUT.puts obj end end stdout_logger.new elsif param == 'stderr' stderr_logger = Class.new do def << obj STDERR.puts obj end end stderr_logger.new else file_logger = Class.new do attr_writer :target_file def << obj File.open(@target_file, 'a') { |f| f.puts obj } end end logger = file_logger.new logger.target_file = param logger end else param end end end @@env_log = create_log ENV['RESTCLIENT_LOG'] @@log = nil def self.log # :nodoc: @@env_log || @@log end @@before_execution_procs = [] # Add a Proc to be called before each request in executed. # The proc parameters will be the http request and the request params. def self.add_before_execution_proc &proc @@before_execution_procs << proc end # Reset the procs to be called before each request is executed. def self.reset_before_execution_procs @@before_execution_procs = [] end def self.before_execution_procs # :nodoc: @@before_execution_procs end end rest-client-1.6.7/lib/rest_client.rb0000644000004100000410000000016711632430106017414 0ustar www-datawww-data# This file exists for backward compatbility with require 'rest_client' require File.dirname(__FILE__) + '/restclient' rest-client-1.6.7/lib/rest-client.rb0000644000004100000410000000013311632430106017323 0ustar www-datawww-data# More logical way to require 'rest-client' require File.dirname(__FILE__) + '/restclient' rest-client-1.6.7/history.md0000644000004100000410000001451511632430106016033 0ustar www-datawww-data# 1.6.7 - rebuild with 1.8.7 to avoid https://github.com/rubygems/rubygems/pull/57 # 1.6.6 - 1.6.5 was yanked # 1.6.5 - RFC6265 requires single SP after ';' for separating parameters pairs in the 'Cookie:' header (patch provided by Hiroshi Nakamura) - enable url parameters for all actions - detect file parameters in arrays - allow disabling the timeouts by passing -1 (patch provided by Sven Böhm) # 1.6.4 - fix restclient script compatibility with 1.9.2 - fix unlinking temp file (patch provided by Evan Smith) - monkeypatching ruby for http patch method (patch provided by Syl Turner) # 1.6.3 - 1.6.2 was yanked # 1.6.2 - add support for HEAD in resources (patch provided by tpresa) - fix shell for 1.9.2 - workaround when some gem monkeypatch net/http (patch provided by Ian Warshak) - DELETE requests should process parameters just like GET and HEAD - adding :block_response parameter for manual processing - limit number of redirections (patch provided by Chris Dinn) - close and unlink the temp file created by playload (patch provided by Chris Green) - make gemspec Rubygems 1.8 compatible (patch provided by David Backeus) - added RestClient.reset_before_execution_procs (patch provided by Cloudify) - added PATCH method (patch provided by Jeff Remer) - hack for HTTP servers that use raw DEFLATE compression, see http://www.ruby-forum.com/topic/136825 (path provided by James Reeves) # 1.6.1 - add response body in Exception#inspect - add support for RestClient.options - fix tests for 1.9.2 (patch provided by Niko Dittmann) - block passing in Resource#[] (patch provided by Niko Dittmann) - cookies set in a response should be kept in a redirect - HEAD requests should process parameters just like GET (patch provided by Rob Eanes) - exception message should never be nil (patch provided by Michael Klett) # 1.6.0 - forgot to include rest-client.rb in the gem - user, password and user-defined headers should survive a redirect - added all missing status codes - added parameter passing for get request using the :param key in header - the warning about the logger when using a string was a bad idea - multipart parameters names should not be escaped - remove the cookie escaping introduced by migrating to CGI cookie parsing in 1.5.1 - add a streamed payload type (patch provided by Caleb Land) - Exception#http_body works even when no response # 1.5.1 - only converts headers keys which are Symbols - use CGI for cookie parsing instead of custom code - unescape user and password before using them (patch provided by Lars Gierth) - expand ~ in ~/.restclientrc (patch provided by Mike Fletcher) - ssl verification raise an exception when the ca certificate is incorrect (patch provided by Braintree) # 1.5.0 - the response is now a String with the Response module a.k.a. the change in 1.4.0 was a mistake (Response.body is returning self for compatability) - added AbstractResponse.to_i to improve semantic - multipart Payloads ignores the name attribute if it's not set (patch provided by Tekin Suleyman) - correctly takes into account user headers whose keys are strings (path provided by Cyril Rohr) - use binary mode for payload temp file - concatenate cookies with ';' - fixed deeper parameter handling - do not quote the boundary in the Content-Type header (patch provided by W. Andrew Loe III) # 1.4.2 - fixed RestClient.add_before_execution_proc (patch provided by Nicholas Wieland) - fixed error when an exception is raised without a response (patch provided by Caleb Land) # 1.4.1 - fixed parameters managment when using hash # 1.4.0 - Response is no more a String, and the mixin is replaced by an abstract_response, existing calls are redirected to response body with a warning. - enable repeated parameters RestClient.post 'http://example.com/resource', :param1 => ['one', 'two', 'three'], => :param2 => 'foo' (patch provided by Rodrigo Panachi) - fixed the redirect code concerning relative path and query string combination (patch provided by Kevin Read) - redirection code moved to Response so redirection can be customized using the block syntax - only get and head redirections are now followed by default, as stated in the specification - added RestClient.add_before_execution_proc to hack the http request, like for oauth The response change may be breaking in rare cases. # 1.3.1 - added compatibility to enable responses in exception to act like Net::HTTPResponse # 1.3.0 - a block can be used to process a request's result, this enable to handle custom error codes or paththrought (design by Cyril Rohr) - cleaner log API, add a warning for some cases but should be compatible - accept multiple "Set-Cookie" headers, see http://www.ietf.org/rfc/rfc2109.txt (patch provided by Cyril Rohr) - remove "Content-Length" and "Content-Type" headers when following a redirection (patch provided by haarts) - all http error codes have now a corresponding exception class and all of them contain the Reponse -> this means that the raised exception can be different - changed "Content-Disposition: multipart/form-data" to "Content-Disposition: form-data" per RFC 2388 (patch provided by Kyle Crawford) The only breaking change should be the exception classes, but as the new classes inherits from the existing ones, the breaking cases should be rare. # 1.2.0 - formatting changed from tabs to spaces - logged requests now include generated headers - accept and content-type headers can now be specified using extentions: RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json - should be 1.1.1 but renamed to 1.2.0 because 1.1.X versions has already been packaged on Debian # 1.1.0 - new maintainer: Archiloque, the working repo is now at http://github.com/archiloque/rest-client - a mailing list has been created at rest.client@librelist.com and an freenode irc channel #rest-client - François Beausoleil' multipart code from http://github.com/francois/rest-client has been merged - ability to use hash in hash as payload - the mime-type code now rely on the mime-types gem http://mime-types.rubyforge.org/ instead of an internal partial list - 204 response returns a Response instead of nil (patch provided by Elliott Draper) All changes exept the last one should be fully compatible with the previous version. NOTE: due to a dependency problem and to the last change, heroku users should update their heroku gem to >= 1.5.3 to be able to use this version.