upload.cc 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //
  2. // upload.cc
  3. //
  4. // Copyright (c) 2026 Yuji Hirose. All rights reserved.
  5. // MIT License
  6. //
  7. #include <fstream>
  8. #include <httplib.h>
  9. #include <iostream>
  10. using namespace httplib;
  11. using namespace std;
  12. const char *html = R"(
  13. <form id="formElem">
  14. <input type="file" name="image_file" accept="image/*">
  15. <input type="file" name="text_file" accept="text/*">
  16. <input type="submit">
  17. </form>
  18. <script>
  19. formElem.onsubmit = async (e) => {
  20. e.preventDefault();
  21. let res = await fetch('/post', {
  22. method: 'POST',
  23. body: new FormData(formElem)
  24. });
  25. console.log(await res.text());
  26. };
  27. </script>
  28. )";
  29. int main(void) {
  30. Server svr;
  31. svr.Get("/", [](const Request & /*req*/, Response &res) {
  32. res.set_content(html, "text/html");
  33. });
  34. svr.Post("/post", [](const Request &req, Response &res) {
  35. const auto &image_file = req.form.get_file("image_file");
  36. const auto &text_file = req.form.get_file("text_file");
  37. cout << "image file length: " << image_file.content.length() << endl
  38. << "image file name: " << image_file.filename << endl
  39. << "text file length: " << text_file.content.length() << endl
  40. << "text file name: " << text_file.filename << endl;
  41. // Reduce a client-supplied filename to a safe base name, or return an
  42. // empty string if it cannot be trusted (empty, ".", "..", or contains a
  43. // path separator).
  44. auto sanitize = [](const string &filename) -> string {
  45. auto name = filename.substr(filename.find_last_of("/\\") + 1);
  46. if (name.empty() || name == "." || name == ".." ||
  47. name.find(':') != string::npos) {
  48. return string();
  49. }
  50. return name;
  51. };
  52. const auto image_name = sanitize(image_file.filename);
  53. const auto text_name = sanitize(text_file.filename);
  54. if (image_name.empty() || text_name.empty()) {
  55. res.status = StatusCode::BadRequest_400;
  56. return;
  57. }
  58. {
  59. ofstream ofs(image_name, ios::binary);
  60. if (!ofs) {
  61. res.status = StatusCode::InternalServerError_500;
  62. res.set_content("Failed to write image file", "text/plain");
  63. return;
  64. }
  65. ofs << image_file.content;
  66. }
  67. {
  68. ofstream ofs(text_name);
  69. if (!ofs) {
  70. res.status = StatusCode::InternalServerError_500;
  71. res.set_content("Failed to write text file", "text/plain");
  72. return;
  73. }
  74. ofs << text_file.content;
  75. }
  76. res.set_content("done", "text/plain");
  77. });
  78. svr.listen("localhost", 1234);
  79. }