funky-simplehttp 0.4.2
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/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +17 -0
- data/README.md +20 -0
- data/Rakefile +36 -0
- data/funky-simplehttp.gemspec +22 -0
- data/lib/simplehttp.rb +255 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 19b2df5b95c721fd8b240d79bba007b27e1b051b
|
4
|
+
data.tar.gz: d83529c9ae13241bb3f5761118391cea43e37086
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 32cc670f116b166c49b5c9f3db867b3717da27fe105647186ddb8dbbb1c11c9b579665ee05a3d2ba09f2a386be10914e2e61e72d5170faa4bb06c7510734067d
|
7
|
+
data.tar.gz: 4f437d49945cc6842524b6041ab7abf42fe0aba310c13511ae485555081d2b6a8ae964a6ec8fdfcadeac8a73e509c7d199b0e61b8e5d851cd4ac038abe065047
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# SimpleHttp Class for mruby
|
2
|
+
|
3
|
+
POC to CloudWalk gems and libs, pure ruby implementation.
|
4
|
+
|
5
|
+
Simple http or https connection class for mruby.
|
6
|
+
|
7
|
+
Project based on matsumoto-r/mruby-simplehttp and iij/mruby-simplehttp
|
8
|
+
|
9
|
+
## Contributing
|
10
|
+
|
11
|
+
1. Fork it
|
12
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
13
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
14
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
15
|
+
5. Create new Pull Request
|
16
|
+
|
17
|
+
# License
|
18
|
+
under the MIT License:
|
19
|
+
|
20
|
+
* http://www.opensource.org/licenses/mit-license.php
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rake'
|
2
|
+
#require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
SIMPLEHTTP_ROOT = File.dirname(File.expand_path(__FILE__))
|
5
|
+
SIMPLEHTTP_OUT = File.join(SIMPLEHTTP_ROOT, "out", "simplehttp.mrb")
|
6
|
+
|
7
|
+
task :default => :build
|
8
|
+
|
9
|
+
task :check do
|
10
|
+
if ENV["MRBC"].nil?
|
11
|
+
if system("type cloudwalk > /dev/null 2>&1 ")
|
12
|
+
ENV["MRBC"] = "env cloudwalk compile"
|
13
|
+
elsif system("type mrbc > /dev/null 2>&1 ")
|
14
|
+
ENV["MRBC"] = "env mrbc"
|
15
|
+
else
|
16
|
+
puts "$MRBC isn't set or mrbc/cloudwalk isn't on $PATH"
|
17
|
+
exit 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Compile simplehttp to mrb"
|
23
|
+
task :build => :check do
|
24
|
+
sh "mkdir -p #{File.join(SIMPLEHTTP_ROOT, "out")}"
|
25
|
+
if ENV["MRBC"]
|
26
|
+
sh "#{ENV["MRBC"]} -g -o #{SIMPLEHTTP_OUT} #{File.join(SIMPLEHTTP_ROOT, "lib", "simplehttp.rb")} "
|
27
|
+
else
|
28
|
+
sh "env mrbc -g -o #{SIMPLEHTTP_OUT} #{File.join(SIMPLEHTTP_ROOT, "lib", "simplehttp.rb")} "
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Clobber/Clean"
|
33
|
+
task :clean => :check do
|
34
|
+
sh "mkdir -p out"
|
35
|
+
sh "rm -f #{SIMPLEHTTP_OUT}"
|
36
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'simplehttp.rb'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "funky-simplehttp"
|
8
|
+
spec.version = SimpleHttp.version
|
9
|
+
spec.authors = ["Thiago Scalone"]
|
10
|
+
spec.email = ["thiago@scalone.com.br"]
|
11
|
+
spec.summary = "Simplehttp"
|
12
|
+
spec.description = "Minimal HTTP implementation"
|
13
|
+
spec.homepage = "http://github.com/cloudwalkio/funky-simplehttp"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.files = `git ls-files -z`.split("\x0") << "out/simplehttp.mrb"
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
end
|
data/lib/simplehttp.rb
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
class SimpleHttp
|
2
|
+
DEFAULTPORT = 80
|
3
|
+
DEFAULTHTTPSPORT = 443
|
4
|
+
HTTP_VERSION = "HTTP/1.0"
|
5
|
+
DEFAULT_ACCEPT = "*/*"
|
6
|
+
SEP = "\r\n"
|
7
|
+
|
8
|
+
def self.version
|
9
|
+
"0.4.2"
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :socket, :socket_tcp, :support_fiber
|
13
|
+
|
14
|
+
def socket_class_exist?
|
15
|
+
c = Module.const_get("TCPSocket")
|
16
|
+
c.is_a?(Class)
|
17
|
+
rescue
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
def uv_module_exist?
|
22
|
+
c = Module.const_get("UV")
|
23
|
+
c.is_a?(Module)
|
24
|
+
rescue
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(schema, address, port = nil)
|
29
|
+
@use_socket = false
|
30
|
+
@use_uv = false
|
31
|
+
if socket_class_exist?
|
32
|
+
@use_socket = true
|
33
|
+
end
|
34
|
+
|
35
|
+
if uv_module_exist?
|
36
|
+
@use_uv = true
|
37
|
+
end
|
38
|
+
@uri = {}
|
39
|
+
if @use_socket
|
40
|
+
# nothing
|
41
|
+
elsif @use_uv
|
42
|
+
ip = ""
|
43
|
+
UV::getaddrinfo(address, "http") do |x, info|
|
44
|
+
if info
|
45
|
+
ip = info.addr
|
46
|
+
end
|
47
|
+
end
|
48
|
+
UV::run()
|
49
|
+
@uri[:ip] = ip
|
50
|
+
else
|
51
|
+
raise "Not found Socket Class or UV Module"
|
52
|
+
end
|
53
|
+
@uri[:schema] = schema
|
54
|
+
@uri[:address] = address
|
55
|
+
if schema == "https"
|
56
|
+
@uri[:port] = port ? port.to_i : DEFAULTHTTPSPORT
|
57
|
+
else
|
58
|
+
@uri[:port] = port ? port.to_i : DEFAULTPORT
|
59
|
+
end
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def address; @uri[:address]; end
|
64
|
+
def port; @uri[:port]; end
|
65
|
+
|
66
|
+
def get(path = "/", req = nil)
|
67
|
+
request("GET", path, req)
|
68
|
+
end
|
69
|
+
|
70
|
+
def post(path = "/", req = nil)
|
71
|
+
request("POST", path, req)
|
72
|
+
end
|
73
|
+
|
74
|
+
# private
|
75
|
+
def request(method, path, req)
|
76
|
+
@uri[:path] = path
|
77
|
+
if @uri[:path].nil?
|
78
|
+
@uri[:path] = "/"
|
79
|
+
elsif @uri[:path][0] != "/"
|
80
|
+
@uri[:path] = "/" + @uri[:path]
|
81
|
+
end
|
82
|
+
request_header = create_request_header(method.upcase.to_s, req)
|
83
|
+
response_text = send_request(request_header)
|
84
|
+
SimpleHttpResponse.new(response_text)
|
85
|
+
end
|
86
|
+
|
87
|
+
def read_fiber
|
88
|
+
response_text = ""
|
89
|
+
loop do
|
90
|
+
return "" if (@socket_tcp.nil? || @socket_tcp.closed?)
|
91
|
+
usleep(10000)
|
92
|
+
if (available = socket.bytes_available) > 0
|
93
|
+
usleep(10000)
|
94
|
+
t = socket.read(available)
|
95
|
+
usleep(10000)
|
96
|
+
break if t.nil?
|
97
|
+
response_text << t
|
98
|
+
end
|
99
|
+
finish = Fiber.yield(false)
|
100
|
+
if finish
|
101
|
+
return response_text
|
102
|
+
end
|
103
|
+
end
|
104
|
+
response_text
|
105
|
+
end
|
106
|
+
|
107
|
+
def read_normal
|
108
|
+
response_text = ""
|
109
|
+
while (t = socket.read(1024))
|
110
|
+
response_text += t
|
111
|
+
end
|
112
|
+
response_text
|
113
|
+
end
|
114
|
+
|
115
|
+
def support_fiber?
|
116
|
+
@support_fiber
|
117
|
+
end
|
118
|
+
|
119
|
+
def send_request(request_header)
|
120
|
+
response_text = ""
|
121
|
+
if @socket
|
122
|
+
socket.write(request_header)
|
123
|
+
if support_fiber?
|
124
|
+
response_text = read_fiber
|
125
|
+
else
|
126
|
+
response_text = read_normal
|
127
|
+
end
|
128
|
+
elsif @use_socket
|
129
|
+
@socket = TCPSocket.new(@uri[:address], @uri[:port])
|
130
|
+
if @uri[:schema] == "https"
|
131
|
+
entropy = PolarSSL::Entropy.new
|
132
|
+
ctr_drbg = PolarSSL::CtrDrbg.new entropy
|
133
|
+
ssl = PolarSSL::SSL.new
|
134
|
+
ssl.set_endpoint PolarSSL::SSL::SSL_IS_CLIENT
|
135
|
+
ssl.set_rng ctr_drbg
|
136
|
+
ssl.set_socket socket
|
137
|
+
ssl.handshake
|
138
|
+
ssl.write request_header
|
139
|
+
while chunk = ssl.read(2048)
|
140
|
+
response_text += chunk
|
141
|
+
end
|
142
|
+
ssl.close_notify
|
143
|
+
socket.close
|
144
|
+
ssl.close
|
145
|
+
else
|
146
|
+
socket.write(request_header)
|
147
|
+
while (t = socket.read(1024))
|
148
|
+
response_text += t
|
149
|
+
end
|
150
|
+
socket.close
|
151
|
+
end
|
152
|
+
elsif @use_uv
|
153
|
+
socket = UV::TCP.new()
|
154
|
+
socket.connect(UV.ip4_addr(@uri[:ip].sin_addr, @uri[:port])) do |x|
|
155
|
+
if x == 0
|
156
|
+
socket.write(request_header) do |x|
|
157
|
+
socket.read_start do |b|
|
158
|
+
response_text += b.to_s
|
159
|
+
end
|
160
|
+
end
|
161
|
+
else
|
162
|
+
socket.close()
|
163
|
+
end
|
164
|
+
end
|
165
|
+
UV::run()
|
166
|
+
else
|
167
|
+
raise "Not found Socket Class or UV Module"
|
168
|
+
end
|
169
|
+
response_text
|
170
|
+
end
|
171
|
+
|
172
|
+
def create_request_header(method, req)
|
173
|
+
req = {} unless req
|
174
|
+
str = ""
|
175
|
+
body = ""
|
176
|
+
str += sprintf("%s %s %s", method, @uri[:path], HTTP_VERSION) + SEP
|
177
|
+
header = {}
|
178
|
+
req.each do |key,value|
|
179
|
+
header[key.capitalize] = value
|
180
|
+
end
|
181
|
+
header["Host"] = @uri[:address] unless header.keys.include?("Host")
|
182
|
+
header["Accept"] = DEFAULT_ACCEPT unless header.keys.include?("Accept")
|
183
|
+
header["Connection"] = "close"
|
184
|
+
if header["Body"]
|
185
|
+
body = header["Body"]
|
186
|
+
header.delete("Body")
|
187
|
+
end
|
188
|
+
if method == "POST" && (not header.keys.include?("content-length".capitalize))
|
189
|
+
header["Content-Length"] = (body || '').length
|
190
|
+
end
|
191
|
+
header.keys.sort.each do |key|
|
192
|
+
str += sprintf("%s: %s", key, header[key]) + SEP
|
193
|
+
end
|
194
|
+
str + SEP + body
|
195
|
+
end
|
196
|
+
|
197
|
+
class SimpleHttpResponse
|
198
|
+
SEP = SimpleHttp::SEP
|
199
|
+
def initialize(response_text)
|
200
|
+
@response = {}
|
201
|
+
@headers = {}
|
202
|
+
if response_text.empty?
|
203
|
+
@response["header"] = nil
|
204
|
+
elsif response_text.include?(SEP + SEP)
|
205
|
+
@response["header"], @response["body"] = response_text.split(SEP + SEP, 2)
|
206
|
+
else
|
207
|
+
@response["header"] = response_text
|
208
|
+
end
|
209
|
+
parse_header
|
210
|
+
self
|
211
|
+
end
|
212
|
+
|
213
|
+
def [](key); @response[key]; end
|
214
|
+
def []=(key, value); @response[key] = value; end
|
215
|
+
|
216
|
+
def header; @response['header']; end
|
217
|
+
def headers; @headers; end
|
218
|
+
def body; @response['body']; end
|
219
|
+
def status; @response['status']; end
|
220
|
+
def code; @response['code']; end
|
221
|
+
def date; @response['date']; end
|
222
|
+
def content_type; @response['content-type']; end
|
223
|
+
def content_length; @response['content-length']; end
|
224
|
+
|
225
|
+
def each(&block)
|
226
|
+
if block
|
227
|
+
@response.each do |k,v| block.call(k,v) end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
def each_name(&block)
|
231
|
+
if block
|
232
|
+
@response.each do |k,v| block.call(k) end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# private
|
237
|
+
def parse_header
|
238
|
+
return unless @response["header"]
|
239
|
+
h = @response["header"].split(SEP)
|
240
|
+
if h[0].include?("HTTP/1")
|
241
|
+
@response["status"] = h[0].split(" ", 2).last
|
242
|
+
@response["code"] = h[0].split(" ", 3)[1].to_i
|
243
|
+
end
|
244
|
+
h.each do |line|
|
245
|
+
if line.include?(": ")
|
246
|
+
k,v = line.split(": ")
|
247
|
+
@response[k.downcase] = v
|
248
|
+
@headers[k.downcase] = v
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: funky-simplehttp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thiago Scalone
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Minimal HTTP implementation
|
42
|
+
email:
|
43
|
+
- thiago@scalone.com.br
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- funky-simplehttp.gemspec
|
54
|
+
- lib/simplehttp.rb
|
55
|
+
- out/simplehttp.mrb
|
56
|
+
homepage: http://github.com/cloudwalkio/funky-simplehttp
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
metadata: {}
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 2.2.2
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: Simplehttp
|
80
|
+
test_files: []
|
81
|
+
has_rdoc:
|