mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
Merge pull request #1333 from Links2004/httpClient
HTTPclient - add CHUNKED encoding support
This commit is contained in:
commit
b640044db2
@ -63,7 +63,7 @@ void loop() {
|
|||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
// httpCode will be negative on error
|
// httpCode will be negative on error
|
||||||
if(httpCode) {
|
if(httpCode > 0) {
|
||||||
// HTTP header has been send and Server response header has been handled
|
// HTTP header has been send and Server response header has been handled
|
||||||
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ void loop() {
|
|||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
// httpCode will be negative on error
|
// httpCode will be negative on error
|
||||||
if(httpCode) {
|
if(httpCode > 0) {
|
||||||
// HTTP header has been send and Server response header has been handled
|
// HTTP header has been send and Server response header has been handled
|
||||||
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ void loop() {
|
|||||||
//http.begin("192.168.1.12", 80, "/test.html");
|
//http.begin("192.168.1.12", 80, "/test.html");
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
if(httpCode) {
|
if(httpCode > 0) {
|
||||||
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||||
|
|
||||||
// file found at server
|
// file found at server
|
||||||
|
@ -50,7 +50,7 @@ void loop() {
|
|||||||
USE_SERIAL.print("[HTTP] GET...\n");
|
USE_SERIAL.print("[HTTP] GET...\n");
|
||||||
// start connection and send HTTP header
|
// start connection and send HTTP header
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
if(httpCode) {
|
if(httpCode > 0) {
|
||||||
// HTTP header has been send and Server response header has been handled
|
// HTTP header has been send and Server response header has been handled
|
||||||
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||||
|
|
||||||
|
@ -40,6 +40,9 @@ HTTPClient::HTTPClient() {
|
|||||||
_port = 0;
|
_port = 0;
|
||||||
|
|
||||||
_reuse = false;
|
_reuse = false;
|
||||||
|
_tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||||
|
_useHTTP10 = false;
|
||||||
|
|
||||||
_https = false;
|
_https = false;
|
||||||
|
|
||||||
_userAgent = "ESP8266HTTPClient";
|
_userAgent = "ESP8266HTTPClient";
|
||||||
@ -50,7 +53,7 @@ HTTPClient::HTTPClient() {
|
|||||||
_returnCode = 0;
|
_returnCode = 0;
|
||||||
_size = -1;
|
_size = -1;
|
||||||
_canReuse = false;
|
_canReuse = false;
|
||||||
_tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
_transferEncoding = HTTPC_TE_IDENTITY;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +267,16 @@ void HTTPClient::setTimeout(uint16_t timeout) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* use HTTP1.0
|
||||||
|
* @param timeout
|
||||||
|
*/
|
||||||
|
void HTTPClient::useHTTP10(bool useHTTP10) {
|
||||||
|
_useHTTP10 = useHTTP10;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send a GET request
|
* send a GET request
|
||||||
* @return http code
|
* @return http code
|
||||||
@ -296,7 +309,7 @@ int HTTPClient::POST(String payload) {
|
|||||||
int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) {
|
int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) {
|
||||||
// connect to server
|
// connect to server
|
||||||
if(!connect()) {
|
if(!connect()) {
|
||||||
return HTTPC_ERROR_CONNECTION_REFUSED;
|
return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(payload && size > 0) {
|
if(payload && size > 0) {
|
||||||
@ -305,18 +318,18 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) {
|
|||||||
|
|
||||||
// send Header
|
// send Header
|
||||||
if(!sendHeader(type)) {
|
if(!sendHeader(type)) {
|
||||||
return HTTPC_ERROR_SEND_HEADER_FAILED;
|
return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Payload if needed
|
// send Payload if needed
|
||||||
if(payload && size > 0) {
|
if(payload && size > 0) {
|
||||||
if(_tcp->write(&payload[0], size) != size) {
|
if(_tcp->write(&payload[0], size) != size) {
|
||||||
return HTTPC_ERROR_SEND_PAYLOAD_FAILED;
|
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle Server Response (Header)
|
// handle Server Response (Header)
|
||||||
return handleHeaderResponse();
|
return returnError(handleHeaderResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -329,12 +342,12 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) {
|
|||||||
int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) {
|
int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) {
|
||||||
|
|
||||||
if(!stream) {
|
if(!stream) {
|
||||||
return HTTPC_ERROR_NO_STREAM;
|
return returnError(HTTPC_ERROR_NO_STREAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect to server
|
// connect to server
|
||||||
if(!connect()) {
|
if(!connect()) {
|
||||||
return HTTPC_ERROR_CONNECTION_REFUSED;
|
return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(size > 0) {
|
if(size > 0) {
|
||||||
@ -343,10 +356,10 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) {
|
|||||||
|
|
||||||
// send Header
|
// send Header
|
||||||
if(!sendHeader(type)) {
|
if(!sendHeader(type)) {
|
||||||
return HTTPC_ERROR_SEND_HEADER_FAILED;
|
return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t buff_size = HTTP_TCP_BUFFER_SIZE;
|
int buff_size = HTTP_TCP_BUFFER_SIZE;
|
||||||
|
|
||||||
int len = size;
|
int len = size;
|
||||||
int bytesWritten = 0;
|
int bytesWritten = 0;
|
||||||
@ -369,25 +382,68 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) {
|
|||||||
while(connected() && (stream->available() > -1) && (len > 0 || len == -1)) {
|
while(connected() && (stream->available() > -1) && (len > 0 || len == -1)) {
|
||||||
|
|
||||||
// get available data size
|
// get available data size
|
||||||
size_t s = stream->available();
|
int sizeAvailable = stream->available();
|
||||||
|
|
||||||
if(len) {
|
if(sizeAvailable) {
|
||||||
s = ((s > len) ? len : s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s) {
|
int readBytes = sizeAvailable;
|
||||||
int c = stream->readBytes(buff, ((s > buff_size) ? buff_size : s));
|
|
||||||
|
|
||||||
// write it to Stream
|
// read only the asked bytes
|
||||||
int w = _tcp->write((const uint8_t *) buff, c);
|
if(len > 0 && readBytes > len) {
|
||||||
bytesWritten += w;
|
readBytes = len;
|
||||||
if(w != c) {
|
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write asked for %d but got %d\n", c, w);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = _tcp->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(_tcp->getWriteError()) {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _tcp->getWriteError());
|
||||||
|
|
||||||
|
//reset write error for retry
|
||||||
|
_tcp->clearWriteError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// some time for the stream
|
||||||
|
delay(1);
|
||||||
|
|
||||||
|
int leftBytes = (readBytes - bytesWrite);
|
||||||
|
|
||||||
|
// retry to send the missed bytes
|
||||||
|
bytesWrite = _tcp->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(_tcp->getWriteError()) {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _tcp->getWriteError());
|
||||||
|
free(buff);
|
||||||
|
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// count bytes to read left
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
len -= c;
|
len -= readBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(0);
|
delay(0);
|
||||||
@ -401,18 +457,18 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) {
|
|||||||
if(size && (int) size != bytesWritten) {
|
if(size && (int) size != bytesWritten) {
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload bytesWritten %d and size %d mismatch!.\n", bytesWritten, size);
|
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload bytesWritten %d and size %d mismatch!.\n", bytesWritten, size);
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] ERROR SEND PAYLOAD FAILED!");
|
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] ERROR SEND PAYLOAD FAILED!");
|
||||||
return HTTPC_ERROR_SEND_PAYLOAD_FAILED;
|
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload written: %d\n", bytesWritten);
|
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload written: %d\n", bytesWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] too less ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
|
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] too less ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
|
||||||
return HTTPC_ERROR_TOO_LESS_RAM;
|
return returnError(HTTPC_ERROR_TOO_LESS_RAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle Server Response (Header)
|
// handle Server Response (Header)
|
||||||
return handleHeaderResponse();
|
return returnError(handleHeaderResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -459,70 +515,73 @@ WiFiClient * HTTPClient::getStreamPtr(void) {
|
|||||||
int HTTPClient::writeToStream(Stream * stream) {
|
int HTTPClient::writeToStream(Stream * stream) {
|
||||||
|
|
||||||
if(!stream) {
|
if(!stream) {
|
||||||
return HTTPC_ERROR_NO_STREAM;
|
return returnError(HTTPC_ERROR_NO_STREAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connected()) {
|
if(!connected()) {
|
||||||
return HTTPC_ERROR_NOT_CONNECTED;
|
return returnError(HTTPC_ERROR_NOT_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get length of document (is -1 when Server sends no Content-Length header)
|
// get length of document (is -1 when Server sends no Content-Length header)
|
||||||
int len = _size;
|
int len = _size;
|
||||||
int bytesWritten = 0;
|
int ret = 0;
|
||||||
|
|
||||||
size_t buff_size = HTTP_TCP_BUFFER_SIZE;
|
if(_transferEncoding == HTTPC_TE_IDENTITY) {
|
||||||
|
ret = writeToStreamDataBlock(stream, len);
|
||||||
|
|
||||||
// if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
|
// have we an error?
|
||||||
if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
|
if(ret < 0) {
|
||||||
buff_size = len;
|
return returnError(ret);
|
||||||
}
|
}
|
||||||
|
} else if(_transferEncoding == HTTPC_TE_CHUNKED) {
|
||||||
// create buffer for read
|
int size = 0;
|
||||||
uint8_t * buff = (uint8_t *) malloc(buff_size);
|
while(1) {
|
||||||
|
if(!connected()) {
|
||||||
if(buff) {
|
return returnError(HTTPC_ERROR_CONNECTION_LOST);
|
||||||
// read all data from server
|
|
||||||
while(connected() && (len > 0 || len == -1)) {
|
|
||||||
|
|
||||||
// get available data size
|
|
||||||
size_t size = _tcp->available();
|
|
||||||
|
|
||||||
if(size) {
|
|
||||||
int c = _tcp->readBytes(buff, ((size > buff_size) ? buff_size : size));
|
|
||||||
|
|
||||||
// write it to Stream
|
|
||||||
int w = stream->write(buff, c);
|
|
||||||
bytesWritten += w;
|
|
||||||
if(w != c) {
|
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] short write asked for %d but got %d\n", c, w);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(len > 0) {
|
|
||||||
len -= c;
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(0);
|
|
||||||
} else {
|
|
||||||
delay(1);
|
|
||||||
}
|
}
|
||||||
|
String chunkHeader = _tcp->readStringUntil('\n');
|
||||||
|
|
||||||
|
if(chunkHeader.length() <= 0) {
|
||||||
|
return returnError(HTTPC_ERROR_READ_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkHeader.trim(); // remove \r
|
||||||
|
|
||||||
|
// read size of chunk
|
||||||
|
len = (uint32_t) strtol((const char *) chunkHeader.c_str(), NULL, 16);
|
||||||
|
size += len;
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client] read chunk len: %d\n", len);
|
||||||
|
|
||||||
|
// data left?
|
||||||
|
if(len > 0) {
|
||||||
|
int r = writeToStreamDataBlock(stream, len);
|
||||||
|
if(r < 0) {
|
||||||
|
// error in writeToStreamDataBlock
|
||||||
|
return returnError(r);
|
||||||
|
}
|
||||||
|
ret += r;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// if no length Header use global chunk size
|
||||||
|
if(_size <= 0) {
|
||||||
|
_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we have write all data out
|
||||||
|
if(ret != _size) {
|
||||||
|
return returnError(HTTPC_ERROR_STREAM_WRITE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buff);
|
|
||||||
|
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] connection closed or file end (written: %d).\n", bytesWritten);
|
|
||||||
|
|
||||||
if(_size && _size != bytesWritten) {
|
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] bytesWritten %d and size %d mismatch!.\n", bytesWritten, _size);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] too less ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
|
return returnError(HTTPC_ERROR_ENCODING);
|
||||||
return HTTPC_ERROR_TOO_LESS_RAM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end();
|
end();
|
||||||
return bytesWritten;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -567,6 +626,12 @@ String HTTPClient::errorToString(int error) {
|
|||||||
return String("no HTTP server");
|
return String("no HTTP server");
|
||||||
case HTTPC_ERROR_TOO_LESS_RAM:
|
case HTTPC_ERROR_TOO_LESS_RAM:
|
||||||
return String("too less ram");
|
return String("too less ram");
|
||||||
|
case HTTPC_ERROR_ENCODING:
|
||||||
|
return String("Transfer-Encoding not supported");
|
||||||
|
case HTTPC_ERROR_STREAM_WRITE:
|
||||||
|
return String("Stream write error");
|
||||||
|
case HTTPC_ERROR_READ_TIMEOUT:
|
||||||
|
return String("read Timeout");
|
||||||
default:
|
default:
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
@ -703,7 +768,15 @@ bool HTTPClient::sendHeader(const char * type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String header = String(type) + " " + _url + " HTTP/1.1\r\n"
|
String header = String(type) + " " + _url + " HTTP/1.";
|
||||||
|
|
||||||
|
if(_useHTTP10) {
|
||||||
|
header += "0";
|
||||||
|
} else {
|
||||||
|
header += "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
header += "\r\n"
|
||||||
"Host: " + _host + "\r\n"
|
"Host: " + _host + "\r\n"
|
||||||
"User-Agent: " + _userAgent + "\r\n"
|
"User-Agent: " + _userAgent + "\r\n"
|
||||||
"Connection: ";
|
"Connection: ";
|
||||||
@ -715,6 +788,10 @@ bool HTTPClient::sendHeader(const char * type) {
|
|||||||
}
|
}
|
||||||
header += "\r\n";
|
header += "\r\n";
|
||||||
|
|
||||||
|
if(!_useHTTP10) {
|
||||||
|
header += "Accept-Encoding: identity;q=1 chunked;q=0.1 *;q=0\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
if(_base64Authorization.length()) {
|
if(_base64Authorization.length()) {
|
||||||
header += "Authorization: Basic " + _base64Authorization + "\r\n";
|
header += "Authorization: Basic " + _base64Authorization + "\r\n";
|
||||||
}
|
}
|
||||||
@ -733,9 +810,10 @@ int HTTPClient::handleHeaderResponse() {
|
|||||||
if(!connected()) {
|
if(!connected()) {
|
||||||
return HTTPC_ERROR_NOT_CONNECTED;
|
return HTTPC_ERROR_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
|
String transferEncoding;
|
||||||
_returnCode = -1;
|
_returnCode = -1;
|
||||||
_size = -1;
|
_size = -1;
|
||||||
|
_transferEncoding = HTTPC_TE_IDENTITY;
|
||||||
|
|
||||||
while(connected()) {
|
while(connected()) {
|
||||||
size_t len = _tcp->available();
|
size_t len = _tcp->available();
|
||||||
@ -759,6 +837,10 @@ int HTTPClient::handleHeaderResponse() {
|
|||||||
_canReuse = headerValue.equalsIgnoreCase("keep-alive");
|
_canReuse = headerValue.equalsIgnoreCase("keep-alive");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(headerName.equalsIgnoreCase("Transfer-Encoding")) {
|
||||||
|
transferEncoding = headerValue;
|
||||||
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < _headerKeysCount; i++) {
|
for(size_t i = 0; i < _headerKeysCount; i++) {
|
||||||
if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
|
if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
|
||||||
_currentHeaders[i].value = headerValue;
|
_currentHeaders[i].value = headerValue;
|
||||||
@ -769,9 +851,22 @@ int HTTPClient::handleHeaderResponse() {
|
|||||||
|
|
||||||
if(headerLine == "") {
|
if(headerLine == "") {
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode);
|
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode);
|
||||||
if(_size) {
|
|
||||||
|
if(_size > 0) {
|
||||||
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size);
|
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(transferEncoding.length() > 0) {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Transfer-Encoding: %s\n", transferEncoding.c_str());
|
||||||
|
if(transferEncoding.equalsIgnoreCase("chunked")) {
|
||||||
|
_transferEncoding = HTTPC_TE_CHUNKED;
|
||||||
|
} else {
|
||||||
|
return HTTPC_ERROR_ENCODING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_transferEncoding = HTTPC_TE_IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
if(_returnCode) {
|
if(_returnCode) {
|
||||||
return _returnCode;
|
return _returnCode;
|
||||||
} else {
|
} else {
|
||||||
@ -787,3 +882,132 @@ int HTTPClient::handleHeaderResponse() {
|
|||||||
|
|
||||||
return HTTPC_ERROR_CONNECTION_LOST;
|
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;
|
||||||
|
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) {
|
||||||
|
// read all data from server
|
||||||
|
while(connected() && (len > 0 || len == -1)) {
|
||||||
|
|
||||||
|
// get available data size
|
||||||
|
size_t sizeAvailable = _tcp->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 = _tcp->readBytes(buff, readBytes);
|
||||||
|
|
||||||
|
// 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 = (readBytes - 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 -= readBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(0);
|
||||||
|
} else {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buff);
|
||||||
|
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] connection closed or file end (written: %d).\n", bytesWritten);
|
||||||
|
|
||||||
|
if((size > 0) && (size != bytesWritten)) {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] bytesWritten %d and size %d mismatch!.\n", bytesWritten, size);
|
||||||
|
return HTTPC_ERROR_STREAM_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] too less ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
|
||||||
|
return HTTPC_ERROR_TOO_LESS_RAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called to handle error return, may disconnect the connection if still exists
|
||||||
|
* @param error
|
||||||
|
* @return error
|
||||||
|
*/
|
||||||
|
int HTTPClient::returnError(int error) {
|
||||||
|
if(error < 0) {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][returnError] error(%d): %s\n", error, errorToString(error).c_str());
|
||||||
|
if(connected()) {
|
||||||
|
DEBUG_HTTPCLIENT("[HTTP-Client][returnError] tcp stop\n");
|
||||||
|
_tcp->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
@ -25,13 +25,13 @@
|
|||||||
#ifndef ESP8266HTTPClient_H_
|
#ifndef ESP8266HTTPClient_H_
|
||||||
#define ESP8266HTTPClient_H_
|
#define ESP8266HTTPClient_H_
|
||||||
|
|
||||||
//#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ )
|
#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ )
|
||||||
|
|
||||||
#ifndef DEBUG_HTTPCLIENT
|
#ifndef DEBUG_HTTPCLIENT
|
||||||
#define DEBUG_HTTPCLIENT(...)
|
#define DEBUG_HTTPCLIENT(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (1000)
|
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000)
|
||||||
|
|
||||||
/// HTTP client errors
|
/// HTTP client errors
|
||||||
#define HTTPC_ERROR_CONNECTION_REFUSED (-1)
|
#define HTTPC_ERROR_CONNECTION_REFUSED (-1)
|
||||||
@ -42,6 +42,9 @@
|
|||||||
#define HTTPC_ERROR_NO_STREAM (-6)
|
#define HTTPC_ERROR_NO_STREAM (-6)
|
||||||
#define HTTPC_ERROR_NO_HTTP_SERVER (-7)
|
#define HTTPC_ERROR_NO_HTTP_SERVER (-7)
|
||||||
#define HTTPC_ERROR_TOO_LESS_RAM (-8)
|
#define HTTPC_ERROR_TOO_LESS_RAM (-8)
|
||||||
|
#define HTTPC_ERROR_ENCODING (-9)
|
||||||
|
#define HTTPC_ERROR_STREAM_WRITE (-10)
|
||||||
|
#define HTTPC_ERROR_READ_TIMEOUT (-11)
|
||||||
|
|
||||||
/// size for the stream handling
|
/// size for the stream handling
|
||||||
#define HTTP_TCP_BUFFER_SIZE (1460)
|
#define HTTP_TCP_BUFFER_SIZE (1460)
|
||||||
@ -108,6 +111,11 @@ typedef enum {
|
|||||||
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
|
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||||
} t_http_codes;
|
} t_http_codes;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HTTPC_TE_IDENTITY,
|
||||||
|
HTTPC_TE_CHUNKED
|
||||||
|
} transferEncoding_t;
|
||||||
|
|
||||||
class HTTPClient {
|
class HTTPClient {
|
||||||
public:
|
public:
|
||||||
HTTPClient();
|
HTTPClient();
|
||||||
@ -129,6 +137,8 @@ class HTTPClient {
|
|||||||
void setAuthorization(const char * auth);
|
void setAuthorization(const char * auth);
|
||||||
void setTimeout(uint16_t timeout);
|
void setTimeout(uint16_t timeout);
|
||||||
|
|
||||||
|
void useHTTP10(bool usehttp10 = true);
|
||||||
|
|
||||||
/// request handling
|
/// request handling
|
||||||
int GET();
|
int GET();
|
||||||
int POST(uint8_t * payload, size_t size);
|
int POST(uint8_t * payload, size_t size);
|
||||||
@ -172,6 +182,7 @@ class HTTPClient {
|
|||||||
uint16_t _port;
|
uint16_t _port;
|
||||||
bool _reuse;
|
bool _reuse;
|
||||||
uint16_t _tcpTimeout;
|
uint16_t _tcpTimeout;
|
||||||
|
bool _useHTTP10;
|
||||||
|
|
||||||
String _url;
|
String _url;
|
||||||
bool _https;
|
bool _https;
|
||||||
@ -188,11 +199,13 @@ class HTTPClient {
|
|||||||
int _returnCode;
|
int _returnCode;
|
||||||
int _size;
|
int _size;
|
||||||
bool _canReuse;
|
bool _canReuse;
|
||||||
|
transferEncoding_t _transferEncoding;
|
||||||
|
|
||||||
|
int returnError(int error);
|
||||||
bool connect(void);
|
bool connect(void);
|
||||||
bool sendHeader(const char * type);
|
bool sendHeader(const char * type);
|
||||||
int handleHeaderResponse();
|
int handleHeaderResponse();
|
||||||
|
int writeToStreamDataBlock(Stream * stream, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,6 +146,9 @@ t_httpUpdate_return ESP8266HTTPUpdate::handleUpdate(HTTPClient * http, const cha
|
|||||||
|
|
||||||
t_httpUpdate_return ret = HTTP_UPDATE_FAILED;
|
t_httpUpdate_return ret = HTTP_UPDATE_FAILED;
|
||||||
|
|
||||||
|
// use HTTP/1.0 for update since the update handler not support any transfer Encoding
|
||||||
|
http->useHTTP10(true);
|
||||||
|
http->setTimeout(8000);
|
||||||
http->setUserAgent("ESP8266-http-Update");
|
http->setUserAgent("ESP8266-http-Update");
|
||||||
http->addHeader("x-ESP8266-STA-MAC", WiFi.macAddress());
|
http->addHeader("x-ESP8266-STA-MAC", WiFi.macAddress());
|
||||||
http->addHeader("x-ESP8266-AP-MAC", WiFi.softAPmacAddress());
|
http->addHeader("x-ESP8266-AP-MAC", WiFi.softAPmacAddress());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user