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 #ifndef LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_ 6 #define LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_ 7 8 #include <memory> 9 #include <string> 10 #include <vector> 11 12 #include <base/files/file_path.h> 13 #include <base/macros.h> 14 #include <brillo/brillo_export.h> 15 #include <brillo/errors/error.h> 16 #include <brillo/streams/stream.h> 17 18 namespace brillo { 19 namespace http { 20 21 namespace content_disposition { 22 BRILLO_EXPORT extern const char kFormData[]; 23 BRILLO_EXPORT extern const char kFile[]; 24 } // namespace content_disposition 25 26 // An abstract base class for all types of form fields used by FormData class. 27 // This class represents basic information about a form part in 28 // multipart/form-data and multipart/mixed content. 29 // For more details on multipart content, see the following RFC: 30 // http://www.ietf.org/rfc/rfc2388 31 // For more details on MIME and content headers, see the following RFC: 32 // http://www.ietf.org/rfc/rfc2045 33 class BRILLO_EXPORT FormField { 34 public: 35 // The constructor that takes the basic data part information common to 36 // all part types. An example of part's headers could include: 37 // 38 // Content-Disposition: form-data; name="field1" 39 // Content-Type: text/plain;charset=windows-1250 40 // Content-Transfer-Encoding: quoted-printable 41 // 42 // The constructor parameters correspond to the basic part attributes: 43 // |name| = the part name ("name" parameter of Content-Disposition header; 44 // "field1" in the example above) 45 // |content_disposition| = the part disposition ("form-data" in the example) 46 // |content_type| = the content type ("text/plain;charset=windows-1250") 47 // |transfer_encoding| = the encoding type for transport ("quoted-printable") 48 // See http://www.ietf.org/rfc/rfc2045, section 6.1 49 FormField(const std::string& name, 50 const std::string& content_disposition, 51 const std::string& content_type, 52 const std::string& transfer_encoding); 53 virtual ~FormField() = default; 54 55 // Returns the full Content-Disposition header value. This might include the 56 // disposition type itself as well as the field "name" and/or "filename" 57 // parameters. 58 virtual std::string GetContentDisposition() const; 59 60 // Returns the full content type of field data. MultiPartFormField overloads 61 // this method to append "boundary" parameter to it. 62 virtual std::string GetContentType() const; 63 64 // Returns a string with all of the field headers, delimited by CRLF 65 // characters ("\r\n"). 66 std::string GetContentHeader() const; 67 68 // Adds the data stream(s) to the list of streams to read from. 69 // This is a potentially destructive operation and can be guaranteed to 70 // succeed only on the first try. Subsequent calls will fail for certain 71 // types of form fields. 72 virtual bool ExtractDataStreams(std::vector<StreamPtr>* streams) = 0; 73 74 protected: 75 // Form field name. If not empty, it will be appended to Content-Disposition 76 // field header using "name" attribute. 77 std::string name_; 78 79 // Form field disposition. Most of the time this will be "form-data". But for 80 // nested file uploads inside "multipart/mixed" sections, this can be "file". 81 std::string content_disposition_; 82 83 // Content type. If omitted (empty), "plain/text" assumed. 84 std::string content_type_; 85 86 // Transfer encoding for field data. If omitted, "7bit" is assumed. For most 87 // binary contents (e.g. for file content), use "binary". 88 std::string transfer_encoding_; 89 90 private: 91 DISALLOW_COPY_AND_ASSIGN(FormField); 92 }; 93 94 // Simple text form field. 95 class BRILLO_EXPORT TextFormField : public FormField { 96 public: 97 // Constructor. Parameters: 98 // name: field name 99 // data: field text data 100 // content_type: the data content type. Empty if not specified. 101 // transfer_encoding: the encoding type of data. If omitted, no encoding 102 // is specified (and "7bit" is assumed). 103 TextFormField(const std::string& name, 104 const std::string& data, 105 const std::string& content_type = {}, 106 const std::string& transfer_encoding = {}); 107 108 bool ExtractDataStreams(std::vector<StreamPtr>* streams) override; 109 110 private: 111 std::string data_; // Buffer/reader for field data. 112 113 DISALLOW_COPY_AND_ASSIGN(TextFormField); 114 }; 115 116 // File upload form field. 117 class BRILLO_EXPORT FileFormField : public FormField { 118 public: 119 // Constructor. Parameters: 120 // name: field name 121 // stream: open stream with the contents of the file. 122 // file_name: just the base file name of the file, e.g. "file.txt". 123 // Used in "filename" parameter of Content-Disposition header. 124 // content_type: valid content type of the file. 125 // transfer_encoding: the encoding type of data. 126 // If omitted, "binary" is used. 127 FileFormField(const std::string& name, 128 StreamPtr stream, 129 const std::string& file_name, 130 const std::string& content_disposition, 131 const std::string& content_type, 132 const std::string& transfer_encoding = {}); 133 134 // Override from FormField. 135 // Appends "filename" parameter to Content-Disposition header. 136 std::string GetContentDisposition() const override; 137 138 bool ExtractDataStreams(std::vector<StreamPtr>* streams) override; 139 140 private: 141 StreamPtr stream_; 142 std::string file_name_; 143 144 DISALLOW_COPY_AND_ASSIGN(FileFormField); 145 }; 146 147 // Multipart form field. 148 // This is used directly by FormData class to build the request body for 149 // form upload. It can also be used with multiple file uploads for a single 150 // file field, when the uploaded files should be sent as "multipart/mixed". 151 class BRILLO_EXPORT MultiPartFormField : public FormField { 152 public: 153 // Constructor. Parameters: 154 // name: field name 155 // content_type: valid content type. If omitted, "multipart/mixed" is used. 156 // boundary: multipart boundary separator. 157 // If omitted/empty, a random string is generated. 158 explicit MultiPartFormField(const std::string& name, 159 const std::string& content_type = {}, 160 const std::string& boundary = {}); 161 162 // Override from FormField. 163 // Appends "boundary" parameter to Content-Type header. 164 std::string GetContentType() const override; 165 166 bool ExtractDataStreams(std::vector<StreamPtr>* streams) override; 167 168 // Adds a form field to the form data. The |field| could be a simple text 169 // field, a file upload field or a multipart form field. 170 void AddCustomField(std::unique_ptr<FormField> field); 171 172 // Adds a simple text form field. 173 void AddTextField(const std::string& name, const std::string& data); 174 175 // Adds a file upload form field using a file path. 176 bool AddFileField(const std::string& name, 177 const base::FilePath& file_path, 178 const std::string& content_disposition, 179 const std::string& content_type, 180 brillo::ErrorPtr* error); 181 182 // Returns a boundary string used to separate multipart form fields. GetBoundary()183 const std::string& GetBoundary() const { return boundary_; } 184 185 private: 186 // Returns the starting boundary string: "--<boundary>". 187 std::string GetBoundaryStart() const; 188 // Returns the ending boundary string: "--<boundary>--". 189 std::string GetBoundaryEnd() const; 190 191 std::string boundary_; // Boundary string used as field separator. 192 std::vector<std::unique_ptr<FormField>> parts_; // Form field list. 193 194 DISALLOW_COPY_AND_ASSIGN(MultiPartFormField); 195 }; 196 197 // A class representing a multipart form data for sending as HTTP POST request. 198 class BRILLO_EXPORT FormData final { 199 public: 200 FormData(); 201 // Allows to specify a custom |boundary| separator string. 202 explicit FormData(const std::string& boundary); 203 204 // Adds a form field to the form data. The |field| could be a simple text 205 // field, a file upload field or a multipart form field. 206 void AddCustomField(std::unique_ptr<FormField> field); 207 208 // Adds a simple text form field. 209 void AddTextField(const std::string& name, const std::string& data); 210 211 // Adds a file upload form field using a file path. 212 bool AddFileField(const std::string& name, 213 const base::FilePath& file_path, 214 const std::string& content_type, 215 brillo::ErrorPtr* error); 216 217 // Returns the complete content type string to be used in HTTP requests. 218 std::string GetContentType() const; 219 220 // Returns the data stream for the form data. This is a potentially 221 // destructive operation and can be called only once. 222 StreamPtr ExtractDataStream(); 223 224 private: 225 MultiPartFormField form_data_; 226 227 DISALLOW_COPY_AND_ASSIGN(FormData); 228 }; 229 230 } // namespace http 231 } // namespace brillo 232 233 #endif // LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_ 234