Arduino DLNA Server
Loading...
Searching...
No Matches
HttpRequest.h
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4
5#include "HttpChunkReader.h"
6#include "HttpChunkWriter.h"
7#include "HttpHeader.h"
8#include "IHttpRequest.h"
9#include "basic/StrPrint.h"
10#ifdef ESP32
11#include <WiFi.h>
12#include <lwip/sockets.h>
13#endif
14
15namespace tiny_dlna {
16
30template <typename ClientType>
31class HttpRequest : public IHttpRequest {
32 public:
35 DlnaLogger.log(DlnaLogLevel::Debug, "HttpRequest (default client)");
37 }
38
40 explicit HttpRequest(ClientType& client) {
41 DlnaLogger.log(DlnaLogLevel::Debug, "HttpRequest");
43 }
44
46 ~HttpRequest() override { stop(); }
47
49 void setClient(Client& client) override { this->client_ptr = &client; }
50
52 void setHost(const char* host) override {
53 DlnaLogger.log(DlnaLogLevel::Info, "HttpRequest::setHost: ", host);
54 this->host_name = host;
55 }
56
58 operator bool() override {
59 return client_ptr != nullptr && static_cast<bool>(*client_ptr);
60 }
61
63 bool connected() override { return client_ptr->connected(); }
64
66 int available() override {
67 if (reply_header.isChunked()) {
68 return chunk_reader.available();
69 }
70 return client_ptr->available();
71 }
72
74 void stop() override {
75 DlnaLogger.log(DlnaLogLevel::Info, "HttpRequest::stop");
76 if (client_ptr != nullptr) {
77 client_ptr->stop();
78 // delay(300);
79 }
80 }
81
83 int post(Url& url, const char* mime, const char* data,
84 int len = -1) override {
85 DlnaLogger.log(DlnaLogLevel::Info, "post %s", url.url());
86 return process(T_POST, url, mime, data, len);
87 }
88
90 int post(Url& url, size_t len, std::function<size_t(Print&, void*)> writer,
91 const char* mime = nullptr, void* ref = nullptr) override {
92 return process(T_POST, url, len, writer, mime, ref);
93 }
94
96 int notify(Url& url, std::function<size_t(Print&, void*)> writer,
97 const char* mime = nullptr, void* ref = nullptr) override {
98 NullPrint nop;
99 int len = writer(nop, ref);
100 return process(T_NOTIFY, url, len, writer, mime, ref);
101 }
102
104 int put(Url& url, const char* mime, const char* data, int len = -1) override {
105 DlnaLogger.log(DlnaLogLevel::Info, "put %s", url.url());
106 return process(T_PUT, url, mime, data, len);
107 }
108
110 int del(Url& url, const char* mime = nullptr, const char* data = nullptr,
111 int len = -1) override {
112 DlnaLogger.log(DlnaLogLevel::Info, "del %s", url.url());
113 return process(T_DELETE, url, mime, data, len);
114 }
115
117 int get(Url& url, const char* acceptMime = nullptr,
118 const char* data = nullptr, int len = -1) override {
119 DlnaLogger.log(DlnaLogLevel::Info, "get %s", str(url.url()));
120 this->accept = acceptMime;
121 return process(T_GET, url, nullptr, data, len);
122 }
123
125 int head(Url& url, const char* acceptMime = nullptr,
126 const char* data = nullptr, int len = -1) override {
127 DlnaLogger.log(DlnaLogLevel::Info, "head %s", url.url());
128 this->accept = acceptMime;
129 return process(T_HEAD, url, nullptr, data, len);
130 }
131
133 int subscribe(Url& url) override {
134 DlnaLogger.log(DlnaLogLevel::Info, "%s %s", methods[T_SUBSCRIBE], url.path());
135 return process(T_SUBSCRIBE, url, nullptr, nullptr, 0);
136 }
137
139 int unsubscribe(Url& url, const char* sid) override {
140 DlnaLogger.log(DlnaLogLevel::Info, "%s %s (SID=%s)", methods[T_UNSUBSCRIBE],
141 url.path(), sid);
142 if (sid != nullptr) {
143 request_header.put("SID", sid);
144 }
145 return process(T_UNSUBSCRIBE, url, nullptr, nullptr, 0);
146 }
147
149 int read(uint8_t* str, int len) override {
150 if (reply_header.isChunked()) {
151 return chunk_reader.read(*client_ptr, str, len);
152 } else {
153 return client_ptr->read(str, len);
154 }
155 }
156
158 int readln(uint8_t* str, int len, bool incl_nl = true) override {
159 if (reply_header.isChunked()) {
160 return chunk_reader.readln(*client_ptr, str, len);
161 } else {
162 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
163 }
164 }
165
167 HttpReplyHeader& reply() override { return reply_header; }
168
171
173 void setAgent(const char* agent) override { this->agent = agent; }
174
176 void setConnection(const char* connection) override {
177 this->connection = connection;
178 }
179
181 void setAcceptsEncoding(const char* enc) override {
182 this->accept_encoding = enc;
183 }
184
186 Client* client() override { return client_ptr; }
187
189 void setTimeout(int ms) override { client_ptr->setTimeout(ms); }
190
192
193 protected:
194 ClientType default_client;
195 Client* client_ptr = nullptr;
201 const char* agent = nullptr;
202 const char* connection = CON_CLOSE;
203 const char* accept = ACCEPT_ALL;
204 const char* accept_encoding = nullptr;
205
207 const char* str(const char* in) { return in == nullptr ? "" : in; }
208
210 virtual int connect(const char* ip, uint16_t port) {
211 this->client_ptr->setTimeout(DLNA_HTTP_REQUEST_TIMEOUT_MS);
212 if (!isKeepAlive() && this->client_ptr->connected()) {
213 stop();
214 }
215#ifdef ESP32
216 // clear input buffer
217 static_cast<ClientType*>(client_ptr)->clear();
218 // static_cast<ClientType*>(client_ptr)
219 // ->setConnectionTimeout(DLNA_HTTP_REQUEST_TIMEOUT_MS);
220 static_cast<ClientType*>(client_ptr)->setNoDelay(true);
221 int enable = 1;
222 static_cast<ClientType*>(client_ptr)
223 ->setSocketOption(SOL_SOCKET, SO_REUSEADDR, &enable,
224 sizeof(enable)); // Address reuse
225#endif
226 DlnaLogger.log(DlnaLogLevel::Info, "HttpRequest::connect %s:%d", ip, port);
227 uint64_t end = millis() + client_ptr->getTimeout();
228 bool rc = false;
229 for (int j = 0; j < 3; j++) {
230 rc = this->client_ptr->connect(ip, port);
231 if (rc) break;
232 delay(200);
233 }
234 if (!connected()) {
235 DlnaLogger.log(
236 DlnaLogLevel::Error, "Connected: %s (rc=%d) with timeout %ld",
237 connected() ? "true" : "false", rc, client_ptr->getTimeout());
238 } else {
239 DlnaLogger.log(
240 DlnaLogLevel::Debug, "Connected: %s (rc=%d) with timeout %ld",
241 connected() ? "true" : "false", rc, client_ptr->getTimeout());
242 }
243 return rc;
244 }
245
247 virtual int process(TinyMethodID action, Url& url, const char* mime,
248 const char* data, int len = -1) {
249 if (!connected()) {
250 DlnaLogger.log(DlnaLogLevel::Info, "Connecting to host %s port %d",
251 url.host(), url.port());
252
253 connect(url.host(), url.port());
254 }
255
256 if (!connected()) {
257 DlnaLogger.log(DlnaLogLevel::Info, "Connected: %s",
258 connected() ? "true" : "false");
259 return -1;
260 }
261
262 if (host_name.isEmpty()) {
263 host_name = url.host();
264 host_name.add(":");
266 }
267
268 request_header.setValues(action, url.path());
269 if (len == -1 && data != nullptr) {
270 len = strlen(data);
271 }
272 if (len > 0) {
274 }
275 if (!host_name.isEmpty()) {
277 }
278 if (agent != nullptr) {
280 }
281 if (accept_encoding != nullptr) {
283 }
284 if (mime != nullptr) {
286 }
287
290
292
293 if (len > 0) {
294 DlnaLogger.log(DlnaLogLevel::Info, "process - writing data: %d bytes",
295 len);
296 client_ptr->write((const uint8_t*)data, len);
297 }
298
300
301 // if we use chunked tranfer we need to read the first chunked length
302 if (reply_header.isChunked()) {
304 };
305
306 return reply_header.statusCode();
307 }
308
311 virtual int process(TinyMethodID method, Url& url, size_t len,
312 std::function<size_t(Print&, void*)> writer,
313 const char* mime = nullptr, void* ref = nullptr) {
314 DlnaLogger.log(DlnaLogLevel::Info, "%s %s", methods[method], url.url());
315
316 if (!connected()) {
317 connect(url.host(), url.port());
318 }
319
320 if (!connected()) {
321 DlnaLogger.log(DlnaLogLevel::Info, "Connected: %s",
322 connected() ? "true" : "false");
323 return -1;
324 }
325
326 if (host_name.isEmpty()) {
327 host_name = url.host();
328 host_name.add(":");
330 }
331
332 // prepare request header
333 request_header.setValues(method, url.path());
334 if (!host_name.isEmpty()) {
336 }
337 if (agent != nullptr) request_header.put(USER_AGENT, agent);
338 if (accept_encoding != nullptr)
340 if (mime != nullptr) request_header.put(CONTENT_TYPE, mime);
341 if (len > 0) request_header.put(CONTENT_LENGTH, len);
342
345
346 // write request header to client
348
349 // write callback (writer returns number of bytes written)
350 if (writer) {
351 size_t written = writer(*client_ptr, ref);
352#if DLNA_LOG_XML
353 writer(Serial, ref);
354#endif
355 if (written != len) {
356 DlnaLogger.log(DlnaLogLevel::Error,
357 "HttpRequest wrote %d bytes: expected %d", written, len);
358 }
359#if DLNA_CHECK_XML_LENGTH
360 StrPrint test;
361 size_t test_len = writer(test, ref);
362 if (strlen(test.c_str()) != len) {
363 DlnaLogger.log(
365 "HttpRequest test wrote %d bytes: expected %d / strlen: %d",
366 test_len, len, strlen(test.c_str()));
367 }
368#endif
369 }
370
371 // read reply header and prepare chunk reader if needed
373 if (reply_header.isChunked()) {
375 }
376
377 return reply_header.statusCode();
378 }
379};
380
381} // namespace tiny_dlna
382
383// using ma = tiny_dlna::HttpRequest;
Http might reply with chunks. So we need to dechunk the data. see https://en.wikipedia....
Definition: HttpChunkReader.h:13
void open(Client &client)
Definition: HttpChunkReader.h:28
virtual int read(Client &client, uint8_t *str, int len)
Definition: HttpChunkReader.h:35
virtual int readln(Client &client, uint8_t *str, int len, bool incl_nl=true)
Definition: HttpChunkReader.h:55
int available()
Definition: HttpChunkReader.h:73
void read(Client &in)
Definition: HttpHeader.h:233
int statusCode()
Definition: HttpHeader.h:223
bool isChunked()
Definition: HttpHeader.h:227
HttpHeader & put(const char *key, const char *value)
Definition: HttpHeader.h:105
void write(Client &out)
Definition: HttpHeader.h:267
virtual int readlnInternal(Stream &client, uint8_t *str, int len, bool incl_nl=true)
Definition: HttpLineReader.h:18
Reading and Writing of Http Replys.
Definition: HttpHeader.h:409
Reading and writing of Http Requests.
Definition: HttpHeader.h:355
HttpHeader & setValues(TinyMethodID id, const char *urlPath, const char *protocol=nullptr)
Definition: HttpHeader.h:358
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition: HttpRequest.h:31
Client * client_ptr
Definition: HttpRequest.h:195
void setConnection(const char *connection) override
Sets the connection type.
Definition: HttpRequest.h:176
HttpChunkReader chunk_reader
Definition: HttpRequest.h:199
HttpRequestHeader & request() override
Returns the request header.
Definition: HttpRequest.h:170
void stop() override
Stops the connection.
Definition: HttpRequest.h:74
HttpRequest()
Default constructor.
Definition: HttpRequest.h:34
const char * accept
Definition: HttpRequest.h:203
const char * str(const char *in)
Returns an empty string if input is null, otherwise returns the input.
Definition: HttpRequest.h:207
~HttpRequest() override
Destructor.
Definition: HttpRequest.h:46
HttpRequestHeader request_header
Definition: HttpRequest.h:197
void setHost(const char *host) override
Sets the host name for the requests.
Definition: HttpRequest.h:52
HttpReplyHeader & reply() override
Returns the reply header.
Definition: HttpRequest.h:167
HttpReplyHeader reply_header
Definition: HttpRequest.h:198
const char * connection
Definition: HttpRequest.h:202
int read(uint8_t *str, int len) override
Reads reply data.
Definition: HttpRequest.h:149
int unsubscribe(Url &url, const char *sid) override
Sends an UNSUBSCRIBE request.
Definition: HttpRequest.h:139
Url url
Definition: HttpRequest.h:196
int put(Url &url, const char *mime, const char *data, int len=-1) override
Sends a PUT request.
Definition: HttpRequest.h:104
void setAcceptsEncoding(const char *enc) override
Sets the accepted encodings.
Definition: HttpRequest.h:181
void setClient(Client &client) override
Sets the client to be used for the requests.
Definition: HttpRequest.h:49
int available() override
Returns the number of available bytes to read.
Definition: HttpRequest.h:66
ClientType default_client
Definition: HttpRequest.h:194
virtual int process(TinyMethodID method, Url &url, size_t len, std::function< size_t(Print &, void *)> writer, const char *mime=nullptr, void *ref=nullptr)
Definition: HttpRequest.h:311
bool connected() override
Checks if connected to the server.
Definition: HttpRequest.h:63
virtual int connect(const char *ip, uint16_t port)
opens a connection to the indicated host
Definition: HttpRequest.h:210
int post(Url &url, size_t len, std::function< size_t(Print &, void *)> writer, const char *mime=nullptr, void *ref=nullptr) override
Sends a POST request with streaming body.
Definition: HttpRequest.h:90
const char * accept_encoding
Definition: HttpRequest.h:204
int notify(Url &url, std::function< size_t(Print &, void *)> writer, const char *mime=nullptr, void *ref=nullptr) override
Sends a NOTIFY request with streaming body.
Definition: HttpRequest.h:96
int post(Url &url, const char *mime, const char *data, int len=-1) override
Sends a POST request with data.
Definition: HttpRequest.h:83
bool isKeepAlive()
Do not close the connection after request.
Definition: HttpRequest.h:191
int get(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1) override
Sends a GET request.
Definition: HttpRequest.h:117
HttpRequest(ClientType &client)
Constructor with specified client.
Definition: HttpRequest.h:40
Client * client() override
Returns the client pointer.
Definition: HttpRequest.h:186
const char * agent
Definition: HttpRequest.h:201
int del(Url &url, const char *mime=nullptr, const char *data=nullptr, int len=-1) override
Sends a DELETE request.
Definition: HttpRequest.h:110
int head(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1) override
Sends a HEAD request.
Definition: HttpRequest.h:125
int readln(uint8_t *str, int len, bool incl_nl=true) override
Reads reply data up to the next new line.
Definition: HttpRequest.h:158
Str host_name
Definition: HttpRequest.h:200
virtual int process(TinyMethodID action, Url &url, const char *mime, const char *data, int len=-1)
sends request and reads the reply_header from the server
Definition: HttpRequest.h:247
void setTimeout(int ms) override
Sets the timeout.
Definition: HttpRequest.h:189
int subscribe(Url &url) override
Sends a SUBSCRIBE request.
Definition: HttpRequest.h:133
void setAgent(const char *agent) override
Sets the user agent.
Definition: HttpRequest.h:173
Abstract interface for HTTP client request functionality.
Definition: IHttpRequest.h:21
Class with does not do any output: it can be used to determine the length of the output.
Definition: NullPrint.h:12
Print to a dynamic string.
Definition: StrPrint.h:13
const char * c_str()
Definition: StrPrint.h:39
A simple wrapper to provide string functions on char*. If the underlying char* is a const we do not a...
Definition: StrView.h:18
virtual bool equals(const char *str)
checks if the string equals indicated parameter string
Definition: StrView.h:177
Heap-backed string utility used throughout tiny_dlna.
Definition: Str.h:27
bool isEmpty() const
True if empty.
Definition: Str.h:54
void add(const char *append)
Append C-string (ignored if nullptr)
Definition: Str.h:96
const char * c_str() const
C-string pointer to internal buffer.
Definition: Str.h:88
URL parser which breaks a full url string up into its individual parts.
Definition: Url.h:18
int port()
Definition: Url.h:46
const char * host()
Definition: Url.h:41
const char * url()
Definition: Url.h:39
const char * path()
Definition: Url.h:40
#define DLNA_HTTP_REQUEST_TIMEOUT_MS
Define the default http request timeout.
Definition: dlna_config.h:25
Definition: Allocator.h:13
const char * CONTENT_TYPE
Definition: HttpHeader.h:16
const char * CON_KEEP_ALIVE
Definition: HttpHeader.h:20
const char * methods[]
Definition: HttpHeader.h:50
const char * CONTENT_LENGTH
Definition: HttpHeader.h:17
const char * CON_CLOSE
Definition: HttpHeader.h:19
const char * HOST_C
Definition: HttpHeader.h:29
TinyMethodID
Definition: HttpHeader.h:35
@ T_DELETE
Definition: HttpHeader.h:41
@ T_UNSUBSCRIBE
Definition: HttpHeader.h:46
@ T_SUBSCRIBE
Definition: HttpHeader.h:47
@ T_HEAD
Definition: HttpHeader.h:38
@ T_GET
Definition: HttpHeader.h:37
@ T_PUT
Definition: HttpHeader.h:40
@ T_POST
Definition: HttpHeader.h:39
@ T_NOTIFY
Definition: HttpHeader.h:48
const char * ACCEPT
Definition: HttpHeader.h:23
const char * ACCEPT_ENCODING
Definition: HttpHeader.h:30
const char * ACCEPT_ALL
Definition: HttpHeader.h:24
const char * USER_AGENT
Definition: HttpHeader.h:26
const char * CONNECTION
Definition: HttpHeader.h:18