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:
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user