#ifndef WEBCC_COMMON_H_ #define WEBCC_COMMON_H_ #include #include #include #include #include "webcc/globals.h" namespace webcc { // ----------------------------------------------------------------------------- using Header = std::pair; class Headers { public: std::size_t size() const { return headers_.size(); } bool empty() const { return headers_.empty(); } const std::vector
& data() const { return headers_; } void Set(const std::string& key, const std::string& value); void Set(std::string&& key, std::string&& value); bool Has(const std::string& key) const; // Get header by index. const Header& Get(std::size_t index) const { assert(index < size()); return headers_[index]; } // Get header value by key. // If there's no such header with the given key, besides return empty, the // optional |existed| parameter will be set to false. const std::string& Get(const std::string& key, bool* existed = nullptr) const; void Clear() { headers_.clear(); } private: std::vector
::iterator Find(const std::string& key); std::vector
headers_; }; // ----------------------------------------------------------------------------- // Content-Type header. // Syntax: // Content-Type: text/html; charset=utf-8 // Content-Type: multipart/form-data; boundary=something class ContentType { public: explicit ContentType(const std::string& str = ""); void Parse(const std::string& str); void Reset(); bool Valid() const; bool multipart() const { return multipart_; } const std::string& media_type() const { return media_type_; } const std::string& charset() const { assert(!multipart_); return additional_; } const std::string& boundary() const { assert(multipart_); return additional_; } private: void Init(const std::string& str); private: std::string media_type_; std::string additional_; bool multipart_ = false; }; // ----------------------------------------------------------------------------- // Content-Disposition header. // Syntax: // Content-Disposition: form-data // Content-Disposition: form-data; name="fieldName" // Content-Disposition: form-data; name="fieldName"; filename="filename.jpg" // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition class ContentDisposition { public: explicit ContentDisposition(const std::string& str) { valid_ = Init(str); } bool valid() const { return valid_; } const std::string& name() const { return name_; } const std::string& file_name() const { return file_name_; } private: bool Init(const std::string& str); private: std::string name_; std::string file_name_; bool valid_ = false; }; // ----------------------------------------------------------------------------- class FormPart; using FormPartPtr = std::shared_ptr; // A part of the multipart form data. class FormPart { public: FormPart() = default; FormPart(const FormPart&) = delete; FormPart& operator=(const FormPart&) = delete; // Construct a non-file part. // The data will be moved, no file name is needed. // The media type is optional. If the data is a JSON string, you can specify // media type as "application/json". static FormPartPtr New(const std::string& name, std::string&& data, const std::string& media_type = ""); // Construct a file part. // The file name will be extracted from path. // The media type, if not provided, will be inferred from file extension. static FormPartPtr NewFile(const std::string& name, const Path& path, const std::string& media_type = ""); // API: SERVER const std::string& name() const { return name_; } // API: SERVER/PARSER void set_name(const std::string& name) { name_ = name; } // API: SERVER const std::string& file_name() const { return file_name_; } // API: SERVER/PARSER void set_file_name(const std::string& file_name) { file_name_ = file_name; } // API: SERVER const std::string& media_type() const { return media_type_; } // API: SERVER const std::string& data() const { return data_; } // API: SERVER/PARSER void AppendData(const std::string& data) { data_.append(data); } // API: SERVER/PARSER void AppendData(const char* data, std::size_t count) { data_.append(data, count); } // API: CLIENT void Prepare(Payload* payload); // Free the memory of the data. void Free(); // Get the size of the whole payload. // Used by the request to calculate content length. std::size_t GetSize(); // Get the size of the data. std::size_t GetDataSize(); // Dump to output stream for logging purpose. void Dump(std::ostream& os, const std::string& prefix) const; private: // Generate headers from properties. void SetHeaders(); private: // The name within the original HTML form. // E.g., given HTML form: // // the name will be "file1". std::string name_; // The path of the file to post. Path path_; // The original local file name. // E.g., "baby.jpg". std::string file_name_; // The content-type if the media type is known (e.g., inferred from the file // extension or operating system typing information) or as // application/octet-stream. // E.g., "image/jpeg". std::string media_type_; // Headers generated from the above properties. // Only Used to prepare payload. Headers headers_; std::string data_; }; } // namespace webcc #endif // WEBCC_COMMON_H_