req 0.0.1
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 +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
|