Support data streaming on server side.

This commit is contained in:
Chunting Gu
2019-08-13 17:35:01 +08:00
parent 0ea4ab7526
commit 9b13dceab9
13 changed files with 167 additions and 59 deletions
+26 -4
View File
@@ -65,22 +65,24 @@ bool StringBodyHandler::Finish() {
// -----------------------------------------------------------------------------
FileBodyHandler::FileBodyHandler(Message* message) : BodyHandler(message) {
bool FileBodyHandler::OpenFile() {
try {
temp_path_ = bfs::temp_directory_path() / bfs::unique_path();
LOG_VERB("Generate a temp path for streaming: %s",
temp_path_.string().c_str());
} catch (const bfs::filesystem_error&) {
LOG_ERRO("Failed to generate temp path: %s", temp_path_.string().c_str());
throw Error{ Error::kFileError };
return false;
}
ofstream_.open(temp_path_, std::ios::binary);
if (ofstream_.fail()) {
LOG_ERRO("Failed to open the temp file: %s", temp_path_.string().c_str());
throw Error{ Error::kFileError };
return false;
}
return true;
}
void FileBodyHandler::AddContent(const char* data, std::size_t count) {
@@ -136,12 +138,17 @@ bool Parser::Parse(const char* data, std::size_t length) {
LOG_INFO("HTTP headers just ended.");
if (!OnHeadersEnd()) {
// Only request parser can reach here when no view matches the request.
// Data streaming or not is also determined for request parser.
return false;
}
CreateBodyHandler();
if (!body_handler_) {
// The only reason to reach here is that it was failed to generate the temp
// file for streaming. Normally, it shouldn't happen.
// TODO: Keep a member |error_| for the user to query.
return false;
}
@@ -152,6 +159,7 @@ bool Parser::Parse(const char* data, std::size_t length) {
void Parser::Reset() {
message_ = nullptr;
body_handler_.reset();
stream_ = false;
pending_data_.clear();
@@ -202,6 +210,20 @@ bool Parser::ParseHeaders() {
return true;
}
void Parser::CreateBodyHandler() {
if (stream_) {
auto file_body_handler = new FileBodyHandler{ message_ };
if (!file_body_handler->OpenFile()) {
body_handler_.reset();
delete file_body_handler;
} else {
body_handler_.reset(file_body_handler);
}
} else {
body_handler_.reset(new StringBodyHandler{ message_ });
}
}
bool Parser::GetNextLine(std::size_t off, std::string* line, bool erase) {
std::size_t pos = pending_data_.find(kCRLF, off);