150
150
import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .CHAR_STAR ;
151
151
import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .CHAR_UNDERSCORE ;
152
152
import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .DIRECTORY ;
153
+ import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .EMPTY_STRING ;
153
154
import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .FILE ;
154
155
import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .ROOT_PATH ;
155
156
import static org .apache .hadoop .fs .azurebfs .constants .AbfsHttpConstants .SINGLE_WHITE_SPACE ;
@@ -343,11 +344,13 @@ public void close() throws IOException {
343
344
}
344
345
345
346
byte [] encodeAttribute (String value ) throws UnsupportedEncodingException {
346
- return value .getBytes (XMS_PROPERTIES_ENCODING );
347
+ // DFS Client works with ISO_8859_1 encoding, Blob Works with UTF-8.
348
+ return getClient ().encodeAttribute (value );
347
349
}
348
350
349
351
String decodeAttribute (byte [] value ) throws UnsupportedEncodingException {
350
- return new String (value , XMS_PROPERTIES_ENCODING );
352
+ // DFS Client works with ISO_8859_1 encoding, Blob Works with UTF-8.
353
+ return getClient ().decodeAttribute (value );
351
354
}
352
355
353
356
private String [] authorityParts (URI uri ) throws InvalidUriAuthorityException , InvalidUriException {
@@ -485,9 +488,8 @@ public Hashtable<String, String> getFilesystemProperties(
485
488
.getFilesystemProperties (tracingContext );
486
489
perfInfo .registerResult (op .getResult ());
487
490
488
- final String xMsProperties = op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_PROPERTIES );
489
-
490
- parsedXmsProperties = parseCommaSeparatedXmsProperties (xMsProperties );
491
+ // Handling difference in request headers formats between DFS and Blob Clients.
492
+ parsedXmsProperties = getClient ().getXMSProperties (op .getResult ());
491
493
perfInfo .registerSuccess (true );
492
494
493
495
return parsedXmsProperties ;
@@ -533,10 +535,8 @@ public Hashtable<String, String> getPathStatus(final Path path,
533
535
perfInfo .registerResult (op .getResult ());
534
536
contextEncryptionAdapter .destroy ();
535
537
536
- final String xMsProperties = op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_PROPERTIES );
537
-
538
- parsedXmsProperties = parseCommaSeparatedXmsProperties (xMsProperties );
539
-
538
+ // Handling difference in request headers formats between DFS and Blob Clients.
539
+ parsedXmsProperties = getClient ().getXMSProperties (op .getResult ());
540
540
perfInfo .registerSuccess (true );
541
541
542
542
return parsedXmsProperties ;
@@ -899,10 +899,8 @@ public AbfsInputStream openFileForRead(Path path,
899
899
} else {
900
900
AbfsHttpOperation op = getClient ().getPathStatus (relativePath , false ,
901
901
tracingContext , null ).getResult ();
902
- resourceType = op .getResponseHeader (
903
- HttpHeaderConfigurations .X_MS_RESOURCE_TYPE );
904
- contentLength = Long .parseLong (
905
- op .getResponseHeader (HttpHeaderConfigurations .CONTENT_LENGTH ));
902
+ resourceType = getClient ().checkIsDir (op ) ? DIRECTORY : FILE ;
903
+ contentLength = extractContentLength (op );
906
904
eTag = op .getResponseHeader (HttpHeaderConfigurations .ETAG );
907
905
/*
908
906
* For file created with ENCRYPTION_CONTEXT, client shall receive
@@ -983,17 +981,15 @@ public OutputStream openFileForWrite(final Path path,
983
981
.getPathStatus (relativePath , false , tracingContext , null );
984
982
perfInfo .registerResult (op .getResult ());
985
983
986
- final String resourceType = op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_RESOURCE_TYPE );
987
- final Long contentLength = Long .valueOf (op .getResult ().getResponseHeader (HttpHeaderConfigurations .CONTENT_LENGTH ));
988
-
989
- if (parseIsDirectory (resourceType )) {
984
+ if (getClient ().checkIsDir (op .getResult ())) {
990
985
throw new AbfsRestOperationException (
991
986
AzureServiceErrorCode .PATH_NOT_FOUND .getStatusCode (),
992
987
AzureServiceErrorCode .PATH_NOT_FOUND .getErrorCode (),
993
- "openFileForRead must be used with files and not directories" ,
988
+ "openFileForWrite must be used with files and not directories" ,
994
989
null );
995
990
}
996
991
992
+ final long contentLength = extractContentLength (op .getResult ());
997
993
final long offset = overwrite ? 0 : contentLength ;
998
994
999
995
perfInfo .registerSuccess (true );
@@ -1180,8 +1176,8 @@ public FileStatus getFileStatus(final Path path,
1180
1176
contentLength = 0 ;
1181
1177
resourceIsDir = true ;
1182
1178
} else {
1183
- contentLength = parseContentLength (result . getResponseHeader ( HttpHeaderConfigurations . CONTENT_LENGTH ) );
1184
- resourceIsDir = parseIsDirectory ( result . getResponseHeader ( HttpHeaderConfigurations . X_MS_RESOURCE_TYPE ) );
1179
+ contentLength = extractContentLength (result );
1180
+ resourceIsDir = getClient (). checkIsDir ( result );
1185
1181
}
1186
1182
1187
1183
final String transformedOwner = identityTransformer .transformIdentityForGetRequest (
@@ -1256,10 +1252,16 @@ public String listStatus(final Path path, final String startFrom,
1256
1252
startFrom );
1257
1253
1258
1254
final String relativePath = getRelativePath (path );
1255
+ AbfsClient listingClient = getClient ();
1259
1256
1260
1257
if (continuation == null || continuation .isEmpty ()) {
1261
1258
// generate continuation token if a valid startFrom is provided.
1262
1259
if (startFrom != null && !startFrom .isEmpty ()) {
1260
+ /*
1261
+ * Blob Endpoint Does not support startFrom yet. Fallback to DFS Client.
1262
+ * startFrom remains null for all HDFS APIs. This is only for internal use.
1263
+ */
1264
+ listingClient = getClient (AbfsServiceType .DFS );
1263
1265
continuation = getIsNamespaceEnabled (tracingContext )
1264
1266
? generateContinuationTokenForXns (startFrom )
1265
1267
: generateContinuationTokenForNonXns (relativePath , startFrom );
@@ -1268,11 +1270,11 @@ public String listStatus(final Path path, final String startFrom,
1268
1270
1269
1271
do {
1270
1272
try (AbfsPerfInfo perfInfo = startTracking ("listStatus" , "listPath" )) {
1271
- AbfsRestOperation op = getClient () .listPath (relativePath , false ,
1273
+ AbfsRestOperation op = listingClient .listPath (relativePath , false ,
1272
1274
abfsConfiguration .getListMaxResults (), continuation ,
1273
1275
tracingContext );
1274
1276
perfInfo .registerResult (op .getResult ());
1275
- continuation = op .getResult (). getResponseHeader ( HttpHeaderConfigurations . X_MS_CONTINUATION );
1277
+ continuation = listingClient . getContinuationFromResponse ( op .getResult ());
1276
1278
ListResultSchema retrievedSchema = op .getResult ().getListResultSchema ();
1277
1279
if (retrievedSchema == null ) {
1278
1280
throw new AbfsRestOperationException (
@@ -1465,7 +1467,7 @@ public void modifyAclEntries(final Path path, final List<AclEntry> aclSpec,
1465
1467
final AbfsRestOperation op = getClient ()
1466
1468
.getAclStatus (relativePath , useUpn , tracingContext );
1467
1469
perfInfoGet .registerResult (op .getResult ());
1468
- final String eTag = op .getResult (). getResponseHeader ( HttpHeaderConfigurations . ETAG );
1470
+ final String eTag = extractEtagHeader ( op .getResult ());
1469
1471
1470
1472
final Map <String , String > aclEntries = AbfsAclHelper .deserializeAclSpec (op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_ACL ));
1471
1473
@@ -1508,7 +1510,7 @@ public void removeAclEntries(final Path path, final List<AclEntry> aclSpec,
1508
1510
final AbfsRestOperation op = getClient ()
1509
1511
.getAclStatus (relativePath , isUpnFormat , tracingContext );
1510
1512
perfInfoGet .registerResult (op .getResult ());
1511
- final String eTag = op .getResult (). getResponseHeader ( HttpHeaderConfigurations . ETAG );
1513
+ final String eTag = extractEtagHeader ( op .getResult ());
1512
1514
1513
1515
final Map <String , String > aclEntries = AbfsAclHelper .deserializeAclSpec (op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_ACL ));
1514
1516
@@ -1546,7 +1548,7 @@ public void removeDefaultAcl(final Path path, TracingContext tracingContext)
1546
1548
final AbfsRestOperation op = getClient ()
1547
1549
.getAclStatus (relativePath , tracingContext );
1548
1550
perfInfoGet .registerResult (op .getResult ());
1549
- final String eTag = op .getResult (). getResponseHeader ( HttpHeaderConfigurations . ETAG );
1551
+ final String eTag = extractEtagHeader ( op .getResult ());
1550
1552
final Map <String , String > aclEntries = AbfsAclHelper .deserializeAclSpec (op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_ACL ));
1551
1553
final Map <String , String > defaultAclEntries = new HashMap <>();
1552
1554
@@ -1590,7 +1592,7 @@ public void removeAcl(final Path path, TracingContext tracingContext)
1590
1592
final AbfsRestOperation op = getClient ()
1591
1593
.getAclStatus (relativePath , tracingContext );
1592
1594
perfInfoGet .registerResult (op .getResult ());
1593
- final String eTag = op .getResult (). getResponseHeader ( HttpHeaderConfigurations . ETAG );
1595
+ final String eTag = extractEtagHeader ( op .getResult ());
1594
1596
1595
1597
final Map <String , String > aclEntries = AbfsAclHelper .deserializeAclSpec (op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_ACL ));
1596
1598
final Map <String , String > newAclEntries = new HashMap <>();
@@ -1636,7 +1638,7 @@ public void setAcl(final Path path, final List<AclEntry> aclSpec,
1636
1638
final AbfsRestOperation op = getClient ()
1637
1639
.getAclStatus (relativePath , isUpnFormat , tracingContext );
1638
1640
perfInfoGet .registerResult (op .getResult ());
1639
- final String eTag = op .getResult (). getResponseHeader ( HttpHeaderConfigurations . ETAG );
1641
+ final String eTag = extractEtagHeader ( op .getResult ());
1640
1642
1641
1643
final Map <String , String > getAclEntries = AbfsAclHelper .deserializeAclSpec (op .getResult ().getResponseHeader (HttpHeaderConfigurations .X_MS_ACL ));
1642
1644
@@ -1859,12 +1861,24 @@ public String getRelativePath(final Path path) {
1859
1861
return relPath ;
1860
1862
}
1861
1863
1862
- private long parseContentLength (final String contentLength ) {
1863
- if (contentLength == null ) {
1864
- return -1 ;
1864
+ /**
1865
+ * Extracts the content length from the HTTP operation's response headers.
1866
+ *
1867
+ * @param op The AbfsHttpOperation instance from which to extract the content length.
1868
+ * This operation contains the HTTP response headers.
1869
+ * @return The content length as a long value. If the Content-Length header is
1870
+ * not present or is empty, returns 0.
1871
+ */
1872
+ private long extractContentLength (AbfsHttpOperation op ) {
1873
+ long contentLength ;
1874
+ String contentLengthHeader = op .getResponseHeader (
1875
+ HttpHeaderConfigurations .CONTENT_LENGTH );
1876
+ if (!contentLengthHeader .equals (EMPTY_STRING )) {
1877
+ contentLength = Long .parseLong (contentLengthHeader );
1878
+ } else {
1879
+ contentLength = 0 ;
1865
1880
}
1866
-
1867
- return Long .parseLong (contentLength );
1881
+ return contentLength ;
1868
1882
}
1869
1883
1870
1884
private boolean parseIsDirectory (final String resourceType ) {
0 commit comments