A basic HTTP client

Let's start from 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, were 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 donwloaded.

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 that is that HTTP request could be quite complex; therefore it is our responsibility to construct a request. We do it when we receive 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, and send a simple GET request:

#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, &done);  // Create client connection
  for (;;) mg_mgr_poll(&mgr, 1000);         // Event loop
  mg_mgr_free(&mgr);                        // Cleanup
  return 0;
}

Error handling

Sometimes not everything goes right and a connection fails for some reason. The host could be down, or the network cable can be cut off during the request, what have you. The right way to catch errors is to handle a MG_EV_ERROR event. An error reason is passed as char * pointer in the ev_data:

static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  if (ev == MG_EV_HTTP_MSG) {
    ...
  } else if (ev == MG_EV_ERROR) {
    printf("Error: %s", (char *) ev_data);
  }

A complete example

A complete example which allows to override a URL via command line flags, and handles HTTPS urls too, can be found at examples/client