simple-http 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b4588e9e8c027217ca27a55496429b8c17b1bb49
4
+ data.tar.gz: be034b0620f7358c4e3d806ca4a0ab8b7c16e77d
5
+ SHA512:
6
+ metadata.gz: 25d97c4098cdd837a45c7cf4b6377d943cd29fde1a51db79b7f52f9457658127a411f910b618d23bb42c368f1dc3ef49c47219f929b72ddd96df552a3639ac27
7
+ data.tar.gz: f8044c467a6f30109a21cfa2d86d5b4c9fadeec52f930375502a11a7dfa0f2a74ae932a669417e7c205e7610feb77a01cbf091e7674296dfe6fba64bf8788df9
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # simple-http
2
+
3
+ A really simple HTTP client
4
+
5
+ - GET, POST, PUT, DELETE
6
+
7
+ require "simple/http"
8
+ http_client = Simple::HTTP.new
9
+ http_client.get "http://google.com" # returns a string
10
+
11
+ - Exceptions on errors: because, after all, when you consume a HTTP endpoint and don't
12
+ get a success (20x), then this is an error. Handle it!
13
+
14
+ require "simple/http"
15
+ http_client = Simple::HTTP.new
16
+ begin
17
+ http_client.get "http://google.com" # returns a string
18
+ rescue Simple::HTTP::Error
19
+ STDERR.puts "Ooops! #{$!}"
20
+ end
21
+
22
+ - Caching
23
+
24
+ require "simple/http"
25
+ http_client = Simple::HTTP.new
26
+
27
+ require "active_support/cache"
28
+ require "active_support/cache/file_store"
29
+ http_client.cache = ActiveSupport::Cache::FileStore.new("var/cache")
30
+ http_client.get "http://google.com" # returns a, potentially, cached string
31
+
32
+ - Automatic de/encoding of JSON payloads
33
+
34
+ - Does not requires anything except core ruby classes.
@@ -0,0 +1,33 @@
1
+ # This file is part of the simple-http ruby gem.
2
+ #
3
+ # Copyright (c) 2011 - 2015 @radiospiel
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ module Simple; end
7
+ class Simple::HTTP; end
8
+
9
+ class Simple::HTTP::Error < RuntimeError
10
+ attr :method, :request, :response
11
+
12
+ def initialize(method, request, response)
13
+ @method, @request, @response = method, request, response
14
+ end
15
+
16
+ def code
17
+ response.code.to_i
18
+ end
19
+
20
+ def message
21
+ message = "#{method} #{response.uri} ##{response.code} #{response.message}"
22
+ if response.is_a?(Net::HTTPRedirection)
23
+ message += " To #{response["Location"]}"
24
+ end
25
+ message
26
+ end
27
+ end
28
+
29
+ class Simple::HTTP::TooManyRedirections < Simple::HTTP::Error
30
+ def message
31
+ "Too many redirections; after\n#{super}"
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ # This file is part of the simple-http ruby gem.
2
+ #
3
+ # Copyright (c) 2011 - 2015 @radiospiel
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ require "net/http"
7
+
8
+ class Net::HTTPResponse
9
+ private
10
+
11
+ #
12
+ # The "max-age" value, in seconds, from the Cache-Control header.
13
+ def max_age
14
+ return unless cache_control = header["Cache-Control"]
15
+ cache_control.split(/, /).each do |part|
16
+ next unless part =~ /max-age=(\d+)/
17
+ return Integer($1)
18
+ end
19
+ nil
20
+ end
21
+
22
+ public
23
+
24
+ #
25
+ # returns expiration information, in seconds from now.
26
+ def expires_in
27
+ expires_in = max_age
28
+ if !expires_in && expires = header["Expires"]
29
+ expires_in = Time.parse(expires) - Time.now
30
+ end
31
+
32
+ return expires_in if expires_in && expires_in > 0
33
+ end
34
+ end
@@ -0,0 +1,41 @@
1
+ # This file is part of the simple-http ruby gem.
2
+ #
3
+ # Copyright (c) 2011 - 2015 @radiospiel
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ require "net/http"
7
+
8
+ class Net::HTTPResponse
9
+ #
10
+ # evaluate and potentially parse response
11
+ def result
12
+ case response.content_type
13
+ when "application/json"
14
+ JSON.parse(body) unless body.empty?
15
+ else
16
+ body_string
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ #
23
+ # returns a body. The resulting string is encoded in ASCII-8BIT, if the
24
+ # content type is binary, and encoded in UTF8 otherwise.
25
+ def body_string
26
+ default_encoding = content_is_binary? ? "ASCII-8BIT" : "UTF-8"
27
+
28
+ body = self.body
29
+ if charset = type_params["charset"]
30
+ body = body.force_encoding(charset)
31
+ end
32
+ body.encode(default_encoding)
33
+ end
34
+
35
+ def content_is_binary?
36
+ case content_type
37
+ when /^image/ then true
38
+ else false
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ # This file is part of the simple-http ruby gem.
2
+ #
3
+ # Copyright (c) 2011 - 2015 @radiospiel
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ module Simple; end
7
+ class Simple::HTTP
8
+ VERSION = "0.1.0"
9
+ end
@@ -0,0 +1,166 @@
1
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
2
+ # Copyright:: Copyright (c) 2011-2015 radiospiel
3
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
4
+
5
+ require "net/http"
6
+ require "json"
7
+
8
+ module Simple; end
9
+ class Simple::HTTP; end
10
+
11
+ require_relative "http/version"
12
+ require_relative "http/result"
13
+ require_relative "http/expires_in"
14
+ require_relative "http/errors"
15
+
16
+ #
17
+ # A very simple, Net::HTTP-based HTTP client.
18
+ #
19
+ # Has some support for transferring JSON data: all data in PUT and POST
20
+ # requests are jsonized, and all data in responses are parsed as JSON if
21
+ # the Content-Type header is set to "application/json".
22
+ class Simple::HTTP
23
+
24
+ #
25
+ # The base URL: when set, all requests that do not start with http: or
26
+ # https: are done relative to this base URL.
27
+ attr :base_url, true
28
+
29
+ #
30
+ # When set (default), redirections are followed. Note: When
31
+ # follows_redirections is not set, a HTTP redirection would raise an
32
+ # error - which is probably only useful when testing an interface.
33
+ attr :follows_redirections, true
34
+
35
+ #
36
+ # When set, appends this to all request URLs
37
+ attr :default_params, true
38
+
39
+ def initialize
40
+ self.follows_redirections = true
41
+ end
42
+
43
+ def get(url, headers = {}); http :GET, url, nil, headers; end
44
+ def post(url, body = nil, headers = {}); http :POST, url, body, headers; end
45
+ def put(url, body = nil, headers = {}); http :PUT, url, body, headers; end
46
+ def delete(url, headers = {}); http :DELETE, url, nil, headers; end
47
+
48
+ #
49
+ # -- Caching ----------------------------------------------------------------
50
+
51
+ # When set, and a response is cacheable (as it returns a valid expires_in
52
+ # value), the cache object is used to cache responses.
53
+ attr :cache, true
54
+
55
+ #
56
+ # when does the response expire? By default, calculates expiration based
57
+ # on response headers. Override as needed.
58
+ def expires_in(response)
59
+ response.expires_in
60
+ end
61
+
62
+ private
63
+
64
+ # -- HTTP request -----------------------------------------------------------
65
+
66
+ def http(method, url, body = nil, headers)
67
+ #
68
+ # normalize url; i.e. prepend base_url if the url itself is incomplete.
69
+ unless url =~ /^(http|https):/
70
+ url = File.join(base_url, url)
71
+ end
72
+
73
+ # append default_params, if set
74
+ if default_params
75
+ url.concat(url.include?("?") ? "&" : "?")
76
+ url.concat default_params
77
+ end
78
+
79
+ # "raw" execute request
80
+ http_ method, url, body, headers
81
+ end
82
+
83
+ #
84
+ # do a HTTP request, return its response or, when not successful,
85
+ # raise an error.
86
+ def http_(method, url, body, headers, max_redirections = 10)
87
+ if method == :GET && cache && result = cache.read(url)
88
+ return result
89
+ end
90
+
91
+ uri = URI.parse(url)
92
+ http = Net::HTTP.new(uri.host, uri.port)
93
+
94
+ #
95
+ # build request
96
+ request = build_request method, uri, body, headers
97
+
98
+ #
99
+ # execute request
100
+ response = http.request(request)
101
+
102
+ #
103
+ # Most of the times Net::HTTP#request returns a response with the :uri
104
+ # attribute set, but sometimes not. We make sure that the uri is set
105
+ # everytime.
106
+ response.uri = uri
107
+
108
+ #
109
+ # handle successful responses.
110
+ if response.is_a?(Net::HTTPSuccess)
111
+ result = response.result
112
+ if cache && method == :GET && expires_in = self.expires_in(response)
113
+ cache.write(url, result, expires_in: expires_in)
114
+ end
115
+
116
+ return result
117
+ end
118
+
119
+ #
120
+ # handle redirections.
121
+ if response.is_a?(Net::HTTPRedirection) && self.follows_redirections
122
+ if max_redirections <= 0
123
+ raise TooManyRedirections.new(method, request, respons)
124
+ end
125
+
126
+ return http_(:GET, response["Location"], nil, {}, max_redirections - 1)
127
+ end
128
+
129
+ #
130
+ # raise an error in any other case.
131
+ raise Error.new(method, request, response)
132
+ end
133
+
134
+ private
135
+
136
+ REQUEST_CLASSES = {
137
+ :GET => Net::HTTP::Get,
138
+ :POST => Net::HTTP::Post,
139
+ :PUT => Net::HTTP::Put,
140
+ :DELETE => Net::HTTP::Delete
141
+ }.freeze #:nodoc:
142
+
143
+ #
144
+ # build a HTTP request object.
145
+ def build_request(method, uri, body, headers)
146
+ klass = REQUEST_CLASSES.fetch(method)
147
+ request = klass.new(uri.request_uri)
148
+
149
+ # set request headers
150
+ # unless headers && !headers.empty?
151
+ # # TODO: set headers
152
+ # # set_request_headers request, headers
153
+ # end
154
+
155
+ # set request body
156
+ if request.request_body_permitted? && body
157
+ request.content_type = "application/json"
158
+ if body.is_a?(Hash) || body.is_a?(Array)
159
+ body = JSON.generate(body)
160
+ end
161
+ request.body = body
162
+ end
163
+
164
+ request
165
+ end
166
+ end
@@ -0,0 +1,14 @@
1
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
2
+ # Copyright:: Copyright (c) 2011-2015 radiospiel
3
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
4
+
5
+ require_relative 'test_helper'
6
+
7
+ class SimpleHttpTest < Test::Unit::TestCase
8
+ HTTP = Simple::HTTP.new
9
+
10
+ def test_loaded
11
+ google = HTTP.get "http://google.com"
12
+ assert_match(/doctype/, google)
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ # require 'simplecov'
5
+ require 'test/unit'
6
+
7
+ # SimpleCov.start do
8
+ # add_filter "test/*.rb"
9
+ # end
10
+
11
+ require "simple/http"
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-http
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - radiospiel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-16 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simple code for simple HTTP requests
14
+ email: eno@radiospiel.org
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - lib/simple/http.rb
21
+ - lib/simple/http/errors.rb
22
+ - lib/simple/http/expires_in.rb
23
+ - lib/simple/http/result.rb
24
+ - lib/simple/http/version.rb
25
+ - test/simple_http_test.rb
26
+ - test/test_helper.rb
27
+ homepage: http://github.com/radiospiel/simple-http
28
+ licenses: []
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.4.6
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Simple code for simple HTTP requests
50
+ test_files: []