arduino-audio-tools
Loading...
Searching...
No Matches
URLStream.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioToolsConfig.h"
4
5#if defined(USE_WIFI)
7#endif
8
13
14// UNO R3 has no WiFiClientSecure implementation, so we need to disable it
15#if !defined(USE_WIFIS3)
16#define HAS_CLIENT_SECURE
17#endif
18
19
20namespace audio_tools {
21
33 public:
34 URLStream(int readBufferSize = DEFAULT_BUFFER_SIZE) {
35 TRACED();
36 setReadBufferSize(readBufferSize);
37 }
38
39 URLStream(Client& clientPar, int readBufferSize = DEFAULT_BUFFER_SIZE) {
40 TRACED();
41 setReadBufferSize(readBufferSize);
42 setClient(clientPar);
43 }
44
45 URLStream(const char* network, const char* password,
46 int readBufferSize = DEFAULT_BUFFER_SIZE) {
47 TRACED();
48 setReadBufferSize(readBufferSize);
51 }
52
53 URLStream(const URLStream&) = delete;
54
56 TRACED();
57 end();
58#if defined(HAS_CLIENT_SECURE)
59 if (client_secure != nullptr) {
60 delete client_secure;
61 client_secure = nullptr;
62 }
63#endif
64 if (client_insecure != nullptr) {
65 delete client_insecure;
66 client_insecure = nullptr;
67 }
68 }
69
71 void setClient(Client& clientPar) override { client = &clientPar; }
72
74 void setSSID(const char* ssid) override { this->network = ssid; }
75
77 void setPassword(const char* password) override { this->password = password; }
78
80 void setReadBufferSize(int readBufferSize) {
81 read_buffer_size = readBufferSize;
82 }
83
85 virtual bool begin(const char* urlStr, const char* acceptMime = nullptr,
86 MethodID action = GET, const char* reqMime = "",
87 const char* reqData = "") override {
88 LOGI("%s: %s", LOG_METHOD, urlStr);
89 if (!preProcess(urlStr, acceptMime)) {
90 LOGE("preProcess failed");
91 return false;
92 }
93 int result = process<const char*>(action, url, reqMime, reqData);
94 if (result > 0) {
96 LOGI("contentLength: %d", (int)content_length);
97 if (content_length >= 0 && wait_for_data) {
99 }
100 }
101 total_read = 0;
102 active = result == 200;
103 LOGI("==> http result: %d", result);
104 return active;
105 }
106
108 virtual bool begin(const char* urlStr, const char* acceptMime,
109 MethodID action, const char* reqMime, Stream& reqData,
110 int len = -1) {
111 LOGI("%s: %s", LOG_METHOD, urlStr);
112 if (!preProcess(urlStr, acceptMime)) {
113 LOGE("preProcess failed");
114 return false;
115 }
116 int result = process<Stream&>(action, url, reqMime, reqData, len);
117 if (result > 0) {
119 LOGI("size: %d", (int)content_length);
120 if (content_length >= 0 && wait_for_data) {
122 }
123 }
124 total_read = 0;
125 active = result == 200;
126 LOGI("==> http status: %d", result);
127 return active;
128 }
129
131 virtual void end() override {
132 if (active) request.stop();
133 active = false;
134 clear();
135 }
136
137 virtual int available() override {
138 if (!active) return 0;
139
140 int result = request.available();
141 LOGD("available: %d", result);
142 return result;
143 }
144
145 virtual size_t readBytes(uint8_t* data, size_t len) override {
146 if (!active) return 0;
147
148 int read = request.read(data, len);
149 if (read < 0) {
150 read = 0;
151 }
152 total_read += read;
153 LOGD("readBytes %d -> %d", (int)len, read);
154 return read;
155 }
156
157 virtual int read() override {
158 if (!active) return -1;
159 // lazy allocation since this is rarely used
161
162 fillBuffer();
163 total_read++;
164 return isEOS() ? -1 : read_buffer[read_pos++];
165 }
166
167 virtual int peek() override {
168 if (!active) return -1;
169 // lazy allocation since this is rarely used
171
172 fillBuffer();
173 return isEOS() ? -1 : read_buffer[read_pos];
174 }
175
176 virtual void flush() override {}
177
178 virtual size_t write(uint8_t) override { return not_supported(0); }
179
180 virtual size_t write(const uint8_t*, size_t len) override {
181 return not_supported(0);
182 }
183
185 virtual HttpRequest& httpRequest() override { return request; }
186
187 operator bool() override { return active && request.isReady(); }
188
190 virtual void setTimeout(int ms) { client_timeout = ms; }
191
194 void setPowerSave(bool ps) override { is_power_save = ps; }
195
197 void setAutoCreateLines(bool flag) {
199 }
200
202 void setConnectionClose(bool close) override {
204 }
205
207 void clear() {
208 httpRequest().reply().clear();
211 read_pos = 0;
212 read_size = 0;
213 }
214
216 void addRequestHeader(const char* key, const char* value) override {
217 request.header().put(key, value);
218 }
219
221 const char* getReplyHeader(const char* key) override {
222 return request.reply().get(key);
223 }
224
226 void setOnConnectCallback(void (*callback)(
227 HttpRequest& request, Url& url, HttpRequestHeader& request_header)) {
229 }
230
232 void setWaitForData(bool flag) { wait_for_data = flag; }
233
235 int contentLength() override { return content_length; }
236
238 size_t totalRead() override { return total_read; }
239
241 bool waitForData (int timeout) override{
242 TRACED();
243 uint32_t end = millis() + timeout;
244 if (request.available() == 0) {
245 LOGI("Request written ... waiting for reply");
246 while (request.available() == 0) {
247 if (millis() > end) break;
248 // stop waiting if we got an error
249 int rc = request.reply().statusCode();
250 if (rc >= 300) {
251 LOGE("Error code %d recieved: stop waiting for reply", rc);
252 break;
253 }
254 delay(500);
255 }
256 }
257 int avail = request.available();
258 LOGD("available: %d", avail);
259 return avail > 0;
260 }
261
263 const char* urlStr() override { return url_str.c_str(); }
264
266 void setCACert(const char* cert) override{
267#if defined(HAS_CLIENT_SECURE)
268 if (client_secure!=nullptr) client_secure->setCACert(cert);
269#else
270 LOGE("setCACert is not supported on this platform");
271#endif
272 }
273
275 size_t size() { return content_length; }
276
277 protected:
282 long total_read = 0;
283 // buffered single byte read
286 uint16_t read_pos = 0;
287 uint16_t read_size = 0;
288 bool active = false;
289 bool wait_for_data = true;
290 Client* client = nullptr; // client defined via setClient
291 WiFiClient* client_insecure = nullptr; // wifi client for http
292#if defined(HAS_CLIENT_SECURE)
293 WiFiClientSecure* client_secure = nullptr; // wifi client for https
294#endif
296 unsigned long handshake_timeout = URL_HANDSHAKE_TIMEOUT; // 120000
297 bool is_power_save = false;
298 // optional
299 const char* network = nullptr;
300 const char* password = nullptr;
301
302 bool preProcess(const char* urlStr, const char* acceptMime) {
303 TRACED();
304 url_str = urlStr;
306 int result = -1;
307
308 // close it - if we have an active connection
309 if (active) end();
310
311 // optional: login if necessary if no external client is defined
312 if (client == nullptr){
313 if (!login()){
314 LOGE("Not connected");
315 return false;
316 }
317 }
318
319 // request.reply().setAutoCreateLines(false);
320 if (acceptMime != nullptr) {
321 request.setAcceptMime(acceptMime);
322 }
323
324 // setup client
328
329#if defined(ESP32)
330 // Performance optimization for ESP32
331 if (!is_power_save) {
332 esp_wifi_set_ps(WIFI_PS_NONE);
333 }
334#endif
335
336 return true;
337 }
338
340 template <typename T>
341 int process(MethodID action, Url& url, const char* reqMime, T reqData,
342 int len = -1) {
343 TRACED();
344 // keep icy across redirect requests ?
345 const char* icy = request.header().get("Icy-MetaData");
346
347 int status_code = request.process(action, url, reqMime, reqData, len);
348 // redirect
349 while (request.reply().isRedirectStatus()) {
350 const char* redirect_url = request.reply().get(LOCATION);
351 if (redirect_url != nullptr) {
352 LOGW("Redirected to: %s", redirect_url);
353 url.setUrl(redirect_url);
354 Client* p_client = &getClient(url.isSecure());
355 p_client->stop();
356 request.setClient(*p_client);
357 if (icy) {
358 request.header().put("Icy-MetaData", icy);
359 }
360 status_code = request.process(action, url, reqMime, reqData, len);
361 } else {
362 LOGE("Location is null");
363 break;
364 }
365 }
366 return status_code;
367 }
368
370 Client& getClient(bool isSecure) {
371#if defined(HAS_CLIENT_SECURE)
372 if (isSecure) {
374 return *client_secure;
375 }
376#endif
377 if (client_insecure == nullptr) {
380#ifdef ESP32
381 #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3,0,0)
382 client_insecure->setConnectionTimeout(client_timeout);
383 #else
385 #endif
386#endif
387 LOGI("WiFiClient");
388 }
389 return *client_insecure;
390 }
391
392#if defined(HAS_CLIENT_SECURE)
393
395 LOGI("setupClientSecure");
396 if (client_secure == nullptr) {
399#ifdef ESP32
401 #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3,0,0)
402 client_secure->setConnectionTimeout(client_timeout);
403 #endif
404 client_secure->setHandshakeTimeout(handshake_timeout);
405#endif
406#ifdef RP2040_HOWER
408 client_secure->setTLSConnectTimeout(client_timeout);
409#endif
410 }
411 }
412
413#endif
414
415 inline void fillBuffer() {
416 if (isEOS()) {
417 // if we consumed all bytes we refill the buffer
419 read_pos = 0;
420 }
421 }
422
423 inline bool isEOS() { return read_pos >= read_size; }
424
425 bool login() {
426 if (network != nullptr && password != nullptr &&
427 WiFi.status() != WL_CONNECTED) {
428 TRACEI();
430 while (WiFi.status() != WL_CONNECTED) {
431 Serial.print(".");
432 delay(500);
433 }
434 Serial.println();
435 delay(10);
436 return WiFi.status() == WL_CONNECTED;
437 }
438 return WiFi.status() == WL_CONNECTED;
439 }
440};
441
442
443#if defined(USE_CONCURRENCY)
446
447#endif
448
449} // namespace audio_tools
static HardwareSerial Serial
Definition Arduino.h:179
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#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 LOG_METHOD
Definition AudioToolsConfig.h:69
MethodID
supported http methods
Definition HttpTypes.h:3
@ GET
Definition HttpTypes.h:5
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
Definition Arduino.h:162
void stop()
Definition Arduino.h:164
Definition Arduino.h:136
Abstract Base class for all URLStream implementations.
Definition AbstractURLStream.h:17
virtual int not_supported(int out, const char *msg="")
Definition BaseStream.h:173
HttpHeader & clear()
clears the data
Definition HttpHeader.h:74
int statusCode()
Definition HttpHeader.h:210
HttpHeader & put(const char *key, const char *value)
Definition HttpHeader.h:86
bool isRedirectStatus()
returns true if the status code is >=300 and < 400
Definition HttpHeader.h:303
void setAutoCreateLines(bool is_auto_line)
automatically create new lines
Definition HttpHeader.h:295
const char * get(const char *key)
Definition HttpHeader.h:155
Reading and writing of Http Requests.
Definition HttpHeader.h:400
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition HttpRequest.h:25
void setTimeout(size_t timeoutMs)
Defines the client timeout in ms.
Definition HttpRequest.h:350
virtual HttpReplyHeader & reply()
Definition HttpRequest.h:163
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
int available() override
Definition HttpRequest.h:54
virtual void setConnection(const char *connection)
Definition HttpRequest.h:171
void setClient(Client &client)
Definition HttpRequest.h:35
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
virtual void stop()
Definition HttpRequest.h:76
virtual HttpRequestHeader & header()
provides access to the request header
Definition HttpRequest.h:166
virtual void setAcceptMime(const char *mime)
Definition HttpRequest.h:179
Str which keeps the data on the heap. We grow the allocated memory only if the copy source is not fit...
Definition Str.h:24
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:380
URLStream implementation for the ESP32 based on a separate FreeRTOS task: the.
Definition URLStreamBufferedT.h:162
Represents the content of a URL as Stream. We use the WiFi.h API. If you run into performance issues,...
Definition URLStream.h:32
Client * client
Definition URLStream.h:290
bool active
Definition URLStream.h:288
size_t size()
Returns the content length of the request.
Definition URLStream.h:275
size_t totalRead() override
returns the total number of bytes read from the stream
Definition URLStream.h:238
WiFiClient * client_insecure
Definition URLStream.h:291
void fillBuffer()
Definition URLStream.h:415
bool preProcess(const char *urlStr, const char *acceptMime)
Definition URLStream.h:302
bool wait_for_data
Definition URLStream.h:289
virtual int read() override
Definition URLStream.h:157
long total_read
Definition URLStream.h:282
HttpRequest request
Definition URLStream.h:278
bool login()
Definition URLStream.h:425
virtual bool begin(const char *urlStr, const char *acceptMime=nullptr, MethodID action=GET, const char *reqMime="", const char *reqData="") override
Execute http request: by default we use a GET request.
Definition URLStream.h:85
const char * network
Definition URLStream.h:299
uint16_t read_size
Definition URLStream.h:287
virtual void setTimeout(int ms)
Defines the client timeout in ms.
Definition URLStream.h:190
bool waitForData(int timeout) override
Waits for some data - returns false if the request has failed.
Definition URLStream.h:241
void setConnectionClose(bool close) override
Sets if the connection should be close automatically.
Definition URLStream.h:202
~URLStream()
Definition URLStream.h:55
virtual size_t readBytes(uint8_t *data, size_t len) override
Definition URLStream.h:145
uint16_t read_buffer_size
Definition URLStream.h:285
void setReadBufferSize(int readBufferSize)
Defines the buffer that is used by individual read() or peek() calls.
Definition URLStream.h:80
WiFiClientSecure * client_secure
Definition URLStream.h:293
void setPowerSave(bool ps) override
Definition URLStream.h:194
Client & getClient(bool isSecure)
Determines the client.
Definition URLStream.h:370
int client_timeout
Definition URLStream.h:295
void setWaitForData(bool flag)
Defines if the stream should wait for data after the request has been sent.
Definition URLStream.h:232
virtual size_t write(uint8_t) override
Definition URLStream.h:178
int process(MethodID action, Url &url, const char *reqMime, T reqData, int len=-1)
Process the Http request and handle redirects.
Definition URLStream.h:341
Url url
Definition URLStream.h:280
Str url_str
Definition URLStream.h:279
void addRequestHeader(const char *key, const char *value) override
Adds/Updates a request header.
Definition URLStream.h:216
virtual int peek() override
Definition URLStream.h:167
URLStream(int readBufferSize=DEFAULT_BUFFER_SIZE)
Definition URLStream.h:34
URLStream(const URLStream &)=delete
const char * password
Definition URLStream.h:300
void setSSID(const char *ssid) override
Sets the ssid that will be used for logging in (when calling begin)
Definition URLStream.h:74
URLStream(const char *network, const char *password, int readBufferSize=DEFAULT_BUFFER_SIZE)
Definition URLStream.h:45
virtual size_t write(const uint8_t *, size_t len) override
Definition URLStream.h:180
virtual bool begin(const char *urlStr, const char *acceptMime, MethodID action, const char *reqMime, Stream &reqData, int len=-1)
Execute e.g. http POST request which submits the content as a stream.
Definition URLStream.h:108
const char * urlStr() override
returns the url as string
Definition URLStream.h:263
bool isEOS()
Definition URLStream.h:423
void setClient(Client &clientPar) override
(Re-)defines the client
Definition URLStream.h:71
Vector< uint8_t > read_buffer
Definition URLStream.h:284
void setCACert(const char *cert) override
Define the Root PEM Certificate for SSL.
Definition URLStream.h:266
void setOnConnectCallback(void(*callback)(HttpRequest &request, Url &url, HttpRequestHeader &request_header))
Callback which allows you to add additional paramters dynamically.
Definition URLStream.h:226
URLStream(Client &clientPar, int readBufferSize=DEFAULT_BUFFER_SIZE)
Definition URLStream.h:39
void clear()
Releases the memory from the request and reply.
Definition URLStream.h:207
uint16_t read_pos
Definition URLStream.h:286
int contentLength() override
returns the content length
Definition URLStream.h:235
void setAutoCreateLines(bool flag)
If set to true, new undefined reply parameters will be stored.
Definition URLStream.h:197
unsigned long handshake_timeout
Definition URLStream.h:296
void setupClientSecure()
Definition URLStream.h:394
void setPassword(const char *password) override
Sets the password that will be used for logging in (when calling begin)
Definition URLStream.h:77
virtual void end() override
Ends the request and releases the memory.
Definition URLStream.h:131
long content_length
Definition URLStream.h:281
virtual HttpRequest & httpRequest() override
provides access to the HttpRequest
Definition URLStream.h:185
bool is_power_save
Definition URLStream.h:297
virtual void flush() override
Definition URLStream.h:176
virtual int available() override
Definition URLStream.h:137
const char * getReplyHeader(const char *key) override
Provides the value of the reply header for the given key.
Definition URLStream.h:221
URL parser which breaks a full url string up into its individual parts.
Definition Url.h:22
bool isSecure()
Definition Url.h:42
void setUrl(const char *url)
Definition Url.h:44
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
Definition WiFiClientSecureZephyr.h:24
void setInsecure()
Definition WiFiClientSecureZephyr.h:44
bool setCACert(const uint8_t *pem, size_t len)
Definition WiFiClientSecureZephyr.h:37
Definition WiFiClientZephyr.h:44
void setTimeout(uint32_t timeout_ms)
Definition WiFiClientZephyr.h:269
bool begin(const char *ssid, const char *password)
Definition WiFiZephyr.h:51
wifi_status_t status()
Definition WiFiZephyr.h:85
#define URL_CLIENT_TIMEOUT
Definition esp8266.h:23
#define URL_HANDSHAKE_TIMEOUT
Definition esp8266.h:24
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void delay(uint32_t ms)
Definition Arduino.h:259
@ WL_CONNECTED
Definition WiFiZephyr.h:30
static WiFiZephyr WiFi
Definition WiFiZephyr.h:230
static const char * LOCATION
Definition HttpHeader.h:32
static const char * CON_KEEP_ALIVE
Definition HttpHeader.h:20
static const char * CON_CLOSE
Definition HttpHeader.h:19
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
WiFiClientZephyr WiFiClient
Definition WiFiClientZephyr.h:311
WiFiClientSecureZephyr WiFiClientSecure
Definition WiFiClientSecureZephyr.h:117