Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S3 Multibucket #23

Merged
merged 18 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ endif()

include_directories(${XROOTD_INCLUDES} ${CURL_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS})

add_library(XrdS3 SHARED src/S3File.cc src/S3FileSystem.cc src/AWSv4-impl.cc src/S3Commands.cc src/HTTPCommands.cc src/stl_string_utils.cc src/shortfile.cc src/logging.cc)
add_library(XrdS3 SHARED src/S3File.cc src/S3AccessInfo.cc src/S3FileSystem.cc src/AWSv4-impl.cc src/S3Commands.cc src/HTTPCommands.cc src/stl_string_utils.cc src/shortfile.cc src/logging.cc)
add_library(XrdHTTPServer SHARED src/HTTPFile.cc src/HTTPFileSystem.cc src/HTTPCommands.cc src/stl_string_utils.cc src/shortfile.cc src/logging.cc)

target_link_libraries(XrdS3 -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${CURL_LIBRARIES} ${LIBCRYPTO_LIBRARIES})
Expand Down
38 changes: 31 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ ofs.osslib libXrdHTTPServer.so
# Upon last testing, the plugin did not yet work in async mode
xrootd.async off



# Configure the upstream HTTP server that XRootD is to treat as a filesystem
httpserver.host_name <hostname of HTTP server>
httpserver.host_url <host url>
Expand Down Expand Up @@ -127,13 +129,35 @@ ofs.osslib libXrdS3.so
# Upon last testing, the plugin did not yet work in async mode
xrootd.async off

# Configure the upstream HTTP server that XRootD is to treat as a filesystem
s3.service_name <s3 service name, eg s3.amazonaws.com>
s3.region <s3 region, eg us-east-1>
s3.service_url <s3 service url, eg https://s3.us-east-1.amazonaws.com>
# For buckets requiring an access/secret key:
# s3.access_key_file </path/to/access_key>
# s3.secret_key_file </path/to/secret_key>
#example url
#https://<origin url>/my-magic-path/bar/foo
# these must be in this order to allow parsing of multiple entries
# To export a bucket requiring an access/private key:
s3.begin
s3.path_name my-magic-path
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved
s3.bucket_name hubzero-private-rich
s3.service_name s3.amazonaws.com
s3.region us-east-1
s3.access_key_file /xrootd-dev/access-key
s3.secret_key_file /xrootd-dev/secret-key
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved
s3.service_url https://s3.us-east-1.amazonaws.com
s3.end

# To export an unauthenticated (public) bucket, remove
# the key-related directives
s3.begin
s3.path_name my-other-magic-path
s3.bucket_name hubzero-private-rich-2
s3.service_name s3.amazonaws.com
s3.region us-east-1
s3.service_url https://s3.us-east-1.amazonaws.com
s3.end

# Specify the path style for URL queries at the endpoint. Valid
# options are `path` and `virtual`, where path corresponds to URLs
# like `https://my-service-url.com/bucket/object` and virtual
# corresponds to URLs like `https://bucket.my-service-url.com/object`
s3.url_style virtual
```


Expand Down
51 changes: 51 additions & 0 deletions src/S3AccessInfo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Created by Rich Wellner on 2/29/24.
//

#include "S3AccessInfo.hh"

const std::string &S3AccessInfo::getS3BucketName() const {
return s3_bucket_name;
}

void S3AccessInfo::setS3BucketName(const std::string &s3BucketName) {
s3_bucket_name = s3BucketName;
}

const std::string &S3AccessInfo::getS3ServiceName() const {
return s3_service_name;
}

void S3AccessInfo::setS3ServiceName(const std::string &s3ServiceName) {
s3_service_name = s3ServiceName;
}

const std::string &S3AccessInfo::getS3Region() const { return s3_region; }

void S3AccessInfo::setS3Region(const std::string &s3Region) {
s3_region = s3Region;
}

const std::string &S3AccessInfo::getS3ServiceUrl() const {
return s3_service_url;
}

void S3AccessInfo::setS3ServiceUrl(const std::string &s3ServiceUrl) {
s3_service_url = s3ServiceUrl;
}

const std::string &S3AccessInfo::getS3AccessKeyFile() const {
return s3_access_key_file;
}

void S3AccessInfo::setS3AccessKeyFile(const std::string &s3AccessKeyFile) {
s3_access_key_file = s3AccessKeyFile;
}

const std::string &S3AccessInfo::getS3SecretKeyFile() const {
return s3_secret_key_file;
}

void S3AccessInfo::setS3SecretKeyFile(const std::string &s3SecretKeyFile) {
s3_secret_key_file = s3SecretKeyFile;
}
46 changes: 46 additions & 0 deletions src/S3AccessInfo.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Created by Rich Wellner on 2/29/24.
//

#ifndef XROOTD_S3_HTTP_S3ACCESSINFO_HH
#define XROOTD_S3_HTTP_S3ACCESSINFO_HH


#include <string>

class S3AccessInfo {
public:
const std::string &getS3BucketName() const;

void setS3BucketName(const std::string &s3BucketName);

const std::string &getS3ServiceName() const;

void setS3ServiceName(const std::string &s3ServiceName);

const std::string &getS3Region() const;

void setS3Region(const std::string &s3Region);

const std::string &getS3ServiceUrl() const;

void setS3ServiceUrl(const std::string &s3ServiceUrl);

const std::string &getS3AccessKeyFile() const;

void setS3AccessKeyFile(const std::string &s3AccessKeyFile);

const std::string &getS3SecretKeyFile() const;

void setS3SecretKeyFile(const std::string &s3SecretKeyFile);

private:
std::string s3_bucket_name;
std::string s3_service_name;
std::string s3_region;
std::string s3_service_url;
std::string s3_access_key_file;
std::string s3_secret_key_file;
};

#endif //XROOTD_S3_HTTP_S3ACCESSINFO_HH
7 changes: 2 additions & 5 deletions src/S3Commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,10 @@
return AWSv4Impl::canonicalizeQueryString( query_parameters );
}

// Takes in the configured `s3.service_url` and uses the bucket/object requested to generate

Check warning on line 56 in src/S3Commands.cc

View workflow job for this annotation

GitHub Actions / Run linters

[lint] reported by reviewdog 🐶 Raw Output: src/S3Commands.cc:56:-// Takes in the configured `s3.service_url` and uses the bucket/object requested to generate src/S3Commands.cc:57:-// the virtual host URL, as well as the canonical URI (which is the path to the object). src/S3Commands.cc:58:-bool AmazonRequest::parseURL( const std::string & url, src/S3Commands.cc:59:- std::string & path ) { src/S3Commands.cc:60:- auto i = url.find( "://" ); src/S3Commands.cc:61:- if( i == std::string::npos ) { return false; } src/S3Commands.cc:62:- //protocol = substring( url, 0, i ); src/S3Commands.cc:63:- src/S3Commands.cc:64:- auto j = url.find( "/", i + 3 ); src/S3Commands.cc:65:- if( j == std::string::npos ) { src/S3Commands.cc:66:- if (style == "path") { src/S3Commands.cc:67:- host = substring( url, i + 3 ); src/S3Commands.cc:68:- } else { src/S3Commands.cc:69:- host = bucket + "." + substring( url, i + 3 ); src/S3Commands.cc:70:- } src/S3Commands.cc:71:- src/S3Commands.cc:72:- path = "/" + object; src/S3Commands.cc:73:- return true; src/S3Commands.cc:57:+// Takes in the configured `s3.service_url` and uses the bucket/object requested src/S3Commands.cc:58:+// to generate the virtual host URL, as well as the canonical URI (which is the src/S3Commands.cc:59:+// path to the object). src/S3Commands.cc:60:+bool AmazonRequest::parseURL(const std::string &url, std::string &path) { src/S3Commands.cc:61:+ auto i = url.find("://"); src/S3Commands.cc:62:+ if (i == std::string::npos) { src/S3Commands.cc:63:+ return false; src/S3Commands.cc:64:+ } src/S3Commands.cc:65:+ // protocol = substring( url, 0, i ); src/S3Commands.cc:66:+ src/S3Commands.cc:67:+ auto j = url.find("/", i + 3); src/S3Commands.cc:68:+ if (j == std::string::npos) { src/S3Commands.cc:69:+ if (style == "path") { src/S3Commands.cc:70:+ host = substring(url, i + 3); src/S3Commands.cc:71:+ } else { src/S3Commands.cc:72:+ host = bucket + "." + substring(url, i + 3);
// the virtual host URL, as well as the canonical URI (which is the path to the object).
bool AmazonRequest::parseURL( const std::string & url,
const std::string & bucket,
const std::string & object,
std::string & host,
std::string & path ) {
bool AmazonRequest::parseURL( const std::string & url,
std::string & path ) {
auto i = url.find( "://" );
if( i == std::string::npos ) { return false; }
//protocol = substring( url, 0, i );
Expand Down
8 changes: 4 additions & 4 deletions src/S3Commands.hh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public:
// Start off by parsing the hostUrl, which we use in conjunction with the bucket to fill in the host (for setting host header).
// For example, if the incoming hostUrl (which we get from config) is "https://my-url.com:443", the bucket is "my-bucket", and
// the object is "my-object", then the host will be "my-bucket.my-url.com:443" and the canonicalURI will be "/my-object".
if (! parseURL(hostUrl, b, o, host, canonicalURI)) {
if (! parseURL(hostUrl, canonicalURI)) {
errorCode = "E_INVALID_SERVICE_URL";
errorMessage = "Failed to parse host and canonicalURI from service URL.";
}
Expand Down Expand Up @@ -75,9 +75,9 @@ public:
return &secretKeyFile; }

bool parseURL( const std::string & url,
const std::string & bucket,
const std::string & object,
std::string & host,
//const std::string & bucket,
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved
//const std::string & object,
//std::string & host,
std::string & path );

virtual bool SendRequest();
Expand Down
73 changes: 39 additions & 34 deletions src/S3File.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

XrdVERSIONINFO(XrdOssGetFileSystem, S3);

S3File::S3File(XrdSysError &log, S3FileSystem *oss) :

Check warning on line 48 in src/S3File.cc

View workflow job for this annotation

GitHub Actions / Run linters

[lint] reported by reviewdog 🐶 Raw Output: src/S3File.cc:48:-S3File::S3File(XrdSysError &log, S3FileSystem *oss) : src/S3File.cc:49:- m_log(log), src/S3File.cc:50:- m_oss(oss), src/S3File.cc:51:- content_length(0), src/S3File.cc:52:- last_modified(0) src/S3File.cc:53:-{} src/S3File.cc:54:- src/S3File.cc:55:- src/S3File.cc:56:-int src/S3File.cc:57:-parse_path( const S3FileSystem & fs, const char * fullPath, std::string & exposedPath, std::string & object ) { src/S3File.cc:58:- // src/S3File.cc:59:- // Check the path for validity. src/S3File.cc:60:- // src/S3File.cc:61:- std::filesystem::path p(fullPath); src/S3File.cc:62:- auto pathComponents = p.begin(); src/S3File.cc:63:- src/S3File.cc:64:- // Iterate through components of the fullPath until we either find a match src/S3File.cc:65:- // or we've reached the end of the path. src/S3File.cc:66:- std::filesystem::path currentPath = *pathComponents; src/S3File.cc:67:- while (pathComponents != p.end()) { src/S3File.cc:68:- if (fs.exposedPathExists(currentPath.string())) { src/S3File.cc:69:- exposedPath = currentPath.string(); src/S3File.cc:70:- break; src/S3File.cc:71:- } src/S3File.cc:72:- ++pathComponents; src/S3File.cc:73:- if (pathComponents != p.end()) { src/S3File.cc:74:- currentPath /= *pathComponents; src/S3File.cc:75:- } else { src/S3File.cc:76:- return -ENOENT; src/S3File.cc:77:- } src/S3File.cc:48:+S3File::S3File(XrdSysError &log, S3FileSystem *oss) src/S3File.cc:49:+ : m_log(log), m_oss(oss), content_length(0), last_modified(0) {} src/S3File.cc:50:+ src/S3File.cc:51:+int parse_path(const S3FileSystem &fs, const char *fullPath, src/S3File.cc:52:+ std::string &exposedPath, std::string &object) { src/S3File.cc:53:+ // src/S3File.cc:54:+ // Check the path for validity. src/S3File.cc:55:+ // src/S3File.cc:56:+ std::filesystem::path p(fullPath); src/S3File.cc:57:+ auto pathComponents = p.begin(); src/S3File.cc:58:+ src/S3File.cc:59:+ // Iterate through components of the fullPath until we either find a match src/S3File.cc:60:+ // or we've reached the end of the path. src/S3File.cc:61:+ std::filesystem::path currentPath = *pathComponents; src/S3File.cc:62:+ while (pathComponents != p.end()) { src/S3File.cc:63:+ if (fs.exposedPathExists(currentPath.string())) { src/S3File.cc:64:+ exposedPath = currentPath.string(); src/S3File.cc:65:+ break;
m_log(log),
m_oss(oss),
content_length(0),
Expand All @@ -54,70 +54,75 @@


int
parse_path( const S3FileSystem & fs, const char * path, std::string & bucket, std::string & object ) {
const std::string & configured_s3_service_name = fs.getS3ServiceName();
const std::string & configured_s3_region = fs.getS3Region();

parse_path( const S3FileSystem & fs, const char * fullPath, std::string & exposedPath, std::string & object ) {
//
// Check the path for validity.
//
std::filesystem::path p(path);
std::filesystem::path p(fullPath);
auto pathComponents = p.begin();

++pathComponents;
if(pathComponents == p.end()) { return -ENOENT; }
if (* pathComponents != configured_s3_service_name) {
return -ENOENT;
}

++pathComponents;
if (pathComponents == p.end()) { return -ENOENT; }
if (*pathComponents != configured_s3_region) {
return -ENOENT;
// Iterate through components of the fullPath until we either find a match
// or we've reached the end of the path.
std::filesystem::path currentPath = *pathComponents;
while (pathComponents != p.end()) {
if (fs.exposedPathExists(currentPath.string())) {
exposedPath = currentPath.string();
break;
}
++pathComponents;
if (pathComponents != p.end()) {
currentPath /= *pathComponents;
} else {
return -ENOENT;
}
}

++pathComponents;
if (pathComponents == p.end()) { return -ENOENT; }
bucket = *pathComponents;

// Objects names may contain path separators.
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved
++pathComponents;
if (pathComponents == p.end()) { return -ENOENT; }
if( pathComponents == p.end() ) { return -ENOENT; }

std::filesystem::path objectPath = *pathComponents++;
for ( ; pathComponents != p.end(); ++pathComponents) {
objectPath /= (*pathComponents);
for( ; pathComponents != p.end(); ++pathComponents ) {
objectPath /= (* pathComponents);
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved
}
object = objectPath.string();
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved

fprintf( stderr, "object = %s\n", object.c_str() );
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved

return 0;
}
jhiemstrawisc marked this conversation as resolved.
Show resolved Hide resolved


int

Check warning on line 96 in src/S3File.cc

View workflow job for this annotation

GitHub Actions / Run linters

[lint] reported by reviewdog 🐶 Raw Output: src/S3File.cc:96:-int src/S3File.cc:97:-S3File::Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env) src/S3File.cc:98:-{ src/S3File.cc:99:- std::string exposedPath, object; src/S3File.cc:100:- int rv = parse_path( * m_oss, path, exposedPath, object ); src/S3File.cc:101:- if( rv != 0 ) { return rv; } src/S3File.cc:102:- if(!m_oss->exposedPathExists(exposedPath)) return -ENOENT; src/S3File.cc:103:- src/S3File.cc:104:- std::string configured_s3_region = m_oss->getS3Region(exposedPath); src/S3File.cc:105:- std::string configured_s3_service_url = m_oss->getS3ServiceURL(exposedPath); src/S3File.cc:106:- std::string configured_s3_access_key = m_oss->getS3AccessKeyFile(exposedPath); src/S3File.cc:107:- std::string configured_s3_secret_key = m_oss->getS3SecretKeyFile(exposedPath); src/S3File.cc:108:- std::string configured_s3_bucket_name = m_oss->getS3BucketName(exposedPath); src/S3File.cc:109:- src/S3File.cc:110:- // We used to query S3 here to see if the object existed, but of course src/S3File.cc:111:- // if you're creating a file on upload, you don't care. src/S3File.cc:112:- src/S3File.cc:113:- this->s3_object_name = object; src/S3File.cc:114:- this->s3_bucket_name = configured_s3_bucket_name; src/S3File.cc:115:- this->s3_service_url = configured_s3_service_url; src/S3File.cc:116:- this->s3_access_key = configured_s3_access_key; src/S3File.cc:117:- this->s3_secret_key = configured_s3_secret_key; src/S3File.cc:118:- std::string configured_s3_url_style = m_oss->getS3URLStyle(); src/S3File.cc:119:- src/S3File.cc:120:- src/S3File.cc:121:- // We used to query S3 here to see if the object existed, but of course src/S3File.cc:122:- // if you're creating a file on upload, you don't care. src/S3File.cc:123:- src/S3File.cc:124:- this->s3_object_name = object; src/S3File.cc:125:- this->s3_bucket_name = configured_s3_bucket_name; src/S3File.cc:126:- this->s3_service_url = configured_s3_service_url; src/S3File.cc:127:- this->s3_access_key = configured_s3_access_key; src/S3File.cc:128:- this->s3_secret_key = configured_s3_secret_key; src/S3File.cc:129:- this->s3_url_style = configured_s3_url_style; src/S3File.cc:130:- return 0; src/S3File.cc:89:+ return 0;
S3File::Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env)
{
std::string configured_s3_region = m_oss->getS3Region();

//
// Check the path for validity.
//
std::string bucket, object;
int rv = parse_path( * m_oss, path, bucket, object );
std::string exposedPath, object;
int rv = parse_path( * m_oss, path, exposedPath, object );
if( rv != 0 ) { return rv; }
if(!m_oss->exposedPathExists(exposedPath)) return -ENOENT;

std::string configured_s3_region = m_oss->getS3Region(exposedPath);
std::string configured_s3_service_url = m_oss->getS3ServiceURL(exposedPath);
std::string configured_s3_access_key = m_oss->getS3AccessKeyFile(exposedPath);
std::string configured_s3_secret_key = m_oss->getS3SecretKeyFile(exposedPath);
std::string configured_s3_bucket_name = m_oss->getS3BucketName(exposedPath);

std::string configured_s3_service_url = m_oss->getS3ServiceURL();
std::string configured_s3_access_key = m_oss->getS3AccessKeyFile();
std::string configured_s3_secret_key = m_oss->getS3SecretKeyFile();
// We used to query S3 here to see if the object existed, but of course
// if you're creating a file on upload, you don't care.

this->s3_object_name = object;
this->s3_bucket_name = configured_s3_bucket_name;
this->s3_service_url = configured_s3_service_url;
this->s3_access_key = configured_s3_access_key;
this->s3_secret_key = configured_s3_secret_key;
std::string configured_s3_url_style = m_oss->getS3URLStyle();


// We used to query S3 here to see if the object existed, but of course
// if you're creating a file on upload, you don't care.

this->s3_object_name = object;
this->s3_bucket_name = bucket;
this->s3_bucket_name = configured_s3_bucket_name;
this->s3_service_url = configured_s3_service_url;
this->s3_access_key = configured_s3_access_key;
this->s3_secret_key = configured_s3_secret_key;
Expand Down Expand Up @@ -178,7 +183,7 @@
}


std::string headers = head.getResultString();

Check warning on line 186 in src/S3File.cc

View workflow job for this annotation

GitHub Actions / Run linters

[lint] reported by reviewdog 🐶 Raw Output: src/S3File.cc:186:- std::string headers = head.getResultString(); src/S3File.cc:187:- src/S3File.cc:188:- std::string line; src/S3File.cc:189:- size_t current_newline = 0; src/S3File.cc:190:- size_t next_newline = std::string::npos; src/S3File.cc:191:- size_t last_character = headers.size(); src/S3File.cc:192:- while( current_newline != std::string::npos && current_newline != last_character - 1 ) { src/S3File.cc:193:- next_newline = headers.find( "\r\n", current_newline + 2); src/S3File.cc:194:- line = substring( headers, current_newline + 2, next_newline ); src/S3File.cc:195:- src/S3File.cc:196:- size_t colon = line.find(":"); src/S3File.cc:197:- if( colon != std::string::npos && colon != line.size() ) { src/S3File.cc:198:- std::string attr = substring( line, 0, colon ); src/S3File.cc:199:- std::string value = substring( line, colon + 1 ); src/S3File.cc:200:- trim(value); src/S3File.cc:201:- toLower(attr); src/S3File.cc:202:- src/S3File.cc:203:- if( attr == "content-length" ) { src/S3File.cc:204:- this->content_length = std::stol(value); src/S3File.cc:205:- } else if( attr == "last-modified" ) { src/S3File.cc:206:- struct tm t; src/S3File.cc:207:- char * eos = strptime( value.c_str(), src/S3File.cc:208:- "%a, %d %b %Y %T %Z", src/S3File.cc:209:- & t ); src/S3File.cc:210:- if( eos == & value.c_str()[value.size()] ) { src/S3File.cc:211:- time_t epoch = timegm(& t); src/S3File.cc:212:- if( epoch != -1 ) { src/S3File.cc:213:- this->last_modified = epoch; src/S3File.cc:214:- } src/S3File.cc:215:- } src/S3File.cc:216:- } src/S3File.cc:147:+int S3File::Fstat(struct stat *buff) { src/S3File.cc:148:+ AmazonS3Head head(this->s3_service_url, this->s3_access_key, src/S3File.cc:149:+ this->s3_secret_key, this->s3_bucket_name, src/S3File.cc:150:+ this->s3_object_name, this->s3_url_style, m_log); src/S3File.cc:151:+ src/S3File.cc:152:+ if (!head.SendRequest()) { src/S3File.cc:153:+ // SendRequest() returns false for all errors, including ones src/S3File.cc:154:+ // where the server properly responded with something other src/S3File.cc:155:+ // than code 200. If xrootd wants us to distinguish between src/S3File.cc:156:+ // these cases, head.getResponseCode() is initialized to 0, so src/S3File.cc:157:+ // we can check. src/S3File.cc:158:+ std::stringstream ss; src/S3File.cc:159:+ ss << "Failed to send HeadObject command: " << head.getResponseCode() << "'" src/S3File.cc:160:+ << head.getResultString() << "'"; src/S3File.cc:161:+ m_log.Log(LogMask::Warning, "S3File::Fstat", ss.str().c_str()); src/S3File.cc:162:+ return -ENOENT; src/S3File.cc:163:+ } src/S3File.cc:164:+ src/S3File.cc:165:+ std::string headers = head.getResultString(); src/S3File.cc:166:+ src/S3File.cc:167:+ std::string line; src/S3File.cc:168:+ size_t current_newline = 0; src/S3File.cc:169:+ size_t next_newline = std::string::npos; src/S3File.cc:170:+ size_t last_character = headers.size(); src/S3File.cc:171:+ while (current_newline != std::string::npos && src/S3File.cc:172:+ current_newline != last_character - 1) { src/S3File.cc:173:+ next_newline = headers.find("\r\n", current_newline + 2); src/S3File.cc:174:+ line = substring(headers, current_newline + 2, next_newline); src/S3File.cc:175:+ src/S3File.cc:176:+ size_t colon = line.find(":"); src/S3File.cc:177:+ if (colon != std::string::npos && colon != line.size()) { src/S3File.cc:178:+ std::string attr = substring(line, 0, colon); src/S3File.cc:179:+ std::string value = substring(line, colon + 1); src/S3File.cc:180:+ trim(value); src/S3File.cc:181:+ toLower(attr); src/S3File.cc:182:+ src/S3File.cc:183:+ if (attr == "content-length") { src/S3

std::string line;
size_t current_newline = 0;
Expand All @@ -186,7 +191,7 @@
size_t last_character = headers.size();
while( current_newline != std::string::npos && current_newline != last_character - 1 ) {
next_newline = headers.find( "\r\n", current_newline + 2);
std::string line = substring( headers, current_newline + 2, next_newline );
line = substring( headers, current_newline + 2, next_newline );

size_t colon = line.find(":");
if( colon != std::string::npos && colon != line.size() ) {
Expand Down
2 changes: 1 addition & 1 deletion src/S3File.hh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

#include <memory>

int parse_path( const S3FileSystem & fs, const char * path, std::string & bucket, std::string & object );
int parse_path( const S3FileSystem & fs, const char * path, std::string & exposedPath, std::string & object );

class S3File : public XrdOssDF {
public:
Expand Down
Loading
Loading