[Webserver]httplib webserver+file upload(multipart,http)(macoOS)

๐Ÿ‘‰๐Ÿป httplib ์›น์„œ๋ฒ„์—์„œ multipart ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
This is a description of implementing multipart file uploads on an httplib web server.

๐Ÿ‘‰๐Ÿป ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋‚ด์— httplib.hํŒŒ์ผ์„ ๋‹ค์šด ๋ฐ›์Šต๋‹ˆ๋‹ค.
Download the httplib.h file into the project directory.

โœ”๏ธ httplib.h(0.42.0)

curl -L https://raw.githubusercontent.com/yhirose/cpp-httplib/master/httplib.h -o httplib.h

๐Ÿ‘‰๐ŸปHttp server basic (upload_server.cpp)

โœ”๏ธ ์•„๋ž˜๋Š” cpp ํด๋ผ์ด์–ธํŠธ์—์„œ ๋กœ์ปฌ ์„œ๋ฒ„๋กœ ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•˜๋Š” ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
The following is an explanation of uploading files from a C++ client to a local server.

โœ”๏ธ ๊นƒํ—ˆ๋ธŒ์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ์‹œ basic ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์— ์žˆ๋Š” ํŒŒ์ผ ์ž…๋‹ˆ๋‹ค.
This is the file located in the basic directory when downloading from GitHub.

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

— upload_server.cpp

#include "../httplib.h"
#include <fstream>
#include <iostream>

int main() {
    httplib::Server svr;

    svr.Post("/upload", [&](const httplib::Request& req, httplib::Response& res,
                            const httplib::ContentReader& content_reader) {
        if (!req.is_multipart_form_data()) {
            res.status = 400;
            res.set_content("Not multipart/form-data", "text/plain");
            return;
        }

        std::string filename;
        std::ofstream ofs;

        content_reader(
            [&](const httplib::FormData& item) {
                if (item.name != "file") return true;

                filename = httplib::sanitize_filename(item.filename);
                if (filename.empty()) {
                    res.status = 400;
                    res.set_content("Invalid filename", "text/plain");
                    return false;
                }
                // file upload directory
                ofs.open("../uploads/" + filename, std::ios::binary);
                if (!ofs) {
                    res.status = 500;
                    res.set_content("Failed to open file", "text/plain");
                    return false;
                }
                return true;
            },
            [&](const char* data, size_t len) {
                if (ofs) ofs.write(data, len);
                return true;
            }
        );

        if (ofs) ofs.close();

        res.set_content("Upload OK", "text/plain");
    });

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

— upload_client.cpp

#include "../httplib.h"
#include <fstream>
#include <iostream>

int main() {
    httplib::Client cli("http://localhost:5080");
 
    // ์—…๋กœ๋“œ ํ•ญ๋ชฉ / upload
    httplib::UploadFormData item;
    item.name = "file";
    item.filename = "test.txt";
    item.content_type = "text/plain";

    // ํŒŒ์ผ ์ฝ๊ธฐ / read file
    std::ifstream ifs("test.txt", std::ios::binary);
    if (!ifs) {
        std::cerr << "cannot open file\n";
        return 1;
    }
    item.content.assign((std::istreambuf_iterator<char>(ifs)),
                         std::istreambuf_iterator<char>());

    httplib::UploadFormDataItems items;
    items.push_back(item);

    httplib::Headers headers; 

    if (auto res = cli.Post("/upload", headers, items)) {
        std::cout << "status: " << res->status << "\n";
        std::cout << res->body << "\n";
    } else {
        std::cerr << "request failed\n";
    }
}

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

g++ upload_server.cpp -o upload_server -std=c++11

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

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

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

g++ upload_client.cpp -o upload_client -std=c++11

โœ”๏ธ ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰ / Run Client

./upload_client
ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰ / Run Client

โœ”๏ธ ํŒŒ์ผ ์—…๋กœ๋“œ ์ƒํƒœ ํ™•์ธ / Check file upload status

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

๐Ÿ‘‰๐ŸปHttp server html (upload_server.cpp)

โœ”๏ธ ์•„๋ž˜๋Š” htmlํŒŒ์ผ์—์„œ ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•˜๋Š” ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
Below is an explanation of how to upload a file in an HTML file.

โœ”๏ธ ๊นƒํ—ˆ๋ธŒ์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ์‹œ uploads_html ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์— ์žˆ๋Š” ํŒŒ์ผ ์ž…๋‹ˆ๋‹ค.
This is the file located in the uploads_html directory when downloading from GitHub.

โœ”๏ธ www ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ฆ๋‹ˆ๋‹ค.
If the www directory does not exist, create the directory.

โœ”๏ธ www ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์— ๊ฐ„๋‹จํ•œ index.htmlํŒŒ์ผ์„ ๋งŒ๋“ฆ๋‹ˆ๋‹ค.
Create a simple index.html file inside the www directory.

โœ”๏ธ index.html

<!doctype html>
<html lang="ko">
    <head>
        <meta charset="utf-8" />
        <title>File Upload</title>
    </head>
    <body>
        <h1>ํŒŒ์ผ ์—…๋กœ๋“œ/File Upload</h1>
        <form action="/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="file" />
            <button type="submit">์—…๋กœ๋“œ/Upload</button>
        </form>
    </body>
</html>

โœ”๏ธupload_server.cpp

#include "../httplib.h"
#include <fstream>
#include <iostream>
#include <sstream>

int main() {
    httplib::Server svr;

    // html upload form
    if (!svr.set_mount_point("/", "./www")) {
        std::cerr << "๊ฒฝ๋กœ ํด๋”๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค! ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•˜์„ธ์š”./The path folder cannot be found! Please check the path." << std::endl;
        return 1;
    }

    // ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ / Upload processing
    svr.Post("/upload", [&](const httplib::Request& req, httplib::Response& res,
                            const httplib::ContentReader& content_reader) {
        if (!req.is_multipart_form_data()) {
            res.status = 400;
            res.set_content("Not multipart/form-data", "text/plain");
            return;
        }

        std::string filename;
        std::ofstream ofs;

        content_reader(
            [&](const httplib::FormData& item) {
                if (item.name != "file") return true;

                filename = httplib::sanitize_filename(item.filename);
                if (filename.empty()) {
                    res.status = 400;
                    res.set_content("Invalid filename", "text/plain");
                    return false;
                }

                ofs.open("../uploads/" + filename, std::ios::binary);
                if (!ofs) {
                    res.status = 500;
                    res.set_content("Failed to open file", "text/plain");
                    return false;
                }
                return true;
            },
            [&](const char* data, size_t len) {
                if (ofs) ofs.write(data, len);
                return true;
            }
        );

        if (ofs) ofs.close();
        res.set_content("Upload OK", "text/plain");
    });

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

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

g++ upload_server.cpp -o upload_server -std=c++11

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

./upload_server

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

/

upload ok

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

Leave a Reply