[Webserver]httplib webserver+large file uploadย 

๐Ÿ‘‰๐Ÿป ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ์œ„ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
This is an explanation for uploading large files.

๐Ÿ‘‰๐Ÿป ์—…๋กœ๋“œ ์ง„ํ–‰๋ฅ ์„ ํ™•์ธ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
You can check the upload progress.

๐Ÿ‘‰๐Ÿป ํ…Œ์ŠคํŠธ๋Š” macOS์—์„œ http๋กœ ํ…Œ์ŠคํŠธ ํ–ˆ์Šต๋‹ˆ๋‹ค.
The test was performed on macOS using http.

๐Ÿ‘‰๐Ÿป macOS์—์„œ ํ…Œ์ŠคํŠธ ํ–ˆ์ง€๋งŒ ๋ฆฌ๋ˆ…์Šค์—์„œ ์‚ฌ์šฉํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.
I tested it on macOS, but it can also be used on Linux.

๐Ÿ‘‰๐Ÿป ๋ฆฌ๋ˆ…์Šค์—์„œ ์‚ฌ์šฉ์‹œ ๋ฐฉํ™”๋ฒฝ์—์„œ 5080ํฌํŠธ ์˜คํ”ˆ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.(์ด์ „ ๊ฒŒ์‹œ๋ฌผ์„ ์ฐธ์กฐ ํ•˜์„ธ์š”)
When using on Linux, port 5080 must be open in the firewall. (Please refer to the previous post.)

โœ”๏ธ ์ฝ”๋“œ / Code

//#define CPPHTTPLIB_OPENSSL_SUPPORT // HTTPS
#include "httplib.h"
#include <filesystem>
#include <fstream>
#include <iostream>

int main() {
    // HTTP๋ฉด Server, HTTPS๋ฉด SSLServer ์‚ฌ์šฉ
    // Use Server for HTTP, SSLServer for HTTPS

    httplib::Server svr;

    // httplib::SSLServer svr("./fullchain.pem", "./privkey.pem"); // HTTPS

    std::filesystem::create_directories("./uploads");
    svr.set_payload_max_length(1024ULL * 1024 * 1024 * 10); // 10GB

    // Multipart ์—…๋กœ๋“œ / Multipart Upload
    svr.Post("/upload/multipart", [&](const httplib::Request& req, httplib::Response& res,
                                      const httplib::ContentReader& reader) {
        if (!req.is_multipart_form_data()) {
            res.status = 400;
            res.set_content("not multipart", "text/plain");
            return;
        }

        std::ofstream ofs;
        bool ok = reader(
            [&](const httplib::FormData& part) {
                if (part.name == "file") {
                    std::string name = httplib::sanitize_filename(part.filename.empty() ? "upload.bin" : part.filename);
                    ofs.open("./uploads/" + name, std::ios::binary);
                    if (!ofs) return false;
                }
                return true;
            },
            [&](const char* data, size_t len) {
                if (ofs) ofs.write(data, static_cast<std::streamsize>(len));
                return true;
            });

        if (ofs) ofs.close();

        if (!ok) {
            res.status = 500;
            res.set_content("multipart stream failed", "text/plain");
            return;
        }

        res.set_content("multipart upload ok", "text/plain");
    });

    // ์—…๋กœ๋“œ ์ง„ํ–‰๋ฅ  ํ‘œ์‹œ
    // HTML form displaying upload status
    svr.Get("/", [](const httplib::Request&, httplib::Response& res) {
        res.set_content(R"(
    <!doctype html>
    <html>
    <body>
      <h1>Upload</h1>

      <form id="uploadForm">
        <input type="file" id="file" name="file" required />
        <button type="submit">Upload</button>
      </form>

      <p id="percent">0%</p>
      <progress id="bar" value="0" max="100" style="width: 300px;"></progress>
      <pre id="result"></pre>

      <script>
        const form = document.getElementById('uploadForm');
        const bar = document.getElementById('bar');
        const percent = document.getElementById('percent');
        const result = document.getElementById('result');

        form.addEventListener('submit', (e) => {
          e.preventDefault();

          const fileInput = document.getElementById('file');
          if (!fileInput.files.length) return;

          const data = new FormData();
          data.append('file', fileInput.files[0]);

          const xhr = new XMLHttpRequest();
          xhr.open('POST', '/upload/multipart', true);

          xhr.upload.onprogress = (evt) => {
            if (evt.lengthComputable) {
              const p = Math.round((evt.loaded / evt.total) * 100);
              bar.value = p;
              percent.textContent = p + '%';
            }
          };

          xhr.onload = () => {
            result.textContent = 'status: ' + xhr.status + '\\n' + xhr.responseText;
          };

          xhr.onerror = () => {
            result.textContent = 'upload failed';
          };

          xhr.send(data);
        });
      </script>
    </body>
    </html>
    )", "text/html; charset=utf-8");
    });

    std::cout << "listen: http://0.0.0.0:5080\n";
    svr.listen("0.0.0.0", 5080);
}

โœ”๏ธ ์ปดํŒŒ์ผ / Compiling

g++ large_upload_server.cpp -o large_upload_server -std=c++17 -pthread  

โœ”๏ธ ์„œ๋ฒ„ ์‹คํ–‰ / Run Server

./large_upload_server
์„œ๋ฒ„ ์‹คํ–‰ / Run Server

โœ”๏ธ ๋ธŒ๋ผ์šฐ์ € ์ ‘์† / Browser Access

— ํŒŒ์ผ ์—…๋กœ๋“œ ํผ / file upload form

ํŒŒ์ผ ์—…๋กœ๋“œ ํผ / file upload form

–ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ / File upload complete

ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ / File upload complete

— ์—…๋กœ๋“œ ์ƒํƒœ ํ™•์ธ / Check upload status

์—…๋กœ๋“œ ์ƒํƒœ ํ™•์ธ / Check upload status

Leave a Reply