From bfedff87c1641a57b9fc47d3346c0de14e39bb53 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 14:18:11 -0400 Subject: [PATCH] Add connection keep alive support --- HttpClient.cpp | 77 +++++++++++++++++++++++++++++++++++++------------- HttpClient.h | 7 +++++ 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index d969ce4..055c121 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -10,7 +10,8 @@ const char* HttpClient::kUserAgent = "Arduino/2.2.0"; const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": "; HttpClient::HttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort) - : iClient(&aClient), iServerName(aServerName), iServerAddress(), iServerPort(aServerPort) + : iClient(&aClient), iServerName(aServerName), iServerAddress(), iServerPort(aServerPort), + iConnectionClose(true) { resetState(); } @@ -21,7 +22,8 @@ HttpClient::HttpClient(Client& aClient, const String& aServerName, uint16_t aSer } HttpClient::HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort) - : iClient(&aClient), iServerName(NULL), iServerAddress(aServerAddress), iServerPort(aServerPort) + : iClient(&aClient), iServerName(NULL), iServerAddress(aServerAddress), iServerPort(aServerPort), + iConnectionClose(true) { resetState(); } @@ -42,6 +44,11 @@ void HttpClient::stop() resetState(); } +void HttpClient::connectionKeepAlive() +{ + iConnectionClose = false; +} + void HttpClient::beginRequest() { iState = eRequestStarted; @@ -49,28 +56,44 @@ void HttpClient::beginRequest() int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod) { + if (!iConnectionClose) + { + flushClientRx(); + + resetState(); + } + tHttpState initialState = iState; if ((eIdle != iState) && (eRequestStarted != iState)) { return HTTP_ERROR_API; } - if (iServerName) { - if (!iClient->connect(iServerName, iServerPort) > 0) - { - #ifdef LOGGING - Serial.println("Connection failed"); - #endif - return HTTP_ERROR_CONNECTION_FAILED; + if (iConnectionClose || !iClient->connected()) + { + if (iServerName) { + if (!iClient->connect(iServerName, iServerPort) > 0) + { +#ifdef LOGGING + Serial.println("Connection failed"); +#endif + return HTTP_ERROR_CONNECTION_FAILED; + } + } else { + if (!iClient->connect(iServerAddress, iServerPort) > 0) + { +#ifdef LOGGING + Serial.println("Connection failed"); +#endif + return HTTP_ERROR_CONNECTION_FAILED; + } } - } else { - if (!iClient->connect(iServerAddress, iServerPort) > 0) - { - #ifdef LOGGING - Serial.println("Connection failed"); - #endif - return HTTP_ERROR_CONNECTION_FAILED; - } + } + else + { +#ifdef LOGGING + Serial.println("Connection already open"); +#endif } // Now we're connected, send the first part of the request @@ -111,9 +134,12 @@ int HttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod // And user-agent string sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent); - // We don't support persistent connections, so tell the server to - // close this connection after we're done - sendHeader(HTTP_HEADER_CONNECTION, "close"); + if (iConnectionClose) + { + // Tell the server to + // close this connection after we're done + sendHeader(HTTP_HEADER_CONNECTION, "close"); + } // Everything has gone well iState = eRequestStarted; @@ -194,6 +220,17 @@ void HttpClient::finishHeaders() iState = eRequestSent; } +void HttpClient::flushClientRx() +{ + if (iClient->connected()) + { + while (iClient->available()) + { + iClient->read(); + } + } +} + void HttpClient::endRequest() { if (iState < eRequestSent) diff --git a/HttpClient.h b/HttpClient.h index ce6a761..79ad889 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -48,6 +48,8 @@ public: HttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort = kHttpPort); HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = kHttpPort); + void connectionKeepAlive(); + /** Start a more complex request. Use this when you need to send additional headers in the request, but you will also need to call endRequest() when you are finished. @@ -247,6 +249,10 @@ protected: */ void finishHeaders(); + /** Reading any pending data from the client (used in connection keep alive mode) + */ + void flushClientRx(); + // Number of milliseconds that we wait each time there isn't any data // available to be read (during status code and header processing) static const int kHttpWaitForDataDelay = 1000; @@ -284,6 +290,7 @@ protected: // How far through a Content-Length header prefix we are const char* iContentLengthPtr; uint32_t iHttpResponseTimeout; + bool iConnectionClose; String iHeaderLine; };