jruby-http-reactor 0.5.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.
- data/README.rdoc +13 -0
- data/README.textile +13 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/examples/opml.rb +31 -0
- data/jruby-http-reactor.gemspec +55 -0
- data/lib/http_reactor/client.rb +287 -0
- data/lib/http_reactor/request.rb +16 -0
- data/lib/http_reactor/response.rb +67 -0
- data/lib/http_reactor.rb +14 -0
- data/test/client_test.rb +49 -0
- data/test/test_helper.rb +2 -0
- data/vendor/httpcore-4.0.1.jar +0 -0
- data/vendor/httpcore-nio-4.0.1.jar +0 -0
- metadata +71 -0
data/README.rdoc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
A client that uses the Apache HttpCore NIO library to do HTTP requests.
|
2
|
+
|
3
|
+
<pre>
|
4
|
+
require 'http_reactor'
|
5
|
+
|
6
|
+
uris = ['http://www.yahoo.com/','http://www.google.com/']
|
7
|
+
requests = uris.map { |uri| HttpReactor::Request.new(uri) }
|
8
|
+
|
9
|
+
HttpReactor::Client.new(requests) do |response, context|
|
10
|
+
puts "Response code: #{response.code}"
|
11
|
+
puts "Response body: #{response.body}"
|
12
|
+
end
|
13
|
+
</pre>
|
data/README.textile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
A client that uses the Apache HttpCore NIO library to do HTTP requests.
|
2
|
+
|
3
|
+
<pre>
|
4
|
+
require 'http_reactor'
|
5
|
+
|
6
|
+
uris = ['http://www.yahoo.com/','http://www.google.com/']
|
7
|
+
requests = uris.map { |uri| HttpReactor::Request.new(uri) }
|
8
|
+
|
9
|
+
HttpReactor::Client.new(requests) do |response, context|
|
10
|
+
puts "Response code: #{response.code}"
|
11
|
+
puts "Response body: #{response.body}"
|
12
|
+
end
|
13
|
+
</pre>
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
|
4
|
+
desc 'Default: run tests.'
|
5
|
+
task :default => [:test]
|
6
|
+
|
7
|
+
desc 'Run tests.'
|
8
|
+
task :test do
|
9
|
+
require File.dirname(__FILE__) + '/test/client_test'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Generate documentation.'
|
13
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'rdoc'
|
15
|
+
rdoc.title = 'JRuby HTTP Reactor'
|
16
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
17
|
+
rdoc.rdoc_files.include('README.rdoc')
|
18
|
+
rdoc.rdoc_files.include('lib/*.rb')
|
19
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'jeweler'
|
24
|
+
Jeweler::Tasks.new do |gemspec|
|
25
|
+
gemspec.name = "jruby-http-reactor"
|
26
|
+
gemspec.summary = "JRuby NIO HTTP client."
|
27
|
+
gemspec.email = "anthonyeden@gmail.com"
|
28
|
+
gemspec.homepage = "http://github.com/aeden/jruby-http-reactor"
|
29
|
+
gemspec.description = ""
|
30
|
+
gemspec.authors = ["Anthony Eden"]
|
31
|
+
gemspec.files.exclude 'docs/**/*'
|
32
|
+
gemspec.files.exclude '.gitignore'
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
36
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.2
|
data/examples/opml.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
#
|
3
|
+
# Usage: jruby examples/opml.rb opml.xml
|
4
|
+
#
|
5
|
+
# Dependencies:
|
6
|
+
#
|
7
|
+
# hpricot (0.6.164)
|
8
|
+
# threadify (1.1.0) (optional, uncomment in code)
|
9
|
+
|
10
|
+
require 'uri'
|
11
|
+
require 'rubygems'
|
12
|
+
require 'hpricot'
|
13
|
+
#require 'threadify'
|
14
|
+
require File.dirname(__FILE__) + '/../lib/http_reactor'
|
15
|
+
|
16
|
+
def requests
|
17
|
+
@requests ||= begin
|
18
|
+
xml = File.read(ARGV.pop)
|
19
|
+
doc = Hpricot::XML(xml)
|
20
|
+
urls = (doc/'outline').map { |outline| outline['xmlUrl'] }
|
21
|
+
urls.map { |url_string| HttpReactor::Request.new(URI.parse(url_string)) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#uris.threadify(:each_slice, 1) do |slice|
|
26
|
+
HttpReactor::Client.new(requests) do |response, context|
|
27
|
+
puts "Response: #{response.status_line.status_code}"
|
28
|
+
puts "Content length: #{response.body.length}"
|
29
|
+
end
|
30
|
+
#end
|
31
|
+
puts "Processed #{requests.length} feeds"
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{jruby-http-reactor}
|
8
|
+
s.version = "0.5.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Anthony Eden"]
|
12
|
+
s.date = %q{2009-10-22}
|
13
|
+
s.description = %q{}
|
14
|
+
s.email = %q{anthonyeden@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc",
|
17
|
+
"README.textile"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"README.rdoc",
|
21
|
+
"README.textile",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"examples/opml.rb",
|
25
|
+
"jruby-http-reactor.gemspec",
|
26
|
+
"lib/http_reactor.rb",
|
27
|
+
"lib/http_reactor/client.rb",
|
28
|
+
"lib/http_reactor/request.rb",
|
29
|
+
"lib/http_reactor/response.rb",
|
30
|
+
"test/client_test.rb",
|
31
|
+
"test/test_helper.rb",
|
32
|
+
"vendor/httpcore-4.0.1.jar",
|
33
|
+
"vendor/httpcore-nio-4.0.1.jar"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/aeden/jruby-http-reactor}
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = %q{1.3.5}
|
39
|
+
s.summary = %q{JRuby NIO HTTP client.}
|
40
|
+
s.test_files = [
|
41
|
+
"test/client_test.rb",
|
42
|
+
"test/test_helper.rb",
|
43
|
+
"examples/opml.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
else
|
52
|
+
end
|
53
|
+
else
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
module HttpReactor #:nodoc:
|
2
|
+
class RequestExecutionHandler #:nodoc:
|
3
|
+
import org.apache.http.protocol
|
4
|
+
import org.apache.http.nio.protocol
|
5
|
+
include HttpRequestExecutionHandler
|
6
|
+
|
7
|
+
REQUEST_SENT = "request-sent"
|
8
|
+
RESPONSE_RECEIVED = "response-received"
|
9
|
+
|
10
|
+
HTTP_TARGET_PATH = 'http_target_path'
|
11
|
+
HTTP_TARGET_REQUEST = 'http_target_request'
|
12
|
+
IO_REACTOR = "io_reactor"
|
13
|
+
REDIRECT_HISTORY = "redirect_history"
|
14
|
+
|
15
|
+
def initialize(request_count, handler_proc)
|
16
|
+
@request_count = request_count
|
17
|
+
@handler_proc = handler_proc
|
18
|
+
end
|
19
|
+
|
20
|
+
def initalize_context(context, attachment)
|
21
|
+
context.set_attribute(ExecutionContext.HTTP_TARGET_HOST, attachment[:host])
|
22
|
+
context.set_attribute(HTTP_TARGET_PATH, attachment[:path])
|
23
|
+
context.set_attribute(HTTP_TARGET_REQUEST, attachment[:request])
|
24
|
+
context.set_attribute(IO_REACTOR, attachment[:io_reactor])
|
25
|
+
context.set_attribute(REDIRECT_HISTORY, attachment[:redirect_history] || [])
|
26
|
+
end
|
27
|
+
|
28
|
+
def finalize_context(context)
|
29
|
+
flag = context.get_attribute(RESPONSE_RECEIVED)
|
30
|
+
@request_count.count_down() unless flag
|
31
|
+
end
|
32
|
+
|
33
|
+
def submit_request(context)
|
34
|
+
target_host = context.get_attribute(ExecutionContext.HTTP_TARGET_HOST);
|
35
|
+
target_path = context.get_attribute(HTTP_TARGET_PATH)
|
36
|
+
target_request = context.get_attribute(HTTP_TARGET_REQUEST)
|
37
|
+
flag = context.get_attribute(REQUEST_SENT);
|
38
|
+
if flag.nil?
|
39
|
+
# Stick some object into the context
|
40
|
+
context.set_attribute(REQUEST_SENT, true);
|
41
|
+
|
42
|
+
#puts "--------------"
|
43
|
+
#puts "Sending request to #{target_host}#{target_path}"
|
44
|
+
#puts "--------------"
|
45
|
+
|
46
|
+
org.apache.http.message.BasicHttpEntityEnclosingRequest.new(
|
47
|
+
target_request.method, target_path
|
48
|
+
)
|
49
|
+
else
|
50
|
+
# No new request to submit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle_response(response, context)
|
55
|
+
begin
|
56
|
+
res = HttpReactor::Response.new(response)
|
57
|
+
case res.code
|
58
|
+
when 301, 302
|
59
|
+
redirect_to = res.headers['Location']
|
60
|
+
redirect_history = context.getAttribute(REDIRECT_HISTORY)
|
61
|
+
if redirect_history.include?(redirect_to)
|
62
|
+
#puts "Too many redirects"
|
63
|
+
context.setAttribute(RESPONSE_RECEIVED, true)
|
64
|
+
@request_count.count_down()
|
65
|
+
else
|
66
|
+
#puts "Redirecting to #{redirect_to}"
|
67
|
+
redirect_history << redirect_to
|
68
|
+
context.setAttribute(REDIRECT_HISTORY, redirect_history)
|
69
|
+
request = context.getAttribute(HTTP_TARGET_REQUEST)
|
70
|
+
request.uri = URI.parse(redirect_to)
|
71
|
+
io_reactor = context.getAttribute(IO_REACTOR)
|
72
|
+
HttpReactor::Client.process_requests([request], io_reactor, @request_count)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
@handler_proc.call(res, context)
|
76
|
+
context.setAttribute(RESPONSE_RECEIVED, true)
|
77
|
+
# Signal completion of the request execution
|
78
|
+
@request_count.count_down()
|
79
|
+
end
|
80
|
+
rescue => e
|
81
|
+
puts "Error handling response: #{e.message}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class SessionRequestCallback #:nodoc:
|
87
|
+
include org.apache.http.nio.reactor.SessionRequestCallback
|
88
|
+
|
89
|
+
def initialize(request_count)
|
90
|
+
@request_count = request_count
|
91
|
+
end
|
92
|
+
|
93
|
+
def cancelled(request)
|
94
|
+
puts "Connect request cancelled: #{request.remote_address}"
|
95
|
+
@request_count.count_down()
|
96
|
+
end
|
97
|
+
|
98
|
+
def completed(request); end
|
99
|
+
|
100
|
+
def failed(request)
|
101
|
+
puts "Connect request failed: #{request.remote_address}"
|
102
|
+
@request_count.count_down()
|
103
|
+
end
|
104
|
+
|
105
|
+
def timeout(request)
|
106
|
+
puts "Connect request timed out: #{request.remote_address}"
|
107
|
+
@request_count.count_down()
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class EventLogger #:nodoc:
|
112
|
+
import org.apache.http.nio.protocol
|
113
|
+
include EventListener
|
114
|
+
def connection_open(conn)
|
115
|
+
puts "Connection open: #{conn}"
|
116
|
+
end
|
117
|
+
def connection_timeout(conn)
|
118
|
+
puts "Connection timed out: #{conn}"
|
119
|
+
end
|
120
|
+
def connection_closed(conn)
|
121
|
+
puts "Connection closed: #{conn}"
|
122
|
+
end
|
123
|
+
def fatal_i_o_exception(ex, conn)
|
124
|
+
puts "Fatal I/O error: #{ex.message}"
|
125
|
+
end
|
126
|
+
def fatal_protocol_exception(ex, conn)
|
127
|
+
puts "HTTP error: #{ex.message}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# An HTTP client that uses the Reactor pattern.
|
132
|
+
class Client
|
133
|
+
import org.apache.http
|
134
|
+
import org.apache.http.params
|
135
|
+
import org.apache.http.protocol
|
136
|
+
import org.apache.http.nio.protocol
|
137
|
+
import org.apache.http.impl.nio
|
138
|
+
import org.apache.http.impl.nio.reactor
|
139
|
+
|
140
|
+
# Create a new HttpReactor client that will request the given URIs.
|
141
|
+
#
|
142
|
+
# Parameters:
|
143
|
+
# * <tt>uris</tt>: An array of URI objects.
|
144
|
+
# * <tt>handler_proc</tt>: A Proc that will be called with the response and context
|
145
|
+
# * <tt>session_request_callback</tt>: A class that implements the session request
|
146
|
+
# callback interface found in the HttpCore library.
|
147
|
+
# * <tt>options: A hash of configuration options. See below.
|
148
|
+
#
|
149
|
+
# The options hash may include the following options
|
150
|
+
# * <tt>:so_timeout</tt>: (default = 5 seconds)
|
151
|
+
# * <tt>:connection_timeout</tt>: The HTTP connection timeout (default = 10 seconds)
|
152
|
+
# * <tt>:socket_buffer_size</tt>: The buffer size (defaults to 8Kb)
|
153
|
+
# * <tt>:stale_connection_check</tt>: (defaults to false)
|
154
|
+
# * <tt>:tcp_nodelay</tt>: (defaults to true)
|
155
|
+
# * <tt>:user_agent</tt>: The user agent string to send (defaults to "JRubyHttpReactor")
|
156
|
+
# * <tt>:event_listener</tt>: A class that implements the org.apache.http.nio.protocol interface
|
157
|
+
def initialize(requests=[], handler_proc=nil, options={}, &block)
|
158
|
+
handler_proc = block if block_given?
|
159
|
+
handler_proc ||= default_handler_proc
|
160
|
+
|
161
|
+
initialize_options(options)
|
162
|
+
|
163
|
+
params = build_params(options)
|
164
|
+
|
165
|
+
io_reactor = DefaultConnectingIOReactor.new(2, params);
|
166
|
+
|
167
|
+
httpproc = BasicHttpProcessor.new;
|
168
|
+
httpproc.add_interceptor(RequestContent.new);
|
169
|
+
httpproc.add_interceptor(RequestTargetHost.new);
|
170
|
+
httpproc.add_interceptor(RequestConnControl.new);
|
171
|
+
httpproc.add_interceptor(RequestUserAgent.new);
|
172
|
+
httpproc.add_interceptor(RequestExpectContinue.new);
|
173
|
+
|
174
|
+
# We are going to use this object to synchronize between the
|
175
|
+
# I/O event and main threads
|
176
|
+
request_counter = java.util.concurrent.CountDownLatch.new(requests.length);
|
177
|
+
|
178
|
+
handler = BufferingHttpClientHandler.new(
|
179
|
+
httpproc,
|
180
|
+
RequestExecutionHandler.new(request_counter, handler_proc),
|
181
|
+
org.apache.http.impl.DefaultConnectionReuseStrategy.new,
|
182
|
+
params
|
183
|
+
)
|
184
|
+
|
185
|
+
handler.event_listener = options[:event_listener].new if options[:event_listener]
|
186
|
+
|
187
|
+
io_event_dispatch = DefaultClientIOEventDispatch.new(handler, params)
|
188
|
+
|
189
|
+
Thread.abort_on_exception = true
|
190
|
+
t = Thread.new do
|
191
|
+
begin
|
192
|
+
#puts "Executing IO reactor"
|
193
|
+
io_reactor.execute(io_event_dispatch)
|
194
|
+
rescue java.io.InterruptedIOException => e
|
195
|
+
puts "Interrupted"
|
196
|
+
rescue java.io.IOException => e
|
197
|
+
puts "I/O error in reactor execution thread: #{e.message}"
|
198
|
+
end
|
199
|
+
#puts "Shutdown"
|
200
|
+
end
|
201
|
+
|
202
|
+
process_requests(requests, io_reactor, request_counter)
|
203
|
+
|
204
|
+
# Block until all connections signal
|
205
|
+
# completion of the request execution
|
206
|
+
request_counter.await()
|
207
|
+
|
208
|
+
#puts "Shutting down I/O reactor"
|
209
|
+
|
210
|
+
io_reactor.shutdown()
|
211
|
+
|
212
|
+
#puts "Done"
|
213
|
+
end
|
214
|
+
|
215
|
+
def process_requests(requests, io_reactor, request_counter)
|
216
|
+
HttpReactor::Client.process_requests(requests, io_reactor, request_counter)
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.process_requests(requests, io_reactor, request_counter)
|
220
|
+
requests.each do |request|
|
221
|
+
uri = request.uri
|
222
|
+
attachment = {
|
223
|
+
:host => HttpHost.new(uri.host),
|
224
|
+
:path => uri.request_uri,
|
225
|
+
:request => request,
|
226
|
+
:io_reactor => io_reactor
|
227
|
+
}
|
228
|
+
io_reactor.connect(
|
229
|
+
java.net.InetSocketAddress.new(uri.host, uri.port),
|
230
|
+
nil,
|
231
|
+
attachment,
|
232
|
+
SessionRequestCallback.new(request_counter)
|
233
|
+
)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
private
|
238
|
+
|
239
|
+
def initialize_options(options)
|
240
|
+
options[:so_timeout] ||= 5000
|
241
|
+
options[:connection_timeout] ||= 10000
|
242
|
+
options[:socket_buffer_size] ||= 8 * 1024
|
243
|
+
options[:stale_connection_check] ||= false
|
244
|
+
options[:tcp_nodelay] ||= true
|
245
|
+
options[:user_agent] ||= "JRubyHttpReactor"
|
246
|
+
#options[:event_listener] ||= EventLogger
|
247
|
+
end
|
248
|
+
|
249
|
+
def build_params(options)
|
250
|
+
params = BasicHttpParams.new
|
251
|
+
params.set_int_parameter(
|
252
|
+
CoreConnectionPNames.SO_TIMEOUT, options[:so_timeout])
|
253
|
+
params.set_int_parameter(
|
254
|
+
CoreConnectionPNames.CONNECTION_TIMEOUT, options[:connection_timeout])
|
255
|
+
params.set_int_parameter(
|
256
|
+
CoreConnectionPNames.SOCKET_BUFFER_SIZE, options[:socket_buffer_size])
|
257
|
+
params.set_boolean_parameter(
|
258
|
+
CoreConnectionPNames.STALE_CONNECTION_CHECK, options[:stale_connection_check])
|
259
|
+
params.set_boolean_parameter(
|
260
|
+
CoreConnectionPNames.TCP_NODELAY, options[:tcp_nodelay])
|
261
|
+
params.set_parameter(
|
262
|
+
CoreProtocolPNames.USER_AGENT, options[:user_agent])
|
263
|
+
params
|
264
|
+
end
|
265
|
+
|
266
|
+
def default_handler_proc
|
267
|
+
Proc.new { |response, context|
|
268
|
+
target_host = context.get_attribute(ExecutionContext.HTTP_TARGET_HOST);
|
269
|
+
target_path = context.get_attribute(RequestExecutionHandler::HTTP_TARGET_PATH)
|
270
|
+
|
271
|
+
entity = response.entity
|
272
|
+
begin
|
273
|
+
content = org.apache.http.util.EntityUtils.toString(entity)
|
274
|
+
|
275
|
+
puts "--------------"
|
276
|
+
puts "Response from #{target_host}#{target_path}"
|
277
|
+
puts response.status_line
|
278
|
+
puts "Document length: #{content.length}"
|
279
|
+
puts "--------------"
|
280
|
+
rescue java.io.IOException => ex
|
281
|
+
puts "I/O error in handle_response: #{ex.message}"
|
282
|
+
end
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module HttpReactor
|
2
|
+
# A class that represents an HTTP request.
|
3
|
+
class Request
|
4
|
+
attr_accessor :uri
|
5
|
+
attr_reader :method, :payload
|
6
|
+
attr_accessor :extra
|
7
|
+
|
8
|
+
# Initialize the request object.
|
9
|
+
def initialize(uri, method='GET', payload=nil, extra={})
|
10
|
+
@uri = uri
|
11
|
+
@method = method
|
12
|
+
@payload = payload
|
13
|
+
@extra = extra
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module HttpReactor #:nodoc:
|
2
|
+
# A class that represents an HTTP response which wraps the
|
3
|
+
# Java HTTP NIO response object and provides methods for accessing
|
4
|
+
# the data using ruby idioms.
|
5
|
+
class Response
|
6
|
+
def initialize(response_impl)
|
7
|
+
@response_impl = response_impl
|
8
|
+
end
|
9
|
+
|
10
|
+
# Delegates to the HTTP NIO response
|
11
|
+
def status_line
|
12
|
+
@response_impl.status_line
|
13
|
+
end
|
14
|
+
|
15
|
+
# Delegates to the HTTP NIO response
|
16
|
+
def entity
|
17
|
+
@response_impl.entity
|
18
|
+
end
|
19
|
+
|
20
|
+
def code
|
21
|
+
status_line.status_code
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the response content type
|
25
|
+
def content_type
|
26
|
+
@content_type ||= @response_impl.entity.content_type.value
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get the response content length
|
30
|
+
def content_length
|
31
|
+
@content_length ||= @response_impl.entity.content_length
|
32
|
+
end
|
33
|
+
|
34
|
+
# Access the headers
|
35
|
+
def [](name)
|
36
|
+
headers[name]
|
37
|
+
end
|
38
|
+
|
39
|
+
def headers
|
40
|
+
@headers ||= begin
|
41
|
+
h = Hash.new
|
42
|
+
@response_impl.all_headers.each do |header|
|
43
|
+
if h[header.name]
|
44
|
+
h[header.name] = [h[header.name], header.value]
|
45
|
+
else
|
46
|
+
h[header.name] = header.value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
h
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get the body text
|
54
|
+
def body
|
55
|
+
@body ||= begin
|
56
|
+
begin
|
57
|
+
io = Java.java_to_ruby(
|
58
|
+
org.jruby.RubyIO.new(JRuby.runtime, entity.content).java_object
|
59
|
+
)
|
60
|
+
io.read
|
61
|
+
rescue Exception => e
|
62
|
+
puts "Error in Response#body: #{e.message}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/http_reactor.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/../vendor/httpcore-4.0.1.jar'
|
3
|
+
require File.dirname(__FILE__) + '/../vendor/httpcore-nio-4.0.1.jar'
|
4
|
+
|
5
|
+
# The Ruby module that contains wrappers for the the Apache
|
6
|
+
# HTTP NIO implementation.
|
7
|
+
module HttpReactor
|
8
|
+
end
|
9
|
+
|
10
|
+
$:.unshift(File.dirname(__FILE__))
|
11
|
+
|
12
|
+
require 'http_reactor/request'
|
13
|
+
require 'http_reactor/response'
|
14
|
+
require 'http_reactor/client'
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'uri'
|
3
|
+
require 'mime/types'
|
4
|
+
|
5
|
+
class ClientTest < Test::Unit::TestCase
|
6
|
+
def requests
|
7
|
+
@requests ||= [
|
8
|
+
'http://yahoo.com/',
|
9
|
+
'http://www.google.com/',
|
10
|
+
'http://www.apache.org/',
|
11
|
+
'http://anthony.mp/about_me',
|
12
|
+
'http://search.twitter.com/search?q=jruby'
|
13
|
+
].map { |url_string| HttpReactor::Request.new(URI.parse(url_string)) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_new
|
17
|
+
assert_nothing_raised do
|
18
|
+
HttpReactor::Client.new(requests)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_proc
|
23
|
+
handler = Proc.new do |response, context|
|
24
|
+
assert_equal 200, response.code
|
25
|
+
assert response.body.length > 0
|
26
|
+
mime_type = MIME::Types[response.content_type].first
|
27
|
+
assert_equal "text/html", mime_type.content_type
|
28
|
+
end
|
29
|
+
HttpReactor::Client.new(requests, handler)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_block
|
33
|
+
HttpReactor::Client.new(requests) do |response, context|
|
34
|
+
assert_equal 200, response.status_line.status_code
|
35
|
+
assert_equal 200, response.code
|
36
|
+
mime_type = MIME::Types[response.content_type].first
|
37
|
+
assert_equal "text/html", mime_type.content_type
|
38
|
+
puts "request ur: #{context.getAttribute('http_target_request').uri}"
|
39
|
+
puts "content-length: #{response.content_length}"
|
40
|
+
assert response.body.length > 0
|
41
|
+
puts "=== HEADERS ==="
|
42
|
+
puts response.headers.inspect
|
43
|
+
# puts "===== BODY ===="
|
44
|
+
# puts response.body
|
45
|
+
# puts "==============="
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/test/test_helper.rb
ADDED
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jruby-http-reactor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anthony Eden
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-22 00:00:00 -10:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: ""
|
17
|
+
email: anthonyeden@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- README.textile
|
25
|
+
files:
|
26
|
+
- README.rdoc
|
27
|
+
- README.textile
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- examples/opml.rb
|
31
|
+
- jruby-http-reactor.gemspec
|
32
|
+
- lib/http_reactor.rb
|
33
|
+
- lib/http_reactor/client.rb
|
34
|
+
- lib/http_reactor/request.rb
|
35
|
+
- lib/http_reactor/response.rb
|
36
|
+
- test/client_test.rb
|
37
|
+
- test/test_helper.rb
|
38
|
+
- vendor/httpcore-4.0.1.jar
|
39
|
+
- vendor/httpcore-nio-4.0.1.jar
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/aeden/jruby-http-reactor
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --charset=UTF-8
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.3.5
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: JRuby NIO HTTP client.
|
68
|
+
test_files:
|
69
|
+
- test/client_test.rb
|
70
|
+
- test/test_helper.rb
|
71
|
+
- examples/opml.rb
|