iudex-jetty-httpclient 1.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
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