Merge branch 'stable-2.9'
* stable-2.9: Link to solved issues from 2.9 release notes Reindex: Include exception cause when dying Fix the request wrapper for http requests served from plugins Fix a possibility to overcome BLOCK permission Add asciidoc build back in the Documentation folder Change CopyableLabel to hide onKeyUp Conflicts: gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java Change-Id: I1ebcc44873eb12acd80b4a0a98d22a73c69a886c
This commit is contained in:
2
Documentation/.gitignore
vendored
Normal file
2
Documentation/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.html
|
||||
/.published
|
||||
95
Documentation/Makefile
Normal file
95
Documentation/Makefile
Normal file
@@ -0,0 +1,95 @@
|
||||
# Copyright (C) 2009 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ASCIIDOC ?= asciidoc
|
||||
ASCIIDOC_EXTRA ?=
|
||||
ASCIIDOC_VER ?= 8.6.3
|
||||
SVN ?= svn
|
||||
PUB_ROOT ?= https://gerrit-documentation.googlecode.com/svn/Documentation
|
||||
|
||||
all: html
|
||||
|
||||
clean:
|
||||
rm -f *.html
|
||||
rm -rf $(LOCAL_ROOT)
|
||||
|
||||
ASCIIDOC_EXE := $(shell which $(ASCIIDOC))
|
||||
ifeq ($(wildcard $(ASCIIDOC_EXE)),)
|
||||
$(error $(ASCIIDOC) must be available)
|
||||
else
|
||||
ASCIIDOC_OK := $(shell expr `asciidoc --version | cut -f2 -d' '` \>= $(ASCIIDOC_VER))
|
||||
ifeq ($(ASCIIDOC_OK),0)
|
||||
$(error $(ASCIIDOC) version $(ASCIIDOC_VER) or higher is required)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(origin VERSION), undefined)
|
||||
VERSION := $(shell ./GEN-DOC-VERSION 2>/dev/null)
|
||||
endif
|
||||
|
||||
DOC_HTML := $(patsubst %.txt,%.html,$(wildcard *.txt))
|
||||
LOCAL_ROOT := .published
|
||||
COMMIT := $(shell git describe HEAD | sed s/^v//)
|
||||
PUB_DIR := $(PUB_ROOT)/$(VERSION)
|
||||
PRIOR = PRIOR
|
||||
|
||||
ifeq ($(VERSION),)
|
||||
REVISION = $(COMMIT)
|
||||
else
|
||||
ifeq ($(VERSION),$(COMMIT))
|
||||
REVISION := $(VERSION)
|
||||
else
|
||||
REVISION := $(VERSION) (from v$(COMMIT))
|
||||
endif
|
||||
endif
|
||||
|
||||
html: $(DOC_HTML)
|
||||
|
||||
update: html
|
||||
ifeq ($(VERSION),)
|
||||
./GEN-DOC-VERSION
|
||||
endif
|
||||
@-rm -rf $(LOCAL_ROOT)
|
||||
@echo "Checking out current $(VERSION)"
|
||||
@if ! $(SVN) checkout $(PUB_DIR) $(LOCAL_ROOT) 2>/dev/null ; then \
|
||||
echo "Copying $(PRIOR) to $(VERSION) ..." && \
|
||||
$(SVN) cp -m "Create $(VERSION) documentation" $(PUB_ROOT)/$(PRIOR) $(PUB_DIR) && \
|
||||
$(SVN) checkout $(PUB_DIR) $(LOCAL_ROOT) ; \
|
||||
fi
|
||||
@rm -f $(LOCAL_ROOT)/*.html
|
||||
@cp *.html $(LOCAL_ROOT)
|
||||
@cd $(LOCAL_ROOT) && \
|
||||
r=`$(SVN) status | perl -ne 'print if s/^! *//' ` && \
|
||||
if [ -n "$$r" ]; then $(SVN) rm $$r; fi && \
|
||||
a=`$(SVN) status | perl -ne 'print if s/^\? *//' ` && \
|
||||
if [ -n "$$a" ]; then \
|
||||
$(SVN) add $$a && \
|
||||
$(SVN) propset svn:mime-type text/html $$a ; \
|
||||
fi && \
|
||||
echo "Committing $(VERSION) at v$(COMMIT)" && \
|
||||
$(SVN) commit -m "Updated $(VERSION) documentation to v$(COMMIT)"
|
||||
@-rm -rf $(LOCAL_ROOT)
|
||||
|
||||
$(DOC_HTML): %.html : %.txt
|
||||
@echo "FORMAT $@"
|
||||
@rm -f $@+ $@
|
||||
@$(ASCIIDOC) -a toc \
|
||||
-a data-uri \
|
||||
-a 'revision=$(REVISION)' \
|
||||
-a 'newline=\n' \
|
||||
-b xhtml11 \
|
||||
-f asciidoc.conf \
|
||||
$(ASCIIDOC_EXTRA) \
|
||||
-o $@+ $<
|
||||
@mv $@+ $@
|
||||
29
Documentation/asciidoc.conf
Normal file
29
Documentation/asciidoc.conf
Normal file
@@ -0,0 +1,29 @@
|
||||
[attributes]
|
||||
asterisk=*
|
||||
plus=+
|
||||
caret=^
|
||||
startsb=[
|
||||
endsb=]
|
||||
tilde=~
|
||||
|
||||
[specialsections]
|
||||
GERRIT=gerrituplink
|
||||
|
||||
[gerrituplink]
|
||||
<hr style="
|
||||
height: 2px;
|
||||
color: silver;
|
||||
margin-top: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
">
|
||||
|
||||
[macros]
|
||||
(?u)^(?P<name>get)::(?P<target>\S*?)$=#
|
||||
|
||||
[get-blockmacro]
|
||||
<a id="{target}" onmousedown="javascript:
|
||||
var i = document.URL.lastIndexOf('/Documentation/');
|
||||
var url = document.URL.substring(0, i) + '{target}';
|
||||
document.getElementById('{target}').href = url;">
|
||||
GET {target} HTTP/1.0
|
||||
</a>
|
||||
@@ -40,7 +40,8 @@ Release Highlights
|
||||
------------------
|
||||
|
||||
|
||||
* The new change screen is now the default change screen.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2065[Issue 2065]:
|
||||
The new change screen is now the default change screen.
|
||||
+
|
||||
The
|
||||
link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-review-ui.html[
|
||||
@@ -90,12 +91,17 @@ the change history.
|
||||
+
|
||||
The support for the old comment visibility strategy is discontinued.
|
||||
|
||||
* Inline comments are shown in the change history.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=93[Issue 93]:
|
||||
Inline comments are shown in the change history.
|
||||
|
||||
* A reply icon is shown on each change message.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=592[Issue 592]:
|
||||
A reply icon is shown on each change message.
|
||||
|
||||
* Quoting is possible when replying to a comment.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2313[Issue 2313]:
|
||||
Show whether a related change is merged or old.
|
||||
|
||||
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-review-ui.html#related-changes[
|
||||
Related Changes] tabs:
|
||||
** `Cherry-Picks`
|
||||
@@ -112,7 +118,8 @@ form: "current patch set/number of patch sets".
|
||||
|
||||
* Support `[`, `/` and `]` keys to navigate between files in a cycle.
|
||||
|
||||
* Show a tooltip on reviewers indicating on which labels they can vote.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2078[Issue 2078]:
|
||||
Show a tooltip on reviewers indicating on which labels they can vote.
|
||||
|
||||
* The `Submit` button is enabled even if the change is not mergeable.
|
||||
+
|
||||
@@ -124,6 +131,32 @@ single merge commit and submit the changes in reverse order.
|
||||
* If a merge commit is viewed this is highlighted by an icon. In this
|
||||
case the parent commits are also shown.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2191[Issue 2191]:
|
||||
New copy-to-clipboard button for commit ID.
|
||||
|
||||
|
||||
New Side-by-Side Diff Screen
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=348[Issue 348]:
|
||||
The lines of a patch file are linkable.
|
||||
+
|
||||
These links can be used to directly link to certain inline comments.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2395[Issue 2395]:
|
||||
The line length preference is used to draw a margin line at that many
|
||||
columns of text.
|
||||
+
|
||||
This allows a user to configure their preferred width (e.g. 80 columns
|
||||
or 100 columns) and see the margin, making it easier to identify lines
|
||||
that run over that width.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2530[Issue 2530]:
|
||||
All diff preferences are honored.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=148[Issue 148]:
|
||||
The full file path is shown.
|
||||
|
||||
|
||||
Change List / Dashboards
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -151,9 +184,11 @@ Project Screens
|
||||
* The general project screen provides a copyable clone command that
|
||||
automatically installs the `commit-msg` hook.
|
||||
|
||||
* Project owners can change `HEAD` from the project branches screen.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=562[Issue 562]:
|
||||
Project owners can change `HEAD` from the project branches screen.
|
||||
|
||||
* Administrators can change the parent project from the project access
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=1298[Issue 1298]:
|
||||
Administrators can change the parent project from the project access
|
||||
screen; other users can save changes to the parent project for review
|
||||
and get the change approved by an administrator.
|
||||
|
||||
@@ -189,7 +224,8 @@ link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-r
|
||||
review] command allowing to control when email notifications should be
|
||||
sent.
|
||||
|
||||
* New `--branch` option on the
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=1752[Issue 1752]:
|
||||
New `--branch` option on the
|
||||
link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-review.html[
|
||||
review] command.
|
||||
|
||||
@@ -201,7 +237,8 @@ reviewers added on the change.
|
||||
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-apropos.html[
|
||||
apropos] command to search the Gerrit documentation.
|
||||
|
||||
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-create-branch.html[
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=1156[Issue 1156]:
|
||||
New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-create-branch.html[
|
||||
create-branch] command.
|
||||
|
||||
REST API
|
||||
@@ -232,7 +269,8 @@ global capability for viewing all accounts].
|
||||
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/access-control.html#capability_viewPlugins[
|
||||
global capability for viewing the list of installed plugins].
|
||||
|
||||
* New `Change Owner` group that allows to assign label permissions to the change owner.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=1993[Issue 1993]:
|
||||
New `Change Owner` group that allows to assign label permissions to the change owner.
|
||||
|
||||
* Support link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/access-control.html#category_submit_on_behalf_of[
|
||||
on behalf of for submit].
|
||||
@@ -268,12 +306,14 @@ is:mergeable] search operator
|
||||
Finds changes that have no merge conflicts and can be merged into the
|
||||
destination branch.
|
||||
|
||||
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#parentproject[
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2163[Issue 2163]:
|
||||
New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#parentproject[
|
||||
parentproject] search operator
|
||||
+
|
||||
Finds changes in the specified project or in one of its child projects.
|
||||
|
||||
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#conflicts[
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2162[Issue 2162]:
|
||||
New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#conflicts[
|
||||
conflicts] search operator
|
||||
+
|
||||
Finds changes that conflict with the specified change.
|
||||
@@ -330,7 +370,8 @@ Configuration
|
||||
|
||||
* New init step for installing the `Verified` label.
|
||||
|
||||
* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/config-gerrit.html#repository.name.defaultSubmitType[
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2257[Issue 2257]:
|
||||
link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/config-gerrit.html#repository.name.defaultSubmitType[
|
||||
Default submit type] for newly created projects can be configured.
|
||||
|
||||
* `sshd_log` and `httpd_log` can use log4j configuration.
|
||||
@@ -341,6 +382,9 @@ Draft workflow can be disabled].
|
||||
* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/config-project-config.html#receive.checkReceivedObjects[
|
||||
Project configuration for checking of received objects].
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2318[Issue 2318]:
|
||||
Allow the text of the "Report Bug" link to be configured.
|
||||
|
||||
|
||||
Misc
|
||||
~~~~
|
||||
@@ -348,7 +392,8 @@ Misc
|
||||
* The removal of reviewers and their votes is recorded as a change
|
||||
message.
|
||||
|
||||
* The change URL is returned on push if the change is updated.
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2229[Issue 2229]:
|
||||
The change URL is returned on push if the change is updated.
|
||||
|
||||
* The topic is included into merge commit messages if all merged
|
||||
changes have the same topic.
|
||||
@@ -427,6 +472,60 @@ Bug Fixes
|
||||
---------
|
||||
|
||||
|
||||
Access Rights
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
* Fix possibility to overcome BLOCK permissions.
|
||||
|
||||
|
||||
Web UI
|
||||
~~~~~~
|
||||
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2652[Issue 2652]:
|
||||
Copy label approvals when cherry-picking change to same branch.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2178[Issue 2178]:
|
||||
Fix background of reply box on new change screen getting transparent.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2362[Issue 2362]:
|
||||
Show quick approve button only for current patch set.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2405[Issue 2405]:
|
||||
Update `Patch Sets` drop-down panel when draft patch set is deleted.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2397[Issue 2397]:
|
||||
Fix linkifying of topics that are set to a URL.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2151[Issue 2151]:
|
||||
Fix overflowing of long lines in commit message block.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2401[Issue 2401]:
|
||||
Fix truncated long lines in new side-by-side diff screen.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2225[Issue 2225]:
|
||||
Display larger icons for Prev / Next and Up to Change links on new
|
||||
side-by-side diff screen.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2340[Issue 2340]:
|
||||
Fix selection in new side-by-side diff screen.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2417[Issue 2417]:
|
||||
Respect base diff revision for files REST call.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2654[Issue 2654]:
|
||||
Require the user to confirm setting the username.
|
||||
+
|
||||
Once the username has been set, it cannot be edited. This can cause
|
||||
problems for users who accidentally set the wrong username. A
|
||||
confirmation dialog now warns the user that setting the username is
|
||||
permanent and the username is only set when the user confirms.
|
||||
|
||||
* link:https://code.google.com/p/gerrit/issues/detail?id=2635[Issue 2635]:
|
||||
Fix copying from copyable label in Safari.
|
||||
|
||||
|
||||
Secondary Index
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -441,15 +540,68 @@ This produced bizarre results for queries like "message:1234".
|
||||
Instead, use Lucene's QueryBuilder with an analyzer to convert a
|
||||
full-text search word/phrase into a phrase query.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2281[Issue 2281]:
|
||||
Reindex change after updating commit message.
|
||||
|
||||
|
||||
REST
|
||||
~~~~
|
||||
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2568[Issue 2568]:
|
||||
Update description file during `PUT /projects/{name}/config`.
|
||||
|
||||
|
||||
SSH
|
||||
~~~
|
||||
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2516[Issue 2516]:
|
||||
Fix parsing of label name on `review` command.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2440[Issue 2440]:
|
||||
Clarify for review command when `--verified` can be used
|
||||
|
||||
|
||||
Plugins
|
||||
~~~~~~~
|
||||
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2551[Issue 2551]:
|
||||
Handle absolute URLs in the top level menu.
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2391[Issue 2391]:
|
||||
Respect servlet context path in URL for top menu items.
|
||||
|
||||
|
||||
Other
|
||||
~~~~~
|
||||
|
||||
|
||||
* link:http://code.google.com/p/gerrit/issues/detail?id=2382[Issue 2382]:
|
||||
Clean left over data migration after removal of TrackingIds table
|
||||
|
||||
|
||||
Upgrades
|
||||
--------
|
||||
|
||||
* Update JGit to 3.4.0.201405051725-m7
|
||||
+
|
||||
This upgrade fixes the MissingObjectExceptions in Gerrit that are
|
||||
described in link:http://code.google.com/p/gerrit/issues/detail?id=2025[
|
||||
issue 2025].
|
||||
|
||||
* Update gwtjsonrpc to 1.5
|
||||
* Update gwtorm to 1.8
|
||||
* Update guava to 16.0
|
||||
|
||||
* Update H2 to 1.3.174
|
||||
+
|
||||
This version includes a fix for an LOB deadlock between reading and
|
||||
updating LOB columns. This could lead to a deadlock between web and SSH
|
||||
clients as described in
|
||||
link:http://code.google.com/p/gerrit/issues/detail?id=2365[issue 2365].
|
||||
|
||||
* Update Jetty to 9.1.0.v20131115
|
||||
* Update Servlet API to 3.1
|
||||
* Update Lucene to 4.6.0
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||
import com.google.gwt.event.dom.client.KeyPressHandler;
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||
import com.google.gwt.http.client.URL;
|
||||
import com.google.gwt.user.client.Command;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
@@ -189,9 +191,14 @@ public class CopyableLabel extends Composite implements HasText {
|
||||
switch (event.getCharCode()) {
|
||||
case 'c':
|
||||
case 'x':
|
||||
Scheduler.get().scheduleDeferred(new Command() {
|
||||
public void execute() {
|
||||
hideTextBox();
|
||||
textBox.addKeyUpHandler(new KeyUpHandler() {
|
||||
@Override
|
||||
public void onKeyUp(final KeyUpEvent event) {
|
||||
Scheduler.get().scheduleDeferred(new Command() {
|
||||
public void execute() {
|
||||
hideTextBox();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2014 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.package com.google.gerrit.httpd.plugins;
|
||||
|
||||
package com.google.gerrit.httpd.plugins;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
class ContextMapper {
|
||||
private static final String PLUGINS_PREFIX = "/plugins/";
|
||||
private static final String AUTHORIZED_PREFIX = "/a" + PLUGINS_PREFIX;
|
||||
private final String base;
|
||||
private final String authorizedBase;
|
||||
|
||||
public ContextMapper(String contextPath) {
|
||||
base = Strings.nullToEmpty(contextPath) + PLUGINS_PREFIX;
|
||||
authorizedBase = Strings.nullToEmpty(contextPath) + AUTHORIZED_PREFIX;
|
||||
}
|
||||
|
||||
private static boolean isAuthorizedCall(HttpServletRequest req) {
|
||||
return !Strings.isNullOrEmpty(req.getServletPath())
|
||||
&& req.getServletPath().startsWith(AUTHORIZED_PREFIX);
|
||||
}
|
||||
|
||||
HttpServletRequest create(HttpServletRequest req, String name) {
|
||||
String contextPath = (isAuthorizedCall(req) ? authorizedBase : base) + name;
|
||||
|
||||
return new WrappedRequest(req, contextPath);
|
||||
}
|
||||
|
||||
public String getFullPath(String name) {
|
||||
return base + name;
|
||||
}
|
||||
|
||||
private class WrappedRequest extends HttpServletRequestWrapper {
|
||||
private final String contextPath;
|
||||
private final String pathInfo;
|
||||
|
||||
private WrappedRequest(HttpServletRequest req, String contextPath) {
|
||||
super(req);
|
||||
this.contextPath = contextPath;
|
||||
this.pathInfo = getRequestURI().substring(contextPath.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletPath() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathInfo() {
|
||||
return pathInfo;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -73,7 +73,6 @@ import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Singleton
|
||||
@@ -83,8 +82,6 @@ class HttpPluginServlet extends HttpServlet
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger log
|
||||
= LoggerFactory.getLogger(HttpPluginServlet.class);
|
||||
private static final String PLUGINS_PREFIX = "/plugins/";
|
||||
private static final String AUTHORIZED_PREFIX = "/a" + PLUGINS_PREFIX;
|
||||
|
||||
private final MimeUtilFileTypeRegistry mimeUtil;
|
||||
private final Provider<String> webUrl;
|
||||
@@ -94,8 +91,7 @@ class HttpPluginServlet extends HttpServlet
|
||||
private final RestApiServlet managerApi;
|
||||
|
||||
private List<Plugin> pending = Lists.newArrayList();
|
||||
private String base;
|
||||
private String authorizedBase;
|
||||
private ContextMapper wrapper;
|
||||
private final ConcurrentMap<String, PluginHolder> plugins
|
||||
= Maps.newConcurrentMap();
|
||||
|
||||
@@ -134,9 +130,7 @@ class HttpPluginServlet extends HttpServlet
|
||||
public synchronized void init(ServletConfig config) throws ServletException {
|
||||
super.init(config);
|
||||
|
||||
String path = config.getServletContext().getContextPath();
|
||||
base = Strings.nullToEmpty(path) + PLUGINS_PREFIX;
|
||||
authorizedBase = Strings.nullToEmpty(path) + AUTHORIZED_PREFIX;
|
||||
wrapper = new ContextMapper(config.getServletContext().getContextPath());
|
||||
for (Plugin plugin : pending) {
|
||||
install(plugin);
|
||||
}
|
||||
@@ -182,7 +176,8 @@ class HttpPluginServlet extends HttpServlet
|
||||
}
|
||||
|
||||
try {
|
||||
ServletContext ctx = PluginServletContext.create(plugin, base + name);
|
||||
ServletContext ctx =
|
||||
PluginServletContext.create(plugin, wrapper.getFullPath(name));
|
||||
filter.init(new WrappedFilterConfig(ctx));
|
||||
} catch (ServletException e) {
|
||||
log.warn(String.format("Plugin %s failed to initialize HTTP", name), e);
|
||||
@@ -220,8 +215,7 @@ class HttpPluginServlet extends HttpServlet
|
||||
return;
|
||||
}
|
||||
|
||||
WrappedRequest wr = new WrappedRequest(req,
|
||||
(isAuthorizedCall(req) ? authorizedBase : base) + name);
|
||||
HttpServletRequest wr = wrapper.create(req, name);
|
||||
FilterChain chain = new FilterChain() {
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res)
|
||||
@@ -236,11 +230,6 @@ class HttpPluginServlet extends HttpServlet
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthorizedCall(HttpServletRequest req) {
|
||||
return !Strings.isNullOrEmpty(req.getServletPath())
|
||||
&& req.getServletPath().startsWith(AUTHORIZED_PREFIX);
|
||||
}
|
||||
|
||||
private static boolean isApiCall(HttpServletRequest req, List<String> parts) {
|
||||
String method = req.getMethod();
|
||||
int cnt = parts.size();
|
||||
@@ -258,14 +247,13 @@ class HttpPluginServlet extends HttpServlet
|
||||
return;
|
||||
}
|
||||
|
||||
String uri = req.getRequestURI();
|
||||
String ctx = req.getContextPath();
|
||||
if (uri.length() <= ctx.length()) {
|
||||
String pathInfo = req.getPathInfo();
|
||||
if (pathInfo.length() < 1) {
|
||||
Resource.NOT_FOUND.send(req, res);
|
||||
return;
|
||||
}
|
||||
|
||||
String file = uri.substring(ctx.length() + 1);
|
||||
String file = pathInfo.substring(1);
|
||||
ResourceKey key = new ResourceKey(holder.plugin, file);
|
||||
Resource rsc = resourceCache.getIfPresent(key);
|
||||
if (rsc != null) {
|
||||
@@ -273,6 +261,7 @@ class HttpPluginServlet extends HttpServlet
|
||||
return;
|
||||
}
|
||||
|
||||
String uri = req.getRequestURI();
|
||||
if ("".equals(file)) {
|
||||
res.sendRedirect(uri + holder.docPrefix + "index.html");
|
||||
return;
|
||||
@@ -675,32 +664,4 @@ class HttpPluginServlet extends HttpServlet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class WrappedRequest extends HttpServletRequestWrapper {
|
||||
private final String contextPath;
|
||||
|
||||
WrappedRequest(HttpServletRequest req, String contextPath) {
|
||||
super(req);
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletPath() {
|
||||
return getRequestURI().substring(contextPath.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURI() {
|
||||
String uri = super.getRequestURI();
|
||||
if (uri.startsWith("/a/")) {
|
||||
uri = uri.substring(2);
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2014 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.package com.google.gerrit.httpd.plugins;
|
||||
|
||||
package com.google.gerrit.httpd.plugins;
|
||||
|
||||
import static org.easymock.EasyMock.createNiceMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class ContextMapperTest {
|
||||
|
||||
private static final String CONTEXT = "/context";
|
||||
private static final String PLUGIN_NAME = "my-plugin";
|
||||
private static final String RESOURCE = "my-resource";
|
||||
|
||||
@Test
|
||||
public void testUnauthorized() throws Exception {
|
||||
ContextMapper classUnderTest = new ContextMapper(CONTEXT);
|
||||
|
||||
HttpServletRequest originalRequest =
|
||||
createMockRequest("/plugins/", PLUGIN_NAME + "/" + RESOURCE);
|
||||
|
||||
HttpServletRequest result =
|
||||
classUnderTest.create(originalRequest, PLUGIN_NAME);
|
||||
|
||||
assertEquals(CONTEXT + "/plugins/" + PLUGIN_NAME, result.getContextPath());
|
||||
assertEquals("", result.getServletPath());
|
||||
assertEquals("/" + RESOURCE, result.getPathInfo());
|
||||
assertEquals(CONTEXT + "/plugins/" + PLUGIN_NAME + "/" + RESOURCE,
|
||||
result.getRequestURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorized() throws Exception {
|
||||
ContextMapper classUnderTest = new ContextMapper(CONTEXT);
|
||||
|
||||
HttpServletRequest originalRequest =
|
||||
createMockRequest("/a/plugins/", PLUGIN_NAME + "/" + RESOURCE);
|
||||
|
||||
HttpServletRequest result =
|
||||
classUnderTest.create(originalRequest, PLUGIN_NAME);
|
||||
|
||||
assertEquals(CONTEXT + "/a/plugins/" + PLUGIN_NAME,
|
||||
result.getContextPath());
|
||||
assertEquals("", result.getServletPath());
|
||||
assertEquals("/" + RESOURCE, result.getPathInfo());
|
||||
assertEquals(CONTEXT + "/a/plugins/" + PLUGIN_NAME + "/" + RESOURCE,
|
||||
result.getRequestURI());
|
||||
}
|
||||
|
||||
private static HttpServletRequest createMockRequest(String servletPath,
|
||||
String pathInfo) {
|
||||
HttpServletRequest req = createNiceMock(HttpServletRequest.class);
|
||||
expect(req.getContextPath()).andStubReturn(CONTEXT);
|
||||
expect(req.getServletPath()).andStubReturn(servletPath);
|
||||
expect(req.getPathInfo()).andStubReturn(pathInfo);
|
||||
String uri = CONTEXT + servletPath + pathInfo;
|
||||
expect(req.getRequestURI()).andStubReturn(uri);
|
||||
replay(req);
|
||||
|
||||
return req;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ public class Reindex extends SiteProgram {
|
||||
result = indexAll();
|
||||
index.markReady(true);
|
||||
} catch (Exception e) {
|
||||
throw die(e.getMessage());
|
||||
throw die(e.getMessage(), e);
|
||||
}
|
||||
sysManager.stop();
|
||||
dbManager.stop();
|
||||
|
||||
@@ -109,8 +109,7 @@ public class PermissionCollection {
|
||||
List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
|
||||
sorter.sort(ref, sections);
|
||||
|
||||
Set<SeenRule> seen = new HashSet<>();
|
||||
Set<SeenRule> seenBlockingRules = new HashSet<>();
|
||||
Set<SeenRule> seen = new HashSet<SeenRule>();
|
||||
Set<String> exclusiveGroupPermissions = new HashSet<>();
|
||||
|
||||
HashMap<String, List<PermissionRule>> permissions = new HashMap<>();
|
||||
@@ -125,7 +124,7 @@ public class PermissionCollection {
|
||||
SeenRule s = new SeenRule(section, permission, rule);
|
||||
boolean addRule;
|
||||
if (rule.isBlock()) {
|
||||
addRule = seenBlockingRules.add(s);
|
||||
addRule = true;
|
||||
} else {
|
||||
addRule = seen.add(s) && !rule.isDeny() && !exclusivePermissionExists;
|
||||
}
|
||||
|
||||
@@ -299,6 +299,15 @@ public class RefControlTest {
|
||||
public void testBlockRule_ParentBlocksChild() {
|
||||
grant(local, PUSH, DEVS, "refs/tags/*");
|
||||
grant(util.getParentConfig(), PUSH, ANONYMOUS_USERS, "refs/tags/*").setBlock();
|
||||
ProjectControl u = util.user(local, DEVS);
|
||||
assertFalse("u can't update tag", u.controlForRef("refs/tags/V10").canUpdate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockRule_ParentBlocksChildEvenIfAlreadyBlockedInChild() {
|
||||
grant(local, PUSH, DEVS, "refs/tags/*");
|
||||
grant(local, PUSH, ANONYMOUS_USERS, "refs/tags/*").setBlock();
|
||||
grant(util.getParentConfig(), PUSH, ANONYMOUS_USERS, "refs/tags/*").setBlock();
|
||||
|
||||
ProjectControl u = util.user(local, DEVS);
|
||||
assertFalse("u can't update tag", u.controlForRef("refs/tags/V10").canUpdate());
|
||||
@@ -318,6 +327,23 @@ public class RefControlTest {
|
||||
assertFalse("u can't vote 2", range.contains(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockLabelRange_ParentBlocksChildEvenIfAlreadyBlockedInChild() {
|
||||
grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
|
||||
grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*").setBlock();
|
||||
grant(util.getParentConfig(), LABEL + "Code-Review", -2, +2, DEVS,
|
||||
"refs/heads/*").setBlock();
|
||||
|
||||
ProjectControl u = util.user(local, DEVS);
|
||||
|
||||
PermissionRange range =
|
||||
u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
|
||||
assertTrue("u can vote -1", range.contains(-1));
|
||||
assertTrue("u can vote +1", range.contains(1));
|
||||
assertFalse("u can't vote -2", range.contains(-2));
|
||||
assertFalse("u can't vote 2", range.contains(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnblockNoForce() {
|
||||
grant(local, PUSH, ANONYMOUS_USERS, "refs/heads/*").setBlock();
|
||||
|
||||
Reference in New Issue
Block a user