The provided functions and classes only support a basic subset of the AWS API; all the methods simply invoke the S3Api::Send
method and return the parsed response. The preference is to avoid creating a fat interface with all the currently supported actions exposed as class methods which makes it impossible to extend the interface, and instead add free functions receiving a context argument and the relevant parameters to implement additional requests.
The main value of the current implementation (and other similar C++ clients) is the generation and parsing of XML text in addition to S3v4 signing. However, client code will most likely need to translate from the returned objects to their own domain-specific internal representation and it might therefore be easier to just parse the XML directly instead of mapping XML constructs to pre-defined C++ structs.
Any of the requests listed here can be sent using this library by:
- creating a function that returns
- request parameters as an
S3Api::SendParams
instance
- request body as text in XML format if required
- sending the request using the
S3Api::Send
method
- creating a function that returns the parsed response body and HTTP headers
- HTTP headers are already parsed and stored into a
map
object
- for parsing the returned XML you can use the provided parsing functions or use a library like pugixml (XPath compliant, value semantics, supports range based loops)
- in addition to high-level parsing functions, tinyXML2 is included in the source tree, used internally but can be used as well by client code
Example: Bucket tagging
We wold like to add the ability to tag buckets using code like:
TagMap tags = {{"tag1", "value1"}, {"tag2", "value2"}};
S3Api s3(access, secret, endpointUrl);
TagBucket(s3, "MyBucket", tags);
and read the tags with:
S3Api s3(access, secret, endpointUrl);
TagMap tags = BucketTags(s3, bucket);
assert(tags["tags1"] == "value1" && tags["tags2"] == "value2");
In the next section we are going to implement the TagBucket
and BucketTags
functions.
TagBucket: PutBucketTagging request
XML request body:
AWS Action
PUT /?tagging HTTP/1.1
Host: Bucket.s3.amazonaws.com
Content-MD5: ContentMD5
x-amz-sdk-checksum-algorithm: ChecksumAlgorithm
x-amz-expected-bucket-owner: ExpectedBucketOwner
<?xml version="1.0" encoding="UTF-8"?>
<Tagging xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<TagSet>
<Tag>
<Key>string</Key>
<Value>string</Value>
</Tag>
</TagSet>
</Tagging>
C++ implementation:
using namespace sss;
using namespace api;
using TagMap = std::unordered_map<std::string, std::string>;
std::unordered_map< std::string, std::string > TagMap
{name, value} map representing bucket or object tags.
Definition xml-parse-test.cpp:45
GeneratePutBucketTaggingRequest(const std::string& bucket,
XMLDocument doc;
os["Tagging/TagSet"];
for(auto kv: tags) {
os["Tag"];
os["Key"] = kv.first;
os["Value"] = kv.second;
os["/"];
}
return {.method = "PUT",
.bucket = bucket,
.params = {{"tagging", ""}},
.headers = headers,
.uploadData = os.XMLText()};
}
XMLGenerator. Use methods or overloaded subscript operator to insert data into XML tree.
Definition xmlstreams.h:125
Map Headers
HTTP headers.
Definition common.h:56
Send request parameters.
Definition s3-api.h:246
void TagBucket(
S3Api& s3,
const std::string& bucket,
auto args = GeneratePutBucketRequest(bucket, tags, headers);
}
S3 Client inteface.
Definition s3-api.h:193
const WebClient & Send(const SendParams &p)
Send request.
Definition s3-api.h:329
<tt>BucketTags</tt>: GetBucketTagging response
XML response body:
AWS Action
HTTP/1.1 200
<?xml version="1.0" encoding="UTF-8"?>
<Tagging>
<TagSet>
<Tag>
<Key>string</Key>
<Value>string</Value>
</Tag>
</TagSet>
</Tagging>
C++ implementation:
using namespace sss;
using namespace api;
using TagMap = std::unordered_map<std::string, std::string>;
TagMap ParseTaggingResponse(
const XML& xml) {
if(xml.empty()) {
return {};
}
for(auto i: r) {
const auto k =
Get(i,
"/key");
if(k.empty()) {
continue;
}
const auto v =
Get(i,
"/value");
if(v.empty()) {
continue;
}
m[k] = v;
}
return m;
}
TagMap BucketTags(
S3Api& s3,
const std::string& bucket) {
s3.SendRequest({.method = "GET",
.bucket = bucket,
.params = {{"tagging", ""}});
return ParseTaggingResponse(s3.GetBodyText());
}
XML parser, returns array of text elements with the same parent path or an array of parsed XML sub tr...
Definition xmlstreams.h:271
std::string Get(const XMLRecord &r, const std::string &path)
Definition xmlstreams.h:343
std::vector< XMLRecord > XMLRecords
Definition xmlstreams.h:68