2 #include "AudioConfig.h"
5 #include "HttpChunkReader.h"
6 #include "HttpHeader.h"
9 #include "AudioLogger.h"
11 #define CHUNK_SIZE 1024
36 void setClient(
Client &client) {
37 this->client_ptr = &client;
38 this->client_ptr->setTimeout(clientTimeout);
43 void setHost(
const char *host) {
44 LOGI(
"setHost %s", host);
45 this->host_name = host;
48 operator bool() {
return client_ptr !=
nullptr ? (bool)*client_ptr :
false; }
50 virtual bool connected() {
51 return client_ptr ==
nullptr ? false : client_ptr->connected();
54 virtual int available()
override {
55 if (reply_header.isChunked()) {
56 return chunk_reader.available();
58 return client_ptr !=
nullptr ? client_ptr->available() : 0;
65 if (is_chunked_output_active) {
66 client_ptr->println(0, HEX);
67 client_ptr->println();
69 is_chunked_output_active =
false;
81 virtual int post(
Url &url,
const char *mime,
const char *data,
int len = -1) {
82 LOGI(
"post %s", url.url());
83 return process(POST, url, mime, data, len);
87 virtual int post(
Url &url,
const char *mime,
Stream &data,
int len = -1) {
88 LOGI(
"post %s", url.url());
89 return process(POST, url, mime, data, len);
93 virtual int put(
Url &url,
const char *mime,
const char *data,
int len = -1) {
94 LOGI(
"put %s", url.url());
95 return process(PUT, url, mime, data, len);
99 virtual int put(
Url &url,
const char *mime,
Stream &data,
int len = -1) {
100 LOGI(
"put %s", url.url());
101 return process(PUT, url, mime, data, len);
105 virtual int del(
Url &url,
const char *mime =
nullptr,
106 const char *data =
nullptr,
int len = -1) {
107 LOGI(
"del %s", url.url());
108 return process(DELETE, url, mime, data, len);
112 virtual int get(
Url &url,
const char *acceptMime =
nullptr,
113 const char *data =
nullptr,
int len = -1) {
114 LOGI(
"get %s", url.url());
115 this->accept = acceptMime;
116 return process(GET, url,
nullptr, data, len);
120 virtual int head(
Url &url,
const char *acceptMime =
nullptr,
121 const char *data =
nullptr,
int len = -1) {
122 LOGI(
"head %s", url.url());
123 this->accept = acceptMime;
124 return process(HEAD, url,
nullptr, data, len);
128 virtual int read(uint8_t *str,
int len) {
130 if (reply_header.isChunked()) {
131 return chunk_reader.read(*client_ptr, str, len);
133 return client_ptr->read(str, len);
137 size_t readBytes(uint8_t *str,
size_t len)
override {
138 return read(str, len);
141 size_t readBytesUntil(
char terminator,
char *buffer,
size_t length) {
143 return client_ptr->readBytesUntil(terminator, buffer, length);
148 virtual int readln(uint8_t *str,
int len,
bool incl_nl =
true) {
150 if (reply_header.isChunked()) {
151 return chunk_reader.readln(*client_ptr, str, len);
153 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
158 virtual HttpReplyHeader &reply() {
return reply_header; }
164 virtual void setAgent(
const char *agent) { this->agent = agent; }
166 virtual void setConnection(
const char *connection) {
167 this->connection = connection;
170 virtual void setAcceptsEncoding(
const char *enc) {
171 this->accept_encoding = enc;
174 virtual void setAcceptMime(
const char *mime) { this->accept = mime; }
176 size_t contentLength() {
177 const char *len_str = reply().get(CONTENT_LENGTH);
179 if (len_str !=
nullptr) {
182 LOGI(
"no CONTENT_LENGTH found in reply");
193 request_header.put(
header, value);
196 Client &client() {
return *client_ptr; }
199 virtual int process(MethodID action, Url &url,
const char *mime,
200 const char *data,
int lenData = -1) {
202 if (data !=
nullptr && len <= 0) {
207 if (len > 0 && data !=
nullptr) {
208 LOGI(
"Writing data: %d bytes", len);
209 client_ptr->write((
const uint8_t *)data, len);
216 virtual int process(MethodID action, Url &url,
const char *mime,
217 Stream &stream,
int len = -1) {
230 if (client_ptr ==
nullptr) {
231 LOGE(
"The client has not been defined");
234 if (http_connect_callback) {
235 http_connect_callback(*
this, url, request_header);
237 if (!this->connected()) {
238 LOGI(
"process connecting to host %s port %d", url.host(), url.port());
239 int is_connected = connect(url.host(), url.port(), clientTimeout);
241 LOGE(
"Connect failed");
245 LOGI(
"process is already connected");
248 #if defined(ESP32) && defined(ARDUINO)
249 LOGI(
"Free heap: %u", (
unsigned)ESP.getFreeHeap());
252 reply_header.setProcessed();
254 host_name = url.host();
255 request_header.setValues(action, url.path());
257 request_header.put(CONTENT_LENGTH, lenData);
259 request_header.put(HOST_C, host_name);
260 request_header.put(CONNECTION, connection);
261 request_header.put(USER_AGENT, agent);
262 request_header.put(ACCEPT_ENCODING, accept_encoding);
263 request_header.put(ACCEPT, accept);
264 request_header.put(CONTENT_TYPE, mime);
265 request_header.
write(*client_ptr);
272 uint8_t buffer[CHUNK_SIZE];
274 int total_written = 0;
275 while (*client_ptr && stream.available() > 0) {
276 int result_len = stream.readBytes(buffer, CHUNK_SIZE);
278 int written =
write(buffer, result_len);
279 total_written += written;
280 LOGI(
"--> Bytes read %d vs written %d", result_len, written);
284 LOGI(
"Total bytes read %d vs written %d", total, total_written);
289 size_t write(
const uint8_t *data,
size_t len)
override {
294 is_chunked_output_active =
true;
295 client_ptr->println(len, HEX);
296 result = client_ptr->write(data, len);
297 client_ptr->println();
300 result = client_ptr->write(data, len);
310 if (is_chunked_output_active) client_ptr->println(0, HEX);
311 client_ptr->println();
312 is_chunked_output_active =
false;
314 LOGI(
"Request written ... waiting for reply");
317 reply_header.
read(*client_ptr);
320 if (reply_header.isChunked()) {
321 chunk_reader.open(*client_ptr);
326 return reply_header.statusCode();
332 http_connect_callback = callback;
336 void setTimeout(
int timeoutMs) { clientTimeout = timeoutMs; }
342 Client *client_ptr =
nullptr;
347 const char *agent =
nullptr;
348 const char *host_name =
nullptr;
349 const char *connection = CON_KEEP_ALIVE;
350 const char *accept = ACCEPT_ALL;
351 const char *accept_encoding = IDENTITY;
352 bool is_ready =
false;
353 int32_t clientTimeout = URL_CLIENT_TIMEOUT;
356 bool is_chunked_output_active =
false;
359 virtual int connect(
const char *ip, uint16_t port, int32_t timeout) {
361 client_ptr->setTimeout(timeout / 1000);
364 int is_connected = this->client_ptr->connect(ip, port);
365 LOGI(
"is connected %s with timeout %d", is_connected ?
"true" :
"false", (
int)timeout);
void stop()
Public generic methods.
Definition: AudioRuntime.h:27