[
https://issues.apache.org/jira/browse/JCR-3858?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14356682#comment-14356682
]
Thomas Mueller commented on JCR-3858:
-------------------------------------
Patch for review:
{noformat}
Index:
src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
(revision 1641780)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
(working copy)
@@ -39,7 +39,7 @@
* Implements the <code>QueryResult</code> interface.
*/
public abstract class QueryResultImpl implements JackrabbitQueryResult {
-
+
/**
* The logger instance for this class
*/
@@ -119,6 +119,8 @@
* The maximum size of this result if limit >= 0
*/
private final long limit;
+
+ private final boolean sizeEstimate;
/**
* Creates a new query result. The concrete sub class is responsible for
@@ -146,6 +148,7 @@
ColumnImpl[] columns, boolean documentOrder,
long offset, long limit) throws RepositoryException {
this.index = index;
+ this.sizeEstimate = index.getSizeEstimate();
this.sessionContext = sessionContext;
this.queryImpl = queryImpl;
this.spellSuggestion = spellSuggestion;
@@ -258,10 +261,12 @@
log.debug("getResults({}) limit={}", size, limit);
}
- // quick check
- // if numResults is set, all relevant results have been fetched
- if (numResults != -1) {
- return;
+ if (!sizeEstimate) {
+ // quick check
+ // if numResults is set, all relevant results have been fetched
+ if (numResults != -1) {
+ return;
+ }
}
long maxResultSize = size;
@@ -291,7 +296,11 @@
List<ScoreNode[]> offsetNodes = new ArrayList<ScoreNode[]>();
if (resultNodes.isEmpty() && offset > 0) {
// collect result offset into dummy list
- collectScoreNodes(result, offsetNodes, offset);
+ if (sizeEstimate) {
+ collectScoreNodes(result, new ArrayList<ScoreNode[]>(),
offset);
+ } else {
+ collectScoreNodes(result, offsetNodes, offset);
+ }
} else {
int start = resultNodes.size() + invalid + (int) offset;
result.skip(start);
@@ -303,24 +312,29 @@
log.debug("retrieved ScoreNodes in {} ms ({})",
System.currentTimeMillis() - time, r3 - r2);
- // update numResults if all results have been fetched
- // if resultNodes.getSize() is strictly smaller than
maxResultSize, it means that all results have been fetched
- int resultSize = resultNodes.size();
- if (resultSize < maxResultSize) {
- if (resultNodes.isEmpty()) {
- // if there's no result nodes, the actual totalResults if
smaller or equals than the offset
- totalResults = offsetNodes.size();
- numResults = 0;
+ if (sizeEstimate) {
+ // update numResults
+ numResults = result.getSize();
+ } else {
+ // update numResults if all results have been fetched
+ // if resultNodes.getSize() is strictly smaller than
maxResultSize, it means that all results have been fetched
+ int resultSize = resultNodes.size();
+ if (resultSize < maxResultSize) {
+ if (resultNodes.isEmpty()) {
+ // if there's no result nodes, the actual totalResults
if smaller or equals than the offset
+ totalResults = offsetNodes.size();
+ numResults = 0;
+ }
+ else {
+ totalResults = resultSize + (int) offset;
+ numResults = resultSize;
+ }
}
- else {
- totalResults = resultSize + (int) offset;
- numResults = resultSize;
+ else if (resultSize == limit) {
+ // if there's "limit" results, we can't know the total
size (which may be greater), but the result size is the limit
+ numResults = (int) limit;
}
}
- else if (resultSize == limit) {
- // if there's "limit" results, we can't know the total size
(which may be greater), but the result size is the limit
- numResults = (int) limit;
- }
} catch (IOException e) {
throw new RepositoryException(e);
} finally {
@@ -393,11 +407,23 @@
* will get get if you don't set any limit or offset. This method may
return
* <code>-1</code> if the total size is unknown.
* <p>
+ * If the "sizeEstimate" options is enabled:
+ * Keep in mind that this number may get smaller if nodes are found in
+ * the result set which the current session has no permission to access.
+ * This might be a security problem.
*
* @return the total number of hits.
*/
public int getTotalSize() {
- return totalResults;
+ if (sizeEstimate) {
+ if (numResults == -1) {
+ return -1;
+ } else {
+ return numResults - invalid;
+ }
+ } else {
+ return totalResults;
+ }
}
private final class LazyScoreNodeIteratorImpl implements ScoreNodeIterator
{
@@ -448,9 +474,26 @@
/**
* {@inheritDoc}
+ * <p/>
+ * If the "sizeEstimate" options is enabled:
+ * This value may shrink when the query result encounters non-existing
+ * nodes or the session does not have access to a node.
*/
public long getSize() {
- return numResults;
+ if (sizeEstimate) {
+ int total = getTotalSize();
+ if (total == -1) {
+ return -1;
+ }
+ long size = offset > total ? 0 : total - offset;
+ if (limit >= 0 && size > limit) {
+ return limit;
+ } else {
+ return size;
+ }
+ } else {
+ return numResults;
+ }
}
/**
@@ -504,9 +547,16 @@
while (next == null) {
if (nextPos >= resultNodes.size()) {
// quick check if there are more results at all
- // if numResults is set, all relevant results have been
fetched
- if (numResults != -1) {
- break;
+ if (sizeEstimate) {
+ // this check is only possible if we have numResults
+ if (numResults != -1 && (nextPos + invalid) >=
numResults) {
+ break;
+ }
+ } else {
+ // if numResults is set, all relevant results have
been fetched
+ if (numResults != -1) {
+ break;
+ }
}
// fetch more results
Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
(revision 1641780)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
(working copy)
@@ -386,6 +386,14 @@
* Default value is: <code>false</code>.
*/
private boolean supportHighlighting = false;
+
+ /**
+ * If enabled, NodeIterator.getSize() may report a larger value than the
+ * actual result. This value may shrink when the query result encounters
+ * non-existing nodes or the session does not have access to a node. This
+ * might be a security problem.
+ */
+ private boolean sizeEstimate = false;
/**
* The excerpt provider class. Implements {@link ExcerptProvider}.
@@ -2178,6 +2186,27 @@
public long getExtractorTimeout() {
return extractorTimeout;
}
+
+ /**
+ * If enabled, NodeIterator.getSize() may report a larger value than the
+ * actual result. This value may shrink when the query result encounters
+ * non-existing nodes or the session does not have access to a node. This
+ * might be a security problem.
+ *
+ * @param b <code>true</code> to enable
+ */
+ public void setSizeEstimate(boolean b) {
+ this.sizeEstimate = b;
+ }
+
+ /**
+ * Get the size estimate setting.
+ *
+ * @return the setting
+ */
+ public boolean getSizeEstimate() {
+ return sizeEstimate;
+ }
/**
* If set to <code>true</code> additional information is stored in the
index
{noformat}
> NodeIterator.getSize(): compatibility with Jackrabbit 2.5
> ---------------------------------------------------------
>
> Key: JCR-3858
> URL: https://issues.apache.org/jira/browse/JCR-3858
> Project: Jackrabbit Content Repository
> Issue Type: New Feature
> Affects Versions: 2.6.2, 2.7
> Reporter: Thomas Mueller
> Assignee: Thomas Mueller
>
> In Jackrabbit 2.5 and older, the query result set (NodeIterator.getSize())
> was an estimation that sometimes included nodes that are not visible for the
> current user.
> This is a possible security problem. The behavior was changed (and the
> security problem fixed) in JCR-3402. However, this is an incompatibility with
> Jackrabbit 2.5.
> I suggest to make this configurable in workspace.xml / repository.xml (or a
> system property, if that turns out to be too complicated). The default is the
> current (secure) behavior, with the option to use the old variant.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)