1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-12 01:53:07 +03:00

Stream::send() (#6979)

This commit is contained in:
david gauchard
2021-03-15 01:36:20 +01:00
committed by GitHub
parent 4cc1472821
commit c720c0d9e8
48 changed files with 2136 additions and 650 deletions

View File

@ -28,6 +28,7 @@
#include "FS.h"
#include "base64.h"
#include "detail/RequestHandlersImpl.h"
#include <StreamDev.h>
static const char AUTHORIZATION_HEADER[] PROGMEM = "Authorization";
static const char qop_auth[] PROGMEM = "qop=auth";
@ -440,72 +441,69 @@ void ESP8266WebServerTemplate<ServerType>::_prepareHeader(String& response, int
_responseHeaders = "";
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send(int code, const char* content_type, const String& content) {
String header;
// Can we asume the following?
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
// _contentLength = CONTENT_LENGTH_UNKNOWN;
_prepareHeader(header, code, content_type, content.length());
_currentClient.write((const uint8_t *)header.c_str(), header.length());
if(content.length())
sendContent(content);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send_P(int code, PGM_P content_type, PGM_P content) {
size_t contentLength = 0;
if (content != NULL) {
contentLength = strlen_P(content);
}
String header;
char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
_prepareHeader(header, code, (const char* )type, contentLength);
_currentClient.write((const uint8_t *)header.c_str(), header.length());
if (contentLength) {
sendContent_P(content);
}
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) {
String header;
char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
_prepareHeader(header, code, (const char* )type, contentLength);
_currentClient.write((const uint8_t *)header.c_str(), header.length());
if (contentLength) {
sendContent_P(content, contentLength);
}
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send(int code, char* content_type, const String& content) {
send(code, (const char*)content_type, content);
return send(code, (const char*)content_type, content);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send(int code, const char* content_type, const String& content) {
return send(code, content_type, content.c_str(), content.length());
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send(int code, const String& content_type, const String& content) {
send(code, (const char*)content_type.c_str(), content);
return send(code, (const char*)content_type.c_str(), content);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::sendContent(const String& content) {
if (_currentMethod == HTTP_HEAD) return;
const char * footer = "\r\n";
size_t len = content.length();
StreamConstPtr ref(content.c_str(), content.length());
sendContent(&ref);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send(int code, const char* content_type, Stream* stream, size_t content_length /*= 0*/) {
String header;
if (content_length == 0)
content_length = std::max((ssize_t)0, stream->streamRemaining());
_prepareHeader(header, code, content_type, content_length);
size_t sent = StreamConstPtr(header).sendAll(&_currentClient);
if (sent != header.length())
DBGWS("HTTPServer: error: sent %zd on %u bytes\n", sent, header.length());
if (content_length)
return sendContent(stream, content_length);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send_P(int code, PGM_P content_type, PGM_P content) {
StreamConstPtr ref(content, strlen_P(content));
return send(code, String(content_type).c_str(), &ref);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) {
StreamConstPtr ref(content, contentLength);
return send(code, String(content_type).c_str(), &ref);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::sendContent(Stream* content, ssize_t content_length /* = 0*/) {
if (_currentMethod == HTTP_HEAD)
return;
if (content_length <= 0)
content_length = std::max((ssize_t)0, content->streamRemaining());
if(_chunked) {
char chunkSize[11];
sprintf(chunkSize, "%zx\r\n", len);
_currentClient.write((const uint8_t *)chunkSize, strlen(chunkSize));
_currentClient.printf("%zx\r\n", content_length);
}
_currentClient.write((const uint8_t *)content.c_str(), len);
if(_chunked){
_currentClient.write((const uint8_t *)footer, 2);
if (len == 0) {
ssize_t sent = content->sendSize(&_currentClient, content_length);
if (sent != content_length)
{
DBGWS("HTTPServer: error: short send after timeout (%d<%d)\n", sent, content_length);
}
if(_chunked) {
_currentClient.printf_P(PSTR("\r\n"));
if (content_length == 0) {
_chunked = false;
}
}
@ -518,19 +516,8 @@ void ESP8266WebServerTemplate<ServerType>::sendContent_P(PGM_P content) {
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::sendContent_P(PGM_P content, size_t size) {
const char * footer = "\r\n";
if(_chunked) {
char chunkSize[11];
sprintf(chunkSize, "%zx\r\n", size);
_currentClient.write((const uint8_t *)chunkSize, strlen(chunkSize));
}
_currentClient.write_P(content, size);
if(_chunked){
_currentClient.write((const uint8_t *)footer, 2);
if (size == 0) {
_chunked = false;
}
}
StreamConstPtr ptr(content, size);
return sendContent(&ptr, size);
}
template <typename ServerType>
@ -694,7 +681,7 @@ void ESP8266WebServerTemplate<ServerType>::_handleRequest() {
}
if (!handled) {
using namespace mime;
send(404, String(FPSTR(mimeTable[html].mimeType)), String(F("Not found: ")) + _currentUri);
send(404, FPSTR(mimeTable[html].mimeType), String(F("Not found: ")) + _currentUri);
handled = true;
}
if (handled) {

View File

@ -149,7 +149,7 @@ public:
// code - HTTP response code, can be 200 or 404
// content_type - HTTP content type, like "text/plain" or "image/png"
// content - actual content body
void send(int code, const char* content_type = NULL, const String& content = String(""));
void send(int code, const char* content_type = NULL, const String& content = emptyString);
void send(int code, char* content_type, const String& content);
void send(int code, const String& content_type, const String& content);
void send(int code, const char *content_type, const char *content) {
@ -164,14 +164,23 @@ public:
void send_P(int code, PGM_P content_type, PGM_P content);
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
void send(int code, const char* content_type, Stream* stream, size_t content_length = 0);
void send(int code, const char* content_type, Stream& stream, size_t content_length = 0);
void setContentLength(const size_t contentLength);
void sendHeader(const String& name, const String& value, bool first = false);
void sendContent(const String& content);
void sendContent(String& content) {
sendContent((const String&)content);
}
void sendContent_P(PGM_P content);
void sendContent_P(PGM_P content, size_t size);
void sendContent(const char *content) { sendContent_P(content); }
void sendContent(const char *content, size_t size) { sendContent_P(content, size); }
void sendContent(Stream* content, ssize_t content_length = 0);
void sendContent(Stream& content, ssize_t content_length = 0) { sendContent(&content, content_length); }
bool chunkedResponseModeStart_P (int code, PGM_P content_type) {
if (_currentVersion == 0)
// no chunk mode in HTTP/1.0
@ -220,6 +229,30 @@ public:
return contentLength;
}
// Implement GET and HEAD requests for stream
// Stream body on HTTP_GET but not on HTTP_HEAD requests.
template<typename T>
size_t stream(T &aStream, const String& contentType, HTTPMethod requestMethod, ssize_t size) {
setContentLength(size);
send(200, contentType, emptyString);
if (requestMethod == HTTP_GET)
size = aStream.sendSize(_currentClient, size);
return size;
}
// Implement GET and HEAD requests for stream
// Stream body on HTTP_GET but not on HTTP_HEAD requests.
template<typename T>
size_t stream(T& aStream, const String& contentType, HTTPMethod requestMethod = HTTP_GET) {
ssize_t size = aStream.size();
if (size < 0)
{
send(500, F("text/html"), F("input stream: undetermined size"));
return 0;
}
return stream(aStream, contentType, requestMethod, size);
}
static String responseCodeToString(const int code);
void addHook (HookFunction hook) {

View File

@ -37,22 +37,8 @@ namespace esp8266webserver {
template <typename ServerType>
static bool readBytesWithTimeout(typename ServerType::ClientType& client, size_t maxLength, String& data, int timeout_ms)
{
if (!data.reserve(maxLength + 1))
return false;
data[0] = 0; // data.clear()??
while (data.length() < maxLength) {
int tries = timeout_ms;
size_t avail;
while (!(avail = client.available()) && tries--)
delay(1);
if (!avail)
break;
if (data.length() + avail > maxLength)
avail = maxLength - data.length();
while (avail--)
data += (char)client.read();
}
return data.length() == maxLength;
S2Stream dataStream(data);
return client.sendSize(dataStream, maxLength, timeout_ms) == maxLength;
}
template <typename ServerType>