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 +7 -0
- data/README.md +34 -0
- data/lib/simple/http/errors.rb +33 -0
- data/lib/simple/http/expires_in.rb +34 -0
- data/lib/simple/http/result.rb +41 -0
- data/lib/simple/http/version.rb +9 -0
- data/lib/simple/http.rb +166 -0
- data/test/simple_http_test.rb +14 -0
- data/test/test_helper.rb +11 -0
- metadata +50 -0
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
|
data/lib/simple/http.rb
ADDED
@@ -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
|
data/test/test_helper.rb
ADDED
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: []
|