iudex-jetty-httpclient 1.1.0-java

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.
File without changes
@@ -0,0 +1,2 @@
1
+ === 1.1.0 (2011-11-13)
2
+ * Initial release with Iudex 1.1.x.
@@ -0,0 +1,10 @@
1
+ History.rdoc
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ pom.xml
6
+ lib/iudex-jetty-httpclient/base.rb
7
+ lib/iudex-jetty-httpclient.rb
8
+ test/setup.rb
9
+ test/test_httpclient.rb
10
+ lib/iudex-jetty-httpclient/iudex-jetty-httpclient-1.1.0.jar
@@ -0,0 +1,25 @@
1
+ = iudex-jetty-httpclient
2
+
3
+ * http://github.com/dekellum/iudex
4
+
5
+ == Description
6
+
7
+ Iudex is a general purpose web crawler and feed processor in
8
+ ruby/java. This gem is a Jetty HTTP Client based implementation of the
9
+ iudex-http interfaces.
10
+
11
+ == License
12
+
13
+ Copyright (c) 2011 David Kellum
14
+
15
+ Licensed under the Apache License, Version 2.0 (the "License"); you
16
+ may not use this file except in compliance with the License. You
17
+ may obtain a copy of the License at:
18
+
19
+ http://www.apache.org/licenses/LICENSE-2.0
20
+
21
+ Unless required by applicable law or agreed to in writing, software
22
+ distributed under the License is distributed on an "AS IS" BASIS,
23
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
24
+ implied. See the License for the specific language governing
25
+ permissions and limitations under the License.
@@ -0,0 +1,43 @@
1
+ # -*- ruby -*-
2
+
3
+ $LOAD_PATH << './lib'
4
+ require 'iudex-jetty-httpclient/base'
5
+
6
+ require 'rubygems'
7
+ gem 'rjack-tarpit', '~> 1.4'
8
+ require 'rjack-tarpit'
9
+
10
+ t = RJack::TarPit.new( 'iudex-jetty-httpclient',
11
+ Iudex::JettyHTTPClient::VERSION,
12
+ :no_assembly, :java_platform )
13
+
14
+ t.specify do |h|
15
+ h.developer( "David Kellum", "dek-oss@gravitext.com" )
16
+
17
+ h.extra_deps += [ [ 'iudex-http', '~> 1.1.0' ],
18
+ [ 'rjack-jetty', '~> 7.5.2' ],
19
+ [ 'hooker', '~> 1.0.0' ] ]
20
+
21
+ h.testlib = :minitest
22
+ h.extra_dev_deps += [ [ 'minitest', '~> 2.3' ],
23
+ [ 'iudex-http-test', '~> 1.1.0' ],
24
+ [ 'rjack-logback', '~> 1.0' ] ]
25
+ end
26
+
27
+ file 'Manifest.txt' => "lib/#{t.name}/base.rb"
28
+
29
+ task :check_pom_version do
30
+ t.test_line_match( 'pom.xml', /<version>/, /#{t.version}/ )
31
+ end
32
+ task :check_history_version do
33
+ t.test_line_match( 'History.rdoc', /^==/, / #{t.version} / )
34
+ end
35
+ task :check_history_date do
36
+ t.test_line_match( 'History.rdoc', /^==/, /\([0-9\-]+\)$/ )
37
+ end
38
+
39
+ task :gem => [ :check_pom_version, :check_history_version ]
40
+ task :tag => [ :check_pom_version, :check_history_version, :check_history_date ]
41
+ task :push => [ :check_history_date ]
42
+
43
+ t.define_tasks
@@ -0,0 +1,73 @@
1
+ #--
2
+ # Copyright (c) 2011 David Kellum
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
5
+ # may not use this file except in compliance with the License. You
6
+ # may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
+ # implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #++
16
+
17
+ require 'iudex-http'
18
+
19
+ require 'rjack-jetty'
20
+ require 'rjack-jetty/client'
21
+
22
+ require 'hooker'
23
+
24
+ require 'iudex-jetty-httpclient/base'
25
+
26
+ require 'java'
27
+
28
+ module Iudex
29
+
30
+ module JettyHTTPClient
31
+ require "#{LIB_DIR}/iudex-jetty-httpclient-#{VERSION}.jar"
32
+
33
+ import 'iudex.jettyhttpclient.Client'
34
+
35
+ include RJack::Jetty
36
+
37
+ def self.create_jetty_client( opts = {} )
38
+ cfg = { :timeout => 6_000,
39
+ :so_timeout => 5_000,
40
+ :connect_timeout => 3_000,
41
+ :idle_timeout => 6_000,
42
+ :max_retries => 1,
43
+ :max_redirects => 6,
44
+ :max_connections_per_address => 2,
45
+ :max_queue_size_per_address => 100,
46
+ :connect_blocking => false,
47
+ :handle_redirects_internal => false }
48
+
49
+ cfg = cfg.merge( opts )
50
+ cfg = Hooker.merge( [ :iudex, :jetty_httpclient ], cfg )
51
+
52
+ jclient = HttpClient.new
53
+
54
+ redir_listen = cfg.delete( :handle_redirects_internal )
55
+
56
+ cfg.each do |key,value|
57
+ jclient.__send__( "set_#{key}", value )
58
+ end
59
+
60
+ if redir_listen
61
+ jclient.register_listener( 'org.eclipse.jetty.client.RedirectListener' )
62
+ end
63
+
64
+ jclient
65
+ end
66
+
67
+ def self.create_client( opts = {} )
68
+ Client.new( create_jetty_client( opts ) )
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,23 @@
1
+ #--
2
+ # Copyright (c) 2011 David Kellum
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
5
+ # may not use this file except in compliance with the License. You
6
+ # may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
+ # implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #++
16
+
17
+ module Iudex
18
+ module JettyHTTPClient
19
+ VERSION = '1.1.0'
20
+
21
+ LIB_DIR = File.dirname( __FILE__ ) # :nodoc:
22
+ end
23
+ end
data/pom.xml ADDED
@@ -0,0 +1,55 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3
+
4
+ <modelVersion>4.0.0</modelVersion>
5
+ <groupId>iudex</groupId>
6
+ <artifactId>iudex-jetty-httpclient</artifactId>
7
+ <packaging>jar</packaging>
8
+ <version>1.1.0</version>
9
+ <name>Iudex Jetty HTTP Client Adaptor</name>
10
+
11
+ <parent>
12
+ <groupId>iudex</groupId>
13
+ <artifactId>iudex-parent</artifactId>
14
+ <version>1.1</version>
15
+ <relativePath>..</relativePath>
16
+ </parent>
17
+
18
+ <repositories>
19
+ <repository>
20
+ <id>Sonatype</id>
21
+ <name>Sonatype Release</name>
22
+ <url>http://oss.sonatype.org/content/repositories/releases </url>
23
+ </repository>
24
+ </repositories>
25
+
26
+ <dependencies>
27
+
28
+ <dependency>
29
+ <groupId>iudex</groupId>
30
+ <artifactId>iudex-http</artifactId>
31
+ <version>[1.1,1.2)</version>
32
+ </dependency>
33
+
34
+ <dependency>
35
+ <groupId>org.eclipse.jetty</groupId>
36
+ <artifactId>jetty-client</artifactId>
37
+ <version>[7.5.2,7.5.9999)</version>
38
+ </dependency>
39
+
40
+ </dependencies>
41
+
42
+ <build>
43
+ <plugins>
44
+ <plugin>
45
+ <!-- Parent settings -->
46
+ <artifactId>maven-compiler-plugin</artifactId>
47
+ </plugin>
48
+ <plugin>
49
+ <!-- Parent settings -->
50
+ <artifactId>maven-source-plugin</artifactId>
51
+ </plugin>
52
+ </plugins>
53
+ </build>
54
+
55
+ </project>
@@ -0,0 +1,46 @@
1
+ #--
2
+ # Copyright (c) 2011 David Kellum
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
5
+ # may not use this file except in compliance with the License. You
6
+ # may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
+ # implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #++
16
+
17
+ #### General test setup: LOAD_PATH, logging, console output ####
18
+
19
+ ldir = File.join( File.dirname( __FILE__ ), "..", "lib" )
20
+ $LOAD_PATH.unshift( ldir ) unless $LOAD_PATH.include?( ldir )
21
+
22
+ require 'rubygems'
23
+ require 'rjack-logback'
24
+ require 'minitest/unit'
25
+ require 'minitest/autorun'
26
+
27
+ module TestSetup
28
+ include RJack
29
+ Logback.config_console( :stderr => true, :thread => true )
30
+
31
+ if ( ARGV & %w[ -v --verbose --debug ] ).empty?
32
+ # Make test output logging compatible: no partial lines.
33
+ class TestOut
34
+ def print( *a ); $stdout.puts( *a ); end
35
+ def puts( *a ); $stdout.puts( *a ); end
36
+ end
37
+ MiniTest::Unit.output = TestOut.new
38
+ Logback[ 'org.eclipse.jetty.http.ssl.SslContextFactory' ].level =
39
+ Logback::WARN
40
+ else
41
+ Logback.root.level = Logback::DEBUG
42
+ end
43
+
44
+ ARGV.delete( '--debug' )
45
+
46
+ end
@@ -0,0 +1,602 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ #--
4
+ # Copyright (c) 2011 David Kellum
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
7
+ # may not use this file except in compliance with the License. You
8
+ # may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15
+ # implied. See the License for the specific language governing
16
+ # permissions and limitations under the License.
17
+ #++
18
+
19
+ require File.join( File.dirname( __FILE__ ), "setup" )
20
+
21
+ require 'iudex-http-test/helper'
22
+ require 'iudex-http-test/broken_server'
23
+
24
+ require 'iudex-jetty-httpclient'
25
+ require 'thread'
26
+ require 'cgi'
27
+ require 'uri'
28
+
29
+ class TestHTTPClient < MiniTest::Unit::TestCase
30
+ include Iudex
31
+ include Iudex::HTTP
32
+ include Iudex::HTTP::Test
33
+ include Helper
34
+
35
+ import 'java.util.concurrent.TimeoutException'
36
+ import 'java.net.ConnectException'
37
+ import 'java.net.UnknownHostException'
38
+ import 'java.net.URISyntaxException'
39
+ import 'java.io.IOException'
40
+ import 'java.lang.IllegalStateException'
41
+ import 'java.nio.channels.UnresolvedAddressException'
42
+
43
+ CustomUnit.register
44
+
45
+ def setup
46
+ @rlock = Mutex.new
47
+ server # make sure jetty starts, for cosmetic log output
48
+ end
49
+
50
+ def test_default_config
51
+ client = JettyHTTPClient.create_client
52
+ client.close
53
+ pass
54
+ end
55
+
56
+ import 'java.util.concurrent.ThreadPoolExecutor'
57
+ import 'java.util.concurrent.ArrayBlockingQueue'
58
+ import 'java.util.concurrent.TimeUnit'
59
+ import 'org.eclipse.jetty.util.thread.ExecutorThreadPool'
60
+
61
+ def test_custom_executor
62
+ #FIXME: A bit shaky, fails under 3 threads?
63
+ executor = ThreadPoolExecutor.new( 3, 10,
64
+ 10, TimeUnit::SECONDS,
65
+ ArrayBlockingQueue.new( 10 ) )
66
+ pool = ExecutorThreadPool.new( executor )
67
+
68
+ with_new_client( :thread_pool => pool ) do |client|
69
+ with_session_handler( client, "/index" ) do |s,x|
70
+ assert_equal( 200, s.status_code )
71
+ end
72
+ end
73
+
74
+ pool.stop
75
+ end
76
+
77
+ def test_200
78
+ with_new_client do |client|
79
+
80
+ with_session_handler( client, "/index" ) do |s,x|
81
+ output_bomb( s ) unless s.status_code == 200
82
+ assert_equal( 200, s.status_code, "see bomb.out" )
83
+ assert_match( /Test Index Page/, s.response_stream.to_io.read )
84
+ end
85
+
86
+ with_session_handler( client, "/atom.xml" ) do |s,x|
87
+ output_bomb( s ) unless s.status_code == 200
88
+ assert_equal( 200, s.status_code, "see bomb.out" )
89
+ cl = find_header( s.response_headers, "Content-Length" )
90
+ assert_operator( cl.to_i, :>, 10_000 )
91
+ end
92
+
93
+ end
94
+ end
95
+
96
+ def test_correct_type
97
+ with_new_client do |client|
98
+ client.accepted_content_types = ContentTypeSet.new( [ "text/html" ] )
99
+ with_session_handler( client, "/index" ) do |s,x|
100
+ assert_equal( 200, s.status_code )
101
+ assert_nil( x )
102
+ assert_match( /^text\/html/,
103
+ find_header( s.response_headers, 'Content-Type' ) )
104
+ end
105
+ end
106
+ end
107
+
108
+ def test_headers
109
+ req,rsp = nil
110
+ with_new_client do |client|
111
+ with_session_handler( client,
112
+ "/echo/header/Accept?noop=3",
113
+ true,
114
+ { 'Accept' => 'text/plain;moo' } ) do |s,x|
115
+ assert_equal( 200, s.status_code )
116
+ assert_equal( 'GET /echo/header/Accept?noop=3',
117
+ find_header( s.request_headers, "Request-Line" ) )
118
+ assert_equal( 'text/plain;moo',
119
+ find_header( s.request_headers, 'Accept' ) )
120
+ assert_equal( 'localhost:19292',
121
+ find_header( s.request_headers, 'Host' ) )
122
+
123
+ assert_match( /^text\/plain/,
124
+ find_header( s.response_headers, 'Content-Type' ) )
125
+ assert_match( /^text\/plain;moo$/, s.response_stream.to_io.read )
126
+ end
127
+ end
128
+ end
129
+
130
+ def test_unknown_host
131
+ with_new_client( :timeout => 12_000,
132
+ :connect_timeout => 10_000,
133
+ :so_timeout => 10_000,
134
+ :idle_timeout => 10_000 ) do |client|
135
+ with_session_handler( client,
136
+ "http://9xa9.a7v6a7lop-9m9q-w12.com" ) do |s,x|
137
+ assert_equal( HTTPSession::UNRESOLVED, s.status_code )
138
+ assert_includes( [ UnresolvedAddressException,
139
+ UnknownHostException ], x.class )
140
+ end
141
+ end
142
+ end
143
+
144
+ def test_local_connection_refused
145
+ with_new_client do |client|
146
+ with_session_handler( client,
147
+ "http://localhost:54929/" ) do |s,x|
148
+ assert_instance_of( ConnectException, x )
149
+ end
150
+ end
151
+ end
152
+
153
+ def test_connection_timeout
154
+ bs = BrokenServer.new
155
+ bs.start
156
+
157
+ #FIXME: Looks like request_timeout is used as this timeout as well.
158
+ with_new_client( :short => true ) do |client|
159
+ with_session_handler( client,
160
+ "http://localhost:19293/" ) do |s,x|
161
+ assert_includes( (-42..-40), s.status_code )
162
+ assert_kind_of( TimeoutException, x )
163
+ end
164
+ end
165
+ ensure
166
+ bs.stop
167
+ end
168
+
169
+ def test_404
170
+ with_new_client do |client|
171
+ with_session_handler( client, "/not-found" ) do |s,x|
172
+ assert_equal( 404, s.status_code )
173
+ end
174
+ end
175
+ end
176
+
177
+ def test_304
178
+ with_new_client do |client|
179
+ client.accepted_content_types = ContentTypeSet.new( [ "text/html" ] )
180
+ with_session_handler( client, "/304" ) do |s,x|
181
+ assert_equal( 304, s.status_code )
182
+ end
183
+ end
184
+ end
185
+
186
+ def test_timeout
187
+ with_new_client( :short => true ) do |client|
188
+ with_session_handler( client, "/index?sleep=1.0" ) do |s,x|
189
+ assert_includes( (-42..-40), s.status_code )
190
+ assert_kind_of( TimeoutException, x )
191
+ end
192
+ end
193
+ sleep 0.70 # FIXME: Account for test server delay. Should be
194
+ # joined instead.
195
+ end
196
+
197
+ def test_redirect
198
+ with_new_client( :handle_redirects_internal => true ) do |client|
199
+ with_session_handler( client, "/" ) do |s,x|
200
+ assert_equal( 200, s.status_code )
201
+ assert_equal( 'http://localhost:19292/index', s.url )
202
+ end
203
+ end
204
+ end
205
+
206
+ def test_redirect_with_query_string
207
+ with_new_client( :handle_redirects_internal => true ) do |client|
208
+ with_session_handler( client, "/redirects/multi/2?sleep=0" ) do |s,x|
209
+ assert_equal( 200, s.status_code )
210
+ assert_equal( 'http://localhost:19292/redirects/multi/1?sleep=0',
211
+ s.url )
212
+ assert_equal( 'GET /redirects/multi/1?sleep=0',
213
+ find_header( s.request_headers, "Request-Line" ) )
214
+ end
215
+ end
216
+ end
217
+
218
+ def test_redirect_multi_host
219
+ with_new_client( :handle_redirects_internal => true ) do |client|
220
+ rurl = 'http://127.0.0.1:19292/index'
221
+ rurl_e = CGI.escape( rurl )
222
+ with_session_handler( client, "/redirect?loc=#{rurl_e}" ) do |s,x|
223
+ assert_equal( 200, s.status_code )
224
+ assert_equal( rurl, s.url )
225
+ end
226
+ end
227
+ end
228
+
229
+ def test_redirect_multi_host_bad
230
+ skip( "Error: -1 java.lang.NumberFormatException" )
231
+ with_new_client( :handle_redirects_internal => true ) do |client|
232
+ rurl = 'http://localhost:19292/index'
233
+ url = "http://127.0.0.1:19292?redirect?loc=" + CGI.escape( rurl )
234
+ # Note >?<redirect? above
235
+ url = "/redirect?loc=" + CGI.escape( url )
236
+
237
+ with_session_handler( client, url ) do |s,x|
238
+ assert_equal( HTTPSession::INVALID_REDIRECT_URL, s.status_code )
239
+ assert_instance_of( URISyntaxException, x )
240
+ end
241
+ end
242
+ end
243
+
244
+ def test_redirect_multi_host_3
245
+ with_new_client( :handle_redirects_internal => true ) do |client|
246
+ rurl = 'http://localhost:19292/index'
247
+ url = "http://127.0.0.1:19292/redirect?loc=" + CGI.escape( rurl )
248
+ url = "/redirect?loc=" + CGI.escape( url )
249
+
250
+ with_session_handler( client, url ) do |s,x|
251
+ assert_equal( 200, s.status_code )
252
+ assert_equal( rurl, s.url )
253
+ end
254
+ end
255
+ end
256
+
257
+ def test_redirect_multi_host_fragment
258
+ with_new_client( :handle_redirects_internal => true ) do |client|
259
+ rurl = '/index#!foo'
260
+ url = "/redirect?loc=" + CGI.escape( rurl )
261
+
262
+ with_session_handler( client, url ) do |s,x|
263
+ assert_equal( 200, s.status_code )
264
+ assert_equal( 'http://localhost:19292' + rurl, s.url )
265
+ end
266
+ end
267
+ end
268
+
269
+ def test_redirect_bad_host
270
+ with_new_client( :handle_redirects_internal => true ) do |client|
271
+ rurl = CGI.escape( 'http://\bad.com/' )
272
+ with_session_handler( client, "/redirect?loc=#{ rurl }" ) do |s,x|
273
+ assert_equal( HTTPSession::INVALID_REDIRECT_URL, s.status_code )
274
+ assert_instance_of( URISyntaxException, x )
275
+ end
276
+ end
277
+ end
278
+
279
+ def test_multi_redirect
280
+ with_new_client( :handle_redirects_internal => true,
281
+ :max_redirects => 8 ) do |client|
282
+ with_session_handler( client, "/redirects/multi/6" ) do |s,x|
283
+ assert_equal( 200, s.status_code )
284
+ assert_nil x
285
+ end
286
+ end
287
+ end
288
+
289
+ def test_unfollowed_301_redirect
290
+ with_new_client do |client|
291
+ with_session_handler( client, "/301" ) do |s,x|
292
+ assert_equal( 301, s.status_code )
293
+ lh = find_header( s.response_headers, "Location" )
294
+ assert_match( %r{/index$}, lh )
295
+ end
296
+ end
297
+ end
298
+
299
+ def test_too_many_redirects
300
+ with_new_client( :handle_redirects_internal => true,
301
+ :max_redirects => 18 ) do |client|
302
+ #FIXME: One redirect off somewhere? 19 fails.
303
+ with_session_handler( client, "/redirects/multi/20" ) do |s,x|
304
+ assert_equal( 302, s.status_code, x )
305
+ end
306
+ end
307
+ end
308
+
309
+ def test_redirect_timeout
310
+ skip( "Unreliable timeout with redirects, timing dependent" )
311
+ with_new_client( :handle_redirects_internal => true,
312
+ :short => true ) do |client|
313
+ with_session_handler( client, "/redirects/multi/3?sleep=0.40" ) do |s,x|
314
+ assert_instance_of( TimeoutException, x )
315
+ end
316
+ sleep 0.80
317
+ end
318
+ end
319
+
320
+ def test_bad_server_response
321
+ bs = BrokenServer.new
322
+ bs.start
323
+
324
+ sthread = Thread.new do
325
+ bs.accept { |sock| sock.write "FU Stinky\r\n" }
326
+ end
327
+
328
+ #FIXME: IllegalStateException on bad HTTP response line?
329
+ with_new_client do |client|
330
+ with_session_handler( client, "http://localhost:19293/" ) do |s,x|
331
+ assert_instance_of( IllegalStateException, x )
332
+ end
333
+ end
334
+
335
+ sthread.join
336
+
337
+ ensure
338
+ bs.stop
339
+ end
340
+
341
+ def test_empty_server_response
342
+ bs = BrokenServer.new
343
+ bs.start
344
+
345
+ sthread = Thread.new do
346
+ bs.accept { |sock| sock.close }
347
+ end
348
+
349
+ with_new_client do |client|
350
+ with_session_handler( client, "http://localhost:19293/" ) do |s,x|
351
+ assert_match( /EofException/i, x.class.name )
352
+ end
353
+ end
354
+
355
+ sthread.join
356
+
357
+ ensure
358
+ bs.stop
359
+ end
360
+
361
+ def test_early_close
362
+ bs = BrokenServer.new
363
+ bs.start
364
+
365
+ sthread = Thread.new do
366
+ bs.accept do |sock|
367
+ sock.write "HTTP/1.1 200 OK\r\n"
368
+ sock.write "Content-Type: text/plain\r\n"
369
+ sock.write "Transfer-Encoding: chunked\r\n"
370
+ sock.write "\r\n"
371
+ sock.write "FF3DF\r\n"
372
+ sock.write "An incomplete chunk"
373
+ sock.write "An incomplete chunk"
374
+ sock.write "An incomplete chunk"
375
+ sock.close
376
+ end
377
+ end
378
+
379
+ with_new_client do |client|
380
+ with_session_handler( client, "http://localhost:19293/" ) do |s,x|
381
+ assert_match( /EofException/i, x.class.name )
382
+ end
383
+ end
384
+
385
+ sthread.join
386
+
387
+ ensure
388
+ bs.stop
389
+ end
390
+
391
+ def test_redirect_early_close
392
+ bs = BrokenServer.new
393
+ bs.start
394
+
395
+ sthread = Thread.new do
396
+ bs.accept do |sock|
397
+ sock.write "HTTP/1.1 302 Found\r\n"
398
+ sock.write "Location: http://localhost:54929/no-exist\r\n"
399
+ sock.write "Content-Type: text/plain\r\n"
400
+ sock.write "Transfer-Encoding: chunked\r\n"
401
+ sock.write "\r\n"
402
+ sock.write "FF3DF\r\n"
403
+ sock.write "An incomplete chunk"
404
+ sock.write "An incomplete chunk"
405
+ sock.write "An incomplete chunk"
406
+ sock.close
407
+ end
408
+ end
409
+
410
+ with_new_client do |client|
411
+ with_session_handler( client, "http://localhost:19293/" ) do |s,x|
412
+ assert_match( /EofException/i, x.class.name )
413
+ end
414
+ end
415
+
416
+ sthread.join
417
+
418
+ ensure
419
+ bs.stop
420
+ end
421
+
422
+ def test_concurrent
423
+ with_new_client( :timeout => 18_000,
424
+ :connect_timeout => 15_000,
425
+ :so_timeout => 12_000,
426
+ :idle_timeout => 12_000,
427
+ :max_connections_per_address => 4 ) do |client|
428
+
429
+ resps = []
430
+ sessions = (1..19).map do |i|
431
+ with_session_handler( client, "/index?sleep=0.05&i=#{i}",
432
+ false ) do |s,x|
433
+ sync do
434
+ resps << [ s.status_code, x ]
435
+ output_bomb( s ) if s.status_code != 200
436
+ end
437
+ end
438
+ end
439
+
440
+ sessions.each { |s| s.wait_for_completion }
441
+
442
+ assert_equal( [ [ 200, nil ] ] * 19, resps )
443
+ end
444
+ end
445
+
446
+ def test_maximum_connections_per_address
447
+ with_new_client( :timeout => 12_000,
448
+ :connect_timeout => 10_000,
449
+ :so_timeout => 10_000,
450
+ :idle_timeout => 10_000,
451
+ :max_connections_per_address => 2 ) do |client|
452
+
453
+ resps = []
454
+ sessions = (1..7).map do |i|
455
+ with_session_handler( client, "/index?sleep=0.1&con=2&i=#{i}",
456
+ false ) do |s,x|
457
+ sync do
458
+ resps << [ s.status_code, x ]
459
+ end
460
+ end
461
+ end
462
+
463
+ sessions.each { |s| s.wait_for_completion }
464
+
465
+ assert_equal( [ [ 200, nil ] ] * 7, resps )
466
+ end
467
+ end
468
+
469
+ def test_abort_when_too_large
470
+ with_new_client do |client|
471
+ with_session_handler( client, "/giant" ) do |s,x|
472
+ assert_nil( x )
473
+ assert_equal( HTTPSession::TOO_LARGE, s.status_code )
474
+ end
475
+ end
476
+ end
477
+
478
+ def test_abort_when_too_large_length
479
+ with_new_client do |client|
480
+ client.max_content_length = 1
481
+ with_session_handler( client, "/atom.xml" ) do |s,x|
482
+ assert_nil( x )
483
+ assert_equal( HTTPSession::TOO_LARGE_LENGTH, s.status_code )
484
+ end
485
+ end
486
+ end
487
+
488
+ def test_abort_when_wrong_type
489
+ with_new_client do |client|
490
+ client.accepted_content_types = ContentTypeSet.new( [ "gold/*" ] )
491
+ with_session_handler( client, "/giant" ) do |s,x|
492
+ assert_nil( x )
493
+ assert_equal( HTTPSession::NOT_ACCEPTED, s.status_code )
494
+ end
495
+ end
496
+ end
497
+
498
+ def sync( &block )
499
+ @rlock.synchronize( &block )
500
+ end
501
+
502
+ def output_bomb( s )
503
+ File.open( "bomb.out", "w" ) do |fout|
504
+ st = s && s.response_stream
505
+ if st
506
+ fout.puts st.to_io.read
507
+ else
508
+ fout.puts st.to_s
509
+ end
510
+ end
511
+ "See bomb.out"
512
+ end
513
+
514
+ def with_session_handler( client, uri, wait = true, headers = {}, &block )
515
+ session = client.create_session
516
+ uri = "http://localhost:#{server.port}#{uri}" unless uri =~ /^http:/
517
+ session.url = uri
518
+ headers.each do |k,v|
519
+ session.add_request_header( Java::iudex.http.Header.new( k, v ) )
520
+ end
521
+ handler = TestHandler.new( &block )
522
+ client.request( session, handler )
523
+ if wait
524
+ session.wait_for_completion
525
+ session.close
526
+ assert( handler.called?, "Handler should have been called!" )
527
+ end
528
+ session
529
+ end
530
+
531
+ def with_new_client( opts = {} )
532
+ o = if opts.delete( :short )
533
+ { :timeout => 400,
534
+ :so_timeout => 200,
535
+ :connect_timeout => 200,
536
+ :idle_timeout => 200 }
537
+ else
538
+ { :timeout => 5000,
539
+ :so_timeout => 4000,
540
+ :connect_timeout => 3000,
541
+ :idle_timeout => 2000 }
542
+ end
543
+
544
+ o = o.merge( { :max_retries => 0,
545
+ :connect_blocking => false } )
546
+ o = o.merge( opts )
547
+
548
+ client = JettyHTTPClient.create_client( o )
549
+ client.start
550
+
551
+ begin
552
+ yield client
553
+ ensure
554
+ client.close
555
+ end
556
+
557
+ end
558
+
559
+ class TestHandler < BaseResponseHandler
560
+
561
+ def initialize( &block )
562
+ @block = block
563
+ @failure = nil
564
+ end
565
+
566
+ def sessionCompleted( session )
567
+ forward( session, session.error )
568
+ end
569
+
570
+ def called?
571
+ raise @failure if @failure
572
+ @block.nil?
573
+ end
574
+
575
+ def forward( s, x = nil )
576
+ b, @block = @block, nil
577
+ if b
578
+ b.call( s, x )
579
+ else
580
+ flunk "Handler called twice!"
581
+ end
582
+ rescue NativeException => x
583
+ @failure = x.cause
584
+ rescue Exception => x
585
+ @failure = x
586
+ end
587
+
588
+ end
589
+
590
+ def find_header( headers, name )
591
+ cl = headers.find { |h| h.name.to_s == name }
592
+ cl && cl.value.to_s
593
+ end
594
+
595
+ end
596
+
597
+ if ARGV.delete( '--loop' )
598
+ loop do
599
+ failed = MiniTest::Unit.new.run( ARGV )
600
+ exit!( 1 ) if failed > 0
601
+ end
602
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iudex-jetty-httpclient
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.1.0
6
+ platform: java
7
+ authors:
8
+ - David Kellum
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-11-13 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: iudex-http
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.0
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rjack-jetty
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 7.5.2
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: hooker
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: minitest
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: "2.3"
57
+ type: :development
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: iudex-http-test
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 1.1.0
68
+ type: :development
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: rjack-logback
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: "1.0"
79
+ type: :development
80
+ version_requirements: *id006
81
+ - !ruby/object:Gem::Dependency
82
+ name: rjack-tarpit
83
+ prerelease: false
84
+ requirement: &id007 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 1.4.0
90
+ type: :development
91
+ version_requirements: *id007
92
+ description: |-
93
+ Iudex is a general purpose web crawler and feed processor in
94
+ ruby/java. This gem is a Jetty HTTP Client based implementation of the
95
+ iudex-http interfaces.
96
+ email:
97
+ - dek-oss@gravitext.com
98
+ executables: []
99
+
100
+ extensions: []
101
+
102
+ extra_rdoc_files:
103
+ - Manifest.txt
104
+ - History.rdoc
105
+ - README.rdoc
106
+ files:
107
+ - History.rdoc
108
+ - Manifest.txt
109
+ - README.rdoc
110
+ - Rakefile
111
+ - pom.xml
112
+ - lib/iudex-jetty-httpclient/base.rb
113
+ - lib/iudex-jetty-httpclient.rb
114
+ - test/setup.rb
115
+ - test/test_httpclient.rb
116
+ - lib/iudex-jetty-httpclient/iudex-jetty-httpclient-1.1.0.jar
117
+ - .gemtest
118
+ homepage: http://github.com/dekellum/iudex
119
+ licenses: []
120
+
121
+ post_install_message:
122
+ rdoc_options:
123
+ - --main
124
+ - README.rdoc
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: "0"
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: "0"
139
+ requirements: []
140
+
141
+ rubyforge_project: iudex-jetty-httpclient
142
+ rubygems_version: 1.8.9
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Iudex is a general purpose web crawler and feed processor in ruby/java
146
+ test_files:
147
+ - test/test_httpclient.rb