manticore 0.2.0-java → 0.2.1-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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0ee8e57988bc31f65a09326d862683aed668e2a
4
- data.tar.gz: 7d7247a8d5087e9630b2ffed540abd16f4930bbd
3
+ metadata.gz: 79bd078a381a202fd2e4e022b384b454fdb80242
4
+ data.tar.gz: 892736cf30a0c490cb92cf690e5e8aa7eb881368
5
5
  SHA512:
6
- metadata.gz: 0728f990ebb06a7251267eb121d1be4bf108a3b13fb742a62289eea6d41f4d376125b79878d2ccb8bed83158783fba1170f826f14fd2b443f31d52c64cff5580
7
- data.tar.gz: 3b32c8017107ce22d1da41b56faa3fab5e3a57749cd47814c86ed2632d771c7d923637e1c359b0f28cf0855089f3343ba921d47b0a0b79d8336c85f63b5999be
6
+ metadata.gz: 03a61af6c2dce93aaa68088b9e605cdcb06c8813a182d04ef17152893947b9e9b58b4031561eab68376eb044e08afcd2aa29bd0cc6448f1fa10a4b786b664e71
7
+ data.tar.gz: 54e578d3b61ac6db04cb60fb13919ddbf157ca0b664e5a066d56eb2ac727ff7798b644ead04e054c74820123a93ec1607c128b1eee9a60dd445d86c8851ae0ac
@@ -2,9 +2,10 @@ Copyright (c) 2013 Chris Heald
2
2
 
3
3
  Some JARs distributed with this project are licensed under the Apache 2.0 License. See APACHE-LICENSE-2.0.txt for details:
4
4
 
5
- lib/jars/commons-logging-1.1.3.jar
6
- lib/jars/httpclient-4.3.2.jar
7
- lib/jars/httpcore-4.3.1.jar
5
+ lib/jar/commons-logging-1.1.3.jar
6
+ lib/jar/httpclient-4.3.2.jar
7
+ lib/jar/httpcore-4.3.1.jar
8
+ lib/jar/commons-codec-1.6.jar
8
9
 
9
10
  All other code distributed with this project is licensed under the MIT License as follows:
10
11
 
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/cheald/manticore.png?branch=master)](https://travis-ci.org/cheald/manticore)
4
4
 
5
- Manticore is a HTTP client with the fast, robust HTTP client built on the Apache HTTPClient libraries. It is only compatible with JRuby.
5
+ Manticore is a fast, robust HTTP client built on the Apache HTTPClient libraries. It is only compatible with JRuby.
6
6
 
7
7
  ## Installation
8
8
 
@@ -34,8 +34,9 @@ Or install it yourself as:
34
34
  * Transparent gzip and deflate handling
35
35
  * Transparent cookie handling
36
36
  * Both synchronous and asynchronous execution models
37
+ * Authentication
38
+ * Proxy support
37
39
  * SSL
38
- * Much more!
39
40
 
40
41
  ## Usage
41
42
 
@@ -36,11 +36,6 @@ public class Manticore implements Library {
36
36
  super(ruby, rubyClass);
37
37
  }
38
38
 
39
- // @JRubyMethod
40
- // public IRubyObject initialize(ThreadContext context) {
41
- // return context.nil;
42
- // }
43
-
44
39
  @JRubyMethod(name = "read_entity")
45
40
  public IRubyObject readEntity(ThreadContext context, IRubyObject rEntity, Block block) throws IOException {
46
41
  HttpEntity entity = (HttpEntity)rEntity.toJava(HttpEntity.class);
@@ -60,13 +55,11 @@ public class Manticore implements Library {
60
55
  }
61
56
  }
62
57
 
63
- // @JRubyMethod(name = "read_entity")
64
58
  private IRubyObject readWholeEntity(ThreadContext context, HttpEntity entity, Encoding encoding) throws IOException {
65
59
  ByteList bl = new ByteList(EntityUtils.toByteArray(entity), false);
66
60
  return RubyString.newStringShared(context.getRuntime(), bl, encoding);
67
61
  }
68
62
 
69
- // @JRubyMethod(name = "stream_entity")
70
63
  private IRubyObject streamEntity(ThreadContext context, HttpEntity entity, Encoding encoding, Block block) throws IOException {
71
64
  InputStream instream = entity.getContent();
72
65
  if (instream == null) { return null; }
@@ -84,7 +77,6 @@ public class Manticore implements Library {
84
77
  byte[] tmp = new byte[4096];
85
78
  int l;
86
79
  while((l = instream.read(tmp)) != -1) {
87
- // String str = new String(tmp, charset);
88
80
  block.call( context, RubyString.newString(context.getRuntime(), new ByteList(tmp, true), encoding) );
89
81
  }
90
82
  } finally {
@@ -3,6 +3,7 @@ require 'java'
3
3
  require_relative "./jar/httpcore-4.3.1"
4
4
  require_relative "./jar/httpclient-4.3.2-patched"
5
5
  require_relative "./jar/commons-logging-1.1.3"
6
+ require_relative "./jar/commons-codec-1.6.jar"
6
7
  require_relative "./jar/manticore-ext"
7
8
 
8
9
  org.manticore.Manticore.new.load(JRuby.runtime, false)
@@ -22,9 +23,16 @@ module Manticore
22
23
  # Friendly wrapper for various Java ClientProtocolExceptions
23
24
  class ClientProtocolException < ManticoreException; end
24
25
 
26
+ # DNS resolution failure
27
+ class ResolutionFailure < ManticoreException; end
28
+
29
+ # Socket breaks, etc
30
+ class SocketException < ManticoreException; end
31
+
25
32
  require_relative './manticore/client'
26
33
  require_relative './manticore/response'
27
34
  require_relative './manticore/async_response'
35
+ require_relative './manticore/cookie'
28
36
  require_relative './manticore/facade'
29
37
 
30
38
  include Facade
@@ -21,14 +21,20 @@ module Manticore
21
21
  # @private
22
22
  # Implementation of Callable#call
23
23
  def call
24
+ ex = nil
24
25
  begin
25
26
  @client.execute @request, self, @context
26
- self
27
+ return self
27
28
  rescue Java::JavaNet::SocketTimeoutException, Java::OrgApacheHttpConn::ConnectTimeoutException, Java::OrgApacheHttp::NoHttpResponseException => e
28
- @handlers[:failure].call( Manticore::Timeout.new(e.get_cause) )
29
- rescue Java::OrgApacheHttpClient::ClientProtocolException => e
30
- @handlers[:failure].call( Manticore::ClientProtocolException.new(e.get_cause) )
29
+ ex = Manticore::Timeout.new(e.get_cause)
30
+ rescue Java::JavaNet::SocketException => e
31
+ ex = Manticore::SocketException.new(e.get_cause)
32
+ rescue Java::OrgApacheHttpClient::ClientProtocolException, Java::JavaxNetSsl::SSLHandshakeException, Java::OrgApacheHttpConn::HttpHostConnectException => e
33
+ ex = Manticore::ClientProtocolException.new(e.get_cause)
34
+ rescue Java::JavaNet::UnknownHostException => e
35
+ ex = Manticore::ResolutionFailure.new(e.get_cause)
31
36
  end
37
+ @handlers[:failure].call ex
32
38
  end
33
39
 
34
40
  # Set handler for success responses
@@ -4,6 +4,51 @@ module Manticore
4
4
  # General Timeout exception thrown for various Manticore timeouts
5
5
  class Timeout < ManticoreException; end
6
6
 
7
+ # @!macro [new] http_method_shared
8
+ # @param url [String] URL to request
9
+ # @param options [Hash]
10
+ # @option options [Hash] params Hash of options to pass as request parameters
11
+ # @option options [Hash] headers Hash of options to pass as additional request headers
12
+ # @option options [String] proxy Proxy host in form: http://proxy.org:1234
13
+ # @option options [Hash] proxy Proxy host in form: {host: 'proxy.org'[, port: 80[, scheme: 'http']]}
14
+ # @option options [URI] proxy Proxy host as a URI object
15
+ # @option options [Integer] connect_timeout Request-specific connect timeout
16
+ # @option options [Integer] socket_timeout Request-specific socket timeout
17
+ # @option options [Integer] request_timeout Request-specific request timeout
18
+ # @option options [Integer] max_redirects Request-specific maximum redirect limit
19
+ # @option options [Boolean] follow_redirects Specify whether this request should follow redirects
20
+ #
21
+ # @!macro [new] http_request_exceptions
22
+ # @raise [Manticore::Timeout] on socket, connection, or response timeout
23
+ # @raise [Manticore::SocketException] on internal socket exception (ie, unexpected socket closure)
24
+ # @raise [Manticore::ClientProtocolException] on protocol errors such as an SSL handshake failure or connection exception
25
+ # @raise [Manticore::ResolutionFailure] on DNS resolution failure
26
+ # @return [Response]
27
+ #
28
+ # @!macro [new] http_method_shared_async
29
+ # @example Simple usage
30
+ # client.$0("http://example.com/some/resource", params: {foo: "bar"}, headers: {"X-Custom-Header" => "whee"}).
31
+ # on_success {|response|
32
+ # # Do something with response.body, response.code, etc
33
+ # }.on_failure {|exception|
34
+ # # Handle request exception
35
+ # }
36
+ # client.execute!
37
+ #
38
+ # @!macro [new] http_method_shared_sync
39
+ # @example Simple usage
40
+ # client.$0("http://example.com/some/resource", params: {foo: "bar"}, headers: {"X-Custom-Header" => "whee"})
41
+ # @macro http_method_shared
42
+ # @macro http_request_exceptions
43
+ #
44
+ # @!macro [new] http_method_shared_async_with_body
45
+ # @macro http_method_shared_async
46
+ # @option options [Hash] body Hash of options to pass as request body
47
+ #
48
+ # @!macro [new] http_method_shared_sync_with_body
49
+ # @macro http_method_shared_sync
50
+ # @option options [Hash] body Hash of options to pass as request body
51
+
7
52
  # Core Manticore client, with a backing {http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html PoolingHttpClientConnectionManager}
8
53
  class Client
9
54
  include_package "org.apache.http.client.methods"
@@ -17,10 +62,10 @@ module Manticore
17
62
  include_package "org.apache.http.message"
18
63
  include_package "org.apache.http.params"
19
64
  include_package "org.apache.http.protocol"
65
+ include_package "org.apache.http.auth"
20
66
  include_package "java.util.concurrent"
21
- java_import 'java.util.concurrent.TimeUnit'
22
- java_import 'java.util.concurrent.CountDownLatch'
23
- java_import 'java.util.concurrent.LinkedBlockingQueue'
67
+ include_package "org.apache.http.client.protocol"
68
+ java_import "org.apache.http.HttpHost"
24
69
 
25
70
  # The default maximum pool size for requests
26
71
  DEFAULT_MAX_POOL_SIZE = 50
@@ -57,18 +102,23 @@ module Manticore
57
102
  # @option options [integer] pool_max_per_route (2) Sets the maximum number of active connections for a given target endpoint
58
103
  # @option options [boolean] cookies (true) enable or disable automatic cookie management between requests
59
104
  # @option options [boolean] compression (true) enable or disable transparent gzip/deflate support
60
- # @option options [integer] request_timeout (60) Sets the timeout for requests. Raises Manticore::Timeout on failure.
105
+ # @option options [integer] request_timeout (60) Sets the timeout for requests. Raises {Manticore::Timeout} on failure.
61
106
  # @option options [integer] connect_timeout (10) Sets the timeout for connections. Raises Manticore::Timeout on failure.
62
107
  # @option options [integer] socket_timeout (10) Sets SO_TIMEOUT for open connections. A value of 0 is an infinite timeout. Raises Manticore::Timeout on failure.
63
108
  # @option options [integer] request_timeout (60) Sets the timeout for a given request. Raises Manticore::Timeout on failure.
64
109
  # @option options [integer] max_redirects (5) Sets the maximum number of redirects to follow.
65
110
  # @option options [boolean] expect_continue (false) Enable support for HTTP 100
66
111
  # @option options [boolean] stale_check (false) Enable support for stale connection checking. Adds overhead.
112
+ # @option options [String] proxy Proxy host in form: http://proxy.org:1234
113
+ # @option options [Hash] proxy Proxy host in form: {host: 'proxy.org'[, port: 80[, scheme: 'http']]}
114
+ # @option options [URI] proxy Proxy host as a URI object
67
115
  def initialize(options = {})
68
116
  builder = client_builder
69
117
  builder.set_user_agent options.fetch(:user_agent, "Manticore #{VERSION}")
70
- builder.disable_cookie_management unless options.fetch(:cookies, false)
118
+ @use_cookies = options.fetch(:cookies, false)
119
+ builder.disable_cookie_management unless @use_cookies
71
120
  builder.disable_content_compression if options.fetch(:compression, true) == false
121
+ builder.set_proxy get_proxy_host(options[:proxy]) if options.key?(:proxy)
72
122
 
73
123
  # This should make it easier to reuse connections
74
124
  builder.disable_connection_state
@@ -98,81 +148,41 @@ module Manticore
98
148
  ### Sync methods
99
149
 
100
150
  # Perform a HTTP GET request
101
- # @param url [String] URL to request
102
- # @param options [Hash]
103
- # @option options [Hash] params Hash of options to pass as request parameters
104
- # @option options [Hash] headers Hash of options to pass as additional request headers
105
- #
106
- # @return [Response]
151
+ # @macro http_method_shared_sync
107
152
  def get(url, options = {}, &block)
108
153
  request HttpGet, url, options, &block
109
154
  end
110
155
 
111
156
  # Perform a HTTP PUT request
112
- # @param url [String] URL to request
113
- # @param options [Hash]
114
- # @option options [Hash] params Hash of options to pass as request parameters
115
- # @option options [Hash] body Hash of options to pass as request body
116
- # @option options [Hash] headers Hash of options to pass as additional request headers
117
- #
118
- # @return [Response]
157
+ # @macro http_method_shared_sync_with_body
119
158
  def put(url, options = {}, &block)
120
159
  request HttpPut, url, options, &block
121
160
  end
122
161
 
123
162
  # Perform a HTTP HEAD request
124
- # @param url [String] URL to request
125
- # @param options [Hash]
126
- # @option options [Hash] params Hash of options to pass as request parameters
127
- # @option options [Hash] headers Hash of options to pass as additional request headers
128
- #
129
- # @return [Response]
163
+ # @macro http_method_shared_sync
130
164
  def head(url, options = {}, &block)
131
165
  request HttpHead, url, options, &block
132
166
  end
133
167
 
134
168
  # Perform a HTTP POST request
135
- # @param url [String] URL to request
136
- # @param options [Hash]
137
- # @option options [Hash] params Hash of options to pass as request parameters
138
- # @option options [Hash] body Hash of options to pass as request body
139
- # @option options [Hash] headers Hash of options to pass as additional request headers
140
- #
141
- # @return [Response]
169
+ # @macro http_method_shared_sync_with_body
142
170
  def post(url, options = {}, &block)
143
171
  request HttpPost, url, options, &block
144
172
  end
145
173
 
146
174
  # Perform a HTTP DELETE request
147
- # @param url [String] URL to request
148
- # @param options [Hash]
149
- # @option options [Hash] params Hash of options to pass as request parameters
150
- # @option options [Hash] headers Hash of options to pass as additional request headers
151
- #
152
- # @return [Response]
175
+ # @macro http_method_shared_sync
153
176
  def delete(url, options = {}, &block)
154
177
  request HttpDelete, url, options, &block
155
178
  end
156
179
 
157
- # Perform a HTTP OPTIONS request
158
- # @param url [String] URL to request
159
- # @param options [Hash]
160
- # @option options [Hash] params Hash of options to pass as request parameters
161
- # @option options [Hash] headers Hash of options to pass as additional request headers
162
- #
163
- # @return [Response]
180
+ # @macro http_method_shared_sync
164
181
  def options(url, options = {}, &block)
165
182
  request HttpOptions, url, options, &block
166
183
  end
167
184
 
168
- # Perform a HTTP PATCH request
169
- # @param url [String] URL to request
170
- # @param options [Hash]
171
- # @option options [Hash] params Hash of options to pass as request parameters
172
- # @option options [Hash] body Hash of options to pass as request body
173
- # @option options [Hash] headers Hash of options to pass as additional request headers
174
- #
175
- # @return [Response]
185
+ # @macro http_method_shared_sync_with_body
176
186
  def patch(url, options = {}, &block)
177
187
  request HttpPatch, url, options, &block
178
188
  end
@@ -180,81 +190,43 @@ module Manticore
180
190
  ### Async methods
181
191
 
182
192
  # Queue an asynchronous HTTP GET request
183
- # @param url [String] URL to request
184
- # @param options [Hash]
185
- # @option options [Hash] params Hash of options to pass as request parameters
186
- # @option options [Hash] headers Hash of options to pass as additional request headers
187
- #
188
- # @return [Response]
193
+ # @macro http_method_shared_async
189
194
  def async_get(url, options = {}, &block)
190
195
  get url, options.merge(async: true), &block
191
196
  end
192
197
 
193
198
  # Queue an asynchronous HTTP HEAD request
194
- # @param url [String] URL to request
195
- # @param options [Hash]
196
- # @option options [Hash] params Hash of options to pass as request parameters
197
- # @option options [Hash] headers Hash of options to pass as additional request headers
198
- #
199
- # @return [Response]
199
+ # @macro http_method_shared_async
200
200
  def async_head(url, options = {}, &block)
201
201
  head url, options.merge(async: true), &block
202
202
  end
203
203
 
204
204
  # Queue an asynchronous HTTP PUT request
205
- # @param url [String] URL to request
206
- # @param options [Hash]
207
- # @option options [Hash] params Hash of options to pass as request parameters
208
- # @option options [Hash] body Hash of options to pass as request body
209
- # @option options [Hash] headers Hash of options to pass as additional request headers
210
- #
211
- # @return [Response]
205
+ # @macro http_method_shared_async_with_body
212
206
  def async_put(url, options = {}, &block)
213
207
  put url, options.merge(async: true), &block
214
208
  end
215
209
 
216
210
  # Queue an asynchronous HTTP POST request
217
- # @param url [String] URL to request
218
- # @param options [Hash]
219
- # @option options [Hash] params Hash of options to pass as request parameters
220
- # @option options [Hash] body Hash of options to pass as request body
221
- # @option options [Hash] headers Hash of options to pass as additional request headers
222
- #
223
- # @return [Response]
211
+ # @macro http_method_shared_async_with_body
224
212
  def async_post(url, options = {}, &block)
225
213
  post url, options.merge(async: true), &block
226
214
  end
227
215
 
228
216
  # Queue an asynchronous HTTP DELETE request
229
- # @param url [String] URL to request
230
- # @param options [Hash]
231
- # @option options [Hash] params Hash of options to pass as request parameters
232
- # @option options [Hash] headers Hash of options to pass as additional request headers
233
- #
234
- # @return [Response]
217
+ # @macro http_method_shared_async
235
218
  def async_delete(url, options = {}, &block)
236
219
  delete url, options.merge(async: true), &block
237
220
  end
238
221
 
239
222
  # Queue an asynchronous HTTP OPTIONS request
240
- # @param url [String] URL to request
241
- # @param options [Hash]
242
- # @option options [Hash] params Hash of options to pass as request parameters
243
- # @option options [Hash] headers Hash of options to pass as additional request headers
244
- #
245
- # @return [Response]
223
+ # @macro http_method_shared_async
246
224
  def async_options(url, options = {}, &block)
247
225
  options url, options.merge(async: true), &block
248
226
  end
249
227
 
250
228
  # Queue an asynchronous HTTP PATCH request
251
- # @param url [String] URL to request
252
- # @param options [Hash]
253
- # @option options [Hash] params Hash of options to pass as request parameters
254
- # @option options [Hash] body Hash of options to pass as request body
255
- # @option options [Hash] headers Hash of options to pass as additional request headers
256
- #
257
- # @return [Response]
229
+ # @macro http_method_shared_async_with_body
258
230
  def async_patch(url, options = {}, &block)
259
231
  patch url, options.merge(async: true), &block
260
232
  end
@@ -309,30 +281,37 @@ module Manticore
309
281
  end
310
282
 
311
283
  def request(klass, url, options, &block)
312
- req = request_from_options(klass, url, options)
284
+ req, context = request_from_options(klass, url, options)
313
285
  if options.delete(:async)
314
- async_request req, &block
286
+ async_request req, context, &block
315
287
  else
316
- sync_request req, &block
288
+ sync_request req, context, &block
317
289
  end
318
290
  end
319
291
 
320
- def async_request(request, &block)
292
+ def async_request(request, context, &block)
321
293
  create_executor_if_needed
322
- response = AsyncResponse.new(@client, request, BasicHttpContext.new, block)
294
+ response = AsyncResponse.new(@client, request, context, block)
323
295
  @async_requests << response
324
296
  response
325
297
  end
326
298
 
327
- def sync_request(request, &block)
328
- response = Response.new(request, BasicHttpContext.new, block)
299
+ def sync_request(request, context, &block)
300
+ response = Response.new(request, context, block)
329
301
  begin
330
302
  @client.execute request, response, response.context
303
+ response
331
304
  rescue Java::JavaNet::SocketTimeoutException, Java::OrgApacheHttpConn::ConnectTimeoutException, Java::OrgApacheHttp::NoHttpResponseException => e
332
305
  raise Manticore::Timeout.new(e.get_cause)
333
- rescue Java::OrgApacheHttpClient::ClientProtocolException => e
306
+ rescue Java::JavaNet::SocketException => e
307
+ raise Manticore::SocketException.new(e.get_cause)
308
+ rescue Java::OrgApacheHttpClient::ClientProtocolException, Java::JavaxNetSsl::SSLHandshakeException,
309
+ Java::OrgApacheHttpConn::HttpHostConnectException, Java::JavaxNetSsl::SSLException => e
334
310
  raise Manticore::ClientProtocolException.new(e.get_cause)
311
+ rescue Java::JavaNet::UnknownHostException => e
312
+ raise Manticore::ResolutionFailure.new(e.get_cause)
335
313
  end
314
+
336
315
  end
337
316
 
338
317
  def uri_from_url_and_options(url, options)
@@ -363,11 +342,58 @@ module Manticore
363
342
  end
364
343
  end
365
344
 
345
+ if options.key?(:proxy) || options.key?(:connect_timeout) || options.key?(:socket_timeout) || options.key?(:max_redirects) || options.key?(:follow_redirects)
346
+ config = RequestConfig.custom()
347
+ config.set_proxy get_proxy_host(options[:proxy]) if options[:proxy]
348
+ config.set_connect_timeout options[:connect_timeout] if options[:connect_timeout]
349
+ config.set_socket_timeout options[:socket_timeout] if options[:socket_timeout]
350
+ config.set_max_redirects options[:max_redirects] if options[:max_redirects]
351
+ config.set_redirects_enabled !!options[:follow_redirects] if options.fetch(:follow_redirects, nil) != nil
352
+ req.set_config config.build
353
+ end
354
+
366
355
  if options[:headers]
367
356
  options[:headers].each {|k, v| req.set_header k, v }
368
357
  end
369
358
 
370
- req
359
+ context = HttpClientContext.new
360
+ auth_from_options(options, context) if options.key? :auth
361
+
362
+ if @use_cookies == :per_request
363
+ store = BasicCookieStore.new
364
+ context.setAttribute(ClientContext.COOKIE_STORE, store)
365
+ end
366
+
367
+ return req, context
368
+ end
369
+
370
+ def get_proxy_host(opt)
371
+ host = nil
372
+ if opt.is_a? String
373
+ uri = URI.parse(opt)
374
+ if uri.host
375
+ get_proxy_host uri
376
+ else
377
+ uri = URI.parse("http://#{opt}")
378
+ get_proxy_host uri
379
+ end
380
+ elsif opt.is_a? Hash
381
+ HttpHost.new(opt[:host], (opt[:port] || 80).to_i, opt[:scheme] || "http")
382
+ elsif opt.is_a? URI
383
+ opt.scheme ||= "http"
384
+ opt.port ||= 80
385
+ HttpHost.new(opt.host, opt.port, opt.scheme)
386
+ end
387
+ end
388
+
389
+ def auth_from_options(options, context)
390
+ if options[:auth]
391
+ provider = BasicCredentialsProvider.new
392
+ username = options[:auth][:user] || options[:auth][:username]
393
+ password = options[:auth][:pass] || options[:auth][:password]
394
+ provider.set_credentials AuthScope::ANY, UsernamePasswordCredentials.new(username, password)
395
+ context.set_credentials_provider(provider)
396
+ end
371
397
  end
372
398
 
373
399
  def hash_to_entity(hash)
@@ -0,0 +1,87 @@
1
+ module Manticore
2
+ # @!attribute [r] comment
3
+ # @return [String] Returns the comment describing the purpose of this cookie, or nil if no such comment has been defined.
4
+ # @!attribute [r] comment_url
5
+ # @return [String] If a user agent (web browser) presents this cookie to a user, the cookie's purpose will be described by the information at this URL.
6
+ # @!attribute [r] domain
7
+ # @return [String] Returns domain attribute of the cookie.
8
+ # @!attribute [r] expiry_date
9
+ # @return [Time] Returns the expiration Date of the cookie, or nil if none exists.
10
+ # @!attribute [r] name
11
+ # @return [String] Returns the name of the cookie.
12
+ # @!attribute [r] path
13
+ # @return [String] Returns the path attribute of the cookie.
14
+ # @!attribute [r] ports
15
+ # @return [Array<Integer>] Returns the ports attribute of the cookie.
16
+ # @!attribute [r] value
17
+ # @return [Array<Integer>] Returns the cookie value
18
+ # @!attribute [r] spec_version
19
+ # @return [Integer] Returns the version of the cookie specification to which this cookie conforms.
20
+ class Cookie
21
+ # @private
22
+ # Create a Manticore::Cookie wrapper from a org.apache.http.cookie.Cookie
23
+ def self.from_java(cookie)
24
+ if cookie.get_expiry_date
25
+ expiry = Time.at(cookie.get_expiry_date / 1000)
26
+ end
27
+
28
+ new(
29
+ comment: cookie.get_comment,
30
+ comment_url: cookie.getCommentURL,
31
+ domain: cookie.get_domain,
32
+ expiry_date: expiry,
33
+ name: cookie.get_name,
34
+ path: cookie.get_path,
35
+ ports: cookie.get_ports.to_a,
36
+ value: cookie.get_value,
37
+ secure: cookie.is_secure,
38
+ persistent: cookie.is_persistent,
39
+ spec_version: cookie.get_version
40
+ )
41
+ end
42
+
43
+ attr_reader :comment, :comment_url, :domain, :expiry_date, :name, :path, :ports, :value, :spec_version
44
+
45
+ def initialize(args)
46
+ @comment = args.fetch(:comment, nil)
47
+ @comment_url = args.fetch(:comment_url, nil)
48
+ @domain = args.fetch(:domain, nil)
49
+ @expiry_date = args.fetch(:expiry_date, nil)
50
+ @name = args.fetch(:name, nil)
51
+ @path = args.fetch(:path, nil)
52
+ @ports = args.fetch(:ports, nil)
53
+ @value = args.fetch(:value, nil)
54
+ @secure = args.fetch(:secure, nil)
55
+ @persistent = args.fetch(:persistent, nil)
56
+ @spec_version = args.fetch(:spec_version, nil)
57
+ end
58
+
59
+ # @param date [Time] Time to compare against
60
+ #
61
+ # @return [Boolean] Whether this cookie is expired at the comparison date
62
+ def expired?(date = Time.now)
63
+ @expiry_date > date
64
+ end
65
+
66
+ # Whether this is a HTTPS-only cookie
67
+ #
68
+ # @return [Boolean]
69
+ def secure?
70
+ @secure
71
+ end
72
+
73
+ # Whether this is a persistent (session-only) cookie
74
+ #
75
+ # @return [Boolean]
76
+ def persistent?
77
+ @persistent
78
+ end
79
+
80
+ # Whether this is a session-only cookie
81
+ #
82
+ # @return [Boolean]
83
+ def session?
84
+ !@persistent
85
+ end
86
+ end
87
+ end
@@ -88,6 +88,18 @@ module Manticore
88
88
  (@headers["content-length"] || -1).to_i
89
89
  end
90
90
 
91
+ # Returns an array of {Manticore::Cookie Cookies} associated with this request's execution context
92
+ #
93
+ # @return [Array<Manticore::Cookie>]
94
+ def cookies
95
+ @context.get_cookie_store.get_cookies.inject({}) do |all, java_cookie|
96
+ c = Cookie.from_java(java_cookie)
97
+ all[c.name] ||= []
98
+ all[c.name] << c
99
+ all
100
+ end
101
+ end
102
+
91
103
  private
92
104
 
93
105
  def encode(string, charset)
@@ -1,3 +1,3 @@
1
1
  module Manticore
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -26,6 +26,83 @@ describe Manticore::Client do
26
26
  json["headers"]["Accept-Encoding"].should match("gzip")
27
27
  end
28
28
 
29
+ it "should authenticate" do
30
+ client.get(local_server("/auth")).code.should == 401
31
+ client.get(local_server("/auth"), auth: {user: "user", pass: "pass"}).code.should == 200
32
+ end
33
+
34
+ it "should proxy" do
35
+ j = JSON.parse(client.get(local_server("/proxy"), proxy: "http://localhost:55442").body)
36
+ j["server_port"].should == 55442
37
+ j["uri"]["port"].should == 55441
38
+ end
39
+
40
+ context "when client-wide cookie management is disabled" do
41
+ let(:client) { Manticore::Client.new cookies: false }
42
+
43
+ it "should persist cookies across multiple redirects from a single request" do
44
+ response = client.get(local_server("/cookies/1/2"))
45
+ response.final_url.to_s.should == local_server("/cookies/2/2")
46
+ response.cookies["x"].should be_nil
47
+ response.headers["set-cookie"].should match(/1/)
48
+ end
49
+
50
+ it "should not persist cookies between requests" do
51
+ response = client.get(local_server("/cookies/1/2"))
52
+ response.final_url.to_s.should == local_server("/cookies/2/2")
53
+ response.cookies["x"].should be_nil
54
+ response.headers["set-cookie"].should match(/1/)
55
+
56
+ response = client.get(local_server("/cookies/1/2"))
57
+ response.final_url.to_s.should == local_server("/cookies/2/2")
58
+ response.cookies["x"].should be_nil
59
+ response.headers["set-cookie"].should match(/1/)
60
+ end
61
+ end
62
+
63
+ context "when client-wide cookie management is set to per-request" do
64
+ let(:client) { Manticore::Client.new cookies: :per_request }
65
+
66
+ it "should persist cookies across multiple redirects from a single request" do
67
+ response = client.get(local_server("/cookies/1/2"))
68
+ response.final_url.to_s.should == local_server("/cookies/2/2")
69
+ response.headers["set-cookie"].should match(/2/)
70
+ response.cookies["x"].first.value.should == "2"
71
+ end
72
+
73
+ it "should not persist cookies between requests" do
74
+ response = client.get(local_server("/cookies/1/2"))
75
+ response.final_url.to_s.should == local_server("/cookies/2/2")
76
+ response.headers["set-cookie"].should match(/2/)
77
+ response.cookies["x"].first.value.should == "2"
78
+
79
+ response = client.get(local_server("/cookies/1/2"))
80
+ response.final_url.to_s.should == local_server("/cookies/2/2")
81
+ response.headers["set-cookie"].should match(/2/)
82
+ response.cookies["x"].first.value.should == "2"
83
+ end
84
+ end
85
+
86
+ context "when client-wide cookie management is enabled" do
87
+ let(:client) { Manticore::Client.new cookies: true }
88
+
89
+ it "should persist cookies across multiple redirects from a single request" do
90
+ response = client.get(local_server("/cookies/1/2"))
91
+ response.final_url.to_s.should == local_server("/cookies/2/2")
92
+ response.cookies["x"].first.value.should == "2"
93
+ end
94
+
95
+ it "should persist cookies between requests" do
96
+ response = client.get(local_server("/cookies/1/2"))
97
+ response.final_url.to_s.should == local_server("/cookies/2/2")
98
+ response.cookies["x"].first.value.should == "2"
99
+
100
+ response = client.get(local_server("/cookies/1/2"))
101
+ response.final_url.to_s.should == local_server("/cookies/2/2")
102
+ response.cookies["x"].first.value.should == "4"
103
+ end
104
+ end
105
+
29
106
  context "when compression is disabled" do
30
107
  let(:client) {
31
108
  Manticore::Client.new do |client, request_config|
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Manticore::Cookie do
4
+ context "created from a Client request" do
5
+ let(:client) { Manticore::Client.new cookies: true }
6
+ subject {
7
+ response = client.get(local_server("/cookies/1/2"))
8
+ response.final_url.to_s.should == local_server("/cookies/2/2")
9
+ response.cookies["x"].first
10
+ }
11
+
12
+ its(:name) { should be_a String }
13
+ its(:value) { should be_a String }
14
+ its(:path) { should be_a String }
15
+ its(:domain) { should be_a String }
16
+ end
17
+ end
@@ -38,10 +38,27 @@ def start_server(port = PORT)
38
38
  request[:body] = read_nonblock stream.socket
39
39
  end
40
40
 
41
- if request[:headers]["X-Redirect"] && request[:uri][:path] != request[:headers]["X-Redirect"]
41
+ content_type = request[:headers]["X-Content-Type"] || "text/plain"
42
+ if request[:uri][:path] == "/auth"
43
+ if request[:headers]["Authorization"] == "Basic dXNlcjpwYXNz"
44
+ payload = JSON.dump(request)
45
+ [200, {'Content-Type' => content_type, "Content-Length" => payload.length}, [payload]]
46
+ else
47
+ [401, {'WWW-Authenticate' => 'Basic realm="test"'}, [""]]
48
+ end
49
+ elsif match = request[:uri][:path].match(/\/cookies\/(\d)\/(\d)/)
50
+ cookie_value = (request[:headers]["Cookie"] || "x=0").split("=").last.to_i
51
+ if match[1].to_i == match[2].to_i
52
+ [200, {"Set-Cookie" => "x=#{cookie_value + 1}; Path=/"}, [""]]
53
+ else
54
+ [301, {"Set-Cookie" => "x=#{cookie_value + 1}; Path=/", "Location" => "/cookies/#{match[1].to_i + 1}/#{match[2]}"}, [""]]
55
+ end
56
+ elsif request[:uri][:path] == "/proxy"
57
+ payload = JSON.dump(request.merge(server_port: port))
58
+ [200, {'Content-Type' => content_type, "Content-Length" => payload.length}, [payload]]
59
+ elsif request[:headers]["X-Redirect"] && request[:uri][:path] != request[:headers]["X-Redirect"]
42
60
  [301, {"Location" => local_server( request[:headers]["X-Redirect"] )}, [""]]
43
61
  else
44
- content_type = request[:headers]["X-Content-Type"] || "text/plain"
45
62
  if request[:headers]["Accept-Encoding"] && request[:headers]["Accept-Encoding"].match("gzip")
46
63
  out = StringIO.new('', "w")
47
64
  io = Zlib::GzipWriter.new(out, 2)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manticore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: java
6
6
  authors:
7
7
  - Chris Heald
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-18 00:00:00.000000000 Z
11
+ date: 2014-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -67,6 +67,7 @@ files:
67
67
  - README.md
68
68
  - Rakefile
69
69
  - ext/manticore/org/manticore/Manticore.java
70
+ - lib/jar/commons-codec-1.6.jar
70
71
  - lib/jar/commons-logging-1.1.3.jar
71
72
  - lib/jar/httpclient-4.3.2-patched.jar
72
73
  - lib/jar/httpcore-4.3.1.jar
@@ -75,11 +76,13 @@ files:
75
76
  - lib/manticore.rb
76
77
  - lib/manticore/async_response.rb
77
78
  - lib/manticore/client.rb
79
+ - lib/manticore/cookie.rb
78
80
  - lib/manticore/facade.rb
79
81
  - lib/manticore/response.rb
80
82
  - lib/manticore/version.rb
81
83
  - manticore.gemspec
82
84
  - spec/manticore/client_spec.rb
85
+ - spec/manticore/cookie_spec.rb
83
86
  - spec/manticore/facade_spec.rb
84
87
  - spec/manticore/response_spec.rb
85
88
  - spec/spec_helper.rb
@@ -109,6 +112,7 @@ specification_version: 4
109
112
  summary: Manticore is an HTTP client built on the Apache HttpCore components
110
113
  test_files:
111
114
  - spec/manticore/client_spec.rb
115
+ - spec/manticore/cookie_spec.rb
112
116
  - spec/manticore/facade_spec.rb
113
117
  - spec/manticore/response_spec.rb
114
118
  - spec/spec_helper.rb