return len;
}
+
+/*
+ * parses params in the format: 'first; param1=foo; param2=bar'
+ */
+static void parse_params(const string& params_str, string& first,
+ map<string, string>& 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<string, struct post_form_part, ltstr_nocase>::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<string, struct post_form_part, ltstr_nocase>::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
int get_padding_last_aws4_chunk_encoded(bufferlist &bl, uint64_t chunk_size);
};
+struct post_part_field {
+ string val;
+ map<string, string> params;
+};
+
+struct post_form_part {
+ string name;
+ string content_type;
+ map<string, struct post_part_field, ltstr_nocase> fields;
+ bufferlist data;
+};
+
class RGWPostObj_ObjStore : public RGWPostObj
{
+protected:
+ bufferlist in_data;
+ map<string, post_form_part, const ltstr_nocase> 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 {}
}
}
-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<string, struct post_form_part, ltstr_nocase>::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<string, struct post_form_part, ltstr_nocase>::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}";
bufferlist* manifest_bl) override;
};
-struct post_part_field {
- string val;
- map<string, string> params;
-};
-
-struct post_form_part {
- string name;
- string content_type;
- map<string, struct post_part_field, ltstr_nocase> fields;
- bufferlist data;
-};
-
class RGWPostObj_ObjStore_S3 : public RGWPostObj_ObjStore {
- string boundary;
string filename;
- bufferlist in_data;
- map<string, post_form_part, const ltstr_nocase> parts;
RGWPolicyEnv env;
RGWPolicy post_policy;
string err_msg;