2024-07-31 22:13:10 +02:00

160 lines
4.7 KiB
C

/*
http.c - HTTP request routines
File based on https://github.com/espressif/esp-idf/tree/master/examples/03_http_request
This file is part of the ESP32 Everest Run project
https://github.com/krzychb/esp32-everest-run
Copyright (c) 2016 Krzysztof Budzynski <krzychb@gazeta.pl>
This work is licensed under the Apache License, Version 2.0, January 2004
See the file LICENSE for details.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include <string.h>
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "http.h"
#define RECV_BUFFER_SIZE 64
static const char* TAG = "HTTP";
void http_client_on_connected(http_client_data *client, http_callback http_on_connected_cb)
{
client->http_connected_cb = http_on_connected_cb;
}
void http_client_on_process_chunk(http_client_data *client, http_callback http_process_chunk_cb)
{
client->http_process_chunk_cb = http_process_chunk_cb;
}
void http_client_on_disconnected(http_client_data *client, http_callback http_disconnected_cb)
{
client->http_disconnected_cb = http_disconnected_cb;
}
esp_err_t http_client_request(http_client_data *client, const char *web_server, const char *request_string)
{
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
struct in_addr *addr;
int s, r;
char recv_buf[RECV_BUFFER_SIZE];
client->recv_buf = recv_buf;
client->recv_buf_size = sizeof(recv_buf);
int err = getaddrinfo(web_server, "80", &hints, &res);
if (err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
return ESP_ERR_HTTP_DNS_LOOKUP_FAILED;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code
*/
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));
s = socket(res->ai_family, res->ai_socktype, 0);
if (s < 0) {
ESP_LOGE(TAG, "... Failed to allocate socket.");
freeaddrinfo(res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
return ESP_ERR_HTTP_FAILED_TO_ALLOCATE_SOCKET;
}
ESP_LOGI(TAG, "... allocated socket");
if (connect(s, res->ai_addr, res->ai_addrlen) != 0) {
ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
close(s);
freeaddrinfo(res);
vTaskDelay(4000 / portTICK_PERIOD_MS);
return ESP_ERR_HTTP_SOCKET_CONNECT_FAILED;
}
ESP_LOGI(TAG, "... connected");
freeaddrinfo(res);
if (client->http_connected_cb) {
client->http_connected_cb((uint32_t*) client);
}
if (write(s, request_string, strlen(request_string)) < 0) {
ESP_LOGE(TAG, "... socket send failed");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
return ESP_ERR_HTTP_SOCKET_SEND_FAILED;
}
ESP_LOGI(TAG, "... socket send success");
/* Read HTTP response */
do {
bzero(recv_buf, sizeof(recv_buf));
r = read(s, recv_buf, sizeof(recv_buf)-1);
if (client->http_process_chunk_cb) {
client->http_process_chunk_cb((uint32_t*) client);
}
} while (r > 0);
ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d", r, errno);
close(s);
if (client->http_disconnected_cb) {
client->http_disconnected_cb((uint32_t*) client);
}
return ESP_OK;
}
/* Out of HTTP response return pointer to response body
Function return NULL if end of header cannot be identified
*/
const char* find_response_body(char * response)
{
// Identify end of the response headers
// http://stackoverflow.com/questions/11254037/how-to-know-when-the-http-headers-part-is-ended
char * eol; // end of line
char * bol; // beginning of line
bool nheaderfound = false; // end of response headers has been found
bol = response;
while ((eol = index(bol, '\n')) != NULL) {
// update bol based upon the value of eol
bol = eol + 1;
// test if end of headers has been reached
if ( (!(strncmp(bol, "\r\n", 2))) || (!(strncmp(bol, "\n", 1))) )
{
// note that end of headers has been found
nheaderfound = true;
// update the value of bol to reflect the beginning of the line
// immediately after the headers
if (bol[0] != '\n') {
bol += 1;
}
bol += 1;
break;
}
}
if (nheaderfound) {
return bol;
} else {
return NULL;
}
}