rsolr 0.13.0.pre → 1.0.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +48 -29
- data/VERSION +1 -1
- data/lib/rsolr/char.rb +9 -0
- data/lib/rsolr/client.rb +80 -58
- data/lib/rsolr/error.rb +122 -0
- data/lib/rsolr/http.rb +106 -0
- data/lib/rsolr/uri.rb +55 -0
- data/lib/rsolr/xml.rb +161 -0
- data/lib/rsolr.rb +18 -39
- data/spec/api/rsolr_client_spec.rb +195 -0
- data/spec/api/rsolr_error_spec.rb +4 -0
- data/spec/api/rsolr_http_spec.rb +4 -0
- data/spec/api/rsolr_spec.rb +11 -23
- data/spec/api/rsolr_uri_spec.rb +70 -0
- data/spec/api/{message_spec.rb → rsolr_xml_spec.rb} +5 -4
- metadata +14 -18
- data/lib/rsolr/connection/httpable.rb +0 -101
- data/lib/rsolr/connection/net_http.rb +0 -30
- data/lib/rsolr/connection/utils.rb +0 -74
- data/lib/rsolr/connection.rb +0 -9
- data/lib/rsolr/message/document.rb +0 -48
- data/lib/rsolr/message/field.rb +0 -20
- data/lib/rsolr/message/generator.rb +0 -89
- data/lib/rsolr/message.rb +0 -8
- data/spec/api/client_spec.rb +0 -115
- data/spec/api/connection/httpable_spec.rb +0 -157
- data/spec/api/connection/net_http_spec.rb +0 -137
- data/spec/api/connection/utils_spec.rb +0 -84
- data/spec/integration/http_errors_spec.rb +0 -12
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
=RSolr
|
2
2
|
|
3
|
+
Notice: This document is only for the the 1.0 (pre-release) in the master branch. The last stable gem release documentation can be found here: http://github.com/mwmitchell/rsolr/tree/v0.12.1
|
4
|
+
|
3
5
|
A simple, extensible Ruby client for Apache Solr.
|
4
6
|
|
5
7
|
== Installation:
|
@@ -11,23 +13,20 @@ A simple, extensible Ruby client for Apache Solr.
|
|
11
13
|
require 'rsolr'
|
12
14
|
|
13
15
|
# Direct connection
|
14
|
-
solr = RSolr.connect
|
16
|
+
solr = RSolr.connect 'http://solrserver.com'
|
15
17
|
|
16
18
|
# Connecting over a proxy server
|
17
|
-
solr = RSolr.connect
|
19
|
+
solr = RSolr.connect 'http://solrserver.com', :proxy=>'http://user:pass@proxy.example.com:8080'
|
18
20
|
|
19
21
|
# send a request to /select
|
20
|
-
response = solr.select :q=>'*:*'
|
22
|
+
response = solr.get 'select', :q=>'*:*'
|
21
23
|
|
22
24
|
# send a request to a custom request handler; /catalog
|
23
|
-
response = solr.
|
25
|
+
response = solr.get 'catalog', :q=>'*:*'
|
24
26
|
|
25
|
-
# alternative to above:
|
26
|
-
response = solr.catalog :q=>'*:*'
|
27
|
-
|
28
27
|
== Querying
|
29
28
|
Use the #select method to send requests to the /select handler:
|
30
|
-
response = solr.select
|
29
|
+
response = solr.get('select', {
|
31
30
|
:q=>'washington',
|
32
31
|
:start=>0,
|
33
32
|
:rows=>10
|
@@ -35,25 +34,23 @@ Use the #select method to send requests to the /select handler:
|
|
35
34
|
|
36
35
|
The params sent into the method are sent to Solr as-is. The one exception is if a value is an array. When an array is used, multiple parameters *with the same name* are generated for the Solr query. Example:
|
37
36
|
|
38
|
-
solr.select :q=>'roses', :fq=>['red', 'violet']
|
37
|
+
solr.get 'select', :q=>'roses', :fq=>['red', 'violet']
|
39
38
|
|
40
39
|
The above statement generates this Solr query:
|
41
40
|
|
42
|
-
?q=roses&fq=red&fq=violet
|
41
|
+
select?q=roses&fq=red&fq=violet
|
43
42
|
|
44
|
-
|
45
|
-
response = solr.
|
46
|
-
|
47
|
-
A shortcut for the above example use a method call instead:
|
48
|
-
response = solr.documents :q=>'test'
|
43
|
+
There may be cases where the query string is too long for a GET request. RSolr solves this issue by providing a simple way to POST a query to Solr:
|
44
|
+
response = solr.post "select", nil, enormous_params_hash
|
49
45
|
|
46
|
+
nil is passed in as the query string data. The enormous_params_hash variable ends up serialized as a form-encoded query string, and the correct content-type headers are sent along to Solr.
|
50
47
|
|
51
48
|
== Updating Solr
|
52
|
-
Updating
|
49
|
+
Updating us done using native Ruby objects. Hashes are used for single documents and arrays are used for a collection of documents (hashes). These objects get turned into simple XML "messages". Raw XML strings can also be used.
|
53
50
|
|
54
51
|
Raw XML via #update
|
55
|
-
solr.update '
|
56
|
-
solr.update '
|
52
|
+
solr.update '<commit/>'
|
53
|
+
solr.update '<optimize/>'
|
57
54
|
|
58
55
|
Single document via #add
|
59
56
|
solr.add :id=>1, :price=>1.00
|
@@ -91,22 +88,26 @@ Commit & optimize shortcuts
|
|
91
88
|
The default response format is Ruby. When the :wt param is set to :ruby, the response is eval'd resulting in a Hash. You can get a raw response by setting the :wt to "ruby" - notice, the string -- not a symbol. RSolr will eval the Ruby string ONLY if the :wt value is :ruby. All other response formats are available as expected, :wt=>'xml' etc..
|
92
89
|
|
93
90
|
===Evaluated Ruby (default)
|
94
|
-
solr.select
|
91
|
+
solr.get 'select', :wt=>:ruby # notice :ruby is a Symbol
|
95
92
|
===Raw Ruby
|
96
|
-
solr.select
|
93
|
+
solr.get 'select', :wt=>'ruby' # notice 'ruby' is a String
|
97
94
|
|
98
95
|
===XML:
|
99
|
-
solr.select
|
96
|
+
solr.get 'select', :wt=>:xml
|
100
97
|
===JSON:
|
101
|
-
solr.select
|
98
|
+
solr.get 'select', :wt=>:json
|
102
99
|
|
103
|
-
You can access the original request context (path, params, url etc.) by calling the #
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
100
|
+
You can access the original request context (path, params, url etc.) by calling the #request method:
|
101
|
+
result = solr.get 'select', :q=>'*:*'
|
102
|
+
result.request[:uri]
|
103
|
+
result.request[:params]
|
104
|
+
etc..
|
108
105
|
|
109
|
-
|
106
|
+
Similarly, the object returned has a response object. This contains any headers that Solr returned, along with the raw response body:
|
107
|
+
result = solr.get 'select', :q=>'*:*'
|
108
|
+
result.response[:headers]
|
109
|
+
result.response[:status]
|
110
|
+
result.response[:body]
|
110
111
|
|
111
112
|
==Related Resources & Projects
|
112
113
|
* {RSolr Google Group}[http://groups.google.com/group/rsolr] -- The RSolr discussion group
|
@@ -127,6 +128,16 @@ The raw is a hash that contains the generated params, url, path, post data, head
|
|
127
128
|
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
128
129
|
* Send me a pull request. Bonus points for topic branches.
|
129
130
|
|
131
|
+
== Note on Patches/Pull Requests
|
132
|
+
|
133
|
+
* Fork the project.
|
134
|
+
* Make your feature addition or bug fix.
|
135
|
+
* Add tests for it. This is important so I don't break it in a
|
136
|
+
future version unintentionally.
|
137
|
+
* Commit, do not mess with rakefile, version, or history.
|
138
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
139
|
+
* Send me a pull request. Bonus points for topic branches.
|
140
|
+
|
130
141
|
==Contributors
|
131
142
|
* Lorenzo Riccucci
|
132
143
|
* Mike Perham
|
@@ -136,4 +147,12 @@ The raw is a hash that contains the generated params, url, path, post data, head
|
|
136
147
|
* Fouad Mardini
|
137
148
|
* Jeremy Hinegardner
|
138
149
|
* Nathan Witmer
|
139
|
-
* Craig Smith
|
150
|
+
* Craig Smith
|
151
|
+
|
152
|
+
==Author
|
153
|
+
|
154
|
+
Matt Mitchell <mailto:goodieboy@gmail.com>
|
155
|
+
|
156
|
+
==Copyright
|
157
|
+
|
158
|
+
Copyright (c) 2008-2010 mwmitchell. See LICENSE for details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0.beta
|
data/lib/rsolr/char.rb
ADDED
data/lib/rsolr/client.rb
CHANGED
@@ -2,37 +2,31 @@ class RSolr::Client
|
|
2
2
|
|
3
3
|
attr_reader :connection
|
4
4
|
|
5
|
-
|
6
|
-
# RSolr::Adapter::HTTP
|
7
|
-
# RSolr::Adapter::Direct (jRuby only)
|
8
|
-
# or any other class that uses the connection "interface"
|
9
|
-
def initialize(connection)
|
5
|
+
def initialize connection
|
10
6
|
@connection = connection
|
11
7
|
end
|
12
8
|
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
request("/#{method_name}", *args, &blk)
|
9
|
+
# GET request
|
10
|
+
def get path = '', params = nil, headers = nil
|
11
|
+
send_request :get, path, params, nil, headers
|
17
12
|
end
|
18
13
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
request '/update', params, data
|
14
|
+
# essentially a GET, but no response body
|
15
|
+
def head path = '', params = nil, headers = nil
|
16
|
+
send_request :head, path, params, nil, headers
|
23
17
|
end
|
24
18
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
def
|
34
|
-
|
35
|
-
|
19
|
+
# A path is required for a POST since, well...
|
20
|
+
# the / resource doesn't do anything with a POST.
|
21
|
+
# Also, Solr doesn't do headers with a POST
|
22
|
+
def post path, data = nil, params = nil, headers = nil
|
23
|
+
send_request :post, path, params, data, headers
|
24
|
+
end
|
25
|
+
|
26
|
+
# POST XML messages to /update with optional params
|
27
|
+
def update data, params = {}, headers = {}
|
28
|
+
headers['Content-Type'] ||= 'text/xml'
|
29
|
+
post 'update', data, params, headers
|
36
30
|
end
|
37
31
|
|
38
32
|
#
|
@@ -43,10 +37,10 @@ class RSolr::Client
|
|
43
37
|
# solr.update([{:id=>1, :name=>'one'}, {:id=>2, :name=>'two'}])
|
44
38
|
#
|
45
39
|
def add(doc, params={}, &block)
|
46
|
-
update
|
40
|
+
update xml.add(doc, params, &block)
|
47
41
|
end
|
48
42
|
|
49
|
-
# send "commit"
|
43
|
+
# send "commit" xml with options
|
50
44
|
#
|
51
45
|
# Options recognized by solr
|
52
46
|
#
|
@@ -58,10 +52,10 @@ class RSolr::Client
|
|
58
52
|
# *NOTE* :expungeDeletes is Solr 1.4 only
|
59
53
|
#
|
60
54
|
def commit( options = {} )
|
61
|
-
update
|
55
|
+
update xml.commit( options )
|
62
56
|
end
|
63
57
|
|
64
|
-
# send "optimize"
|
58
|
+
# send "optimize" xml with options.
|
65
59
|
#
|
66
60
|
# Options recognized by solr
|
67
61
|
#
|
@@ -73,61 +67,89 @@ class RSolr::Client
|
|
73
67
|
# *NOTE* :expungeDeletes is Solr 1.4 only
|
74
68
|
#
|
75
69
|
def optimize( options = {} )
|
76
|
-
update
|
70
|
+
update xml.optimize( options )
|
77
71
|
end
|
78
72
|
|
79
73
|
# send </rollback>
|
80
74
|
# NOTE: solr 1.4 only
|
81
75
|
def rollback
|
82
|
-
update
|
76
|
+
update xml.rollback
|
83
77
|
end
|
84
78
|
|
85
79
|
# Delete one or many documents by id
|
86
80
|
# solr.delete_by_id 10
|
87
81
|
# solr.delete_by_id([12, 41, 199])
|
88
82
|
def delete_by_id(id)
|
89
|
-
update
|
83
|
+
update xml.delete_by_id(id)
|
90
84
|
end
|
91
85
|
|
92
86
|
# delete one or many documents by query
|
93
87
|
# solr.delete_by_query 'available:0'
|
94
88
|
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
95
89
|
def delete_by_query(query)
|
96
|
-
update
|
90
|
+
update xml.delete_by_query(query)
|
97
91
|
end
|
98
92
|
|
99
93
|
# shortcut to RSolr::Message::Generator
|
100
|
-
def
|
101
|
-
@
|
94
|
+
def xml
|
95
|
+
@xml ||= RSolr::Xml::Generator.new
|
102
96
|
end
|
103
97
|
|
104
|
-
|
98
|
+
def send_request method, path, params, data, headers
|
99
|
+
params = map_params params
|
100
|
+
uri, data, headers = build_request path, params, data, headers
|
101
|
+
request_context = {:connection=>connection, :method => method, :uri => uri, :data => data, :headers => headers, :params => params}
|
102
|
+
begin
|
103
|
+
response = data ? connection.send(method, uri, data, headers) : connection.send(method, uri, headers)
|
104
|
+
rescue
|
105
|
+
$!.extend(RSolr::Error::SolrContext).request = request_context
|
106
|
+
raise $!
|
107
|
+
end
|
108
|
+
raise "The connection adapter returned an unexpected object" unless response.is_a?(Hash)
|
109
|
+
raise RSolr::Error::Http.new request_context, response unless [200,302].include?(response[:status])
|
110
|
+
adapt_response request_context, response
|
111
|
+
end
|
105
112
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
params
|
110
|
-
{:wt=>:ruby}.merge(params)
|
113
|
+
def map_params params
|
114
|
+
params = params.nil? ? {} : params.dup
|
115
|
+
params[:wt] ||= :ruby
|
116
|
+
params
|
111
117
|
end
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
data
|
124
|
-
|
125
|
-
|
126
|
-
|
118
|
+
|
119
|
+
def build_request path, params, data, headers
|
120
|
+
params ||= {}
|
121
|
+
headers ||= {}
|
122
|
+
request_uri = params.any? ? "#{path}?#{RSolr::Uri.params_to_solr params}" : path
|
123
|
+
if data
|
124
|
+
if data.is_a? Hash
|
125
|
+
data = RSolr::Uri.params_to_solr data
|
126
|
+
headers['Content-Type'] ||= 'application/x-www-form-urlencoded'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
[request_uri, data, headers]
|
130
|
+
end
|
131
|
+
|
132
|
+
# This method will evaluate the :body value
|
133
|
+
# if the params[:uri].params[:wt] == :ruby
|
134
|
+
# ... otherwise, the body is returned as is.
|
135
|
+
# The return object has a special method attached called #context.
|
136
|
+
# This method gives you access to the original
|
137
|
+
# request and response from the connection.
|
138
|
+
# This method will raise an InvalidRubyResponse
|
139
|
+
# if the :wt => :ruby and the body
|
140
|
+
# couldn't be evaluated.
|
141
|
+
def adapt_response request, response
|
142
|
+
data = response[:body]
|
143
|
+
if request[:params][:wt] == :ruby
|
144
|
+
begin
|
145
|
+
data = Kernel.eval data.to_s
|
146
|
+
rescue SyntaxError
|
147
|
+
raise RSolr::Error::InvalidRubyResponse.new request, response
|
148
|
+
end
|
127
149
|
end
|
128
|
-
|
129
|
-
|
130
|
-
data.
|
150
|
+
data.extend Module.new.instance_eval{attr_accessor :request, :response; self}
|
151
|
+
data.request = request
|
152
|
+
data.response = response
|
131
153
|
data
|
132
154
|
end
|
133
155
|
|
data/lib/rsolr/error.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module RSolr::Error
|
2
|
+
|
3
|
+
module SolrContext
|
4
|
+
|
5
|
+
attr_accessor :request, :response
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
m = "#{super.to_s}"
|
9
|
+
|
10
|
+
if response
|
11
|
+
m << " - #{response[:status]} #{Http::STATUS_CODES[response[:status].to_i]}"
|
12
|
+
details = parse_solr_error_response response[:body]
|
13
|
+
m << "Error: #{details}\n" if details
|
14
|
+
end
|
15
|
+
|
16
|
+
m << "\n" + self.backtrace[0..10].join("\n")
|
17
|
+
m << "\n\nSolr Request:"
|
18
|
+
m << "\n Method: #{request[:method].to_s.upcase}"
|
19
|
+
m << "\n Base URL: #{request[:connection].uri.to_s}"
|
20
|
+
m << "\n URL: #{request[:uri]}"
|
21
|
+
m << "\n Params: #{request[:params].inspect}"
|
22
|
+
m << "\n Data: #{request[:data].inspect}" if request[:data]
|
23
|
+
m << "\n Headers: #{request[:headers].inspect}"
|
24
|
+
if response
|
25
|
+
m << "\n\nSolr Response:"
|
26
|
+
m << "\n Code: #{response[:status]}"
|
27
|
+
m << "\n Headers: #{response[:headers].inspect}"
|
28
|
+
end
|
29
|
+
m
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def parse_solr_error_response body
|
35
|
+
begin
|
36
|
+
info = body.scan(/<pre>(.*)<\/pre>/mi)[0]
|
37
|
+
partial = info.to_s.split("\n")[0..10]
|
38
|
+
partial.join("\n").gsub(">", ">").gsub("<", "<")
|
39
|
+
rescue
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class Http < RuntimeError
|
47
|
+
|
48
|
+
include SolrContext
|
49
|
+
|
50
|
+
# ripped right from ActionPack
|
51
|
+
# Defines the standard HTTP status codes, by integer, with their
|
52
|
+
# corresponding default message texts.
|
53
|
+
# Source: http://www.iana.org/assignments/http-status-codes
|
54
|
+
STATUS_CODES = {
|
55
|
+
100 => "Continue",
|
56
|
+
101 => "Switching Protocols",
|
57
|
+
102 => "Processing",
|
58
|
+
|
59
|
+
200 => "OK",
|
60
|
+
201 => "Created",
|
61
|
+
202 => "Accepted",
|
62
|
+
203 => "Non-Authoritative Information",
|
63
|
+
204 => "No Content",
|
64
|
+
205 => "Reset Content",
|
65
|
+
206 => "Partial Content",
|
66
|
+
207 => "Multi-Status",
|
67
|
+
226 => "IM Used",
|
68
|
+
|
69
|
+
300 => "Multiple Choices",
|
70
|
+
301 => "Moved Permanently",
|
71
|
+
302 => "Found",
|
72
|
+
303 => "See Other",
|
73
|
+
304 => "Not Modified",
|
74
|
+
305 => "Use Proxy",
|
75
|
+
307 => "Temporary Redirect",
|
76
|
+
|
77
|
+
400 => "Bad Request",
|
78
|
+
401 => "Unauthorized",
|
79
|
+
402 => "Payment Required",
|
80
|
+
403 => "Forbidden",
|
81
|
+
404 => "Not Found",
|
82
|
+
405 => "Method Not Allowed",
|
83
|
+
406 => "Not Acceptable",
|
84
|
+
407 => "Proxy Authentication Required",
|
85
|
+
408 => "Request Timeout",
|
86
|
+
409 => "Conflict",
|
87
|
+
410 => "Gone",
|
88
|
+
411 => "Length Required",
|
89
|
+
412 => "Precondition Failed",
|
90
|
+
413 => "Request Entity Too Large",
|
91
|
+
414 => "Request-URI Too Long",
|
92
|
+
415 => "Unsupported Media Type",
|
93
|
+
416 => "Requested Range Not Satisfiable",
|
94
|
+
417 => "Expectation Failed",
|
95
|
+
422 => "Unprocessable Entity",
|
96
|
+
423 => "Locked",
|
97
|
+
424 => "Failed Dependency",
|
98
|
+
426 => "Upgrade Required",
|
99
|
+
|
100
|
+
500 => "Internal Server Error",
|
101
|
+
501 => "Not Implemented",
|
102
|
+
502 => "Bad Gateway",
|
103
|
+
503 => "Service Unavailable",
|
104
|
+
504 => "Gateway Timeout",
|
105
|
+
505 => "HTTP Version Not Supported",
|
106
|
+
507 => "Insufficient Storage",
|
107
|
+
510 => "Not Extended"
|
108
|
+
}
|
109
|
+
|
110
|
+
def initialize request, response
|
111
|
+
@request, @response = request, response
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
# Thrown if the :wt is :ruby
|
117
|
+
# but the body wasn't succesfully parsed/evaluated
|
118
|
+
class InvalidRubyResponse < Http
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
data/lib/rsolr/http.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
module RSolr
|
2
|
+
|
3
|
+
class Http
|
4
|
+
|
5
|
+
attr_reader :uri, :proxy, :options
|
6
|
+
|
7
|
+
def initialize base_url, options = {}
|
8
|
+
@options = options
|
9
|
+
@uri = base_url
|
10
|
+
@proxy = options[:proxy]
|
11
|
+
end
|
12
|
+
|
13
|
+
def base_uri
|
14
|
+
@proxy ? @proxy.request_uri : @uri.request_uri
|
15
|
+
end
|
16
|
+
|
17
|
+
def http
|
18
|
+
@http ||= (
|
19
|
+
http = if proxy
|
20
|
+
proxy_user, proxy_pass = proxy.userinfo.split(/:/) if proxy.userinfo
|
21
|
+
Net::HTTP.Proxy(proxy.host, proxy.port, proxy_user, proxy_pass).new uri.host, uri.port
|
22
|
+
else
|
23
|
+
Net::HTTP.new uri.host, uri.port
|
24
|
+
end
|
25
|
+
|
26
|
+
http.use_ssl = uri.port == 443 || uri.instance_of?(URI::HTTPS)
|
27
|
+
|
28
|
+
if options[:timeout] && options[:timeout].is_a?(Integer)
|
29
|
+
http.open_timeout = options[:timeout]
|
30
|
+
http.read_timeout = options[:timeout]
|
31
|
+
end
|
32
|
+
|
33
|
+
if options[:pem] && http.use_ssl?
|
34
|
+
http.cert = OpenSSL::X509::Certificate.new(options[:pem])
|
35
|
+
http.key = OpenSSL::PKey::RSA.new(options[:pem])
|
36
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
37
|
+
else
|
38
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
39
|
+
end
|
40
|
+
|
41
|
+
if options[:debug_output]
|
42
|
+
http.set_debug_output(options[:debug_output])
|
43
|
+
end
|
44
|
+
|
45
|
+
http
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
# send in path w/query
|
50
|
+
def get request_uri, headers = {}
|
51
|
+
req = setup_raw_request Net::HTTP::Get, request_uri, headers
|
52
|
+
perform_request http, req
|
53
|
+
end
|
54
|
+
|
55
|
+
# send in path w/query
|
56
|
+
def head request_uri, headers = {}
|
57
|
+
req = setup_raw_request Net::HTTP::Head, request_uri, headers
|
58
|
+
perform_request http, req
|
59
|
+
end
|
60
|
+
|
61
|
+
# send in path w/query
|
62
|
+
def post request_uri, data, headers = {}
|
63
|
+
req = setup_raw_request Net::HTTP::Post, request_uri, headers
|
64
|
+
req.body = data if data
|
65
|
+
perform_request http, req
|
66
|
+
end
|
67
|
+
|
68
|
+
def perform_request http, request
|
69
|
+
begin
|
70
|
+
response = http.request request
|
71
|
+
{:status => response.code.to_i, :headers => response.to_hash, :body => response.body}
|
72
|
+
rescue NoMethodError
|
73
|
+
$!.message == "undefined method `closed?' for nil:NilClass" ?
|
74
|
+
raise(Errno::ECONNREFUSED.new) :
|
75
|
+
raise($!)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def setup_raw_request http_method, request_uri, headers = {}
|
80
|
+
raw_request = http_method.new "#{base_uri}#{request_uri}"
|
81
|
+
raw_request.initialize_http_header headers
|
82
|
+
raw_request.basic_auth username, password if options[:basic_auth]
|
83
|
+
if options[:digest_auth]
|
84
|
+
res = http.head(request_uri, headers)
|
85
|
+
if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
|
86
|
+
raw_request.digest_auth username, password, res
|
87
|
+
end
|
88
|
+
end
|
89
|
+
raw_request
|
90
|
+
end
|
91
|
+
|
92
|
+
def credentials
|
93
|
+
options[:basic_auth] || options[:digest_auth]
|
94
|
+
end
|
95
|
+
|
96
|
+
def username
|
97
|
+
credentials[:username]
|
98
|
+
end
|
99
|
+
|
100
|
+
def password
|
101
|
+
credentials[:password]
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
data/lib/rsolr/uri.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module RSolr::Uri
|
2
|
+
|
3
|
+
def self.create url
|
4
|
+
::URI.parse url[-1] == ?/ ? url : "#{url}/"
|
5
|
+
end
|
6
|
+
|
7
|
+
# Returns a query string param pair as a string.
|
8
|
+
# Both key and value are escaped.
|
9
|
+
def build_param(k,v)
|
10
|
+
"#{escape_query_value(k)}=#{escape_query_value(v)}"
|
11
|
+
end
|
12
|
+
|
13
|
+
# Return the bytesize of String; uses String#size under Ruby 1.8 and
|
14
|
+
# String#bytesize under 1.9.
|
15
|
+
if ''.respond_to?(:bytesize)
|
16
|
+
def bytesize(string)
|
17
|
+
string.bytesize
|
18
|
+
end
|
19
|
+
else
|
20
|
+
def bytesize(string)
|
21
|
+
string.size
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates a Solr based query string.
|
26
|
+
# Keys that have arrays values are set multiple times:
|
27
|
+
# params_to_solr(:q => 'query', :fq => ['a', 'b'])
|
28
|
+
# is converted to:
|
29
|
+
# ?q=query&fq=a&fq=b
|
30
|
+
def params_to_solr(params)
|
31
|
+
mapped = params.map do |k, v|
|
32
|
+
next if v.to_s.empty?
|
33
|
+
if v.class == Array
|
34
|
+
params_to_solr(v.map { |x| [k, x] })
|
35
|
+
else
|
36
|
+
build_param k, v
|
37
|
+
end
|
38
|
+
end
|
39
|
+
mapped.compact.join("&")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Performs URI escaping so that you can construct proper
|
43
|
+
# query strings faster. Use this rather than the cgi.rb
|
44
|
+
# version since it's faster.
|
45
|
+
# (Stolen from Rack).
|
46
|
+
def escape_query_value(s)
|
47
|
+
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
48
|
+
#'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
49
|
+
'%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
|
50
|
+
}.tr(' ', '+')
|
51
|
+
end
|
52
|
+
|
53
|
+
extend self
|
54
|
+
|
55
|
+
end
|