Skip to content

Commit

Permalink
Merge pull request #24 from saalfeldlab/refactor/uriParsing
Browse files Browse the repository at this point in the history
refactor: uri parsing
  • Loading branch information
bogovicj authored Mar 14, 2024
2 parents fe02901 + 9b0217c commit 0b2c58d
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Expand All @@ -30,11 +30,12 @@

import java.net.URI;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.Splitter;

public class GoogleCloudStorageURI
{
public class GoogleCloudStorageURI {
private static final String storageHost = "storage.googleapis.com";
private static final String googleCloudHost = "googleapis.com";
private static final String googleCloudHost2 = "storage.cloud.google.com";
Expand All @@ -46,91 +47,79 @@ public class GoogleCloudStorageURI
private final String bucketName;
private final String objectKey;
private final String query;
private Map< String, String > queryMap;
private Map<String, String> queryMap;

public GoogleCloudStorageURI( final String str )
{
this( URI.create( str ) );
public GoogleCloudStorageURI(final String str) {

this(URI.create(str));
}

public GoogleCloudStorageURI( final URI uri )
{
public GoogleCloudStorageURI(final URI uri) {

this.uri = uri;
final String path;
if ( uri.getScheme() != null && uri.getScheme().equalsIgnoreCase( "gs" ) )
{
if (uri.getScheme() == null)
throw new IllegalArgumentException("Invalid scheme");

if (uri.getScheme().equalsIgnoreCase("gs")) {
bucketName = uri.getAuthority();
objectKey = uri.getPath();
query = uri.getQuery();
}
else if ( uri.getScheme().equalsIgnoreCase( "http" ) || uri.getScheme().equalsIgnoreCase( "https" ) )
{
} else if (uri.getScheme().matches("(?i)http(s)?")) {
final String host = uri.getHost();

if( host.equalsIgnoreCase( googleCloudHost ) || host.equalsIgnoreCase( "www." +googleCloudHost ))
{
if ( !uri.getPath().toLowerCase().startsWith( storagePathPrefix ) )
throw new IllegalArgumentException( "Not a google cloud storage link" );

path = uri.getPath().substring( storagePathPrefix.length() );
final int delimeterIndex = path.indexOf( "/" );

bucketName = path.substring( 0, delimeterIndex != -1 ? delimeterIndex : path.length() );
objectKey = delimeterIndex != -1 && delimeterIndex < path.length() - 1 ? path.substring( delimeterIndex ) : "";
query = uri.getQuery();
}
else if( host.equalsIgnoreCase( storageHost ) || host.equalsIgnoreCase( googleCloudHost2 ))
{
path = uri.getPath().indexOf( '/' ) == 0 ? uri.getPath().substring( 1 ) : uri.getPath();
final int delimeterIndex = path.indexOf( "/" );

bucketName = path.substring( 0, delimeterIndex != -1 ? delimeterIndex : path.length() );
objectKey = delimeterIndex != -1 && delimeterIndex < path.length() - 1 ? path.substring( delimeterIndex ) : "";
query = uri.getQuery();
final String path = uri.getPath();

final Matcher match;
if (host.matches("(?i)(www.)?" + googleCloudHost)) {
match = Pattern.compile("^" + storagePathPrefix + "(?<bucket>[^/]*)(?<key>/?.*)", Pattern.CASE_INSENSITIVE).matcher(path);
} else if (host.matches("(?i)" + storageHost + "|" + googleCloudHost2)) {
match = Pattern.compile("/?(?<bucket>[^/]*)(?<key>.*)", Pattern.CASE_INSENSITIVE).matcher(path);
} else
match = null;
if (match == null || !match.matches()) {
throw new IllegalArgumentException("Not a google cloud storage link");
}
else
{
throw new IllegalArgumentException( "Not a google cloud storage link" );
}
}
else
{
throw new IllegalArgumentException( "Invalid scheme" );

bucketName = match.group("bucket");
objectKey = match.group("key");
query = uri.getQuery();
} else {
throw new IllegalArgumentException("Invalid scheme");
}
queryMap = parseQuery();
}

public String getBucket()
{
public String getBucket() {

return bucketName;
}

public URI asURI() {

return this.uri;
}

public String getKey()
{
public String getKey() {

return objectKey;
}

public String getQuery()
{
public String getQuery() {

return query;
}
public String getProject()
{
if( queryMap != null && queryMap.containsKey( projectKey ))
return queryMap.get( projectKey );

public String getProject() {

if (queryMap != null && queryMap.containsKey(projectKey))
return queryMap.get(projectKey);

return null;
}

private Map<String,String> parseQuery()
{
if( query != null )
return Splitter.on( '&' ).trimResults().withKeyValueSeparator( '=' ).split( query );
private Map<String, String> parseQuery() {

if (query != null)
return Splitter.on('&').trimResults().withKeyValueSeparator('=').split(query);
else
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.janelia.saalfeldlab.googlecloud;

import org.junit.Test;

import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

public class GoogleCloudUtilsTest {

@Test
public void getGSInfoTest() {

final String bucketName = "my-gs-bucket";
final String[] noKeyTests = new String[]{
"https://googleapis.com/storage/v1/b/" + bucketName,
"https://www.googleapis.com/storage/v1/b/" + bucketName,
"https://storage.cloud.google.com/" + bucketName,
"gs://" + bucketName,
};

final String[] rootKeyTests = new String[]{
"http://googleapis.com/storage/v1/b/" + bucketName + "/",
"http://www.googleapis.com/storage/v1/b/" + bucketName + "/",
"http://storage.cloud.google.com/" + bucketName + "/",
"gs://" + bucketName + "/",
};

final String[] onePartKeyWithSlashTests = new String[]{
"http://googleapis.com/storage/v1/b/" + bucketName + "/a/",
"http://www.googleapis.com/storage/v1/b/" + bucketName + "/a/",
"http://storage.cloud.google.com/" + bucketName + "/a/",
"gs://" + bucketName + "/a/",
};

final String[] multiPartKeyWithSlashTests = new String[]{
"http://googleapis.com/storage/v1/b/" + bucketName + "/a/b/c/d/",
"http://www.googleapis.com/storage/v1/b/" + bucketName + "/a/b/c/d/",
"http://storage.cloud.google.com/" + bucketName + "/a/b/c/d/",
"gs://" + bucketName + "/a/b/c/d/",
};

final String[] onePartKeyNoSlashTests = new String[]{
"http://googleapis.com/storage/v1/b/" + bucketName + "/a",
"http://www.googleapis.com/storage/v1/b/" + bucketName + "/a",
"http://storage.cloud.google.com/" + bucketName + "/a",
"gs://" + bucketName + "/a",
};

final String[] multiPartKeyNoSlashTests = new String[]{
"http://googleapis.com/storage/v1/b/" + bucketName + "/a/b/c/d",
"http://www.googleapis.com/storage/v1/b/" + bucketName + "/a/b/c/d",
"http://storage.cloud.google.com/" + bucketName + "/a/b/c/d",
"gs://" + bucketName + "/a/b/c/d",
};

final HashMap<String, String[]> keyToTests = new HashMap<>();

keyToTests.put("", noKeyTests);
keyToTests.put("/", rootKeyTests);
keyToTests.put("/a/", onePartKeyWithSlashTests);
keyToTests.put("/a/b/c/d/", multiPartKeyWithSlashTests);
keyToTests.put("/a", onePartKeyNoSlashTests);
keyToTests.put("/a/b/c/d", multiPartKeyNoSlashTests);

for (Map.Entry<String, String[]> tests : keyToTests.entrySet()) {
final String expectedKey = tests.getKey();
for (String uri : tests.getValue()) {
final GoogleCloudStorageURI gsUri;
try {
gsUri = new GoogleCloudStorageURI(uri);
} catch (Throwable e) {
System.err.println("Could not parse Google Cloud URI for " + uri);
throw e;
}
assertEquals(bucketName, gsUri.getBucket());
assertEquals("Unexpected key for " + uri, expectedKey, GoogleCloudUtils.getGoogleCloudStorageKey(uri));
}
}

assertThrows("Invalid URI should throw exception", Throwable.class, () -> new GoogleCloudStorageURI(("invalid uri \\ _ ~ 435: q2234[;5.")));
assertThrows("Invalid URI should throw exception", Throwable.class, () -> GoogleCloudUtils.getGoogleCloudStorageKey("invalid uri \\ _ ~ 435: q2234[;5."));
}
}

0 comments on commit 0b2c58d

Please sign in to comment.