[ 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)