@Override
    public DescriptiveUrlBag toUrl(final Path file) {
        final DescriptiveUrlBag list = new DescriptiveUrlBag();
        if(file.isFile()) {
            Optional<Region> optional = accounts.keySet().stream().filter(r -> StringUtils.equals(r.getRegionId(),
                    file.attributes().getRegion())).findAny();
            if(!optional.isPresent()) {
                list.addAll(new DefaultUrlProvider(session.getHost()).toUrl(file));
            }
            else {
                final Region region = optional.get();
                list.addAll(new HostWebUrlProvider(session.getHost()).toUrl(file));
                list.add(new DescriptiveUrl(
                        URI.create(region.getStorageUrl(containerService.getContainer(file).getName(),
                                containerService.getKey(file)).toString()),
                        DescriptiveUrl.Type.provider,
                        MessageFormat.format(LocaleFactory.localizedString("{0} URL"),
                                session.getHost().getProtocol().getScheme().name().toUpperCase(Locale.ROOT))
                ));
                // In one hour
                list.add(this.toSignedUrl(region, file, (int) TimeUnit.HOURS.toSeconds(1)));
                // Default signed URL expiring in 24 hours.
                list.add(this.toSignedUrl(region, file, (int) TimeUnit.SECONDS.toSeconds(
                        new HostPreferences(session.getHost()).getInteger("s3.url.expire.seconds"))));
                // 1 Week
                list.add(this.toSignedUrl(region, file, (int) TimeUnit.DAYS.toSeconds(7)));
                // 1 Month
                list.add(this.toSignedUrl(region, file, (int) TimeUnit.DAYS.toSeconds(30)));
                // 1 Year
                list.add(this.toSignedUrl(region, file, (int) TimeUnit.DAYS.toSeconds(365)));
            }
        }
        // Filter by matching container name
        final Optional<Set<Distribution>> filtered = distributions.entrySet().stream().filter(entry ->
                        new SimplePathPredicate(containerService.getContainer(file)).test(entry.getKey()))
                .map(Map.Entry::getValue).findFirst();
        if(filtered.isPresent()) {
            // Add CloudFront distributions
            for(Distribution distribution : filtered.get()) {
                list.addAll(new DistributionUrlProvider(distribution).toUrl(file));
            }
        }
        return list;
    }
@Test
    public void testSigned() throws Exception {
        final Map<Region, AccountInfo> accounts = new SwiftAccountLoader(session).operate(new DisabledPasswordCallback(),
                new Path(String.valueOf(Path.DELIMITER), EnumSet.of(Path.Type.volume, Path.Type.directory)));
        final UrlProvider provider = new SwiftUrlProvider(session, accounts);
        final Path container = new Path("test.cyberduck.ch", EnumSet.of(Path.Type.directory, Path.Type.volume));
        container.attributes().setRegion("IAD");
        final Path file = new Path(container, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file));
        container.attributes().setRegion("IAD");
        new SwiftTouchFeature(session, new SwiftRegionService(session)).touch(file, new TransferStatus());
        final DescriptiveUrlBag list = provider.toUrl(file);
        final DescriptiveUrl signed = list.find(DescriptiveUrl.Type.signed);
        assertNotNull(signed);
        assertNotEquals(DescriptiveUrl.EMPTY, signed);
        assertFalse(list.filter(DescriptiveUrl.Type.signed).isEmpty());
        assertEquals(5, list.filter(DescriptiveUrl.Type.signed).size());
        for(DescriptiveUrl s : list.filter(DescriptiveUrl.Type.signed)) {
            assertNotNull(s);
            assertNotEquals(DescriptiveUrl.EMPTY, s);
        }
        new SwiftDeleteFeature(session).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }