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 // ***************************************************************************
EncodeParam(const std::string & param)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
DecodeParam(const std::string & param)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
Split(const std::string & mime_string,std::string * type,std::string * subtype,mime::Parameters * parameters)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
Split(const std::string & mime_string,std::string * type,std::string * subtype)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
Combine(const std::string & type,const std::string & subtype,const mime::Parameters & parameters)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
GetType(const std::string & mime_string)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
GetSubtype(const std::string & mime_string)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
GetParameters(const std::string & mime_string)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, ¶meters))
135 return parameters;
136
137 return mime::Parameters();
138 }
139
RemoveParameters(const std::string & mime_string)140 std::string mime::RemoveParameters(const std::string& mime_string) {
141 return brillo::string_utils::SplitAtFirst(mime_string, ";").first;
142 }
143
AppendParameter(const std::string & mime_string,const std::string & paramName,const std::string & paramValue)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
GetParameterValue(const std::string & mime_string,const std::string & paramName)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