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
29 HttpRequest() = default;
30
32
34
36 this->client_ptr = &client;
37 this->client_ptr->setTimeout(clientTimeout);
38 }
39
40 // the requests usually need a host. This needs to be set if we did not
41 // provide a URL
42 void setHost(const char *host) {
43 LOGI("setHost %s", host);
44 this->host_name = host;
45 }
46
47 operator bool() { return client_ptr != nullptr ? (bool)*client_ptr : false; }
48
49 virtual bool connected() {
50 return client_ptr == nullptr ? false : client_ptr->connected();
51 }
52
53 virtual int available() override {
54 if (reply_header.isChunked()) {
55 return chunk_reader.available();
56 }
57 return client_ptr != nullptr ? client_ptr->available() : 0;
58 }
59
61 void end() override {
62 if (connected()) {
63 // write final 0 chunk if necessary
65 client_ptr->println(0, HEX);
66 client_ptr->println();
69 }
70 LOGI("stop");
72 }
73 }
74
75 virtual void stop() {
76 end();
77 }
78
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);
83 }
84
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);
89 }
90
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);
95 }
96
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);
101 }
102
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);
108 }
109
111 virtual int get(Url &url, const char *acceptMime = nullptr,
112 const char *data = nullptr, int len = -1) {
113 LOGI("get %s", url.url());
114 this->accept = acceptMime;
115 return process(GET, url, nullptr, data, len);
116 }
117
119 virtual int head(Url &url, const char *acceptMime = nullptr,
120 const char *data = nullptr, int len = -1) {
121 LOGI("head %s", url.url());
122 this->accept = acceptMime;
123 return process(HEAD, url, nullptr, data, len);
124 }
125
126 // reads the reply data
127 virtual int read(uint8_t *str, int len) {
128 TRACED();
129 if (reply_header.isChunked()) {
130 return chunk_reader.read(*client_ptr, str, len);
131 } else {
132 return client_ptr->read(str, len);
133 }
134 }
135
136 size_t readBytes(uint8_t *str, size_t len) override {
137 return read(str, len);
138 }
139
140 size_t readBytesUntil(char terminator, char *buffer, size_t length) {
141 TRACED();
142 return client_ptr->readBytesUntil(terminator, buffer, length);
143 }
144
145 // read the reply data up to the next new line. For Chunked data we provide
146 // the full chunk!
147 virtual int readln(uint8_t *str, int len, bool incl_nl = true) {
148 TRACED();
149 if (reply_header.isChunked()) {
150 return chunk_reader.readln(*client_ptr, str, len);
151 } else {
152 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
153 }
154 }
155
156 // provides the head information of the reply
157 virtual HttpReplyHeader &reply() { return reply_header; }
158
161
163 virtual void setAgent(const char *agent) { this->agent = agent; }
164
165 virtual void setConnection(const char *connection) {
166 this->connection = connection;
167 }
168
169 virtual void setAcceptsEncoding(const char *enc) {
170 this->accept_encoding = enc;
171 }
172
173 virtual void setAcceptMime(const char *mime) { this->accept = mime; }
174
175 size_t contentLength() {
176 const char *len_str = reply().get(CONTENT_LENGTH);
177 int len = 0;
178 if (len_str != nullptr) {
179 len = atoi(len_str);
180 } else {
181 LOGI("no CONTENT_LENGTH found in reply");
182 }
183 return len;
184 }
185
188 bool isReady() { return is_ready; }
189
191 void addRequestHeader(const char *key, const char *value) {
192 request_header.put(key, value);
193 }
194 const char* getReplyHeader(const char *key) {
195 return reply_header.get(key);
196 }
197
198 Client &client() { return *client_ptr; }
199
200 // process http request and reads the reply_header from the server
201 virtual int process(MethodID action, Url &url, const char *mime,
202 const char *data, int lenData = -1) {
203 int len = lenData;
204 if (data != nullptr && len <= 0) {
205 len = strlen(data);
206 }
207 processBegin(action, url, mime, len);
208 // posting data parameter
209 if (len > 0 && data != nullptr) {
210 LOGI("Writing data: %d bytes", len);
211 client_ptr->write((const uint8_t *)data, len);
212 LOGD("%s", data);
213 }
214 return processEnd();
215 }
216
217 // process http request and reads the reply_header from the server
218 virtual int process(MethodID action, Url &url, const char *mime,
219 Stream &stream, int len = -1) {
220 if (!processBegin(action, url, mime, len))
221 return -1;
222 processWrite(stream);
223 return processEnd();
224 }
225
227 virtual bool processBegin(MethodID action, Url &url, const char *mime,
228 int lenData = -1) {
229 TRACED();
230 int len = lenData;
231 is_ready = false;
232 if (client_ptr == nullptr) {
233 LOGE("The client has not been defined");
234 return false;
235 }
238 }
239 if (!this->connected()) {
240 LOGI("process connecting to host %s port %d", url.host(), url.port());
242 if (!is_connected) {
243 LOGE("Connect failed");
244 return false;
245 }
246 } else {
247 LOGI("process is already connected");
248 }
249
250#if defined(ESP32) && defined(ARDUINO)
251 LOGI("Free heap: %u", (unsigned)ESP.getFreeHeap());
252#endif
253
255
256 host_name = url.host();
258 if (lenData > 0) {
260 }
268
269 return true;
270 }
271
273 virtual void processWrite(Stream &stream) {
274 uint8_t buffer[CHUNK_SIZE];
275 int total = 0;
276 int total_written = 0;
277 while (*client_ptr && stream.available() > 0) {
278 int result_len = stream.readBytes(buffer, CHUNK_SIZE);
279 total += result_len;
280 int written = write(buffer, result_len);
281 total_written += written;
282 LOGI("--> Bytes read %d vs written %d", result_len, written);
283 delay(1);
284 }
285 client_ptr->flush();
286 LOGI("Total bytes read %d vs written %d", total, total_written);
287 }
288
291 size_t write(const uint8_t *data, size_t len) override {
292 TRACED();
293 size_t result = 0;
294 if (isChunked()) {
295 if (len > 0) {
297 client_ptr->println(len, HEX);
298 result = client_ptr->write(data, len);
299 client_ptr->println();
300 }
301 } else {
302 result = client_ptr->write(data, len);
303 }
304 return result;
305 }
306
308 virtual int processEnd() {
309 TRACED();
310 // if sending is chunked we terminate with an empty chunk
311 if (isChunked()) {
312 if (is_chunked_output_active) client_ptr->println(0, HEX);
313 client_ptr->println();
315 }
316 LOGI("Request written ... waiting for reply");
317 // Commented out because this breaks the RP2040 W
318 // client_ptr->flush();
320
321 // if we use chunked tranfer we need to read the first chunked length
322 if (reply_header.isChunked()) {
324 };
325
326 // wait for data
327 is_ready = true;
328 return reply_header.statusCode();
329 }
330
332 void setOnConnectCallback(void (*callback)(
334 http_connect_callback = callback;
335 }
336
339
341 bool isChunked() { return request_header.isChunked(); }
342
343 protected:
344 Client *client_ptr = nullptr;
349 const char *agent = nullptr;
350 const char *host_name = nullptr;
352 const char *accept = ACCEPT_ALL;
354 bool is_ready = false;
359
360 // opens a connection to the indicated host
361 virtual int connect(const char *ip, uint16_t port, int32_t timeout) {
362 TRACED();
363 client_ptr->setTimeout(timeout / 1000); // client timeout is in seconds!
364 request_header.setTimeout(timeout);
365 reply_header.setTimeout(timeout);
366 int is_connected = this->client_ptr->connect(ip, port);
367 LOGI("is connected %s with timeout %d", is_connected ? "true" : "false", (int)timeout);
368 return is_connected;
369 }
370};
371
372} // namespace audio_tools
373
#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
virtual int readln(Client &client, uint8_t *str, int len, bool incl_nl=true)
Definition HttpChunkReader.h:56
int available()
Definition HttpChunkReader.h:74
void open(Client &client)
Definition HttpChunkReader.h:29
virtual int read(Client &client, uint8_t *str, int len)
Definition HttpChunkReader.h:36
void setTimeout(int timeoutMs)
Set the timout.
Definition HttpHeader.h:294
bool isChunked()
Definition HttpHeader.h:210
void setProcessed()
Definition HttpHeader.h:273
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:261
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:19
Reading and Writing of Http Replys.
Definition HttpHeader.h:444
Reading and writing of Http Requests.
Definition HttpHeader.h:385
HttpHeader & setValues(MethodID id, const char *urlPath, const char *protocol=nullptr)
Definition HttpHeader.h:388
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:169
virtual bool connected()
Definition HttpRequest.h:49
bool isChunked()
we are sending the data chunked
Definition HttpRequest.h:341
void setTimeout(size_t timeoutMs)
Defines the client timeout in ms.
Definition HttpRequest.h:338
virtual int post(Url &url, const char *mime, Stream &data, int len=-1)
http post
Definition HttpRequest.h:86
virtual HttpReplyHeader & reply()
Definition HttpRequest.h:157
void addRequestHeader(const char *key, const char *value)
Adds/Updates a request header.
Definition HttpRequest.h:191
virtual int connect(const char *ip, uint16_t port, int32_t timeout)
Definition HttpRequest.h:361
virtual int get(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1)
http get
Definition HttpRequest.h:111
virtual int processEnd()
Ends the http request processing and returns the status code.
Definition HttpRequest.h:308
~HttpRequest()
Definition HttpRequest.h:31
bool is_chunked_output_active
Definition HttpRequest.h:358
bool is_ready
Definition HttpRequest.h:354
HttpRequestHeader request_header
Definition HttpRequest.h:346
virtual int put(Url &url, const char *mime, const char *data, int len=-1)
http put
Definition HttpRequest.h:92
size_t readBytes(uint8_t *str, size_t len) override
Definition HttpRequest.h:136
const char * connection
Definition HttpRequest.h:351
const char * agent
Definition HttpRequest.h:349
virtual int process(MethodID action, Url &url, const char *mime, const char *data, int lenData=-1)
Definition HttpRequest.h:201
size_t contentLength()
Definition HttpRequest.h:175
virtual void processWrite(Stream &stream)
Writes (Posts) the data of the indicated stream after calling processBegin.
Definition HttpRequest.h:273
virtual void setAgent(const char *agent)
Defines the agent.
Definition HttpRequest.h:163
virtual int readln(uint8_t *str, int len, bool incl_nl=true)
Definition HttpRequest.h:147
void end() override
same as end()
Definition HttpRequest.h:61
void(* http_connect_callback)(HttpRequest &request, Url &url, HttpRequestHeader &request_header)
Definition HttpRequest.h:356
virtual int process(MethodID action, Url &url, const char *mime, Stream &stream, int len=-1)
Definition HttpRequest.h:218
size_t write(const uint8_t *data, size_t len) override
Definition HttpRequest.h:291
virtual bool processBegin(MethodID action, Url &url, const char *mime, int lenData=-1)
starts http request processing
Definition HttpRequest.h:227
Url url
Definition HttpRequest.h:345
Client * client_ptr
Definition HttpRequest.h:344
virtual void setConnection(const char *connection)
Definition HttpRequest.h:165
virtual int put(Url &url, const char *mime, Stream &data, int len=-1)
http put
Definition HttpRequest.h:98
size_t readBytesUntil(char terminator, char *buffer, size_t length)
Definition HttpRequest.h:140
const char * accept_encoding
Definition HttpRequest.h:353
HttpRequest(Client &client)
Definition HttpRequest.h:33
void setClient(Client &client)
Definition HttpRequest.h:35
virtual int head(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1)
http head
Definition HttpRequest.h:119
Client & client()
Definition HttpRequest.h:198
HttpChunkReader chunk_reader
Definition HttpRequest.h:348
virtual int post(Url &url, const char *mime, const char *data, int len=-1)
http post
Definition HttpRequest.h:80
void setOnConnectCallback(void(*callback)(HttpRequest &request, Url &url, HttpRequestHeader &request_header))
Callback which allows you to add additional paramters dynamically.
Definition HttpRequest.h:332
virtual int read(uint8_t *str, int len)
Definition HttpRequest.h:127
bool isReady()
Definition HttpRequest.h:188
const char * host_name
Definition HttpRequest.h:350
size_t clientTimeout
Definition HttpRequest.h:355
virtual void stop()
Definition HttpRequest.h:75
virtual HttpRequestHeader & header()
provides access to the request header
Definition HttpRequest.h:160
const char * getReplyHeader(const char *key)
Definition HttpRequest.h:194
virtual int del(Url &url, const char *mime=nullptr, const char *data=nullptr, int len=-1)
http del
Definition HttpRequest.h:104
const char * accept
Definition HttpRequest.h:352
HttpReplyHeader reply_header
Definition HttpRequest.h:347
virtual int available() override
Definition HttpRequest.h:53
void setHost(const char *host)
Definition HttpRequest.h:42
virtual void setAcceptMime(const char *mime)
Definition HttpRequest.h:173
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