From: Radoslaw Zarzynski Date: Wed, 14 Sep 2016 11:54:27 +0000 (+0200) Subject: rgw: ONLY move the parts of RGWPostObj_ObjStore_S3 to RGWPostObj_ObjStore. X-Git-Tag: v12.0.3~99^2~23 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=593fb572ea426658c1b9a4da2647b27a57c596e7;p=ceph.git rgw: ONLY move the parts of RGWPostObj_ObjStore_S3 to RGWPostObj_ObjStore. Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 175ceb9606b..79ed7b20867 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -1236,6 +1236,266 @@ int RGWPutObj_ObjStore::get_data(bufferlist& bl) return len; } + +/* + * parses params in the format: 'first; param1=foo; param2=bar' + */ +static void parse_params(const string& params_str, string& first, + map& params) +{ + size_t pos = params_str.find(';'); + if (pos == string::npos) { + first = rgw_trim_whitespace(params_str); + return; + } + + first = rgw_trim_whitespace(params_str.substr(0, pos)); + + pos++; + + while (pos < params_str.size()) { + size_t end = params_str.find(';', pos); + if (end == string::npos) + end = params_str.size(); + + string param = params_str.substr(pos, end - pos); + + size_t eqpos = param.find('='); + if (eqpos != string::npos) { + params[rgw_trim_whitespace(param.substr(0, eqpos))] = + rgw_trim_quotes(param.substr(eqpos + 1)); + } else { + params[rgw_trim_whitespace(param)] = ""; + } + + pos = end + 1; + } +} + +static int parse_part_field(const string& line, string& field_name, + struct post_part_field& field) +{ + size_t pos = line.find(':'); + if (pos == string::npos) + return -EINVAL; + + field_name = line.substr(0, pos); + if (pos >= line.size() - 1) + return 0; + + parse_params(line.substr(pos + 1), field.val, field.params); + + return 0; +} + +bool is_crlf(const char *s) +{ + return (*s == '\r' && *(s + 1) == '\n'); +} + +/* + * find the index of the boundary, if exists, or optionally the next end of line + * also returns how many bytes to skip + */ +static int index_of(bufferlist& bl, int max_len, const string& str, + bool check_crlf, + bool *reached_boundary, int *skip) +{ + *reached_boundary = false; + *skip = 0; + + if (str.size() < 2) // we assume boundary is at least 2 chars (makes it easier with crlf checks) + return -EINVAL; + + if (bl.length() < str.size()) + return -1; + + const char *buf = bl.c_str(); + const char *s = str.c_str(); + + if (max_len > (int)bl.length()) + max_len = bl.length(); + + int i; + for (i = 0; i < max_len; i++, buf++) { + if (check_crlf && + i >= 1 && + is_crlf(buf - 1)) { + return i + 1; // skip the crlf + } + if ((i < max_len - (int)str.size() + 1) && + (buf[0] == s[0] && buf[1] == s[1]) && + (strncmp(buf, s, str.size()) == 0)) { + *reached_boundary = true; + *skip = str.size(); + + /* oh, great, now we need to swallow the preceding crlf + * if exists + */ + if ((i >= 2) && + is_crlf(buf - 2)) { + i -= 2; + *skip += 2; + } + return i; + } + } + + return -1; +} + +int RGWPostObj_ObjStore_S3::read_with_boundary(bufferlist& bl, uint64_t max, + bool check_crlf, + bool *reached_boundary, + bool *done) +{ + uint64_t cl = max + 2 + boundary.size(); + + if (max > in_data.length()) { + uint64_t need_to_read = cl - in_data.length(); + + bufferptr bp(need_to_read); + + const auto read_len = recv_body(s, bp.c_str(), need_to_read); + in_data.append(bp, 0, read_len); + } + + *done = false; + int skip; + int index = index_of(in_data, cl, boundary, check_crlf, reached_boundary, + &skip); + if (index >= 0) + max = index; + + if (max > in_data.length()) + max = in_data.length(); + + bl.substr_of(in_data, 0, max); + + bufferlist new_read_data; + + /* + * now we need to skip boundary for next time, also skip any crlf, or + * check to see if it's the last final boundary (marked with "--" at the end + */ + if (*reached_boundary) { + int left = in_data.length() - max; + if (left < skip + 2) { + int need = skip + 2 - left; + bufferptr boundary_bp(need); + recv_body(s, boundary_bp.c_str(), need); + in_data.append(boundary_bp); + } + max += skip; // skip boundary for next time + if (in_data.length() >= max + 2) { + const char *data = in_data.c_str(); + if (is_crlf(data + max)) { + max += 2; + } else { + if (*(data + max) == '-' && + *(data + max + 1) == '-') { + *done = true; + max += 2; + } + } + } + } + + new_read_data.substr_of(in_data, max, in_data.length() - max); + in_data = new_read_data; + + return 0; +} + +int RGWPostObj_ObjStore_S3::read_line(bufferlist& bl, uint64_t max, + bool *reached_boundary, bool *done) +{ + return read_with_boundary(bl, max, true, reached_boundary, done); +} + +int RGWPostObj_ObjStore_S3::read_data(bufferlist& bl, uint64_t max, + bool *reached_boundary, bool *done) +{ + return read_with_boundary(bl, max, false, reached_boundary, done); +} + + +int RGWPostObj_ObjStore_S3::read_form_part_header(struct post_form_part *part, + bool *done) +{ + bufferlist bl; + bool reached_boundary; + uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; + int r = read_line(bl, chunk_size, &reached_boundary, done); + if (r < 0) + return r; + + if (*done) { + return 0; + } + + if (reached_boundary) { // skip the first boundary + r = read_line(bl, chunk_size, &reached_boundary, done); + if (r < 0) + return r; + if (*done) + return 0; + } + + while (true) { + /* + * iterate through fields + */ + string line = rgw_trim_whitespace(string(bl.c_str(), bl.length())); + + if (line.empty()) + break; + + struct post_part_field field; + + string field_name; + r = parse_part_field(line, field_name, field); + if (r < 0) + return r; + + part->fields[field_name] = field; + + if (stringcasecmp(field_name, "Content-Disposition") == 0) { + part->name = field.params["name"]; + } + + if (reached_boundary) + break; + + r = read_line(bl, chunk_size, &reached_boundary, done); + } + + return 0; +} + +bool RGWPostObj_ObjStore_S3::part_str(const string& name, string *val) +{ + map::iterator iter + = parts.find(name); + if (iter == parts.end()) + return false; + + bufferlist& data = iter->second.data; + string str = string(data.c_str(), data.length()); + *val = rgw_trim_whitespace(str); + return true; +} + +bool RGWPostObj_ObjStore_S3::part_bl(const string& name, bufferlist *pbl) +{ + map::iterator iter = + parts.find(name); + if (iter == parts.end()) + return false; + + *pbl = iter->second.data; + return true; +} int RGWPostObj_ObjStore::verify_params() { /* check that we have enough memory to store the object diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index c618f532f3c..18ec59be4e4 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -216,8 +216,39 @@ public: int get_padding_last_aws4_chunk_encoded(bufferlist &bl, uint64_t chunk_size); }; +struct post_part_field { + string val; + map params; +}; + +struct post_form_part { + string name; + string content_type; + map fields; + bufferlist data; +}; + class RGWPostObj_ObjStore : public RGWPostObj { +protected: + bufferlist in_data; + map parts; + + int read_with_boundary(bufferlist& bl, uint64_t max, bool check_eol, + bool *reached_boundary, + bool *done); + + int read_line(bufferlist& bl, uint64_t max, + bool *reached_boundary, bool *done); + + int read_data(bufferlist& bl, uint64_t max, bool *reached_boundary, bool *done); + string boundary; + + int read_form_part_header(struct post_form_part *part, + bool *done); + bool part_str(const string& name, string *val); + bool part_bl(const string& name, bufferlist *pbl); + public: RGWPostObj_ObjStore() {} ~RGWPostObj_ObjStore() override {} diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index b790f254e4b..d93731f1989 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -1529,231 +1529,6 @@ static void parse_params(const string& params_str, string& first, } } -static int parse_part_field(const string& line, string& field_name, - struct post_part_field& field) -{ - size_t pos = line.find(':'); - if (pos == string::npos) - return -EINVAL; - - field_name = line.substr(0, pos); - if (pos >= line.size() - 1) - return 0; - - parse_params(line.substr(pos + 1), field.val, field.params); - - return 0; -} - -bool is_crlf(const char *s) -{ - return (*s == '\r' && *(s + 1) == '\n'); -} - -/* - * find the index of the boundary, if exists, or optionally the next end of line - * also returns how many bytes to skip - */ -static int index_of(bufferlist& bl, int max_len, const string& str, - bool check_crlf, - bool *reached_boundary, int *skip) -{ - *reached_boundary = false; - *skip = 0; - - if (str.size() < 2) // we assume boundary is at least 2 chars (makes it easier with crlf checks) - return -EINVAL; - - if (bl.length() < str.size()) - return -1; - - const char *buf = bl.c_str(); - const char *s = str.c_str(); - - if (max_len > (int)bl.length()) - max_len = bl.length(); - - int i; - for (i = 0; i < max_len; i++, buf++) { - if (check_crlf && - i >= 1 && - is_crlf(buf - 1)) { - return i + 1; // skip the crlf - } - if ((i < max_len - (int)str.size() + 1) && - (buf[0] == s[0] && buf[1] == s[1]) && - (strncmp(buf, s, str.size()) == 0)) { - *reached_boundary = true; - *skip = str.size(); - - /* oh, great, now we need to swallow the preceding crlf - * if exists - */ - if ((i >= 2) && - is_crlf(buf - 2)) { - i -= 2; - *skip += 2; - } - return i; - } - } - - return -1; -} - -int RGWPostObj_ObjStore_S3::read_with_boundary(bufferlist& bl, uint64_t max, - bool check_crlf, - bool *reached_boundary, - bool *done) -{ - uint64_t cl = max + 2 + boundary.size(); - - if (max > in_data.length()) { - uint64_t need_to_read = cl - in_data.length(); - - bufferptr bp(need_to_read); - - const auto read_len = recv_body(s, bp.c_str(), need_to_read); - in_data.append(bp, 0, read_len); - } - - *done = false; - int skip; - int index = index_of(in_data, cl, boundary, check_crlf, reached_boundary, - &skip); - if (index >= 0) - max = index; - - if (max > in_data.length()) - max = in_data.length(); - - bl.substr_of(in_data, 0, max); - - bufferlist new_read_data; - - /* - * now we need to skip boundary for next time, also skip any crlf, or - * check to see if it's the last final boundary (marked with "--" at the end - */ - if (*reached_boundary) { - int left = in_data.length() - max; - if (left < skip + 2) { - int need = skip + 2 - left; - bufferptr boundary_bp(need); - recv_body(s, boundary_bp.c_str(), need); - in_data.append(boundary_bp); - } - max += skip; // skip boundary for next time - if (in_data.length() >= max + 2) { - const char *data = in_data.c_str(); - if (is_crlf(data + max)) { - max += 2; - } else { - if (*(data + max) == '-' && - *(data + max + 1) == '-') { - *done = true; - max += 2; - } - } - } - } - - new_read_data.substr_of(in_data, max, in_data.length() - max); - in_data = new_read_data; - - return 0; -} - -int RGWPostObj_ObjStore_S3::read_line(bufferlist& bl, uint64_t max, - bool *reached_boundary, bool *done) -{ - return read_with_boundary(bl, max, true, reached_boundary, done); -} - -int RGWPostObj_ObjStore_S3::read_data(bufferlist& bl, uint64_t max, - bool *reached_boundary, bool *done) -{ - return read_with_boundary(bl, max, false, reached_boundary, done); -} - - -int RGWPostObj_ObjStore_S3::read_form_part_header(struct post_form_part *part, - bool *done) -{ - bufferlist bl; - bool reached_boundary; - uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; - int r = read_line(bl, chunk_size, &reached_boundary, done); - if (r < 0) - return r; - - if (*done) { - return 0; - } - - if (reached_boundary) { // skip the first boundary - r = read_line(bl, chunk_size, &reached_boundary, done); - if (r < 0) - return r; - if (*done) - return 0; - } - - while (true) { - /* - * iterate through fields - */ - string line = rgw_trim_whitespace(string(bl.c_str(), bl.length())); - - if (line.empty()) - break; - - struct post_part_field field; - - string field_name; - r = parse_part_field(line, field_name, field); - if (r < 0) - return r; - - part->fields[field_name] = field; - - if (stringcasecmp(field_name, "Content-Disposition") == 0) { - part->name = field.params["name"]; - } - - if (reached_boundary) - break; - - r = read_line(bl, chunk_size, &reached_boundary, done); - } - - return 0; -} - -bool RGWPostObj_ObjStore_S3::part_str(const string& name, string *val) -{ - map::iterator iter - = parts.find(name); - if (iter == parts.end()) - return false; - - bufferlist& data = iter->second.data; - string str = string(data.c_str(), data.length()); - *val = rgw_trim_whitespace(str); - return true; -} - -bool RGWPostObj_ObjStore_S3::part_bl(const string& name, bufferlist *pbl) -{ - map::iterator iter = - parts.find(name); - if (iter == parts.end()) - return false; - - *pbl = iter->second.data; - return true; -} - void RGWPostObj_ObjStore_S3::rebuild_key(string& key) { static string var = "${filename}"; diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index 5b1f8143c2d..2431df893dd 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -195,23 +195,8 @@ public: bufferlist* manifest_bl) override; }; -struct post_part_field { - string val; - map params; -}; - -struct post_form_part { - string name; - string content_type; - map fields; - bufferlist data; -}; - class RGWPostObj_ObjStore_S3 : public RGWPostObj_ObjStore { - string boundary; string filename; - bufferlist in_data; - map parts; RGWPolicyEnv env; RGWPolicy post_policy; string err_msg;