Files
gerrit/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
Shawn Pearce c2cb3cda1d Disable caching for revision URLs using "current"
The current revision is resolved dynamically and may change. Do
not allow browser level caching on these URLs as the contents can
(and usually does) change in the future.

Clients that want caching must request the revision-id using a stable
identifier, ideally the commit SHA-1, or at least the unique patch
set number. This allows contents to cache as data behind the URL
will not change.

Change-Id: I00c5c607a78297dadaf5d5338f025aaf4832af63
2013-07-12 10:21:41 -07:00

124 lines
4.5 KiB
Java

// Copyright (C) 2012 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.server.change;
import com.google.common.collect.Lists;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Collections;
import java.util.List;
public class Revisions implements ChildCollection<ChangeResource, RevisionResource> {
private final DynamicMap<RestView<RevisionResource>> views;
private final Provider<ReviewDb> dbProvider;
@Inject
Revisions(DynamicMap<RestView<RevisionResource>> views,
Provider<ReviewDb> dbProvider) {
this.views = views;
this.dbProvider = dbProvider;
}
@Override
public DynamicMap<RestView<RevisionResource>> views() {
return views;
}
@Override
public RestView<ChangeResource> list() throws ResourceNotFoundException {
throw new ResourceNotFoundException();
}
@Override
public RevisionResource parse(ChangeResource change, IdString id)
throws ResourceNotFoundException, OrmException {
if (id.equals("current")) {
PatchSet.Id p = change.getChange().currentPatchSetId();
PatchSet ps = p != null ? dbProvider.get().patchSets().get(p) : null;
if (ps != null && visible(change, ps)) {
return new RevisionResource(change, ps).doNotCache();
}
throw new ResourceNotFoundException(id);
}
List<PatchSet> match = Lists.newArrayListWithExpectedSize(2);
for (PatchSet ps : find(change, id.get())) {
Change.Id changeId = ps.getId().getParentKey();
if (changeId.equals(change.getChange().getId()) && visible(change, ps)) {
match.add(ps);
}
}
if (match.size() != 1) {
throw new ResourceNotFoundException(id);
}
return new RevisionResource(change, match.get(0));
}
private boolean visible(ChangeResource change, PatchSet ps)
throws OrmException {
return change.getControl().isPatchVisible(ps, dbProvider.get());
}
private List<PatchSet> find(ChangeResource change, String id)
throws OrmException {
ReviewDb db = dbProvider.get();
if (id.length() < 6 && id.matches("^[1-9][0-9]{0,4}$")) {
// Legacy patch set number syntax.
PatchSet ps = dbProvider.get().patchSets().get(new PatchSet.Id(
change.getChange().getId(),
Integer.parseInt(id)));
if (ps != null) {
return Collections.singletonList(ps);
}
return Collections.emptyList();
} else if (id.length() < 4 || id.length() > RevId.LEN) {
// Require a minimum of 4 digits.
// Impossibly long identifier will never match.
return Collections.emptyList();
} else if (id.length() >= 8) {
// Commit names are rather unique. Query for the commit and later
// match to the change. This is most likely going to identify 1 or
// at most 2 patch sets to consider, which is smaller than looking
// for all patch sets in the change.
RevId revid = new RevId(id);
if (revid.isComplete()) {
return db.patchSets().byRevision(revid).toList();
} else {
return db.patchSets().byRevisionRange(revid, revid.max()).toList();
}
} else {
// Chance of collision rises; look at all patch sets on the change.
List<PatchSet> out = Lists.newArrayList();
for (PatchSet ps : db.patchSets().byChange(change.getChange().getId())) {
if (ps.getRevision() != null && ps.getRevision().get().startsWith(id)) {
out.add(ps);
}
}
return out;
}
}
}