Corrected the isReplyAvailable methode
This commit is contained in:
parent
2f430b305c
commit
f76639745f
@ -7,20 +7,8 @@
|
|||||||
* End of HttpClientHelper
|
* 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;
|
_port = port;
|
||||||
|
|
||||||
connectByHostOrIp();
|
connectByHostOrIp();
|
||||||
@ -44,35 +32,28 @@ HttpClient::HttpClient(const HttpClient &object)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
_resource = NULL;
|
_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;
|
_connectionStatus = object._connectionStatus;
|
||||||
_keepAlive = object._keepAlive;
|
_keepAlive = object._keepAlive;
|
||||||
_maxRetries = object._maxRetries;
|
_maxRetries = object._maxRetries;
|
||||||
_retries = object._retries;
|
_retries = object._retries;
|
||||||
_port = object._port;
|
_port = object._port;
|
||||||
_httpCode = object._httpCode;
|
_httpCode = object._httpCode;
|
||||||
_bodyReadyToRead = object._bodyReadyToRead;
|
_httpCodeParsed = object._httpCodeParsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClient::~HttpClient()
|
HttpClient::~HttpClient()
|
||||||
{
|
{
|
||||||
if(_resource != NULL)free(_resource);
|
if(_resource != NULL)free(_resource);
|
||||||
if(_address != NULL)free(_address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean HttpClient::connectByHostOrIp()
|
boolean HttpClient::connectByHostOrIp()
|
||||||
{
|
{
|
||||||
IPAddress ipAddress;
|
IPAddress ipAddress;
|
||||||
if(ipAddress.fromString(_address))
|
if(ipAddress.fromString(_pAddress))
|
||||||
{
|
{
|
||||||
|
_isIp = true;
|
||||||
_connectionStatus = connect(ipAddress, _port) == 1 ? SUCCESSFUL : FAILED;
|
_connectionStatus = connect(ipAddress, _port) == 1 ? SUCCESSFUL : FAILED;
|
||||||
#ifdef DEBUG_HTTP_CLIENT
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
Serial.printf("Correct ip address. Connection status : %d\n", _connectionStatus);
|
Serial.printf("Correct ip address. Connection status : %d\n", _connectionStatus);
|
||||||
@ -80,7 +61,8 @@ boolean HttpClient::connectByHostOrIp()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_connectionStatus = connect(_address, _port) == 1 ? SUCCESSFUL : FAILED;
|
_isIp = false;
|
||||||
|
_connectionStatus = connect(_pAddress, _port) == 1 ? SUCCESSFUL : FAILED;
|
||||||
#ifdef DEBUG_HTTP_CLIENT
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
Serial.printf("Probably a hostname. Connection status : %d\n", _connectionStatus);
|
Serial.printf("Probably a hostname. Connection status : %d\n", _connectionStatus);
|
||||||
#endif
|
#endif
|
||||||
@ -108,7 +90,7 @@ boolean HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<Dictionar
|
|||||||
{
|
{
|
||||||
//We reset this two flags
|
//We reset this two flags
|
||||||
_httpCode = HTTP_CODE::UNDEFINED_CODE;
|
_httpCode = HTTP_CODE::UNDEFINED_CODE;
|
||||||
_bodyReadyToRead = false;
|
_httpCodeParsed = false;
|
||||||
|
|
||||||
#ifdef DEBUG_HTTP_CLIENT
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
if(_keepAlive)
|
if(_keepAlive)
|
||||||
@ -127,9 +109,9 @@ boolean HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<Dictionar
|
|||||||
|
|
||||||
#ifdef DEBUG_HTTP_CLIENT
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
if(_keepAlive)
|
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
|
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
|
#endif
|
||||||
|
|
||||||
connectByHostOrIp();
|
connectByHostOrIp();
|
||||||
@ -180,71 +162,125 @@ boolean HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<Dictionar
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClient::HTTP_CODE HttpClient::isReplyAvailable()
|
HttpClient::HTTP_CODE HttpClient::isReplyAvailable(uint16_t timeout)
|
||||||
{
|
{
|
||||||
uint32_t bytesAvailable(available());
|
uint32_t ts(millis());
|
||||||
uint8_t readBuffer[100];
|
char buffer[100];
|
||||||
uint8_t safeSize;
|
|
||||||
|
if(!_httpCodeParsed)_httpCodeParsed = true;
|
||||||
if(bytesAvailable && !_bodyReadyToRead)
|
else
|
||||||
{
|
{
|
||||||
safeSize = bytesAvailable > 99 ? 99 : bytesAvailable;
|
return _httpCode;
|
||||||
peekBytes(readBuffer, safeSize);
|
}
|
||||||
readBuffer[safeSize] = '\0';
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
|
Serial.println("Before timeout");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_HTTP_CLIENT
|
//This is the loop where we parse the data
|
||||||
Serial.printf("Data chunk from server size -> %u - %u : %s\n", safeSize, bytesAvailable, readBuffer);
|
while(available() || millis() - ts < timeout)
|
||||||
#endif
|
{
|
||||||
|
if(available())
|
||||||
//We try to extract the http return code:
|
|
||||||
if(_httpCode == HTTP_CODE::UNDEFINED_CODE)
|
|
||||||
{
|
{
|
||||||
char *code = strchr((char *)readBuffer, ' '), *endP;
|
//If we do not have the HTTP response code yet, we parse it
|
||||||
|
if(_httpCode == HTTP_CODE::UNDEFINED_CODE)
|
||||||
if(code != NULL)
|
|
||||||
{
|
{
|
||||||
endP = strchr(code + 1, ' ');
|
uint8_t bytesRed = buffer[peekBytes((uint8_t*)buffer,99)] = '\0';
|
||||||
if(endP != NULL)
|
//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
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
Serial.printf("Http code : %s\n", code + 1);
|
Serial.println("New line found");
|
||||||
#endif
|
#endif
|
||||||
|
//We extract the code
|
||||||
|
char *code = strchr((char *)buffer, ' '), *endP;
|
||||||
_httpCode = numberToHTTP_CODE(strtoul(code+1, NULL, 10));
|
if(code)
|
||||||
read(readBuffer, safeSize - 4); //To remove the peek bytes
|
{
|
||||||
|
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)
|
#ifdef DEBUG_HTTP_CLIENT
|
||||||
return _httpCode;
|
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());
|
uint32_t bytesAvailable(available());
|
||||||
uint8_t safeSize(0);
|
uint8_t safeSize(0);
|
||||||
@ -310,7 +346,12 @@ void HttpClient::keepAlive(boolean enabled)
|
|||||||
void HttpClient::sendHeader(HttpMIMEType contentType, uint64_t contentLength, HttpVersion httpVersion)
|
void HttpClient::sendHeader(HttpMIMEType contentType, uint64_t contentLength, HttpVersion httpVersion)
|
||||||
{
|
{
|
||||||
char mime[255] = "", httpVer[15] = "";
|
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)
|
if(contentLength > 0)
|
||||||
{
|
{
|
||||||
printf("Content-Length: %u\r\n", contentLength);
|
printf("Content-Length: %u\r\n", contentLength);
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Anatole SCHRAMM-HENRY
|
||||||
|
* Updated on 12/07/2020
|
||||||
|
*/
|
||||||
#ifndef HTTPCLIENT_H
|
#ifndef HTTPCLIENT_H
|
||||||
#define HTTPCLIENT_H
|
#define HTTPCLIENT_H
|
||||||
|
|
||||||
@ -15,7 +19,6 @@ class HttpClient : public WiFiClient, public HttpConstants
|
|||||||
public:
|
public:
|
||||||
enum ConnectionStatus { NO_ATTEMPT = 0, SUCCESSFUL, FAILED };
|
enum ConnectionStatus { NO_ATTEMPT = 0, SUCCESSFUL, FAILED };
|
||||||
|
|
||||||
HttpClient();
|
|
||||||
HttpClient(const char *address, uint16_t port = 80);
|
HttpClient(const char *address, uint16_t port = 80);
|
||||||
HttpClient(const char *address, const char *resource, 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);
|
boolean sendHttpQuery(HttpRequestMethod method = HttpRequestMethod::GET, Dictionary<DictionaryHelper::StringEntity> *getData = NULL, Dictionary<DictionaryHelper::StringEntity> *postData = NULL);
|
||||||
void keepAlive(boolean enabled);
|
void keepAlive(boolean enabled);
|
||||||
void setMaxRetries(int16_t retries);
|
void setMaxRetries(int16_t retries);
|
||||||
|
//100 ms is the default timeout
|
||||||
HTTP_CODE isReplyAvailable();
|
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:
|
protected:
|
||||||
private:
|
private:
|
||||||
boolean connectByHostOrIp();
|
boolean connectByHostOrIp();
|
||||||
@ -40,13 +43,14 @@ class HttpClient : public WiFiClient, public HttpConstants
|
|||||||
|
|
||||||
ConnectionStatus _connectionStatus;
|
ConnectionStatus _connectionStatus;
|
||||||
char *_resource;
|
char *_resource;
|
||||||
char *_address;
|
const char *_pAddress;
|
||||||
uint16_t _port;
|
uint16_t _port;
|
||||||
boolean _keepAlive;
|
boolean _keepAlive;
|
||||||
int16_t _maxRetries;
|
int16_t _maxRetries;
|
||||||
uint16_t _retries;
|
uint16_t _retries;
|
||||||
|
boolean _isIp;
|
||||||
HTTP_CODE _httpCode;
|
HTTP_CODE _httpCode;
|
||||||
boolean _bodyReadyToRead;
|
boolean _httpCodeParsed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //HTTPCLIENT_H
|
#endif //HTTPCLIENT_H
|
||||||
|
Loading…
Reference in New Issue
Block a user