arduino-audio-tools
Loading...
Searching...
No Matches
HttpHeader.h
Go to the documentation of this file.
1#pragma once
2
5#include "AudioToolsConfig.h"
6#include "AudioClient.h" // for Client
7#include "HttpLineReader.h"
8#include "HttpTypes.h"
9#include "Url.h"
10
11namespace audio_tools {
12
13// Class Configuration
14
15// Define relevant header content
16static const char* CONTENT_TYPE = "Content-Type";
17static const char* CONTENT_LENGTH = "Content-Length";
18static const char* CONNECTION = "Connection";
19static const char* CON_CLOSE = "close";
20static const char* CON_KEEP_ALIVE = "keep-alive";
21static const char* TRANSFER_ENCODING = "Transfer-Encoding";
22static const char* CHUNKED = "chunked";
23static const char* ACCEPT = "Accept";
24static const char* ACCEPT_ALL = "*/*";
25static const char* SUCCESS = "Success";
26static const char* USER_AGENT = "User-Agent";
27static const char* DEFAULT_AGENT =
28 "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)";
29static const char* HOST_C = "Host";
30static const char* ACCEPT_ENCODING = "Accept-Encoding";
31static const char* IDENTITY = "identity";
32static const char* LOCATION = "Location";
33
34// Http methods
35static const char* methods[] = {"?", "GET", "HEAD", "POST",
36 "PUT", "DELETE", "TRACE", "OPTIONS",
37 "CONNECT", "PATCH", nullptr};
38constexpr int HTTP_STATUS_UNDEFINED = -1;
46 bool active = true;
47 HttpHeaderLine(const char* k) { key = k; }
48};
49
60 public:
62 LOGD("HttpHeader");
63 // set default values
64 protocol_str = "HTTP/1.1";
65 url_path = "/";
66 status_msg = "";
67 }
69 LOGD("~HttpHeader");
70 clear();
71 }
72
75 is_written = false;
76 is_chunked = false;
77 url_path = "/";
78 // delete HttpHeaderLine objects
79 for (auto& ptr : lines){
80 delete ptr;
81 }
82 lines.clear();
83 return *this;
84 }
85
86 HttpHeader& put(const char* key, const char* value) {
87 if (value != nullptr && strlen(value) > 0) {
88 LOGD("HttpHeader::put %s %s", key, value);
90 if (hl == nullptr) {
92 LOGE("HttpHeader::put - did not add HttpHeaderLine for %s", key);
93 }
94 return *this;
95 }
96
97 // log entry
98 LOGD("HttpHeader::put -> '%s' : '%s'", key, value);
99
100 hl->value = value;
101 hl->active = true;
102
103 // determine if chunked
104 if (StrView(key).equalsIgnoreCase(TRANSFER_ENCODING) && StrView(value) == CHUNKED) {
105 LOGI("- is_chunked!!!");
106 this->is_chunked = true;
107 }
108 // log content type
109 if (StrView(key).equalsIgnoreCase(CONTENT_TYPE)) {
110 LOGI("%s: %s", CONTENT_TYPE, value);
111 }
112 } else {
113 LOGD("HttpHeader::put - value ignored because it is null for %s", key);
114 }
115 return *this;
116 }
117
119 HttpHeader& put(const char* key, int value) {
120 LOGD("HttpHeader::put %s %d", key, value);
122
123 if (value > 1000) {
124 LOGW("value is > 1000");
125 }
126
127 // add value
128 hl->value = value;
129 hl->active = true;
130 LOGI("%s %s", key, hl->value.c_str());
131 return *this;
132 }
133
135 HttpHeader& put(const char* line) {
136 LOGD("HttpHeader::put -> %s", (const char*)line);
138 int pos = keyStr.indexOf(":");
139 char* key = (char*)line;
140 key[pos] = 0;
141
142 // usually there is a leading space - but unfurtunately not always
143 const char* value = line + pos + 1;
144 if (value[0] == ' ') {
145 value = line + pos + 2;
146 }
147 return put((const char*)key, value);
148 }
149
150 // determines a header value with the key
151 const char* get(const char* key) {
152 for (auto& line_ptr : lines) {
154 trimmed.trim();
155 line_ptr->key = trimmed.c_str();
156 //line->key.rtrim();
157 if (StrView(line_ptr->key.c_str()).equalsIgnoreCase(key)) {
158 const char* result = line_ptr->value.c_str();
159 return line_ptr->active ? result : nullptr;
160 }
161 }
162 return nullptr;
163 }
164
165 // reads a single header line
166 int readLine(Client& in, char* str, int len) {
167 int result = reader.readlnInternal(in, (uint8_t*)str, len, false);
168 LOGD("HttpHeader::readLine -> %s", str);
169 return result;
170 }
171
172 // writes a lingle header line
174 LOGD("HttpHeader::writeHeaderLine: %s", header.key.c_str());
175 if (!header.active) {
176 LOGD("HttpHeader::writeHeaderLine - not active");
177 return;
178 }
179 if (header.value.c_str() == nullptr) {
180 LOGD("HttpHeader::writeHeaderLine - ignored because value is null");
181 return;
182 }
183
184 char* msg = tempBuffer();
186 msg_str = header.key.c_str();
187 msg_str += ": ";
188 msg_str += header.value.c_str();
189 msg_str += CRLF;
190 out.print(msg_str.c_str());
191
192 // remove crlf from log
193
194 int len = strlen(msg);
195 msg[len - 2] = 0;
196 LOGI(" -> %s ", msg);
197
198 // mark as processed
199 // header->active = false;
200 }
201
202 const char* urlPath() { return url_path.c_str(); }
203
205
206 int statusCode() { return status_code; }
207
208 const char* statusMessage() { return status_msg.c_str(); }
209
210 bool isChunked() {
211 // the value is automatically set from the reply
212 return is_chunked;
213 }
214
216 bool read(Client& in) {
217 LOGD("HttpHeader::read");
218 // remove all existing value
219 clear();
220
221 char* line = tempBuffer();
222 if (in.connected()) {
223 if (in.available() == 0) {
224 int count = 0;
225 uint32_t timeout = millis() + timeout_ms;
226 while (in.available() == 0) {
227 delay(50);
228 count++;
229 if (count == 2) {
230 LOGI("Waiting for data...");
231 }
232 // If we dont get an answer, we abort
233 if (millis() > timeout) {
234 LOGE("Request timed out after %d ms", (int)timeout_ms);
235 status_code = 401;
236 return false;
237 }
238 }
239 LOGI("Data available: %d", in.available());
240 }
241
242 if (readLine(in, line, HTTP_MAX_LEN) <= 0) {
243 LOGE("Failed to read the first line of the header");
245 return false;
246 }
248 while (true) {
249 int len = readLine(in, line, HTTP_MAX_LEN);
250 if (len == 0 && in.available() == 0) break;
251 if (len < 0) {
252 LOGE("Failed to read header line");
254 return false;
255 }
256 if (isValidStatus() || isRedirectStatus()) {
258 lineStr.ltrim();
259 if (lineStr.isEmpty()) {
260 break;
261 }
262 put(line);
263 }
264 }
265 }
266 return true;
267 }
268
270 void write(Client& out) {
271 LOGI("HttpHeader::write");
272 write1stLine(out);
273 for (auto& line_ptr : lines) {
275 }
276 // print empty line
277 crlf(out);
278 out.flush();
279 is_written = true;
280 }
281
283 for (auto& line :lines) {
284 line->active = false;
285 }
286 }
287
292
294 bool isValidStatus() { return status_code >= 200 && status_code < 300; }
295
297 bool isRedirectStatus() { return status_code >= 300 && status_code < 400; }
298
300 void end() { temp_buffer.resize(0); }
301
304
306 const char* protocol() { return protocol_str.c_str(); }
307
309 void setProtocol(const char* protocal) { protocol_str = protocal; }
310
312 void resize(int bufferSize){
313 temp_buffer.resize(bufferSize);
314 }
315
320
321 protected:
323 bool is_written = false;
324 bool is_chunked = false;
325 bool create_new_lines = true;
327 // we store the values on the heap. this is acceptable because we just have
328 // one instance for the requests and one for the replys: which needs about
329 // 2*100 bytes
335 const char* CRLF = "\r\n";
338
339 char* tempBuffer() {
341 return temp_buffer.data();
342 }
343
344 // the headers need to delimited with CR LF
345 void crlf(Client& out) {
346 out.print(CRLF);
347 LOGI(" -> %s ", "<CR LF>");
348 }
349
350 // gets or creates a header line by key
351 HttpHeaderLine* headerLine(const char* key) {
352 if (key != nullptr) {
353 for (auto& line_ptr : lines) {
354 if (line_ptr->key.c_str() != nullptr) {
355 if (line_ptr->key.equalsIgnoreCase(key)) {
356 line_ptr->active = true;
357 return line_ptr;
358 }
359 }
360 }
364 lines.push_back(new_line);
365 return new_line;
366 }
367 } else {
368 LOGI("HttpHeader::headerLine %s", "The key must not be null");
369 }
370 return nullptr;
371 }
372
373 MethodID getMethod(const char* line) {
374 // set action
375 for (int j = 0; methods[j] != nullptr; j++) {
376 const char* action = methods[j];
377 int len = strlen(action);
378 if (strncmp(action, line, len) == 0) {
379 return (MethodID)j;
380 }
381 }
382 return (MethodID)0;
383 }
384
385 virtual void write1stLine(Client& out) = 0;
386 virtual void parse1stLine(const char* line) = 0;
387};
388
395 public:
396 // Defines the action id, url path and http version for an request
398 const char* protocol = nullptr) {
399 this->method_id = id;
400 this->url_path = urlPath;
401
402 LOGD("HttpRequestHeader::setValues - path: %s", this->url_path.c_str());
403 if (protocol != nullptr) {
404 this->protocol_str = protocol;
405 }
406 return *this;
407 }
408
409 // action path protocol
410 void write1stLine(Client& out) override {
411 LOGD("HttpRequestHeader::write1stLine");
412 char* msg = tempBuffer();
414
415 const char* method_str = methods[this->method_id];
416 msg_str = method_str;
417 msg_str += " ";
418 msg_str += this->url_path.c_str();
419 msg_str += " ";
420 msg_str += this->protocol_str.c_str();
421 msg_str += CRLF;
422 out.print(msg);
423
424 int len = strlen(msg);
425 msg[len - 2] = 0;
426 LOGI("-> %s", msg);
427 }
428
429 // parses the requestline
430 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
431 void parse1stLine(const char* line) override {
432 LOGD("HttpRequestHeader::parse1stLine %s", line);
434 int space1 = line_str.indexOf(" ");
435 int space2 = line_str.indexOf(" ", space1 + 1);
436
437 this->method_id = getMethod(line);
438 this->protocol_str.substring(line_str, space2 + 1, line_str.length());
439 this->url_path.substring(line_str, space1 + 1, space2);
440 this->url_path.trim();
441
442 LOGD("->method %s", methods[this->method_id]);
443 LOGD("->protocol %s", protocol_str.c_str());
444 LOGD("->url_path %s", url_path.c_str());
445 }
446};
447
454 public:
455 // defines the values for the rely
456 void setValues(int statusCode, const char* msg = "",
457 const char* protocol = nullptr) {
458 LOGI("HttpReplyHeader::setValues");
459 status_msg = msg;
461 if (protocol != nullptr) {
462 this->protocol_str = protocol;
463 }
464 }
465
466 // reads the final chunked reply headers
467 void readExt(Client& in) {
468 LOGI("HttpReplyHeader::readExt");
469 char* line = tempBuffer();
471 while (strlen(line) != 0) {
472 put(line);
474 }
475 }
476
477 // HTTP-Version SP Status-Code SP Reason-Phrase CRLF
478 void write1stLine(Client& out) override {
479 LOGI("HttpReplyHeader::write1stLine");
480 char* msg = tempBuffer();
482 msg_str = this->protocol_str.c_str();
483 msg_str += " ";
484 msg_str += this->status_code;
485 msg_str += " ";
486 msg_str += this->status_msg.c_str();
487 LOGI("-> %s", msg);
488 out.print(msg);
489 crlf(out);
490 }
491
492 // HTTP-Version SP Status-Code SP Reason-Phrase CRLF
493 // we just update the pointers to point to the correct position in the
494 // http_status_line
495 void parse1stLine(const char* line) override {
496 LOGD("HttpReplyHeader::parse1stLine: %s", line);
498 int space1 = line_str.indexOf(' ', 0);
499 int space2 = line_str.indexOf(' ', space1 + 1);
500
501 // save http version
503
504 // find response status code after the first space
505 char status_c[6];
506 StrView status(status_c, 6);
507 status.substring(line_str, space1 + 1, space2);
509
510 // get reason-phrase after last SP
512 }
513};
514
515} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define HTTP_MAX_LEN
Definition AudioToolsConfig.h:143
MethodID
supported http methods
Definition HttpTypes.h:3
Definition NoArduino.h:169
bool connected()
Definition NoArduino.h:174
In a http request and reply we need to process header information. With this API we can define and qu...
Definition HttpHeader.h:59
List< HttpHeaderLine * > & getHeaderLines()
Provides the http parameter lines.
Definition HttpHeader.h:317
void setTimeout(int timeoutMs)
Set the timout.
Definition HttpHeader.h:303
void crlf(Client &out)
Definition HttpHeader.h:345
Str status_msg
Definition HttpHeader.h:332
virtual void parse1stLine(const char *line)=0
bool isChunked()
Definition HttpHeader.h:210
virtual void write1stLine(Client &out)=0
const char * statusMessage()
Definition HttpHeader.h:208
HttpLineReader reader
Definition HttpHeader.h:334
HttpHeader & clear()
clears the data
Definition HttpHeader.h:74
void setProcessed()
Definition HttpHeader.h:282
int statusCode()
Definition HttpHeader.h:206
HttpHeaderLine * headerLine(const char *key)
Definition HttpHeader.h:351
void setProtocol(const char *protocal)
Defines the protocol: e.g. HTTP/1.1.
Definition HttpHeader.h:309
MethodID method_id
Definition HttpHeader.h:326
Vector< char > temp_buffer
Definition HttpHeader.h:337
void writeHeaderLine(Client &out, HttpHeaderLine &header)
Definition HttpHeader.h:173
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
HttpHeader()
Definition HttpHeader.h:61
~HttpHeader()
Definition HttpHeader.h:68
void resize(int bufferSize)
Resizes the internal read buffer.
Definition HttpHeader.h:312
Str url_path
Definition HttpHeader.h:331
bool isRedirectStatus()
returns true if the status code is >=300 and < 400
Definition HttpHeader.h:297
int readLine(Client &in, char *str, int len)
Definition HttpHeader.h:166
void end()
release static temp buffer
Definition HttpHeader.h:300
void setAutoCreateLines(bool is_auto_line)
automatically create new lines
Definition HttpHeader.h:289
HttpHeader & put(const char *key, int value)
adds a new line to the header - e.g. for content size
Definition HttpHeader.h:119
bool read(Client &in)
reads the full header from the request (stream)
Definition HttpHeader.h:216
bool isValidStatus()
returns true if status code >=200 and < 300
Definition HttpHeader.h:294
List< HttpHeaderLine * > lines
Definition HttpHeader.h:333
Str protocol_str
Definition HttpHeader.h:330
int status_code
Definition HttpHeader.h:322
bool create_new_lines
Definition HttpHeader.h:325
int timeout_ms
Definition HttpHeader.h:336
MethodID getMethod(const char *line)
Definition HttpHeader.h:373
const char * protocol()
Provide the protocol.
Definition HttpHeader.h:306
bool is_chunked
Definition HttpHeader.h:324
const char * get(const char *key)
Definition HttpHeader.h:151
HttpHeader & put(const char *line)
adds a received new line to the header
Definition HttpHeader.h:135
const char * urlPath()
Definition HttpHeader.h:202
bool is_written
Definition HttpHeader.h:323
MethodID method()
Definition HttpHeader.h:204
char * tempBuffer()
Definition HttpHeader.h:339
const char * CRLF
Definition HttpHeader.h:335
We read a single line. A terminating 0 is added to the string to make it compliant for c string funct...
Definition HttpLineReader.h:14
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
void write1stLine(Client &out) override
Definition HttpHeader.h:478
void readExt(Client &in)
Definition HttpHeader.h:467
void parse1stLine(const char *line) override
Definition HttpHeader.h:495
void setValues(int statusCode, const char *msg="", const char *protocol=nullptr)
Definition HttpHeader.h:456
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
void write1stLine(Client &out) override
Definition HttpHeader.h:410
void parse1stLine(const char *line) override
Definition HttpHeader.h:431
Double linked list.
Definition List.h:18
virtual void flush()
Definition NoArduino.h:136
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
void clear() override
clears and resizes to 0
Definition Str.h:167
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual int length()
Definition StrView.h:383
virtual bool equalsIgnoreCase(const char *alt)
Compares the string ignoring the case.
Definition StrView.h:564
virtual void trim()
remove leading and traling spaces
Definition StrView.h:504
virtual void substring(StrView &from, int start, int end)
copies a substring into the current string
Definition StrView.h:477
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:379
virtual int available()
Definition NoArduino.h:146
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(int newSize, T value)
Definition Vector.h:266
void clear()
Definition Vector.h:176
T * data()
Definition Vector.h:316
#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 * CHUNKED
Definition HttpHeader.h:22
static const char * DEFAULT_AGENT
Definition HttpHeader.h:27
static const char * IDENTITY
Definition HttpHeader.h:31
static const char * TRANSFER_ENCODING
Definition HttpHeader.h:21
static const char * methods[]
Definition HttpHeader.h:35
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
constexpr int HTTP_STATUS_UNDEFINED
Definition HttpHeader.h:38
static const char * LOCATION
Definition HttpHeader.h:32
static const char * CON_KEEP_ALIVE
Definition HttpHeader.h:20
static const char * SUCCESS
Definition HttpHeader.h:25
static const char * ACCEPT_ALL
Definition HttpHeader.h:24
static const char * CON_CLOSE
Definition HttpHeader.h:19
uint32_t millis()
Returns the milliseconds since the start.
Definition Time.h:12
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
A individual key - value header line.
Definition HttpHeader.h:43
bool active
Definition HttpHeader.h:46
Str key
Definition HttpHeader.h:44
Str value
Definition HttpHeader.h:45
HttpHeaderLine(const char *k)
Definition HttpHeader.h:47