Home | History | Annotate | Download | only in brillo
      1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <brillo/mime_utils.h>
      6 
      7 #include <algorithm>
      8 #include <base/strings/string_util.h>
      9 #include <brillo/strings/string_utils.h>
     10 
     11 namespace brillo {
     12 
     13 // ***************************************************************************
     14 // ******************************* MIME types ********************************
     15 // ***************************************************************************
     16 const char mime::types::kApplication[]             = "application";
     17 const char mime::types::kAudio[]                   = "audio";
     18 const char mime::types::kImage[]                   = "image";
     19 const char mime::types::kMessage[]                 = "message";
     20 const char mime::types::kMultipart[]               = "multipart";
     21 const char mime::types::kText[]                    = "text";
     22 const char mime::types::kVideo[]                   = "video";
     23 
     24 const char mime::parameters::kCharset[]            = "charset";
     25 
     26 const char mime::image::kJpeg[]                    = "image/jpeg";
     27 const char mime::image::kPng[]                     = "image/png";
     28 const char mime::image::kBmp[]                     = "image/bmp";
     29 const char mime::image::kTiff[]                    = "image/tiff";
     30 const char mime::image::kGif[]                     = "image/gif";
     31 
     32 const char mime::text::kPlain[]                    = "text/plain";
     33 const char mime::text::kHtml[]                     = "text/html";
     34 const char mime::text::kXml[]                      = "text/xml";
     35 
     36 const char mime::application::kOctet_stream[]      = "application/octet-stream";
     37 const char mime::application::kJson[]              = "application/json";
     38 const char mime::application::kWwwFormUrlEncoded[] =
     39     "application/x-www-form-urlencoded";
     40 const char mime::application::kProtobuf[]          = "application/x-protobuf";
     41 
     42 const char mime::multipart::kFormData[]            = "multipart/form-data";
     43 const char mime::multipart::kMixed[]               = "multipart/mixed";
     44 
     45 // ***************************************************************************
     46 // **************************** Utility Functions ****************************
     47 // ***************************************************************************
     48 static std::string EncodeParam(const std::string& param) {
     49   // If the string contains one of "tspecials" characters as
     50   // specified in RFC 1521, enclose it in quotes.
     51   if (param.find_first_of("()<>@,;:\\\"/[]?=") != std::string::npos) {
     52     return '"' + param + '"';
     53   }
     54   return param;
     55 }
     56 
     57 static std::string DecodeParam(const std::string& param) {
     58   if (param.size() > 1 && param.front() == '"' && param.back() == '"') {
     59     return param.substr(1, param.size() - 2);
     60   }
     61   return param;
     62 }
     63 
     64 // ***************************************************************************
     65 // ******************** Main MIME manipulation functions *********************
     66 // ***************************************************************************
     67 
     68 bool mime::Split(const std::string& mime_string,
     69                  std::string* type,
     70                  std::string* subtype,
     71                  mime::Parameters* parameters) {
     72   std::vector<std::string> parts =
     73       brillo::string_utils::Split(mime_string, ";");
     74   if (parts.empty())
     75     return false;
     76 
     77   if (!mime::Split(parts.front(), type, subtype))
     78     return false;
     79 
     80   if (parameters) {
     81     parameters->clear();
     82     parameters->reserve(parts.size() - 1);
     83     for (size_t i = 1; i < parts.size(); i++) {
     84       auto pair = brillo::string_utils::SplitAtFirst(parts[i], "=");
     85       pair.second = DecodeParam(pair.second);
     86       parameters->push_back(pair);
     87     }
     88   }
     89   return true;
     90 }
     91 
     92 bool mime::Split(const std::string& mime_string,
     93                  std::string* type,
     94                  std::string* subtype) {
     95   std::string mime = mime::RemoveParameters(mime_string);
     96   auto types = brillo::string_utils::SplitAtFirst(mime, "/");
     97 
     98   if (type)
     99     *type = types.first;
    100 
    101   if (subtype)
    102     *subtype = types.second;
    103 
    104   return !types.first.empty() && !types.second.empty();
    105 }
    106 
    107 std::string mime::Combine(const std::string& type,
    108                           const std::string& subtype,
    109                           const mime::Parameters& parameters) {
    110   std::vector<std::string> parts;
    111   parts.push_back(brillo::string_utils::Join("/", type, subtype));
    112   for (const auto& pair : parameters) {
    113     parts.push_back(
    114         brillo::string_utils::Join("=", pair.first, EncodeParam(pair.second)));
    115   }
    116   return brillo::string_utils::Join("; ", parts);
    117 }
    118 
    119 std::string mime::GetType(const std::string& mime_string) {
    120   std::string mime = mime::RemoveParameters(mime_string);
    121   return brillo::string_utils::SplitAtFirst(mime, "/").first;
    122 }
    123 
    124 std::string mime::GetSubtype(const std::string& mime_string) {
    125   std::string mime = mime::RemoveParameters(mime_string);
    126   return brillo::string_utils::SplitAtFirst(mime, "/").second;
    127 }
    128 
    129 mime::Parameters mime::GetParameters(const std::string& mime_string) {
    130   std::string type;
    131   std::string subtype;
    132   mime::Parameters parameters;
    133 
    134   if (mime::Split(mime_string, &type, &subtype, &parameters))
    135     return parameters;
    136 
    137   return mime::Parameters();
    138 }
    139 
    140 std::string mime::RemoveParameters(const std::string& mime_string) {
    141   return brillo::string_utils::SplitAtFirst(mime_string, ";").first;
    142 }
    143 
    144 std::string mime::AppendParameter(const std::string& mime_string,
    145                                   const std::string& paramName,
    146                                   const std::string& paramValue) {
    147   std::string mime(mime_string);
    148   mime += "; ";
    149   mime += brillo::string_utils::Join("=", paramName, EncodeParam(paramValue));
    150   return mime;
    151 }
    152 
    153 std::string mime::GetParameterValue(const std::string& mime_string,
    154                                     const std::string& paramName) {
    155   mime::Parameters params = mime::GetParameters(mime_string);
    156   for (const auto& pair : params) {
    157     if (base::EqualsCaseInsensitiveASCII(pair.first.c_str(), paramName.c_str()))
    158       return pair.second;
    159   }
    160   return std::string();
    161 }
    162 
    163 }  // namespace brillo
    164