RESTful HTTP Client in a Browser using JavaScript

A frustration I’ve often faced when interacting with RESTful HTTP servers is that browsers make poor RESTful HTTP clients. Specifically, browsers only support the GET and POST methods and do not allow you to specify media types or other header values. This does not make for simple, self-served, human interfaces in the IoT world.

It turns out, with a little JavaScript magic, your browser can make a pretty decent RESTful HTTP client.

The code snippets below show how to perform a GET with a specified Accept header as well as a PUT with a specified Content-Type header. I’ll leave the extension to other methods and headers as an exercise to the reader.

function getOnOff(contentType)
{
	var xmlhttp = new XMLHttpRequest();
	var ds = "";
	xmlhttp.open("GET", "/onoff");
	xmlhttp.setRequestHeader("Accept", contentType);
	xmlhttp.onreadystatechange = function()
	{
		if(xmlhttp.readyState == 4)
		{
			ds = xmlhttp.responseText;
			document.forms[0].textArea1.value = ds;
		}
	}
	xmlhttp.send();
}

function putOnOff(state, contentType)
{
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("PUT", "/onoff");
	xmlhttp.setRequestHeader("Content-Type", contentType);
	if(contentType == "application/xml")
	{
		if(state == "on")
		{
			xmlhttp.send("<OnOff>\n\t<state>on</state>\n</OnOff>");
		}
		else if(state == "off")
		{
			xmlhttp.send("<OnOff>\n\t<state>off</state>\n</OnOff>");
		}
	}
	else if(contentType == "application/json")
	{
		if(state == "on")
		{
			xmlhttp.send("{\n\"state\": \"on\"\n}");
		}
		else if(state == "off")
		{
			xmlhttp.send("{\n\"state\": \"off\"\n}");
		}
	}
}

I’ve integrated a page with similar functions into the Deuterium demo to provide a simple human interface. The demo server simply serves up this page and the user can easily interact RESTfully with the server’s resources. Check out the Deuterium test servers to see this in action.

One limitation (unless you want to fool around with your browser’s security settings) is that these snippets are subject to cross domain scripting restrictions, making a generic client less easy. At that point, you may want to look into various browser plugins.

As a bonus, if your browser supports HTTP/2, then this trick will work seamlessly with HTTP/2 (essentially the JavaScript utilizes whatever transport the browser is using).

Implementing HTTP/2 with mbed TLS

I’ve recently been exploring mbed TLS and thought I’d share some numbers I’ve found.

First, the specifics:

  • mbed TLS version: 1.3.10
  • Compiler: arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20141119 (release) [ARM/embedded-4_9-branch revision 218278]
  • Processor: TI CC3200 (ARM Cortex-M4 core)

As I’ve been primarily focused on an HTTP/2 server here, I configured mbed TLS to support the mandatory to implement (MTI) ciphersuite for HTTP/2, TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256, along with various required features such as SNI, ALPN, and X.509 certificates. This resulted in a config.h file with the following items #define’ed:

  • POLARSSL_HAVE_LONGLONG
  • POLARSSL_HAVE_ASM
  • POLARSSL_HAVE_IPV6
  • POLARSSL_PLATFORM_PRINTF_ALT
  • POLARSSL_PLATFORM_FPRINTF_ALT
  • POLARSSL_REMOVE_ARC4_CIPHERSUITES
  • POLARSSL_ECP_DP_SECP256R1_ENABLED
  • POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED
  • POLARSSL_NO_PLATFORM_ENTROPY
  • POLARSSL_PKCS1_V15
  • POLARSSL_SSL_EXTENDED_MASTER_SECRET
  • POLARSSL_SSL_DISABLE_RENEGOTIATION
  • POLARSSL_SSL_MAX_FRAGMENT_LENGTH
  • POLARSSL_SSL_PROTO_TLS1_2
  • POLARSSL_SSL_ALPN
  • POLARSSL_SSL_SERVER_NAME_INDICATION
  • POLARSSL_SSL_TRUNCATED_HMAC
  • POLARSSL_SSL_SET_CURVES
  • POLARSSL_X509_CHECK_KEY_USAGE
  • POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE
  • POLARSSL_AES_C
  • POLARSSL_ASN1_PARSE_C
  • POLARSSL_BIGNUM_C
  • POLARSSL_CIPHER_C
  • POLARSSL_CTR_DRBG_C
  • POLARSSL_ECDH_C
  • POLARSSL_ECP_C
  • POLARSSL_ENTROPY_C
  • POLARSSL_GCM_C
  • POLARSSL_MD_C
  • POLARSSL_OID_C
  • POLARSSL_PK_C
  • POLARSSL_PK_PARSE_C
  • POLARSSL_PLATFORM_C
  • POLARSSL_RSA_C
  • POLARSSL_SHA256_C
  • POLARSSL_SSL_CACHE_C
  • POLARSSL_SSL_SRV_C
  • POLARSSL_SSL_TLS_C
  • POLARSSL_X509_USE_C
  • POLARSSL_X509_CRT_PARSE_C
  • SSL_CIPHERSUITES TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

With this config.h in place, I executed the following command:
CC=arm-none-eabi-gcc AR=arm-none-eabi-ar CFLAGS+=”-mthumb -mcpu=cortex-m4 -ffunction-sections -fdata-sections” make lib

This resulted in a static library (libmbedtls.a) with a size of 238972 bytes. Keep in mind that this is doing everything in software (AES, SHA, ECC, etc.).

One trick I learned along the way: It’s best to store your certificates and keys in DER format — no PEM. This allows you to remove POLARSSL_PEM_PARSE_C and POLARSSL_BASE64_C. With this trick, I went from a static library (libmbedtls.a) with a size of 243536 bytes to one with a size of 238972 bytes. This method also reduces size of the certificates and keys themselves.

If you have any optimizations or findings with mbed TLS, particularly for HTTP/2, please share in the comments!

First IoT Device with HTTP/2?

As far as I know, this is the first embedded / Internet of Things device to run HTTP/2!

TI CC3200 LaunchPad running an HTTP/2 server

TI CC3200 LaunchPad running an HTTP/2 server

This particular platform is a Texas Instruments CC3200 LaunchPad. The CC3200 is a Wi-Fi SoC that incorporates an ARM Cortex-M4 and Wi-Fi into a single piece of silicon.

Over the past couple of days, I ported the Deuterium HTTP/2 library to the CC3200 and set up a simple HTTP/2 server with a RESTful interface to one of the onboard LEDs.

I went with Wi-Fi in this case (as opposed to 802.15.4, for example) so that I can easily show it off at the upcoming IETF in Dallas.

Granted, I had 256 KB of RAM and BSD socket support to work with, so no huge accomplishment… But, it still demonstrates the capabilities of HTTP/2 for the Internet of Things.

Kudos to TI for such a good product!

If you are interested in using HTTP/2 on this or another embedded platform, check out the Deuterium HTTP/2 library.

HTTP/2 and the Internet of Things

I have never been a fan of using custom or obscure protocols to talk to embedded devices, particularly if the goal is to bring them into the mainstream of communications (e.g., the Internet of Things). I’m looking at you CoAP, MQTT, etc.!

It’s not that CoAP, MQTT, and all of the others aren’t well designed, useful, or perhaps even better. It’s that they are not what the rest of the Internet are using to communicate.

So, what is? Well, I think we all know the answer to that: HTTP. Even email, which has always had its own protocols, is largely using HTTP at this point.

The HTTP we all know and love, HTTP/1.1, is poorly suited to embedded devices. Its use of loose, plain ASCII makes for complex parsing (codespace!) and eats up a lot of RAM and buffer space. Then, when you try and shuffle all of those ASCII characters across the network, you eat up bandwidth — something embedded devices often do not have in abundance. Further, transmitting bits takes energy – a particular problem if you are battery-powered.

Well, I’m hoping that the next version of HTTP, HTTP/2, helps to lessen those problems. Of course it will not be as efficient and great for embedded devices as a protocol designed for the embedded space, but consideration was given to the embedded space during the design of HTTP/2. And the goals of the large Web servers often align with those of the embedded space — less memory and bandwidth also matter if you are serving millions of clients!

How does HTTP/2 help? Well, for starters, it employs a very efficient, yet low memory (unlike gzip) compression technique, HPACK. HPACK works by assigning header names and values to entries in tables. Then, only the entry number needs to be used. This allows for efficient use of bandwidth while not sacrificing the original syntax of HTTP. The sizes of the tables can be limited via negotiation, limiting RAM usage.

What about the complex parsing, you ask? Well, it’s not entirely gone, but HTTP/2 did a lot to try and tighten the syntax and thus the parsing. As with all new protocols, a lot of the legacy could be dropped or tightened. Finally, for those header names and values that may not warrant entry into the tables built up between server and client, Huffman codes can be used. Canonical Huffman codes, in fact.

HTTP/2 also encourages each client/server pair to use a single TCP connection. Individual requests and their responses are sent in streams over this connection. Once again, the number of simultaneous streams can also be limited via negotiation. This connection reuse means less network overhead – no more three-way handshake for each request/response, no more slow start over and over again, no more TLS renegotiation over and over again. You get the point. And considering IoT devices tend to focus on short messages, the benefits really add up.

Other features of HTTP/2 that are particularly beneficial to the embedded world include: binary message framing, header list size negotiation, server push, ping, and windowing. Each of these could definitely use a lot more description, but I’m hoping to avoid “tl;dr”.

In conclusion, I believe that HTTP/2, while not perfect, will allow embedded/IoT devices to fully join the rest of the Internet and no longer be second-class citizens. Truly enabling the Web of Things!

If you are interested in using HTTP/2 for an IoT application, check out Deuterium, my own embedded implementation of HTTP/2.