Hi everyone! Nowadays there are a lot of applications written in Vala that make HTTP requests and various libraries that can help with it. At the same time, there is a certain lack of information on how to make requests via curl. This article is aimed to cover the gap.
I've encountered this lack of info while working on the Whaler app. The app calls Docker Engine API methods to manage Docker containers under the hood.
At the start of the project, I faced a question: Which library should I use to make HTTP requests? There was an important requirement - the library had to support UNIX sockets.
There were three options:
- GLib.Socket
- libsoup-2.4
- libcurl
GLib.Socket required implementing a wrapper to work with the HTTP protocol. Libsoup-2.4 didn't support UNIX sockets (they became available starting from the 3.0 version). That’s why I skipped the first two and chose libcurl. It had Vala bindings and supported UNIX sockets.
How to add libcurl to a project
First of all, check if libcurl is installed on your system. If not, make sure to install it.
Let’s have a look at a small demo project.
Folder structure:
project/
meson.build
app.vala
vapi/
libcurl.vapi
libcurl.deps
You can download libcurl.vapi and libcurl.deps on List of Vala Bindings.
meson.build:
project('com.github.sdv43.vala-recipes.curl', 'vala', 'c', version: '1.0.0')
vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
executable(
meson.project_name(),
'app.vala',
dependencies: [
dependency('glib-2.0'),
meson.get_compiler('vala').find_library('posix'),
meson.get_compiler('vala').find_library('libcurl', dirs: vapi_dir),
meson.get_compiler('c').find_library('libcurl'),
],
)
Now we can use CURL in the app.vala:
void main() {
var curl = new Curl.EasyHandle();
// set curl options
var code = curl.perform();
assert_true(code == Curl.Code.OK);
}
Easy interface vs. Multi interface
CURL provides two different interfaces: Easy and Multi. The first one works synchronously and the second one, if I got it right, can make several requests simultaneously and works in asynchronous manner.
I chose to use the Easy interface because I found an example written in Vala.
The last problem to be solved was the one with blocking the thread when calling curl_perform
.
I decided to go with the first solution that came to mind. That is to call curl_perform
in a separate thread by using GLib.Task. It prevents the main thread from blocking and allows the app to work correctly. Here is an example:
app.vala:
void main() {
var curl = new Curl.EasyHandle();
// set curl options
var task = new Task (null, null, (source_obj, cl_task) => {
var curl_code = (Curl.Code)cl_task.propagate_int ();
assert_true(curl_code == Curl.Code.OK);
});
task.set_task_data (curl, null);
task.run_in_thread ((cl_task, source_obj, curl, cancellable) => {
unowned var cl_curl = (Curl.EasyHandle)curl;
var code = cl_curl.perform ();
cl_task.return_int (code);
});
}
The final solution used in Whaler is available on Github: HttpClient.vala
Links
- Curl example from Richard-W
- List of Vala Bindings
- CURL Manual
Questions & What's next
I believe it is just one of many possible ways to make HTTP requests in Vala. So I would be happy to hear your thoughts:
- Are there any other HTTP libraries for Vala?
- Is it possible to create a solution without using GLib.Task? Can the Multi interface help with it?
Top comments (0)