diff --git a/src/S3Commands.cc b/src/S3Commands.cc index 587994b..c5cc9b6 100644 --- a/src/S3Commands.cc +++ b/src/S3Commands.cc @@ -553,9 +553,10 @@ bool AmazonS3Head::SendRequest() { // --------------------------------------------------------------------------- bool AmazonS3List::SendRequest(const std::string &continuationToken) { - query_parameters["list-type"] = "2"; // Version 2 of the object-listing API + query_parameters["list-type"] = "2"; // Version 2 of the object-listing query_parameters["delimiter"] = "/"; query_parameters["prefix"] = urlquote(object); + query_parameters["encoding-type"] = "url"; if (!continuationToken.empty()) { query_parameters["continuation-token"] = urlquote(continuationToken); } @@ -564,6 +565,7 @@ bool AmazonS3List::SendRequest(const std::string &continuationToken) { // Operation is on the bucket itself; alter the URL to remove the object hostUrl = getProtocol() + "://" + host + bucketPath; + canonicalURI = bucketPath; return SendS3Request(""); } diff --git a/src/S3Directory.cc b/src/S3Directory.cc index 31375b5..34ea6c8 100644 --- a/src/S3Directory.cc +++ b/src/S3Directory.cc @@ -77,9 +77,13 @@ int S3Directory::Opendir(const char *path, XrdOucEnv &env) { return -EBADF; } Reset(); + std::string realPath = path; + if (realPath.back() != '/') { + realPath = realPath + "/"; + } std::string exposedPath, object; - int rv = m_fs.parsePath(path, exposedPath, object); + int rv = m_fs.parsePath(realPath.c_str(), exposedPath, object); if (rv != 0) { return rv; } diff --git a/src/S3FileSystem.cc b/src/S3FileSystem.cc index d8d10d1..c428a2f 100644 --- a/src/S3FileSystem.cc +++ b/src/S3FileSystem.cc @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -202,9 +203,14 @@ XrdOssDF *S3FileSystem::newFile(const char *user) { int S3FileSystem::Stat(const char *path, struct stat *buff, int opts, XrdOucEnv *env) { m_log.Log(XrdHTTPServer::Debug, "Stat", "Stat'ing path", path); + std::string localPath = path; + + if (std::count(localPath.begin(), localPath.end(), '/') == 1) { + localPath = localPath + "/"; + } std::string exposedPath, object; - auto rv = parsePath(path, exposedPath, object); + auto rv = parsePath(localPath.c_str(), exposedPath, object); if (rv != 0) { return rv; } @@ -226,7 +232,7 @@ int S3FileSystem::Stat(const char *path, struct stat *buff, int opts, if (httpCode == 0) { if (m_log.getMsgMask() & XrdHTTPServer::Info) { std::stringstream ss; - ss << "Failed to stat path " << path + ss << "Failed to stat path " << localPath << "; error: " << listCommand.getErrorMessage() << " (code=" << listCommand.getErrorCode() << ")"; m_log.Log(XrdHTTPServer::Info, "Stat", ss.str().c_str()); @@ -235,7 +241,7 @@ int S3FileSystem::Stat(const char *path, struct stat *buff, int opts, } else { if (m_log.getMsgMask() & XrdHTTPServer::Info) { std::stringstream ss; - ss << "Failed to stat path " << path << "; response code " + ss << "Failed to stat path " << localPath << "; response code " << httpCode; m_log.Log(XrdHTTPServer::Info, "Stat", ss.str().c_str()); } diff --git a/test/s3_tests.cc b/test/s3_tests.cc index 099b334..f943e75 100644 --- a/test/s3_tests.cc +++ b/test/s3_tests.cc @@ -49,7 +49,8 @@ TEST(TestS3URLGeneration, Test1) { TestAmazonRequest pathReq{serviceUrl, "akf", "skf", b, o, "path", 4}; std::string generatedHostUrl = pathReq.getHostUrl(); ASSERT_EQ(generatedHostUrl, - "https://s3-service.com:443/test-bucket/test-object"); + "https://s3-service.com:443/test-bucket/test-object") + << "generatedURL: " << generatedHostUrl; // Test virtual-style URL generation TestAmazonRequest virtReq{serviceUrl, "akf", "skf", b, o, "virtual", 4};