Skip to content

Commit cc00376

Browse files
committed
add CHUNKED encoding support too http client (esp8266#1324)
HTTP Client - fix examples increase default timeout to 5000ms
1 parent bbaed29 commit cc00376

File tree

6 files changed

+148
-57
lines changed

6 files changed

+148
-57
lines changed

libraries/ESP8266HTTPClient/examples/Authorization/Authorization.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void loop() {
6363
int httpCode = http.GET();
6464

6565
// httpCode will be negative on error
66-
if(httpCode) {
66+
if(httpCode > 0) {
6767
// HTTP header has been send and Server response header has been handled
6868
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
6969

libraries/ESP8266HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void loop() {
5151
int httpCode = http.GET();
5252

5353
// httpCode will be negative on error
54-
if(httpCode) {
54+
if(httpCode > 0) {
5555
// HTTP header has been send and Server response header has been handled
5656
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
5757

libraries/ESP8266HTTPClient/examples/ReuseConnection/ReuseConnection.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void loop() {
4848
//http.begin("192.168.1.12", 80, "/test.html");
4949

5050
int httpCode = http.GET();
51-
if(httpCode) {
51+
if(httpCode > 0) {
5252
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
5353

5454
// file found at server

libraries/ESP8266HTTPClient/examples/StreamHttpClient/StreamHttpClient.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void loop() {
5050
USE_SERIAL.print("[HTTP] GET...\n");
5151
// start connection and send HTTP header
5252
int httpCode = http.GET();
53-
if(httpCode) {
53+
if(httpCode > 0) {
5454
// HTTP header has been send and Server response header has been handled
5555
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
5656

libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp

+132-50
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ HTTPClient::HTTPClient() {
4040
_port = 0;
4141

4242
_reuse = false;
43+
_tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
44+
4345
_https = false;
4446

4547
_userAgent = "ESP8266HTTPClient";
@@ -50,7 +52,7 @@ HTTPClient::HTTPClient() {
5052
_returnCode = 0;
5153
_size = -1;
5254
_canReuse = false;
53-
_tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
55+
_transferEncoding = HTTPC_TE_IDENTITY;
5456

5557
}
5658

@@ -468,61 +470,36 @@ int HTTPClient::writeToStream(Stream * stream) {
468470

469471
// get length of document (is -1 when Server sends no Content-Length header)
470472
int len = _size;
471-
int bytesWritten = 0;
472-
473-
size_t buff_size = HTTP_TCP_BUFFER_SIZE;
474-
475-
// if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
476-
if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
477-
buff_size = len;
478-
}
479-
480-
// create buffer for read
481-
uint8_t * buff = (uint8_t *) malloc(buff_size);
482-
483-
if(buff) {
484-
// read all data from server
485-
while(connected() && (len > 0 || len == -1)) {
486-
487-
// get available data size
488-
size_t size = _tcp->available();
489-
490-
if(size) {
491-
int c = _tcp->readBytes(buff, ((size > buff_size) ? buff_size : size));
492-
493-
// write it to Stream
494-
int w = stream->write(buff, c);
495-
bytesWritten += w;
496-
if(w != c) {
497-
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] short write asked for %d but got %d\n", c, w);
498-
break;
499-
}
500-
501-
if(len > 0) {
502-
len -= c;
473+
int ret = 0;
474+
475+
if(_transferEncoding == HTTPC_TE_IDENTITY) {
476+
ret = writeToStreamDataBlock(stream, len);
477+
} else if(_transferEncoding == HTTPC_TE_CHUNKED) {
478+
while(1) {
479+
String chunkHeader = _tcp->readStringUntil('\n');
480+
chunkHeader.trim(); // remove \r
481+
482+
// read size of chunk
483+
len = (uint32_t) strtol((const char *) chunkHeader.c_str(), NULL, 16);
484+
DEBUG_HTTPCLIENT("[HTTP-Client] read chunk len: %d\n", len);
485+
if(len > 0) {
486+
int r = writeToStreamDataBlock(stream, len);
487+
if(r < 0) {
488+
// error in writeToStreamDataBlock
489+
return r;
503490
}
504-
505-
delay(0);
491+
ret += r;
506492
} else {
507-
delay(1);
493+
break;
508494
}
495+
delay(0);
509496
}
510-
511-
free(buff);
512-
513-
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] connection closed or file end (written: %d).\n", bytesWritten);
514-
515-
if(_size && _size != bytesWritten) {
516-
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] bytesWritten %d and size %d mismatch!.\n", bytesWritten, _size);
517-
}
518-
519497
} else {
520-
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] too less ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
521-
return HTTPC_ERROR_TOO_LESS_RAM;
498+
return HTTPC_ERROR_ENCODING;
522499
}
523500

524501
end();
525-
return bytesWritten;
502+
return ret;
526503
}
527504

528505
/**
@@ -567,6 +544,8 @@ String HTTPClient::errorToString(int error) {
567544
return String("no HTTP server");
568545
case HTTPC_ERROR_TOO_LESS_RAM:
569546
return String("too less ram");
547+
case HTTPC_ERROR_ENCODING:
548+
return String("Transfer-Encoding not supported");
570549
default:
571550
return String();
572551
}
@@ -706,6 +685,7 @@ bool HTTPClient::sendHeader(const char * type) {
706685
String header = String(type) + " " + _url + " HTTP/1.1\r\n"
707686
"Host: " + _host + "\r\n"
708687
"User-Agent: " + _userAgent + "\r\n"
688+
"Accept-Encoding: identity;q=1 chunked;q=0.1 *;q=0\r\n"
709689
"Connection: ";
710690

711691
if(_reuse) {
@@ -733,9 +713,10 @@ int HTTPClient::handleHeaderResponse() {
733713
if(!connected()) {
734714
return HTTPC_ERROR_NOT_CONNECTED;
735715
}
736-
716+
String transferEncoding;
737717
_returnCode = -1;
738718
_size = -1;
719+
_transferEncoding = HTTPC_TE_IDENTITY;
739720

740721
while(connected()) {
741722
size_t len = _tcp->available();
@@ -759,6 +740,10 @@ int HTTPClient::handleHeaderResponse() {
759740
_canReuse = headerValue.equalsIgnoreCase("keep-alive");
760741
}
761742

743+
if(headerName.equalsIgnoreCase("Transfer-Encoding")) {
744+
transferEncoding = headerValue;
745+
}
746+
762747
for(size_t i = 0; i < _headerKeysCount; i++) {
763748
if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
764749
_currentHeaders[i].value = headerValue;
@@ -769,9 +754,22 @@ int HTTPClient::handleHeaderResponse() {
769754

770755
if(headerLine == "") {
771756
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode);
772-
if(_size) {
757+
758+
if(_size > 0) {
773759
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size);
774760
}
761+
762+
if(transferEncoding.length() > 0) {
763+
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Transfer-Encoding: %s\n", transferEncoding.c_str());
764+
if(transferEncoding.equalsIgnoreCase("chunked")) {
765+
_transferEncoding = HTTPC_TE_CHUNKED;
766+
} else {
767+
return HTTPC_ERROR_ENCODING;
768+
}
769+
} else {
770+
_transferEncoding = HTTPC_TE_IDENTITY;
771+
}
772+
775773
if(_returnCode) {
776774
return _returnCode;
777775
} else {
@@ -787,3 +785,87 @@ int HTTPClient::handleHeaderResponse() {
787785

788786
return HTTPC_ERROR_CONNECTION_LOST;
789787
}
788+
789+
790+
791+
/**
792+
*
793+
* @param stream
794+
* @param len
795+
* @return
796+
*/
797+
int HTTPClient::writeToStreamDataBlock(Stream * stream, int size) {
798+
int buff_size = HTTP_TCP_BUFFER_SIZE;
799+
int len = size;
800+
int bytesWritten = 0;
801+
802+
// if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
803+
if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
804+
buff_size = len;
805+
}
806+
807+
// create buffer for read
808+
uint8_t * buff = (uint8_t *) malloc(buff_size);
809+
810+
if(buff) {
811+
// read all data from server
812+
while(connected() && (len > 0 || len == -1)) {
813+
814+
// get available data size
815+
size_t sizeAvailable = _tcp->available();
816+
817+
if(sizeAvailable) {
818+
819+
int readBytes = sizeAvailable;
820+
821+
// read only the asked bytes
822+
if(readBytes > len) {
823+
readBytes = len;
824+
}
825+
826+
// not read more the buffer can handle
827+
if(readBytes > buff_size) {
828+
readBytes = buff_size;
829+
}
830+
831+
// read data
832+
int c = _tcp->readBytes(buff, readBytes);
833+
834+
// write it to Stream
835+
int w = stream->write(buff, c);
836+
bytesWritten += w;
837+
if(w != c) {
838+
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] short write asked for %d but got %d\n", c, w);
839+
break;
840+
}
841+
842+
if(stream->getWriteError()) {
843+
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] stream write error %d\n", stream->getWriteError());
844+
break;
845+
}
846+
847+
if(len > 0) {
848+
len -= c;
849+
}
850+
851+
delay(0);
852+
} else {
853+
delay(1);
854+
}
855+
}
856+
857+
free(buff);
858+
859+
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] connection closed or file end (written: %d).\n", bytesWritten);
860+
861+
if((size > 0) && (size != bytesWritten)) {
862+
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] bytesWritten %d and size %d mismatch!.\n", bytesWritten, size);
863+
}
864+
865+
} else {
866+
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] too less ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
867+
return HTTPC_ERROR_TOO_LESS_RAM;
868+
}
869+
870+
return bytesWritten;
871+
}

libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h

+12-3
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
#ifndef ESP8266HTTPClient_H_
2626
#define ESP8266HTTPClient_H_
2727

28-
//#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ )
28+
#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ )
2929

3030
#ifndef DEBUG_HTTPCLIENT
3131
#define DEBUG_HTTPCLIENT(...)
3232
#endif
3333

34-
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (1000)
34+
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000)
3535

3636
/// HTTP client errors
3737
#define HTTPC_ERROR_CONNECTION_REFUSED (-1)
@@ -42,6 +42,8 @@
4242
#define HTTPC_ERROR_NO_STREAM (-6)
4343
#define HTTPC_ERROR_NO_HTTP_SERVER (-7)
4444
#define HTTPC_ERROR_TOO_LESS_RAM (-8)
45+
#define HTTPC_ERROR_ENCODING (-9)
46+
4547

4648
/// size for the stream handling
4749
#define HTTP_TCP_BUFFER_SIZE (1460)
@@ -108,6 +110,11 @@ typedef enum {
108110
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
109111
} t_http_codes;
110112

113+
typedef enum {
114+
HTTPC_TE_IDENTITY,
115+
HTTPC_TE_CHUNKED
116+
} transferEncoding_t;
117+
111118
class HTTPClient {
112119
public:
113120
HTTPClient();
@@ -188,11 +195,13 @@ class HTTPClient {
188195
int _returnCode;
189196
int _size;
190197
bool _canReuse;
198+
transferEncoding_t _transferEncoding;
199+
191200

192201
bool connect(void);
193202
bool sendHeader(const char * type);
194203
int handleHeaderResponse();
195-
204+
int writeToStreamDataBlock(Stream * stream, int len);
196205
};
197206

198207

0 commit comments

Comments
 (0)