3#include "AudioConfig.h"
4#include "HttpChunkReader.h"
8#include "AudioLogger.h"
10#define CHUNK_SIZE 1024
35 void setClient(
Client &client) {
36 this->client_ptr = &client;
37 this->client_ptr->setTimeout(clientTimeout);
42 void setHost(
const char *host) {
43 LOGI(
"setHost %s", host);
44 this->host_name = host;
47 operator bool() {
return client_ptr !=
nullptr ? (
bool)*client_ptr :
false; }
49 virtual bool connected() {
50 return client_ptr ==
nullptr ?
false : client_ptr->connected();
53 virtual int available()
override {
54 if (reply_header.isChunked()) {
55 return chunk_reader.available();
57 return client_ptr !=
nullptr ? client_ptr->available() : 0;
64 if (is_chunked_output_active) {
65 client_ptr->println(0, HEX);
66 client_ptr->println();
68 is_chunked_output_active =
false;
80 virtual int post(
Url &url,
const char *mime,
const char *data,
int len = -1) {
81 LOGI(
"post %s", url.url());
82 return process(POST, url, mime, data, len);
80 virtual int post(
Url &url,
const char *mime,
const char *data,
int len = -1) {
…}
86 virtual int post(
Url &url,
const char *mime,
Stream &data,
int len = -1) {
87 LOGI(
"post %s", url.url());
88 return process(POST, url, mime, data, len);
92 virtual int put(
Url &url,
const char *mime,
const char *data,
int len = -1) {
93 LOGI(
"put %s", url.url());
94 return process(PUT, url, mime, data, len);
92 virtual int put(
Url &url,
const char *mime,
const char *data,
int len = -1) {
…}
98 virtual int put(
Url &url,
const char *mime,
Stream &data,
int len = -1) {
99 LOGI(
"put %s", url.url());
100 return process(PUT, url, mime, data, len);
98 virtual int put(
Url &url,
const char *mime,
Stream &data,
int len = -1) {
…}
104 virtual int del(
Url &url,
const char *mime =
nullptr,
105 const char *data =
nullptr,
int len = -1) {
106 LOGI(
"del %s", url.url());
107 return process(DELETE, url, mime, data, len);
104 virtual int del(
Url &url,
const char *mime =
nullptr, {
…}
112 const char *data =
nullptr,
int len = -1) {
113 LOGI(
"get %s", url.url());
115 return process(GET, url,
nullptr, data, len);
120 const char *data =
nullptr,
int len = -1) {
121 LOGI(
"head %s", url.url());
123 return process(HEAD, url,
nullptr, data, len);
127 virtual int read(
uint8_t *str,
int len) {
129 if (reply_header.isChunked()) {
130 return chunk_reader.read(*client_ptr, str, len);
132 return client_ptr->read(str, len);
136 size_t readBytes(uint8_t *str,
size_t len)
override {
137 return read(str, len);
140 size_t readBytesUntil(
char terminator,
char *buffer,
size_t length) {
142 return client_ptr->readBytesUntil(terminator, buffer, length);
147 virtual int readln(uint8_t *str,
int len,
bool incl_nl =
true) {
149 if (reply_header.isChunked()) {
150 return chunk_reader.readln(*client_ptr, str, len);
152 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
157 virtual HttpReplyHeader &reply() {
return reply_header; }
163 virtual void setAgent(
const char *agent) { this->agent = agent; }
165 virtual void setConnection(
const char *connection) {
166 this->connection = connection;
169 virtual void setAcceptsEncoding(
const char *enc) {
170 this->accept_encoding = enc;
173 virtual void setAcceptMime(
const char *mime) { this->accept = mime; }
175 size_t contentLength() {
176 const char *len_str = reply().get(CONTENT_LENGTH);
178 if (len_str !=
nullptr) {
181 LOGI(
"no CONTENT_LENGTH found in reply");
192 request_header.put(key, value);
194 const char* getReplyHeader(
const char *key) {
195 return reply_header.get(key);
198 Client &client() {
return *client_ptr; }
201 virtual int process(MethodID action, Url &url,
const char *mime,
202 const char *data,
int lenData = -1) {
204 if (data !=
nullptr && len <= 0) {
209 if (len > 0 && data !=
nullptr) {
210 LOGI(
"Writing data: %d bytes", len);
211 client_ptr->write((
const uint8_t *)data, len);
218 virtual int process(MethodID action, Url &url,
const char *mime,
219 Stream &stream,
int len = -1) {
232 if (client_ptr ==
nullptr) {
233 LOGE(
"The client has not been defined");
236 if (http_connect_callback) {
237 http_connect_callback(*
this, url, request_header);
239 if (!this->connected()) {
240 LOGI(
"process connecting to host %s port %d", url.host(), url.port());
241 int is_connected = connect(url.host(), url.port(), clientTimeout);
243 LOGE(
"Connect failed");
247 LOGI(
"process is already connected");
250#if defined(ESP32) && defined(ARDUINO)
251 LOGI(
"Free heap: %u", (
unsigned)
ESP.getFreeHeap());
254 reply_header.setProcessed();
256 host_name = url.host();
257 request_header.setValues(
action, url.path());
259 request_header.put(CONTENT_LENGTH,
lenData);
261 request_header.put(HOST_C, host_name);
262 request_header.put(CONNECTION, connection);
263 request_header.put(USER_AGENT, agent);
264 request_header.put(ACCEPT_ENCODING, accept_encoding);
265 request_header.put(ACCEPT, accept);
266 request_header.put(CONTENT_TYPE, mime);
267 request_header.
write(*client_ptr);
276 int total_written = 0;
277 while (*client_ptr && stream.available() > 0) {
278 int result_len = stream.readBytes(buffer, CHUNK_SIZE);
281 total_written += written;
282 LOGI(
"--> Bytes read %d vs written %d",
result_len, written);
286 LOGI(
"Total bytes read %d vs written %d", total, total_written);
296 is_chunked_output_active =
true;
297 client_ptr->println(len, HEX);
298 result = client_ptr->write(data, len);
299 client_ptr->println();
302 result = client_ptr->write(data, len);
312 if (is_chunked_output_active) client_ptr->println(0, HEX);
313 client_ptr->println();
314 is_chunked_output_active =
false;
316 LOGI(
"Request written ... waiting for reply");
319 reply_header.
read(*client_ptr);
322 if (reply_header.isChunked()) {
323 chunk_reader.open(*client_ptr);
328 return reply_header.statusCode();
334 http_connect_callback = callback;
344 Client *client_ptr =
nullptr;
349 const char *agent =
nullptr;
350 const char *host_name =
nullptr;
351 const char *connection = CON_KEEP_ALIVE;
352 const char *accept = ACCEPT_ALL;
353 const char *accept_encoding = IDENTITY;
354 bool is_ready =
false;
355 int32_t clientTimeout = URL_CLIENT_TIMEOUT;
358 bool is_chunked_output_active =
false;
363 client_ptr->setTimeout(timeout / 1000);
367 LOGI(
"is connected %s with timeout %d",
is_connected ?
"true" :
"false", (
int)timeout);