[k2] add support http multipart content-type#1545
[k2] add support http multipart content-type#1545astrophysik wants to merge 26 commits intomasterfrom
Conversation
runtime-light/server/http/multipart/details/parts-processing.cpp
Outdated
Show resolved
Hide resolved
runtime-light/server/http/multipart/details/parts-processing.cpp
Outdated
Show resolved
Hide resolved
| #include "runtime-light/state/instance-state.h" | ||
| #include "runtime-light/stdlib/component/component-api.h" | ||
| #include "runtime-light/stdlib/diagnostics/logs.h" | ||
| #include "runtime-light/stdlib/file/file-system-functions.h" |
| #include "runtime-light/tl/tl-functions.h" | ||
| #include "runtime-light/tl/tl-types.h" | ||
|
|
||
| #include "runtime-light/stdlib/output/print-functions.h" |
| http_server_instance_st.opt_raw_post_data.emplace(std::move(body)); | ||
| } else if (!std::ranges::search(content_type, CONTENT_TYPE_MULTIPART_FORM_DATA).empty()) { | ||
| kphp::log::error("unsupported content-type: {}", CONTENT_TYPE_MULTIPART_FORM_DATA); | ||
| if (auto boundary_opt{kphp::http::multipart::extract_boundary(content_type)}; boundary_opt.has_value()) { |
There was a problem hiding this comment.
Looks like an error that we do nothing in case we couldn't extract boundary
There was a problem hiding this comment.
Add warning in this case
|
|
||
| kphp::coro::task<> finalize_server() noexcept { | ||
| auto& http_server_instance_st{HttpServerInstanceState::get()}; | ||
| auto& superglobals{InstanceState::get().php_script_mutable_globals_singleton.get_superglobals()}; |
There was a problem hiding this comment.
This variable is only used in a single switch-case. Let's declare it there to not waste CPU cycles unless it's really necessary
nit: you may use PhpScriptMutableGlobals::current() instead of InstanceState::get().php_script_mutable_globals_singleton
| const array<mixed> files{superglobals.v$_FILES.to_array()}; | ||
| for (const auto& files_it : files) { | ||
| const mixed& file{files_it.get_value()}; | ||
| const mixed& tmp_filenames{file.get_value(string{"tmp_name"})}; |
There was a problem hiding this comment.
string{"tmp_name"} constructs a new string object every iteration. Since this is a constant key, it could be cached
| return std::nullopt; | ||
| } | ||
|
|
||
| std::expected<size_t, int32_t> write_temporary_file(std::string_view tmp_name, std::span<const std::byte> content) noexcept { |
There was a problem hiding this comment.
Consider following implementation:
std::expected<size_t, int32_t> write_temporary_file(std::string_view tmp_name, std::span<const std::byte> content) noexcept {
auto file_res{kphp::fs::file::open(tmp_name, "w")};
if (!file_res.has_value()) {
return std::unexpected{UPLOAD_ERR_NO_FILE};
}
auto written_res{(*file_res).write(content)};
if (!written_res.has_value()) {
return std::unexpected{UPLOAD_ERR_CANT_WRITE};
}
size_t file_size{*written_res};
if (file_size < content.size()) {
return std::unexpected{UPLOAD_ERR_PARTIAL};
}
return file_size;
}
Moreover, I don't see a reason to return std::expected<size_t, int32_t> instead of std::expected<void, size_t>
There was a problem hiding this comment.
Thanks
Error code and size are used in mixed file{}; initialization
| const string name{part.name_attribute.data(), static_cast<string::size_type>(part.name_attribute.size())}; | ||
| const string body{part.body.data(), static_cast<string::size_type>(part.body.size())}; | ||
| if (part.content_type.has_value() && !std::ranges::search(*part.content_type, CONTENT_TYPE_APP_FORM_URLENCODED).empty()) { | ||
| f$parse_str(body, post[name]); |
There was a problem hiding this comment.
It'd be more systematic to use get_value here
There was a problem hiding this comment.
Okay, but it leads to extra allocation
| void process_post_multipart(const kphp::http::multipart::details::part& part, mixed& post) noexcept { | ||
| const string name{part.name_attribute.data(), static_cast<string::size_type>(part.name_attribute.size())}; | ||
| const string body{part.body.data(), static_cast<string::size_type>(part.body.size())}; | ||
| if (part.content_type.has_value() && !std::ranges::search(*part.content_type, CONTENT_TYPE_APP_FORM_URLENCODED).empty()) { |
There was a problem hiding this comment.
Why not *part.content_type == CONTENT_TYPE_APP_FORM_URLENCODED?
There was a problem hiding this comment.
Because content-type may looks like Content-type: application/x-www-form-urlencoded; charset=UTF-8
|
|
||
| auto tmp_name_opt{generate_temporary_name()}; | ||
| if (!tmp_name_opt.has_value()) { | ||
| kphp::log::warning("cannot generate unique name for multipart temporary file"); |
There was a problem hiding this comment.
Isn't it dangerous that we can't create a file and just emit a warning? It looks like this may lead to some state corruption
| auto tmp_name{*tmp_name_opt}; | ||
| auto write_res{write_temporary_file(tmp_name, {reinterpret_cast<const std::byte*>(part.body.data()), part.body.size()})}; | ||
|
|
||
| mixed file{}; |
There was a problem hiding this comment.
Isn't it simpler to declare it as array<mixed>?
No description provided.