You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
8.7 KiB
234 lines
8.7 KiB
4 months ago
|
// Copyright 2014 The Chromium OS Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#ifndef LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_
|
||
|
#define LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_
|
||
|
|
||
|
#include <memory>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <base/files/file_path.h>
|
||
|
#include <base/macros.h>
|
||
|
#include <brillo/brillo_export.h>
|
||
|
#include <brillo/errors/error.h>
|
||
|
#include <brillo/streams/stream.h>
|
||
|
|
||
|
namespace brillo {
|
||
|
namespace http {
|
||
|
|
||
|
namespace content_disposition {
|
||
|
BRILLO_EXPORT extern const char kFormData[];
|
||
|
BRILLO_EXPORT extern const char kFile[];
|
||
|
} // namespace content_disposition
|
||
|
|
||
|
// An abstract base class for all types of form fields used by FormData class.
|
||
|
// This class represents basic information about a form part in
|
||
|
// multipart/form-data and multipart/mixed content.
|
||
|
// For more details on multipart content, see the following RFC:
|
||
|
// http://www.ietf.org/rfc/rfc2388
|
||
|
// For more details on MIME and content headers, see the following RFC:
|
||
|
// http://www.ietf.org/rfc/rfc2045
|
||
|
class BRILLO_EXPORT FormField {
|
||
|
public:
|
||
|
// The constructor that takes the basic data part information common to
|
||
|
// all part types. An example of part's headers could include:
|
||
|
//
|
||
|
// Content-Disposition: form-data; name="field1"
|
||
|
// Content-Type: text/plain;charset=windows-1250
|
||
|
// Content-Transfer-Encoding: quoted-printable
|
||
|
//
|
||
|
// The constructor parameters correspond to the basic part attributes:
|
||
|
// |name| = the part name ("name" parameter of Content-Disposition header;
|
||
|
// "field1" in the example above)
|
||
|
// |content_disposition| = the part disposition ("form-data" in the example)
|
||
|
// |content_type| = the content type ("text/plain;charset=windows-1250")
|
||
|
// |transfer_encoding| = the encoding type for transport ("quoted-printable")
|
||
|
// See http://www.ietf.org/rfc/rfc2045, section 6.1
|
||
|
FormField(const std::string& name,
|
||
|
const std::string& content_disposition,
|
||
|
const std::string& content_type,
|
||
|
const std::string& transfer_encoding);
|
||
|
virtual ~FormField() = default;
|
||
|
|
||
|
// Returns the full Content-Disposition header value. This might include the
|
||
|
// disposition type itself as well as the field "name" and/or "filename"
|
||
|
// parameters.
|
||
|
virtual std::string GetContentDisposition() const;
|
||
|
|
||
|
// Returns the full content type of field data. MultiPartFormField overloads
|
||
|
// this method to append "boundary" parameter to it.
|
||
|
virtual std::string GetContentType() const;
|
||
|
|
||
|
// Returns a string with all of the field headers, delimited by CRLF
|
||
|
// characters ("\r\n").
|
||
|
std::string GetContentHeader() const;
|
||
|
|
||
|
// Adds the data stream(s) to the list of streams to read from.
|
||
|
// This is a potentially destructive operation and can be guaranteed to
|
||
|
// succeed only on the first try. Subsequent calls will fail for certain
|
||
|
// types of form fields.
|
||
|
virtual bool ExtractDataStreams(std::vector<StreamPtr>* streams) = 0;
|
||
|
|
||
|
protected:
|
||
|
// Form field name. If not empty, it will be appended to Content-Disposition
|
||
|
// field header using "name" attribute.
|
||
|
std::string name_;
|
||
|
|
||
|
// Form field disposition. Most of the time this will be "form-data". But for
|
||
|
// nested file uploads inside "multipart/mixed" sections, this can be "file".
|
||
|
std::string content_disposition_;
|
||
|
|
||
|
// Content type. If omitted (empty), "plain/text" assumed.
|
||
|
std::string content_type_;
|
||
|
|
||
|
// Transfer encoding for field data. If omitted, "7bit" is assumed. For most
|
||
|
// binary contents (e.g. for file content), use "binary".
|
||
|
std::string transfer_encoding_;
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(FormField);
|
||
|
};
|
||
|
|
||
|
// Simple text form field.
|
||
|
class BRILLO_EXPORT TextFormField : public FormField {
|
||
|
public:
|
||
|
// Constructor. Parameters:
|
||
|
// name: field name
|
||
|
// data: field text data
|
||
|
// content_type: the data content type. Empty if not specified.
|
||
|
// transfer_encoding: the encoding type of data. If omitted, no encoding
|
||
|
// is specified (and "7bit" is assumed).
|
||
|
TextFormField(const std::string& name,
|
||
|
const std::string& data,
|
||
|
const std::string& content_type = {},
|
||
|
const std::string& transfer_encoding = {});
|
||
|
|
||
|
bool ExtractDataStreams(std::vector<StreamPtr>* streams) override;
|
||
|
|
||
|
private:
|
||
|
std::string data_; // Buffer/reader for field data.
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(TextFormField);
|
||
|
};
|
||
|
|
||
|
// File upload form field.
|
||
|
class BRILLO_EXPORT FileFormField : public FormField {
|
||
|
public:
|
||
|
// Constructor. Parameters:
|
||
|
// name: field name
|
||
|
// stream: open stream with the contents of the file.
|
||
|
// file_name: just the base file name of the file, e.g. "file.txt".
|
||
|
// Used in "filename" parameter of Content-Disposition header.
|
||
|
// content_type: valid content type of the file.
|
||
|
// transfer_encoding: the encoding type of data.
|
||
|
// If omitted, "binary" is used.
|
||
|
FileFormField(const std::string& name,
|
||
|
StreamPtr stream,
|
||
|
const std::string& file_name,
|
||
|
const std::string& content_disposition,
|
||
|
const std::string& content_type,
|
||
|
const std::string& transfer_encoding = {});
|
||
|
|
||
|
// Override from FormField.
|
||
|
// Appends "filename" parameter to Content-Disposition header.
|
||
|
std::string GetContentDisposition() const override;
|
||
|
|
||
|
bool ExtractDataStreams(std::vector<StreamPtr>* streams) override;
|
||
|
|
||
|
private:
|
||
|
StreamPtr stream_;
|
||
|
std::string file_name_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(FileFormField);
|
||
|
};
|
||
|
|
||
|
// Multipart form field.
|
||
|
// This is used directly by FormData class to build the request body for
|
||
|
// form upload. It can also be used with multiple file uploads for a single
|
||
|
// file field, when the uploaded files should be sent as "multipart/mixed".
|
||
|
class BRILLO_EXPORT MultiPartFormField : public FormField {
|
||
|
public:
|
||
|
// Constructor. Parameters:
|
||
|
// name: field name
|
||
|
// content_type: valid content type. If omitted, "multipart/mixed" is used.
|
||
|
// boundary: multipart boundary separator.
|
||
|
// If omitted/empty, a random string is generated.
|
||
|
explicit MultiPartFormField(const std::string& name,
|
||
|
const std::string& content_type = {},
|
||
|
const std::string& boundary = {});
|
||
|
|
||
|
// Override from FormField.
|
||
|
// Appends "boundary" parameter to Content-Type header.
|
||
|
std::string GetContentType() const override;
|
||
|
|
||
|
bool ExtractDataStreams(std::vector<StreamPtr>* streams) override;
|
||
|
|
||
|
// Adds a form field to the form data. The |field| could be a simple text
|
||
|
// field, a file upload field or a multipart form field.
|
||
|
void AddCustomField(std::unique_ptr<FormField> field);
|
||
|
|
||
|
// Adds a simple text form field.
|
||
|
void AddTextField(const std::string& name, const std::string& data);
|
||
|
|
||
|
// Adds a file upload form field using a file path.
|
||
|
bool AddFileField(const std::string& name,
|
||
|
const base::FilePath& file_path,
|
||
|
const std::string& content_disposition,
|
||
|
const std::string& content_type,
|
||
|
brillo::ErrorPtr* error);
|
||
|
|
||
|
// Returns a boundary string used to separate multipart form fields.
|
||
|
const std::string& GetBoundary() const { return boundary_; }
|
||
|
|
||
|
private:
|
||
|
// Returns the starting boundary string: "--<boundary>".
|
||
|
std::string GetBoundaryStart() const;
|
||
|
// Returns the ending boundary string: "--<boundary>--".
|
||
|
std::string GetBoundaryEnd() const;
|
||
|
|
||
|
std::string boundary_; // Boundary string used as field separator.
|
||
|
std::vector<std::unique_ptr<FormField>> parts_; // Form field list.
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(MultiPartFormField);
|
||
|
};
|
||
|
|
||
|
// A class representing a multipart form data for sending as HTTP POST request.
|
||
|
class BRILLO_EXPORT FormData final {
|
||
|
public:
|
||
|
FormData();
|
||
|
// Allows to specify a custom |boundary| separator string.
|
||
|
explicit FormData(const std::string& boundary);
|
||
|
|
||
|
// Adds a form field to the form data. The |field| could be a simple text
|
||
|
// field, a file upload field or a multipart form field.
|
||
|
void AddCustomField(std::unique_ptr<FormField> field);
|
||
|
|
||
|
// Adds a simple text form field.
|
||
|
void AddTextField(const std::string& name, const std::string& data);
|
||
|
|
||
|
// Adds a file upload form field using a file path.
|
||
|
bool AddFileField(const std::string& name,
|
||
|
const base::FilePath& file_path,
|
||
|
const std::string& content_type,
|
||
|
brillo::ErrorPtr* error);
|
||
|
|
||
|
// Returns the complete content type string to be used in HTTP requests.
|
||
|
std::string GetContentType() const;
|
||
|
|
||
|
// Returns the data stream for the form data. This is a potentially
|
||
|
// destructive operation and can be called only once.
|
||
|
StreamPtr ExtractDataStream();
|
||
|
|
||
|
private:
|
||
|
MultiPartFormField form_data_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(FormData);
|
||
|
};
|
||
|
|
||
|
} // namespace http
|
||
|
} // namespace brillo
|
||
|
|
||
|
#endif // LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_
|