Corrected the isReplyAvailable methode

This commit is contained in:
Th3maz1ng 2020-07-14 11:48:43 +02:00
parent 2f430b305c
commit f76639745f
2 changed files with 129 additions and 84 deletions

View File

@ -7,20 +7,8 @@
* End of HttpClientHelper
*/
HttpClient::HttpClient() : WiFiClient(), _connectionStatus(NO_ATTEMPT), _resource(NULL), _address(NULL), _port(0), _keepAlive(false), _maxRetries(-1), _retries(0), _httpCode(HTTP_CODE::UNDEFINED_CODE), _bodyReadyToRead(false)
HttpClient::HttpClient(const char *address, uint16_t port) : WiFiClient(), _connectionStatus(NO_ATTEMPT), _resource(NULL), _pAddress(address), _port(0), _keepAlive(false), _maxRetries(-1), _retries(0), _isIp(false), _httpCode(HTTP_CODE::UNDEFINED_CODE), _httpCodeParsed(false)
{
}
HttpClient::HttpClient(const char *address, uint16_t port) : HttpClient()
{
if(address != NULL)
{
_address = (char *)malloc(strlen(address) * sizeof(char) + 1);
strcpy(_address, address);
}
_port = port;
connectByHostOrIp();
@ -44,35 +32,28 @@ HttpClient::HttpClient(const HttpClient &object)
}
else
_resource = NULL;
if(object._address != NULL)
{
_address = (char *)malloc(strlen(object._address) * sizeof(char) + 1);
strcpy(_address, object._address);
}
else
_address = NULL;
_pAddress = object._pAddress;
_connectionStatus = object._connectionStatus;
_keepAlive = object._keepAlive;
_maxRetries = object._maxRetries;
_retries = object._retries;
_port = object._port;
_httpCode = object._httpCode;
_bodyReadyToRead = object._bodyReadyToRead;
_httpCodeParsed = object._httpCodeParsed;
}
HttpClient::~HttpClient()
{
if(_resource != NULL)free(_resource);
if(_address != NULL)free(_address);
}
boolean HttpClient::connectByHostOrIp()
{
IPAddress ipAddress;
if(ipAddress.fromString(_address))
if(ipAddress.fromString(_pAddress))
{
_isIp = true;
_connectionStatus = connect(ipAddress, _port) == 1 ? SUCCESSFUL : FAILED;
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("Correct ip address. Connection status : %d\n", _connectionStatus);
@ -80,7 +61,8 @@ boolean HttpClient::connectByHostOrIp()
}
else
{
_connectionStatus = connect(_address, _port) == 1 ? SUCCESSFUL : FAILED;
_isIp = false;
_connectionStatus = connect(_pAddress, _port) == 1 ? SUCCESSFUL : FAILED;
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("Probably a hostname. Connection status : %d\n", _connectionStatus);
#endif
@ -108,7 +90,7 @@ boolean HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<Dictionar
{
//We reset this two flags
_httpCode = HTTP_CODE::UNDEFINED_CODE;
_bodyReadyToRead = false;
_httpCodeParsed = false;
#ifdef DEBUG_HTTP_CLIENT
if(_keepAlive)
@ -127,9 +109,9 @@ boolean HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<Dictionar
#ifdef DEBUG_HTTP_CLIENT
if(_keepAlive)
Serial.printf("Link broken, we try to reconnect : addr : %s port %u\nretries : %u\n", _address, _port, _retries);
Serial.printf("Link broken, we try to reconnect : addr : %s port %u\nretries : %u\n", _pAddress, _port, _retries);
else
Serial.printf("We start a new connection : %s port %u\nretries : %u\n", _address, _port, _retries);
Serial.printf("We start a new connection : %s port %u\nretries : %u\n", _pAddress, _port, _retries);
#endif
connectByHostOrIp();
@ -180,71 +162,125 @@ boolean HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<Dictionar
return true;
}
HttpClient::HTTP_CODE HttpClient::isReplyAvailable()
HttpClient::HTTP_CODE HttpClient::isReplyAvailable(uint16_t timeout)
{
uint32_t bytesAvailable(available());
uint8_t readBuffer[100];
uint8_t safeSize;
if(bytesAvailable && !_bodyReadyToRead)
uint32_t ts(millis());
char buffer[100];
if(!_httpCodeParsed)_httpCodeParsed = true;
else
{
safeSize = bytesAvailable > 99 ? 99 : bytesAvailable;
peekBytes(readBuffer, safeSize);
readBuffer[safeSize] = '\0';
return _httpCode;
}
#ifdef DEBUG_HTTP_CLIENT
Serial.println("Before timeout");
#endif
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("Data chunk from server size -> %u - %u : %s\n", safeSize, bytesAvailable, readBuffer);
#endif
//We try to extract the http return code:
if(_httpCode == HTTP_CODE::UNDEFINED_CODE)
//This is the loop where we parse the data
while(available() || millis() - ts < timeout)
{
if(available())
{
char *code = strchr((char *)readBuffer, ' '), *endP;
if(code != NULL)
//If we do not have the HTTP response code yet, we parse it
if(_httpCode == HTTP_CODE::UNDEFINED_CODE)
{
endP = strchr(code + 1, ' ');
if(endP != NULL)
uint8_t bytesRed = buffer[peekBytes((uint8_t*)buffer,99)] = '\0';
//We look for the end of the first line ie : HTTP/1.1 200 OK\r\n
char *pNewLine = strstr(buffer, "\r\n");
//If we found the new line, we can retrieve the code
if(pNewLine)
{
*endP = '\0';
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("Http code : %s\n", code + 1);
Serial.println("New line found");
#endif
_httpCode = numberToHTTP_CODE(strtoul(code+1, NULL, 10));
read(readBuffer, safeSize - 4); //To remove the peek bytes
//We extract the code
char *code = strchr((char *)buffer, ' '), *endP;
if(code)
{
endP = strchr(code + 1, ' ');
if(endP != NULL)
{
*endP = '\0';
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("Http code : %s\n", code + 1);
#endif
_httpCode = numberToHTTP_CODE(strtoul(code+1, NULL, 10));
//We can now discard the first line
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("First line length : %u\n",(pNewLine - buffer) + 2);
#endif
read((uint8_t *)buffer, (pNewLine - buffer) + 2);
#ifdef DEBUG_HTTP_CLIENT
buffer[peekBytes((uint8_t*)buffer,99)] = '\0';
Serial.printf("Next chunk is : %s\n",buffer);
#endif
}
}
else
{
#ifdef DEBUG_HTTP_CLIENT
Serial.println("Code delimiter NOT found, leaving");
#endif
break;
}
}
else if(millis() - ts >= timeout)//Time out is over, received data is probably junk.
{
//we leave the loop;
#ifdef DEBUG_HTTP_CLIENT
Serial.println("New line NOT found, leaving");
#endif
break;
}
}
else//We found the HTTP code, now we discard all the header data
{
char *bodyDelimiter(NULL);
char *newLineDelimiter;
do
{
buffer[peekBytes((uint8_t*)buffer,99)] = '\0';
bodyDelimiter = strstr(buffer, "\r\n\r\n");
newLineDelimiter = strstr(buffer, "\r\n");
if(!bodyDelimiter)
{
if(newLineDelimiter)
{
read((uint8_t *)buffer, (newLineDelimiter - buffer) + 2);
}
else
{
read((uint8_t *)buffer, strlen(buffer));
}
}
else
{
#ifdef DEBUG_HTTP_CLIENT
Serial.println("We found the body delimiter");
#endif
read((uint8_t *)buffer, (bodyDelimiter - buffer) + 4);
#ifdef DEBUG_HTTP_CLIENT
buffer[peekBytes((uint8_t*)buffer,99)] = '\0';
Serial.printf("Body chunk is : %s\n",buffer);
#endif
}
}while(!bodyDelimiter);
break;
}
}
if(!_bodyReadyToRead)
{
char *endP = strstr((char *)readBuffer, "\r\n\r\n");
if(endP != NULL)
{
#ifdef DEBUG_HTTP_CLIENT
Serial.printf("Body found, bytes to discard : %u\n", (uint8_t *)endP - readBuffer + 4);
#endif
read(readBuffer, (uint8_t *)endP - readBuffer + 4);
_bodyReadyToRead = true;
}
else
{
read(readBuffer, safeSize - 3);
}
}
}
if(_httpCode != HTTP_CODE::UNDEFINED_CODE && _bodyReadyToRead)
return _httpCode;
#ifdef DEBUG_HTTP_CLIENT
Serial.println("\nAfter timeout or all data is received");
#endif
return HTTP_CODE::UNDEFINED_CODE;
return _httpCode;
}
uint16_t HttpClient::readHttpReply(uint8_t *buffer, uint32_t size)
uint16_t HttpClient::readHttpBody(uint8_t *buffer, uint32_t size)
{
uint32_t bytesAvailable(available());
uint8_t safeSize(0);
@ -310,7 +346,12 @@ void HttpClient::keepAlive(boolean enabled)
void HttpClient::sendHeader(HttpMIMEType contentType, uint64_t contentLength, HttpVersion httpVersion)
{
char mime[255] = "", httpVer[15] = "";
printf(" %s\r\nHost: %u.%u.%u.%u:%u\r\nConnection: %s\r\n", httpVersionToString(httpVersion, httpVer), remoteIP()[0], remoteIP()[1], remoteIP()[2], remoteIP()[3], remotePort(), _keepAlive ? "keep-alive" : "close");
//Host could be an IP address or a host name
if(_isIp)
printf(" %s\r\nHost: %u.%u.%u.%u:%u\r\nConnection: %s\r\n", httpVersionToString(httpVersion, httpVer), remoteIP()[0], remoteIP()[1], remoteIP()[2], remoteIP()[3], remotePort(), _keepAlive ? "keep-alive" : "close");
else
printf(" %s\r\nHost: %s\r\nConnection: %s\r\n", httpVersionToString(httpVersion, httpVer), _pAddress, _keepAlive ? "keep-alive" : "close");
if(contentLength > 0)
{
printf("Content-Length: %u\r\n", contentLength);

View File

@ -1,3 +1,7 @@
/**
* Anatole SCHRAMM-HENRY
* Updated on 12/07/2020
*/
#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H
@ -15,7 +19,6 @@ class HttpClient : public WiFiClient, public HttpConstants
public:
enum ConnectionStatus { NO_ATTEMPT = 0, SUCCESSFUL, FAILED };
HttpClient();
HttpClient(const char *address, uint16_t port = 80);
HttpClient(const char *address, const char *resource, uint16_t port = 80);
@ -26,10 +29,10 @@ class HttpClient : public WiFiClient, public HttpConstants
boolean sendHttpQuery(HttpRequestMethod method = HttpRequestMethod::GET, Dictionary<DictionaryHelper::StringEntity> *getData = NULL, Dictionary<DictionaryHelper::StringEntity> *postData = NULL);
void keepAlive(boolean enabled);
void setMaxRetries(int16_t retries);
HTTP_CODE isReplyAvailable();
//100 ms is the default timeout
HTTP_CODE isReplyAvailable(uint16_t timeout = 100);
uint16_t readHttpReply(uint8_t *buffer, uint32_t size);
uint16_t readHttpBody(uint8_t *buffer, uint32_t size);
protected:
private:
boolean connectByHostOrIp();
@ -40,13 +43,14 @@ class HttpClient : public WiFiClient, public HttpConstants
ConnectionStatus _connectionStatus;
char *_resource;
char *_address;
const char *_pAddress;
uint16_t _port;
boolean _keepAlive;
int16_t _maxRetries;
uint16_t _retries;
boolean _isIp;
HTTP_CODE _httpCode;
boolean _bodyReadyToRead;
boolean _httpCodeParsed;
};
#endif //HTTPCLIENT_H