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

@ -25,9 +25,22 @@
#include "ESP8266HTTPClient.h"
#include <ESP8266WiFi.h>
#include <StreamString.h>
#include <StreamDev.h>
#include <base64.h>
static int StreamReportToHttpClientReport (Stream::Report streamSendError)
{
switch (streamSendError)
{
case Stream::Report::TimedOut: return HTTPC_ERROR_READ_TIMEOUT;
case Stream::Report::ReadError: return HTTPC_ERROR_NO_STREAM;
case Stream::Report::WriteError: return HTTPC_ERROR_STREAM_WRITE;
case Stream::Report::ShortOperation: return HTTPC_ERROR_STREAM_WRITE;
case Stream::Report::Success: return 0;
}
return 0; // never reached, keep gcc quiet
}
/**
* constructor
*/
@ -429,24 +442,9 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
}
// send Payload if needed
if (payload && size > 0) {
size_t bytesWritten = 0;
const uint8_t *p = payload;
size_t originalSize = size;
while (bytesWritten < originalSize) {
int written;
int towrite = std::min((int)size, (int)HTTP_TCP_BUFFER_SIZE);
written = _client->write(p + bytesWritten, towrite);
if (written < 0) {
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
} else if (written == 0) {
return returnError(HTTPC_ERROR_CONNECTION_LOST);
}
bytesWritten += written;
size -= written;
}
}
// transfer all of it, with send-timeout
if (size && StreamConstPtr(payload, size).sendAll(_client) != size)
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
// handle Server Response (Header)
code = handleHeaderResponse();
@ -545,111 +543,12 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
}
int buff_size = HTTP_TCP_BUFFER_SIZE;
int len = size;
int bytesWritten = 0;
if(len == 0) {
len = -1;
}
// if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
buff_size = len;
}
// create buffer for read
uint8_t * buff = (uint8_t *) malloc(buff_size);
if(buff) {
// read all data from stream and send it to server
while(connected() && (stream->available() > 0) && (len > 0 || len == -1)) {
// get available data size
int sizeAvailable = stream->available();
if(sizeAvailable) {
int readBytes = sizeAvailable;
// read only the asked bytes
if(len > 0 && readBytes > len) {
readBytes = len;
}
// not read more the buffer can handle
if(readBytes > buff_size) {
readBytes = buff_size;
}
// read data
int bytesRead = stream->readBytes(buff, readBytes);
// write it to Stream
int bytesWrite = _client->write((const uint8_t *) buff, bytesRead);
bytesWritten += bytesWrite;
// are all Bytes a writen to stream ?
if(bytesWrite != bytesRead) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d retry...\n", bytesRead, bytesWrite);
// check for write error
if(_client->getWriteError()) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _client->getWriteError());
//reset write error for retry
_client->clearWriteError();
}
// some time for the stream
delay(1);
int leftBytes = (readBytes - bytesWrite);
// retry to send the missed bytes
bytesWrite = _client->write((const uint8_t *) (buff + bytesWrite), leftBytes);
bytesWritten += bytesWrite;
if(bytesWrite != leftBytes) {
// failed again
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d failed.\n", leftBytes, bytesWrite);
free(buff);
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
}
}
// check for write error
if(_client->getWriteError()) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _client->getWriteError());
free(buff);
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
}
// count bytes to read left
if(len > 0) {
len -= readBytes;
}
delay(0);
} else {
delay(1);
}
}
free(buff);
if(size && (int) size != bytesWritten) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload bytesWritten %d and size %zd mismatch!.\n", bytesWritten, size);
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] ERROR SEND PAYLOAD FAILED!");
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
} else {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload written: %d\n", bytesWritten);
}
} else {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] not enough ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
return returnError(HTTPC_ERROR_TOO_LESS_RAM);
// transfer all of it, with timeout
size_t transferred = stream->sendSize(_client, size);
if (transferred != size)
{
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d failed.\n", size, transferred);
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
}
// handle Server Response (Header)
@ -725,13 +624,13 @@ int HTTPClient::writeToStream(Stream * stream)
int ret = 0;
if(_transferEncoding == HTTPC_TE_IDENTITY) {
if(len > 0 || len == -1) {
ret = writeToStreamDataBlock(stream, len);
// len < 0: transfer all of it, with timeout
// len >= 0: max:len, with timeout
ret = _client->sendSize(stream, len);
// have we an error?
if(ret < 0) {
return returnError(ret);
}
// do we have an error?
if(_client->getLastSendReport() != Stream::Report::Success) {
return returnError(StreamReportToHttpClientReport(_client->getLastSendReport()));
}
} else if(_transferEncoding == HTTPC_TE_CHUNKED) {
int size = 0;
@ -754,11 +653,11 @@ int HTTPClient::writeToStream(Stream * stream)
// data left?
if(len > 0) {
int r = writeToStreamDataBlock(stream, len);
if(r < 0) {
// error in writeToStreamDataBlock
return returnError(r);
}
// read len bytes with timeout
int r = _client->sendSize(stream, len);
if (_client->getLastSendReport() != Stream::Report::Success)
// not all data transferred
return returnError(StreamReportToHttpClientReport(_client->getLastSendReport()));
ret += r;
} else {
@ -948,9 +847,7 @@ bool HTTPClient::connect(void)
{
if(_reuse && _canReuse && connected()) {
DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, reusing connection\n");
while(_client->available() > 0) {
_client->read();
}
_client->sendAvailable(devnull); // clear _client's output (all of it, no timeout)
return true;
}
@ -1032,7 +929,8 @@ bool HTTPClient::sendHeader(const char * type)
DEBUG_HTTPCLIENT("[HTTP-Client] sending request header\n-----\n%s-----\n", header.c_str());
return (_client->write((const uint8_t *) header.c_str(), header.length()) == header.length());
// transfer all of it, with timeout
return StreamConstPtr(header).sendAll(_client) == header.length();
}
/**
@ -1150,116 +1048,6 @@ int HTTPClient::handleHeaderResponse()
return HTTPC_ERROR_CONNECTION_LOST;
}
/**
* write one Data Block to Stream
* @param stream Stream *
* @param size int
* @return < 0 = error >= 0 = size written
*/
int HTTPClient::writeToStreamDataBlock(Stream * stream, int size)
{
int buff_size = HTTP_TCP_BUFFER_SIZE;
int len = size; // left size to read
int bytesWritten = 0;
// if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
buff_size = len;
}
// create buffer for read
uint8_t * buff = (uint8_t *) malloc(buff_size);
if(!buff) {
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] not enough ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
return HTTPC_ERROR_TOO_LESS_RAM;
}
// read all data from server
while(connected() && (len > 0 || len == -1))
{
int readBytes = len;
// not read more the buffer can handle
if(readBytes > buff_size) {
readBytes = buff_size;
}
// len == -1 or len > what is available, read only what is available
int av = _client->available();
if (readBytes < 0 || readBytes > av) {
readBytes = av;
}
// read data
int bytesRead = _client->readBytes(buff, readBytes);
if (!bytesRead)
{
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] input stream timeout\n");
free(buff);
return HTTPC_ERROR_READ_TIMEOUT;
}
// write it to Stream
int bytesWrite = stream->write(buff, bytesRead);
bytesWritten += bytesWrite;
// are all Bytes a writen to stream ?
if(bytesWrite != bytesRead) {
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] short write asked for %d but got %d retry...\n", bytesRead, bytesWrite);
// check for write error
if(stream->getWriteError()) {
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] stream write error %d\n", stream->getWriteError());
//reset write error for retry
stream->clearWriteError();
}
// some time for the stream
delay(1);
int leftBytes = (bytesRead - bytesWrite);
// retry to send the missed bytes
bytesWrite = stream->write((buff + bytesWrite), leftBytes);
bytesWritten += bytesWrite;
if(bytesWrite != leftBytes) {
// failed again
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] short write asked for %d but got %d failed.\n", leftBytes, bytesWrite);
free(buff);
return HTTPC_ERROR_STREAM_WRITE;
}
}
// check for write error
if(stream->getWriteError()) {
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] stream write error %d\n", stream->getWriteError());
free(buff);
return HTTPC_ERROR_STREAM_WRITE;
}
// count bytes to read left
if(len > 0) {
len -= bytesRead;
}
delay(0);
}
free(buff);
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] end of chunk or data (transferred: %d).\n", bytesWritten);
if((size > 0) && (size != bytesWritten)) {
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] transferred size %d and request size %d mismatch!.\n", bytesWritten, size);
return HTTPC_ERROR_STREAM_WRITE;
}
return bytesWritten;
}
/**
* called to handle error return, may disconnect the connection if still exists
* @param error

View File

@ -28,7 +28,7 @@
#include <memory>
#include <Arduino.h>
#include <StreamString.h>
#include <WiFiClient.h>
#ifdef DEBUG_ESP_HTTP_CLIENT
@ -148,8 +148,6 @@ typedef enum {
class TransportTraits;
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
class StreamString;
class HTTPClient
{
public: