Add simple XML parsing wrapper

Also simplify check_region_error.
This commit is contained in:
Andrew Gaul 2019-01-30 18:29:34 -08:00
parent 21321a9d96
commit b8ff6a647e
5 changed files with 68 additions and 99 deletions

View File

@ -31,9 +31,6 @@
#include <pthread.h>
#include <assert.h>
#include <curl/curl.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/tree.h>
#include <iostream>
#include <fstream>
#include <sstream>
@ -2531,50 +2528,6 @@ string S3fsCurl::CalcSignature(const string& method, const string& canonical_uri
return Signature;
}
// XML in BodyData has UploadId, Parse XML body for UploadId
bool S3fsCurl::GetUploadId(string& upload_id)
{
bool result = false;
if(!bodydata){
return result;
}
upload_id.clear();
xmlDocPtr doc;
if(NULL == (doc = xmlReadMemory(bodydata->str(), bodydata->size(), "", NULL, 0))){
return result;
}
if(NULL == doc->children){
S3FS_XMLFREEDOC(doc);
return result;
}
for(xmlNodePtr cur_node = doc->children->children; NULL != cur_node; cur_node = cur_node->next){
// For DEBUG
// string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
// printf("cur_node_name: %s\n", cur_node_name.c_str());
if(XML_ELEMENT_NODE == cur_node->type){
string elementName = reinterpret_cast<const char*>(cur_node->name);
// For DEBUG
// printf("elementName: %s\n", elementName.c_str());
if(cur_node->children){
if(XML_TEXT_NODE == cur_node->children->type){
if(elementName == "UploadId") {
upload_id = reinterpret_cast<const char *>(cur_node->children->content);
result = true;
break;
}
}
}
}
}
S3FS_XMLFREEDOC(doc);
return result;
}
void S3fsCurl::insertV4Headers()
{
string server_path = type == REQTYPE_LISTBUCKET ? "/" : path;
@ -3449,8 +3402,7 @@ int S3fsCurl::PreMultipartPostRequest(const char* tpath, headers_t& meta, string
return result;
}
// Parse XML body for UploadId
if(!S3fsCurl::GetUploadId(upload_id)){
if(!simple_parse_xml(bodydata->str(), bodydata->size(), "UploadId", upload_id)){
delete bodydata;
bodydata = NULL;
return -1;
@ -3793,33 +3745,12 @@ bool S3fsCurl::CopyMultipartPostCallback(S3fsCurl* s3fscurl)
bool S3fsCurl::CopyMultipartPostComplete()
{
// parse ETag from response
xmlDocPtr doc;
if(NULL == (doc = xmlReadMemory(bodydata->str(), bodydata->size(), "", NULL, 0))){
return false;
std::string etag;
partdata.uploaded = simple_parse_xml(bodydata->str(), bodydata->size(), "ETag", etag);
if(etag.size() >= 2 && *etag.begin() == '"' && *etag.rbegin() == '"'){
etag.assign(etag.substr(1, etag.size() - 2));
}
if(NULL == doc->children){
S3FS_XMLFREEDOC(doc);
return false;
}
for(xmlNodePtr cur_node = doc->children->children; NULL != cur_node; cur_node = cur_node->next){
if(XML_ELEMENT_NODE == cur_node->type){
string elementName = reinterpret_cast<const char*>(cur_node->name);
if(cur_node->children){
if(XML_TEXT_NODE == cur_node->children->type){
if(elementName == "ETag") {
string etag = reinterpret_cast<const char *>(cur_node->children->content);
if(etag.size() >= 2 && *etag.begin() == '"' && *etag.rbegin() == '"'){
etag.assign(etag.substr(1, etag.size() - 2));
}
partdata.etaglist->at(partdata.etagpos).assign(etag);
partdata.uploaded = true;
}
}
}
}
}
S3FS_XMLFREEDOC(doc);
partdata.etaglist->at(partdata.etagpos).assign(etag);
delete bodydata;
bodydata = NULL;

View File

@ -379,7 +379,6 @@ class S3fsCurl
void insertAuthHeaders();
std::string CalcSignatureV2(const std::string& method, const std::string& strMD5, const std::string& content_type, const std::string& date, const std::string& resource);
std::string CalcSignature(const std::string& method, const std::string& canonical_uri, const std::string& query_string, const std::string& strdate, const std::string& payload_hash, const std::string& date8601);
bool GetUploadId(std::string& upload_id);
int GetIAMCredentials(void);
int UploadMultipartPostSetup(const char* tpath, int part_num, const std::string& upload_id);

View File

@ -3766,39 +3766,30 @@ static int s3fs_utility_processing(time_t abort_time)
//
// If calling with wrong region, s3fs gets following error body as 400 error code.
// "<Error><Code>AuthorizationHeaderMalformed</Code><Message>The authorization header is
// malformed; the region 'us-east-1' is wrong; expecting 'ap-northeast-1'</Message>
// <Region>ap-northeast-1</Region><RequestId>...</RequestId><HostId>...</HostId>
// "<Error>
// <Code>AuthorizationHeaderMalformed</Code>
// <Message>The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'ap-northeast-1'</Message>
// <Region>ap-northeast-1</Region>
// <RequestId>...</RequestId>
// <HostId>...</HostId>
// </Error>"
//
// So this is cheep codes but s3fs should get correct region automatically.
// So this is cheap code but s3fs should get correct region automatically.
//
static bool check_region_error(const char* pbody, const string& currentep, string& expectregion)
static bool check_region_error(const char* pbody, size_t len, string& expectregion)
{
if(!pbody){
return false;
}
const char* region;
const char* regionend;
if(NULL == (region = strcasestr(pbody, "<Message>The authorization header is malformed; the region "))){
std::string code;
if(!simple_parse_xml(pbody, len, "Code", code) || code != "AuthorizationHeaderMalformed"){
return false;
}
// check current endpoint region in body.
if(NULL == (region = strcasestr(region, currentep.c_str()))){
if(!simple_parse_xml(pbody, len, "Region", expectregion)){
return false;
}
if(NULL == (region = strcasestr(region, "expecting \'"))){
return false;
}
region += strlen("expecting \'");
if(NULL == (regionend = strchr(region, '\''))){
return false;
}
string strtmp(region, (regionend - region));
if(0 == strtmp.length()){
return false;
}
expectregion = strtmp;
return true;
}
@ -3825,7 +3816,7 @@ static int s3fs_check_service()
// check region error(for putting message or retrying)
BodyData* body = s3fscurl.GetBodyData();
string expectregion;
if(check_region_error(body->str(), endpoint, expectregion)){
if(check_region_error(body->str(), body->size(), expectregion)){
// [NOTE]
// If endpoint is not specified(using us-east-1 region) and
// an error is encountered accessing a different region, we

View File

@ -31,6 +31,9 @@
#include <pthread.h>
#include <sys/types.h>
#include <dirent.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/tree.h>
#include <string>
#include <sstream>
@ -972,6 +975,50 @@ bool is_need_check_obj_detail(headers_t& meta)
return true;
}
bool simple_parse_xml(const char* data, size_t len, const char* key, std::string& value)
{
bool result = false;
if(!data || !key){
return result;
}
value.clear();
xmlDocPtr doc;
if(NULL == (doc = xmlReadMemory(data, len, "", NULL, 0))){
return result;
}
if(NULL == doc->children){
S3FS_XMLFREEDOC(doc);
return result;
}
for(xmlNodePtr cur_node = doc->children->children; NULL != cur_node; cur_node = cur_node->next){
// For DEBUG
// string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
// printf("cur_node_name: %s\n", cur_node_name.c_str());
if(XML_ELEMENT_NODE == cur_node->type){
string elementName = reinterpret_cast<const char*>(cur_node->name);
// For DEBUG
// printf("elementName: %s\n", elementName.c_str());
if(cur_node->children){
if(XML_TEXT_NODE == cur_node->children->type){
if(elementName == key) {
value = reinterpret_cast<const char *>(cur_node->children->content);
result = true;
break;
}
}
}
}
}
S3FS_XMLFREEDOC(doc);
return result;
}
//-------------------------------------------------------------------
// Help
//-------------------------------------------------------------------

View File

@ -133,6 +133,7 @@ time_t cvtIAMExpireStringToTime(const char* s);
time_t get_lastmodified(const char* s);
time_t get_lastmodified(headers_t& meta);
bool is_need_check_obj_detail(headers_t& meta);
bool simple_parse_xml(const char* data, size_t len, const char* key, std::string& value);
void show_usage(void);
void show_help(void);