generated from espressif/esp-idf-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
https_req.c
260 lines (227 loc) · 8.11 KB
/
https_req.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "esp_tls.h"
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
#include "esp_crt_bundle.h"
#endif
#include "https_req.h"
#include "config.h"
/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "api.bilibili.com"
#define WEB_PORT "443"
#define WEB_URL "https://api.bilibili.com/x/relation/stat?vmid="
#define SERVER_URL_MAX_SZ 256
char https_req_buf[MAX_REQUEST_BUF_LEN];
static const char *TAG = "https req";
static const char HOWSMYSSL_REQUEST[] = "GET " WEB_URL BILIBILI_VMID " HTTP/1.1\r\n"
"Host: " WEB_SERVER "\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static const char LOCAL_SRV_REQUEST[] = "GET " CONFIG_EXAMPLE_LOCAL_SERVER_URL " HTTP/1.1\r\n"
"Host: " WEB_SERVER "\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
#endif
/* Root cert for howsmyssl.com, taken from server_root_cert.pem
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
// extern const uint8_t local_server_cert_pem_start[] asm("_binary_local_server_cert_pem_start");
// extern const uint8_t local_server_cert_pem_end[] asm("_binary_local_server_cert_pem_end");
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static esp_tls_client_session_t *tls_client_session = NULL;
static bool save_client_session = false;
#endif
static void https_get_request(esp_tls_cfg_t cfg, const char *WEB_SERVER_URL, const char *REQUEST)
{
char buf[MAX_REQUEST_BUF_LEN];
int ret, len;
struct esp_tls *tls = esp_tls_conn_http_new(WEB_SERVER_URL, &cfg);
if (tls != NULL)
{
ESP_LOGI(TAG, "Connection established...");
}
else
{
ESP_LOGE(TAG, "Connection failed...");
goto exit;
}
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
/* The TLS session is successfully established, now saving the session ctx for reuse */
if (save_client_session)
{
free(tls_client_session);
tls_client_session = esp_tls_get_client_session(tls);
}
#endif
size_t written_bytes = 0;
do
{
ret = esp_tls_conn_write(tls,
REQUEST + written_bytes,
strlen(REQUEST) - written_bytes);
if (ret >= 0)
{
ESP_LOGI(TAG, "%d bytes written", ret);
written_bytes += ret;
}
else if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE)
{
ESP_LOGE(TAG, "esp_tls_conn_write returned: [0x%02X](%s)", ret, esp_err_to_name(ret));
goto exit;
}
} while (written_bytes < strlen(REQUEST));
ESP_LOGI(TAG, "Reading HTTP response...");
do
{
len = sizeof(buf) - 1;
bzero(buf, sizeof(buf));
ret = esp_tls_conn_read(tls, (char *)buf, len);
if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ)
{
continue;
}
if (ret < 0)
{
ESP_LOGE(TAG, "esp_tls_conn_read returned [-0x%02X](%s)", -ret, esp_err_to_name(ret));
break;
}
if (ret == 0)
{
ESP_LOGI(TAG, "connection closed");
break;
}
len = ret;
ESP_LOGD(TAG, "%d bytes read", len);
/* Print response directly to stdout as it is read */
for (int i = 0; i < len; i++)
{
putchar(buf[i]);
}
putchar('\n'); // JSON output doesn't have a newline at end
memcpy(https_req_buf, buf, MAX_REQUEST_BUF_LEN);
} while (1);
exit:
esp_tls_conn_delete(tls);
for (int countdown = 10; countdown >= 0; countdown--)
{
ESP_LOGI(TAG, "%d...", countdown);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
static void https_get_request_using_crt_bundle(void)
{
ESP_LOGI(TAG, "https_request using crt bundle");
esp_tls_cfg_t cfg = {
.crt_bundle_attach = esp_crt_bundle_attach,
};
https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST);
}
#endif // CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
static void https_get_request_using_cacert_buf(void)
{
ESP_LOGI(TAG, "https_request using cacert_buf");
esp_tls_cfg_t cfg = {
.cacert_buf = (const unsigned char *)server_root_cert_pem_start,
.cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start,
};
https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST);
}
static void https_get_request_using_global_ca_store(void)
{
esp_err_t esp_ret = ESP_FAIL;
ESP_LOGI(TAG, "https_request using global ca_store");
esp_ret = esp_tls_set_global_ca_store(server_root_cert_pem_start, server_root_cert_pem_end - server_root_cert_pem_start);
if (esp_ret != ESP_OK)
{
ESP_LOGE(TAG, "Error in setting the global ca store: [%02X] (%s),could not complete the https_request using global_ca_store", esp_ret, esp_err_to_name(esp_ret));
return;
}
esp_tls_cfg_t cfg = {
.use_global_ca_store = true,
};
https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST);
esp_tls_free_global_ca_store();
}
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static void https_get_request_to_local_server(const char *url)
{
ESP_LOGI(TAG, "https_request to local server");
esp_tls_cfg_t cfg = {
.cacert_buf = (const unsigned char *)local_server_cert_pem_start,
.cacert_bytes = local_server_cert_pem_end - local_server_cert_pem_start,
.skip_common_name = true,
};
save_client_session = true;
https_get_request(cfg, url, LOCAL_SRV_REQUEST);
}
static void https_get_request_using_already_saved_session(const char *url)
{
ESP_LOGI(TAG, "https_request using saved client session");
esp_tls_cfg_t cfg = {
.client_session = tls_client_session,
};
https_get_request(cfg, url, LOCAL_SRV_REQUEST);
esp_tls_free_client_session(tls_client_session);
save_client_session = false;
tls_client_session = NULL;
}
#endif
void https_request_task(void *pvparameters)
{
ESP_LOGI(TAG, "Start https_request example");
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
char *server_url = NULL;
#ifdef CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN
char url_buf[SERVER_URL_MAX_SZ];
if (strcmp(CONFIG_EXAMPLE_LOCAL_SERVER_URL, "FROM_STDIN") == 0)
{
example_configure_stdin_stdout();
fgets(url_buf, SERVER_URL_MAX_SZ, stdin);
int len = strlen(url_buf);
url_buf[len - 1] = '\0';
server_url = url_buf;
}
else
{
ESP_LOGE(TAG, "Configuration mismatch: invalid url for local server");
abort();
}
printf("\nServer URL obtained is %s\n", url_buf);
#else
server_url = CONFIG_EXAMPLE_LOCAL_SERVER_URL;
#endif /* CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN */
https_get_request_to_local_server(server_url);
https_get_request_using_already_saved_session(server_url);
#endif
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
https_get_request_using_crt_bundle();
#endif
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
https_get_request_using_cacert_buf();
https_get_request_using_global_ca_store();
ESP_LOGI(TAG, "Finish https_request example");
vTaskDelete(NULL);
}