README.md 6.37 KB
Newer Older
Jan Jongboom's avatar
Jan Jongboom committed
1
2
# HTTP and HTTPS library for mbed OS 5

3
This library is used to make HTTP and HTTPS calls from Mbed OS 5 applications.
Jan Jongboom's avatar
Jan Jongboom committed
4
5
6
7
8
9
10
11

## HTTP Request API

```cpp
NetworkInterface* network = /* obtain a NetworkInterface object */

const char body[] = "{\"hello\":\"world\"}";

Jan Jongboom's avatar
Jan Jongboom committed
12
13
14
HttpRequest* request = new HttpRequest(network, HTTP_POST, "http://httpbin.org/post");
request->set_header("Content-Type", "application/json");
HttpResponse* response = request->send(body, strlen(body));
Jan Jongboom's avatar
Jan Jongboom committed
15
16
17
// if response is NULL, check response->get_error()

printf("status is %d - %s\n", response->get_status_code(), response->get_status_message());
Jan Jongboom's avatar
Jan Jongboom committed
18
19
20
printf("body is:\n%s\n", response->get_body_as_string().c_str());

delete request; // also clears out the response
Jan Jongboom's avatar
Jan Jongboom committed
21
22
23
24
25
```

## HTTPS Request API

```cpp
26
// pass in the root certificates that you trust, there is no central CA registry in Mbed OS
Jan Jongboom's avatar
Jan Jongboom committed
27
28
29
30
31
32
33
const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
    /* rest of the CA root certificates */;

NetworkInterface* network = /* obtain a NetworkInterface object */

const char body[] = "{\"hello\":\"world\"}";

Jan Jongboom's avatar
Jan Jongboom committed
34
35
HttpsRequest* request = new HttpsRequest(network, SSL_CA_PEM, HTTP_GET "https://httpbin.org/status/418");
HttpResponse* response = request->send();
Jan Jongboom's avatar
Jan Jongboom committed
36
37
38
39
// if response is NULL, check response->get_error()

printf("status is %d - %s\n", response->get_status_code(), response->get_status_message());
printf("body is:\n%s\n", response->get_body().c_str());
Jan Jongboom's avatar
Jan Jongboom committed
40
41

delete request;
Jan Jongboom's avatar
Jan Jongboom committed
42
43
```

44
45
**Note:** You can get the root CA for a domain easily from Firefox. Click on the green padlock, click *More information > Security > View certificate > Details*. Select the top entry in the 'Certificate Hierarchy' and click *Export...*. This gives you a PEM file. Add the content of the PEM file to your root CA list ([here's an image](img/root-ca-selection.png)).

46
### Mbed TLS Entropy configuration
47

48
If your target does not have a built-in TRNG, or other entropy sources, add the following macros to your `mbed_app.json` file to disable entropy:
49

50
51
52
53
54
55
56
57
```json
{
    "macros": [
        "MBEDTLS_TEST_NULL_ENTROPY",
        "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES"
    ]
}
```
58

59
Note that this is **not** secure, and you should not deploy this device into production with this configuration.
60

61
## Memory usage
62

63
Small requests where the body of the response is cached by the library (like the one found in main-http.cpp), require ~4K of RAM. When the request is finished they require ~1.5K of RAM, depending on the size of the response. This applies both to HTTP and HTTPS. If you need to handle requests that return a large response body, see 'Dealing with large body'.
64

65
HTTPS requires additional memory: on FRDM-K64F about 50K of heap space (at its peak). This means that you cannot use HTTPS on devices with less than 128K of memory, as you also need to reserve memory for the stack and network interface.
66

Jan Jongboom's avatar
Jan Jongboom committed
67
### Dealing with large response body
Jan Jongboom's avatar
Jan Jongboom committed
68

Jan Jongboom's avatar
Jan Jongboom committed
69
By default the library will store the full request body on the heap. This works well for small responses, but you'll run out of memory when receiving a large response body. To mitigate this you can pass in a callback as the last argument to the request constructor. This callback will be called whenever a chunk of the body is received. You can set the request chunk size in the `HTTP_RECEIVE_BUFFER_SIZE` macro (see `mbed_lib.json` for the definition) although it also depends on the buffer size of the underlying network connection.
Jan Jongboom's avatar
Jan Jongboom committed
70
71

```cpp
72
void body_callback(const char* data, uint32_t data_len) {
Jan Jongboom's avatar
Jan Jongboom committed
73
74
75
    // do something with the data
}

76
77
HttpRequest* req = new HttpRequest(network, HTTP_GET, "http://pathtolargefile.com", &body_callback);
req->send(NULL, 0);
Jan Jongboom's avatar
Jan Jongboom committed
78
79
```

Jan Jongboom's avatar
Jan Jongboom committed
80
81
82
83
84
### Dealing with a large request body

If you cannot load the full request into memory, you can pass a callback into the `send` function. Through this callback you can feed in chunks of the request body. This is very useful if you want to send files from a file system.

```cpp
85
const void * get_chunk(uint32_t* out_size) {
Jan Jongboom's avatar
Jan Jongboom committed
86
87
88
89
90
91
92
93
94
95
    // set the value of out_size (via *out_size = 10) to the size of the buffer
    // return the buffer

    // if you don't have any more data, set *out_size to 0
}

HttpRequest* req = new HttpRequest(network, HTTP_POST, "http://my_api.com/upload");
req->send(callback(&get_chunk));
```

Jan Jongboom's avatar
Jan Jongboom committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
## Socket re-use

By default the library opens a new socket per request. This is wasteful, especially when dealing with TLS requests. You can re-use sockets like this:

### HTTP

```cpp
TCPSocket* socket = new TCPSocket();

nsapi_error_t open_result = socket->open(network);
// check open_result

nsapi_error_t connect_result = socket->connect("httpbin.org", 80);
// check connect_result

// Pass in `socket`, instead of `network` as first argument
HttpRequest* req = new HttpRequest(socket, HTTP_GET, "http://httpbin.org/status/418");
```

### HTTPS

```cpp
Jan Jongboom's avatar
Jan Jongboom committed
118
TLSSocket* socket = new TLSSocket();
119
120

nsapi_error_t r;
Jan Jongboom's avatar
Jan Jongboom committed
121
// make sure to check the return values for the calls below (should return NSAPI_ERROR_OK)
122
123
124
r = socket->open(network);
r = socket->set_root_ca_cert(SSL_CA_PEM);
r = socket->connect("httpbin.org", 443);
Jan Jongboom's avatar
Jan Jongboom committed
125
126
127
128
129

// Pass in `socket`, instead of `network` as first argument, and omit the `SSL_CA_PEM` argument
HttpsRequest* get_req = new HttpsRequest(socket, HTTP_GET, "https://httpbin.org/status/418");
```

Jan Jongboom's avatar
Jan Jongboom committed
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
## Request logging

To make debugging easier you can log the raw request body that goes over the line. This also works with chunked encoding.

```cpp
uint8_t *request_buffer = (uint8_t*)calloc(2048, 1);
req->set_request_log_buffer(request_buffer, 2048);

// after the request is done:
printf("\n----- Request buffer -----\n");
for (size_t ix = 0; ix < req->get_request_log_buffer_length(); ix++) {
    printf("%02x ", request_buffer[ix]);
}
printf("\n");
```

146
147
148
149
150
151
152
153
## Integration tests

Integration tests are located in the `TESTS` folder and are ran through [Greentea](https://github.com/ARMmbed/greentea). Instructions on how to run the tests are in [http-example](https://os.mbed.com/teams/sandbox/code/http-example/).

## Mbed OS 5.10 or lower

If you want to use this library on Mbed OS 5.10 or lower, you need to add the [TLSSocket](https://github.com/ARMmbed/TLSSocket) library to your project. This library is included in Mbed OS 5.11 and up.

Jan Jongboom's avatar
Jan Jongboom committed
154
155
156
157
## Tested on

* K64F with Ethernet.
* NUCLEO_F411RE with ESP8266.
158
* ODIN-W2 with WiFi.
Jan Jongboom's avatar
Jan Jongboom committed
159
* K64F with Atmel 6LoWPAN shield.
160
* DISCO-L475VG-IOT01A with WiFi.
161
* [Mbed Simulator](https://github.com/janjongboom/mbed-simulator).
Jan Jongboom's avatar
Jan Jongboom committed
162
163

But this should work with any Mbed OS 5 device that implements the `NetworkInterface` API.