Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit 146da0f

Browse files
authored
Merge pull request #415 from amishra-dev/New-Storage-SDK-V10-Preview
Adding support for ip style endpoint
2 parents 5f8101a + a62b525 commit 146da0f

File tree

7 files changed

+194
-12
lines changed

7 files changed

+194
-12
lines changed

blob/src/main/java/com/microsoft/azure/storage/blob/BlobURLParts.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public final class BlobURLParts {
4848

4949
private Map<String, String[]> unparsedParameters;
5050

51+
private IPStyleEndPointInfo ipStyleEndPointInfo;
52+
5153
/**
5254
* The scheme. Ex: "https://".
5355
*/
@@ -140,6 +142,21 @@ public BlobURLParts withSasQueryParameters(SASQueryParameters sasQueryParameters
140142
return this;
141143
}
142144

145+
/**
146+
* A {@link IPStyleEndPointInfo}
147+
*/
148+
public IPStyleEndPointInfo ipEndPointStyleInfo() {
149+
return ipStyleEndPointInfo;
150+
}
151+
152+
/**
153+
* A {@link IPStyleEndPointInfo}
154+
*/
155+
public BlobURLParts withIPEndPointStyleInfo(IPStyleEndPointInfo ipStyleEndPointInfo) {
156+
this.ipStyleEndPointInfo = ipStyleEndPointInfo;
157+
return this;
158+
}
159+
143160
/**
144161
* The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were
145162
* no such parameters.
@@ -179,6 +196,18 @@ public URL toURL() throws MalformedURLException {
179196
UrlBuilder url = new UrlBuilder().withScheme(this.scheme).withHost(this.host);
180197

181198
StringBuilder path = new StringBuilder();
199+
200+
if (this.ipStyleEndPointInfo != null) {
201+
if (this.ipStyleEndPointInfo.accountName() != null) {
202+
/* Added a path separator after the account name. Anything that is added
203+
after the account name doesn't need to care about the "/". */
204+
path.append(this.ipStyleEndPointInfo.accountName() + "/");
205+
}
206+
if (this.ipStyleEndPointInfo.port() != null) {
207+
url.withPort(this.ipStyleEndPointInfo.port());
208+
}
209+
}
210+
182211
if (this.containerName != null) {
183212
path.append(this.containerName);
184213
if (this.blobName != null) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright Microsoft Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
package com.microsoft.azure.storage.blob;
16+
17+
/**
18+
* IPEndpointStyleInfo is used for IP endpoint style URL. It's commonly used when
19+
* working with Azure storage emulator or testing environments. For Example:
20+
* "https://10.132.141.33/accountname/container/blob"
21+
*/
22+
public final class IPStyleEndPointInfo {
23+
24+
private String accountName;
25+
26+
private Integer port;
27+
28+
/**
29+
* The account name. For Example: "https://10.132.41.33/accountname"
30+
*/
31+
public String accountName() {
32+
return accountName;
33+
}
34+
35+
/**
36+
* The account name. For Example: "https://10.132.41.33/accountname"
37+
* Note: if the standard <account>.blob.core.windows.net is presented to {@link BlobURLParts},
38+
* {@link IPStyleEndPointInfo} will be null because the url may be a custom domain. In these cases, if the
39+
* account happens to be present in the host, it will simply remain as a part of the host field in the
40+
* {@link BlobURLParts} object.
41+
* {@link IPStyleEndPointInfo} is present and populated with accountname only if an IP address is used to present
42+
* the blob url
43+
*/
44+
public IPStyleEndPointInfo withAccountName(String accountName) {
45+
this.accountName = accountName;
46+
return this;
47+
}
48+
49+
/**
50+
* The port number of the IP address. For Example: "https://10.132.41.33:80/accountname"
51+
*/
52+
public Integer port() {
53+
return port;
54+
}
55+
56+
/**
57+
* The port number of the IP address. For Example: "https://10.132.41.33:80/accountname"
58+
*/
59+
public IPStyleEndPointInfo withPort(Integer port) {
60+
this.port = port;
61+
return this;
62+
}
63+
}

blob/src/main/java/com/microsoft/azure/storage/blob/URLParser.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.Map;
2222
import java.util.TreeMap;
2323

24+
import sun.net.util.IPAddressUtil;
25+
2426
/**
2527
* A class used to conveniently parse URLs into {@link BlobURLParts} to modify the components of the URL.
2628
*/
@@ -42,6 +44,7 @@ public static BlobURLParts parse(URL url) throws UnknownHostException {
4244

4345
final String scheme = url.getProtocol();
4446
final String host = url.getHost();
47+
IPStyleEndPointInfo ipStyleEndPointInfo = null;
4548

4649
String containerName = null;
4750
String blobName = null;
@@ -54,6 +57,34 @@ public static BlobURLParts parse(URL url) throws UnknownHostException {
5457
path = path.substring(1);
5558
}
5659

60+
// If the host name is in the ip-address format
61+
if (isHostIPEndPointStyle(host)) {
62+
// Create the IPStyleEndPointInfo and set the port number.
63+
ipStyleEndPointInfo = new IPStyleEndPointInfo();
64+
if (url.getPort() != -1) {
65+
ipStyleEndPointInfo.withPort(url.getPort());
66+
}
67+
String accountName;
68+
/*If the host is in the IP Format, then account name is provided after the ip-address.
69+
For Example: "https://10.132.141.33/accountname/container/blob". Get the index of "/" in the path.
70+
*/
71+
int pathSepEndIndex = path.indexOf('/');
72+
if (pathSepEndIndex == -1) {
73+
/* If there does not exists "/" in the path, it means the entire path is the account name
74+
For Example: path = accountname */
75+
accountName = path;
76+
// since path contains only the account name, after account name is set, set path to empty string.
77+
path = Constants.EMPTY_STRING;
78+
} else {
79+
/* If there exists the "/", it means all the content in the path till "/" is the account name
80+
For Example: accountname/container/blob */
81+
accountName = path.substring(0, pathSepEndIndex);
82+
// After path name has been extracted from the path, strip account name from path
83+
path = path.substring(pathSepEndIndex + 1);
84+
}
85+
ipStyleEndPointInfo.withAccountName(accountName);
86+
}
87+
5788
int containerEndIndex = path.indexOf('/');
5889
if (containerEndIndex == -1) {
5990
// path contains only a container name and no blob name
@@ -84,7 +115,8 @@ public static BlobURLParts parse(URL url) throws UnknownHostException {
84115
.withBlobName(blobName)
85116
.withSnapshot(snapshot)
86117
.withSasQueryParameters(sasQueryParameters)
87-
.withUnparsedParameters(queryParamsMap);
118+
.withUnparsedParameters(queryParamsMap)
119+
.withIPEndPointStyleInfo(ipStyleEndPointInfo);
88120
}
89121

90122
/**
@@ -140,4 +172,22 @@ public int compare(String s1, String s2) {
140172

141173
return retVals;
142174
}
175+
176+
/**
177+
* Checks if URL's host is IP. If true storage account endpoint will be composed as: http(s)://IP(:port)/storageaccount/...
178+
* As url's Host property, host could be both host or host:port
179+
*
180+
* @param host
181+
* The host. Ex: "account.blob.core.windows.net" or 10.31.141.33:80
182+
*
183+
* @return true, if the host is an ip address (ipv4/ipv6) with or without port.
184+
*/
185+
public static boolean isHostIPEndPointStyle(String host) {
186+
if ((host == null) || host.equals("")) {
187+
return false;
188+
}
189+
190+
return IPAddressUtil.isIPv4LiteralAddress(host);
191+
}
143192
}
193+

blob/src/test/java/com/microsoft/azure/storage/blob/HelperTest.groovy

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,4 +628,31 @@ class HelperTest extends APISpec {
628628
parts.sasQueryParameters().signature() ==
629629
Utility.safeURLDecode("Ee%2BSodSXamKSzivSdRTqYGh7AeMVEk3wEoRZ1yzkpSc%3D")
630630
}
631+
632+
@Unroll
633+
def "IP Style Host Url parse test"() {
634+
when:
635+
def u = new URL(url)
636+
def blobUrlParts = URLParser.parse(u)
637+
638+
then:
639+
blobUrlParts.scheme() == scheme
640+
blobUrlParts.host() == host
641+
if (blobUrlParts.ipEndPointStyleInfo() != null) {
642+
assert blobUrlParts.ipEndPointStyleInfo().port() == port
643+
assert blobUrlParts.ipEndPointStyleInfo().accountName() == accountname
644+
}
645+
blobUrlParts.blobName() == blob
646+
blobUrlParts.snapshot() == snapshot
647+
blobUrlParts.containerName() == container
648+
649+
where:
650+
url || scheme | host | port | accountname | container | blob | snapshot
651+
"http://105.232.1.23/accountname" || "http" | "105.232.1.23" | null | "accountname" | "" | null | null
652+
"http://105.232.1.23/accountname/container" || "http" | "105.232.1.23" | null | "accountname" | "container" | null | null
653+
"http://105.232.1.23:80/accountname/container" || "http" | "105.232.1.23" | 80 | "accountname" | "container" | null | null
654+
"http://105.232.1.23:8080/accountname/container/blob" || "http" | "105.232.1.23" | 8080 | "accountname" | "container" | "blob" | null
655+
"http://105.232.1.23/accountname/container/blob" || "http" | "105.232.1.23" | null | "accountname" | "container" | "blob" | null
656+
"http://105.232.1.23:80/accountname/container/blob?snapshot=snapshot" || "http" | "105.232.1.23" | 80 | "accountname" | "container" | "blob" | "snapshot"
657+
}
631658
}

queue/src/main/java/com/microsoft/azure/storage/queue/IPStyleEndPointInfo.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
/*
2+
* Copyright Microsoft Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
115
package com.microsoft.azure.storage.queue;
216

317
/**

queue/src/main/java/com/microsoft/azure/storage/queue/URLParser.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,14 @@
2020
import java.util.Locale;
2121
import java.util.Map;
2222
import java.util.TreeMap;
23-
import java.util.regex.Pattern;
23+
24+
import sun.net.util.IPAddressUtil;
2425

2526
/**
2627
* A class used to conveniently parse URLs into {@link QueueURLParts} to modify the components of the URL.
2728
*/
2829
public final class URLParser {
2930

30-
// ipv4PatternString represents the pattern of ipv4 addresses.
31-
private final static String ipv4PatternString = "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$";
32-
// ipv4Pattern represents a compiled pattern of ipv4 address pattern.
33-
private static Pattern ipv4Pattern = Pattern.compile(ipv4PatternString);
34-
3531
/**
3632
* URLParser parses a URL initializing QueueURLParts' fields including any SAS-related query parameters.
3733
* Any other query parameters remain in the UnparsedParams field. This method overwrites all fields in the
@@ -54,7 +50,6 @@ public static QueueURLParts parse(URL url) throws UnknownHostException {
5450
boolean messages = false;
5551
String messageId = null;
5652
IPStyleEndPointInfo ipStyleEndPointInfo = null;
57-
Integer port = null;
5853

5954
String path = url.getPath();
6055
if (!Utility.isNullOrEmpty(path)) {
@@ -194,7 +189,7 @@ public static boolean isHostIPEndPointStyle(String host) {
194189
if ((host == null) || host.equals("")) {
195190
return false;
196191
}
197-
// returns true if host represents an ipv4 address.
198-
return ipv4Pattern.matcher(host).matches();
192+
193+
return IPAddressUtil.isIPv4LiteralAddress(host);
199194
}
200195
}

queue/src/test/java/com/microsoft/azure/storage/HelperTest.groovy

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class HelperTest extends APISpec {
163163
"105.232.1.23" | 80 || "http://105.232.1.23:80/accountname/aqueue"
164164
}
165165

166+
@Unroll
166167
def "IP Style Host Url parse test"() {
167168
when:
168169
def u = new URL(url)
@@ -171,8 +172,10 @@ class HelperTest extends APISpec {
171172
then:
172173
q.scheme() == scheme
173174
q.host() == host
174-
q.ipEndPointStyleInfo().port() == port
175-
q.ipEndPointStyleInfo().accountName() == accountname
175+
if (q.ipEndPointStyleInfo() != null) {
176+
assert q.ipEndPointStyleInfo().port() == port
177+
assert q.ipEndPointStyleInfo().accountName() == accountname
178+
}
176179
q.queueName() == queuename
177180
q.messages() == messages
178181
q.messageId() == messageId
@@ -183,5 +186,6 @@ class HelperTest extends APISpec {
183186
"http://105.232.1.23:80/accountname/aqueue" || "http" | "105.232.1.23" | 80 | "accountname" | "aqueue" | false | null
184187
"http://105.232.1.23/accountname/aqueue/messages" || "http" | "105.232.1.23" | null | "accountname" | "aqueue" | true | null
185188
"http://105.232.1.23/accountname/aqueue/messages/randommessageId" || "http" | "105.232.1.23" | null | "accountname" | "aqueue" | true | "randommessageId"
189+
"http://105.232.1.23/accountname" || "http" | "105.232.1.23" | null | "accountname" | "" | false | null
186190
}
187191
}

0 commit comments

Comments
 (0)