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
11namespace tiny_dlna {
12
26template <typename ClientType>
27class HttpRequest : public IHttpRequest {
28 public:
31 DlnaLogger.log(DlnaLogLevel::Debug, "HttpRequest (default client)");
33 }
34
36 explicit HttpRequest(ClientType& client) {
37 DlnaLogger.log(DlnaLogLevel::Debug, "HttpRequest");
39 }
40
42 ~HttpRequest() override { stop(); }
43
45 void setClient(Client& client) override { this->client_ptr = &client; }
46
48 void setHost(const char* host) override {
49 DlnaLogger.log(DlnaLogLevel::Info, "HttpRequest::setHost: ", host);
50 this->host_name = host;
51 }
52
54 operator bool() override {
55 return client_ptr != nullptr && static_cast<bool>(*client_ptr);
56 }
57
59 bool connected() override { return client_ptr->connected(); }
60
62 int available() override {
63 if (reply_header.isChunked()) {
64 return chunk_reader.available();
65 }
66 return client_ptr->available();
67 }
68
70 void stop() override {
71 DlnaLogger.log(DlnaLogLevel::Info, "HttpRequest::stop");
72 if (client_ptr != nullptr) {
73 client_ptr->stop();
74 }
75 }
76
78 int post(Url& url, const char* mime, const char* data,
79 int len = -1) override {
80 DlnaLogger.log(DlnaLogLevel::Info, "post %s", url.url());
81 return process(T_POST, url, mime, data, len);
82 }
83
85 int post(Url& url, size_t len, std::function<size_t(Print&, void*)> writer,
86 const char* mime = nullptr, void* ref = nullptr) override {
87 return process(T_POST, url, len, writer, mime, ref);
88 }
89
91 int notify(Url& url, std::function<size_t(Print&, void*)> writer,
92 const char* mime = nullptr, void* ref = nullptr) override {
93 NullPrint nop;
94 int len = writer(nop, ref);
95 return process(T_NOTIFY, url, len, writer, mime, ref);
96 }
97
99 int put(Url& url, const char* mime, const char* data, int len = -1) override {
100 DlnaLogger.log(DlnaLogLevel::Info, "put %s", url.url());
101 return process(T_PUT, url, mime, data, len);
102 }
103
105 int del(Url& url, const char* mime = nullptr, const char* data = nullptr,
106 int len = -1) override {
107 DlnaLogger.log(DlnaLogLevel::Info, "del %s", url.url());
108 return process(T_DELETE, url, mime, data, len);
109 }
110
112 int get(Url& url, const char* acceptMime = nullptr,
113 const char* data = nullptr, int len = -1) override {
114 DlnaLogger.log(DlnaLogLevel::Info, "get %s", str(url.url()));
115 this->accept = acceptMime;
116 return process(T_GET, url, nullptr, data, len);
117 }
118
120 int head(Url& url, const char* acceptMime = nullptr,
121 const char* data = nullptr, int len = -1) override {
122 DlnaLogger.log(DlnaLogLevel::Info, "head %s", url.url());
123 this->accept = acceptMime;
124 return process(T_HEAD, url, nullptr, data, len);
125 }
126
128 int subscribe(Url& url) override {
129 DlnaLogger.log(DlnaLogLevel::Info, "post %s", url.url());
130 return process(T_SUBSCRIBE, url, nullptr, nullptr, 0);
131 }
132
134 int unsubscribe(Url& url, const char* sid) override {
135 DlnaLogger.log(DlnaLogLevel::Info, "unsubscribe %s (SID=%s)", url.url(),
136 sid);
137 if (sid != nullptr) {
138 request_header.put("SID", sid);
139 }
140 return process(T_UNSUBSCRIBE, url, nullptr, nullptr, 0);
141 }
142
144 int read(uint8_t* str, int len) override {
145 if (reply_header.isChunked()) {
146 return chunk_reader.read(*client_ptr, str, len);
147 } else {
148 return client_ptr->read(str, len);
149 }
150 }
151
153 int readln(uint8_t* str, int len, bool incl_nl = true) override {
154 if (reply_header.isChunked()) {
155 return chunk_reader.readln(*client_ptr, str, len);
156 } else {
157 return chunk_reader.readlnInternal(*client_ptr, str, len, incl_nl);
158 }
159 }
160
162 HttpReplyHeader& reply() override { return reply_header; }
163
166
168 void setAgent(const char* agent) override { this->agent = agent; }
169
171 void setConnection(const char* connection) override {
172 this->connection = connection;
173 }
174
176 void setAcceptsEncoding(const char* enc) override {
177 this->accept_encoding = enc;
178 }
179
181 Client* client() override { return client_ptr; }
182
184 void setTimeout(int ms) override { client_ptr->setTimeout(ms); }
185
186 protected:
187 ClientType default_client;
188 Client* client_ptr = nullptr;
194 const char* agent = nullptr;
195 const char* connection = CON_CLOSE;
196 const char* accept = ACCEPT_ALL;
197 const char* accept_encoding = nullptr;
198
200 const char* str(const char* in) { return in == nullptr ? "" : in; }
201
203 virtual int connect(const char* ip, uint16_t port) {
204 DlnaLogger.log(DlnaLogLevel::Info, "HttpRequest::connect %s", ip);
205 int rc = this->client_ptr->connect(ip, port);
206 uint64_t end = millis() + client_ptr->getTimeout();
207 DlnaLogger.log(DlnaLogLevel::Info, "Connected: %s (rc=%d) with timeout %ld",
208 connected() ? "true" : "false", rc,
209 client_ptr->getTimeout());
210 return rc;
211 }
212
214 virtual int process(TinyMethodID action, Url& url, const char* mime,
215 const char* data, int len = -1) {
216 if (!connected()) {
217 DlnaLogger.log(DlnaLogLevel::Info, "Connecting to host %s port %d",
218 url.host(), url.port());
219
220 connect(url.host(), url.port());
221 }
222
223 if (!connected()) {
224 DlnaLogger.log(DlnaLogLevel::Info, "Connected: %s",
225 connected() ? "true" : "false");
226 return -1;
227 }
228
229 if (host_name.isEmpty()) {
230 host_name = url.host();
231 host_name.add(":");
233 }
234
235 request_header.setValues(action, url.path());
236 if (len == -1 && data != nullptr) {
237 len = strlen(data);
238 }
239 if (len > 0) {
241 }
242 if (!host_name.isEmpty()) {
244 }
245 if (agent != nullptr) {
247 }
248 if (accept_encoding != nullptr) {
250 }
251 if (mime != nullptr) {
253 }
254
257
259
260 if (len > 0) {
261 DlnaLogger.log(DlnaLogLevel::Info, "process - writing data: %d bytes",
262 len);
263 client_ptr->write((const uint8_t*)data, len);
264 }
265
267
268 // if we use chunked tranfer we need to read the first chunked length
269 if (reply_header.isChunked()) {
271 };
272
273 return reply_header.statusCode();
274 }
275
278 virtual int process(TinyMethodID method, Url& url, size_t len,
279 std::function<size_t(Print&, void*)> writer,
280 const char* mime = nullptr, void* ref = nullptr) {
281 DlnaLogger.log(DlnaLogLevel::Info, "%s %s", methods[method], url.url());
282
283 if (!connected()) {
284 DlnaLogger.log(DlnaLogLevel::Info,
285 "HttpRequest::connecting to host %s port %d", url.host(),
286 url.port());
287 connect(url.host(), url.port());
288 }
289
290 if (!connected()) {
291 DlnaLogger.log(DlnaLogLevel::Info, "Connected: %s",
292 connected() ? "true" : "false");
293 return -1;
294 }
295
296 if (host_name.isEmpty()) {
297 host_name = url.host();
298 host_name.add(":");
300 }
301
302 // prepare request header
303 request_header.setValues(method, url.path());
304 if (!host_name.isEmpty()) {
306 }
307 if (agent != nullptr) request_header.put(USER_AGENT, agent);
308 if (accept_encoding != nullptr)
310 if (mime != nullptr) request_header.put(CONTENT_TYPE, mime);
311 if (len > 0) request_header.put(CONTENT_LENGTH, len);
312
315
316 // write request header to client
318
319 // write callback (writer returns number of bytes written)
320 if (writer) {
321 size_t written = writer(*client_ptr, ref);
322#if DLNA_LOG_XML
323 writer(Serial, ref);
324#endif
325 if (written != len) {
326 DlnaLogger.log(DlnaLogLevel::Error,
327 "HttpRequest wrote %d bytes: expected %d", written, len);
328 }
329#if DLNA_CHECK_XML_LENGTH
330 StrPrint test;
331 size_t test_len = writer(test, ref);
332 if (strlen(test.c_str()) != len) {
333 DlnaLogger.log(DlnaLogLevel::Error,
334 "HttpRequest test wrote %d bytes: expected %d / strlen: %d", test_len, len, strlen(test.c_str()));
335 }
336#endif
337 }
338
339 // read reply header and prepare chunk reader if needed
341 if (reply_header.isChunked()) {
343 }
344
345 return reply_header.statusCode();
346 }
347};
348
349} // namespace tiny_dlna
350
351// 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:412
Reading and writing of Http Requests.
Definition: HttpHeader.h:358
HttpHeader & setValues(TinyMethodID id, const char *urlPath, const char *protocol=nullptr)
Definition: HttpHeader.h:361
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition: HttpRequest.h:27
Client * client_ptr
Definition: HttpRequest.h:188
void setConnection(const char *connection) override
Sets the connection type.
Definition: HttpRequest.h:171
HttpChunkReader chunk_reader
Definition: HttpRequest.h:192
HttpRequestHeader & request() override
Returns the request header.
Definition: HttpRequest.h:165
void stop() override
Stops the connection.
Definition: HttpRequest.h:70
HttpRequest()
Default constructor.
Definition: HttpRequest.h:30
const char * accept
Definition: HttpRequest.h:196
const char * str(const char *in)
Returns an empty string if input is null, otherwise returns the input.
Definition: HttpRequest.h:200
~HttpRequest() override
Destructor.
Definition: HttpRequest.h:42
HttpRequestHeader request_header
Definition: HttpRequest.h:190
void setHost(const char *host) override
Sets the host name for the requests.
Definition: HttpRequest.h:48
HttpReplyHeader & reply() override
Returns the reply header.
Definition: HttpRequest.h:162
HttpReplyHeader reply_header
Definition: HttpRequest.h:191
const char * connection
Definition: HttpRequest.h:195
int read(uint8_t *str, int len) override
Reads reply data.
Definition: HttpRequest.h:144
int unsubscribe(Url &url, const char *sid) override
Sends an UNSUBSCRIBE request.
Definition: HttpRequest.h:134
Url url
Definition: HttpRequest.h:189
int put(Url &url, const char *mime, const char *data, int len=-1) override
Sends a PUT request.
Definition: HttpRequest.h:99
void setAcceptsEncoding(const char *enc) override
Sets the accepted encodings.
Definition: HttpRequest.h:176
void setClient(Client &client) override
Sets the client to be used for the requests.
Definition: HttpRequest.h:45
int available() override
Returns the number of available bytes to read.
Definition: HttpRequest.h:62
ClientType default_client
Definition: HttpRequest.h:187
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:278
bool connected() override
Checks if connected to the server.
Definition: HttpRequest.h:59
virtual int connect(const char *ip, uint16_t port)
opens a connection to the indicated host
Definition: HttpRequest.h:203
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:85
const char * accept_encoding
Definition: HttpRequest.h:197
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:91
int post(Url &url, const char *mime, const char *data, int len=-1) override
Sends a POST request with data.
Definition: HttpRequest.h:78
int get(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1) override
Sends a GET request.
Definition: HttpRequest.h:112
HttpRequest(ClientType &client)
Constructor with specified client.
Definition: HttpRequest.h:36
Client * client() override
Returns the client pointer.
Definition: HttpRequest.h:181
const char * agent
Definition: HttpRequest.h:194
int del(Url &url, const char *mime=nullptr, const char *data=nullptr, int len=-1) override
Sends a DELETE request.
Definition: HttpRequest.h:105
int head(Url &url, const char *acceptMime=nullptr, const char *data=nullptr, int len=-1) override
Sends a HEAD request.
Definition: HttpRequest.h:120
int readln(uint8_t *str, int len, bool incl_nl=true) override
Reads reply data up to the next new line.
Definition: HttpRequest.h:153
Str host_name
Definition: HttpRequest.h:193
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:214
void setTimeout(int ms) override
Sets the timeout.
Definition: HttpRequest.h:184
int subscribe(Url &url) override
Sends a SUBSCRIBE request.
Definition: HttpRequest.h:128
void setAgent(const char *agent) override
Sets the user agent.
Definition: HttpRequest.h:168
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
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
Definition: Allocator.h:13
const char * CONTENT_TYPE
Definition: HttpHeader.h:16
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