]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: switch from boost::string_ref to string_view in AWSv4-related code (part 2).
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Mon, 15 May 2017 13:33:50 +0000 (15:33 +0200)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Wed, 7 Jun 2017 10:43:19 +0000 (12:43 +0200)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
12 files changed:
src/rgw/rgw_auth_keystone.cc
src/rgw/rgw_auth_keystone.h
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_b64.h
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_crypt.cc
src/rgw/rgw_crypt.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_string.h

index 614f837cecb7f45d9c383df6538a168e8706c99f..5ab70e945977cbb79ddd52599589a5b1b745fd8b 100644 (file)
@@ -289,9 +289,9 @@ TokenEngine::authenticate(const std::string& token,
  * Try to validate S3 auth against keystone s3token interface
  */
 std::pair<boost::optional<rgw::keystone::TokenEnvelope>, int>
-EC2Engine::get_from_keystone(const std::string& access_key_id,
+EC2Engine::get_from_keystone(const boost::string_view& access_key_id,
                              const std::string& string_to_sign,
-                             const std::string& signature) const
+                             const boost::string_view& signature) const
 {
   /* prepare keystone url */
   std::string keystone_url = config.get_endpoint_url();
@@ -335,9 +335,9 @@ EC2Engine::get_from_keystone(const std::string& access_key_id,
   JSONFormatter credentials(false);
   credentials.open_object_section("");
   credentials.open_object_section("credentials");
-  credentials.dump_string("access", access_key_id);
+  credentials.dump_string("access", sview2cstr(access_key_id).data());
   credentials.dump_string("token", rgw::to_base64(string_to_sign));
-  credentials.dump_string("signature", signature);
+  credentials.dump_string("signature", sview2cstr(signature).data());
   credentials.close_section();
   credentials.close_section();
 
@@ -414,8 +414,8 @@ EC2Engine::get_creds_info(const EC2Engine::token_envelope_t& token,
 }
 
 rgw::auth::Engine::result_t EC2Engine::authenticate(
-  const std::string& access_key_id,
-  const std::string& signature,
+  const boost::string_view& access_key_id,
+  const boost::string_view& signature,
   const std::string& string_to_sign,
   const signature_factory_t& signature_factory,
   const completer_factory_t& completer_factory,
index 934fec1cf482dd1a984d071e4a10d23f1b6db770..53884ebe37f915311000b3a5ccb054ca841580aa 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <utility>
 #include <boost/optional.hpp>
+#include <boost/utility/string_view.hpp>
 
 #include "rgw_auth.h"
 #include "rgw_rest_s3.h"
@@ -87,11 +88,11 @@ class EC2Engine : public rgw::auth::s3::AWSEngine {
                              const std::vector<std::string>& admin_roles
                             ) const noexcept;
   std::pair<boost::optional<token_envelope_t>, int>
-  get_from_keystone(const std::string& access_key_id,
+  get_from_keystone(const boost::string_view& access_key_id,
                     const std::string& string_to_sign,
-                    const std::string& signature) const;
-  result_t authenticate(const std::string& access_key_id,
-                        const std::string& signature,
+                    const boost::string_view& signature) const;
+  result_t authenticate(const boost::string_view& access_key_id,
+                        const boost::string_view& signature,
                         const std::string& string_to_sign,
                         const signature_factory_t& signature_factory,
                         const completer_factory_t& completer_factory,
index 3cfffdfb00947aa8eb0693212ea2bacdc4717082..97b963bc6e8c61b960fa7b3b50859922fed653c6 100644 (file)
@@ -13,7 +13,6 @@
 #include "rgw_rest.h"
 #include "rgw_crypt_sanitize.h"
 
-#include "include/str_list.h"
 #include <boost/utility/string_view.hpp>
 
 #define dout_context g_ceph_context
@@ -250,11 +249,11 @@ namespace s3 {
 /* FIXME(rzarzynski): duplicated from rgw_rest_s3.h. */
 #define RGW_AUTH_GRACE_MINS 15
 
-static inline int parse_v4_credentials_qs(const req_info& info,           /* in */
-                                          std::string& credential,        /* out */
-                                          std::string& signedheaders,     /* out */
-                                          std::string& signature,         /* out */
-                                          std::string& date)              /* out */
+static inline int parse_v4_query_string(const req_info& info,              /* in */
+                                        boost::string_view& credential,    /* out */
+                                        boost::string_view& signedheaders, /* out */
+                                        boost::string_view& signature,     /* out */
+                                        boost::string_view& date)          /* out */
 {
   /* auth ships with req params ... */
 
@@ -266,8 +265,9 @@ static inline int parse_v4_credentials_qs(const req_info& info,           /* in
 
   date = info.args.get("X-Amz-Date");
   struct tm date_t;
-  if (!parse_iso8601(date.c_str(), &date_t, NULL, false))
+  if (!parse_iso8601(sview2cstr(date).data(), &date_t, nullptr, false)) {
     return -EPERM;
+  }
 
   /* Used for pre-signatured url, We shouldn't return -ERR_REQUEST_TIME_SKEWED
    * when current time <= X-Amz-Expires */
@@ -276,12 +276,12 @@ static inline int parse_v4_credentials_qs(const req_info& info,           /* in
   uint64_t now_req = 0;
   uint64_t now = ceph_clock_now();
 
-  std::string expires = info.args.get("X-Amz-Expires");
+  boost::string_view expires = info.args.get("X-Amz-Expires");
   if (!expires.empty()) {
     /* X-Amz-Expires provides the time period, in seconds, for which
        the generated presigned URL is valid. The minimum value
        you can set is 1, and the maximum is 604800 (seven days) */
-    time_t exp = atoll(expires.c_str());
+    time_t exp = atoll(expires.data());
     if ((exp < 1) || (exp > 7*24*60*60)) {
       dout(10) << "NOTICE: exp out of range, exp = " << exp << dendl;
       return -EPERM;
@@ -319,56 +319,99 @@ static inline int parse_v4_credentials_qs(const req_info& info,           /* in
   return 0;
 }
 
-static inline int parse_v4_credentials_hdrs(const req_info& info,           /* in */
-                                            std::string& credential,        /* out */
-                                            std::string& signedheaders,     /* out */
-                                            std::string& signature,         /* out */
-                                            std::string& date)              /* out */
+namespace {
+static bool get_next_token(const boost::string_view& s,
+                           size_t& pos,
+                           const char* const delims,
+                           boost::string_view& token)
 {
-  /* auth ships in headers ... */
+  const size_t start = s.find_first_not_of(delims, pos);
+  if (start == boost::string_view::npos) {
+    pos = s.size();
+    return false;
+  }
 
-  /* ------------------------- handle Credential header */
+  size_t end = s.find_first_of(delims, start);
+  if (end != boost::string_view::npos)
+    pos = end + 1;
+  else {
+    pos = end = s.size();
+  }
 
-  const char* const http_auth = info.env->get("HTTP_AUTHORIZATION");
-  string auth_str = http_auth;
+  token = s.substr(start, end - start);
+  return true;
+}
 
-  constexpr size_t min_len = strlen(AWS4_HMAC_SHA256_STR) + 1;
-  if (auth_str.length() < min_len) {
-    dout(10) << "credentials string is too short" << dendl;
-    return -EINVAL;
+std::vector<boost::string_view> get_str_vec(const boost::string_view& str,
+                                            const char* const delims)
+{
+  std::vector<boost::string_view> str_vec;
+
+  size_t pos = 0;
+  boost::string_view token;
+  while (pos < str.size()) {
+    if (get_next_token(str, pos, delims, token)) {
+      if (token.size() > 0) {
+        str_vec.push_back(token);
+      }
+    }
   }
 
-  list<string> auth_list;
-  get_str_list(auth_str.substr(min_len), ",", auth_list);
+  return str_vec;
+}
 
-  map<string, string> kv;
+std::vector<boost::string_view> get_str_vec(const boost::string_view& str)
+{
+  const char delims[] = ";,= \t";
+  return get_str_vec(str, delims);
+}
+};
 
-  for (string& s : auth_list) {
-    string key, val;
-    int ret = parse_key_value(s, key, val);
-    if (ret < 0) {
-      dout(10) << "NOTICE: failed to parse auth header (s=" << s << ")" << dendl;
+static inline int parse_v4_auth_header(const req_info& info,               /* in */
+                                       boost::string_view& credential,     /* out */
+                                       boost::string_view& signedheaders,  /* out */
+                                       boost::string_view& signature,      /* out */
+                                       boost::string_view& date)           /* out */
+{
+  boost::string_view input(info.env->get("HTTP_AUTHORIZATION", ""));
+  try {
+    input = input.substr(::strlen(AWS4_HMAC_SHA256_STR) + 1);
+  } catch (std::out_of_range&) {
+    /* We should never ever run into this situation as the presence of
+     * AWS4_HMAC_SHA256_STR had been verified earlier. */
+    dout(10) << "credentials string is too short" << dendl;
+    return -EINVAL;
+  }
+
+  std::map<boost::string_view, boost::string_view> kv;
+  for (const auto& s : get_str_vec(input, ",")) {
+    const auto parsed_pair = parse_key_value(s);
+    if (parsed_pair) {
+      kv[parsed_pair->first] = parsed_pair->second;
+    } else {
+      dout(10) << "NOTICE: failed to parse auth header (s=" << s << ")"
+               << dendl;
       return -EINVAL;
     }
-    kv[key] = std::move(val);
   }
 
-  static std::array<string, 3> aws4_presigned_required_keys = {
+  static const std::array<boost::string_view, 3> required_keys = {
     "Credential",
     "SignedHeaders",
     "Signature"
   };
 
-  for (string& k : aws4_presigned_required_keys) {
-    if (kv.find(k) == kv.end()) {
+  /* Ensure that the presigned required keys are really there. */
+  for (const auto& k : required_keys) {
+    if (kv.find(k) == std::end(kv)) {
       dout(10) << "NOTICE: auth header missing key: " << k << dendl;
       return -EINVAL;
     }
   }
 
-  credential = std::move(kv["Credential"]);
-  signedheaders = std::move(kv["SignedHeaders"]);
-  signature = std::move(kv["Signature"]);
+  credential = kv["Credential"];
+  signedheaders = kv["SignedHeaders"];
+  signature = kv["Signature"];
 
   /* sig hex str */
   dout(10) << "v4 signature format = " << signature << dendl;
@@ -388,25 +431,25 @@ static inline int parse_v4_credentials_hdrs(const req_info& info,           /* i
   return 0;
 }
 
-int parse_credentials(const req_info& info,             /* in */
-                      std::string& access_key_id,       /* out */
-                      std::string& credential_scope,    /* out */
-                      std::string& signedheaders,       /* out */
-                      std::string& signature,           /* out */
-                      std::string& date,                /* out */
-                      bool& using_qs)                   /* out */
+int parse_credentials(const req_info& info,                     /* in */
+                      boost::string_view& access_key_id,        /* out */
+                      boost::string_view& credential_scope,     /* out */
+                      boost::string_view& signedheaders,        /* out */
+                      boost::string_view& signature,            /* out */
+                      boost::string_view& date,                 /* out */
+                      bool& using_qs)                           /* out */
 {
   const char* const http_auth = info.env->get("HTTP_AUTHORIZATION");
   using_qs = http_auth == nullptr || http_auth[0] == '\0';
 
   int ret;
-  std::string credential;
+  boost::string_view credential;
   if (using_qs) {
-    ret = parse_v4_credentials_qs(info, credential, signedheaders,
-                                  signature, date);
+    ret = parse_v4_query_string(info, credential, signedheaders,
+                                signature, date);
   } else {
-    ret = parse_v4_credentials_hdrs(info, credential, signedheaders,
-                                    signature, date);
+    ret = parse_v4_auth_header(info, credential, signedheaders,
+                               signature, date);
   }
 
   if (ret < 0) {
@@ -532,12 +575,12 @@ std::string get_v4_canonical_qs(const req_info& info, const bool using_qs)
 
 boost::optional<std::string>
 get_v4_canonical_headers(const req_info& info,
-                         const std::string& signedheaders,
+                         const boost::string_view& signedheaders,
                          const bool using_qs,
                          const bool force_boto2_compat)
 {
   map<string, string> canonical_hdrs_map;
-  istringstream sh(signedheaders);
+  istringstream sh(signedheaders.to_string());
   string token;
   string port = info.env->get("SERVER_PORT", "");
   string secure_port = info.env->get("SERVER_PORT_SECURE", "");
@@ -598,7 +641,7 @@ get_v4_canon_req_hash(CephContext* cct,
                       const std::string& canonical_uri,
                       const std::string& canonical_qs,
                       const std::string& canonical_hdrs,
-                      const std::string& signed_hdrs,
+                      const boost::string_view& signed_hdrs,
                       const boost::string_view& request_payload_hash)
 {
   ldout(cct, 10) << "payload request hash = " << request_payload_hash << dendl;
@@ -612,7 +655,7 @@ get_v4_canon_req_hash(CephContext* cct,
     .append("\n")
     .append(canonical_hdrs)
     .append("\n")
-    .append(signed_hdrs)
+    .append(signed_hdrs.data(), signed_hdrs.length())
     .append("\n")
     .append(request_payload_hash.data(), request_payload_hash.length());
 
@@ -830,10 +873,14 @@ AWSv4ComplMulti::calc_chunk_signature(const std::string& payload_hash) const
 {
   std::string string_to_sign = "AWS4-HMAC-SHA256-PAYLOAD\n";
 
-  string_to_sign.append(date + "\n");
-  string_to_sign.append(credential_scope + "\n");
-  string_to_sign.append(prev_chunk_signature + "\n");
-  string_to_sign.append(std::string(AWS4_EMPTY_PAYLOAD_HASH) + "\n");
+  string_to_sign.append(date.data(), date.length());
+  string_to_sign.append("\n");
+  string_to_sign.append(credential_scope.data(), credential_scope.length());
+  string_to_sign.append("\n");
+  string_to_sign.append(prev_chunk_signature);
+  string_to_sign.append("\n");
+  string_to_sign.append(AWS4_EMPTY_PAYLOAD_HASH, strlen(AWS4_EMPTY_PAYLOAD_HASH));
+  string_to_sign.append("\n");
   string_to_sign.append(payload_hash);
 
   ldout(cct, 20) << "AWSv4ComplMulti: string_to_sign=\n" << string_to_sign
@@ -988,9 +1035,9 @@ bool AWSv4ComplMulti::complete()
 
 rgw::auth::Completer::cmplptr_t
 AWSv4ComplMulti::create(const req_state* const s,
-                        std::string date,
-                        std::string credential_scope,
-                        std::string seed_signature,
+                        boost::string_view date,
+                        boost::string_view credential_scope,
+                        boost::string_view seed_signature,
                         const boost::optional<std::string>& secret_key)
 {
   if (!secret_key) {
index 69ea89f3d52744aa8669503e722904a52be2c2d0..11abf9ccc0e7212642e9e79ee333a59f7a199b2a 100644 (file)
@@ -141,10 +141,8 @@ class AWSv4ComplMulti : public rgw::auth::Completer,
 
   CephContext* const cct;
 
-  /* TODO(rzarzynski): move to boost::string_ref. This should be just fine
-   * as (all?) parameters here are actually views over req_info. */
-  const std::string date;
-  const std::string credential_scope;
+  const boost::string_view date;
+  const boost::string_view credential_scope;
   const signing_key_t signing_key;
 
   class ChunkMeta {
@@ -160,7 +158,7 @@ class AWSv4ComplMulti : public rgw::auth::Completer,
         signature(signature.to_string()) {
     }
 
-    ChunkMeta(const boost::string_ref signature)
+    ChunkMeta(const boost::string_view& signature)
       : signature(signature.to_string()) {
     }
 
@@ -187,7 +185,7 @@ class AWSv4ComplMulti : public rgw::auth::Completer,
 
     /* Factory: create an object representing metadata of first, initial chunk
      * in a stream. */
-    static ChunkMeta create_first(const boost::string_ref seed_signature) {
+    static ChunkMeta create_first(const boost::string_view& seed_signature) {
       return ChunkMeta(seed_signature);
     }
 
@@ -212,9 +210,9 @@ public:
   /* We need the constructor to be public because of the std::make_shared that
    * is employed by the create() method. */
   AWSv4ComplMulti(const req_state* const s,
-                  std::string date,
-                  std::string credential_scope,
-                  std::string seed_signature,
+                  boost::string_view date,
+                  boost::string_view credential_scope,
+                  boost::string_view seed_signature,
                   const signing_key_t& signing_key)
     : io_base_t(nullptr),
       cct(s->cct),
@@ -244,9 +242,9 @@ public:
 
   /* Factories. */
   static cmplptr_t create(const req_state* s,
-                          std::string date,
-                          std::string credential_scope,
-                          std::string seed_signature,
+                          boost::string_view date,
+                          boost::string_view credential_scope,
+                          boost::string_view seed_signature,
                           const boost::optional<std::string>& secret_key);
 
 };
@@ -324,13 +322,13 @@ static constexpr char AWS4_HMAC_SHA256_STR[] = "AWS4-HMAC-SHA256";
 static constexpr char AWS4_EMPTY_PAYLOAD_HASH[] = \
   "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
 
-int parse_credentials(const req_info& info,             /* in */
-                      std::string& access_key_id,       /* out */
-                      std::string& credential_scope,    /* out */
-                      std::string& signedheaders,       /* out */
-                      std::string& signature,           /* out */
-                      std::string& date,                /* out */
-                      bool& using_qs);                  /* out */
+int parse_credentials(const req_info& info,                     /* in */
+                      boost::string_view& access_key_id,        /* out */
+                      boost::string_view& credential_scope,     /* out */
+                      boost::string_view& signedheaders,        /* out */
+                      boost::string_view& signature,            /* out */
+                      boost::string_view& date,                 /* out */
+                      bool& using_qs);                          /* out */
 
 static inline std::string get_v4_canonical_uri(const req_info& info) {
   /* The code should normalize according to RFC 3986 but S3 does NOT do path
@@ -396,10 +394,11 @@ static inline bool is_v4_payload_streamed(const char* const exp_payload_hash)
 
 std::string get_v4_canonical_qs(const req_info& info, bool using_qs);
 
-boost::optional<std::string> get_v4_canonical_headers(const req_info& info,
-                                                      const std::string& signedheaders,
-                                                      bool using_qs,
-                                                      bool force_boto2_compat);
+boost::optional<std::string>
+get_v4_canonical_headers(const req_info& info,
+                         const boost::string_view& signedheaders,
+                         bool using_qs,
+                         bool force_boto2_compat);
 
 extern sha256_digest_t
 get_v4_canon_req_hash(CephContext* cct,
@@ -407,7 +406,7 @@ get_v4_canon_req_hash(CephContext* cct,
                       const std::string& canonical_uri,
                       const std::string& canonical_qs,
                       const std::string& canonical_hdrs,
-                      const std::string& signed_hdrs,
+                      const boost::string_view& signed_hdrs,
                       const boost::string_view& request_payload_hash);
 
 std::string get_v4_string_to_sign(CephContext* cct,
index 3f79eccd0ee2e4cc4c09bc3b33bd7ad63027e4a8..c4ad98806692c69d97d64c178cc05b743fde0284 100644 (file)
@@ -5,6 +5,7 @@
 #define RGW_B64_H
 
 #include <boost/utility/string_ref.hpp>
+#include <boost/utility/string_view.hpp>
 #include <boost/archive/iterators/base64_from_binary.hpp>
 #include <boost/archive/iterators/binary_from_base64.hpp>
 #include <boost/archive/iterators/insert_linebreaks.hpp>
@@ -18,19 +19,19 @@ namespace rgw {
    * A header-only Base64 encoder built on boost::archive.  The
    * formula is based on a class poposed for inclusion in boost in
    * 2011 by Denis Shevchenko (abandoned), updated slightly
-   * (e.g., uses boost::string_ref).
+   * (e.g., uses boost::string_view).
    *
    * Also, wrap_width added as template argument, based on
    * feedback from Marcus.
    */
 
   template<int wrap_width = std::numeric_limits<int>::max()>
-  inline std::string to_base64(boost::string_ref sref)
+  inline std::string to_base64(boost::string_view sview)
   {
     using namespace boost::archive::iterators;
 
     // output must be =padded modulo 3
-    auto psize = sref.size();
+    auto psize = sview.size();
     while ((psize % 3) != 0) {
       ++psize;
     }
@@ -42,26 +43,26 @@ namespace rgw {
       insert_linebreaks<
         base64_from_binary<
           transform_width<
-           boost::string_ref::const_iterator
+           boost::string_view::const_iterator
             ,6,8>
           >
           ,wrap_width
         > b64_iter;
 
-    std::string outstr(b64_iter(sref.data()),
-                      b64_iter(sref.data() + sref.size()));
+    std::string outstr(b64_iter(sview.data()),
+                      b64_iter(sview.data() + sview.size()));
 
     // pad outstr with '=' to a length that is a multiple of 3
-    for (size_t ix = 0; ix < (psize-sref.size()); ++ix)
+    for (size_t ix = 0; ix < (psize-sview.size()); ++ix)
       outstr.push_back('=');
 
     return outstr;
   }
 
-  inline std::string from_base64(boost::string_ref sref)
+  inline std::string from_base64(boost::string_view sview)
   {
     using namespace boost::archive::iterators;
-    if (sref.empty())
+    if (sview.empty())
       return std::string();
     /* MIME-compliant input will have line-breaks, so we have to
      * filter WS */
@@ -69,19 +70,18 @@ namespace rgw {
       transform_width<
       binary_from_base64<
        remove_whitespace<
-         boost::string_ref::const_iterator>>
+         boost::string_view::const_iterator>>
       ,8,6
       > b64_iter;
 
-    while (sref.back() == '=')
-      sref.remove_suffix(1);
+    while (sview.back() == '=')
+      sview.remove_suffix(1);
 
-    std::string outstr(b64_iter(sref.data()),
-                     b64_iter(sref.data() + sref.size()));
+    std::string outstr(b64_iter(sview.data()),
+                     b64_iter(sview.data() + sview.size()));
 
     return outstr;
   }
-
 } /* namespace */
 
 #endif /* RGW_B64_H */
index f107ad33eb19d4cd0e815f8a48f7e91140021af0..99993e1883f80d4c3f42db4c1c853bdb37bc4c89 100644 (file)
@@ -464,6 +464,17 @@ static void trim_whitespace(const string& src, string& dst)
   dst = src.substr(start, end - start + 1);
 }
 
+static boost::string_view trim_whitespace(const boost::string_view& src)
+{
+  const char* spacestr = " \t\n\r\f\v";
+  const size_t start = src.find_first_not_of(spacestr);
+  if (start == boost::string_view::npos) {
+    return boost::string_view();
+  }
+
+  const size_t end = src.find_last_not_of(spacestr);
+  return src.substr(start, end - start + 1);
+}
 static bool check_str_end(const char *s)
 {
   if (!s)
@@ -544,8 +555,7 @@ bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_for
     dout(0) << "parse_iso8601 failed" << dendl;
     return false;
   }
-  string str;
-  trim_whitespace(p, str);
+  const boost::string_view str = trim_whitespace(p);
   int len = str.size();
 
   if (len == 0 || (len == 1 && str[0] == 'Z'))
@@ -556,8 +566,8 @@ bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_for
     return false;
 
   uint32_t ms;
-  string nsstr = str.substr(1,  len - 2);
-  int r = stringtoul(nsstr, &ms);
+  boost::string_view nsstr = str.substr(1,  len - 2);
+  int r = stringtoul(nsstr.to_string(), &ms);
   if (r < 0)
     return false;
 
@@ -608,6 +618,27 @@ int parse_key_value(string& in_str, string& key, string& val)
   return parse_key_value(in_str, "=", key,val);
 }
 
+boost::optional<std::pair<boost::string_view, boost::string_view>>
+parse_key_value(const boost::string_view& in_str,
+                const boost::string_view& delim)
+{
+  const size_t pos = in_str.find(delim);
+  if (pos == boost::string_view::npos) {
+    return boost::none;
+  }
+
+  const auto key = trim_whitespace(in_str.substr(0, pos));
+  const auto val = trim_whitespace(in_str.substr(pos + 1));
+
+  return std::make_pair(key, val);
+}
+
+boost::optional<std::pair<boost::string_view, boost::string_view>>
+parse_key_value(const boost::string_view& in_str)
+{
+  return parse_key_value(in_str, "=");
+}
+
 int parse_time(const char *time_str, real_time *time)
 {
   struct tm tm;
@@ -1453,9 +1484,9 @@ string rgw_trim_whitespace(const string& src)
   return src.substr(start, end - start + 1);
 }
 
-boost::string_ref rgw_trim_whitespace(const boost::string_ref& src)
+boost::string_view rgw_trim_whitespace(const boost::string_view& src)
 {
-  boost::string_ref res = src;
+  boost::string_view res = src;
 
   while (res.size() > 0 && std::isspace(res.front())) {
     res.remove_prefix(1);
@@ -1528,7 +1559,7 @@ int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm)
 {
   int pos = cap.find('=');
   if (pos >= 0) {
-    trim_whitespace(cap.substr(0, pos), type);
+    type = trim_whitespace(cap.substr(0, pos)).to_string();
   }
 
   if (!is_valid_cap_type(type))
index 6e425016ecd9fc6783be9f2b42cfcc4100441f3f..a90a0daa92453807dcb401ca9ff6beeec7aa2f9c 100644 (file)
@@ -2153,12 +2153,20 @@ extern string rgw_string_unquote(const string& s);
 extern void parse_csv_string(const string& ival, vector<string>& ovals);
 extern int parse_key_value(string& in_str, string& key, string& val);
 extern int parse_key_value(string& in_str, const char *delim, string& key, string& val);
+
+extern boost::optional<std::pair<boost::string_view, boost::string_view>>
+parse_key_value(const boost::string_view& in_str,
+                const boost::string_view& delim);
+extern boost::optional<std::pair<boost::string_view, boost::string_view>>
+parse_key_value(const boost::string_view& in_str);
+
+
 /** time parsing */
 extern int parse_time(const char *time_str, real_time *time);
 extern bool parse_rfc2616(const char *s, struct tm *t);
 extern bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns = NULL, bool extended_format = true);
 extern string rgw_trim_whitespace(const string& src);
-extern boost::string_ref rgw_trim_whitespace(const boost::string_ref& src);
+extern boost::string_view rgw_trim_whitespace(const boost::string_view& src);
 extern string rgw_trim_quotes(const string& val);
 
 extern void rgw_to_iso8601(const real_time& t, char *dest, int buf_size);
index 0d57f4da270a305d32549885e56d553f512a2d9c..9fb474c46f0ecf90263f96e41e7c4e0bd3f02e36 100644 (file)
@@ -9,7 +9,7 @@
 #include <rgw/rgw_b64.h>
 #include <rgw/rgw_rest_s3.h>
 #include "include/assert.h"
-#include <boost/utility/string_ref.hpp>
+#include <boost/utility/string_view.hpp>
 #include <rgw/rgw_keystone.h>
 #include "include/str_map.h"
 #include "crypto/crypto_accel.h"
@@ -923,8 +923,8 @@ static int get_barbican_url(CephContext * const cct,
 }
 
 static int request_key_from_barbican(CephContext *cct,
-                              boost::string_ref key_id,
-                              boost::string_ref key_selector,
+                              boost::string_view key_id,
+                              boost::string_view key_selector,
                               const std::string& barbican_token,
                               std::string& actual_key) {
   std::string secret_url;
@@ -967,8 +967,8 @@ static map<string,string> get_str_map(const string &str) {
 }
 
 static int get_actual_key_from_kms(CephContext *cct,
-                            boost::string_ref key_id,
-                            boost::string_ref key_selector,
+                            boost::string_view key_id,
+                            boost::string_view key_selector,
                             std::string& actual_key)
 {
   int res = 0;
@@ -1012,7 +1012,7 @@ static int get_actual_key_from_kms(CephContext *cct,
 
 static inline void set_attr(map<string, bufferlist>& attrs,
                             const char* key,
-                            boost::string_ref value)
+                            boost::string_view value)
 {
   bufferlist bl;
   bl.append(value.data(), value.size());
@@ -1051,7 +1051,7 @@ static const crypt_option_names crypt_options[] = {
     {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID",      "x-amz-server-side-encryption-aws-kms-key-id"},
 };
 
-static boost::string_ref get_crypt_attribute(
+static boost::string_view get_crypt_attribute(
     RGWEnv* env,
     std::map<std::string,
              RGWPostObj_ObjStore::post_form_part,
@@ -1065,16 +1065,16 @@ static boost::string_ref get_crypt_attribute(
     auto iter
       = parts->find(crypt_options[option].post_part_name);
     if (iter == parts->end())
-      return boost::string_ref();
+      return boost::string_view();
     bufferlist& data = iter->second.data;
-    boost::string_ref str = boost::string_ref(data.c_str(), data.length());
+    boost::string_view str = boost::string_view(data.c_str(), data.length());
     return rgw_trim_whitespace(str);
   } else {
     const char* hdr = env->get(crypt_options[option].http_header_name, nullptr);
     if (hdr != nullptr) {
-      return boost::string_ref(hdr);
+      return boost::string_view(hdr);
     } else {
-      return boost::string_ref();
+      return boost::string_view();
     }
   }
 }
@@ -1091,7 +1091,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
   int res = 0;
   crypt_http_responses.clear();
   {
-    boost::string_ref req_sse_ca =
+    boost::string_view req_sse_ca =
         get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM);
     if (! req_sse_ca.empty()) {
       if (req_sse_ca != "AES256") {
@@ -1106,7 +1106,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
       if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
         return -ERR_INVALID_REQUEST;
       }
-      boost::string_ref keymd5 =
+      boost::string_view keymd5 =
           get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
       std::string keymd5_bin = from_base64(keymd5);
       if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
@@ -1135,7 +1135,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
       return 0;
     }
     /* AMAZON server side encryption with KMS (key management service) */
-    boost::string_ref req_sse =
+    boost::string_view req_sse =
         get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION);
     if (! req_sse.empty()) {
       if (req_sse != "aws:kms") {
@@ -1145,7 +1145,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
           !s->info.env->exists("SERVER_PORT_SECURE")) {
         return -ERR_INVALID_REQUEST;
       }
-      boost::string_ref key_id =
+      boost::string_view key_id =
           get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
       if (key_id.empty()) {
         return -ERR_INVALID_ACCESS_KEY;
index 1774983758d0b9632553e07e1caf680c1155a414..77f07f8f2fe2ead5dea00d57296c1068ac7bd3fb 100644 (file)
@@ -9,7 +9,7 @@
 #include <rgw/rgw_op.h>
 #include <rgw/rgw_rest.h>
 #include <rgw/rgw_rest_s3.h>
-#include <boost/utility/string_ref.hpp>
+#include <boost/utility/string_view.hpp>
 
 /**
  * \brief Interface for block encryption methods
index 4f0ccc896f205ea6d7cc18f2d6cc9916f87fe29f..056956099cf2bb520ddf01d16c1c2a7bbc56f4c0 100644 (file)
@@ -3567,7 +3567,7 @@ AWSGeneralAbstractor::get_auth_data(const req_state* const s) const
 }
 
 static inline
-std::string v4_signature(const std::string& credential_scope,
+std::string v4_signature(const boost::string_view& credential_scope,
 
                          CephContext* const cct,
                          const boost::string_view& secret_key,
@@ -3592,12 +3592,12 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
                                        /* FIXME: const. */
                                        bool using_qs) const
 {
-  std::string access_key_id;
-  std::string signed_hdrs;
+  boost::string_view access_key_id;
+  boost::string_view signed_hdrs;
 
-  std::string date;
-  std::string credential_scope;
-  std::string client_signature;
+  boost::string_view date;
+  boost::string_view credential_scope;
+  boost::string_view client_signature;
 
   int ret = rgw::auth::s3::parse_credentials(s->info,
                                              access_key_id,
@@ -3637,7 +3637,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
                                          std::move(canonical_uri),
                                          std::move(canonical_qs),
                                          std::move(*canonical_headers),
-                                         std::move(signed_hdrs),
+                                         signed_hdrs,
                                          exp_payload_hash);
 
   auto string_to_sign = \
@@ -3666,8 +3666,8 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
    * aws4_auth_needs_complete and aws4_auth_streaming_mode are set to false
    * by default. We don't need to change that. */
   if (is_v4_payload_unsigned(exp_payload_hash) || is_v4_payload_empty(s)) {
-    return std::make_tuple(std::move(access_key_id),
-                           std::move(client_signature),
+    return std::make_tuple(access_key_id,
+                           client_signature,
                            std::move(string_to_sign),
                            sig_factory,
                            null_completer_factory);
@@ -3703,8 +3703,8 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
       const auto cmpl_factory = std::bind(AWSv4ComplSingle::create,
                                           s,
                                           std::placeholders::_1);
-      return std::make_tuple(std::move(access_key_id),
-                             std::move(client_signature),
+      return std::make_tuple(access_key_id,
+                             client_signature,
                              std::move(string_to_sign),
                              sig_factory,
                              cmpl_factory);
@@ -3739,12 +3739,12 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
        * for CanonReq. */
       const auto cmpl_factory = std::bind(AWSv4ComplMulti::create,
                                           s,
-                                          std::move(date),
-                                          std::move(credential_scope),
+                                          date,
+                                          credential_scope,
                                           client_signature,
                                           std::placeholders::_1);
-      return std::make_tuple(std::move(access_key_id),
-                             std::move(client_signature),
+      return std::make_tuple(access_key_id,
+                             client_signature,
                              std::move(string_to_sign),
                              sig_factory,
                              cmpl_factory);
@@ -3760,8 +3760,8 @@ std::tuple<AWSVerAbstractor::access_key_id_t,
            AWSVerAbstractor::completer_factory_t>
 AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
 {
-  std::string access_key_id;
-  std::string signature;
+  boost::string_view access_key_id;
+  boost::string_view signature;
   bool qsr = false;
 
   const char* http_auth = s->info.env->get("HTTP_AUTHORIZATION");
@@ -3772,9 +3772,11 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
     signature = s->info.args.get("Signature");
     qsr = true;
 
-    std::string expires = s->info.args.get("Expires");
+    boost::string_view expires = s->info.args.get("Expires");
     if (! expires.empty()) {
-      const time_t exp = atoll(expires.c_str());
+      /* It looks we have the guarantee that expires is a null-terminated,
+       * and thus string_view::data() can be safely used. */
+      const time_t exp = atoll(expires.data());
       time_t now;
       time(&now);
 
@@ -3784,9 +3786,9 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
     }
   } else {
     /* The "Authorization" HTTP header is being used. */
-    const std::string auth_str(http_auth + strlen("AWS "));
+    const boost::string_view auth_str(http_auth + strlen("AWS "));
     const size_t pos = auth_str.rfind(':');
-    if (pos != std::string::npos) {
+    if (pos != boost::string_view::npos) {
       access_key_id = auth_str.substr(0, pos);
       signature = auth_str.substr(pos + 1);
     }
@@ -3838,15 +3840,15 @@ std::tuple<AWSVerAbstractor::access_key_id_t,
            AWSVerAbstractor::completer_factory_t>
 AWSBrowserUploadAbstractor::get_auth_data_v4(const req_state* const s) const
 {
-  const std::string& credential = s->auth.s3_postobj_creds.x_amz_credential;
+  const boost::string_view credential = s->auth.s3_postobj_creds.x_amz_credential;
 
   /* grab access key id */
   const size_t pos = credential.find("/");
-  const std::string access_key_id = credential.substr(0, pos);
+  const boost::string_view access_key_id = credential.substr(0, pos);
   dout(10) << "access key id = " << access_key_id << dendl;
 
   /* grab credential scope */
-  const std::string credential_scope = credential.substr(pos + 1);
+  const boost::string_view credential_scope = credential.substr(pos + 1);
   dout(10) << "credential scope = " << credential_scope << dendl;
 
   const auto sig_factory = std::bind(v4_signature,
@@ -3934,8 +3936,8 @@ rgw::auth::s3::LDAPEngine::get_creds_info(const rgw::RGWToken& token) const noex
 
 rgw::auth::Engine::result_t
 rgw::auth::s3::LDAPEngine::authenticate(
-  const std::string& access_key_id,
-  const std::string& signature,
+  const boost::string_view& access_key_id,
+  const boost::string_view& signature,
   const std::string& string_to_sign,
   const signature_factory_t& signature_factory,
   const completer_factory_t& completer_factory,
@@ -3978,8 +3980,8 @@ rgw::auth::s3::LDAPEngine::authenticate(
 /* LocalEndgine */
 rgw::auth::Engine::result_t
 rgw::auth::s3::LocalEngine::authenticate(
-  const std::string& access_key_id,
-  const std::string& signature,
+  const boost::string_view& _access_key_id,
+  const boost::string_view& signature,
   const std::string& string_to_sign,
   const signature_factory_t& signature_factory,
   const completer_factory_t& completer_factory,
@@ -3987,6 +3989,8 @@ rgw::auth::s3::LocalEngine::authenticate(
 {
   /* get the user info */
   RGWUserInfo user_info;
+  /* TODO(rzarzynski): we need to have string-view taking variant. */
+  const std::string access_key_id = _access_key_id.to_string();
   if (rgw_get_user_info_by_access_key(store, access_key_id, user_info) < 0) {
       ldout(cct, 5) << "error reading user info, uid=" << access_key_id
               << " can't authenticate" << dendl;
index 8bf803628caa0eee5e9f9f8ec952953c2e6932b2..0c34d5b66a193cc3a0f5df77ba667c7f5963abdf 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <mutex>
 
+#include <boost/utility/string_view.hpp>
+
 #include "rgw_op.h"
 #include "rgw_rest.h"
 #include "rgw_http_errors.h"
@@ -664,8 +666,8 @@ public:
   public:
     virtual ~VersionAbstractor() {};
 
-    using access_key_id_t = std::string;
-    using signature_t = std::string;
+    using access_key_id_t = boost::string_view;
+    using signature_t = boost::string_view;
     using string_to_sign_t = std::string;
 
     /* Transformation for crafting the AWS signature at server side which is
@@ -707,8 +709,8 @@ protected:
   /* TODO(rzarzynski): clean up. We've too many input parameter hee. Also
    * the signature get_auth_data() of VersionAbstractor is too complicated.
    * Replace these thing with a simple, dedicated structure. */
-  virtual result_t authenticate(const std::string& access_key_id,
-                                const std::string& signature,
+  virtual result_t authenticate(const boost::string_view& access_key_id,
+                                const boost::string_view& signature,
                                 const std::string& string_to_sign,
                                 const signature_factory_t& signature_factory,
                                 const completer_factory_t& completer_factory,
@@ -716,8 +718,8 @@ protected:
 
 public:
   result_t authenticate(const req_state* const s) const final {
-    std::string access_key_id;
-    std::string signature;
+    boost::string_view access_key_id;
+    boost::string_view signature;
     std::string string_to_sign;
 
     VersionAbstractor::signature_factory_t signature_factory;
@@ -818,8 +820,8 @@ protected:
   acl_strategy_t get_acl_strategy() const;
   auth_info_t get_creds_info(const rgw::RGWToken& token) const noexcept;
 
-  result_t authenticate(const std::string& access_key_id,
-                        const std::string& signature,
+  result_t authenticate(const boost::string_view& access_key_id,
+                        const boost::string_view& signature,
                         const std::string& string_to_sign,
                         const signature_factory_t& signature_factory,
                         const completer_factory_t& completer_factory,
@@ -847,8 +849,8 @@ class LocalEngine : public AWSEngine {
   RGWRados* const store;
   const rgw::auth::LocalApplier::Factory* const apl_factory;
 
-  result_t authenticate(const std::string& access_key_id,
-                        const std::string& signature,
+  result_t authenticate(const boost::string_view& access_key_id,
+                        const boost::string_view& signature,
                         const std::string& string_to_sign,
                         const signature_factory_t& signature_factory,
                         const completer_factory_t& completer_factory,
index 74e023b4cb19e006017e90f049f9f9e205c9aba3..6bc529cb8604bd2206c9fad1fb9d8dacb5170d58 100644 (file)
@@ -7,6 +7,8 @@
 #include <stdlib.h>
 #include <limits.h>
 
+#include <boost/container/small_vector.hpp>
+#include <boost/utility/string_view.hpp>
 struct ltstr_nocase
 {
   bool operator()(const string& s1, const string& s2) const
@@ -94,4 +96,20 @@ static inline int stringtoul(const string& s, uint32_t *val)
   return 0;
 }
 
+/* A converter between boost::string_view and null-terminated C-strings.
+ * It copies memory while trying to utilize the local memory instead of
+ * issuing dynamic allocations. */
+template<std::size_t N = 128>
+static inline boost::container::small_vector<char, N>
+sview2cstr(const boost::string_view& sv)
+{
+  boost::container::small_vector<char, N> cstr;
+  cstr.reserve(sv.size() + sizeof('\0'));
+
+  cstr.assign(std::begin(sv), std::end(sv));
+  cstr.push_back('\0');
+
+  return cstr;
+}
+
 #endif