mwmitchell-rsolr 0.6.9 → 0.7.0
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/CHANGES.txt +8 -0
- data/README.rdoc +21 -27
- data/examples/direct.rb +2 -1
- data/examples/http.rb +1 -1
- data/lib/core_ext.rb +8 -0
- data/lib/rsolr/connection/adapter/common_methods.rb +30 -25
- data/lib/rsolr/connection/adapter/direct.rb +1 -1
- data/lib/rsolr/connection/adapter/http.rb +1 -1
- data/lib/rsolr/connection/base.rb +39 -89
- data/lib/rsolr/connection.rb +0 -1
- data/lib/rsolr.rb +4 -1
- data/test/connection/test_methods.rb +0 -31
- metadata +2 -5
- data/lib/rsolr/connection/param_mapping/dismax.rb +0 -41
- data/lib/rsolr/connection/param_mapping/standard.rb +0 -127
- data/lib/rsolr/connection/param_mapping.rb +0 -39
- data/test/connection/param_mapping_test.rb +0 -61
- data/test/ruby-lang.org.rss.xml +0 -391
data/CHANGES.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
0.7.0 - February 20, 2009
|
2
|
+
Removed all param mapping behavior, code and tests
|
3
|
+
- this stuff just gunks up rsolr and should be in an extension of some sort
|
4
|
+
Can now specify the request handler in all RSolr::Connection::Base methods as the first argument:
|
5
|
+
- solr.query 'select', :q=>'ipod'
|
6
|
+
- solr.query 'catalog', :q=>'humphry'
|
7
|
+
- solr.query :q=>'big' # defaults to the /select handler
|
8
|
+
|
1
9
|
0.6.9 - January 29, 2009
|
2
10
|
Simplified facet response methods
|
3
11
|
Main facet method is called #facets
|
data/README.rdoc
CHANGED
@@ -10,8 +10,9 @@ Simple usage:
|
|
10
10
|
require 'rubygems'
|
11
11
|
require 'rsolr'
|
12
12
|
rsolr = RSolr.connect
|
13
|
-
response = rsolr.query(:q=>'*:*')
|
14
|
-
|
13
|
+
response = rsolr.query(:q=>'*:*') # becomes /solr/select?q=*:*
|
14
|
+
# can also set the request handler path like:
|
15
|
+
response = rsolr.query('catalog', :q=>'*:*') # becomes /solr/catalog?q=*:*
|
15
16
|
|
16
17
|
To run tests:
|
17
18
|
|
@@ -28,41 +29,35 @@ To get a direct connection (no http) in jRuby using DirectSolrConnection:
|
|
28
29
|
|
29
30
|
solr = RSolr.connect(:adapter=>:direct, :home_dir=>'/path/to/solr/home', :dist_dir=>'/path/to/solr/distribution')
|
30
31
|
|
31
|
-
You can set
|
32
|
+
You can set the request handler paths for every request:
|
32
33
|
|
33
|
-
solr = RSolr.connect(:
|
34
|
+
solr = RSolr.connect(:select_path=>'select', :update_path=>'update', :luke_path=>'admin/luke')
|
34
35
|
|
35
36
|
|
36
37
|
== Requests
|
37
38
|
Once you have a connection, you can execute queries, updates etc..
|
38
39
|
|
40
|
+
You can optionally specify the request handler path by sending it in as the first argument:
|
41
|
+
solr.query 'catalog', :q=>'object_type:"book"'
|
42
|
+
solr.update 'my/update', '<xml/>'
|
43
|
+
|
44
|
+
The default request handler path value for each of the different methods are as follows:
|
45
|
+
find_by_id, query == 'select'
|
46
|
+
add, update, commit, optimize, rollback, delete_by_id, delete_by_query == 'update'
|
47
|
+
index_info == 'admin/luke'
|
48
|
+
|
49
|
+
Please note that the path you specify should be relative.
|
50
|
+
|
39
51
|
|
40
52
|
=== Querying
|
41
|
-
Use the #query method to send requests to
|
42
|
-
|
43
|
-
response = solr.query(:q=>'washington', :facet=>true, 'facet.limit'=>-1, 'facet.field'=>'cat', 'facet.field'=>'inStock')
|
53
|
+
Use the #query method to send requests to the /select handler:
|
54
|
+
response = solr.query(:q=>'washington', :facet=>true, 'facet.limit'=>-1, 'facet.field'=>'cat', 'facet.field'=>'inStock', :start=>0, :rows=>10)
|
44
55
|
response = solr.find_by_id(1)
|
45
56
|
|
46
|
-
==== Search Params
|
47
|
-
The #search method can accept the following params:
|
48
|
-
===== When :qt is :standard
|
49
|
-
:page
|
50
|
-
:per_page
|
51
|
-
:queries
|
52
|
-
:filters
|
53
|
-
:phrase_queries
|
54
|
-
:phrase_filters
|
55
|
-
:facets
|
56
|
-
===== When :qt is :dismax (also includes the :standard params)
|
57
|
-
:alternate_query
|
58
|
-
:query_fields
|
59
|
-
:phrase_fields
|
60
|
-
:boost_query
|
61
|
-
|
62
57
|
==== Pagination
|
63
|
-
Pagination is simplified
|
64
|
-
|
65
|
-
response = solr.
|
58
|
+
Pagination is simplified from having a few helpful response methods:
|
59
|
+
|
60
|
+
response = solr.query(:start=>0, :rows=>10, :q=>'*:*')
|
66
61
|
response.per_page
|
67
62
|
response.total_pages
|
68
63
|
response.current_page
|
@@ -73,7 +68,6 @@ If you use WillPaginate, just pass-in the response to the #will_paginate view he
|
|
73
68
|
|
74
69
|
<%= will_paginate(@response) %>
|
75
70
|
|
76
|
-
The #search method automatically figures out the :start and :rows values, based on the values of :page and :per_page. The will_paginate view helper uses the methods: #current_page, #previous_page, #next_page and #total_pages to create the pagination view widget.
|
77
71
|
|
78
72
|
=== Updating Solr
|
79
73
|
Updating is done using native Ruby structures. Hashes are used for single documents and arrays are used for a collection of documents (hashes). These structures get turned into simple XML "messages".
|
data/examples/direct.rb
CHANGED
@@ -9,7 +9,8 @@ solr = RSolr.connect(:adapter=>:direct, :home_dir=>home, :dist_dir=>dist)
|
|
9
9
|
|
10
10
|
`cd ../apache-solr/example/exampledocs && ./post.sh ./*.xml`
|
11
11
|
|
12
|
-
|
12
|
+
# the 'select' here is optional
|
13
|
+
response = solr.query 'select', :q=>'ipod', :fq=>'price:[0 TO 50]', :rows=>2, :start=>0
|
13
14
|
|
14
15
|
solr.delete_by_query('*:*')
|
15
16
|
|
data/examples/http.rb
CHANGED
@@ -5,7 +5,7 @@ solr = RSolr.connect
|
|
5
5
|
|
6
6
|
`cd ../apache-solr/example/exampledocs && ./post.sh ./*.xml`
|
7
7
|
|
8
|
-
response = solr.
|
8
|
+
response = solr.query :q=>'ipod', :fq=>'price:[0 TO 50]', :rows=>2, :start=>0
|
9
9
|
|
10
10
|
solr.delete_by_query('*:*')
|
11
11
|
|
data/lib/core_ext.rb
CHANGED
@@ -4,42 +4,47 @@
|
|
4
4
|
# The classes that include this module only need to provide a request method like:
|
5
5
|
# send_request(request_path, params, data)
|
6
6
|
# where:
|
7
|
-
# request_path is a string to a handler (/select)
|
7
|
+
# request_path is a string to a handler (/select etc.)
|
8
8
|
# params is a hash for query string params
|
9
9
|
# data is optional string of xml
|
10
10
|
module RSolr::Connection::Adapter::CommonMethods
|
11
11
|
|
12
12
|
# send a request to the "select" handler
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# string (valid solr update xml)
|
20
|
-
# object with respond_to?(:to_xml)
|
21
|
-
# params is a hash with valid solr update params
|
22
|
-
def update(data, params={})
|
23
|
-
send_request @opts[:update_path], params, data
|
13
|
+
# the first argument is the select handler path
|
14
|
+
# the last argument is a hash of params
|
15
|
+
def query(*args)
|
16
|
+
params = args.extract_options!
|
17
|
+
path = args.first || @opts[:select_path]
|
18
|
+
self.send_request "/#{path}", params
|
24
19
|
end
|
25
20
|
|
26
21
|
# sends a request to the admin luke handler to get info on the index
|
27
|
-
|
22
|
+
# the first argument is the admin/luke request handler path
|
23
|
+
# the last argument is a hash of params
|
24
|
+
def index_info(*args)
|
25
|
+
params = args.extract_options!
|
26
|
+
path = args.first || @opts[:luke_path]
|
28
27
|
params[:numTerms]||=0
|
29
|
-
send_request
|
28
|
+
self.send_request "/#{path}", params
|
30
29
|
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
#
|
41
|
-
|
42
|
-
|
31
|
+
# sends data to the update handler
|
32
|
+
# If 2 arguments are passed in:
|
33
|
+
# - the first should be the POST data string
|
34
|
+
# - the second can be an optional url params hash
|
35
|
+
# - the path is defaulted to '/update'
|
36
|
+
# If 3 arguments are passed in:
|
37
|
+
# - the first argument should be the url path ('/my-update-handler' etc.)
|
38
|
+
# - the second should be the POST data string
|
39
|
+
# - the last/third should be an optional url params hash
|
40
|
+
# data can be:
|
41
|
+
# string (valid solr update xml)
|
42
|
+
# object with respond_to?(:to_xml)
|
43
|
+
def update(*args)
|
44
|
+
params = args.extract_options!
|
45
|
+
data = args.last
|
46
|
+
path = args.size == 2 ? args.first : @opts[:update_path]
|
47
|
+
self.send_request "/#{path}", params, data
|
43
48
|
end
|
44
49
|
|
45
50
|
end
|
@@ -27,7 +27,7 @@ class RSolr::Connection::Adapter::Direct
|
|
27
27
|
# add the standard lib and dist directories to the :jar_paths
|
28
28
|
opts[:jar_paths] = [File.join(opts[:dist_dir], 'lib'), File.join(opts[:dist_dir], 'dist')]
|
29
29
|
end
|
30
|
-
@opts =
|
30
|
+
@opts = opts
|
31
31
|
end
|
32
32
|
|
33
33
|
# loads/imports the java dependencies
|
@@ -21,7 +21,7 @@ class RSolr::Connection::Adapter::HTTP
|
|
21
21
|
#
|
22
22
|
def initialize(opts={}, &block)
|
23
23
|
opts[:url]||='http://127.0.0.1:8983/solr'
|
24
|
-
@opts =
|
24
|
+
@opts = opts
|
25
25
|
end
|
26
26
|
|
27
27
|
def connection
|
@@ -5,33 +5,14 @@ class RSolr::Connection::Base
|
|
5
5
|
|
6
6
|
attr_reader :adapter, :opts
|
7
7
|
|
8
|
-
attr_accessor :param_mappers
|
9
|
-
|
10
8
|
# "adapter" is instance of:
|
11
9
|
# RSolr::Adapter::HTTP
|
12
10
|
# RSolr::Adapter::Direct (jRuby only)
|
13
11
|
def initialize(adapter, opts={})
|
14
12
|
@adapter = adapter
|
15
|
-
@param_mappers = {
|
16
|
-
:standard=>RSolr::Connection::ParamMapping::Standard,
|
17
|
-
:dismax=>RSolr::Connection::ParamMapping::Dismax
|
18
|
-
}
|
19
|
-
opts[:global_params]||={}
|
20
|
-
default_global_params = {
|
21
|
-
:wt=>:ruby,
|
22
|
-
:echoParams=>'EXPLICIT',
|
23
|
-
:debugQuery=>true
|
24
|
-
}
|
25
|
-
opts[:global_params] = default_global_params.merge(opts[:global_params])
|
26
13
|
@opts = opts
|
27
14
|
end
|
28
15
|
|
29
|
-
# sets default params etc.. - could be used as a mapping hook
|
30
|
-
# type of request should be passed in here? -> map_params(:query, {})
|
31
|
-
def map_params(params)
|
32
|
-
{}.merge(@opts[:global_params]).merge(params)
|
33
|
-
end
|
34
|
-
|
35
16
|
# send request (no param mapping) to the select handler
|
36
17
|
# params is hash with valid solr request params (:q, :fl, :qf etc..)
|
37
18
|
# if params[:wt] is not set, the default is :ruby (see opts[:global_params])
|
@@ -39,106 +20,68 @@ class RSolr::Connection::Base
|
|
39
20
|
# otherwise, an instance of RSolr::Response::Query is returned
|
40
21
|
# NOTE: to get raw ruby, use :wt=>'ruby'
|
41
22
|
# There is NO param mapping here, what you put it is what gets sent to Solr
|
42
|
-
def query(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# The #search method uses a param mapper to prepare the request for solr.
|
49
|
-
# For example, instead of doing your fq params by hand,
|
50
|
-
# you can use the simplified :filters param instead.
|
51
|
-
# The 2 built in mappers are for dismax and standard: RSolr::Connection::ParamMapping::*
|
52
|
-
# The default is :dismax
|
53
|
-
# If you create your own request handler in solrconfig.xml,
|
54
|
-
# you can use it by setting the :qt=>:my_handler
|
55
|
-
# You'll need to set the correct param mapper class (when using the search method)
|
56
|
-
# To take advantage of the param mapping
|
57
|
-
# If your request handler uses the solr dismax class, then do nothing
|
58
|
-
# if it uses the standard, you'll need to set it like:
|
59
|
-
# solr.param_mappers[:my_search_handler] = :standard
|
60
|
-
# The value can also be a custom class constant that must have a #map method
|
61
|
-
# The initialize method must accept a hash of input params
|
62
|
-
# The #map method must handle a block being passed in and return a new hash of raw solr params
|
63
|
-
def search(params,&blk)
|
64
|
-
qt = params[:qt] ? params[:qt].to_sym : :dismax
|
65
|
-
mapper_class = @param_mappers[qt]
|
66
|
-
mapper_class = RSolr::Connection::ParamMapping::Dismax if mapper_class==:dismax
|
67
|
-
mapper_class = RSolr::Connection::ParamMapping::Standard if mapper_class==:standard
|
68
|
-
mapper = mapper_class.new(params)
|
69
|
-
query(mapper.map(&blk))
|
70
|
-
end
|
71
|
-
|
72
|
-
# "facet_field" -- the name of a facet field: language_facet
|
73
|
-
# "params" -- the standard #search method params
|
74
|
-
# Returns an instance of RSolr::Response::Query::Base
|
75
|
-
def search_facet_by_name(facet_field, params, &blk)
|
76
|
-
params[:per_page] = 0
|
77
|
-
params[:rows] = 0
|
78
|
-
params[:facets] ||= {}
|
79
|
-
params[:facets][:fields] = [facet_field]
|
80
|
-
params[:facets][:mincount] ||= 1
|
81
|
-
params[:facets][:prefix] ||= nil
|
82
|
-
params[:facets][:missing] ||= false
|
83
|
-
params[:facets][:sort] ||= :count
|
84
|
-
params[:facets][:offset] ||= 0
|
85
|
-
self.search(params, &blk)
|
23
|
+
def query(*args)
|
24
|
+
params = map_params(args.extract_options!)
|
25
|
+
args << params
|
26
|
+
response = @adapter.query(*args)
|
27
|
+
params[:wt] == :ruby ? RSolr::Response::Query::Base.new(response) : response
|
86
28
|
end
|
87
29
|
|
88
30
|
# Finds a document by its id
|
89
|
-
def find_by_id(
|
90
|
-
params = map_params(
|
31
|
+
def find_by_id(*args)
|
32
|
+
params = map_params(args.extract_options!)
|
91
33
|
params[:q] = 'id:"#{id}"'
|
92
|
-
|
34
|
+
args << params
|
35
|
+
self.query(*args)
|
93
36
|
end
|
94
37
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
38
|
+
#
|
39
|
+
def update(*args)
|
40
|
+
params = map_params(args.extract_options!)
|
41
|
+
args << params
|
42
|
+
response = @adapter.update(*args)
|
43
|
+
params[:wt] == :ruby ? RSolr::Response::Update.new(response) : response
|
99
44
|
end
|
100
45
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
params
|
106
|
-
response = @adapter.update(data, params)
|
107
|
-
params[:wt]==:ruby ? RSolr::Response::Update.new(response) : response
|
46
|
+
def index_info(*args)
|
47
|
+
params = map_params(args.extract_options!)
|
48
|
+
args << params
|
49
|
+
response = @adapter.index_info(*args)
|
50
|
+
params[:wt] == :ruby ? RSolr::Response::IndexInfo.new(response) : response
|
108
51
|
end
|
109
52
|
|
110
|
-
def add(
|
111
|
-
update message.add(
|
53
|
+
def add(*args, &block)
|
54
|
+
update message.add(*args, &block)
|
112
55
|
end
|
113
56
|
|
114
57
|
# send </commit>
|
115
|
-
def commit(
|
116
|
-
update message.commit,
|
58
|
+
def commit(*args)
|
59
|
+
update message.commit, *args
|
117
60
|
end
|
118
61
|
|
119
62
|
# send </optimize>
|
120
|
-
def optimize(
|
121
|
-
update message.optimize,
|
63
|
+
def optimize(*args)
|
64
|
+
update message.optimize, *args
|
122
65
|
end
|
123
66
|
|
124
67
|
# send </rollback>
|
125
68
|
# NOTE: solr 1.4 only
|
126
|
-
def rollback(
|
127
|
-
update message.rollback,
|
69
|
+
def rollback(*args)
|
70
|
+
update message.rollback, *args
|
128
71
|
end
|
129
72
|
|
130
73
|
# Delete one or many documents by id
|
131
74
|
# solr.delete_by_id 10
|
132
75
|
# solr.delete_by_id([12, 41, 199])
|
133
|
-
def delete_by_id(
|
134
|
-
update message.delete_by_id(
|
76
|
+
def delete_by_id(*args)
|
77
|
+
update message.delete_by_id(args.shift), *args
|
135
78
|
end
|
136
79
|
|
137
80
|
# delete one or many documents by query
|
138
81
|
# solr.delete_by_query 'available:0'
|
139
82
|
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
140
|
-
def delete_by_query(
|
141
|
-
update message.delete_by_query(
|
83
|
+
def delete_by_query(*args)
|
84
|
+
update message.delete_by_query(args.shift), *args
|
142
85
|
end
|
143
86
|
|
144
87
|
protected
|
@@ -148,4 +91,11 @@ class RSolr::Connection::Base
|
|
148
91
|
RSolr::Message
|
149
92
|
end
|
150
93
|
|
94
|
+
# sets default params etc.. - could be used as a mapping hook
|
95
|
+
# type of request should be passed in here? -> map_params(:query, {})
|
96
|
+
def map_params(params)
|
97
|
+
params||={}
|
98
|
+
{:wt=>:ruby}.merge(params)
|
99
|
+
end
|
100
|
+
|
151
101
|
end
|
data/lib/rsolr/connection.rb
CHANGED
data/lib/rsolr.rb
CHANGED
@@ -7,7 +7,7 @@ proc {|base, files|
|
|
7
7
|
|
8
8
|
module RSolr
|
9
9
|
|
10
|
-
VERSION = '0.
|
10
|
+
VERSION = '0.7.0'
|
11
11
|
|
12
12
|
autoload :Message, 'rsolr/message'
|
13
13
|
autoload :Response, 'rsolr/response'
|
@@ -25,6 +25,9 @@ module RSolr
|
|
25
25
|
:http=>'HTTP',
|
26
26
|
:direct=>'Direct'
|
27
27
|
}
|
28
|
+
opts[:select_path] ||= 'select'
|
29
|
+
opts[:update_path] ||= 'update'
|
30
|
+
opts[:luke_path] ||= 'admin/luke'
|
28
31
|
adapter_class = RSolr::Connection::Adapter.const_get(types[adapter_name])
|
29
32
|
RSolr::Connection::Base.new(adapter_class.new(opts), opts)
|
30
33
|
end
|
@@ -12,18 +12,6 @@ module ConnectionTestMethods
|
|
12
12
|
# assert_equal 0, @solr.query(:q=>'*:*').docs.size
|
13
13
|
#end
|
14
14
|
|
15
|
-
def test_default_options
|
16
|
-
assert_equal '/select', @solr.adapter.default_options[:select_path]
|
17
|
-
assert_equal '/update', @solr.adapter.default_options[:update_path]
|
18
|
-
assert_equal '/admin/luke', @solr.adapter.default_options[:luke_path]
|
19
|
-
end
|
20
|
-
|
21
|
-
# setting adapter options in Solr.connect method should set them in the adapter
|
22
|
-
def test_set_adapter_options
|
23
|
-
solr = RSolr.connect(:select_path=>'/select2')
|
24
|
-
assert_equal '/select2', solr.adapter.opts[:select_path]
|
25
|
-
end
|
26
|
-
|
27
15
|
# setting connection options in Solr.connect method should set them in the connection
|
28
16
|
def test_set_connection_options
|
29
17
|
solr = RSolr.connect(:default_wt=>:json)
|
@@ -116,23 +104,4 @@ module ConnectionTestMethods
|
|
116
104
|
assert [true, false].include?(response.has_deletions?)
|
117
105
|
end
|
118
106
|
|
119
|
-
def test_search_facet_by_name
|
120
|
-
@solr.add([{:id=>1, :cat=>'eletronics'}, {:id=>2, :cat=>'software'}]) and @solr.commit
|
121
|
-
response = @solr.search_facet_by_name('cat', {:q=>'*:*'})
|
122
|
-
|
123
|
-
response.facets.each do |facet|
|
124
|
-
puts facet.field
|
125
|
-
puts facet.values.inspect
|
126
|
-
facet.values.each do |value|
|
127
|
-
puts value.value
|
128
|
-
puts value.hits
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
assert_equal 2, response.facet_by_field_name(:cat).values.size
|
133
|
-
#
|
134
|
-
response = @solr.search_facet_by_name('cat', {:q=>'*:*'})
|
135
|
-
assert_equal 0, response.docs.size
|
136
|
-
end
|
137
|
-
|
138
107
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mwmitchell-rsolr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Mitchell
|
@@ -14,6 +14,7 @@ default_executable:
|
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: builder
|
17
|
+
type: :runtime
|
17
18
|
version_requirement:
|
18
19
|
version_requirements: !ruby/object:Gem::Requirement
|
19
20
|
requirements:
|
@@ -43,9 +44,6 @@ files:
|
|
43
44
|
- lib/rsolr/connection/adapter/http.rb
|
44
45
|
- lib/rsolr/connection/adapter.rb
|
45
46
|
- lib/rsolr/connection/base.rb
|
46
|
-
- lib/rsolr/connection/param_mapping.rb
|
47
|
-
- lib/rsolr/connection/param_mapping/dismax.rb
|
48
|
-
- lib/rsolr/connection/param_mapping/standard.rb
|
49
47
|
- lib/rsolr/connection.rb
|
50
48
|
- lib/rsolr/http_client/adapter/curb.rb
|
51
49
|
- lib/rsolr/http_client/adapter/net_http.rb
|
@@ -92,7 +90,6 @@ summary: A Ruby client for Apache Solr
|
|
92
90
|
test_files:
|
93
91
|
- test/connection/direct_test.rb
|
94
92
|
- test/connection/http_test.rb
|
95
|
-
- test/connection/param_mapping_test.rb
|
96
93
|
- test/connection/test_methods.rb
|
97
94
|
- test/http_client/curb_test.rb
|
98
95
|
- test/http_client/net_http_test.rb
|
@@ -1,41 +0,0 @@
|
|
1
|
-
class RSolr::Connection::ParamMapping::Dismax < RSolr::Connection::ParamMapping::Standard
|
2
|
-
|
3
|
-
def setup_mappings
|
4
|
-
super
|
5
|
-
|
6
|
-
mapping_for :alternate_query, 'q.alt' do |val|
|
7
|
-
format_query(val).join(' ')
|
8
|
-
end
|
9
|
-
|
10
|
-
mapping_for :query_fields, :qf do |val|
|
11
|
-
create_boost_query(val)
|
12
|
-
end
|
13
|
-
|
14
|
-
mapping_for :phrase_fields, :pf do |val|
|
15
|
-
create_boost_query(val)
|
16
|
-
end
|
17
|
-
|
18
|
-
mapping_for :boost_query, :bq do |val|
|
19
|
-
format_query(val).join(' ')
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
|
26
|
-
def create_boost_query(input)
|
27
|
-
case input
|
28
|
-
when Hash
|
29
|
-
qf = []
|
30
|
-
input.each_pair do |k,v|
|
31
|
-
qf << (v.to_s.empty? ? k : "#{k}^#{v}")
|
32
|
-
end
|
33
|
-
qf.join(' ')
|
34
|
-
when Array
|
35
|
-
input.join(' ')
|
36
|
-
when String
|
37
|
-
input
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
class RSolr::Connection::ParamMapping::Standard
|
2
|
-
|
3
|
-
include RSolr::Connection::ParamMapping::MappingMethods
|
4
|
-
|
5
|
-
attr_reader :input, :output
|
6
|
-
|
7
|
-
def initialize(input)
|
8
|
-
@output = {}
|
9
|
-
@input = input
|
10
|
-
setup_mappings
|
11
|
-
end
|
12
|
-
|
13
|
-
def setup_mappings
|
14
|
-
|
15
|
-
mapping_for :per_page, :rows do |val|
|
16
|
-
val = val.to_s.to_i
|
17
|
-
val < 0 ? 0 : val
|
18
|
-
end
|
19
|
-
|
20
|
-
mapping_for :page, :start do |val|
|
21
|
-
val = val.to_s.to_i
|
22
|
-
page = val > 0 ? val : 1
|
23
|
-
((page - 1) * (@output[:rows] || 0))
|
24
|
-
end
|
25
|
-
|
26
|
-
mapping_for :queries, :q do |val|
|
27
|
-
format_query(val)
|
28
|
-
end
|
29
|
-
|
30
|
-
mapping_for :phrase_queries, :q do |val|
|
31
|
-
values = [@output[:q], format_query(val, true)]
|
32
|
-
# remove blank items
|
33
|
-
values.reject!{|v|v.to_s.empty?}
|
34
|
-
# join all items on a space
|
35
|
-
values.join(' ')
|
36
|
-
end
|
37
|
-
|
38
|
-
mapping_for :filters, :fq do |val|
|
39
|
-
format_query(val)
|
40
|
-
end
|
41
|
-
|
42
|
-
# this must come after the :filter/:fq mapper
|
43
|
-
mapping_for :phrase_filters, :fq do |val|
|
44
|
-
# use the previously set fq queries and generate the new phrased based ones
|
45
|
-
values = [@output[:fq], format_query(val, true)]
|
46
|
-
# flatten (need to do this because the previous fq could have been an array)
|
47
|
-
values = values.flatten
|
48
|
-
# remove blank items
|
49
|
-
values.reject!{|v|v.to_s.empty?} # don't join -- instead create multiple fq params
|
50
|
-
# don't join... fq needs to be an array so multiple fq params are sent to solr
|
51
|
-
values
|
52
|
-
end
|
53
|
-
|
54
|
-
mapping_for :facets do |input|
|
55
|
-
next if input.to_s.empty?
|
56
|
-
@output[:facet] = true
|
57
|
-
@output['facet.field'] = []
|
58
|
-
if input[:queries]
|
59
|
-
# convert to an array if needed
|
60
|
-
input[:queries] = [input[:queries]] unless input[:queries].is_a?(Array)
|
61
|
-
@output[:facet.query] = input[:queries].map{|q|format_query(q)}
|
62
|
-
end
|
63
|
-
common_sub_fields = [:sort, :limit, :missing, :mincount, :prefix, :offset, :method, 'enum.cache.minDf']
|
64
|
-
(common_sub_fields).each do |subfield|
|
65
|
-
next unless input[subfield]
|
66
|
-
@output["facet.#{subfield}"] = input[subfield]
|
67
|
-
end
|
68
|
-
if input[:fields]
|
69
|
-
input[:fields].each do |f|
|
70
|
-
if f.kind_of? Hash
|
71
|
-
key = f.keys[0]
|
72
|
-
value = f[key]
|
73
|
-
@output[:facet.field] << key
|
74
|
-
common_sub_fields.each do |subfield|
|
75
|
-
next unless value[subfield]
|
76
|
-
@output["f.#{key}.facet.#{subfield}"] = input[subfield]
|
77
|
-
end
|
78
|
-
else
|
79
|
-
@output['facet.field'] << f
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# takes an input and returns a formatted value
|
87
|
-
def format_query(input, quote=false)
|
88
|
-
case input
|
89
|
-
when Array
|
90
|
-
format_array_query(input, quote)
|
91
|
-
when Hash
|
92
|
-
format_hash_query(input, quote)
|
93
|
-
else
|
94
|
-
prep_value(input, quote)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def format_array_query(input, quote)
|
99
|
-
input.collect do |v|
|
100
|
-
v.is_a?(Hash) ? format_hash_query(v, quote) : prep_value(v, quote)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# groups values to a single field: title:(value1 value2) instead of title:value1 title:value2
|
105
|
-
# a value can be a range or a string
|
106
|
-
def format_hash_query(input, quote=false)
|
107
|
-
q = []
|
108
|
-
input.each_pair do |field,value|
|
109
|
-
next if value.to_s.empty? # skip blank values!
|
110
|
-
# create the field plus the delimiter if the field is not blank
|
111
|
-
value = [value] unless value.is_a?(Array)
|
112
|
-
fielded_queries = value.collect do |vv|
|
113
|
-
vv.is_a?(Range) ? "[#{vv.min} TO #{vv.max}]" : prep_value(vv, quote)
|
114
|
-
end
|
115
|
-
field = field.to_s.empty? ? '' : "#{field}:"
|
116
|
-
fielded_queries.each do |fq|
|
117
|
-
q << "#{field}(#{fq})"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
q
|
121
|
-
end
|
122
|
-
|
123
|
-
def prep_value(val, quote=false)
|
124
|
-
quote ? %(\"#{val}\") : val.to_s
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module RSolr::Connection::ParamMapping
|
2
|
-
|
3
|
-
autoload :Standard, 'rsolr/connection/param_mapping/standard'
|
4
|
-
autoload :Dismax, 'rsolr/connection/param_mapping/dismax'
|
5
|
-
|
6
|
-
module MappingMethods
|
7
|
-
|
8
|
-
def mappers
|
9
|
-
@mappers ||= []
|
10
|
-
end
|
11
|
-
|
12
|
-
def mapping_for(user_param_name, solr_param_name=nil, &block)
|
13
|
-
return unless @input[user_param_name]
|
14
|
-
if (m = self.mappers.detect{|m|m[:input_name] == user_param_name})
|
15
|
-
self.mappers.delete m
|
16
|
-
end
|
17
|
-
self.mappers << {:input_name=>user_param_name, :output_name=>solr_param_name, :block=>block}
|
18
|
-
end
|
19
|
-
|
20
|
-
def map(&blk)
|
21
|
-
input = @input.dup
|
22
|
-
mappers.each do |m|
|
23
|
-
input_value = input[m[:input_name]]
|
24
|
-
input.delete m[:input_name]
|
25
|
-
if m[:block]
|
26
|
-
value = m[:block].call(input_value)
|
27
|
-
else
|
28
|
-
value = input_value
|
29
|
-
end
|
30
|
-
if m[:output_name]
|
31
|
-
@output[m[:output_name]] = value
|
32
|
-
end
|
33
|
-
end
|
34
|
-
@output.merge(input)
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', 'test_helpers')
|
2
|
-
|
3
|
-
class ParamMappingTest < RSolrBaseTest
|
4
|
-
|
5
|
-
include RSolr::Connection::ParamMapping
|
6
|
-
|
7
|
-
def test_standard_simple
|
8
|
-
input = {
|
9
|
-
:queries=>'a query',
|
10
|
-
:filters=>'a filter',
|
11
|
-
:page=>1,
|
12
|
-
:per_page=>10,
|
13
|
-
:phrase_queries=>'a phrase query',
|
14
|
-
:phrase_filters=>'a phrase filter',
|
15
|
-
:facets=>{
|
16
|
-
:fields=>[:one,:two]
|
17
|
-
}
|
18
|
-
}
|
19
|
-
mapper = Standard.new(input)
|
20
|
-
output = mapper.map
|
21
|
-
|
22
|
-
assert_equal "a query \"a phrase query\"", output[:q]
|
23
|
-
assert_equal ["a filter", "\"a phrase filter\""], output[:fq]
|
24
|
-
assert_equal 0, output[:start]
|
25
|
-
assert_equal 10, output[:rows]
|
26
|
-
# facet.field can be specified multiple times, so we need an array
|
27
|
-
# the url builder automatically adds multiple params for arrays
|
28
|
-
assert_equal [:one, :two], output['facet.field']
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_standard_complex
|
32
|
-
input = {
|
33
|
-
:queries=>['a query', {:field=>'value'}, 'blah'],
|
34
|
-
:filters=>['a filter', {:filter=>'field'}, 'blah'],
|
35
|
-
:phrase_queries=>['a phrase', {:phrase_field=>'phrase value'}],
|
36
|
-
:phrase_filters=>{:can_also_be_a=>'hash'}
|
37
|
-
}
|
38
|
-
mapper = Standard.new(input)
|
39
|
-
output = mapper.map
|
40
|
-
|
41
|
-
assert_equal "a query field:(value) blah \"a phrase\" phrase_field:(\"phrase value\")", output[:q]
|
42
|
-
assert_equal ["a filter", "filter:(field)", "blah", "can_also_be_a:(\"hash\")"], output[:fq]
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_dismax
|
46
|
-
input = {
|
47
|
-
:alternate_query=>{:can_be_a_string_hash_or_array=>'OK'},
|
48
|
-
:query_fields=>{:a_field_to_boost=>20, :another_field_to_boost=>200},
|
49
|
-
:phrase_fields=>{:phrase_field=>20},
|
50
|
-
:boost_query=>[{:field_to_use_for_boost_query=>'a'}, 'test']
|
51
|
-
}
|
52
|
-
mapper = Dismax.new(input)
|
53
|
-
output = mapper.map
|
54
|
-
assert_equal 'can_be_a_string_hash_or_array:(OK)', output['q.alt']
|
55
|
-
assert output[:qf]=~/another_field_to_boost\^200/
|
56
|
-
assert output[:qf]=~/a_field_to_boost\^20/
|
57
|
-
assert_equal 'phrase_field^20', output[:pf]
|
58
|
-
assert_equal 'field_to_use_for_boost_query:(a) test', output[:bq]
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
data/test/ruby-lang.org.rss.xml
DELETED
@@ -1,391 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
3
|
-
<channel>
|
4
|
-
<title>Ruby News</title>
|
5
|
-
<link>http://www.ruby-lang.org/en/feeds/news.rss/</link>
|
6
|
-
<language>en-us</language>
|
7
|
-
<ttl>40</ttl>
|
8
|
-
<description>The latest news from Ruby-Lang.org.</description>
|
9
|
-
|
10
|
-
|
11
|
-
<item>
|
12
|
-
<title>Scotland on Rails 2009</title>
|
13
|
-
<description><p><a href="http://scotlandonrails.com">Scotland on Rails</a> is pleased to announce that Conference2009 will be held March 26-28 in Edinburgh, Scotland.</p>
|
14
|
-
|
15
|
-
|
16
|
-
<p>We are now accepting submissions. The closing date for submissions is December 1st 2008, so there&#8217;s still time! Please mail your plaintext proposals for 45 minute sessions to <a href="mailto:submissions@scotlandonrails.com">submissions@scotlandonrails.com</a>.</p>
|
17
|
-
|
18
|
-
|
19
|
-
<p>Alternatively, if you are interested in sponsoring the conference, please mail <a href="mailto:sponsorship@scotlandonrails.com">sponsorship@scotlandonrails.com</a> for a prospectus.</p>
|
20
|
-
|
21
|
-
|
22
|
-
<p>Lastly, if you wish to be notified when we open for registration, you can sign up on the site.</p>
|
23
|
-
|
24
|
-
|
25
|
-
<p>Come and enjoy all that Edinburgh has to offer (whisky! castle! volcano! ruby! whisky!) in March. We hope to see you there.</p> </description>
|
26
|
-
<pubDate>Mon, 10 Nov 2008 14:55:53 GMT</pubDate>
|
27
|
-
<guid>http://www.ruby-lang.org/en/news/2008/11/10/scotland-on-rails-2009/</guid>
|
28
|
-
<link>http://www.ruby-lang.org/en/news/2008/11/10/scotland-on-rails-2009/</link>
|
29
|
-
</item>
|
30
|
-
|
31
|
-
<item>
|
32
|
-
<title>MountainWest RubyConf 2009 dates and CFP</title>
|
33
|
-
<description><p><a href="http://mtnwestrubyconf.org">MountainWest RubyConf 2009</a> will be held March 13-14, 2009, in Salt Lake City, Utah, <span class="caps">USA</span>.</p>
|
34
|
-
|
35
|
-
|
36
|
-
<p>Proposals to speak at this regional conference are now being accepted. Please send your proposal to proposals@mtnwestrubyconf.org.</p>
|
37
|
-
|
38
|
-
|
39
|
-
<p>The submission deadline is midnight (MST) on December 31st, 2008.</p>
|
40
|
-
|
41
|
-
|
42
|
-
<p>There are sponsorship opportunities available as well. Please contact sponsorship@mtnwestruby.org if you are interested.</p>
|
43
|
-
|
44
|
-
|
45
|
-
<p>Please see <a href="http://mtnwestrubyconf.org">mtnwestrubyconf.org/</a> for more details as they become available.</p> </description>
|
46
|
-
<pubDate>Sat, 08 Nov 2008 15:03:32 GMT</pubDate>
|
47
|
-
<guid>http://www.ruby-lang.org/en/news/2008/11/08/mountainwest-rubyconf-2009-dates-and-cfp/</guid>
|
48
|
-
<link>http://www.ruby-lang.org/en/news/2008/11/08/mountainwest-rubyconf-2009-dates-and-cfp/</link>
|
49
|
-
</item>
|
50
|
-
|
51
|
-
<item>
|
52
|
-
<title> Ruby 1.9.1-preview 1 released</title>
|
53
|
-
<description><p>Yugui (Yuki Sonoda) announced the release of Ruby 1.9.1-preview 1:</p>
|
54
|
-
|
55
|
-
|
56
|
-
<blockquote>
|
57
|
-
This is a preview release of Ruby 1.9.1, which will be the first stable version of the Ruby 1.9 series. Try it out now and get an early taste of a modern, faster, multilingualized, and much improved Ruby with clearer syntax.<br><br>
|
58
|
-
|
59
|
-
<p>If you encounter any bugs or problems, please let us know via the official issue tracking system:</p>
|
60
|
-
|
61
|
-
|
62
|
-
<p><a href="http://redmine.ruby-lang.org">http://redmine.ruby-lang.org</a></p>
|
63
|
-
|
64
|
-
|
65
|
-
</blockquote>
|
66
|
-
|
67
|
-
<p>You can download the release from;</p>
|
68
|
-
|
69
|
-
|
70
|
-
<ul>
|
71
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.bz2">ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.bz2</a>
|
72
|
-
|
73
|
-
<p><span class="caps">SIZE</span>: 6169022 bytes
|
74
|
-
<span class="caps">MD5</span>: 0d51dc949bb6b438ad4ebfabbb5f6754
|
75
|
-
<span class="caps">SHA256</span>: dc39000537d7c7528ef26af8e1c3a6215b30b6c579c615eaec7013513410456a</p></li>
|
76
|
-
</ul>
|
77
|
-
|
78
|
-
|
79
|
-
<ul>
|
80
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz">ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz</a>
|
81
|
-
|
82
|
-
<p><span class="caps">SIZE</span>: 7409682 bytes
|
83
|
-
<span class="caps">MD5</span>: 738f701532452fd5d36f5c155f3ba692
|
84
|
-
<span class="caps">SHA256</span>: 99443bdae9f94ba7b08de187881f8cbee172379edf9c5fa85fc04c869150ff6d</p></li>
|
85
|
-
</ul>
|
86
|
-
|
87
|
-
|
88
|
-
<ul>
|
89
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.zip">ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.zip</a>
|
90
|
-
|
91
|
-
<p><span class="caps">SIZE</span>: 8569116 bytes
|
92
|
-
<span class="caps">MD5</span>: 5f68246246c4cd29d8a3b6b34b29b6ac
|
93
|
-
<span class="caps">SHA256</span>: a6c3a7bf7ea83b595024764926353e08596a78e40c57ac58c568662e5e88df95</p></li>
|
94
|
-
</ul> </description>
|
95
|
-
<pubDate>Tue, 28 Oct 2008 19:45:27 GMT</pubDate>
|
96
|
-
<guid>http://www.ruby-lang.org/en/news/2008/10/28/ruby-1-9-1-preview-1-released/</guid>
|
97
|
-
<link>http://www.ruby-lang.org/en/news/2008/10/28/ruby-1-9-1-preview-1-released/</link>
|
98
|
-
</item>
|
99
|
-
|
100
|
-
<item>
|
101
|
-
<title>RubyConf 2008 is Sold-out</title>
|
102
|
-
<description><p><a href="http://rubyconf.org/">RubyConf 2008</a> is sold out</p>
|
103
|
-
|
104
|
-
|
105
|
-
<p>However, there is a <a href="http://www.regonline.com/builder/site/Default.aspx?eventid=636797">waiting list</a> you can join in case of cancellations.</p> </description>
|
106
|
-
<pubDate>Thu, 02 Oct 2008 23:21:06 GMT</pubDate>
|
107
|
-
<guid>http://www.ruby-lang.org/en/news/2008/10/02/rubyconf-2008-is-sold-out/</guid>
|
108
|
-
<link>http://www.ruby-lang.org/en/news/2008/10/02/rubyconf-2008-is-sold-out/</link>
|
109
|
-
</item>
|
110
|
-
|
111
|
-
<item>
|
112
|
-
<title>Voices That Matter 2008</title>
|
113
|
-
<description><p>Pearson Education is running a <a href="http://www.voicesthatmatter.com/ruby2008/">Voices That Matter</a> Ruby conference this fall in Boston. The conference, from the same people who Addison-Wesley's Professional Ruby Series, will give you a chance to meet and learn from those very same authors. Don't miss a chance to interact with so many Ruby professionals.</p> </description>
|
114
|
-
<pubDate>Tue, 09 Sep 2008 02:49:37 GMT</pubDate>
|
115
|
-
<guid>http://www.ruby-lang.org/en/news/2008/09/09/voices-that-matter-2008/</guid>
|
116
|
-
<link>http://www.ruby-lang.org/en/news/2008/09/09/voices-that-matter-2008/</link>
|
117
|
-
</item>
|
118
|
-
|
119
|
-
<item>
|
120
|
-
<title>DoS vulnerability in REXML</title>
|
121
|
-
<description><p>There is a DoS vulnerability in the REXML library included in the Ruby
|
122
|
-
Standard Library. A so-called "XML entity explosion" attack technique
|
123
|
-
can be used for remotely bringing down (disabling) any application
|
124
|
-
which parses user-provided XML using REXML.</p><p>Most Rails applications will be vulnerable because Rails parses
|
125
|
-
user-provided XML using REXML by default. </p> <h2><a name="label-0" id="label-0">Impact</a></h2><!-- RDLabel: "Impact" --><p>An attacker can cause a denial of service by causing REXML to parse a
|
126
|
-
document containing recursively nested entities such as:</p><pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
|
127
|
-
&lt;!DOCTYPE member [
|
128
|
-
&lt;!ENTITY a "&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;"&gt;
|
129
|
-
&lt;!ENTITY b "&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;"&gt;
|
130
|
-
&lt;!ENTITY c "&amp;d;&amp;d;&amp;d;&amp;d;&amp;d;&amp;d;&amp;d;&amp;d;&amp;d;&amp;d;"&gt;
|
131
|
-
&lt;!ENTITY d "&amp;e;&amp;e;&amp;e;&amp;e;&amp;e;&amp;e;&amp;e;&amp;e;&amp;e;&amp;e;"&gt;
|
132
|
-
&lt;!ENTITY e "&amp;f;&amp;f;&amp;f;&amp;f;&amp;f;&amp;f;&amp;f;&amp;f;&amp;f;&amp;f;"&gt;
|
133
|
-
&lt;!ENTITY f "&amp;g;&amp;g;&amp;g;&amp;g;&amp;g;&amp;g;&amp;g;&amp;g;&amp;g;&amp;g;"&gt;
|
134
|
-
&lt;!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"&gt;
|
135
|
-
]&gt;
|
136
|
-
&lt;member&gt;
|
137
|
-
&amp;a;
|
138
|
-
&lt;/member&gt;</pre><h2><a name="label-1" id="label-1">Vulnerable versions</a></h2><!-- RDLabel: "Vulnerable versions" --><h3><a name="label-2" id="label-2">1.8 series</a></h3><!-- RDLabel: "1.8 series" --><ul>
|
139
|
-
<li>1.8.6-p287 and all prior versions</li>
|
140
|
-
<li>1.8.7-p72 and all prior versions</li>
|
141
|
-
</ul><h3><a name="label-3" id="label-3">1.9 series</a></h3><!-- RDLabel: "1.9 series" --><ul>
|
142
|
-
<li>all versions</li>
|
143
|
-
</ul><h2><a name="label-4" id="label-4">Solution</a></h2><!-- RDLabel: "Solution" --><p>Please download the following monkey patch to fix this problem.</p><ul>
|
144
|
-
<li><a href="http://www.ruby-lang.org/security/20080823rexml/rexml-expansion-fix2.rb">&lt;URL:http://www.ruby-lang.org/security/20080823rexml/rexml-expansion-fix2.rb&gt;</a></li>
|
145
|
-
</ul><p>Then fix your application to load rexml-expansion-fix2.rb before using
|
146
|
-
REXML.</p><pre>require "rexml-expansion-fix2"
|
147
|
-
...
|
148
|
-
doc = REXML::Document.new(str)
|
149
|
-
...</pre><p>If you have a Rails application, copy rexml-expansion-fix2.rb into a
|
150
|
-
directory on the load path (such as RAILS_ROOT/lib/), and put the
|
151
|
-
following line into config/environment.rb.</p><pre>require "rexml-expansion-fix2"</pre><p>If your application is Rails 2.1 or later, you can simply copy
|
152
|
-
rexml-expansion-fix2.rb to RAILS_ROOT/config/initializers and it will
|
153
|
-
be required automatically.</p><p>By default, XML entity expansion limit is 10000. You can change it by
|
154
|
-
changing REXML::Document.entity_expansion_limit. e.g.</p><pre>REXML::Document.entity_expansion_limit = 1000</pre><p>This fix will be made available as a gem and used by future versions of
|
155
|
-
rails, but users should take corrective action immediately.</p><h2><a name="label-5" id="label-5">Credit</a></h2><!-- RDLabel: "Credit" --><p>Credit to Luka Treiber and Mitja Kolsek of ACROS Security for
|
156
|
-
disclosing the problem to Ruby and Rails Security Teams.</p><p>Credit to Michael Koziarski of Rails Core Team for creating the monkey
|
157
|
-
patch to fix the vulnerability.</p><h2><a name="label-6" id="label-6">Changes</a></h2><!-- RDLabel: "Changes" --><ul>
|
158
|
-
<li>2008-08-29 18:46 +09:00 fixed the summary not to mislead that this vulnerability is Rails specific.</li>
|
159
|
-
<li>2008-11-09 12:40 +09:00 fixed <a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=502535">a bug of the monkey patch</a>.</li>
|
160
|
-
</ul></description>
|
161
|
-
<pubDate>Sat, 23 Aug 2008 07:56:11 GMT</pubDate>
|
162
|
-
<guid>http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/</guid>
|
163
|
-
<link>http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/</link>
|
164
|
-
</item>
|
165
|
-
|
166
|
-
<item>
|
167
|
-
<title>Ruby 1.8.7-p72 and 1.8.6-p287 released</title>
|
168
|
-
<description><p>Ruby 1.8.7-p72 and 1.8.6-p287 have been released.
|
169
|
-
The last releases were incomplete, and the new releases include fixes of <a href="http://www.ruby-lang.org/en/news/2008/08/08/multiple-vulnerabilities-in-ruby/#label-3">the previously announced vulnerability of dl</a>.</p><p>The released source archives are available at:</p><ul>
|
170
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.gz&gt;</a></li>
|
171
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.bz2">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.bz2&gt;</a></li>
|
172
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.zip">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.zip&gt;</a></li>
|
173
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz&gt;</a></li>
|
174
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.bz2">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.bz2&gt;</a></li>
|
175
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.zip">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.zip&gt;</a></li>
|
176
|
-
</ul> <p>Checksums:</p><pre>MD5(ruby-1.8.6-p287.tar.gz)= f6cd51001534ced5375339707a757556
|
177
|
-
SHA256(ruby-1.8.6-p287.tar.gz)= 6463d1932c34ff72b79174ac7d2c28940d29d147928250928a00a0dbee43db57
|
178
|
-
SIZE(ruby-1.8.6-p287.tar.gz)= 4590393
|
179
|
-
|
180
|
-
MD5(ruby-1.8.6-p287.tar.bz2)= 80b5f3db12531d36e6c81fac6d05dda9
|
181
|
-
SHA256(ruby-1.8.6-p287.tar.bz2)= ac15a1cb78c50ec9cc7e831616a143586bdd566bc865c6b769a0c47b3b3936ce
|
182
|
-
SIZE(ruby-1.8.6-p287.tar.bz2)= 3956902
|
183
|
-
|
184
|
-
MD5(ruby-1.8.6-p287.zip)= e555d51f5b387fdd52ae53d9bafa13f5
|
185
|
-
SHA256(ruby-1.8.6-p287.zip)= 844c66c015565839531a34b83e0526cd4fa2a71cc0f5cc8ddb0d4c158403543a
|
186
|
-
SIZE(ruby-1.8.6-p287.zip)= 5606238
|
187
|
-
|
188
|
-
MD5(ruby-1.8.7-p72.tar.gz)= 5e5b7189674b3a7f69401284f6a7a36d
|
189
|
-
SHA256(ruby-1.8.7-p72.tar.gz)= e15ca005076f5d6f91fc856fdfbd071698a4cadac3c6e25855899dba1f6fc5ef
|
190
|
-
SIZE(ruby-1.8.7-p72.tar.gz)= 4805594
|
191
|
-
|
192
|
-
MD5(ruby-1.8.7-p72.tar.bz2)= 0b215c46b89b28d7ab8d56d96e72d5b9
|
193
|
-
SHA256(ruby-1.8.7-p72.tar.bz2)= a8f8a28e286dd76747d8e97ea5cfe7a315eb896906ab8c8606d687d9f6f6146e
|
194
|
-
SIZE(ruby-1.8.7-p72.tar.bz2)= 4127450
|
195
|
-
|
196
|
-
MD5(ruby-1.8.7-p72.zip)= b44fe5a12d4bf138ba0d3660e13a8216
|
197
|
-
SHA256(ruby-1.8.7-p72.zip)= 77e67be4aa8c3e041e1d20d24e5fcf2e33ad9bccb3da3332b6c0a5b648334903
|
198
|
-
SIZE(ruby-1.8.7-p72.zip)= 5855902</pre><p>For a full list of all changes, see the bundled files named ChangeLog, which are also available at the following locations:</p><ul>
|
199
|
-
<li><a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_287/ChangeLog">&lt;URL:http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_287/ChangeLog&gt;</a></li>
|
200
|
-
<li><a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7_72/ChangeLog">&lt;URL:http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7_72/ChangeLog&gt;</a></li>
|
201
|
-
</ul></description>
|
202
|
-
<pubDate>Mon, 11 Aug 2008 02:01:00 GMT</pubDate>
|
203
|
-
<guid>http://www.ruby-lang.org/en/news/2008/08/11/ruby-1-8-7-p72-and-1-8-6-p287-released/</guid>
|
204
|
-
<link>http://www.ruby-lang.org/en/news/2008/08/11/ruby-1-8-7-p72-and-1-8-6-p287-released/</link>
|
205
|
-
</item>
|
206
|
-
|
207
|
-
<item>
|
208
|
-
<title>Multiple vulnerabilities in Ruby</title>
|
209
|
-
<description><p>Multiple vulnerabilities have been discovered in Ruby. It's
|
210
|
-
recommended that you upgrade to the latest versions.</p> <h2><a name="label-0" id="label-0">Details</a></h2><!-- RDLabel: "Details" --><p>The following vulnerabilities have been discovered.</p><h3><a name="label-1" id="label-1">Several vulnerabilities in safe level</a></h3><!-- RDLabel: "Several vulnerabilities in safe level" --><p>Several vulnerabilities in safe level have been discovered.</p><ul>
|
211
|
-
<li><p>untrace_var is permitted at safe level 4.</p>
|
212
|
-
<pre>trace_var(:$VAR) {|val| puts "$VAR = #{val}" }
|
213
|
-
|
214
|
-
Thread.new do
|
215
|
-
$SAFE = 4
|
216
|
-
eval %q{
|
217
|
-
proc = untrace_var :$VAR
|
218
|
-
proc.first.call("aaa")
|
219
|
-
}
|
220
|
-
end.join</pre></li>
|
221
|
-
<li><p>$PROGRAM_NAME may be modified at safe level 4.</p>
|
222
|
-
<pre>Thread.new do
|
223
|
-
$SAFE = 4
|
224
|
-
eval %q{$PROGRAM_NAME.replace "Hello, World!"}
|
225
|
-
end.join
|
226
|
-
|
227
|
-
$PROGRAM_NAME #=&gt; "Hello, World!"</pre></li>
|
228
|
-
<li><p>Insecure methods may be called at safe level 1-3.</p>
|
229
|
-
<pre>class Hello
|
230
|
-
def world
|
231
|
-
Thread.new do
|
232
|
-
$SAFE = 4
|
233
|
-
msg = "Hello, World!"
|
234
|
-
def msg.size
|
235
|
-
self.replace self*10 # replace string
|
236
|
-
1 # return wrong size
|
237
|
-
end
|
238
|
-
msg
|
239
|
-
end.value
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
$SAFE = 1 # or 2, or 3
|
244
|
-
s = Hello.new.world
|
245
|
-
if s.kind_of?(String)
|
246
|
-
puts s if s.size &lt; 20 # print string which size is less than 20
|
247
|
-
end</pre></li>
|
248
|
-
<li><p>Syslog operations are permitted at safe level 4.</p>
|
249
|
-
<pre>require "syslog"
|
250
|
-
|
251
|
-
Syslog.open
|
252
|
-
|
253
|
-
Thread.new do
|
254
|
-
$SAFE = 4
|
255
|
-
eval %q{
|
256
|
-
Syslog.log(Syslog::LOG_WARNING, "Hello, World!")
|
257
|
-
Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_EMERG)
|
258
|
-
Syslog.info("masked")
|
259
|
-
Syslog.close
|
260
|
-
}
|
261
|
-
end.join</pre></li>
|
262
|
-
</ul><p>These vulnerabilities were reported by Keita Yamaguchi.</p><h3><a name="label-2" id="label-2">DoS vulnerability in WEBrick</a></h3><!-- RDLabel: "DoS vulnerability in WEBrick" --><p>WEBrick::HTTP::DefaultFileHandler is faulty of exponential time taking
|
263
|
-
requests due to a backtracking regular expression in
|
264
|
-
WEBrick::HTTPUtils.split_header_value.</p><p>Exploitable server:</p><pre>require 'webrick'
|
265
|
-
WEBrick::HTTPServer.new(:Port =&gt; 2000, :DocumentRoot =&gt; "/etc").start</pre><p>Attack:</p><pre>require 'net/http'
|
266
|
-
res = Net::HTTP.start("localhost", 2000) { |http|
|
267
|
-
req = Net::HTTP::Get.new("/passwd")
|
268
|
-
req['If-None-Match'] = %q{meh=""} + %q{foo="bar" } * 100
|
269
|
-
http.request(req)
|
270
|
-
}
|
271
|
-
p res</pre><p>The request likely won't finish in this universe.</p><p>This vulnerability was reported by Christian Neukirchen.</p><h3><a name="label-3" id="label-3">Lack of taintness check in dl</a></h3><!-- RDLabel: "Lack of taintness check in dl" --><p>dl doesn't check taintness, so it could allow attackers to call
|
272
|
-
dangerous functions.</p><pre>require 'dl'
|
273
|
-
$SAFE = 1
|
274
|
-
h = DL.dlopen(nil)
|
275
|
-
sys = h.sym('system', 'IP')
|
276
|
-
uname = 'uname -rs'.taint
|
277
|
-
sys[uname]</pre><p>This vulnerability was reported by sheepman.</p><h3><a name="label-4" id="label-4">DNS spoofing vulnerability in resolv.rb</a></h3><!-- RDLabel: "DNS spoofing vulnerability in resolv.rb" --><p>resolv.rb allow remote attackers to spoof DNS answers. This risk can be
|
278
|
-
reduced by randomness of DNS transaction IDs and source ports, so resolv.rb
|
279
|
-
is fixed to randomize them.</p><ul>
|
280
|
-
<li>see also: <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-1447">CVE-2008-1447</a></li>
|
281
|
-
</ul><p>This vulnerability was reported by Tanaka Akira.</p><h2><a name="label-5" id="label-5">Vulnerable versions</a></h2><!-- RDLabel: "Vulnerable versions" --><dl>
|
282
|
-
<dt><a name="label-6" id="label-6">1.8 series</a></dt><!-- RDLabel: "1.8 series" -->
|
283
|
-
<dd>
|
284
|
-
<ul>
|
285
|
-
<li>1.8.5 and all prior versions</li>
|
286
|
-
<li>1.8.6-p286 and all prior versions</li>
|
287
|
-
<li>1.8.7-p71 and all prior versions</li>
|
288
|
-
</ul>
|
289
|
-
</dd>
|
290
|
-
<dt><a name="label-7" id="label-7">1.9 series</a></dt><!-- RDLabel: "1.9 series" -->
|
291
|
-
<dd>
|
292
|
-
<ul>
|
293
|
-
<li>r18423 and all prior revisions</li>
|
294
|
-
</ul>
|
295
|
-
</dd>
|
296
|
-
</dl><h2><a name="label-8" id="label-8">Solution</a></h2><!-- RDLabel: "Solution" --><dl>
|
297
|
-
<dt><a name="label-9" id="label-9">1.8 series</a></dt><!-- RDLabel: "1.8 series" -->
|
298
|
-
<dd>
|
299
|
-
Please upgrade to 1.8.6-p287, or 1.8.7-p72.
|
300
|
-
<ul>
|
301
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.gz&gt;</a></li>
|
302
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz&gt;</a></li>
|
303
|
-
</ul>
|
304
|
-
</dd>
|
305
|
-
<dt><a name="label-10" id="label-10">1.9 series</a></dt><!-- RDLabel: "1.9 series" -->
|
306
|
-
<dd>
|
307
|
-
<p>Please check out the latest version using Subversion.</p>
|
308
|
-
<pre>$ svn co http://svn.ruby-lang.org/repos/ruby/trunk ruby</pre>
|
309
|
-
</dd>
|
310
|
-
</dl><p>Please note that a package that corrects this weakness may already be
|
311
|
-
available through your package management software.</p><h2><a name="label-11" id="label-11">Credit</a></h2><!-- RDLabel: "Credit" --><p>Credit to Keita Yamaguchi, Christian Neukirchen, sheepman, and Tanaka
|
312
|
-
Akira for disclosing these problems to Ruby Security Team.</p><h2><a name="label-12" id="label-12">Changes</a></h2><!-- RDLabel: "Changes" --><ul>
|
313
|
-
<li>2008-08-08 12:21 +09:00 fixed the revision number of ruby 1.9.</li>
|
314
|
-
<li>2008-08-11 11:23 +09:00 fixed the patchlevel of ruby 1.8. see <a href="http://www.ruby-lang.org/en/news/2008/08/11/ruby-1-8-7-p72-and-1-8-6-p287-released/">the release announcement of Ruby 1.8.7-p72 and 1.8.6-p287</a></li>
|
315
|
-
</ul></description>
|
316
|
-
<pubDate>Fri, 08 Aug 2008 02:59:49 GMT</pubDate>
|
317
|
-
<guid>http://www.ruby-lang.org/en/news/2008/08/08/multiple-vulnerabilities-in-ruby/</guid>
|
318
|
-
<link>http://www.ruby-lang.org/en/news/2008/08/08/multiple-vulnerabilities-in-ruby/</link>
|
319
|
-
</item>
|
320
|
-
|
321
|
-
<item>
|
322
|
-
<title>RubyConf 2008 Proposals Now Being Accepted</title>
|
323
|
-
<description><p><a href="http://www.rubyconf.org">RubyConf 2008</a> will be held in Orlando, Florida, <span class="caps">USA</span>, from November 6 to November 8.</p>
|
324
|
-
|
325
|
-
|
326
|
-
<p><a href="http://www.rubyconf.org/proposals/new">Proposals for presentations</a> are now begin accepted. All proposals must be received by August 21.</p> </description>
|
327
|
-
<pubDate>Mon, 04 Aug 2008 20:26:29 GMT</pubDate>
|
328
|
-
<guid>http://www.ruby-lang.org/en/news/2008/08/04/rubyconf-2008-proposals-now-being-accepted/</guid>
|
329
|
-
<link>http://www.ruby-lang.org/en/news/2008/08/04/rubyconf-2008-proposals-now-being-accepted/</link>
|
330
|
-
</item>
|
331
|
-
|
332
|
-
<item>
|
333
|
-
<title>Arbitrary code execution vulnerabilities</title>
|
334
|
-
<description><p>Multiple vulnerabilities in Ruby may lead to a denial of service (DoS)
|
335
|
-
condition or allow execution of arbitrary code.</p> <h2><a name="label-0" id="label-0">Impact</a></h2><!-- RDLabel: "Impact" --><p>With the following vulnerabilities, an attacker can lead to denial of
|
336
|
-
service condition or execute arbitrary code.</p><ul>
|
337
|
-
<li><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-2662">CVE-2008-2662</a></li>
|
338
|
-
<li><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-2663">CVE-2008-2663</a></li>
|
339
|
-
<li><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-2725">CVE-2008-2725</a></li>
|
340
|
-
<li><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-2726">CVE-2008-2726</a></li>
|
341
|
-
<li><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-2664">CVE-2008-2664</a></li>
|
342
|
-
</ul><h2><a name="label-1" id="label-1">Vulnerable versions</a></h2><!-- RDLabel: "Vulnerable versions" --><dl>
|
343
|
-
<dt><a name="label-2" id="label-2">1.8 series</a></dt><!-- RDLabel: "1.8 series" -->
|
344
|
-
<dd>
|
345
|
-
<ul>
|
346
|
-
<li>1.8.4 and all prior versions</li>
|
347
|
-
<li>1.8.5-p230 and all prior versions</li>
|
348
|
-
<li>1.8.6-p229 and all prior versions</li>
|
349
|
-
<li>1.8.7-p21 and all prior versions</li>
|
350
|
-
</ul>
|
351
|
-
</dd>
|
352
|
-
<dt><a name="label-3" id="label-3">1.9 series</a></dt><!-- RDLabel: "1.9 series" -->
|
353
|
-
<dd>
|
354
|
-
<ul>
|
355
|
-
<li>1.9.0-1 and all prior versions</li>
|
356
|
-
</ul>
|
357
|
-
</dd>
|
358
|
-
</dl><h2><a name="label-4" id="label-4">Solution</a></h2><!-- RDLabel: "Solution" --><dl>
|
359
|
-
<dt><a name="label-5" id="label-5">1.8 series</a></dt><!-- RDLabel: "1.8 series" -->
|
360
|
-
<dd>
|
361
|
-
Please upgrade to 1.8.5-p231, or 1.8.6-p230, or 1.8.7-p22.
|
362
|
-
<ul>
|
363
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.5-p231.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.5-p231.tar.gz&gt;</a>
|
364
|
-
(md5sum: e900cf225d55414bffe878f00a85807c)</li>
|
365
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p230.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p230.tar.gz&gt;</a>
|
366
|
-
(md5sum: 5e8247e39be2dc3c1a755579c340857f)</li>
|
367
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p22.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p22.tar.gz&gt;</a>
|
368
|
-
(md5sum: fc3ede83a98f48d8cb6de2145f680ef2)</li>
|
369
|
-
</ul>
|
370
|
-
</dd>
|
371
|
-
<dt><a name="label-6" id="label-6">1.9 series</a></dt><!-- RDLabel: "1.9 series" -->
|
372
|
-
<dd>
|
373
|
-
Please upgrade to 1.9.0-2.
|
374
|
-
<ul>
|
375
|
-
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.0-2.tar.gz">&lt;URL:ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.0-2.tar.gz&gt;</a>
|
376
|
-
(md5sum: 2a848b81ed1d6393b88eec8aa6173b75)</li>
|
377
|
-
</ul>
|
378
|
-
</dd>
|
379
|
-
</dl><p>These versions also fix the vulnerability of WEBrick (<a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-1891">CVE-2008-1891</a>).</p><p>Please note that a package that corrects this weakness may already be
|
380
|
-
available through your package management software.</p><h2><a name="label-7" id="label-7">Credit</a></h2><!-- RDLabel: "Credit" --><p>Credit to Drew Yao of Apple Product Security for disclosing the problem to Ruby
|
381
|
-
Security Team.</p><h2><a name="label-8" id="label-8">Changes</a></h2><!-- RDLabel: "Changes" --><ul>
|
382
|
-
<li>2008-06-21 00:29 +09:00 removed wrong CVE IDs (CVE-2008-2727, CVE-2008-2728).</li>
|
383
|
-
</ul></description>
|
384
|
-
<pubDate>Fri, 20 Jun 2008 12:54:43 GMT</pubDate>
|
385
|
-
<guid>http://www.ruby-lang.org/en/news/2008/06/20/arbitrary-code-execution-vulnerabilities/</guid>
|
386
|
-
<link>http://www.ruby-lang.org/en/news/2008/06/20/arbitrary-code-execution-vulnerabilities/</link>
|
387
|
-
</item>
|
388
|
-
|
389
|
-
|
390
|
-
</channel>
|
391
|
-
</rss>
|