Home | History | Annotate | Download | only in http
      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.
    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