req 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +1 -0
- data/lib/req.rb +16 -0
- data/lib/req/client.rb +167 -0
- data/lib/req/part.rb +53 -0
- data/lib/req/query.rb +75 -0
- data/lib/req/version.rb +3 -0
- data/req.gemspec +30 -0
- data/server.rb +108 -0
- data/spec/auth_spec.rb +32 -0
- data/spec/get_spec.rb +27 -0
- data/spec/header_spec.rb +53 -0
- data/spec/post_spec.rb +33 -0
- data/spec/schema_spec.rb +13 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/tmp.txt +1 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YzlmZDE1M2FiNzMwN2U3YzRkNTg0YjFmMGIxZTk0ODg5YjU5MzE3ZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OTk0NzIxZmYxNTUyYTVmZGUwYzgyYjI5ZjMyMmM4YmFiMjMxMzk2Mg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmQ4MDllNTBmMGMzNjc3NGNjYzAxODY2NjY4ZDFhMTE4ZTI3OTE3NDY4OWRk
|
10
|
+
ZTMwZDg3MGYyZDYyYmQzNDY1MzM3NzExOWY0ODQ4NmEyMzE5MmI1YzI3ZjEz
|
11
|
+
MzhkMGNmM2M0YzU3ZTllZTk3ZDgzODNmNTI4YzliYmJiZjkzNmM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjhmMzNlZDA2MzM0OWEyYjAzMjk5M2U1YzYyYzA4Y2FjZTJiNDA0OTY1ZWRk
|
14
|
+
OTA2NTFmZGViM2RiMjMzZjhmOWVjNjE4NDI2ZGU0ZjM0NmJlYzE1ZTA2OGUz
|
15
|
+
YjdjYjMxZjA0ZTE5MGZlZDcwN2ZmZGE0M2QyMTQ5N2FiMjk2YzE=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 wenjun.yan
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Req
|
2
|
+
MAKE SIMPLE REQUEST SIMPLE.
|
3
|
+
|
4
|
+
A simple http/net wrapper to make http request easy.
|
5
|
+
|
6
|
+
Inspired by request.js
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'req'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install req
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
> How to fork it?
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
Req["https://api.github.com/repo/v2e4lisp/req/forks"].auth("user", "pass").post
|
28
|
+
```
|
29
|
+
|
30
|
+
> Send data(get).
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
Req[url].send(a: 1, b: 2).get
|
34
|
+
```
|
35
|
+
|
36
|
+
> Post json
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Req[url].send(a: 1, b: 2).send(c: 3).type(:json).post
|
40
|
+
```
|
41
|
+
|
42
|
+
> Post form
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Req[url].send(field1: "username").send(field2: "password").type(:form).post
|
46
|
+
```
|
47
|
+
|
48
|
+
> Post form with file(multipart form)
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Req[url].send(field1: "username").send("file", csv_file, "optional-filename").post
|
52
|
+
```
|
53
|
+
|
54
|
+
> some other simple API
|
55
|
+
|
56
|
+
* write(string): write to body
|
57
|
+
* header(hash) : write to header
|
58
|
+
* reset : reset body and header
|
59
|
+
* get(n) : get with redirection limit default is 4
|
60
|
+
* use_ssl(bool): turn on/off ssl. It will be auto turned on when scheme is "https"
|
61
|
+
* mulit(bool) : multipart form header. Auto turned on when files detected
|
62
|
+
* type() : specify content-type (:text,:json,:html,:xml,:form)
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
1. Fork it
|
69
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
70
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
72
|
+
5. Create new Pull Req
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/req.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'base64'
|
4
|
+
require 'mime/types'
|
5
|
+
require "req/version"
|
6
|
+
require "req/query"
|
7
|
+
require "req/part"
|
8
|
+
require "req/client"
|
9
|
+
|
10
|
+
module Req
|
11
|
+
class << self
|
12
|
+
def [](url)
|
13
|
+
Client.new(url)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/req/client.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
module Req
|
2
|
+
TYPE = {json: 'application/json',
|
3
|
+
form: 'application/x-www-form-urlencoded',
|
4
|
+
text: 'text/plain',
|
5
|
+
html: 'text/html',
|
6
|
+
xml: 'application/xml'}
|
7
|
+
|
8
|
+
class Client
|
9
|
+
attr_accessor :data, :files, :body, :headers
|
10
|
+
attr_reader :client, :url
|
11
|
+
|
12
|
+
def initialize(url)
|
13
|
+
self.url = url
|
14
|
+
@data = {}
|
15
|
+
@headers = {}
|
16
|
+
@files = []
|
17
|
+
@body = ''
|
18
|
+
@client = Net::HTTP.new(uri.hostname, uri.port)
|
19
|
+
use_ssl if uri.scheme == "https"
|
20
|
+
end
|
21
|
+
|
22
|
+
def get limit=4
|
23
|
+
update_uri
|
24
|
+
res = client.get(uri.request_uri, headers)
|
25
|
+
limit.times do
|
26
|
+
break unless res.is_a? Net::HTTPRedirection
|
27
|
+
# reset url and http client in case of the url scheme changed
|
28
|
+
# if no location found, Invalid response! CRUSH DOWN.
|
29
|
+
self.url = res['location']
|
30
|
+
@client = Net::HTTP.new(uri.hostname, uri.port)
|
31
|
+
use_ssl if uri.scheme == "https"
|
32
|
+
res = client.get(res['location'], headers)
|
33
|
+
end
|
34
|
+
block_given? ? yield(res) : res
|
35
|
+
end
|
36
|
+
|
37
|
+
# http verbs
|
38
|
+
[:head, :delete, :options].each do |method|
|
39
|
+
define_method method do |&block|
|
40
|
+
update_uri
|
41
|
+
res = client.send(method, uri.request_uri, headers)
|
42
|
+
block ? block.call(res) : res
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
[:post, :put, :patch].each do |method|
|
47
|
+
define_method method do |&block|
|
48
|
+
build
|
49
|
+
res = client.send(method, uri.request_uri, body, headers)
|
50
|
+
block ? block.call(res) : res
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def use_ssl use=true
|
55
|
+
client.use_ssl = use
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# basic authentication
|
60
|
+
def auth user, pass
|
61
|
+
set "Authorization" => "Basic #{Base64.encode64(user + ":" + pass).chop}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def send name, file=nil, filename=nil
|
65
|
+
if file
|
66
|
+
upload name, file, filename
|
67
|
+
else
|
68
|
+
query name
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def upload field, file, filename = nil
|
73
|
+
file = File.open(file)
|
74
|
+
@files << [field, file, filename || file.path]
|
75
|
+
self
|
76
|
+
end
|
77
|
+
alias_method :attach, :upload
|
78
|
+
|
79
|
+
def query option
|
80
|
+
data.merge! option
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def header option
|
85
|
+
headers.merge! option
|
86
|
+
self
|
87
|
+
end
|
88
|
+
alias_method :set, :header
|
89
|
+
|
90
|
+
def write body
|
91
|
+
@body << body
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def type t
|
96
|
+
# Set `Content-Type` header
|
97
|
+
tp = t.to_sym
|
98
|
+
t = TYPE[tp] if TYPE[tp]
|
99
|
+
set "Content-Type" => t
|
100
|
+
end
|
101
|
+
|
102
|
+
def multi on=true
|
103
|
+
@multi = on
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def clear
|
108
|
+
@data = {}
|
109
|
+
@headers = {}
|
110
|
+
@files = []
|
111
|
+
@body = ''
|
112
|
+
self
|
113
|
+
end
|
114
|
+
alias_method :reset, :clear
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def build
|
119
|
+
if not files.empty? or @multi
|
120
|
+
build_multipart
|
121
|
+
else
|
122
|
+
build_body
|
123
|
+
end
|
124
|
+
build_header
|
125
|
+
end
|
126
|
+
|
127
|
+
def build_header
|
128
|
+
return if headers['Content-Length']
|
129
|
+
headers['Content-Length'] = body.bytesize.to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
def build_body
|
133
|
+
case headers['Content-Type']
|
134
|
+
when nil, TYPE[:form] then write data.to_query
|
135
|
+
when TYPE[:json] then write data.to_json
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def build_multipart
|
140
|
+
m = Multipart.create(files, data)
|
141
|
+
write m.body
|
142
|
+
header m.header
|
143
|
+
end
|
144
|
+
|
145
|
+
def update_uri
|
146
|
+
unless data.empty?
|
147
|
+
url << "?" unless url["?"]
|
148
|
+
url << data.to_query
|
149
|
+
@uri = nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def uri
|
154
|
+
@uri ||= URI(url).tap do |u|
|
155
|
+
# If the url is something like this: http://user:password@localhost",
|
156
|
+
# we setup the basic authorization header.
|
157
|
+
auth(u.user, u.password) if u.user and u.password
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# if not schema is given, default is `http`
|
162
|
+
def url= url
|
163
|
+
@uri = nil
|
164
|
+
@url = (url['://'] ? '' : 'http://') << url
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/req/part.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Req
|
2
|
+
module Multipart
|
3
|
+
BOUNDARY = "--ruby-request--"
|
4
|
+
DEFAULT_MIME = "application/octet-stream"
|
5
|
+
|
6
|
+
def self.create files, data
|
7
|
+
Fields.new(files, data)
|
8
|
+
end
|
9
|
+
|
10
|
+
class Fields
|
11
|
+
def initialize files, data
|
12
|
+
@files = files || []
|
13
|
+
@params = data || []
|
14
|
+
end
|
15
|
+
|
16
|
+
def body
|
17
|
+
@body ||= '' << @files.inject("") { |acc, file|
|
18
|
+
acc << Attachment.new(*file).part
|
19
|
+
} << @params.inject("") { |acc, param|
|
20
|
+
acc << Param.new(*param).part
|
21
|
+
} << "--#{BOUNDARY}--\r\n\r\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def header
|
25
|
+
@header ||= {"Content-Length" => @body.bytesize.to_s,
|
26
|
+
"Content-Type" => "multipart/form-data; boundary=#{BOUNDARY}"}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Attachment < Struct.new(:field, :file, :filename)
|
31
|
+
def part
|
32
|
+
return @part if @part
|
33
|
+
type = ::MIME::Types.type_for(filename).first || DEFAULT_MIME
|
34
|
+
@part = ''
|
35
|
+
@part << "--#{BOUNDARY}\r\n"
|
36
|
+
@part << "Content-Disposition: form-data; name=\"#{field}\"; filename=\"#{filename}\"\r\n"
|
37
|
+
@part << "Content-Type: #{type}\r\n\r\n"
|
38
|
+
@part << "#{file.read}\r\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Param < Struct.new(:field, :value)
|
43
|
+
def part
|
44
|
+
return @part if @part
|
45
|
+
@part = ''
|
46
|
+
@part << "--#{BOUNDARY}\r\n"
|
47
|
+
@part << "Content-Disposition: form-data; name=\"#{field}\"\r\n"
|
48
|
+
@part << "\r\n"
|
49
|
+
@part << "#{value}\r\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/req/query.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# FOLLOWING CODE IS FROM `rails/activesupport'
|
2
|
+
class Object
|
3
|
+
# Alias of <tt>to_s</tt>.
|
4
|
+
def to_param
|
5
|
+
to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
# Converts an object into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
|
9
|
+
# param name.
|
10
|
+
#
|
11
|
+
# Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
|
12
|
+
def to_query(key)
|
13
|
+
require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
|
14
|
+
"#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class NilClass
|
19
|
+
def to_param
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TrueClass
|
25
|
+
def to_param
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class FalseClass
|
31
|
+
def to_param
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Array
|
37
|
+
# Calls <tt>to_param</tt> on all its elements and joins the result with
|
38
|
+
# slashes. This is used by <tt>url_for</tt> in Action Pack.
|
39
|
+
def to_param
|
40
|
+
collect { |e| e.to_param }.join '/'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Converts an array into a string suitable for use as a URL query string,
|
44
|
+
# using the given +key+ as the param name.
|
45
|
+
#
|
46
|
+
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
|
47
|
+
def to_query(key)
|
48
|
+
prefix = "#{key}[]"
|
49
|
+
collect { |value| value.to_query(prefix) }.join '&'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Hash
|
54
|
+
# Returns a string representation of the receiver suitable for use as a URL
|
55
|
+
# query string:
|
56
|
+
#
|
57
|
+
# {:name => 'David', :nationality => 'Danish'}.to_param
|
58
|
+
# # => "name=David&nationality=Danish"
|
59
|
+
#
|
60
|
+
# An optional namespace can be passed to enclose the param names:
|
61
|
+
#
|
62
|
+
# {:name => 'David', :nationality => 'Danish'}.to_param('user')
|
63
|
+
# # => "user[name]=David&user[nationality]=Danish"
|
64
|
+
#
|
65
|
+
# The string pairs "key=value" that conform the query string
|
66
|
+
# are sorted lexicographically in ascending order.
|
67
|
+
#
|
68
|
+
# This method is also aliased as +to_query+.
|
69
|
+
def to_param(namespace = nil)
|
70
|
+
collect do |key, value|
|
71
|
+
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
|
72
|
+
end.sort * '&'
|
73
|
+
end
|
74
|
+
alias_method :to_query, :to_param
|
75
|
+
end
|
data/lib/req/version.rb
ADDED
data/req.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'req/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "req"
|
8
|
+
spec.version = Req::VERSION
|
9
|
+
spec.authors = ["wenjun.yan"]
|
10
|
+
spec.email = ["mylastnameisyan@gmail.com"]
|
11
|
+
spec.description = %q{an easy way to deal with simple http request}
|
12
|
+
spec.summary = %q{FORK ME => Req["https://api.github.com/repo/v2e4lisp/req/forks"].auth("user", "pass").post }
|
13
|
+
spec.homepage = "https://github.com/v2e4lisp/req"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "mime-types"
|
22
|
+
spec.add_dependency "json"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency 'sinatra'
|
29
|
+
spec.add_development_dependency 'sinatra-contrib'
|
30
|
+
end
|
data/server.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require "sinatra/multi_route"
|
3
|
+
require "sinatra/cookies"
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
def header_titleize header
|
7
|
+
header.split("_").map {|w| w.capitalize }.join "-"
|
8
|
+
end
|
9
|
+
|
10
|
+
class Httpbin < Sinatra::Base
|
11
|
+
register Sinatra::MultiRoute
|
12
|
+
helpers Sinatra::Cookies
|
13
|
+
include FileUtils::Verbose
|
14
|
+
|
15
|
+
def authorized? user="test", pass="test"
|
16
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
17
|
+
@auth.provided? &&
|
18
|
+
@auth.basic? &&
|
19
|
+
@auth.credentials &&
|
20
|
+
@auth.credentials == [user, pass]
|
21
|
+
end
|
22
|
+
|
23
|
+
def echo
|
24
|
+
request.env.inject({}) { |acc, item|
|
25
|
+
acc.tap do |result|
|
26
|
+
if item[0]["HTTP_"]
|
27
|
+
result[header_titleize(item[0].gsub(/^HTTP_/, ""))] = item[1]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
}.tap {|header|
|
31
|
+
header["Content-Type"] = env["CONTENT_TYPE"] if env["CONTENT_TYPE"]
|
32
|
+
}.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
def data
|
36
|
+
if request.env["CONTENT_TYPE"] == "application/json"
|
37
|
+
request.body
|
38
|
+
else
|
39
|
+
params.to_json
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def render_cookies
|
44
|
+
cookies.to_hash.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
before '/auth*' do
|
48
|
+
path = params[:splat].first
|
49
|
+
user, pass = path["/"] ? path[1..-1].split("/") : ["test", "test"]
|
50
|
+
unless authorized? user, pass
|
51
|
+
response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
|
52
|
+
throw(:halt, [401, "Oops... we need your login name & password\n"])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
get "/cookie" do
|
57
|
+
render_cookies
|
58
|
+
end
|
59
|
+
|
60
|
+
get "/cookie/delete/:name" do
|
61
|
+
#response.delete_cookie params[:name]
|
62
|
+
response.set_cookie(params[:name],
|
63
|
+
value: "",
|
64
|
+
path: "/cookie",
|
65
|
+
:expires => Time.now - 3600*24)
|
66
|
+
params[:name]
|
67
|
+
end
|
68
|
+
|
69
|
+
get "/cookie/:name/:value" do
|
70
|
+
response.set_cookie(params[:name],
|
71
|
+
value: params[:value],
|
72
|
+
path: "/cookie")
|
73
|
+
render_cookies
|
74
|
+
end
|
75
|
+
|
76
|
+
get "/upload" do
|
77
|
+
<<-FORM
|
78
|
+
<form action='/upload' enctype="multipart/form-data" method='post'>
|
79
|
+
<input name="file" type="file" />
|
80
|
+
<input name="var" type="text" />
|
81
|
+
<input type="submit" value="Upload" />
|
82
|
+
</form>
|
83
|
+
FORM
|
84
|
+
end
|
85
|
+
|
86
|
+
route :post, :put, "/upload" do
|
87
|
+
params[:file][:tempfile].read
|
88
|
+
# request.body
|
89
|
+
end
|
90
|
+
|
91
|
+
route :get, :post, :put, :patch, :delete, "/auth" do
|
92
|
+
data
|
93
|
+
end
|
94
|
+
|
95
|
+
route :get, :post, :put, :patch, :delete, "/auth/:user/:pass" do
|
96
|
+
data
|
97
|
+
end
|
98
|
+
|
99
|
+
route :get, :post, :put, :patch, :delete, "/headers" do
|
100
|
+
echo
|
101
|
+
end
|
102
|
+
|
103
|
+
route :get, :post, :put, :patch, :delete, "/" do
|
104
|
+
data
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
Httpbin.run!
|
data/spec/auth_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "./spec_helper"
|
2
|
+
include Helpers
|
3
|
+
|
4
|
+
describe "basic auth" do
|
5
|
+
describe "using auth method for basic authentication" do
|
6
|
+
url = base + "/auth"
|
7
|
+
it "should return ok" do
|
8
|
+
req = request(url).auth("test", "test")
|
9
|
+
request(url).auth("test", "test").get.body.should eq("{}")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should fail when no user or password" do
|
13
|
+
request(url).get.should respond_status(401)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should fail when invalid user and password" do
|
17
|
+
request(url).auth("fake", "test").get.should respond_status(401)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "using url for basic authentication" do
|
22
|
+
it "should return ok" do
|
23
|
+
url = "http://test:test@localhost:4567/auth"
|
24
|
+
request(url).get.body.should eq("{}")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should fail when invalid user and password" do
|
28
|
+
url = "http://fake:test@localhost:4567/auth"
|
29
|
+
request(url).get.should respond_status(401)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/get_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "./spec_helper"
|
2
|
+
|
3
|
+
describe "Get from localhost:4567" do
|
4
|
+
url = base
|
5
|
+
it "should success" do
|
6
|
+
request(url).get.should respond_status(200)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return the query data" do
|
10
|
+
query = "x=1"
|
11
|
+
request("#{url}?#{query}").get.body.from_json.should eq({"x" => "1"})
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Using query or send to set query data" do
|
15
|
+
it "Set data in one query" do
|
16
|
+
request(url).send(hello: "x", world: 1).get.body.from_json
|
17
|
+
.should eq({"hello" => "x", "world" => "1"})
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Multiple query call will merge the data" do
|
21
|
+
request(url).send(hello: "x").send(world: 1).get.body.from_json
|
22
|
+
.should eq({"hello" => "x", "world" => "1"})
|
23
|
+
request(url).query(hello: "x").query(world: 1).get.body.from_json
|
24
|
+
.should eq({"hello" => "x", "world" => "1"})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/header_spec.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require "./spec_helper"
|
2
|
+
include Helpers
|
3
|
+
|
4
|
+
describe "Request.header" do
|
5
|
+
url = base + "/headers"
|
6
|
+
|
7
|
+
it "set multiple header" do
|
8
|
+
request(url).header("X-1" => "x1").header("X-2" => "x2").get
|
9
|
+
.should send_header("X-1" => "x1","X-2" => "x2")
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "Content-Type" do
|
13
|
+
describe "#header" do
|
14
|
+
it "set to application/json" do
|
15
|
+
request(url).header("Content-Type" => "xxx").post
|
16
|
+
.should send_header("content-type" => "xxx")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#type" do
|
21
|
+
it "set Content-Type to customized type" do
|
22
|
+
request(url).type("xxx").post
|
23
|
+
.should send_header("content-type" => "xxx")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "set Content-Type to text/html" do
|
27
|
+
request(url).type(:html).post
|
28
|
+
.should send_header("content-type" => "text/html")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "set Content-Type to application/json" do
|
32
|
+
request(url).type(:json).post
|
33
|
+
.should send_header("content-type" => "application/json")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "set Content-Type to application/x-www-form-urlencoded" do
|
37
|
+
request(url).type(:form).post
|
38
|
+
.should send_header("content-type" =>
|
39
|
+
"application/x-www-form-urlencoded")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "set Content-Type to application/xml" do
|
43
|
+
request(url).type(:xml).post
|
44
|
+
.should send_header("content-type" => "application/xml")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "set Content-Type to text/plain" do
|
48
|
+
request(url).type(:text).post
|
49
|
+
.should send_header("content-type" => "text/plain")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/post_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "./spec_helper"
|
2
|
+
|
3
|
+
describe "Post to localhost:4567" do
|
4
|
+
url = base
|
5
|
+
query = {"x" => 1}
|
6
|
+
|
7
|
+
it "should success" do
|
8
|
+
request(url).post.should respond_status(200)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Post form" do
|
12
|
+
context "with param" do
|
13
|
+
it "should return the same query data" do
|
14
|
+
request(url).query(query).post.body.from_json.should eq({"x" => "1"})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
context "with file" do
|
18
|
+
it "should return the same text in the uploaded file" do
|
19
|
+
text = "uploading"
|
20
|
+
tmpfile = "./tmp.txt"
|
21
|
+
File.open(tmpfile, "w") { |f| f << text }
|
22
|
+
request(url + "/upload").upload("file", tmpfile)
|
23
|
+
.post.body.should eq(text)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "Post json" do
|
29
|
+
it "should reutrn the same json data" do
|
30
|
+
request(url).query(query).type(:json).post.body.from_json.should eq(query)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/schema_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require '../lib/req.rb'
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
class String
|
5
|
+
def from_json
|
6
|
+
JSON.parse self
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def base
|
11
|
+
"http://localhost:4567"
|
12
|
+
end
|
13
|
+
|
14
|
+
# API
|
15
|
+
def request url
|
16
|
+
Req::Client.new(url)
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
end
|
21
|
+
|
22
|
+
module Helpers
|
23
|
+
extend RSpec::Matchers::DSL
|
24
|
+
matcher :respond_status do |code|
|
25
|
+
match do |actual|
|
26
|
+
actual.code.to_i == code.to_i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
matcher :send_header do |header|
|
31
|
+
match do |actual|
|
32
|
+
actual_header = actual.body.from_json
|
33
|
+
header.inject(true) do |acc, item|
|
34
|
+
key = item.first.split("-").map {|w| w.capitalize }.join "-"
|
35
|
+
acc and (actual_header[key] == item.last)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/tmp.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
uploading
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: req
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- wenjun.yan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mime-types
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sinatra
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sinatra-contrib
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: an easy way to deal with simple http request
|
126
|
+
email:
|
127
|
+
- mylastnameisyan@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- Gemfile
|
134
|
+
- LICENSE.txt
|
135
|
+
- README.md
|
136
|
+
- Rakefile
|
137
|
+
- lib/req.rb
|
138
|
+
- lib/req/client.rb
|
139
|
+
- lib/req/part.rb
|
140
|
+
- lib/req/query.rb
|
141
|
+
- lib/req/version.rb
|
142
|
+
- req.gemspec
|
143
|
+
- server.rb
|
144
|
+
- spec/auth_spec.rb
|
145
|
+
- spec/get_spec.rb
|
146
|
+
- spec/header_spec.rb
|
147
|
+
- spec/post_spec.rb
|
148
|
+
- spec/schema_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
- spec/tmp.txt
|
151
|
+
homepage: https://github.com/v2e4lisp/req
|
152
|
+
licenses:
|
153
|
+
- MIT
|
154
|
+
metadata: {}
|
155
|
+
post_install_message:
|
156
|
+
rdoc_options: []
|
157
|
+
require_paths:
|
158
|
+
- lib
|
159
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ! '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ! '>='
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
requirements: []
|
170
|
+
rubyforge_project:
|
171
|
+
rubygems_version: 2.0.5
|
172
|
+
signing_key:
|
173
|
+
specification_version: 4
|
174
|
+
summary: FORK ME => Req["https://api.github.com/repo/v2e4lisp/req/forks"].auth("user",
|
175
|
+
"pass").post
|
176
|
+
test_files:
|
177
|
+
- spec/auth_spec.rb
|
178
|
+
- spec/get_spec.rb
|
179
|
+
- spec/header_spec.rb
|
180
|
+
- spec/post_spec.rb
|
181
|
+
- spec/schema_spec.rb
|
182
|
+
- spec/spec_helper.rb
|
183
|
+
- spec/tmp.txt
|