Skip to content

Commit faba519

Browse files
committed
Update README
1 parent 3159dd7 commit faba519

File tree

1 file changed

+106
-16
lines changed

1 file changed

+106
-16
lines changed

README.md

Lines changed: 106 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,28 +99,28 @@ auto res = cli.Get("/");
9999
if (!res) {
100100
// Check the error type
101101
auto err = res.error();
102-
102+
103103
switch (err) {
104104
case httplib::Error::SSLConnection:
105-
std::cout << "SSL connection failed, SSL error: "
105+
std::cout << "SSL connection failed, SSL error: "
106106
<< res->ssl_error() << std::endl;
107107
break;
108108

109109
case httplib::Error::SSLLoadingCerts:
110-
std::cout << "SSL cert loading failed, OpenSSL error: "
110+
std::cout << "SSL cert loading failed, OpenSSL error: "
111111
<< std::hex << res->ssl_openssl_error() << std::endl;
112112
break;
113-
113+
114114
case httplib::Error::SSLServerVerification:
115-
std::cout << "SSL verification failed, X509 error: "
115+
std::cout << "SSL verification failed, X509 error: "
116116
<< res->ssl_openssl_error() << std::endl;
117117
break;
118-
118+
119119
case httplib::Error::SSLServerHostnameVerification:
120-
std::cout << "SSL hostname verification failed, X509 error: "
120+
std::cout << "SSL hostname verification failed, X509 error: "
121121
<< res->ssl_openssl_error() << std::endl;
122122
break;
123-
123+
124124
default:
125125
std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
126126
}
@@ -356,13 +356,90 @@ svr.set_pre_request_handler([](const auto& req, auto& res) {
356356
});
357357
```
358358

359-
### 'multipart/form-data' POST data
359+
### Form data handling
360+
361+
#### URL-encoded form data ('application/x-www-form-urlencoded')
362+
363+
```cpp
364+
svr.Post("/form", [&](const auto& req, auto& res) {
365+
// URL query parameters and form-encoded data are accessible via req.params
366+
std::string username = req.get_param_value("username");
367+
std::string password = req.get_param_value("password");
368+
369+
// Handle multiple values with same name
370+
auto interests = req.get_param_values("interests");
371+
372+
// Check existence
373+
if (req.has_param("newsletter")) {
374+
// Handle newsletter subscription
375+
}
376+
});
377+
```
378+
379+
#### 'multipart/form-data' POST data
360380

361381
```cpp
362382
svr.Post("/multipart", [&](const auto& req, auto& res) {
363-
auto size = req.files.size();
364-
auto ret = req.has_file("name1");
365-
const auto& file = req.get_file_value("name1");
383+
// New structured form data API provides clear separation between text fields and files
384+
385+
// Access text fields (from form inputs without files)
386+
std::string username = req.form.get_field("username");
387+
std::string bio = req.form.get_field("bio");
388+
389+
// Access uploaded files
390+
if (req.form.has_file("avatar")) {
391+
const auto& file = req.form.get_file("avatar");
392+
std::cout << "Uploaded file: " << file.filename
393+
<< " (" << file.content_type << ") - "
394+
<< file.content.size() << " bytes" << std::endl;
395+
396+
// Save to disk
397+
std::ofstream ofs(file.filename, std::ios::binary);
398+
ofs << file.content;
399+
}
400+
401+
// Handle multiple values with same name
402+
auto tags = req.form.get_fields("tags"); // e.g., multiple checkboxes
403+
for (const auto& tag : tags) {
404+
std::cout << "Tag: " << tag << std::endl;
405+
}
406+
407+
auto documents = req.form.get_files("documents"); // multiple file upload
408+
for (const auto& doc : documents) {
409+
std::cout << "Document: " << doc.filename
410+
<< " (" << doc.content.size() << " bytes)" << std::endl;
411+
}
412+
413+
// Check existence before accessing
414+
if (req.form.has_field("newsletter")) {
415+
std::cout << "Newsletter subscription: " << req.form.get_field("newsletter") << std::endl;
416+
}
417+
418+
// Get counts for validation
419+
if (req.form.get_field_count("tags") > 5) {
420+
res.status = StatusCode::BadRequest_400;
421+
res.set_content("Too many tags", "text/plain");
422+
return;
423+
}
424+
425+
// Summary
426+
std::cout << "Received " << req.form.fields.size() << " text fields and "
427+
<< req.form.files.size() << " files" << std::endl;
428+
429+
res.set_content("Upload successful", "text/plain");
430+
});
431+
```
432+
433+
#### Legacy API (still supported)
434+
435+
> **Note**: The `req.files` field has been removed. Use `req.form.files` and `req.form.fields` instead.
436+
> For backward compatibility, `req.get_file_value()`, `req.has_file()`, and `req.get_file_values()` methods are still available and will delegate to the new `req.form` API.
437+
438+
```cpp
439+
svr.Post("/multipart", [&](const auto& req, auto& res) {
440+
// Legacy API - still works but delegates to req.form internally
441+
auto ret = req.has_file("name1"); // -> req.form.has_file("name1")
442+
const auto& file = req.get_file_value("name1"); // -> req.form.get_file("name1")
366443
// file.filename;
367444
// file.content_type;
368445
// file.content;
@@ -376,16 +453,29 @@ svr.Post("/content_receiver",
376453
[&](const Request &req, Response &res, const ContentReader &content_reader) {
377454
if (req.is_multipart_form_data()) {
378455
// NOTE: `content_reader` is blocking until every form data field is read
379-
MultipartFormDataItems files;
456+
// This approach allows streaming processing of large files
457+
MultipartFormDataItems items;
380458
content_reader(
381-
[&](const MultipartFormData &file) {
382-
files.push_back(file);
459+
[&](const MultipartFormData &item) {
460+
items.push_back(item);
383461
return true;
384462
},
385463
[&](const char *data, size_t data_length) {
386-
files.back().content.append(data, data_length);
464+
items.back().content.append(data, data_length);
387465
return true;
388466
});
467+
468+
// Process the received items
469+
for (const auto& item : items) {
470+
if (item.filename.empty()) {
471+
// Text field
472+
std::cout << "Field: " << item.name << " = " << item.content << std::endl;
473+
} else {
474+
// File
475+
std::cout << "File: " << item.name << " (" << item.filename << ") - "
476+
<< item.content.size() << " bytes" << std::endl;
477+
}
478+
}
389479
} else {
390480
std::string body;
391481
content_reader([&](const char *data, size_t data_length) {

0 commit comments

Comments
 (0)