http.c 4.66 KB
Newer Older
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
#include <esp_http_client.h>
#include <esp_log.h>
#include <esp_tls.h>
#include "http.h"
#include "config.h"
#include "wifi.h"

/**
 * @brief Input buffer
 */
static char* _buffer = NULL;

/**
 * @brief Input buffer size
 */
static int _buffer_bytes_written = 0;

static const char* TAG = "DOOR HTTP MODULE";

static esp_http_client_handle_t _client = NULL;

void door_http_free_buffer(void)
{
	free(_buffer);
	_buffer = NULL;
	_buffer_bytes_written = 0;
}

/**
 * This function assumes that only one request is placed at a time.
 * This is fine currently as I am using blocking calls to get data,
 * but if this is ever changed the way this function works will also
 * need to be changed.
 *
 * @brief Event handler for the ESP http event handler
 * @return
 */
static esp_err_t _http_event_handler(esp_http_client_event_t* evt)
{
	switch (evt->event_id)
	{
	case HTTP_EVENT_ERROR:
		ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
		break;
	case HTTP_EVENT_ON_CONNECTED:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
		break;
	case HTTP_EVENT_HEADER_SENT:
		ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
		break;
	case HTTP_EVENT_ON_HEADER:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
		break;
	case HTTP_EVENT_ON_DATA:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
		ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, data: %.*s", evt->data_len, (char*)evt->data);
		// If user_data buffer is configured, copy the response into the buffer
		if (!esp_http_client_is_chunked_response(evt->client)) {
			if (evt->user_data)
			{
				memcpy(evt->user_data + _buffer_bytes_written, evt->data, evt->data_len);
			}
			else
			{
				if (!_buffer)
				{
					int content_length = esp_http_client_get_content_length(evt->client);
					ESP_LOGI(TAG, "Allocating %d bytes for buffer", content_length);
					_buffer = (char*)malloc(content_length);
					_buffer_bytes_written = 0;
					if (!_buffer && content_length != 0)
					{
						ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
						return ESP_FAIL;
					}
				}
			}
		} else {
			// create new buffer with adequate size.
			char* new_buffer = (char*)malloc(_buffer_bytes_written + evt->data_len);
			if (!new_buffer) {
				ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
				return ESP_FAIL;
			}
			memcpy(new_buffer, _buffer, _buffer_bytes_written);
			free(_buffer);
			_buffer = new_buffer;
		}
		memcpy(_buffer + _buffer_bytes_written, evt->data, evt->data_len);
		_buffer_bytes_written += evt->data_len;
		break;
	case HTTP_EVENT_ON_FINISH:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
		break;
	case HTTP_EVENT_DISCONNECTED:
		ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
		int mbedtls_err = 0;
		esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
		if (err != 0)
		{
			if (_buffer != NULL)
				door_http_free_buffer();
			ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
			ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
		}
		break;
	default:
		break;
	}

	return ESP_OK;
}

extern const char _door_root_cert_pem_start[] asm("_binary_doorcode_root_cert_pem_start");

static esp_http_client_config_t _http_base_config = {
	.event_handler = _http_event_handler,
	.host = API_HOST,
	.port = API_PORT,
	.path = API_BASE_PATH,
#ifdef API_USE_SSL
	.transport_type = HTTP_TRANSPORT_OVER_SSL,
#ifdef API_NO_NAME_VERIFY
	.skip_cert_common_name_check = false,
#endif
#else
	.transport_type = HTTP_TRANSPORT_OVER_TCP,
#endif
};

int door_http_init(void)
{
	if (_client)
		return DOOR_HTTP_ERR_SUCCESS;

	if (!door_wifi_is_connected()) {
		ESP_LOGE(TAG, "Not connected to wifi.");
		return DOOR_HTTP_ERR_FAIL;
	}

	_http_base_config.cert_pem = _door_root_cert_pem_start;
	_client = esp_http_client_init(&_http_base_config);
	if (!_client)
	{
		ESP_LOGE(TAG, "Failed to initialize the esp http client");
		return DOOR_HTTP_ERR_FAIL;
	}
	return DOOR_HTTP_ERR_SUCCESS;
}

void door_http_destroy(void)
{
	door_http_free_buffer();
	esp_http_client_cleanup(_client);
	_client = NULL;
}

int door_http_get(const char* path, char** buffer, int* buffer_len)
{
	ESP_LOGI(TAG, "DOOR_HTTP_SET: sending GET request to: %s", path);
	if (!door_wifi_is_connected() || !_client) {
		ESP_LOGI(TAG, "Not connected to wifi or client in call to get");
		return DOOR_HTTP_ERR_FAIL;
	}

	esp_http_client_set_url(_client, path);
	esp_http_client_set_method(_client, HTTP_METHOD_GET);
	esp_http_client_perform(_client);

	if (buffer)
		*buffer = _buffer;
	if (buffer_len)
		*buffer_len = _buffer_bytes_written;

	ESP_LOGI(TAG, "Total data retrieved from response: %.*s", _buffer_bytes_written, _buffer);

	int status_code = esp_http_client_get_status_code(_client);
	ESP_LOGI(TAG, "Status code from get call: %d", status_code);
	return status_code;
}