优化文件上传速度,增加请求头预校验功能
This commit is contained in:
+214
-178
@@ -9,241 +9,277 @@
|
||||
#include "webcc/fs.h"
|
||||
#include "webcc/globals.h"
|
||||
|
||||
namespace webcc {
|
||||
namespace webcc
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Header = std::pair<std::string, std::string>;
|
||||
using Header = std::pair<std::string, std::string>;
|
||||
|
||||
class Headers {
|
||||
public:
|
||||
std::size_t size() const {
|
||||
return headers_.size();
|
||||
}
|
||||
class Headers
|
||||
{
|
||||
//fix core dumped
|
||||
public:
|
||||
Headers() : headers_()
|
||||
{
|
||||
|
||||
bool empty() const {
|
||||
return headers_.empty();
|
||||
}
|
||||
}
|
||||
public:
|
||||
std::size_t size() const
|
||||
{
|
||||
return headers_.size();
|
||||
}
|
||||
|
||||
const std::vector<Header>& data() const {
|
||||
return headers_;
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return headers_.empty();
|
||||
}
|
||||
|
||||
bool Set(string_view key, string_view value);
|
||||
const std::vector<Header>& data() const
|
||||
{
|
||||
return headers_;
|
||||
}
|
||||
|
||||
bool Has(string_view key) const;
|
||||
bool Set(string_view key, string_view value);
|
||||
|
||||
// Get header by index.
|
||||
const Header& Get(std::size_t index) const {
|
||||
assert(index < size());
|
||||
return headers_[index];
|
||||
}
|
||||
bool Has(string_view key) const;
|
||||
|
||||
// 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(string_view key, bool* existed = nullptr) const;
|
||||
// Get header by index.
|
||||
const Header& Get(std::size_t index) const
|
||||
{
|
||||
assert(index < size());
|
||||
return headers_[index];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
headers_.clear();
|
||||
}
|
||||
// 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(string_view key, bool* existed = nullptr) const;
|
||||
|
||||
private:
|
||||
std::vector<Header>::iterator Find(string_view key);
|
||||
void Clear()
|
||||
{
|
||||
headers_.clear();
|
||||
}
|
||||
|
||||
std::vector<Header> headers_;
|
||||
};
|
||||
private:
|
||||
std::vector<Header>::iterator Find(string_view key);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
std::vector<Header> headers_;
|
||||
};
|
||||
|
||||
// Content-Type header.
|
||||
// Syntax:
|
||||
// Content-Type: text/html; charset=utf-8
|
||||
// Content-Type: multipart/form-data; boundary=something
|
||||
class ContentType {
|
||||
public:
|
||||
explicit ContentType(string_view str = "");
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Parse(string_view str);
|
||||
// Content-Type header.
|
||||
// Syntax:
|
||||
// Content-Type: text/html; charset=utf-8
|
||||
// Content-Type: multipart/form-data; boundary=something
|
||||
class ContentType
|
||||
{
|
||||
public:
|
||||
explicit ContentType(string_view str = "");
|
||||
|
||||
void Reset();
|
||||
void Parse(string_view str);
|
||||
|
||||
bool Valid() const;
|
||||
void Reset();
|
||||
|
||||
bool multipart() const {
|
||||
return multipart_;
|
||||
}
|
||||
bool Valid() const;
|
||||
|
||||
const std::string& media_type() const {
|
||||
return media_type_;
|
||||
}
|
||||
bool multipart() const
|
||||
{
|
||||
return multipart_;
|
||||
}
|
||||
|
||||
const std::string& charset() const {
|
||||
assert(!multipart_);
|
||||
return additional_;
|
||||
}
|
||||
const std::string& media_type() const
|
||||
{
|
||||
return media_type_;
|
||||
}
|
||||
|
||||
const std::string& boundary() const {
|
||||
assert(multipart_);
|
||||
return additional_;
|
||||
}
|
||||
const std::string& charset() const
|
||||
{
|
||||
assert(!multipart_);
|
||||
return additional_;
|
||||
}
|
||||
|
||||
private:
|
||||
void Init(string_view str);
|
||||
const std::string& boundary() const
|
||||
{
|
||||
assert(multipart_);
|
||||
return additional_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string media_type_;
|
||||
std::string additional_;
|
||||
bool multipart_ = false;
|
||||
};
|
||||
private:
|
||||
void Init(string_view 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(string_view str) {
|
||||
valid_ = Init(str);
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool valid() const {
|
||||
return valid_;
|
||||
}
|
||||
// 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(string_view str)
|
||||
{
|
||||
valid_ = Init(str);
|
||||
}
|
||||
|
||||
const std::string& name() const {
|
||||
return name_;
|
||||
}
|
||||
bool valid() const
|
||||
{
|
||||
return valid_;
|
||||
}
|
||||
|
||||
const std::string& file_name() const {
|
||||
return file_name_;
|
||||
}
|
||||
const std::string& name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Init(string_view str);
|
||||
const std::string& file_name() const
|
||||
{
|
||||
return file_name_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string file_name_;
|
||||
bool valid_ = false;
|
||||
};
|
||||
private:
|
||||
bool Init(string_view str);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
private:
|
||||
std::string name_;
|
||||
std::string file_name_;
|
||||
bool valid_ = false;
|
||||
};
|
||||
|
||||
class FormPart;
|
||||
using FormPartPtr = std::shared_ptr<FormPart>;
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// A part of the multipart form data.
|
||||
class FormPart {
|
||||
public:
|
||||
FormPart() = default;
|
||||
class FormPart;
|
||||
using FormPartPtr = std::shared_ptr<FormPart>;
|
||||
|
||||
FormPart(const FormPart&) = delete;
|
||||
FormPart& operator=(const FormPart&) = delete;
|
||||
// A part of the multipart form data.
|
||||
class FormPart
|
||||
{
|
||||
public:
|
||||
FormPart() = default;
|
||||
|
||||
// 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(string_view name, std::string&& data,
|
||||
string_view media_type = "");
|
||||
FormPart(const FormPart&) = delete;
|
||||
FormPart& operator=(const FormPart&) = delete;
|
||||
|
||||
// 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(string_view name, const fs::path& path,
|
||||
string_view media_type = "");
|
||||
// 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(string_view name, std::string&& data,
|
||||
string_view media_type = "");
|
||||
|
||||
// API: SERVER
|
||||
const std::string& name() const {
|
||||
return name_;
|
||||
}
|
||||
// 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(string_view name, const fs::path& path,
|
||||
string_view media_type = "");
|
||||
|
||||
// API: SERVER/PARSER
|
||||
void set_name(const std::string& name) {
|
||||
name_ = name;
|
||||
}
|
||||
void ReserveData(std::size_t capacity);
|
||||
|
||||
// API: SERVER
|
||||
const std::string& file_name() const {
|
||||
return file_name_;
|
||||
}
|
||||
// API: SERVER
|
||||
const std::string& name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
// API: SERVER/PARSER
|
||||
void set_file_name(const std::string& file_name) {
|
||||
file_name_ = file_name;
|
||||
}
|
||||
// API: SERVER/PARSER
|
||||
void set_name(const std::string& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
// API: SERVER
|
||||
const std::string& media_type() const {
|
||||
return media_type_;
|
||||
}
|
||||
// API: SERVER
|
||||
const std::string& file_name() const
|
||||
{
|
||||
return file_name_;
|
||||
}
|
||||
|
||||
// API: SERVER
|
||||
const std::string& data() const {
|
||||
return data_;
|
||||
}
|
||||
// API: SERVER/PARSER
|
||||
void set_file_name(const std::string& file_name)
|
||||
{
|
||||
file_name_ = file_name;
|
||||
}
|
||||
|
||||
// API: SERVER/PARSER
|
||||
void AppendData(const std::string& data) {
|
||||
data_.append(data);
|
||||
}
|
||||
// API: SERVER
|
||||
const std::string& media_type() const
|
||||
{
|
||||
return media_type_;
|
||||
}
|
||||
|
||||
// API: SERVER/PARSER
|
||||
void AppendData(const char* data, std::size_t count) {
|
||||
data_.append(data, count);
|
||||
}
|
||||
// API: SERVER
|
||||
const std::string& data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
// API: CLIENT
|
||||
void Prepare(Payload* payload);
|
||||
// API: SERVER/PARSER
|
||||
void AppendData(const std::string& data)
|
||||
{
|
||||
data_.append(data);
|
||||
}
|
||||
|
||||
// Free the memory of the data.
|
||||
void Free();
|
||||
// API: SERVER/PARSER
|
||||
void AppendData(const char* data, std::size_t count)
|
||||
{
|
||||
data_.append(data, count);
|
||||
}
|
||||
|
||||
// Get the size of the whole payload.
|
||||
// Used by the request to calculate content length.
|
||||
std::size_t GetSize();
|
||||
// API: CLIENT
|
||||
void Prepare(Payload* payload);
|
||||
|
||||
// Get the size of the data.
|
||||
std::size_t GetDataSize();
|
||||
// Free the memory of the data.
|
||||
void Free();
|
||||
|
||||
// Dump to output stream for logging purpose.
|
||||
void Dump(std::ostream& os, string_view prefix) const;
|
||||
// Get the size of the whole payload.
|
||||
// Used by the request to calculate content length.
|
||||
std::size_t GetSize();
|
||||
|
||||
private:
|
||||
// Generate headers from properties.
|
||||
void SetHeaders();
|
||||
// Get the size of the data.
|
||||
std::size_t GetDataSize();
|
||||
|
||||
private:
|
||||
// The <input> name within the original HTML form.
|
||||
// E.g., given HTML form:
|
||||
// <input name="file1" type="file">
|
||||
// the name will be "file1".
|
||||
std::string name_;
|
||||
// Dump to output stream for logging purpose.
|
||||
void Dump(std::ostream& os, string_view prefix) const;
|
||||
|
||||
// The path of the file to post.
|
||||
fs::path path_;
|
||||
private:
|
||||
// Generate headers from properties.
|
||||
void SetHeaders();
|
||||
|
||||
// The original local file name.
|
||||
// E.g., "baby.jpg".
|
||||
std::string file_name_;
|
||||
private:
|
||||
// The <input> name within the original HTML form.
|
||||
// E.g., given HTML form:
|
||||
// <input name="file1" type="file">
|
||||
// the name will be "file1".
|
||||
std::string 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_;
|
||||
// The path of the file to post.
|
||||
fs::path path_;
|
||||
|
||||
// Headers generated from the above properties.
|
||||
// Only Used to prepare payload.
|
||||
Headers headers_;
|
||||
// The original local file name.
|
||||
// E.g., "baby.jpg".
|
||||
std::string file_name_;
|
||||
|
||||
std::string data_;
|
||||
};
|
||||
// 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_;
|
||||
};
|
||||
|
||||
inline std::size_t g_max_multipart_size = 1024 * 1024 * 1024;
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user