A tiny, C++ network socket wrapper (based on Mongoose and Mbed-TLS) for http(s) requests especially for embedded devices. Inspired by the excellent CPR library, WNetWrap, it has mostly identical function names, and will likewise work with random parameter order.
Implemented | Upcoming |
---|---|
Custom headers | Cookie support |
Url encoded parameters | Self-signed Root CA support, All well-known Root CA support |
Multipart upload | Change default dns server |
File upload | Add auth proxy |
Custom request methods | |
Basic authentication | |
Bearer authentication | |
Request timeout | |
Non-Auth Proxy support |
That is a basic GET request - for detailed examples see the documentation below.
#include <iostream>
#include "ehlib.h"
//Tested on Postman Echo
//GET Request
ehlib::Response r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/get"},
ehlib::UrlRequestParams{
{"foo1", "bar1"},
{"foo2", "bar2"}
},
ehlib::RequestMethod{"GET"},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.raw << std::endl; // basic parser
std::cout << r.status_code << std::endl; // 200
-
Just copy folders
include
,lib
into your project. -
Add static libs and include
ehlib.h
into your build. -
That's it!
For now it's all here on the readme, but it will eventually be put on a different page to make navigation more user friendly.
To navigate through it use the table of contents dropdown menu.
Making a GET
request with Ehlib
is simple - the GET
method is used by default so doesn't need to be specified:
#include "ehlib.h"
ehlib::Response r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/get"},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
This gives us a Response
object which we’ve called r.
There’s a lot of useful stuff in there:
std::cout << r.url << std::endl; // https://postman-echo.com/get
std::cout << r.status_code << std::endl; // 200
std::cout << r.header["Content-type"] << std::endl; // application/json; charset=utf-8
std::cout << r.raw << std::endl;
/*
{
"args": {},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d67257-24fc86582562e80206287bbe",
"content-length": "0",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"url": "https://postman-echo.com/get"
}
*/
To add URL-encoded parameters, add a UrlRequestParams
object to the request
call:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/get"},
ehlib::UrlRequestParams{
{"foo1", "bar1"},
{"foo2", "bar2"}
},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.url << std::endl; // https://postman-echo.com/get?foo1=bar1&foo2=bar2
std::cout << r.raw << std::endl;
/*
{
"args": {
"foo1": "bar1",
"foo2": "bar2"
},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d674e0-26f038a10e869e521dcdbfdc",
"content-length": "0",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2"
}
*/
UrlRequestParams
is an object with a map-like interface.
You can construct it using a list of key/value pairs inside the request
or have it outlive request
by constructing it outside:
// Constructing it in a place
auto r = ehlib::request(
ehlib::RequestUrl{"http://www.httpbin.org/get"},
ehlib::UrlRequestParams{
{"foo1", "bar1"},
{"foo2", "bar2"}
},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.url << std::endl; // https://postman-echo.com/get?foo1=bar1&foo2=bar2
std::cout << r.raw << std::endl;
/*
{
"args": {
"foo1": "bar1",
"foo2": "bar2"
},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d67627-0f91d09203e69af636c8fcfb",
"content-length": "0",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2"
}
*/
// Constructing it an outside
auto parameters = ehlib::UrlRequestParams{
{"foo1", "bar1"},
{"foo2", "bar2"}
};
auto r_outside = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/get"},
parameters
);
std::cout << r_outside.url << std::endl; // https://postman-echo.com/get?foo1=bar1&foo2=bar2
std::cout << r_outside.raw << std::endl; // Same text response as above
To download the contents of the request you simply add RequestUrl
to request
.
File content will return into Response's raw
field.
For example, to download the CPR library:
auto r = ehlib::request(
ehlib::RequestUrl{ "https://github.com/whoshuu/cpr/archive/refs/tags/1.10.4.zip" },
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.raw << std::endl; // print donwloaded file's content (our 1.10.4.zip archive bytes)
Making a POST request must use RequestMethod
:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/post"},
ehlib::RequestMethod{"POST"}
);
std::cout << r.text << std::endl;
/*
{
"args": {},
"data": {},
"files": {},
"form": {},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d688e8-1a56cc76092b9abd7de205d9",
"content-length": "0",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"json": null,
"url": "https://postman-echo.com/post"
}
*/
This sends some data "This is raw POST data"
with use PostRequestBody
:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/post"},
ehlib::PostRequestBody{"This is raw POST data"},
ehlib::RequestMethod{"POST"}
);
std::cout << r.text << std::endl;
/*
{
"args": {},
"data": "This is raw POST data",
"files": {},
"form": {},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d689c1-3a281bae0158913d6a4f240a",
"content-length": "21",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"content-type": "application/json"
},
"json": null,
"url": "https://postman-echo.com/post"
}
*/
If the data package is large or contains a file, it’s more appropriate to use a RequestMultipartUpload
upload.
In this example we are uploading a text files to https://postman-echo.com/post
:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/post"},
ehlib::RequestMultipartUpload{
{"file_path:1.txt", "1.txt"},
{"file_path:C:/Windows/win.ini", "win.ini"},
{"some raw data", "2.txt"}
},
ehlib::RequestMethod{"POST"}
);
std::cout << r.text << std::endl;
/*
{
"args": {},
"data": {},
"files": {
"1.txt": "data:application/octet-stream;base64,aGVsbG8gd29ybGQh",
"win.ini": "data:application/octet-stream;base64,OyBmb3IgMTYtYml0IGFwcCBzdXBwb3J0DQpbZm9udHNdDQpbZXh0ZW5zaW9uc10NClttY2kgZXh0ZW5zaW9uc10NCltmaWxlc10NCltNYWlsXQ0KTUFQST0xDQo="
},
"form": {
"some raw data": "2.txt"
},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d68e5f-0e0b852e32702ddc7806ff31",
"content-length": "513",
"content-type": "multipart/form-data; boundary=1816741701207515830740325151",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"json": null,
"url": "https://postman-echo.com/post"
}
*/
Notice file_path:
prefix - this tells that is file on disk and not a key - value pair as form {"some raw data", "2.txt"}
.
To use Basic Authentication which uses a username and password, just add BasicAuth
to the call:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/basic-auth"},
ehlib::BasicAuth {"postman", "password"},
ehlib::RequestMethod{"GET"}
);
std::cout << r.text << std::endl;
/*
{
"authenticated": true
}
*/
Authentication via an OAuth - Bearer Token can be done using the BearerAuth
authentication object:
auto r = ehlib::request(
ehlib::RequestUrl{"http://www.httpbin.org/bearer"},
ehlib::BearerAuth {"ACCESS_TOKEN"},
ehlib::RequestMethod{"GET"}
);
std::cout << r.text << std::endl;
/*
{
"authenticated": true,
"token": "ACCESS_TOKEN"
}
*/
A Response
has these public fields and methods:
std::string status_code; // The HTTP(S) status code for the request
std::string raw; // The data of the HTTP response
std::map header; // A map of the header fields received
std::map sent_headers; // A map of the headers sent
std::string url; // The effective URL of the ultimate request
std::string err; // An error string containing the error code and a message
unsigned long uploaded_bytes; // How many bytes have been sent to the server
unsigned long downloaded_bytes; // How many bytes have been received from the server
unsigned long redirect_count; // How many redirects occurred
void reset(); // Reset Response object to default state
Using RequestHeaders
in your request
you can specify custom headers:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/get"},
ehlib::RequestHeaders{
{"accept", "application/json"},
{"master", "slave"}
},
ehlib::RequestMethod{"GET"},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.text << std::endl;
/*
{
"args": {},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"x-amzn-trace-id": "Root=1-64d6950a-387220f76b21c06865853326",
"content-length": "0",
"accept": "application/json",
"master": "slave",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"url": "https://postman-echo.com/get"
}
*/
It’s possible to set a timeout for your request if you have strict timing requirements:
auto r = ehlib::request(
ehlib::RequestUrl{"https://postman-echo.com/get"},
ehlib::RequestTimeout{ 10 },
ehlib::RequestMethod{"GET"},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.text << std::endl; // Connection timeout
Setting the RequestTimeout
option sets the maximum allowed time the connection or request operation can take in milliseconds. By default a RequestTimeout
set in 5000 milliseconds
Setting up a proxy is easy. For example, we have tor http proxy
on localhost
port 9080
.
Try to connect to https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/
.
This is official duckduckgo.com
.onion mirror. To do this we will use RequestProxy
.
auto r = ehlib::request(
ehlib::RequestUrl{"https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/"},
ehlib::RequestTimeout{ 100000 },
ehlib::RequestProxy{ "http://127.0.0.1:9080"},
ehlib::RequestMethod{"GET"},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.raw << std::endl;
/*
<!DOCTYPE html>\n<!--[if IEMobile 7 ]> <html lang=\"en-US\" class=\"no-js iem7\"> <![endif]-->\n<!--[if lt IE 7]> <html class=\"ie6 lt-ie10 lt-ie9 lt-ie8 lt-ie7 no-js\" lang=\"en-US\"> <![endif]-->\n<!--[if IE 7]> <html class=\"ie7 lt-ie10 lt-ie9 lt-ie8 no-js\" lang=\"en-US\"> <![endif]-->\n<!--[if IE 8]> <html class=\"ie8 lt-ie10 lt-ie9 no-js\" lang=\"en-US\"> <![endif]-->\n<!--[if IE 9]> <html class=\"ie9 lt-ie10 no-js\" lang=\"en-US\"> <![endif]-->\n<!--[if (gte IE 9)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class=\"no-js\" lang=\"en-US\" data-ntp-features=\"tracker-stats-widget:off\"><!--<![endif]-->\n\n<head>\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge\" />\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8;charset=utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=1\" />\n<meta name=\"HandheldFriendly\" content=\"true\"/>\n<meta name=\"darkreader-lock\" />\n\n<link rel=\"canonical\" href=\"https://duckduckgo.com/duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion\">\n\n<link rel=\"stylesheet\" ...</html>\n
*/
Allowed options | Upcoming |
---|---|
auto-redirect (on/off) | ? |
The RequestOptions
constructor allows you to specify additional options for the request. For example, turn off
auto-redirects (default: auto-redirect
turn on
). To enable the option you can use on
.
auto r = ehlib::request(
ehlib::RequestUrl{"http://ya.ru"},
ehlib::RequestOptions {
{"auto-redirect", "off"}
},
ehlib::RequestUserAgent{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
);
std::cout << r.status_code << std::endl; // 301