allow user to specify whether to use dav:// or webdav:// scheme for Linux GVFS mounts. Fixes #307

This commit is contained in:
Sebastian Stenzel
2016-07-25 10:08:21 +02:00
parent a8ad335aed
commit f071efe1b9
21 changed files with 245 additions and 154 deletions
@@ -45,7 +45,7 @@ class WebDavFrontend implements Frontend {
@Override
public void mount(Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
mount = webdavMounterProvider.get().mount(uri, mountParams);
mount = webdavMounterProvider.chooseMounter(mountParams).mount(uri, mountParams);
}
@Override
@@ -0,0 +1,11 @@
package org.cryptomator.frontend.webdav;
import org.cryptomator.common.CommonsModule;
import org.cryptomator.frontend.webdav.mount.WebDavMounterModule;
import dagger.Module;
@Module(includes = {CommonsModule.class, WebDavMounterModule.class})
public class WebDavModule {
}
@@ -23,7 +23,7 @@ import org.cryptomator.frontend.Frontend.MountParam;
final class FallbackWebDavMounter implements WebDavMounterStrategy {
@Override
public boolean shouldWork() {
public boolean shouldWork(Map<MountParam, Optional<String>> mountParams) {
return true;
}
@@ -0,0 +1,94 @@
/*******************************************************************************
* Copyright (c) 2014, 2016 Sebastian Stenzel, Markus Kreusch
* This file is licensed under the terms of the MIT license.
* See the LICENSE.txt file for more info.
*
* Contributors:
* Sebastian Stenzel - initial API and implementation
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
* Mohit Raju - Added fallback schema-name "webdav" when opening file managers
******************************************************************************/
package org.cryptomator.frontend.webdav.mount;
import java.net.URI;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.frontend.CommandFailedException;
import org.cryptomator.frontend.Frontend.MountParam;
import org.cryptomator.frontend.webdav.mount.command.Script;
@Singleton
final class LinuxGvfsDavMounter implements WebDavMounterStrategy {
@Inject
LinuxGvfsDavMounter() {
}
@Override
public boolean shouldWork(Map<MountParam, Optional<String>> mountParams) {
if (SystemUtils.IS_OS_LINUX) {
Optional<String> prefScheme = mountParams.getOrDefault(MountParam.PREFERRED_GVFS_SCHEME, Optional.empty());
boolean prefSchemeIsUnspecifiedOrDav = !prefScheme.isPresent() || prefScheme.get().equalsIgnoreCase("dav");
final Script checkScripts = Script.fromLines("which gvfs-mount xdg-open");
try {
checkScripts.execute();
return prefSchemeIsUnspecifiedOrDav;
} catch (CommandFailedException e) {
return false;
}
} else {
return false;
}
}
@Override
public void warmUp(int serverPort) {
// no-op
}
@Override
public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
final Script mountScript = Script.fromLines("set -x", "gvfs-mount \"dav:$DAV_SSP\"").addEnv("DAV_SSP", uri.getRawSchemeSpecificPart());
mountScript.execute();
return new LinuxGvfsDavMount(uri);
}
private static class LinuxGvfsDavMount extends AbstractWebDavMount {
private final URI webDavUri;
private final Script testMountStillExistsScript;
private final Script unmountScript;
private LinuxGvfsDavMount(URI webDavUri) {
this.webDavUri = webDavUri;
this.testMountStillExistsScript = Script.fromLines("set -x", "test `gvfs-mount --list | grep \"$DAV_SSP\" | wc -l` -eq 1").addEnv("DAV_SSP", webDavUri.getRawSchemeSpecificPart());
this.unmountScript = Script.fromLines("set -x", "gvfs-mount -u \"dav:$DAV_SSP\"").addEnv("DAV_SSP", webDavUri.getRawSchemeSpecificPart());
}
@Override
public void unmount() throws CommandFailedException {
boolean mountStillExists;
try {
testMountStillExistsScript.execute();
mountStillExists = true;
} catch (CommandFailedException e) {
mountStillExists = false;
}
// only attempt unmount if user didn't unmount manually:
if (mountStillExists) {
unmountScript.execute();
}
}
@Override
public void reveal() throws CommandFailedException {
Script.fromLines("set -x", "xdg-open \"webdav:$DAV_SSP\"").addEnv("DAV_SSP", webDavUri.getRawSchemeSpecificPart()).execute();
}
}
}
@@ -30,12 +30,14 @@ final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy {
}
@Override
public boolean shouldWork() {
public boolean shouldWork(Map<MountParam, Optional<String>> mountParams) {
if (SystemUtils.IS_OS_LINUX) {
Optional<String> prefScheme = mountParams.getOrDefault(MountParam.PREFERRED_GVFS_SCHEME, Optional.empty());
boolean prefSchemeIsUnspecifiedOrWebDav = !prefScheme.isPresent() || prefScheme.get().equalsIgnoreCase("webdav");
final Script checkScripts = Script.fromLines("which gvfs-mount xdg-open");
try {
checkScripts.execute();
return true;
return prefSchemeIsUnspecifiedOrWebDav;
} catch (CommandFailedException e) {
return false;
}
@@ -84,15 +86,7 @@ final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy {
@Override
public void reveal() throws CommandFailedException {
try {
openMountWithWebdavUri("dav:" + webDavUri.getRawSchemeSpecificPart()).execute();
} catch (CommandFailedException exception) {
openMountWithWebdavUri("webdav:" + webDavUri.getRawSchemeSpecificPart()).execute();
}
}
private Script openMountWithWebdavUri(String webdavUri) {
return Script.fromLines("set -x", "xdg-open \"$DAV_URI\"").addEnv("DAV_URI", webdavUri);
Script.fromLines("set -x", "xdg-open \"webdav:$DAV_SSP\"").addEnv("DAV_SSP", webDavUri.getRawSchemeSpecificPart()).execute();
}
}
@@ -38,7 +38,7 @@ final class MacOsXAppleScriptWebDavMounter implements WebDavMounterStrategy {
}
@Override
public boolean shouldWork() {
public boolean shouldWork(Map<MountParam, Optional<String>> mountParams) {
return SystemUtils.IS_OS_MAC_OSX && semVerComparator.compare(SystemUtils.OS_VERSION, "10.10") >= 0;
}
@@ -37,7 +37,7 @@ final class MacOsXShellScriptWebDavMounter implements WebDavMounterStrategy {
}
@Override
public boolean shouldWork() {
public boolean shouldWork(Map<MountParam, Optional<String>> mountParams) {
return SystemUtils.IS_OS_MAC_OSX && semVerComparator.compare(SystemUtils.OS_VERSION, "10.10") < 0;
}
@@ -1,105 +0,0 @@
/*******************************************************************************
* Copyright (c) 2016 Sebastian Stenzel and others.
* This file is licensed under the terms of the MIT license.
* See the LICENSE.txt file for more info.
*
* Contributors:
* Sebastian Stenzel - initial API and implementation
*******************************************************************************/
package org.cryptomator.frontend.webdav.mount;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import java.util.Collection;
import java.util.Iterator;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
class MountStrategies implements Collection<WebDavMounterStrategy> {
private final Collection<WebDavMounterStrategy> delegate;
@Inject
MountStrategies(LinuxGvfsWebDavMounter linuxMounter, MacOsXAppleScriptWebDavMounter osxAppleScriptMounter, MacOsXShellScriptWebDavMounter osxShellScriptMounter, WindowsWebDavMounter winMounter) {
delegate = unmodifiableList(asList(linuxMounter, osxAppleScriptMounter, osxShellScriptMounter, winMounter));
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
return delegate.contains(o);
}
@Override
public Iterator<WebDavMounterStrategy> iterator() {
return delegate.iterator();
}
@Override
public Object[] toArray() {
return delegate.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return delegate.toArray(a);
}
@Override
public boolean add(WebDavMounterStrategy e) {
return delegate.add(e);
}
@Override
public boolean remove(Object o) {
return delegate.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends WebDavMounterStrategy> c) {
return delegate.addAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public boolean equals(Object o) {
return delegate.equals(o);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
}
@@ -0,0 +1,31 @@
package org.cryptomator.frontend.webdav.mount;
import java.util.Set;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.collect.Sets;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.ElementsIntoSet;
@Module
public class WebDavMounterModule {
@Provides
@ElementsIntoSet
static Set<WebDavMounterStrategy> provideMounters(LinuxGvfsWebDavMounter linuxWebDavMounter, LinuxGvfsDavMounter linuxDavMounter, MacOsXAppleScriptWebDavMounter osxAppleScriptMounter,
MacOsXShellScriptWebDavMounter osxShellScriptMounter, WindowsWebDavMounter winMounter) {
return Sets.newHashSet(linuxWebDavMounter, linuxDavMounter, osxAppleScriptMounter, osxShellScriptMounter, winMounter);
}
@Provides
@Singleton
@Named("fallback")
static WebDavMounterStrategy provideFallbackStrategy() {
return new FallbackWebDavMounter();
}
}
@@ -10,34 +10,35 @@
package org.cryptomator.frontend.webdav.mount;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Named;
import javax.inject.Singleton;
import org.cryptomator.frontend.Frontend.MountParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class WebDavMounterProvider implements Provider<WebDavMounter> {
public class WebDavMounterProvider {
private static final Logger LOG = LoggerFactory.getLogger(WebDavMounterProvider.class);
private final WebDavMounterStrategy choosenStrategy;
private final Collection<WebDavMounterStrategy> availableStrategies;
private final WebDavMounterStrategy fallbackStrategy;
@Inject
public WebDavMounterProvider(MountStrategies availableStrategies) {
this.choosenStrategy = getStrategyWhichShouldWork(availableStrategies);
public WebDavMounterProvider(Set<WebDavMounterStrategy> availableStrategies, @Named("fallback") WebDavMounterStrategy fallbackStrategy) {
this.availableStrategies = availableStrategies;
this.fallbackStrategy = fallbackStrategy;
}
@Override
public WebDavMounter get() {
return this.choosenStrategy;
}
private WebDavMounterStrategy getStrategyWhichShouldWork(Collection<WebDavMounterStrategy> availableStrategies) {
WebDavMounterStrategy strategy = availableStrategies.stream().filter(WebDavMounterStrategy::shouldWork).findFirst().orElse(new FallbackWebDavMounter());
LOG.info("Using {}", strategy.getClass().getSimpleName());
return strategy;
public WebDavMounter chooseMounter(Map<MountParam, Optional<String>> mountParams) {
WebDavMounterStrategy result = availableStrategies.stream().filter(strategy -> strategy.shouldWork(mountParams)).findFirst().orElse(fallbackStrategy);
LOG.info("Using {}", result.getClass().getSimpleName());
return result;
}
}
@@ -9,6 +9,11 @@
******************************************************************************/
package org.cryptomator.frontend.webdav.mount;
import java.util.Map;
import java.util.Optional;
import org.cryptomator.frontend.Frontend.MountParam;
/**
* A strategy able to mount a webdav share and display it to the user.
*
@@ -19,7 +24,7 @@ interface WebDavMounterStrategy extends WebDavMounter {
/**
* @return {@code false} if this {@code WebDavMounterStrategy} can not work on the local machine, {@code true} if it could work
*/
boolean shouldWork();
boolean shouldWork(Map<MountParam, Optional<String>> mountParams);
/**
* Invoked when mounting strategy gets chosen. On some operating systems (we don't want to tell names here) mounting might be faster,
@@ -61,7 +61,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
}
@Override
public boolean shouldWork() {
public boolean shouldWork(Map<MountParam, Optional<String>> mountParams) {
return SystemUtils.IS_OS_WINDOWS;
}
@@ -102,7 +102,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
mountScript.addEnv("DAV_UNC_PATH", uri.getRawPath().replace('/', '\\'));
return mountScript.execute(MOUNT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
private void addProxyOverrides(URI uri) throws IOException, CommandFailedException {
try {
// get existing value for ProxyOverride key from reqistry:
@@ -110,7 +110,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
Process queryCmd = query.start();
String queryStdOut = IOUtils.toString(queryCmd.getInputStream(), StandardCharsets.UTF_8);
int queryResult = queryCmd.waitFor();
// determine new value for ProxyOverride key:
Set<String> overrides = new HashSet<>();
Matcher matcher = REG_QUERY_PROXY_OVERRIDES_PATTERN.matcher(queryStdOut);
@@ -122,7 +122,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
overrides.add("<local>");
overrides.add(uri.getHost());
overrides.add(uri.getHost() + ":" + uri.getPort());
// set new value:
String overridesStr = StringUtils.join(overrides, ';');
ProcessBuilder add = new ProcessBuilder("reg", "add", "\"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\"", "/v", "ProxyOverride", "/d", "\"" + overridesStr + "\"", "/f");
@@ -10,12 +10,10 @@ package org.cryptomator.frontend.webdav;
import javax.inject.Singleton;
import org.cryptomator.common.CommonsModule;
import dagger.Component;
@Singleton
@Component(modules = {CommonsModule.class})
@Component(modules = {WebDavModule.class})
public interface WebDavComponent {
WebDavServer server();