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(client_timeout);
38
39 }
40
41 // the requests usually need a host. This needs to be set if we did not
42 // provide a URL
43 void setHost(const char *host) {
44 LOGI("setHost %s", host);
45 this->host_name = host;
46 }
47
48 operator bool() { return client_ptr != nullptr ? (bool)*client_ptr : false; }
49
50 virtual bool connected() {
51 return client_ptr == nullptr ? false : client_ptr->connected();
52 }
53
54 int available() override {
55 if (reply_header.isChunked()) {
56 return chunk_reader.available();
57 }
58 return client_ptr != nullptr ? client_ptr->available() : 0;
59 }
60
62 void end() override {
63 if (connected()) {
64 // write final 0 chunk if necessary
66 client_ptr->println(0, HEX);
67 client_ptr->println();
70 }
71 LOGI("stop");
73 }
74 }
75
76 virtual void stop() {
77 end();
78 }
79
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);
84 }
85
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);
90 }
91
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);
96 }
97
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);
102 }
103
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);
109 }
110
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);
117 }
118
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);
125 }
126
127 // reads the reply data
128 virtual int read(uint8_t *str, int len) {
129 TRACED();
130 if (reply_header.isChunked()) {
131 return chunk_reader.read(*client_ptr, str, len);
132 } else {
133 return client_ptr->read(str, len);
134 }
135 }
136
137 size_t readBytes(uint8_t *str, size_t len) override {
138 int result = read(str, len);
139 if ( result < 0) {
140 LOGE("HttpRequest::read error");
141 return 0;
142 }
143 return result;
144 }
145
146 size_t readBytesUntil(char terminator, char *buffer, size_t length) {
147 TRACED();
148 return client_ptr->readBytesUntil(terminator, buffer, length);
149 }
150
151 // read the reply data up to the next new line. For Chunked data we provide
152 // the full chunk!
153 virtual int readln(uint8_t *str, int len, bool incl_nl = true) {
154 TRACED();
155 if (reply_header.isChunked()) {
156 return chunk_reader.readln(*client_ptr, str, len);
157 } else {
158 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
159 }
160 }
161
162 // provides the head information of the reply
163 virtual HttpReplyHeader &reply() { return reply_header; }
164
167
169 virtual void setAgent(const char *agent) { this->agent = agent; }
170
171 virtual void setConnection(const char *connection) {
172 this->connection = connection;
173 }
174
175 virtual void setAcceptsEncoding(const char *enc) {
176 this->accept_encoding = enc;
177 }
178
179 virtual void setAcceptMime(const char *mime) { this->accept = mime; }
180
181 size_t contentLength() {
182 const char *len_str = reply().get(CONTENT_LENGTH);
183 int len = 0;
184 if (len_str != nullptr) {
185 len = atoi(len_str);
186 } else {
187 LOGI("no CONTENT_LENGTH found in reply");
188 }
189 return len;
190 }
191
194 bool isReady() { return is_ready; }
195
197 void addRequestHeader(const char *key, const char *value) {
198 request_header.put(key, value);
199 }
200 const char* getReplyHeader(const char *key) {
201 return reply_header.get(key);
202 }
203
204 Client &client() { return *client_ptr; }
205
206 // process http request and reads the reply_header from the server
207 virtual int process(MethodID action, Url &url, const char *mime,
208 const char *data, int lenData = -1) {
209 LOGD("processing %s", url.url());
210 int len = lenData;
211 if (data != nullptr && len <= 0) {
212 len = strlen(data);
213 }
214 if (!processBegin(action, url, mime, len)){
215 return false;
216 }
217 // posting data parameter
218 if (len > 0 && data != nullptr) {
219 LOGI("Writing data: %d bytes", len);
220 client_ptr->write((const uint8_t *)data, len);
221 LOGD("%s", data);
222 }
223 return processEnd();
224 }
225
226 // process http request and reads the reply_header from the server
227 virtual int process(MethodID action, Url &url, const char *mime,
228 Stream &stream, int len = -1) {
229 if (!processBegin(action, url, mime, len))
230 return -1;
231 processWrite(stream);
232 return processEnd();
233 }
234
236 virtual bool processBegin(MethodID action, Url &url, const char *mime,
237 int lenData = -1) {
238 TRACED();
239 int len = lenData;
240 is_ready = false;
241 if (client_ptr == nullptr) {
242 LOGE("The client has not been defined");
243 return false;
244 }
247 }
248 if (!this->connected()) {
249 LOGI("process connecting to host %s port %d", url.host(), url.port());
251 if (!is_connected) {
252 LOGE("Connect failed");
253 return false;
254 } else {
255 LOGI("Connected to host %s port %d", url.host(), url.port());
256 }
257 } else {
258 LOGI("process is already connected");
259 }
260
261#if defined(ESP32) && defined(ARDUINO)
262 LOGI("Free heap: %u", (unsigned)ESP.getFreeHeap());
263#endif
264
266
267 host_name = url.host();
269 if (lenData > 0) {
271 }
279 }
280
282 virtual void processWrite(Stream &stream) {
283 uint8_t buffer[CHUNK_SIZE];
284 int total = 0;
285 int total_written = 0;
286 while (*client_ptr && stream.available() > 0) {
287 int result_len = stream.readBytes(buffer, CHUNK_SIZE);
288 total += result_len;
289 int written = write(buffer, result_len);
290 total_written += written;
291 LOGI("--> Bytes read %d vs written %d", result_len, written);
292 delay(1);
293 }
294 client_ptr->flush();
295 LOGI("Total bytes read %d vs written %d", total, total_written);
296 }
297
300 size_t write(const uint8_t *data, size_t len) override {
301 TRACED();
302 size_t result = 0;
303 if (isChunked()) {
304 if (len > 0) {
306 client_ptr->println(len, HEX);
307 result = client_ptr->write(data, len);
308 client_ptr->println();
309 }
310 } else {
311 result = client_ptr->write(data, len);
312 }
313 return result;
314 }
315
317 virtual int processEnd() {
318 TRACED();
319 // if sending is chunked we terminate with an empty chunk
320 if (isChunked()) {
321 if (is_chunked_output_active) client_ptr->println(0, HEX);
322 client_ptr->println();
324 }
325 LOGI("Request written ... waiting for reply");
326 // Commented out because this breaks the RP2040 W
327 // client_ptr->flush();
329
330 // if we use chunked tranfer we need to read the first chunked length
331 if (reply_header.isChunked()) {
333 LOGE("HttpRequest: Failed to open chunked reader");
334 return -1;
335 }
336 }
337
338 // wait for data
339 is_ready = true;
340 return reply_header.statusCode();
341 }
342
344 void setOnConnectCallback(void (*callback)(
346 http_connect_callback = callback;
347 }
348
350 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
@ HEX
Definition Arduino.h:54
#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
Definition Arduino.h:162
bool connect(const char *ip, int port)
Definition Arduino.h:168
bool connected()
Definition Arduino.h:167
virtual int read(uint8_t *buffer, size_t len)
Definition Arduino.h:165
void stop()
Definition Arduino.h:164
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
virtual void flush()
Definition Arduino.h:130
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
Base class for all Streams. It relies on write(const uint8_t *buffer, size_t size) and readBytes(uint...
Definition BaseStream.h:33
Http might reply with chunks. So we need to dechunk the data. see https://en.wikipedia....
Definition HttpChunkReader.h:14
int readln(Client &client, uint8_t *str, int len, bool incl_nl=true)
reads a single line from the chunks
Definition HttpChunkReader.h:61
int available()
returns the number of bytes which are still available in the current chunk
Definition HttpChunkReader.h:84
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:309
bool isChunked()
Definition HttpHeader.h:214
void setProcessed()
Definition HttpHeader.h:288
int statusCode()
Definition HttpHeader.h:210
bool write(Client &out)
writes the full header to the indicated HttpStreamedMultiOutput stream
Definition HttpHeader.h:273
HttpHeader & put(const char *key, const char *value)
Definition HttpHeader.h:86
bool read(Client &in)
reads the full header from the request (stream)
Definition HttpHeader.h:220
const char * get(const char *key)
Definition HttpHeader.h:155
virtual int readlnInternal(Stream &client, uint8_t *str, int len, bool incl_nl=true)
reads up the the next CR LF - but never more then the indicated len.
Definition HttpLineReader.h:20
Reading and Writing of Http Replys.
Definition HttpHeader.h:464
Reading and writing of Http Requests.
Definition HttpHeader.h:400
HttpHeader & setValues(MethodID id, const char *urlPath, const char *protocol=nullptr)
Definition HttpHeader.h:403
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:175
virtual bool connected()
Definition HttpRequest.h:50
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:350
virtual int post(Url &url, const char *mime, Stream &data, int len=-1)
http post
Definition HttpRequest.h:87
virtual HttpReplyHeader & reply()
Definition HttpRequest.h:163
void addRequestHeader(const char *key, const char *value)
Adds/Updates a request header.
Definition HttpRequest.h:197
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:112
virtual int processEnd()
Ends the http request processing and returns the status code or -1 on error.
Definition HttpRequest.h:317
~HttpRequest()
Definition HttpRequest.h:31
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:93
size_t readBytes(uint8_t *str, size_t len) override
Definition HttpRequest.h:137
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:207
size_t contentLength()
Definition HttpRequest.h:181
virtual void processWrite(Stream &stream)
Writes (Posts) the data of the indicated stream after calling processBegin.
Definition HttpRequest.h:282
virtual void setAgent(const char *agent)
Defines the agent.
Definition HttpRequest.h:169
virtual int readln(uint8_t *str, int len, bool incl_nl=true)
Definition HttpRequest.h:153
void end() override
same as end()
Definition HttpRequest.h:62
int available() override
Definition HttpRequest.h:54
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:227
size_t write(const uint8_t *data, size_t len) override
Definition HttpRequest.h:300
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:236
Url url
Definition HttpRequest.h:362
Client * client_ptr
Definition HttpRequest.h:361
virtual void setConnection(const char *connection)
Definition HttpRequest.h:171
virtual int put(Url &url, const char *mime, Stream &data, int len=-1)
http put
Definition HttpRequest.h:99
size_t readBytesUntil(char terminator, char *buffer, size_t length)
Definition HttpRequest.h:146
const char * accept_encoding
Definition HttpRequest.h:370
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:120
Client & client()
Definition HttpRequest.h:204
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:81
void setOnConnectCallback(void(*callback)(HttpRequest &request, Url &url, HttpRequestHeader &request_header))
Callback which allows you to add additional paramters dynamically.
Definition HttpRequest.h:344
virtual int read(uint8_t *str, int len)
Definition HttpRequest.h:128
bool isReady()
Definition HttpRequest.h:194
const char * host_name
Definition HttpRequest.h:367
virtual void stop()
Definition HttpRequest.h:76
virtual HttpRequestHeader & header()
provides access to the request header
Definition HttpRequest.h:166
const char * getReplyHeader(const char *key)
Definition HttpRequest.h:200
virtual int del(Url &url, const char *mime=nullptr, const char *data=nullptr, int len=-1)
http del
Definition HttpRequest.h:105
const char * accept
Definition HttpRequest.h:369
HttpReplyHeader reply_header
Definition HttpRequest.h:364
void setHost(const char *host)
Definition HttpRequest.h:43
virtual void setAcceptMime(const char *mime)
Definition HttpRequest.h:179
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
static const char * CONTENT_LENGTH
Definition HttpHeader.h:17
void delay(uint32_t ms)
Definition Arduino.h:255
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:508
static const char * HOST_C
Definition HttpHeader.h:29
static const char * ACCEPT
Definition HttpHeader.h:23