Overview

This tutorial will show you how to configure an HTTP client.

We'll start from a very basic loop and add the connection function, and later address error handling.

A basic HTTP client

Let's start with a minimal Mongoose template that initialises and starts an event manager, but does nothing:

#include "mongoose.h"

int main(int argc, char *argv[]) {
  struct mg_mgr mgr;
  mg_mgr_init(&mgr);                  // Init manager
  for (;;) mg_mgr_poll(&mgr, 1000);   // Event loop
  mg_mgr_free(&mgr);                  // Cleanup
  return 0;
}

Now, let's create an HTTP client connection before the event loop starts. We will fetch the very first web page in history - a page from CERN, where the Web was invented by Tim Bernes-Lee. That web page is still alive! Let's create a variable that holds a URL:

  // First web page in history
  static const char *s_url = "http://info.cern.ch/";  

Client connection

Now, add a client connection. We need an event handler function for it. That event handler function is going to get an MG_EV_HTTP_MSG event when a full page content gets downloaded.

A client connection is created by the mg_http_connect() function. An important aspect of that function is that it only creates a TCP connection to the server, but does not send a request. The reason for this is that an HTTP request could be quite complex; therefore it is our responsibility to construct the request. We do it when we receive an MG_EV_CONNECT event.

There, we extract a hostname from the URL to form a valid Host header, which is mandatory for HTTP/1.1, using the mg_url_host() function. We also make use of the mg_url_uri() function to point to the URI part in the URL.

Finally, we send a simple GET request using mg_printf():

#include "mongoose.h"

// First web page in history
static const char *s_url = "http://info.cern.ch/";  

static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  if (ev == MG_EV_CONNECT) {
    struct mg_str host = mg_url_host(s_url);
    // Send request
    mg_printf(c,
              "GET %s HTTP/1.0\r\n"
              "Host: %.*s\r\n"
              "\r\n",
              mg_url_uri(s_url), (int) host.len, host.ptr);
  } if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
    printf("%.*s", (int) hm->message.len, hm->message.ptr);
  }
}

int main(int argc, char *argv[]) {
  struct mg_mgr mgr;
  mg_mgr_init(&mgr);                        // Init manager
  mg_http_connect(&mgr, s_url, fn, NULL);   // Create client connection
  for (;;) mg_mgr_poll(&mgr, 1000);         // Event loop
  mg_mgr_free(&mgr);                        // Cleanup
  return 0;
}

Error handling

Connection failures will trigger an MG_EV_ERROR event; an error reason is passed as a char * pointer in parameter ev_data.

Check the error handling tutorial for more information

Build and run

A complete example which allows to override a URL via command line flags, handles connection errors, exits when finished, and handles HTTPS URLs too, can be found at examples/http-client

  • If you've not already done so, clone the Mongoose Library repo
    $ git clone https://github.com/cesanta/mongoose
    
  • Build and run the example
    $ cd mongoose/examples/http-client
    $ make clean all
    
  • Observe the log, you'll see the HTML code of the first web page

To help with verbosity, you can also change the default log level by setting the environment variable LOG_LEVEL to the desired level.

$ export LOG_LEVEL=3 ; ./example

If you like, you can also run the example with a URL of your choice

$ ./example http://somesite

Build with TLS support

The makefile will take care of this, just pass it the proper argument.

  • For openSSL:

    $ make clean all SSL=OPENSSL
    
  • For mbedTLS:

    $ make clean all SSL=MBEDTLS
    
  • If you need to provide extra information, like for example includes and library paths, do it with the EXTRA_CFLAGS variable, like:

    $ make clean all SSL=MBEDTLS EXTRA_CFLAGS="-I/path/to/mbedtls/include -L/path/to/mbedtls/lib"
    

Now you can pass an HTTPS URL to the compiled example.

For more information on building TLS clients, check the TLS tutorial