arduino-audio-tools
Loading...
Searching...
No Matches
HttpRequest.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioToolsConfig.h"
4#include "HttpChunkReader.h"
5#include "HttpHeader.h"
6#include "HttpTypes.h"
7#include "Url.h"
8#include "AudioLogger.h"
9
10#define CHUNK_SIZE 1024
11
12namespace audio_tools {
13
25class HttpRequest : public BaseStream {
26 public:
27// friend class URLStream;
28
32
34
36
38 this->client_ptr = &client;
39 this->client_ptr->setTimeout(client_timeout);
40
41 }
42
43 // the requests usually need a host. This needs to be set if we did not
44 // provide a URL
45 void setHost(const char *host) {
46 LOGI("setHost %s", host);
47 this->host_name = host;
48 }
49
50 operator bool() { return client_ptr != nullptr ? (bool)*client_ptr : false; }
51
52 virtual bool connected() {
53 return client_ptr == nullptr ? false : client_ptr->connected();
54 }
55
56 int available() override {
57 if (reply_header.isChunked()) {
58 return chunk_reader.available();
59 }
60 return client_ptr != nullptr ? client_ptr->available() : 0;
61 }
62
64 void end() override {
65 if (connected()) {
66 // write final 0 chunk if necessary
68 client_ptr->println(0, HEX);
69 client_ptr->println();
72 }
73 LOGI("stop");
75 }
76 }
77
78 virtual void stop() {
79 end();
80 }
81
83 virtual int post(Url &url, const char *mime, const char *data, int len = -1) {
84 LOGI("post %s", url.url());
85 return process(POST, url, mime, data, len);
86 }
87
89 virtual int post(Url &url, const char *mime, Stream &data, int len = -1) {
90 LOGI("post %s", url.url());
91 return process(POST, url, mime, data, len);
92 }
93
95 virtual int put(Url &url, const char *mime, const char *data, int len = -1) {
96 LOGI("put %s", url.url());
97 return process(PUT, url, mime, data, len);
98 }
99
101 virtual int put(Url &url, const char *mime, Stream &data, int len = -1) {
102 LOGI("put %s", url.url());
103 return process(PUT, url, mime, data, len);
104 }
105
107 virtual int del(Url &url, const char *mime = nullptr,
108 const char *data = nullptr, int len = -1) {
109 LOGI("del %s", url.url());
110 return process(DELETE, url, mime, data, len);
111 }
112
114 virtual int get(Url &url, const char *acceptMime = nullptr,
115 const char *data = nullptr, int len = -1) {
116 LOGI("get %s", url.url());
117 this->accept = acceptMime;
118 return process(GET, url, nullptr, data, len);
119 }
120
122 virtual int head(Url &url, const char *acceptMime = nullptr,
123 const char *data = nullptr, int len = -1) {
124 LOGI("head %s", url.url());
125 this->accept = acceptMime;
126 return process(HEAD, url, nullptr, data, len);
127 }
128
129 // reads the reply data
130 virtual int read(uint8_t *str, int len) {
131 TRACED();
132 if (reply_header.isChunked()) {
133 return chunk_reader.read(*client_ptr, str, len);
134 } else {
135 return client_ptr->read(str, len);
136 }
137 }
138
139 size_t readBytes(uint8_t *str, size_t len) override {
140 int result = read(str, len);
141 if ( result < 0) {
142 LOGE("HttpRequest::read error");
143 return 0;
144 }
145 return result;
146 }
147
148 size_t readBytesUntil(char terminator, char *buffer, size_t length) {
149 TRACED();
150 return client_ptr->readBytesUntil(terminator, buffer, length);
151 }
152
153 // read the reply data up to the next new line. For Chunked data we provide
154 // the full chunk!
155 virtual int readln(uint8_t *str, int len, bool incl_nl = true) {
156 TRACED();
157 if (reply_header.isChunked()) {
158 return chunk_reader.readln(*client_ptr, str, len);
159 } else {
160 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
161 }
162 }
163
164 // provides the head information of the reply
165 virtual HttpReplyHeader &reply() { return reply_header; }
166
169
171 virtual void setAgent(const char *agent) { this->agent = agent; }
172
173 virtual void setConnection(const char *connection) {
174 this->connection = connection;
175 }
176
177 virtual void setAcceptsEncoding(const char *enc) {
178 this->accept_encoding = enc;
179 }
180
181 virtual void setAcceptMime(const char *mime) { this->accept = mime; }
182
183 size_t contentLength() {
184 const char *len_str = reply().get(CONTENT_LENGTH);
185 int len = 0;
186 if (len_str != nullptr) {
187 len = atoi(len_str);
188 } else {
189 LOGI("no CONTENT_LENGTH found in reply");
190 }
191 return len;
192 }
193
196 bool isReady() { return is_ready; }
197
199 void addRequestHeader(const char *key, const char *value) {
200 request_header.put(key, value);
201 }
202 const char* getReplyHeader(const char *key) {
203 return reply_header.get(key);
204 }
205
206 Client &client() { return *client_ptr; }
207
208 // process http request and reads the reply_header from the server
209 virtual int process(MethodID action, Url &url, const char *mime,
210 const char *data, int lenData = -1) {
211 int len = lenData;
212 if (data != nullptr && len <= 0) {
213 len = strlen(data);
214 }
215 processBegin(action, url, mime, len);
216 // posting data parameter
217 if (len > 0 && data != nullptr) {
218 LOGI("Writing data: %d bytes", len);
219 client_ptr->write((const uint8_t *)data, len);
220 LOGD("%s", data);
221 }
222 return processEnd();
223 }
224
225 // process http request and reads the reply_header from the server
226 virtual int process(MethodID action, Url &url, const char *mime,
227 Stream &stream, int len = -1) {
228 if (!processBegin(action, url, mime, len))
229 return -1;
230 processWrite(stream);
231 return processEnd();
232 }
233
235 virtual bool processBegin(MethodID action, Url &url, const char *mime,
236 int lenData = -1) {
237 TRACED();
238 int len = lenData;
239 is_ready = false;
240 if (client_ptr == nullptr) {
241 LOGE("The client has not been defined");
242 return false;
243 }
246 }
247 if (!this->connected()) {
248 LOGI("process connecting to host %s port %d", url.host(), url.port());
250 if (!is_connected) {
251 LOGE("Connect failed");
252 return false;
253 }
254 } else {
255 LOGI("process is already connected");
256 }
257
258#if defined(ESP32) && defined(ARDUINO)
259 LOGI("Free heap: %u", (unsigned)ESP.getFreeHeap());
260#endif
261
263
264 host_name = url.host();
266 if (lenData > 0) {
268 }
276
277 return true;
278 }
279
281 virtual void processWrite(Stream &stream) {
282 uint8_t buffer[CHUNK_SIZE];
283 int total = 0;
284 int total_written = 0;
285 while (*client_ptr && stream.available() > 0) {
286 int result_len = stream.readBytes(buffer, CHUNK_SIZE);
287 total += result_len;
288 int written = write(buffer, result_len);
289 total_written += written;
290 LOGI("--> Bytes read %d vs written %d", result_len, written);
291 delay(1);
292 }
293 client_ptr->flush();
294 LOGI("Total bytes read %d vs written %d", total, total_written);
295 }
296
299 size_t write(const uint8_t *data, size_t len) override {
300 TRACED();
301 size_t result = 0;
302 if (isChunked()) {
303 if (len > 0) {
305 client_ptr->println(len, HEX);
306 result = client_ptr->write(data, len);
307 client_ptr->println();
308 }
309 } else {
310 result = client_ptr->write(data, len);
311 }
312 return result;
313 }
314
316 virtual int processEnd() {
317 TRACED();
318 // if sending is chunked we terminate with an empty chunk
319 if (isChunked()) {
320 if (is_chunked_output_active) client_ptr->println(0, HEX);
321 client_ptr->println();
323 }
324 LOGI("Request written ... waiting for reply");
325 // Commented out because this breaks the RP2040 W
326 // client_ptr->flush();
328
329 // if we use chunked tranfer we need to read the first chunked length
330 if (reply_header.isChunked()) {
332 LOGE("HttpRequest: Failed to open chunked reader");
333 return -1;
334 }
335 }
336
337 // wait for data
338 is_ready = true;
339 return reply_header.statusCode();
340 }
341
343 void setOnConnectCallback(void (*callback)(
345 http_connect_callback = callback;
346 }
347
349 void setTimeout(size_t timeoutMs) {
352 if(client_ptr != nullptr){
353 client_ptr->setTimeout(timeoutMs);
354 }
355 }
356
358 bool isChunked() { return request_header.isChunked(); }
359
360 protected:
361 Client *client_ptr = nullptr;
366 const char *agent = nullptr;
367 const char *host_name = nullptr;
369 const char *accept = ACCEPT_ALL;
371 bool is_ready = false;
376
377 // opens a connection to the indicated host
378 virtual int connect(const char *ip, uint16_t port, int32_t timeout) {
379 TRACED();
380 client_ptr->setTimeout(timeout);
381 request_header.setTimeout(timeout);
382 reply_header.setTimeout(timeout);
383 int is_connected = this->client_ptr->connect(ip, port);
384 LOGI("is connected %s with timeout %d", is_connected ? "true" : "false", (int)timeout);
385 return is_connected;
386 }
387};
388
389} // namespace audio_tools
390
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define CHUNK_SIZE
Definition HttpRequest.h:10
MethodID
supported http methods
Definition HttpTypes.h:3
@ HEAD
Definition HttpTypes.h:6
@ GET
Definition HttpTypes.h:5
@ POST
Definition HttpTypes.h:7
@ DELETE
Definition HttpTypes.h:9
@ PUT
Definition HttpTypes.h:8
@ HEX
Definition NoArduino.h:58
Base class for all Streams. It relies on write(const uint8_t *buffer, size_t size) and readBytes(uint...
Definition BaseStream.h:36
Definition NoArduino.h:169
bool connect(const char *ip, int port)
Definition NoArduino.h:175
bool connected()
Definition NoArduino.h:174
virtual int read(uint8_t *buffer, size_t len)
Definition NoArduino.h:172
void stop()
Definition NoArduino.h:171
Http might reply with chunks. So we need to dechunk the data. see https://en.wikipedia....
Definition HttpChunkReader.h:14
void setTimeout(int timeoutMs)
Timout is just used for logging.
Definition HttpChunkReader.h:101
int readln(Client &client, uint8_t *str, int len, bool incl_nl=true)
reads a single line from the chunks
Definition HttpChunkReader.h:71
int available()
returns the number of bytes which are still available in the current chunk
Definition HttpChunkReader.h:94
bool open(Client &client)
opens the chunk reader and reads the first chunk length
Definition HttpChunkReader.h:30
int read(Client &client, uint8_t *str, int len)
reads a block of data from the chunks
Definition HttpChunkReader.h:37
void setTimeout(int timeoutMs)
Set the timout.
Definition HttpHeader.h:303
bool isChunked()
Definition HttpHeader.h:210
void setProcessed()
Definition HttpHeader.h:282
int statusCode()
Definition HttpHeader.h:206
HttpHeader & put(const char *key, const char *value)
Definition HttpHeader.h:86
void write(Client &out)
writes the full header to the indicated HttpStreamedMultiOutput stream
Definition HttpHeader.h:270
bool read(Client &in)
reads the full header from the request (stream)
Definition HttpHeader.h:216
const char * get(const char *key)
Definition HttpHeader.h:151
virtual int readlnInternal(Stream &client, uint8_t *str, int len, bool incl_nl=true)
Definition HttpLineReader.h:21
Reading and Writing of Http Replys.
Definition HttpHeader.h:453
Reading and writing of Http Requests.
Definition HttpHeader.h:394
HttpHeader & setValues(MethodID id, const char *urlPath, const char *protocol=nullptr)
Definition HttpHeader.h:397
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition HttpRequest.h:25
virtual void setAcceptsEncoding(const char *enc)
Definition HttpRequest.h:177
virtual bool connected()
Definition HttpRequest.h:52
bool isChunked()
we are sending the data chunked
Definition HttpRequest.h:358
void setTimeout(size_t timeoutMs)
Defines the client timeout in ms.
Definition HttpRequest.h:349
virtual int post(Url &url, const char *mime, Stream &data, int len=-1)
http post
Definition HttpRequest.h:89
virtual HttpReplyHeader & reply()
Definition HttpRequest.h:165
void addRequestHeader(const char *key, const char *value)
Adds/Updates a request header.
Definition HttpRequest.h:199
virtual int connect(const char *ip, uint16_t port, int32_t timeout)
Definition HttpRequest.h:378
virtual int get(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1)
http get
Definition HttpRequest.h:114
virtual int processEnd()
Ends the http request processing and returns the status code or -1 on error.
Definition HttpRequest.h:316
~HttpRequest()
Definition HttpRequest.h:33
bool is_chunked_output_active
Definition HttpRequest.h:375
bool is_ready
Definition HttpRequest.h:371
HttpRequestHeader request_header
Definition HttpRequest.h:363
virtual int put(Url &url, const char *mime, const char *data, int len=-1)
http put
Definition HttpRequest.h:95
size_t readBytes(uint8_t *str, size_t len) override
Definition HttpRequest.h:139
const char * connection
Definition HttpRequest.h:368
const char * agent
Definition HttpRequest.h:366
virtual int process(MethodID action, Url &url, const char *mime, const char *data, int lenData=-1)
Definition HttpRequest.h:209
size_t contentLength()
Definition HttpRequest.h:183
virtual void processWrite(Stream &stream)
Writes (Posts) the data of the indicated stream after calling processBegin.
Definition HttpRequest.h:281
virtual void setAgent(const char *agent)
Defines the agent.
Definition HttpRequest.h:171
virtual int readln(uint8_t *str, int len, bool incl_nl=true)
Definition HttpRequest.h:155
void end() override
same as end()
Definition HttpRequest.h:64
int available() override
Definition HttpRequest.h:56
void(* http_connect_callback)(HttpRequest &request, Url &url, HttpRequestHeader &request_header)
Definition HttpRequest.h:373
virtual int process(MethodID action, Url &url, const char *mime, Stream &stream, int len=-1)
Definition HttpRequest.h:226
size_t write(const uint8_t *data, size_t len) override
Definition HttpRequest.h:299
HttpRequest()
Definition HttpRequest.h:29
int client_timeout
Definition HttpRequest.h:372
virtual bool processBegin(MethodID action, Url &url, const char *mime, int lenData=-1)
starts http request processing
Definition HttpRequest.h:235
Url url
Definition HttpRequest.h:362
Client * client_ptr
Definition HttpRequest.h:361
virtual void setConnection(const char *connection)
Definition HttpRequest.h:173
virtual int put(Url &url, const char *mime, Stream &data, int len=-1)
http put
Definition HttpRequest.h:101
size_t readBytesUntil(char terminator, char *buffer, size_t length)
Definition HttpRequest.h:148
const char * accept_encoding
Definition HttpRequest.h:370
HttpRequest(Client &client)
Definition HttpRequest.h:35
void setClient(Client &client)
Definition HttpRequest.h:37
virtual int head(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1)
http head
Definition HttpRequest.h:122
Client & client()
Definition HttpRequest.h:206
HttpChunkReader chunk_reader
Definition HttpRequest.h:365
virtual int post(Url &url, const char *mime, const char *data, int len=-1)
http post
Definition HttpRequest.h:83
void setOnConnectCallback(void(*callback)(HttpRequest &request, Url &url, HttpRequestHeader &request_header))
Callback which allows you to add additional paramters dynamically.
Definition HttpRequest.h:343
virtual int read(uint8_t *str, int len)
Definition HttpRequest.h:130
bool isReady()
Definition HttpRequest.h:196
const char * host_name
Definition HttpRequest.h:367
virtual void stop()
Definition HttpRequest.h:78
virtual HttpRequestHeader & header()
provides access to the request header
Definition HttpRequest.h:168
const char * getReplyHeader(const char *key)
Definition HttpRequest.h:202
virtual int del(Url &url, const char *mime=nullptr, const char *data=nullptr, int len=-1)
http del
Definition HttpRequest.h:107
const char * accept
Definition HttpRequest.h:369
HttpReplyHeader reply_header
Definition HttpRequest.h:364
void setHost(const char *host)
Definition HttpRequest.h:45
virtual void setAcceptMime(const char *mime)
Definition HttpRequest.h:181
virtual size_t write(const uint8_t *data, size_t len)
Definition NoArduino.h:126
virtual void flush()
Definition NoArduino.h:136
Definition NoArduino.h:142
virtual size_t readBytes(uint8_t *data, size_t len)
Definition NoArduino.h:147
virtual int available()
Definition NoArduino.h:146
URL parser which breaks a full url string up into its individual parts.
Definition Url.h:22
int port()
Definition Url.h:40
const char * url()
Definition Url.h:33
const char * path()
Definition Url.h:34
const char * host()
Definition Url.h:35
#define URL_CLIENT_TIMEOUT
Definition esp8266.h:23
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
static const char * IDENTITY
Definition HttpHeader.h:31
static const char * USER_AGENT
Definition HttpHeader.h:26
void delay(unsigned long ms)
Definition Time.h:23
static const char * CONTENT_LENGTH
Definition HttpHeader.h:17
static const char * ACCEPT_ENCODING
Definition HttpHeader.h:30
static const char * CON_KEEP_ALIVE
Definition HttpHeader.h:20
static const char * ACCEPT_ALL
Definition HttpHeader.h:24
static const char * CONTENT_TYPE
Definition HttpHeader.h:16
static const char * CONNECTION
Definition HttpHeader.h:18
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512
static const char * HOST_C
Definition HttpHeader.h:29
static const char * ACCEPT
Definition HttpHeader.h:23