/* * Copyright 2013 gitblit.com. * * 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.gitblit.wicket; import java.util.Date; import com.google.inject.Inject; import com.google.inject.Singleton; import javax.servlet.http.HttpServletRequest; import org.apache.wicket.protocol.http.IWebApplicationFactory; import org.apache.wicket.protocol.http.WebApplication; import org.apache.wicket.protocol.http.WicketFilter; import org.apache.wicket.util.string.Strings; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.manager.IProjectManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.StringUtils; /** * * Customization of the WicketFilter to allow smart browser-side caching of * some pages. * * @author James Moger * */ @Singleton public class GitblitWicketFilter extends WicketFilter { private IStoredSettings settings; private IRuntimeManager runtimeManager; private IRepositoryManager repositoryManager; private IProjectManager projectManager; private GitBlitWebApp webapp; @Inject public GitblitWicketFilter( IStoredSettings settings, IRuntimeManager runtimeManager, IRepositoryManager repositoryManager, IProjectManager projectManager, GitBlitWebApp webapp) { this.settings = settings; this.runtimeManager = runtimeManager; this.repositoryManager = repositoryManager; this.projectManager = projectManager; this.webapp = webapp; } @Override protected IWebApplicationFactory getApplicationFactory() { return new IWebApplicationFactory() { @Override public WebApplication createApplication(WicketFilter filter) { return webapp; } }; } /** * Determines the last-modified date of the requested resource. * * @param servletRequest * @return The last modified time stamp */ @Override protected long getLastModified(final HttpServletRequest servletRequest) { final String pathInfo = getRelativePath(servletRequest); if (Strings.isEmpty(pathInfo)) { return -1; } long lastModified = super.getLastModified(servletRequest); if (lastModified > -1) { return lastModified; } // try to match request against registered CacheControl pages String [] paths = pathInfo.split("/"); String page = paths[0]; String repo = ""; String commitId = ""; if (paths.length >= 2) { repo = paths[1]; } if (paths.length >= 3) { commitId = paths[2]; } if (!StringUtils.isEmpty(servletRequest.getParameter("r"))) { repo = servletRequest.getParameter("r"); } if (!StringUtils.isEmpty(servletRequest.getParameter("h"))) { commitId = servletRequest.getParameter("h"); } repo = repo.replace("%2f", "/").replace("%2F", "/").replace(settings.getChar(Keys.web.forwardSlashCharacter, '/'), '/'); GitBlitWebApp app = (GitBlitWebApp) getWebApplication(); int expires = settings.getInteger(Keys.web.pageCacheExpires, 0); if (!StringUtils.isEmpty(page) && app.isCacheablePage(page) && expires > 0) { // page can be cached by the browser CacheControl cacheControl = app.getCacheControl(page); Date bootDate = runtimeManager.getBootDate(); switch (cacheControl.value()) { case ACTIVITY: // returns the last activity date of the server Date activityDate = repositoryManager.getLastActivityDate(); if (activityDate != null) { return activityDate.after(bootDate) ? activityDate.getTime() : bootDate.getTime(); } return bootDate.getTime(); case BOOT: // return the boot date of the server return bootDate.getTime(); case PROJECT: // return the latest change date for the project OR the boot date ProjectModel project = projectManager.getProjectModel(StringUtils.getRootPath(repo)); if (project != null) { return project.lastChange.after(bootDate) ? project.lastChange.getTime() : bootDate.getTime(); } break; case REPOSITORY: // return the lastest change date for the repository OR the boot // date, whichever is latest RepositoryModel repository = repositoryManager.getRepositoryModel(repo); if (repository != null && repository.lastChange != null) { return repository.lastChange.after(bootDate) ? repository.lastChange.getTime() : bootDate.getTime(); } break; case COMMIT: // get the date of the specified commit if (StringUtils.isEmpty(commitId)) { // no commit id, use boot date return bootDate.getTime(); } else { // last modified date is the commit date Repository r = null; try { // return the timestamp of the associated commit r = repositoryManager.getRepository(repo); if (r != null) { RevCommit commit = JGitUtils.getCommit(r, commitId); if (commit != null) { Date date = JGitUtils.getCommitDate(commit); return date.after(bootDate) ? date.getTime() : bootDate.getTime(); } } } finally { if (r != null) { r.close(); } } } break; default: break; } } return -1; } }