import java.io.File;
import org.apache.commons.io.FileUtils;
-import org.sonar.api.platform.ServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.api.utils.ZipUtils;
import org.sonar.core.platform.ExplodedPlugin;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginLoader;
import org.sonar.core.platform.PluginRepository;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
private static final String[] JAR_FILE_EXTENSIONS = new String[] {"jar"};
private static final String NOT_STARTED_YET = "not started yet";
- private final DefaultServerFileSystem fs;
+ private final ServerFileSystem fs;
private final PluginLoader loader;
private final AtomicBoolean started = new AtomicBoolean(false);
private final Map<String, PluginInfo> pluginInfosByKeys = new HashMap<>();
private final Map<String, Plugin> pluginInstancesByKeys = new HashMap<>();
- public CePluginRepository(DefaultServerFileSystem fs, PluginLoader loader) {
+ public CePluginRepository(ServerFileSystem fs, PluginLoader loader) {
this.fs = fs;
this.loader = loader;
}
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.ComponentService;
import org.sonar.server.computation.CeModule;
-import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule;
import org.sonar.server.computation.CeQueueModule;
import org.sonar.server.computation.queue.PurgeCeActivities;
+import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule;
import org.sonar.server.computation.taskprocessor.CeTaskProcessorModule;
import org.sonar.server.debt.DebtModelPluginRepository;
import org.sonar.server.debt.DebtRulesXMLImporter;
import org.sonar.server.notification.email.AlertsEmailTemplate;
import org.sonar.server.notification.email.EmailNotificationChannel;
import org.sonar.server.platform.DatabaseServerCompatibility;
-import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.server.platform.DefaultServerUpgradeStatus;
import org.sonar.server.platform.PersistentSettings;
+import org.sonar.server.platform.ServerFileSystemImpl;
import org.sonar.server.platform.ServerImpl;
import org.sonar.server.platform.ServerLifecycleNotifier;
import org.sonar.server.platform.ServerLogging;
DatabaseServerCompatibility.class,
DatabaseVersion.class,
PurgeProfiler.class,
- DefaultServerFileSystem.class,
+ ServerFileSystemImpl.class,
// no TempFolderCleaner.class, responsibility of Web Server
new TempFolderProvider(),
System2.INSTANCE,
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.ServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.core.platform.ExplodedPlugin;
import org.sonar.core.platform.PluginInfo;
this.temp = temp;
}
+ @Override
+ public File getDataDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getDeployDir() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public File getHomeDir() {
throw new UnsupportedOperationException();
return tempDir;
}
+ @Override
+ public File getDeployedPluginsDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getDownloadedPluginsDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getInstalledPluginsDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getBundledPluginsDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getPluginIndex() {
+ throw new UnsupportedOperationException();
+ }
+
}
}
import org.sonar.api.Plugin;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginLoader;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Rule
public ExpectedException expectedException = ExpectedException.none();
- DefaultServerFileSystem fs = mock(DefaultServerFileSystem.class, Mockito.RETURNS_DEEP_STUBS);
- PluginLoader pluginLoader = new DumbPluginLoader();
- CePluginRepository underTest = new CePluginRepository(fs, pluginLoader);
+ private ServerFileSystem fs = mock(ServerFileSystem.class, Mockito.RETURNS_DEEP_STUBS);
+ private PluginLoader pluginLoader = new DumbPluginLoader();
+ private CePluginRepository underTest = new CePluginRepository(fs, pluginLoader);
@After
public void tearDown() {
import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
-import org.sonar.api.platform.Server;
import org.sonar.api.server.ServerSide;
+import org.sonar.server.platform.ServerFileSystem;
/**
* JAR files to be downloaded by sonar-runner.
@ServerSide
public class BatchIndex implements Startable {
- private final Server server;
+ private final ServerFileSystem fs;
private String index;
private File batchDir;
- public BatchIndex(Server server) {
- this.server = server;
+ public BatchIndex(ServerFileSystem fs) {
+ this.fs = fs;
}
@Override
public void start() {
StringBuilder sb = new StringBuilder();
- batchDir = new File(server.getRootDir(), "lib/batch");
+ batchDir = new File(fs.getHomeDir(), "lib/batch");
if (batchDir.exists()) {
Collection<File> files = FileUtils.listFiles(batchDir, HiddenFileFilter.VISIBLE, FileFilterUtils.directoryFileFilter());
for (File file : files) {
import org.picocontainer.ComponentLifecycle;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.platform.ServerFileSystem;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.internal.DefaultTempFolder;
+import org.sonar.server.platform.ServerFileSystem;
/**
* Provides a TempFolder instance pointing to a directory dedicated to the processing of a specific item.
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Lists;
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import javax.annotation.Nullable;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.CharEncoding;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.utils.log.Loggers;
-
-/**
- * @since 3.0
- */
-class ClassLoaderUtils {
-
- private ClassLoaderUtils() {
- // only static methods
- }
-
- static File copyResources(ClassLoader classLoader, String rootPath, File toDir, Function<String, String> relocationFunction) {
- Collection<String> relativePaths = listFiles(classLoader, rootPath);
- for (String relativePath : relativePaths) {
- URL resource = classLoader.getResource(relativePath);
- String filename = relocationFunction.apply(relativePath);
- File toFile = new File(toDir, filename);
- try {
- FileUtils.copyURLToFile(resource, toFile);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to extract " + relativePath + " to " + toFile.getAbsolutePath(), e);
- }
- }
-
- return toDir;
- }
-
- /**
- * Finds files within a given directory and its subdirectories
- *
- * @param classLoader
- * @param rootPath the root directory, for example org/sonar/sqale
- * @return a list of relative paths, for example {"org/sonar/sqale/foo/bar.txt}. Never null.
- */
- static Collection<String> listFiles(ClassLoader classLoader, String rootPath) {
- return listResources(classLoader, rootPath, new Predicate<String>() {
- @Override
- public boolean apply(@Nullable String path) {
- return !StringUtils.endsWith(path, "/");
- }
- });
- }
-
- /**
- * Finds directories and files within a given directory and its subdirectories.
- *
- * @param classLoader
- * @param rootPath the root directory, for example org/sonar/sqale, or a file in this root directory, for example org/sonar/sqale/index.txt
- * @param predicate
- * @return a list of relative paths, for example {"org/sonar/sqale", "org/sonar/sqale/foo", "org/sonar/sqale/foo/bar.txt}. Never null.
- */
- static Collection<String> listResources(ClassLoader classLoader, String rootPath, Predicate<String> predicate) {
- String jarPath = null;
- JarFile jar = null;
- try {
- Collection<String> paths = Lists.newArrayList();
- URL root = classLoader.getResource(rootPath);
- if (root != null) {
- checkJarFile(root);
-
- // Path of the root directory
- // Examples :
- // org/sonar/sqale/index.txt -> rootDirectory is org/sonar/sqale
- // org/sonar/sqale/ -> rootDirectory is org/sonar/sqale
- // org/sonar/sqale -> rootDirectory is org/sonar/sqale
- String rootDirectory = rootPath;
- if (StringUtils.substringAfterLast(rootPath, "/").indexOf('.') >= 0) {
- rootDirectory = StringUtils.substringBeforeLast(rootPath, "/");
- }
- //strip out only the JAR file
- jarPath = root.getPath().substring(5, root.getPath().indexOf('!'));
- jar = new JarFile(URLDecoder.decode(jarPath, CharEncoding.UTF_8));
- Enumeration<JarEntry> entries = jar.entries();
- while (entries.hasMoreElements()) {
- String name = entries.nextElement().getName();
- if (name.startsWith(rootDirectory) && predicate.apply(name)) {
- paths.add(name);
- }
- }
- }
- return paths;
- } catch (Exception e) {
- throw Throwables.propagate(e);
- } finally {
- closeJar(jar, jarPath);
- }
- }
-
- private static void closeJar(JarFile jar, String jarPath) {
- if (jar != null) {
- try {
- jar.close();
- } catch (Exception e) {
- Loggers.get(ClassLoaderUtils.class).error("Fail to close JAR file: " + jarPath, e);
- }
- }
- }
-
- private static void checkJarFile(URL root) {
- if (!"jar".equals(root.getProtocol())) {
- throw new IllegalStateException("Unsupported protocol: " + root.getProtocol());
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import java.io.File;
-import java.io.IOException;
-import javax.annotation.CheckForNull;
-import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
-import org.sonar.api.config.Settings;
-import org.sonar.api.platform.Server;
-import org.sonar.api.platform.ServerFileSystem;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.process.ProcessProperties;
-
-/**
- * Introspect the filesystem and the classloader to get extension files at startup.
- *
- * @since 2.2
- */
-public class DefaultServerFileSystem implements ServerFileSystem, Startable {
-
- private static final Logger LOGGER = Loggers.get(DefaultServerFileSystem.class);
-
- private final Server server;
- private final File homeDir;
- private final File tempDir;
-
- public DefaultServerFileSystem(Settings settings, Server server) {
- this.server = server;
- this.homeDir = new File(settings.getString(ProcessProperties.PATH_HOME));
- this.tempDir = new File(settings.getString(ProcessProperties.PATH_TEMP));
- }
-
- /**
- * for unit tests
- */
- public DefaultServerFileSystem(File homeDir, File tempDir, Server server) {
- this.homeDir = homeDir;
- this.tempDir = tempDir;
- this.server = server;
- }
-
- @Override
- public void start() {
- LOGGER.info("SonarQube home: " + homeDir.getAbsolutePath());
-
- File deployDir = getDeployDir();
- if (deployDir == null) {
- throw new IllegalArgumentException("Web app directory does not exist");
- }
-
- File deprecated = getDeprecatedPluginsDir();
- try {
- FileUtils.forceMkdir(deprecated);
- org.sonar.core.util.FileUtils.cleanDirectory(deprecated);
- } catch (IOException e) {
- throw new IllegalStateException("The following directory can not be created: " + deprecated.getAbsolutePath(), e);
- }
- }
-
- @Override
- public void stop() {
- // do nothing
- }
-
- @Override
- public File getHomeDir() {
- return homeDir;
- }
-
- @Override
- public File getTempDir() {
- return tempDir;
- }
-
- @CheckForNull
- public File getDeployDir() {
- return server.getDeployDir();
- }
-
- public File getDeployedPluginsDir() {
- return new File(getDeployDir(), "plugins");
- }
-
- public File getDownloadedPluginsDir() {
- return new File(getHomeDir(), "extensions/downloads");
- }
-
- public File getInstalledPluginsDir() {
- return new File(getHomeDir(), "extensions/plugins");
- }
-
- public File getBundledPluginsDir() {
- return new File(getHomeDir(), "lib/bundled-plugins");
- }
-
- public File getDeprecatedPluginsDir() {
- return new File(getHomeDir(), "extensions/deprecated");
- }
-
- public File getPluginIndex() {
- return new File(getDeployDir(), "plugins/index.txt");
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.List;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.web.ServletFilter;
-
-/**
- * Inspired by http://stackoverflow.com/a/7592883/229031
- */
-public class MasterServletFilter implements Filter {
-
- public static volatile MasterServletFilter INSTANCE;
- private ServletFilter[] filters;
- private FilterConfig config;
-
- public MasterServletFilter() {
- if (INSTANCE != null) {
- throw new IllegalStateException("Servlet filter " + getClass().getName() + " is already instantiated");
- }
- INSTANCE = this;
- }
-
- @Override
- public void init(FilterConfig config) throws ServletException {
- // Filters are already available in picocontainer unless a database migration is required. See
- // org.sonar.server.startup.RegisterServletFilters.
- init(config, Platform.getInstance().getContainer().getComponentsByType(ServletFilter.class));
- }
-
- void init(FilterConfig config, List<ServletFilter> filters) throws ServletException {
- this.config = config;
- initFilters(filters);
- }
-
- public void initFilters(List<ServletFilter> filterExtensions) throws ServletException {
- List<ServletFilter> filterList = Lists.newArrayList();
- for (ServletFilter extension : filterExtensions) {
- try {
- Loggers.get(MasterServletFilter.class).info(String.format("Initializing servlet filter %s [pattern=%s]", extension, extension.doGetPattern()));
- extension.init(config);
- filterList.add(extension);
- } catch (Exception e) {
- throw new IllegalStateException("Fail to initialize servlet filter: " + extension + ". Message: " + e.getMessage(), e);
- }
- }
- filters = filterList.toArray(new ServletFilter[filterList.size()]);
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
- HttpServletRequest hsr = (HttpServletRequest) request;
- if (filters.length == 0) {
- chain.doFilter(request, response);
- } else {
- String path = hsr.getRequestURI().replaceFirst(hsr.getContextPath(), "");
- GodFilterChain godChain = new GodFilterChain(chain);
-
- for (ServletFilter filter : filters) {
- if (filter.doGetPattern().matches(path)) {
- godChain.addFilter(filter);
- }
- }
- godChain.doFilter(request, response);
- }
- }
-
- @Override
- public void destroy() {
- for (ServletFilter filter : filters) {
- filter.destroy();
- }
- }
-
- @VisibleForTesting
- ServletFilter[] getFilters() {
- return filters;
- }
-
- private static final class GodFilterChain implements FilterChain {
- private FilterChain chain;
- private List<Filter> filters = Lists.newLinkedList();
- private Iterator<Filter> iterator;
-
- public GodFilterChain(FilterChain chain) {
- this.chain = chain;
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
- if (iterator == null) {
- iterator = filters.iterator();
- }
- if (iterator.hasNext()) {
- iterator.next().doFilter(request, response, this);
- } else {
- chain.doFilter(request, response);
- }
- }
-
- public void addFilter(Filter filter) {
- Preconditions.checkState(iterator == null);
- filters.add(filter);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.base.Throwables;
-import java.util.Enumeration;
-import java.util.Properties;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-public final class PlatformServletContextListener implements ServletContextListener {
-
- static final String STARTED_ATTRIBUTE = "sonarqube.started";
-
- @Override
- public void contextInitialized(ServletContextEvent event) {
- try {
- Properties props = new Properties();
- ServletContext servletContext = event.getServletContext();
- Enumeration<String> paramKeys = servletContext.getInitParameterNames();
- while (paramKeys.hasMoreElements()) {
- String key = paramKeys.nextElement();
- props.put(key, servletContext.getInitParameter(key));
- }
- Platform.getInstance().init(props, servletContext);
- Platform.getInstance().doStart();
- event.getServletContext().setAttribute(STARTED_ATTRIBUTE, Boolean.TRUE);
-
- } catch (Throwable t) {
- // Tomcat 7 "limitations":
- // - server does not stop if webapp fails at startup
- // - the second listener for jruby on rails is started even if this listener fails. It generates
- // unexpected errors
- stopQuietly();
- throw Throwables.propagate(t);
- }
- }
-
- private void stopQuietly() {
- try {
- Platform.getInstance().doStop();
- } catch (Exception e) {
- // ignored, but an error during startup generally prevents pico to be correctly stopped
- }
- }
-
- @Override
- public void contextDestroyed(ServletContextEvent event) {
- Platform.getInstance().doStop();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.collect.ImmutableSet;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-import java.io.IOException;
-import java.util.Set;
-
-/**
- * <p>Profile HTTP requests using platform profiling utility.</p>
- * <p>To avoid profiling of requests for static resources, the <code>staticDirs</code>
- * filter parameter can be set in the servlet context descriptor. This parameter should
- * contain a comma-separated list of paths, starting at the context root;
- * requests on subpaths of these paths will not be profiled.</p>
- *
- * @since 4.1
- */
-public class ProfilingFilter implements Filter {
-
- private static final String CONFIG_SEPARATOR = ",";
- private static final String URL_SEPARATOR = "/";
-
- private static final String MESSAGE_WITH_QUERY = "%s %s?%s";
- private static final String MESSAGE_WITHOUT_QUERY = "%s %s";
- public static final org.sonar.api.utils.log.Logger Logger = Loggers.get("http");
-
- private String contextRoot;
- private Set<String> staticResourceDirs;
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- contextRoot = filterConfig.getServletContext().getContextPath();
-
- String staticResourcesConfig = filterConfig.getInitParameter("staticDirs");
- if (StringUtils.isNotBlank(staticResourcesConfig)) {
- staticResourceDirs = ImmutableSet.copyOf(staticResourcesConfig.split(CONFIG_SEPARATOR));
- } else {
- staticResourceDirs = ImmutableSet.of();
- }
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- if (request instanceof HttpServletRequest) {
- HttpServletRequest httpRequest = (HttpServletRequest) request;
- String requestUri = httpRequest.getRequestURI();
- String rootDir = getRootDir(requestUri);
-
- if (staticResourceDirs.contains(rootDir)) {
- // Static resource, not profiled
- chain.doFilter(request, response);
- } else {
- Profiler profiler = Profiler.createIfDebug(Logger).start();
- try {
- chain.doFilter(request, response);
- } finally {
- if (profiler.isDebugEnabled()) {
- String queryString = httpRequest.getQueryString();
- String message = String.format(queryString == null ? MESSAGE_WITHOUT_QUERY : MESSAGE_WITH_QUERY, httpRequest.getMethod(), requestUri, queryString);
- profiler.stopDebug(message);
- }
- }
- }
- } else {
- // Not an HTTP request, not profiled
- chain.doFilter(request, response);
- }
- }
-
- private String getRootDir(String requestUri) {
- String rootPath = "";
- String localPath = StringUtils.substringAfter(requestUri, contextRoot);
- if (localPath.startsWith(URL_SEPARATOR)) {
- int secondSlash = localPath.indexOf(URL_SEPARATOR, 1);
- if (secondSlash > 0) {
- rootPath = URL_SEPARATOR + localPath.substring(1, secondSlash);
- }
- }
- return rootPath;
- }
-
- @Override
- public void destroy() {
- // Nothing
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import java.io.File;
-import java.io.IOException;
-import javax.annotation.Nullable;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
-import org.sonar.api.Plugin;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.ServerFileSystem;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-
-/**
- * Ruby on Rails requires the files to be on filesystem but not in Java classpath (JAR). This component extracts
- * all the needed files from plugins and copy them to $SONAR_HOME/temp
- *
- * @since 3.0
- */
-public class RailsAppsDeployer implements Startable {
-
- private static final Logger LOG = Loggers.get(RailsAppsDeployer.class);
- private static final String ROR_PATH = "org/sonar/ror/";
-
- private final ServerFileSystem fs;
- private final PluginRepository pluginRepository;
-
- public RailsAppsDeployer(ServerFileSystem fs, PluginRepository pluginRepository) {
- this.fs = fs;
- this.pluginRepository = pluginRepository;
- }
-
- @Override
- public void start() {
- LOG.info("Deploying Ruby on Rails applications");
- File appsDir = prepareRailsDirectory();
-
- for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
- String pluginKey = pluginInfo.getKey();
- Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
- try {
- deployRailsApp(appsDir, pluginKey, plugin.getClass().getClassLoader());
- } catch (Exception e) {
- throw new IllegalStateException(String.format("Fail to deploy Ruby on Rails application of plugin [%s]", pluginKey), e);
- }
- }
- }
-
- @Override
- public void stop() {
- // do nothing
- }
-
- @VisibleForTesting
- File prepareRailsDirectory() {
- File appsDir = new File(fs.getTempDir(), "ror");
- prepareDir(appsDir);
- return appsDir;
- }
-
- @VisibleForTesting
- static void deployRailsApp(File appsDir, final String pluginKey, ClassLoader appClassLoader) {
- if (hasRailsApp(pluginKey, appClassLoader)) {
- LOG.info("Deploying app: " + pluginKey);
- File appDir = new File(appsDir, pluginKey);
- ClassLoaderUtils.copyResources(appClassLoader, pathToRubyInitFile(pluginKey), appDir, new Function<String, String>() {
- @Override
- public String apply(@Nullable String relativePath) {
- // Relocate the deployed files :
- // relativePath format is: org/sonar/ror/sqale/app/controllers/foo_controller.rb
- // app path is: org/sonar/ror/sqale
- // -> deployed file is app/controllers/foo_controller.rb
- return StringUtils.substringAfter(relativePath, pluginKey + "/");
- }
- });
- }
- }
-
- private static String pathToRubyInitFile(String pluginKey) {
- return ROR_PATH + pluginKey + "/init.rb";
- }
-
- @VisibleForTesting
- static boolean hasRailsApp(String pluginKey, ClassLoader classLoader) {
- return classLoader.getResource(pathToRubyInitFile(pluginKey)) != null;
- }
-
- private void prepareDir(File appsDir) {
- if (appsDir.exists() && appsDir.isDirectory()) {
- try {
- org.sonar.core.util.FileUtils.deleteDirectory(appsDir);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to delete temp directory: " + appsDir, e);
- }
- }
- try {
- FileUtils.forceMkdir(appsDir);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to create temp directory: " + appsDir, e);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import static java.lang.String.format;
-
-import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class RoutesFilter implements Filter {
-
- private static final String EMPTY = "";
- private static final String BATCH_WS = "/batch";
- private static final String API_SOURCES_WS = "/api/sources";
-
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) servletRequest;
- HttpServletResponse response = (HttpServletResponse) servletResponse;
- String path = request.getRequestURI().replaceFirst(request.getContextPath(), EMPTY);
- if (path.startsWith(BATCH_WS + "/") && path.endsWith(".jar")) {
- // Scanner is still using /batch/file.jar url
- response.sendRedirect(format("%s%s/file?name=%s", request.getContextPath(), BATCH_WS, path.replace(BATCH_WS + "/", EMPTY)));
- } else if ("/batch_bootstrap/index".equals(path)) {
- // Scanner is still using /batch_bootstrap url
- response.sendRedirect(format("%s%s/index", request.getContextPath(), BATCH_WS));
- } else if (API_SOURCES_WS.equals(path)) {
- // SONAR-7852 /api/sources?resource url is still used
- response.sendRedirect(format("%s%s/index?%s", request.getContextPath(), API_SOURCES_WS, request.getQueryString()));
- } else {
- chain.doFilter(request, response);
- }
- }
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- // Nothing
- }
-
- @Override
- public void destroy() {
- // Nothing
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.base.Throwables;
-import javax.servlet.ServletContextEvent;
-import org.jruby.rack.RackApplicationFactory;
-import org.jruby.rack.rails.RailsServletContextListener;
-import org.jruby.rack.servlet.ServletRackContext;
-
-/**
- * Overriding {@link RailsServletContextListener} allows to disable initialization of Ruby on Rails
- * environment when Java components fail to start.
- * See https://jira.sonarsource.com/browse/SONAR-6740
- */
-public class RubyRailsContextListener extends RailsServletContextListener {
-
- @Override
- public void contextInitialized(ServletContextEvent event) {
- if (event.getServletContext().getAttribute(PlatformServletContextListener.STARTED_ATTRIBUTE) != null) {
- super.contextInitialized(event);
- }
- }
-
- // Always stop server when an error is raised during startup.
- // By default Rack only logs an error (see org.jruby.rack.RackServletContextListener#handleInitializationException()).
- // Rack propagates exceptions if the properties jruby.rack.exception or jruby.rack.error are set to true.
- // Unfortunately we didn't succeed in defining these properties, so the method is overridden here.
- // Initial need: SONAR-6171
- @Override
- protected void handleInitializationException(Exception e, RackApplicationFactory factory, ServletRackContext rackContext) {
- throw Throwables.propagate(e);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import com.google.common.collect.ImmutableSet;
-import java.io.IOException;
-import java.util.Set;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * This servlet filter sets response headers that enable browser protection against several classes if Web attacks.
- * The list of headers is mirrored in environment.rb as a workaround to Rack swallowing the headers..
- */
-public class SecurityServletFilter implements Filter {
-
- private static final Set<String> ALLOWED_HTTP_METHODS = ImmutableSet.of("DELETE", "GET", "HEAD", "POST", "PUT");
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- // nothing
- }
-
- @Override
- public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
- doHttpFilter((HttpServletRequest) req, (HttpServletResponse) resp, chain);
- }
-
- private static void doHttpFilter(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain) throws IOException, ServletException {
- // SONAR-6881 Disable OPTIONS and TRACE methods
- if (!ALLOWED_HTTP_METHODS.contains(httpRequest.getMethod())) {
- httpResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
-
- chain.doFilter(httpRequest, httpResponse);
-
- // Clickjacking protection
- // See https://www.owasp.org/index.php/Clickjacking_Protection_for_Java_EE
- httpResponse.addHeader("X-Frame-Options", "SAMEORIGIN");
-
- // Cross-site scripting
- // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers
- httpResponse.addHeader("X-XSS-Protection", "1; mode=block");
-
- // MIME-sniffing
- // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers
- httpResponse.addHeader("X-Content-Type-Options", "nosniff");
- }
-
- @Override
- public void destroy() {
- // nothing
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform;
+
+import java.io.File;
+
+/**
+ * Replaces the incomplete {@link org.sonar.api.platform.ServerFileSystem} as many directories can't be
+ * published in API.
+ *
+ * @since 6.0
+ */
+public interface ServerFileSystem {
+
+ /**
+ * Directory that contains the persisted data to be kept on restarts and upgrades.
+ * @return an existing directory
+ */
+ File getDataDir();
+
+ /**
+ * Directory accessible by scanners through web server
+ * @return a non-null directory that MAY exist
+ */
+ File getDeployDir();
+
+ /**
+ * Root directory of the server installation
+ * @return an existing directory
+ */
+ File getHomeDir();
+
+ /**
+ * Temporary directory, clean up on restarts
+ * @return an existing directory
+ */
+ File getTempDir();
+
+ /**
+ * Files of plugins published by web server for scanners
+ * @return a non-null directory that MAY exist
+ */
+ File getDeployedPluginsDir();
+
+ /**
+ * Directory of plugins downloaded through update center. Files
+ * will be moved to {@link #getInstalledPluginsDir()} on startup.
+ * @return an existing directory
+ */
+ File getDownloadedPluginsDir();
+
+ /**
+ * Directory of currently installed plugins. Used at startup.
+ * @return an existing directory
+ */
+ File getInstalledPluginsDir();
+
+ /**
+ * Directory of the plugins packaged by default with application. These
+ * plugins are installed during the first fresh startup.
+ * @return an existing directory
+ */
+ File getBundledPluginsDir();
+
+ /**
+ * The file listing all the installed plugins. Used by scanner only.
+ * @return an existing file
+ */
+ File getPluginIndex();
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform;
+
+import java.io.File;
+import org.picocontainer.Startable;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.process.ProcessProperties;
+import org.sonar.server.app.TomcatContexts;
+
+import static java.util.Objects.requireNonNull;
+
+public class ServerFileSystemImpl implements ServerFileSystem, org.sonar.api.platform.ServerFileSystem, Startable {
+
+ private static final Logger LOGGER = Loggers.get(ServerFileSystemImpl.class);
+
+ private final File homeDir;
+ private final File tempDir;
+ private final File dataDir;
+ private final File deployDir;
+
+ public ServerFileSystemImpl(Settings settings) {
+ this.homeDir = new File(requireNonNull(settings.getString(ProcessProperties.PATH_HOME)));
+ this.tempDir = new File(requireNonNull(settings.getString(ProcessProperties.PATH_TEMP)));
+ this.dataDir = new File(requireNonNull(settings.getString(ProcessProperties.PATH_DATA)));
+ this.deployDir = new File(this.dataDir, TomcatContexts.WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR);
+ }
+
+ @Override
+ public void start() {
+ LOGGER.info("SonarQube home: " + homeDir.getAbsolutePath());
+ }
+
+ @Override
+ public void stop() {
+ // do nothing
+ }
+
+ @Override
+ public File getHomeDir() {
+ return homeDir;
+ }
+
+ @Override
+ public File getTempDir() {
+ return tempDir;
+ }
+
+ @Override
+ public File getDataDir() {
+ return dataDir;
+ }
+
+ @Override
+ public File getDeployDir() {
+ return deployDir;
+ }
+
+ @Override
+ public File getDeployedPluginsDir() {
+ return new File(getDeployDir(), "plugins");
+ }
+
+ @Override
+ public File getDownloadedPluginsDir() {
+ return new File(getHomeDir(), "extensions/downloads");
+ }
+
+ @Override
+ public File getInstalledPluginsDir() {
+ return new File(getHomeDir(), "extensions/plugins");
+ }
+
+ @Override
+ public File getBundledPluginsDir() {
+ return new File(getHomeDir(), "lib/bundled-plugins");
+ }
+
+ @Override
+ public File getPluginIndex() {
+ return new File(getDeployDir(), "plugins/index.txt");
+ }
+
+}
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.process.ProcessProperties;
-import org.sonar.server.app.TomcatContexts;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
private String version;
private String implementationBuild;
private File sonarHome;
- private File deployDir;
private String contextPath;
public ServerImpl(Settings settings) {
throw new IllegalStateException("SonarQube home directory is not valid");
}
- deployDir = new File(settings.getString(ProcessProperties.PATH_DATA), TomcatContexts.WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR);
-
contextPath = StringUtils.defaultIfBlank(settings.getString(PROPERTY_CONTEXT), "")
// Remove trailing slashes
.replaceFirst("(\\/+)$", "");
@Override
@CheckForNull
public File getDeployDir() {
- return deployDir;
+ return null;
}
@Override
*/
package org.sonar.server.platform;
+import java.io.File;
+import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.platform.ServerFileSystem;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.internal.DefaultTempFolder;
-import java.io.File;
-import java.io.IOException;
-
public class TempFolderProvider extends ProviderAdapter {
private TempFolder tempFolder;
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
package org.sonar.server.platform.cluster;
import com.google.common.collect.ImmutableList;
import org.sonar.server.db.EmbeddedDatabaseFactory;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.platform.DatabaseServerCompatibility;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystemImpl;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.ServerImpl;
import org.sonar.server.platform.ServerSettingsImpl;
DatabaseServerCompatibility.class,
DatabaseVersion.class,
PurgeProfiler.class,
- DefaultServerFileSystem.class,
+ ServerFileSystemImpl.class,
SemaphoresImpl.class,
TempFolderCleaner.class,
new TempFolderProvider(),
import org.sonar.server.db.migrations.PlatformDatabaseMigration;
import org.sonar.server.db.migrations.PlatformDatabaseMigrationExecutorServiceImpl;
import org.sonar.server.platform.DefaultServerUpgradeStatus;
-import org.sonar.server.platform.RailsAppsDeployer;
+import org.sonar.server.platform.web.RailsAppsDeployer;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
import org.sonar.server.plugins.ServerPluginJarExploder;
import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.startup.RegisterMetrics;
import org.sonar.server.startup.RegisterNewMeasureFilters;
import org.sonar.server.startup.RegisterPermissionTemplates;
-import org.sonar.server.startup.RegisterServletFilters;
+import org.sonar.server.platform.web.RegisterServletFilters;
import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
import org.sonar.server.startup.RenameIssueWidgets;
import org.sonar.server.user.DoPrivileged;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.web.ServletFilter;
+import org.sonar.server.platform.Platform;
+
+/**
+ * Inspired by http://stackoverflow.com/a/7592883/229031
+ */
+public class MasterServletFilter implements Filter {
+
+ public static volatile MasterServletFilter INSTANCE;
+ private ServletFilter[] filters;
+ private FilterConfig config;
+
+ public MasterServletFilter() {
+ if (INSTANCE != null) {
+ throw new IllegalStateException("Servlet filter " + getClass().getName() + " is already instantiated");
+ }
+ INSTANCE = this;
+ }
+
+ @Override
+ public void init(FilterConfig config) throws ServletException {
+ // Filters are already available in picocontainer unless a database migration is required. See
+ // org.sonar.server.startup.RegisterServletFilters.
+ init(config, Platform.getInstance().getContainer().getComponentsByType(ServletFilter.class));
+ }
+
+ void init(FilterConfig config, List<ServletFilter> filters) throws ServletException {
+ this.config = config;
+ initFilters(filters);
+ }
+
+ public void initFilters(List<ServletFilter> filterExtensions) throws ServletException {
+ List<ServletFilter> filterList = Lists.newArrayList();
+ for (ServletFilter extension : filterExtensions) {
+ try {
+ Loggers.get(MasterServletFilter.class).info(String.format("Initializing servlet filter %s [pattern=%s]", extension, extension.doGetPattern()));
+ extension.init(config);
+ filterList.add(extension);
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to initialize servlet filter: " + extension + ". Message: " + e.getMessage(), e);
+ }
+ }
+ filters = filterList.toArray(new ServletFilter[filterList.size()]);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
+ HttpServletRequest hsr = (HttpServletRequest) request;
+ if (filters.length == 0) {
+ chain.doFilter(request, response);
+ } else {
+ String path = hsr.getRequestURI().replaceFirst(hsr.getContextPath(), "");
+ GodFilterChain godChain = new GodFilterChain(chain);
+
+ for (ServletFilter filter : filters) {
+ if (filter.doGetPattern().matches(path)) {
+ godChain.addFilter(filter);
+ }
+ }
+ godChain.doFilter(request, response);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ for (ServletFilter filter : filters) {
+ filter.destroy();
+ }
+ }
+
+ @VisibleForTesting
+ ServletFilter[] getFilters() {
+ return filters;
+ }
+
+ private static final class GodFilterChain implements FilterChain {
+ private FilterChain chain;
+ private List<Filter> filters = Lists.newLinkedList();
+ private Iterator<Filter> iterator;
+
+ public GodFilterChain(FilterChain chain) {
+ this.chain = chain;
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+ if (iterator == null) {
+ iterator = filters.iterator();
+ }
+ if (iterator.hasNext()) {
+ iterator.next().doFilter(request, response, this);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ public void addFilter(Filter filter) {
+ Preconditions.checkState(iterator == null);
+ filters.add(filter);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import com.google.common.base.Throwables;
+import java.util.Enumeration;
+import java.util.Properties;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import org.sonar.server.platform.Platform;
+
+public final class PlatformServletContextListener implements ServletContextListener {
+
+ static final String STARTED_ATTRIBUTE = "sonarqube.started";
+
+ @Override
+ public void contextInitialized(ServletContextEvent event) {
+ try {
+ Properties props = new Properties();
+ ServletContext servletContext = event.getServletContext();
+ Enumeration<String> paramKeys = servletContext.getInitParameterNames();
+ while (paramKeys.hasMoreElements()) {
+ String key = paramKeys.nextElement();
+ props.put(key, servletContext.getInitParameter(key));
+ }
+ Platform.getInstance().init(props, servletContext);
+ Platform.getInstance().doStart();
+ event.getServletContext().setAttribute(STARTED_ATTRIBUTE, Boolean.TRUE);
+
+ } catch (Throwable t) {
+ // Tomcat 7 "limitations":
+ // - server does not stop if webapp fails at startup
+ // - the second listener for jruby on rails is started even if this listener fails. It generates
+ // unexpected errors
+ stopQuietly();
+ throw Throwables.propagate(t);
+ }
+ }
+
+ private void stopQuietly() {
+ try {
+ Platform.getInstance().doStop();
+ } catch (Exception e) {
+ // ignored, but an error during startup generally prevents pico to be correctly stopped
+ }
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent event) {
+ Platform.getInstance().doStop();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * <p>Profile HTTP requests using platform profiling utility.</p>
+ * <p>To avoid profiling of requests for static resources, the <code>staticDirs</code>
+ * filter parameter can be set in the servlet context descriptor. This parameter should
+ * contain a comma-separated list of paths, starting at the context root;
+ * requests on subpaths of these paths will not be profiled.</p>
+ *
+ * @since 4.1
+ */
+public class ProfilingFilter implements Filter {
+
+ private static final String CONFIG_SEPARATOR = ",";
+ private static final String URL_SEPARATOR = "/";
+
+ private static final String MESSAGE_WITH_QUERY = "%s %s?%s";
+ private static final String MESSAGE_WITHOUT_QUERY = "%s %s";
+ public static final org.sonar.api.utils.log.Logger Logger = Loggers.get("http");
+
+ private String contextRoot;
+ private Set<String> staticResourceDirs;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ contextRoot = filterConfig.getServletContext().getContextPath();
+
+ String staticResourcesConfig = filterConfig.getInitParameter("staticDirs");
+ if (StringUtils.isNotBlank(staticResourcesConfig)) {
+ staticResourceDirs = ImmutableSet.copyOf(staticResourcesConfig.split(CONFIG_SEPARATOR));
+ } else {
+ staticResourceDirs = ImmutableSet.of();
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ if (request instanceof HttpServletRequest) {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ String requestUri = httpRequest.getRequestURI();
+ String rootDir = getRootDir(requestUri);
+
+ if (staticResourceDirs.contains(rootDir)) {
+ // Static resource, not profiled
+ chain.doFilter(request, response);
+ } else {
+ Profiler profiler = Profiler.createIfDebug(Logger).start();
+ try {
+ chain.doFilter(request, response);
+ } finally {
+ if (profiler.isDebugEnabled()) {
+ String queryString = httpRequest.getQueryString();
+ String message = String.format(queryString == null ? MESSAGE_WITHOUT_QUERY : MESSAGE_WITH_QUERY, httpRequest.getMethod(), requestUri, queryString);
+ profiler.stopDebug(message);
+ }
+ }
+ }
+ } else {
+ // Not an HTTP request, not profiled
+ chain.doFilter(request, response);
+ }
+ }
+
+ private String getRootDir(String requestUri) {
+ String rootPath = "";
+ String localPath = StringUtils.substringAfter(requestUri, contextRoot);
+ if (localPath.startsWith(URL_SEPARATOR)) {
+ int secondSlash = localPath.indexOf(URL_SEPARATOR, 1);
+ if (secondSlash > 0) {
+ rootPath = URL_SEPARATOR + localPath.substring(1, secondSlash);
+ }
+ }
+ return rootPath;
+ }
+
+ @Override
+ public void destroy() {
+ // Nothing
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.picocontainer.Startable;
+import org.sonar.api.Plugin;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.server.platform.ServerFileSystem;
+import org.sonar.server.util.ClassLoaderUtils;
+
+/**
+ * Ruby on Rails requires the files to be on filesystem but not in Java classpath (JAR). This component extracts
+ * all the needed files from plugins and copy them to $SONAR_HOME/temp
+ *
+ * @since 3.0
+ */
+public class RailsAppsDeployer implements Startable {
+
+ private static final Logger LOG = Loggers.get(RailsAppsDeployer.class);
+ private static final String ROR_PATH = "org/sonar/ror/";
+
+ private final ServerFileSystem fs;
+ private final PluginRepository pluginRepository;
+
+ public RailsAppsDeployer(ServerFileSystem fs, PluginRepository pluginRepository) {
+ this.fs = fs;
+ this.pluginRepository = pluginRepository;
+ }
+
+ @Override
+ public void start() {
+ LOG.info("Deploying Ruby on Rails applications");
+ File appsDir = prepareRailsDirectory();
+
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ String pluginKey = pluginInfo.getKey();
+ Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
+ try {
+ deployRailsApp(appsDir, pluginKey, plugin.getClass().getClassLoader());
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Fail to deploy Ruby on Rails application of plugin [%s]", pluginKey), e);
+ }
+ }
+ }
+
+ @Override
+ public void stop() {
+ // do nothing
+ }
+
+ @VisibleForTesting
+ File prepareRailsDirectory() {
+ File appsDir = new File(fs.getTempDir(), "ror");
+ prepareDir(appsDir);
+ return appsDir;
+ }
+
+ @VisibleForTesting
+ static void deployRailsApp(File appsDir, final String pluginKey, ClassLoader appClassLoader) {
+ if (hasRailsApp(pluginKey, appClassLoader)) {
+ LOG.info("Deploying app: " + pluginKey);
+ File appDir = new File(appsDir, pluginKey);
+ ClassLoaderUtils.copyResources(appClassLoader, pathToRubyInitFile(pluginKey), appDir, relativePath -> {
+ // Relocate the deployed files :
+ // relativePath format is: org/sonar/ror/sqale/app/controllers/foo_controller.rb
+ // app path is: org/sonar/ror/sqale
+ // -> deployed file is app/controllers/foo_controller.rb
+ return StringUtils.substringAfter(relativePath, pluginKey + "/");
+ });
+ }
+ }
+
+ private static String pathToRubyInitFile(String pluginKey) {
+ return ROR_PATH + pluginKey + "/init.rb";
+ }
+
+ @VisibleForTesting
+ static boolean hasRailsApp(String pluginKey, ClassLoader classLoader) {
+ return classLoader.getResource(pathToRubyInitFile(pluginKey)) != null;
+ }
+
+ private void prepareDir(File appsDir) {
+ if (appsDir.exists() && appsDir.isDirectory()) {
+ try {
+ org.sonar.core.util.FileUtils.deleteDirectory(appsDir);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to delete temp directory: " + appsDir, e);
+ }
+ }
+ try {
+ FileUtils.forceMkdir(appsDir);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temp directory: " + appsDir, e);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import java.util.Arrays;
+import javax.servlet.ServletException;
+import org.sonar.api.web.ServletFilter;
+
+/**
+ * @since 3.5
+ */
+public class RegisterServletFilters {
+ private final ServletFilter[] filters;
+
+ public RegisterServletFilters(ServletFilter[] filters) {
+ this.filters = filters;
+ }
+
+ public RegisterServletFilters() {
+ this(new ServletFilter[0]);
+ }
+
+ public void start() throws ServletException {
+ if (MasterServletFilter.INSTANCE != null) {
+ // Probably a database upgrade. MasterSlaveFilter was instantiated by the servlet container
+ // while picocontainer was not completely up.
+ // See https://jira.sonarsource.com/browse/SONAR-3612
+ MasterServletFilter.INSTANCE.initFilters(Arrays.asList(filters));
+ }
+ }
+}
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class RoutesFilter implements Filter {
+
+ private static final String EMPTY = "";
+ private static final String BATCH_WS = "/batch";
+ private static final String API_SOURCES_WS = "/api/sources";
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+ String path = request.getRequestURI().replaceFirst(request.getContextPath(), EMPTY);
+ if (path.startsWith(BATCH_WS + "/") && path.endsWith(".jar")) {
+ // Scanner is still using /batch/file.jar url
+ response.sendRedirect(format("%s%s/file?name=%s", request.getContextPath(), BATCH_WS, path.replace(BATCH_WS + "/", EMPTY)));
+ } else if ("/batch_bootstrap/index".equals(path)) {
+ // Scanner is still using /batch_bootstrap url
+ response.sendRedirect(format("%s%s/index", request.getContextPath(), BATCH_WS));
+ } else if (API_SOURCES_WS.equals(path)) {
+ // SONAR-7852 /api/sources?resource url is still used
+ response.sendRedirect(format("%s%s/index?%s", request.getContextPath(), API_SOURCES_WS, request.getQueryString()));
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Nothing
+ }
+
+ @Override
+ public void destroy() {
+ // Nothing
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import com.google.common.base.Throwables;
+import javax.servlet.ServletContextEvent;
+import org.jruby.rack.RackApplicationFactory;
+import org.jruby.rack.rails.RailsServletContextListener;
+import org.jruby.rack.servlet.ServletRackContext;
+
+/**
+ * Overriding {@link RailsServletContextListener} allows to disable initialization of Ruby on Rails
+ * environment when Java components fail to start.
+ * See https://jira.sonarsource.com/browse/SONAR-6740
+ */
+public class RubyRailsContextListener extends RailsServletContextListener {
+
+ @Override
+ public void contextInitialized(ServletContextEvent event) {
+ if (event.getServletContext().getAttribute(PlatformServletContextListener.STARTED_ATTRIBUTE) != null) {
+ super.contextInitialized(event);
+ }
+ }
+
+ // Always stop server when an error is raised during startup.
+ // By default Rack only logs an error (see org.jruby.rack.RackServletContextListener#handleInitializationException()).
+ // Rack propagates exceptions if the properties jruby.rack.exception or jruby.rack.error are set to true.
+ // Unfortunately we didn't succeed in defining these properties, so the method is overridden here.
+ // Initial need: SONAR-6171
+ @Override
+ protected void handleInitializationException(Exception e, RackApplicationFactory factory, ServletRackContext rackContext) {
+ throw Throwables.propagate(e);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * This servlet filter sets response headers that enable browser protection against several classes if Web attacks.
+ * The list of headers is mirrored in environment.rb as a workaround to Rack swallowing the headers..
+ */
+public class SecurityServletFilter implements Filter {
+
+ private static final Set<String> ALLOWED_HTTP_METHODS = ImmutableSet.of("DELETE", "GET", "HEAD", "POST", "PUT");
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // nothing
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
+ doHttpFilter((HttpServletRequest) req, (HttpServletResponse) resp, chain);
+ }
+
+ private static void doHttpFilter(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain) throws IOException, ServletException {
+ // SONAR-6881 Disable OPTIONS and TRACE methods
+ if (!ALLOWED_HTTP_METHODS.contains(httpRequest.getMethod())) {
+ httpResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ return;
+ }
+
+ chain.doFilter(httpRequest, httpResponse);
+
+ // Clickjacking protection
+ // See https://www.owasp.org/index.php/Clickjacking_Protection_for_Java_EE
+ httpResponse.addHeader("X-Frame-Options", "SAMEORIGIN");
+
+ // Cross-site scripting
+ // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers
+ httpResponse.addHeader("X-XSS-Protection", "1; mode=block");
+
+ // MIME-sniffing
+ // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers
+ httpResponse.addHeader("X-Content-Type-Options", "nosniff");
+ }
+
+ @Override
+ public void destroy() {
+ // nothing
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.platform.web;
+
+import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.platform.PluginInfo;
import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.updatecenter.common.Release;
import org.sonar.updatecenter.common.UpdateCenter;
import org.sonar.updatecenter.common.Version;
private final File downloadDir;
public PluginDownloader(UpdateCenterMatrixFactory updateCenterMatrixFactory, HttpDownloader downloader,
- DefaultServerFileSystem fileSystem) {
+ ServerFileSystem fileSystem) {
this.updateCenterMatrixFactory = updateCenterMatrixFactory;
this.downloader = downloader;
this.downloadDir = fileSystem.getDownloadedPluginsDir();
import org.sonar.core.platform.ExplodedPlugin;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginJarExploder;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import static org.apache.commons.io.FileUtils.forceMkdir;
@ComputeEngineSide
public class ServerPluginJarExploder extends PluginJarExploder {
- private final DefaultServerFileSystem fs;
+ private final ServerFileSystem fs;
- public ServerPluginJarExploder(DefaultServerFileSystem fs) {
+ public ServerPluginJarExploder(ServerFileSystem fs) {
this.fs = fs;
}
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginLoader;
import org.sonar.core.platform.PluginRepository;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.updatecenter.common.Version;
import static com.google.common.base.Preconditions.checkArgument;
private static final String NOT_STARTED_YET = "not started yet";
private final Server server;
- private final DefaultServerFileSystem fs;
+ private final ServerFileSystem fs;
private final ServerUpgradeStatus upgradeStatus;
private final PluginLoader loader;
private final AtomicBoolean started = new AtomicBoolean(false);
private final Map<String, Plugin> pluginInstancesByKeys = new HashMap<>();
public ServerPluginRepository(Server server, ServerUpgradeStatus upgradeStatus,
- DefaultServerFileSystem fs, PluginLoader loader) {
+ ServerFileSystem fs, PluginLoader loader) {
this.server = server;
this.upgradeStatus = upgradeStatus;
this.fs = fs;
*/
package org.sonar.server.startup;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.CharUtils;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
import org.sonar.core.platform.RemotePlugin;
-import org.sonar.server.platform.DefaultServerFileSystem;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
+import org.sonar.server.platform.ServerFileSystem;
@ServerSide
public final class GeneratePluginIndex {
- private DefaultServerFileSystem fileSystem;
- private PluginRepository repository;
+ private final ServerFileSystem fileSystem;
+ private final PluginRepository repository;
- public GeneratePluginIndex(DefaultServerFileSystem fileSystem, PluginRepository repository) {
+ public GeneratePluginIndex(ServerFileSystem fileSystem, PluginRepository repository) {
this.fileSystem = fileSystem;
this.repository = repository;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.startup;
-
-import org.sonar.api.web.ServletFilter;
-import org.sonar.server.platform.MasterServletFilter;
-
-import javax.servlet.ServletException;
-
-import java.util.Arrays;
-
-/**
- * @since 3.5
- */
-public class RegisterServletFilters {
- private final ServletFilter[] filters;
-
- public RegisterServletFilters(ServletFilter[] filters) {
- this.filters = filters;
- }
-
- public RegisterServletFilters() {
- this(new ServletFilter[0]);
- }
-
- public void start() throws ServletException {
- if (MasterServletFilter.INSTANCE != null) {
- // Probably a database upgrade. MasterSlaveFilter was instantiated by the servlet container
- // while picocontainer was not completely up.
- // See https://jira.sonarsource.com/browse/SONAR-3612
- MasterServletFilter.INSTANCE.initFilters(Arrays.asList(filters));
- }
- }
-}
-
package org.sonar.server.updatecenter.ws;
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
-import static org.apache.commons.io.IOUtils.closeQuietly;
-import static org.sonar.api.server.ws.Request.Part;
-
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.server.user.UserSession;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+import static org.sonar.api.server.ws.Request.Part;
+
public class UploadAction implements UpdateCenterWsAction {
public static final String PARAM_FILE = "file";
private final UserSession userSession;
private final File downloadDir;
- public UploadAction(UserSession userSession, DefaultServerFileSystem fileSystem) {
+ public UploadAction(UserSession userSession, ServerFileSystem fileSystem) {
this.userSession = userSession;
this.downloadDir = fileSystem.getDownloadedPluginsDir();
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import javax.annotation.Nullable;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.CharEncoding;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.utils.log.Loggers;
+
+/**
+ * @since 3.0
+ */
+public class ClassLoaderUtils {
+
+ private ClassLoaderUtils() {
+ // only static methods
+ }
+
+ public static File copyResources(ClassLoader classLoader, String rootPath, File toDir, Function<String, String> relocationFunction) {
+ Collection<String> relativePaths = listFiles(classLoader, rootPath);
+ for (String relativePath : relativePaths) {
+ URL resource = classLoader.getResource(relativePath);
+ String filename = relocationFunction.apply(relativePath);
+ File toFile = new File(toDir, filename);
+ try {
+ FileUtils.copyURLToFile(resource, toFile);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to extract " + relativePath + " to " + toFile.getAbsolutePath(), e);
+ }
+ }
+
+ return toDir;
+ }
+
+ /**
+ * Finds files within a given directory and its subdirectories
+ *
+ * @param classLoader
+ * @param rootPath the root directory, for example org/sonar/sqale
+ * @return a list of relative paths, for example {"org/sonar/sqale/foo/bar.txt}. Never null.
+ */
+ public static Collection<String> listFiles(ClassLoader classLoader, String rootPath) {
+ return listResources(classLoader, rootPath, path -> !StringUtils.endsWith(path, "/"));
+ }
+
+ /**
+ * Finds directories and files within a given directory and its subdirectories.
+ *
+ * @param classLoader
+ * @param rootPath the root directory, for example org/sonar/sqale, or a file in this root directory, for example org/sonar/sqale/index.txt
+ * @param predicate
+ * @return a list of relative paths, for example {"org/sonar/sqale", "org/sonar/sqale/foo", "org/sonar/sqale/foo/bar.txt}. Never null.
+ */
+ public static Collection<String> listResources(ClassLoader classLoader, String rootPath, Predicate<String> predicate) {
+ String jarPath = null;
+ JarFile jar = null;
+ try {
+ Collection<String> paths = Lists.newArrayList();
+ URL root = classLoader.getResource(rootPath);
+ if (root != null) {
+ checkJarFile(root);
+
+ // Path of the root directory
+ // Examples :
+ // org/sonar/sqale/index.txt -> rootDirectory is org/sonar/sqale
+ // org/sonar/sqale/ -> rootDirectory is org/sonar/sqale
+ // org/sonar/sqale -> rootDirectory is org/sonar/sqale
+ String rootDirectory = rootPath;
+ if (StringUtils.substringAfterLast(rootPath, "/").indexOf('.') >= 0) {
+ rootDirectory = StringUtils.substringBeforeLast(rootPath, "/");
+ }
+ //strip out only the JAR file
+ jarPath = root.getPath().substring(5, root.getPath().indexOf('!'));
+ jar = new JarFile(URLDecoder.decode(jarPath, CharEncoding.UTF_8));
+ Enumeration<JarEntry> entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ String name = entries.nextElement().getName();
+ if (name.startsWith(rootDirectory) && predicate.apply(name)) {
+ paths.add(name);
+ }
+ }
+ }
+ return paths;
+ } catch (Exception e) {
+ throw Throwables.propagate(e);
+ } finally {
+ closeJar(jar, jarPath);
+ }
+ }
+
+ private static void closeJar(@Nullable JarFile jar, String jarPath) {
+ if (jar != null) {
+ try {
+ jar.close();
+ } catch (Exception e) {
+ Loggers.get(ClassLoaderUtils.class).error("Fail to close JAR file: " + jarPath, e);
+ }
+ }
+ }
+
+ private static void checkJarFile(URL root) {
+ if (!"jar".equals(root.getProtocol())) {
+ throw new IllegalStateException("Unsupported protocol: " + root.getProtocol());
+ }
+ }
+}
*/
package org.sonar.server.batch;
+import java.io.File;
+import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.CharUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.Server;
-
-import java.io.File;
-import java.io.IOException;
+import org.sonar.server.platform.ServerFileSystem;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Rule
public ExpectedException thrown = ExpectedException.none();
- File jar;
+ private File jar;
- Server server = mock(Server.class);
+ private ServerFileSystem fs = mock(ServerFileSystem.class);
@Before
public void prepare_fs() throws IOException {
- File rootDir = temp.newFolder();
- when(server.getRootDir()).thenReturn(rootDir);
+ File homeDir = temp.newFolder();
+ when(fs.getHomeDir()).thenReturn(homeDir);
- File batchDir = new File(rootDir, "lib/batch");
+ File batchDir = new File(homeDir, "lib/batch");
FileUtils.forceMkdir(batchDir);
jar = new File(batchDir, "sonar-batch.jar");
FileUtils.writeStringToFile(new File(batchDir, "sonar-batch.jar"), "foo");
@Test
public void get_index() {
- BatchIndex batchIndex = new BatchIndex(server);
+ BatchIndex batchIndex = new BatchIndex(fs);
batchIndex.start();
String index = batchIndex.getIndex();
@Test
public void get_file() {
- BatchIndex batchIndex = new BatchIndex(server);
+ BatchIndex batchIndex = new BatchIndex(fs);
batchIndex.start();
File file = batchIndex.getFile("sonar-batch.jar");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Bad filename: ../sonar-batch.jar");
- BatchIndex batchIndex = new BatchIndex(server);
+ BatchIndex batchIndex = new BatchIndex(fs);
batchIndex.start();
batchIndex.getFile("../sonar-batch.jar");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Bad filename: other.jar");
- BatchIndex batchIndex = new BatchIndex(server);
+ BatchIndex batchIndex = new BatchIndex(fs);
batchIndex.start();
batchIndex.getFile("other.jar");
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings;
-import org.sonar.api.platform.Server;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexDefinition;
import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
- IssueIndex issueIndex;
- IssueIndexer issueIndexer;
- IssueAuthorizationIndexer issueAuthorizationIndexer;
+ private IssueIndex issueIndex;
+ private IssueIndexer issueIndexer;
+ private IssueAuthorizationIndexer issueAuthorizationIndexer;
+ private ServerFileSystem fs = mock(ServerFileSystem.class);
WsTester tester;
issueAuthorizationIndexer = new IssueAuthorizationIndexer(null, es.client());
issuesAction = new IssuesAction(db.getDbClient(), issueIndex, userSessionRule, new ComponentFinder(db.getDbClient()));
- tester = new WsTester(new BatchWs(new BatchIndex(mock(Server.class)), issuesAction));
+ tester = new WsTester(new BatchWs(new BatchIndex(fs), issuesAction));
}
@Test
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings;
-import org.sonar.api.platform.Server;
import org.sonar.scanner.protocol.input.ScannerInput.User;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.index.UserDoc;
import org.sonar.server.user.index.UserIndex;
public void before() {
userIndex = new UserIndex(es.client());
usersAction = new UsersAction(userIndex, userSessionRule);
- tester = new WsTester(new BatchWs(new BatchIndex(mock(Server.class)), usersAction));
+ tester = new WsTester(new BatchWs(new BatchIndex(mock(ServerFileSystem.class)), usersAction));
}
@Test
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
+import org.sonar.server.util.ClassLoaderUtils;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItems;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.web.ServletFilter;
-
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class MasterServletFilterTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Before
- public void resetSingleton() {
- MasterServletFilter.INSTANCE = null;
- }
-
- @Test
- public void should_init_and_destroy_filters() throws Exception {
- ServletFilter filter = mock(ServletFilter.class);
- FilterConfig config = mock(FilterConfig.class);
- MasterServletFilter master = new MasterServletFilter();
- master.init(config, Arrays.asList(filter));
-
- assertThat(master.getFilters()).containsOnly(filter);
- verify(filter).init(config);
-
- master.destroy();
- verify(filter).destroy();
- }
-
- @Test
- public void servlet_container_should_instantiate_only_a_single_master_instance() {
- new MasterServletFilter();
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Servlet filter org.sonar.server.platform.MasterServletFilter is already instantiated");
- new MasterServletFilter();
- }
-
- @Test
- public void should_propagate_initialization_failure() throws Exception {
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("foo");
-
- ServletFilter filter = mock(ServletFilter.class);
- doThrow(new IllegalStateException("foo")).when(filter).init(any(FilterConfig.class));
-
- FilterConfig config = mock(FilterConfig.class);
- MasterServletFilter filters = new MasterServletFilter();
- filters.init(config, Arrays.asList(filter));
- }
-
- @Test
- public void filters_should_be_optional() throws Exception {
- FilterConfig config = mock(FilterConfig.class);
- MasterServletFilter filters = new MasterServletFilter();
- filters.init(config, Collections.<ServletFilter>emptyList());
-
- ServletRequest request = mock(HttpServletRequest.class);
- ServletResponse response = mock(HttpServletResponse.class);
- FilterChain chain = mock(FilterChain.class);
- filters.doFilter(request, response, chain);
-
- verify(chain).doFilter(request, response);
- }
-
- @Test
- public void should_keep_filter_ordering() throws Exception {
- TrueFilter filter1 = new TrueFilter();
- TrueFilter filter2 = new TrueFilter();
-
- MasterServletFilter filters = new MasterServletFilter();
- filters.init(mock(FilterConfig.class), Arrays.<ServletFilter>asList(filter1, filter2));
-
- HttpServletRequest request = mock(HttpServletRequest.class);
- when(request.getRequestURI()).thenReturn("/foo/bar");
- when(request.getContextPath()).thenReturn("");
- ServletResponse response = mock(HttpServletResponse.class);
- FilterChain chain = mock(FilterChain.class);
- filters.doFilter(request, response, chain);
-
- assertThat(filter1.count).isEqualTo(1);
- assertThat(filter2.count).isEqualTo(2);
- }
-
- private static final class TrueFilter extends ServletFilter {
- private static int globalCount = 0;
- private int count = 0;
-
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- globalCount++;
- count = globalCount;
- filterChain.doFilter(servletRequest, servletResponse);
- }
-
- public void destroy() {
- }
-
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ProfilingFilterTest {
-
- private ProfilingFilter filter;
- private FilterChain chain;
-
- @Before
- public void initialize() throws Exception {
- FilterConfig filterConfig = mock(FilterConfig.class);
- when(filterConfig.getInitParameter("staticDirs")).thenReturn("/static,/assets");
- ServletContext context = mock(ServletContext.class);
- when(context.getContextPath()).thenReturn("/context");
- when(filterConfig.getServletContext()).thenReturn(context);
- chain = mock(FilterChain.class);
-
- filter = new ProfilingFilter();
- filter.init(filterConfig);
- }
-
- @Test
- public void should_profile_service_call() throws Exception {
- filter.doFilter(request("POST", "/context/service/call", "param=value"), null, chain);
- }
-
- @Test
- public void should_profile_service() throws Exception {
- filter.doFilter(request("POST", "/context/service", null), null, chain);
- }
-
- @Test
- public void should_profile_context_root_as_slash2() throws Exception {
- filter.doFilter(request("POST", "/context", null), null, chain);
- }
-
- @Test(expected = ServletException.class)
- public void should_profile_even_when_exception() throws Exception {
- Mockito.doThrow(new ServletException()).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
- filter.doFilter(request("POST", "/context/service/call", "param=value"), null, chain);
- }
-
- @Test
- public void should_not_profile_non_http_request() throws Exception {
- filter.doFilter(mock(ServletRequest.class), null, chain);
- }
-
- @Test
- public void should_not_profile_static_resource() throws Exception {
- filter.doFilter(request("GET", "/context/static/image.png", null), null, chain);
- }
-
- @Test
- public void should_profile_static_resource_if_no_config() throws Exception {
- FilterConfig filterConfig = mock(FilterConfig.class);
- ServletContext context = mock(ServletContext.class);
- when(context.getContextPath()).thenReturn("/context");
- when(filterConfig.getServletContext()).thenReturn(context);
-
- filter.init(filterConfig);
- filter.doFilter(request("GET", "/context/static/image.png", null), null, chain);
- }
-
- private HttpServletRequest request(String method, String path, String query) {
- HttpServletRequest request = mock(HttpServletRequest.class);
- when(request.getMethod()).thenReturn(method);
- when(request.getRequestURI()).thenReturn(path);
- when(request.getQueryString()).thenReturn(query);
- return request;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.ServerFileSystem;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-
-import java.io.File;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Collections;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class RailsAppsDeployerTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void hasRubyRailsApp() throws Exception {
- ClassLoader classLoader = new URLClassLoader(new URL[]{
- getClass().getResource("/org/sonar/server/platform/RailsAppsDeployerTest/FakeRubyRailsApp.jar").toURI().toURL()}, null);
-
- assertTrue(RailsAppsDeployer.hasRailsApp("fake", classLoader));
- assertFalse(RailsAppsDeployer.hasRailsApp("other", classLoader));
- }
-
- @Test
- public void deployRubyRailsApp() throws Exception {
- File tempDir = this.temp.getRoot();
- ClassLoader classLoader = new URLClassLoader(new URL[]{
- getClass().getResource("/org/sonar/server/platform/RailsAppsDeployerTest/FakeRubyRailsApp.jar").toURI().toURL()}, null);
-
- RailsAppsDeployer.deployRailsApp(tempDir, "fake", classLoader);
-
- File appDir = new File(tempDir, "fake");
- assertThat(appDir.isDirectory(), is(true));
- assertThat(appDir.exists(), is(true));
- assertThat(FileUtils.listFiles(appDir, null, true).size(), is(3));
- assertThat(new File(appDir, "init.rb").exists(), is(true));
- assertThat(new File(appDir, "app/controllers/fake_controller.rb").exists(), is(true));
- assertThat(new File(appDir, "app/views/fake/index.html.erb").exists(), is(true));
- }
-
- @Test
- public void deployRubyRailsApps_no_apps() {
- ServerFileSystem fileSystem = mock(ServerFileSystem.class);
- File tempDir = this.temp.getRoot();
- when(fileSystem.getTempDir()).thenReturn(tempDir);
-
- PluginRepository pluginRepository = mock(PluginRepository.class);
- when(pluginRepository.getPluginInfos()).thenReturn(Collections.<PluginInfo>emptyList());
- new RailsAppsDeployer(fileSystem, pluginRepository).start();
-
- File appDir = new File(tempDir, "ror");
- assertThat(appDir.isDirectory(), is(true));
- assertThat(appDir.exists(), is(true));
- assertThat(FileUtils.listFiles(appDir, null, true).size(), is(0));
- }
-
- @Test
- public void prepareRubyRailsRootDirectory() throws Exception {
- ServerFileSystem fileSystem = mock(ServerFileSystem.class);
- File tempDir = this.temp.getRoot();
- when(fileSystem.getTempDir()).thenReturn(tempDir);
-
- File dir = new RailsAppsDeployer(fileSystem, mock(PluginRepository.class)).prepareRailsDirectory();
-
- assertThat(dir.isDirectory(), is(true));
- assertThat(dir.exists(), is(true));
- assertThat(dir.getCanonicalPath(), is(new File(tempDir, "ror").getCanonicalPath()));
- }
-
- @Test
- public void prepareRubyRailsRootDirectory_delete_existing_dir() throws Exception {
- ServerFileSystem fileSystem = mock(ServerFileSystem.class);
- File tempDir = this.temp.getRoot();
- when(fileSystem.getTempDir()).thenReturn(tempDir);
-
- File file = new File(tempDir, "ror/foo/bar.txt");
- FileUtils.writeStringToFile(file, "foooo");
-
- File dir = new RailsAppsDeployer(fileSystem, mock(PluginRepository.class)).prepareRailsDirectory();
-
- assertThat(dir.isDirectory(), is(true));
- assertThat(dir.exists(), is(true));
- assertThat(dir.getCanonicalPath(), is(new File(tempDir, "ror").getCanonicalPath()));
- assertThat(FileUtils.listFiles(new File(tempDir, "ror"), null, true).size(), is(0));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-package org.sonar.server.platform;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import javax.servlet.FilterChain;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.junit.Before;
-import org.junit.Test;
-
-public class RoutesFilterTest {
-
- HttpServletRequest request = mock(HttpServletRequest.class);
- HttpServletResponse response = mock(HttpServletResponse.class);
- FilterChain chain = mock(FilterChain.class);
-
- RoutesFilter underTest = new RoutesFilter();
-
- @Before
- public void setUp() throws Exception {
- when(request.getContextPath()).thenReturn("/sonarqube");
- }
-
- @Test
- public void send_redirect_when_url_contains_batch_with_jar() throws Exception {
- when(request.getRequestURI()).thenReturn("/batch/file.jar");
-
- underTest.doFilter(request, response, chain);
-
- verify(response).sendRedirect("/sonarqube/batch/file?name=file.jar");
- verifyZeroInteractions(chain);
- }
-
- @Test
- public void send_redirect_when_url_contains_batch_bootstrap() throws Exception {
- when(request.getRequestURI()).thenReturn("/batch_bootstrap/index");
-
- underTest.doFilter(request, response, chain);
-
- verify(response).sendRedirect("/sonarqube/batch/index");
- verifyZeroInteractions(chain);
- }
-
- @Test
- public void send_redirect_when_url_contains_api_sources() throws Exception {
- when(request.getRequestURI()).thenReturn("/api/sources");
- when(request.getQueryString()).thenReturn("resource=my.project");
-
- underTest.doFilter(request, response, chain);
-
- verify(response).sendRedirect("/sonarqube/api/sources/index?resource=my.project");
- verifyZeroInteractions(chain);
- }
-
- @Test
- public void does_not_redirect_and_execute_remaining_filter_on_unknown_path() throws Exception {
- when(request.getRequestURI()).thenReturn("/api/issues/search");
-
- underTest.doFilter(request, response, chain);
-
- verify(chain).doFilter(request, response);
- verifyZeroInteractions(response);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import java.io.IOException;
-import javax.servlet.ServletContextEvent;
-import org.jruby.rack.RackApplicationFactory;
-import org.jruby.rack.servlet.ServletRackContext;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.Mockito;
-
-import static java.lang.Boolean.TRUE;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class RubyRailsContextListenerTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- ServletContextEvent event = mock(ServletContextEvent.class, Mockito.RETURNS_DEEP_STUBS);
- RubyRailsContextListener underTest = new RubyRailsContextListener();
-
- @Test
- public void do_not_initialize_rails_if_error_during_startup() {
- when(event.getServletContext().getAttribute(PlatformServletContextListener.STARTED_ATTRIBUTE)).thenReturn(null);
-
- underTest.contextInitialized(event);
-
- verify(event.getServletContext(), never()).setAttribute(anyString(), anyObject());
- }
-
- @Test
- public void initialize_rails_if_no_errors_during_startup() {
- when(event.getServletContext().getAttribute(PlatformServletContextListener.STARTED_ATTRIBUTE)).thenReturn(TRUE);
- underTest.contextInitialized(event);
- // Ruby environment is started
- // See RailsServletContextListener -> RackServletContextListener
- verify(event.getServletContext()).setAttribute(eq("rack.factory"), anyObject());
- }
-
- @Test
- public void always_propagates_initialization_errors() {
- expectedException.expect(RuntimeException.class);
-
- underTest.handleInitializationException(new IOException(), mock(RackApplicationFactory.class), mock(ServletRackContext.class));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.junit.Test;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.startsWith;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class SecurityServletFilterTest {
-
- SecurityServletFilter underTest = new SecurityServletFilter();
- HttpServletResponse response = mock(HttpServletResponse.class);
- FilterChain chain = mock(FilterChain.class);
-
- @Test
- public void allow_GET_method() throws IOException, ServletException {
- assertThatMethodIsAllowed("GET");
- }
-
- @Test
- public void allow_HEAD_method() throws IOException, ServletException {
- assertThatMethodIsAllowed("HEAD");
- }
-
- @Test
- public void allow_PUT_method() throws IOException, ServletException {
- assertThatMethodIsAllowed("PUT");
- }
-
- @Test
- public void allow_POST_method() throws IOException, ServletException {
- assertThatMethodIsAllowed("POST");
- }
-
- private void assertThatMethodIsAllowed(String httpMethod) throws IOException, ServletException {
- HttpServletRequest request = newRequest(httpMethod);
- underTest.doFilter(request, response, chain);
- verify(response, never()).setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
- verify(chain).doFilter(request, response);
- }
-
- @Test
- public void deny_OPTIONS_method() throws IOException, ServletException {
- assertThatMethodIsDenied("OPTIONS");
- }
-
- @Test
- public void deny_TRACE_method() throws IOException, ServletException {
- assertThatMethodIsDenied("TRACE");
- }
-
- private void assertThatMethodIsDenied(String httpMethod) throws IOException, ServletException {
- underTest.doFilter(newRequest(httpMethod), response, chain);
- verify(response).setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- @Test
- public void set_secured_headers() throws ServletException, IOException {
- underTest.init(mock(FilterConfig.class));
- HttpServletRequest request = newRequest("GET");
-
- underTest.doFilter(request, response, chain);
-
- verify(response, times(3)).addHeader(startsWith("X-"), anyString());
-
- underTest.destroy();
- }
-
- private HttpServletRequest newRequest(String httpMethod) {
- HttpServletRequest req = mock(HttpServletRequest.class);
- when(req.getMethod()).thenReturn(httpMethod);
- return req;
- }
-}
*/
package org.sonar.server.platform;
+import java.io.File;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.ServerFileSystem;
import org.sonar.api.utils.TempFolder;
-import java.io.File;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
package org.sonar.server.platform.cluster;
import org.junit.Rule;
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
package org.sonar.server.platform.cluster;
public class ClusterMock implements Cluster {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import java.io.IOException;
+import java.util.Collections;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.web.ServletFilter;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MasterServletFilterTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void resetSingleton() {
+ MasterServletFilter.INSTANCE = null;
+ }
+
+ @Test
+ public void should_init_and_destroy_filters() throws Exception {
+ ServletFilter filter = mock(ServletFilter.class);
+ FilterConfig config = mock(FilterConfig.class);
+ MasterServletFilter master = new MasterServletFilter();
+ master.init(config, singletonList(filter));
+
+ assertThat(master.getFilters()).containsOnly(filter);
+ verify(filter).init(config);
+
+ master.destroy();
+ verify(filter).destroy();
+ }
+
+ @Test
+ public void servlet_container_should_instantiate_only_a_single_master_instance() {
+ new MasterServletFilter();
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Servlet filter org.sonar.server.platform.web.MasterServletFilter is already instantiated");
+ new MasterServletFilter();
+ }
+
+ @Test
+ public void should_propagate_initialization_failure() throws Exception {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("foo");
+
+ ServletFilter filter = mock(ServletFilter.class);
+ doThrow(new IllegalStateException("foo")).when(filter).init(any(FilterConfig.class));
+
+ FilterConfig config = mock(FilterConfig.class);
+ MasterServletFilter filters = new MasterServletFilter();
+ filters.init(config, singletonList(filter));
+ }
+
+ @Test
+ public void filters_should_be_optional() throws Exception {
+ FilterConfig config = mock(FilterConfig.class);
+ MasterServletFilter filters = new MasterServletFilter();
+ filters.init(config, Collections.emptyList());
+
+ ServletRequest request = mock(HttpServletRequest.class);
+ ServletResponse response = mock(HttpServletResponse.class);
+ FilterChain chain = mock(FilterChain.class);
+ filters.doFilter(request, response, chain);
+
+ verify(chain).doFilter(request, response);
+ }
+
+ @Test
+ public void should_keep_filter_ordering() throws Exception {
+ TrueFilter filter1 = new TrueFilter();
+ TrueFilter filter2 = new TrueFilter();
+
+ MasterServletFilter filters = new MasterServletFilter();
+ filters.init(mock(FilterConfig.class), asList(filter1, filter2));
+
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getRequestURI()).thenReturn("/foo/bar");
+ when(request.getContextPath()).thenReturn("");
+ ServletResponse response = mock(HttpServletResponse.class);
+ FilterChain chain = mock(FilterChain.class);
+ filters.doFilter(request, response, chain);
+
+ assertThat(filter1.count).isEqualTo(1);
+ assertThat(filter2.count).isEqualTo(2);
+ }
+
+ private static final class TrueFilter extends ServletFilter {
+ private static int globalCount = 0;
+ private int count = 0;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ globalCount++;
+ count = globalCount;
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ public void destroy() {
+ }
+
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.sonar.server.platform.web.ProfilingFilter;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ProfilingFilterTest {
+
+ private ProfilingFilter filter;
+ private FilterChain chain;
+
+ @Before
+ public void initialize() throws Exception {
+ FilterConfig filterConfig = mock(FilterConfig.class);
+ when(filterConfig.getInitParameter("staticDirs")).thenReturn("/static,/assets");
+ ServletContext context = mock(ServletContext.class);
+ when(context.getContextPath()).thenReturn("/context");
+ when(filterConfig.getServletContext()).thenReturn(context);
+ chain = mock(FilterChain.class);
+
+ filter = new ProfilingFilter();
+ filter.init(filterConfig);
+ }
+
+ @Test
+ public void should_profile_service_call() throws Exception {
+ filter.doFilter(request("POST", "/context/service/call", "param=value"), null, chain);
+ }
+
+ @Test
+ public void should_profile_service() throws Exception {
+ filter.doFilter(request("POST", "/context/service", null), null, chain);
+ }
+
+ @Test
+ public void should_profile_context_root_as_slash2() throws Exception {
+ filter.doFilter(request("POST", "/context", null), null, chain);
+ }
+
+ @Test(expected = ServletException.class)
+ public void should_profile_even_when_exception() throws Exception {
+ Mockito.doThrow(new ServletException()).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
+ filter.doFilter(request("POST", "/context/service/call", "param=value"), null, chain);
+ }
+
+ @Test
+ public void should_not_profile_non_http_request() throws Exception {
+ filter.doFilter(mock(ServletRequest.class), null, chain);
+ }
+
+ @Test
+ public void should_not_profile_static_resource() throws Exception {
+ filter.doFilter(request("GET", "/context/static/image.png", null), null, chain);
+ }
+
+ @Test
+ public void should_profile_static_resource_if_no_config() throws Exception {
+ FilterConfig filterConfig = mock(FilterConfig.class);
+ ServletContext context = mock(ServletContext.class);
+ when(context.getContextPath()).thenReturn("/context");
+ when(filterConfig.getServletContext()).thenReturn(context);
+
+ filter.init(filterConfig);
+ filter.doFilter(request("GET", "/context/static/image.png", null), null, chain);
+ }
+
+ private HttpServletRequest request(String method, String path, String query) {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getMethod()).thenReturn(method);
+ when(request.getRequestURI()).thenReturn(path);
+ when(request.getQueryString()).thenReturn(query);
+ return request;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.server.platform.ServerFileSystem;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RailsAppsDeployerTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void hasRubyRailsApp() throws Exception {
+ ClassLoader classLoader = new URLClassLoader(new URL[]{
+ getClass().getResource("/org/sonar/server/platform/web/RailsAppsDeployerTest/FakeRubyRailsApp.jar").toURI().toURL()}, null);
+
+ assertTrue(RailsAppsDeployer.hasRailsApp("fake", classLoader));
+ assertFalse(RailsAppsDeployer.hasRailsApp("other", classLoader));
+ }
+
+ @Test
+ public void deployRubyRailsApp() throws Exception {
+ File tempDir = this.temp.getRoot();
+ ClassLoader classLoader = new URLClassLoader(new URL[]{
+ getClass().getResource("/org/sonar/server/platform/web/RailsAppsDeployerTest/FakeRubyRailsApp.jar").toURI().toURL()}, null);
+
+ RailsAppsDeployer.deployRailsApp(tempDir, "fake", classLoader);
+
+ File appDir = new File(tempDir, "fake");
+ assertThat(appDir.isDirectory(), is(true));
+ assertThat(appDir.exists(), is(true));
+ assertThat(FileUtils.listFiles(appDir, null, true).size(), is(3));
+ assertThat(new File(appDir, "init.rb").exists(), is(true));
+ assertThat(new File(appDir, "app/controllers/fake_controller.rb").exists(), is(true));
+ assertThat(new File(appDir, "app/views/fake/index.html.erb").exists(), is(true));
+ }
+
+ @Test
+ public void deployRubyRailsApps_no_apps() {
+ ServerFileSystem fileSystem = mock(ServerFileSystem.class);
+ File tempDir = this.temp.getRoot();
+ when(fileSystem.getTempDir()).thenReturn(tempDir);
+
+ PluginRepository pluginRepository = mock(PluginRepository.class);
+ when(pluginRepository.getPluginInfos()).thenReturn(Collections.emptyList());
+ new RailsAppsDeployer(fileSystem, pluginRepository).start();
+
+ File appDir = new File(tempDir, "ror");
+ assertThat(appDir.isDirectory(), is(true));
+ assertThat(appDir.exists(), is(true));
+ assertThat(FileUtils.listFiles(appDir, null, true).size(), is(0));
+ }
+
+ @Test
+ public void prepareRubyRailsRootDirectory() throws Exception {
+ ServerFileSystem fileSystem = mock(ServerFileSystem.class);
+ File tempDir = this.temp.getRoot();
+ when(fileSystem.getTempDir()).thenReturn(tempDir);
+
+ File dir = new RailsAppsDeployer(fileSystem, mock(PluginRepository.class)).prepareRailsDirectory();
+
+ assertThat(dir.isDirectory(), is(true));
+ assertThat(dir.exists(), is(true));
+ assertThat(dir.getCanonicalPath(), is(new File(tempDir, "ror").getCanonicalPath()));
+ }
+
+ @Test
+ public void prepareRubyRailsRootDirectory_delete_existing_dir() throws Exception {
+ ServerFileSystem fileSystem = mock(ServerFileSystem.class);
+ File tempDir = this.temp.getRoot();
+ when(fileSystem.getTempDir()).thenReturn(tempDir);
+
+ File file = new File(tempDir, "ror/foo/bar.txt");
+ FileUtils.writeStringToFile(file, "foooo");
+
+ File dir = new RailsAppsDeployer(fileSystem, mock(PluginRepository.class)).prepareRailsDirectory();
+
+ assertThat(dir.isDirectory(), is(true));
+ assertThat(dir.exists(), is(true));
+ assertThat(dir.getCanonicalPath(), is(new File(tempDir, "ror").getCanonicalPath()));
+ assertThat(FileUtils.listFiles(new File(tempDir, "ror"), null, true).size(), is(0));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.platform.web;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.server.platform.web.RoutesFilter;
+
+public class RoutesFilterTest {
+
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ HttpServletResponse response = mock(HttpServletResponse.class);
+ FilterChain chain = mock(FilterChain.class);
+
+ RoutesFilter underTest = new RoutesFilter();
+
+ @Before
+ public void setUp() throws Exception {
+ when(request.getContextPath()).thenReturn("/sonarqube");
+ }
+
+ @Test
+ public void send_redirect_when_url_contains_batch_with_jar() throws Exception {
+ when(request.getRequestURI()).thenReturn("/batch/file.jar");
+
+ underTest.doFilter(request, response, chain);
+
+ verify(response).sendRedirect("/sonarqube/batch/file?name=file.jar");
+ verifyZeroInteractions(chain);
+ }
+
+ @Test
+ public void send_redirect_when_url_contains_batch_bootstrap() throws Exception {
+ when(request.getRequestURI()).thenReturn("/batch_bootstrap/index");
+
+ underTest.doFilter(request, response, chain);
+
+ verify(response).sendRedirect("/sonarqube/batch/index");
+ verifyZeroInteractions(chain);
+ }
+
+ @Test
+ public void send_redirect_when_url_contains_api_sources() throws Exception {
+ when(request.getRequestURI()).thenReturn("/api/sources");
+ when(request.getQueryString()).thenReturn("resource=my.project");
+
+ underTest.doFilter(request, response, chain);
+
+ verify(response).sendRedirect("/sonarqube/api/sources/index?resource=my.project");
+ verifyZeroInteractions(chain);
+ }
+
+ @Test
+ public void does_not_redirect_and_execute_remaining_filter_on_unknown_path() throws Exception {
+ when(request.getRequestURI()).thenReturn("/api/issues/search");
+
+ underTest.doFilter(request, response, chain);
+
+ verify(chain).doFilter(request, response);
+ verifyZeroInteractions(response);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import java.io.IOException;
+import javax.servlet.ServletContextEvent;
+import org.jruby.rack.RackApplicationFactory;
+import org.jruby.rack.servlet.ServletRackContext;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+import org.sonar.server.platform.web.PlatformServletContextListener;
+import org.sonar.server.platform.web.RubyRailsContextListener;
+
+import static java.lang.Boolean.TRUE;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class RubyRailsContextListenerTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ ServletContextEvent event = mock(ServletContextEvent.class, Mockito.RETURNS_DEEP_STUBS);
+ RubyRailsContextListener underTest = new RubyRailsContextListener();
+
+ @Test
+ public void do_not_initialize_rails_if_error_during_startup() {
+ when(event.getServletContext().getAttribute(PlatformServletContextListener.STARTED_ATTRIBUTE)).thenReturn(null);
+
+ underTest.contextInitialized(event);
+
+ verify(event.getServletContext(), never()).setAttribute(anyString(), anyObject());
+ }
+
+ @Test
+ public void initialize_rails_if_no_errors_during_startup() {
+ when(event.getServletContext().getAttribute(PlatformServletContextListener.STARTED_ATTRIBUTE)).thenReturn(TRUE);
+ underTest.contextInitialized(event);
+ // Ruby environment is started
+ // See RailsServletContextListener -> RackServletContextListener
+ verify(event.getServletContext()).setAttribute(eq("rack.factory"), anyObject());
+ }
+
+ @Test
+ public void always_propagates_initialization_errors() {
+ expectedException.expect(RuntimeException.class);
+
+ underTest.handleInitializationException(new IOException(), mock(RackApplicationFactory.class), mock(ServletRackContext.class));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.web;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Test;
+import org.sonar.server.platform.web.SecurityServletFilter;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.startsWith;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SecurityServletFilterTest {
+
+ SecurityServletFilter underTest = new SecurityServletFilter();
+ HttpServletResponse response = mock(HttpServletResponse.class);
+ FilterChain chain = mock(FilterChain.class);
+
+ @Test
+ public void allow_GET_method() throws IOException, ServletException {
+ assertThatMethodIsAllowed("GET");
+ }
+
+ @Test
+ public void allow_HEAD_method() throws IOException, ServletException {
+ assertThatMethodIsAllowed("HEAD");
+ }
+
+ @Test
+ public void allow_PUT_method() throws IOException, ServletException {
+ assertThatMethodIsAllowed("PUT");
+ }
+
+ @Test
+ public void allow_POST_method() throws IOException, ServletException {
+ assertThatMethodIsAllowed("POST");
+ }
+
+ private void assertThatMethodIsAllowed(String httpMethod) throws IOException, ServletException {
+ HttpServletRequest request = newRequest(httpMethod);
+ underTest.doFilter(request, response, chain);
+ verify(response, never()).setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ verify(chain).doFilter(request, response);
+ }
+
+ @Test
+ public void deny_OPTIONS_method() throws IOException, ServletException {
+ assertThatMethodIsDenied("OPTIONS");
+ }
+
+ @Test
+ public void deny_TRACE_method() throws IOException, ServletException {
+ assertThatMethodIsDenied("TRACE");
+ }
+
+ private void assertThatMethodIsDenied(String httpMethod) throws IOException, ServletException {
+ underTest.doFilter(newRequest(httpMethod), response, chain);
+ verify(response).setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ }
+
+ @Test
+ public void set_secured_headers() throws ServletException, IOException {
+ underTest.init(mock(FilterConfig.class));
+ HttpServletRequest request = newRequest("GET");
+
+ underTest.doFilter(request, response, chain);
+
+ verify(response, times(3)).addHeader(startsWith("X-"), anyString());
+
+ underTest.destroy();
+ }
+
+ private HttpServletRequest newRequest(String httpMethod) {
+ HttpServletRequest req = mock(HttpServletRequest.class);
+ when(req.getMethod()).thenReturn(httpMethod);
+ return req;
+ }
+}
import org.sonar.api.utils.SonarException;
import org.sonar.core.platform.PluginInfo;
import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.Release;
import org.sonar.updatecenter.common.UpdateCenter;
}
}).when(httpDownloader).download(any(URI.class), any(File.class));
- DefaultServerFileSystem defaultServerFileSystem = mock(DefaultServerFileSystem.class);
+ ServerFileSystem fs = mock(ServerFileSystem.class);
downloadDir = testFolder.newFolder("downloads");
- when(defaultServerFileSystem.getDownloadedPluginsDir()).thenReturn(downloadDir);
+ when(fs.getDownloadedPluginsDir()).thenReturn(downloadDir);
- pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, defaultServerFileSystem);
+ pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, fs);
}
@After
@Test
public void throw_exception_if_download_dir_is_invalid() throws Exception {
- DefaultServerFileSystem defaultServerFileSystem = mock(DefaultServerFileSystem.class);
+ ServerFileSystem fs = mock(ServerFileSystem.class);
// download dir is a file instead of being a directory
File downloadDir = testFolder.newFile();
- when(defaultServerFileSystem.getDownloadedPluginsDir()).thenReturn(downloadDir);
+ when(fs.getDownloadedPluginsDir()).thenReturn(downloadDir);
- pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, defaultServerFileSystem);
+ pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, fs);
try {
pluginDownloader.start();
fail();
*/
package org.sonar.server.plugins;
+import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.ExplodedPlugin;
-import org.sonar.server.platform.DefaultServerFileSystem;
-
-import java.io.File;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.server.platform.ServerFileSystem;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- DefaultServerFileSystem fs = mock(DefaultServerFileSystem.class);
+ ServerFileSystem fs = mock(ServerFileSystem.class);
ServerPluginJarExploder underTest = new ServerPluginJarExploder(fs);
@Test
import org.sonar.api.utils.log.LogTester;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginLoader;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.updatecenter.common.Version;
import static org.assertj.core.api.Assertions.assertThat;
Server server = mock(Server.class);
ServerUpgradeStatus upgradeStatus = mock(ServerUpgradeStatus.class);
- DefaultServerFileSystem fs = mock(DefaultServerFileSystem.class, Mockito.RETURNS_DEEP_STUBS);
+ ServerFileSystem fs = mock(ServerFileSystem.class, Mockito.RETURNS_DEEP_STUBS);
PluginLoader pluginLoader = mock(PluginLoader.class);
ServerPluginRepository underTest = new ServerPluginRepository(server, upgradeStatus, fs, pluginLoader);
underTest.getPluginInfos();
}
-
+
private File copyTestPluginTo(String testPluginName, File toDir) throws IOException {
File jar = TestProjectUtils.jarOf(testPluginName);
// file is copied because it's supposed to be moved by the test
*/
package org.sonar.server.startup;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
import org.apache.commons.io.FileUtils;
import org.hamcrest.core.Is;
import org.junit.Before;
import org.junit.rules.TemporaryFolder;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
-import org.sonar.server.platform.DefaultServerFileSystem;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
+import org.sonar.server.platform.ServerFileSystem;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.containsString;
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- DefaultServerFileSystem fileSystem;
- File index;
+ private ServerFileSystem fileSystem = mock(ServerFileSystem.class);
+ private File underTest;
@Before
public void createIndexFile() {
- fileSystem = mock(DefaultServerFileSystem.class);
- index = new File("target/test-tmp/GeneratePluginIndexTest/plugins.txt");
- when(fileSystem.getPluginIndex()).thenReturn(index);
+ when(fileSystem.getPluginIndex()).thenReturn(underTest);
+ underTest = new File("target/test-tmp/GeneratePluginIndexTest/plugins.txt");
}
@Test
new GeneratePluginIndex(fileSystem, repository).start();
- List<String> lines = FileUtils.readLines(index);
+ List<String> lines = FileUtils.readLines(underTest);
assertThat(lines.size(), Is.is(2));
assertThat(lines.get(0), containsString("sqale"));
assertThat(lines.get(1), containsString("checkstyle"));
import org.junit.Test;
import org.sonar.api.web.ServletFilter;
-import org.sonar.server.platform.MasterServletFilter;
+import org.sonar.server.platform.web.MasterServletFilter;
import javax.servlet.ServletException;
+import org.sonar.server.platform.web.RegisterServletFilters;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Mockito.mock;
*/
package org.sonar.server.updatecenter.ws;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.server.ws.RailsHandler;
import org.sonar.api.server.ws.WebService;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.server.ws.WsTester;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
public class UpdateCenterWsTest {
WsTester tester;
@Before
public void setUp() {
tester = new WsTester(new UpdateCenterWs(
- new UploadAction(null, mock(DefaultServerFileSystem.class))));
+ new UploadAction(null, mock(ServerFileSystem.class))));
}
@Test
package org.sonar.server.updatecenter.ws;
-import static java.nio.file.Files.newInputStream;
-import static org.assertj.core.api.Java6Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
-import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
-import static org.sonar.test.ExceptionCauseMatcher.hasType;
-
import java.io.File;
import java.io.InputStream;
import java.nio.channels.ClosedChannelException;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.server.platform.ServerFileSystem;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
+import static java.nio.file.Files.newInputStream;
+import static org.assertj.core.api.Java6Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.test.ExceptionCauseMatcher.hasType;
+
public class UploadActionTest {
static final String PLUGIN_NAME = "plugin.jar";
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
- DefaultServerFileSystem fileSystem = mock(DefaultServerFileSystem.class);
+ ServerFileSystem fileSystem = mock(ServerFileSystem.class);
File pluginDirectory;
File plugin = new File(getClass().getResource("UploadActionTest/plugin.jar").getFile());
<filter>
<filter-name>ServletFilters</filter-name>
- <filter-class>org.sonar.server.platform.MasterServletFilter</filter-class>
+ <filter-class>org.sonar.server.platform.web.MasterServletFilter</filter-class>
</filter>
<filter>
<filter-name>UserSessionFilter</filter-name>
</filter>
<filter>
<filter-name>SecurityFilter</filter-name>
- <filter-class>org.sonar.server.platform.SecurityServletFilter</filter-class>
+ <filter-class>org.sonar.server.platform.web.SecurityServletFilter</filter-class>
</filter>
<filter>
<filter-name>ProfilingFilter</filter-name>
- <filter-class>org.sonar.server.platform.ProfilingFilter</filter-class>
+ <filter-class>org.sonar.server.platform.web.ProfilingFilter</filter-class>
<init-param>
<param-name>staticDirs</param-name>
<param-value>/images,/javascripts,/stylesheets</param-value>
</filter>
<filter>
<filter-name>RoutesFilter</filter-name>
- <filter-class>org.sonar.server.platform.RoutesFilter</filter-class>
+ <filter-class>org.sonar.server.platform.web.RoutesFilter</filter-class>
</filter>
<!-- order of execution is important -->
</session-config>
<listener>
- <listener-class>org.sonar.server.platform.PlatformServletContextListener</listener-class>
+ <listener-class>org.sonar.server.platform.web.PlatformServletContextListener</listener-class>
</listener>
<listener>
- <listener-class>org.sonar.server.platform.RubyRailsContextListener</listener-class>
+ <listener-class>org.sonar.server.platform.web.RubyRailsContextListener</listener-class>
</listener>
<mime-mapping>
@ComputeEngineSide
public interface ServerFileSystem {
+ /**
+ * Root directory of the server installation
+ * @return an existing directory
+ */
File getHomeDir();
+ /**
+ * Temporary directory, clean up on restarts
+ * @return an existing directory
+ */
File getTempDir();
}