From 1c6612099be0f3cb7f95145fe12bdf0c1a7a028a Mon Sep 17 00:00:00 2001 From: Randy Date: Sun, 10 May 2015 02:10:30 -0400 Subject: [PATCH 1/6] POST request to support sending a body POST request functions now support sending a content type and a body along with the request. --- HttpClient.cpp | 22 +++++++++++++------ HttpClient.h | 57 +++++++++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index c095f76..2e427e6 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -56,7 +56,7 @@ void HttpClient::beginRequest() iState = eRequestStarted; } -int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent) +int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aContentType, const char* aBody) { tHttpState initialState = iState; if ((eIdle != iState) && (eRequestStarted != iState)) @@ -92,14 +92,14 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons if ((initialState == eIdle) && (HTTP_SUCCESS == ret)) { // This was a simple version of the API, so terminate the headers now - finishHeaders(); + finishHeaders(aContentType, aBody); } // else we'll call it in endRequest or in the first call to print, etc. return ret; } -int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent) +int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aContentType, const char* aBody) { tHttpState initialState = iState; if ((eIdle != iState) && (eRequestStarted != iState)) @@ -135,7 +135,7 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServe if ((initialState == eIdle) && (HTTP_SUCCESS == ret)) { // This was a simple version of the API, so terminate the headers now - finishHeaders(); + finishHeaders(aContentType, aBody); } // else we'll call it in endRequest or in the first call to print, etc. @@ -272,9 +272,19 @@ void HttpClient::sendBasicAuth(const char* aUser, const char* aPassword) iClient->println(); } -void HttpClient::finishHeaders() +void HttpClient::finishHeaders(const char* aContentType, const char* aBody) { + if (aContentType) + sendHeader(HTTP_HEADER_CONTENT_TYPE, aContentType); + + if (aBody) + sendHeader(HTTP_HEADER_CONTENT_LENGTH, strlen(aBody)); + iClient->println(); + + if (aBody) + iClient->println(aBody); + iState = eRequestSent; } @@ -283,7 +293,7 @@ void HttpClient::endRequest() if (iState < eRequestSent) { // We still need to finish off the headers - finishHeaders(); + finishHeaders(NULL, NULL); } // else the end of headers has already been sent, so nothing to do here } diff --git a/HttpClient.h b/HttpClient.h index b4c3974..803c0fe 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -33,6 +33,7 @@ static const int HTTP_ERROR_INVALID_RESPONSE =-4; #define HTTP_HEADER_CONTENT_LENGTH "Content-Length" #define HTTP_HEADER_CONNECTION "Connection" #define HTTP_HEADER_USER_AGENT "User-Agent" +#define HTTP_HEADER_CONTENT_TYPE "Content-Type" class HttpClient : public Client { @@ -73,7 +74,7 @@ class HttpClient : public Client */ int get(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } + { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a GET request. @param aServerName Name of the server being connected to. If NULL, the @@ -84,7 +85,7 @@ class HttpClient : public Client @return 0 if successful, else error */ int get(const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } + { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a GET request. This version connects doesn't perform a DNS lookup and just connects to the given IP address. @@ -102,7 +103,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } + { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a GET request. This version connects doesn't perform a DNS lookup and just connects to the given IP address. @@ -118,7 +119,7 @@ class HttpClient : public Client const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } + { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a POST request. @param aServerName Name of the server being connected to. If NULL, the @@ -131,9 +132,11 @@ class HttpClient : public Client */ int post(const char* aServerName, uint16_t aServerPort, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } + const char* aURLPath, + const char* aUserAgent =NULL, + const char* aContentType =NULL, + const char* aBody =NULL) + { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a POST request. @param aServerName Name of the server being connected to. If NULL, the @@ -145,8 +148,10 @@ class HttpClient : public Client */ int post(const char* aServerName, const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } + const char* aUserAgent =NULL, + const char* aContentType =NULL, + const char* aBody =NULL) + { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a POST request. This version connects doesn't perform a DNS lookup and just connects to the given IP address. @@ -163,8 +168,10 @@ class HttpClient : public Client const char* aServerName, uint16_t aServerPort, const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } + const char* aUserAgent =NULL, + const char* aContentType =NULL, + const char* aBody =NULL) + { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a POST request. This version connects doesn't perform a DNS lookup and just connects to the given IP address. @@ -179,8 +186,10 @@ class HttpClient : public Client int post(const IPAddress& aServerAddress, const char* aServerName, const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } + const char* aUserAgent =NULL, + const char* aContentType =NULL, + const char* aBody =NULL) + { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a PUT request. @param aServerName Name of the server being connected to. If NULL, the @@ -195,7 +204,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } + { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a PUT request. @param aServerName Name of the server being connected to. If NULL, the @@ -208,7 +217,7 @@ class HttpClient : public Client int put(const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } + { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a PUT request. This version connects doesn't perform a DNS lookup and just connects to the given IP address. @@ -226,7 +235,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } + { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); } /** Connect to the server and start to send a PUT request. This version connects doesn't perform a DNS lookup and just connects to the given IP address. @@ -242,7 +251,7 @@ class HttpClient : public Client const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } + { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); } /** Connect to the server and start to send the request. @param aServerName Name of the server being connected to. @@ -257,7 +266,9 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, - const char* aUserAgent); + const char* aUserAgent, + const char* aContentType, + const char* aBody); /** Connect to the server and start to send the request. @param aServerAddress IP address of the server to connect to. @@ -275,7 +286,9 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, - const char* aUserAgent); + const char* aUserAgent, + const char* aContentType, + const char* aBody); /** Send an additional header line. This can only be called in between the calls to startRequest and finishRequest. @@ -361,8 +374,8 @@ class HttpClient : public Client // Inherited from Print // Note: 1st call to these indicates the user is sending the body, so if need // Note: be we should finish the header first - virtual size_t write(uint8_t aByte) { if (iState < eRequestSent) { finishHeaders(); }; return iClient-> write(aByte); }; - virtual size_t write(const uint8_t *aBuffer, size_t aSize) { if (iState < eRequestSent) { finishHeaders(); }; return iClient->write(aBuffer, aSize); }; + virtual size_t write(uint8_t aByte) { if (iState < eRequestSent) { finishHeaders(NULL, NULL); }; return iClient-> write(aByte); }; + virtual size_t write(const uint8_t *aBuffer, size_t aSize) { if (iState < eRequestSent) { finishHeaders(NULL, NULL); }; return iClient->write(aBuffer, aSize); }; // Inherited from Stream virtual int available() { return iClient->available(); }; /** Read the next byte from the server. @@ -407,7 +420,7 @@ class HttpClient : public Client /* Let the server know that we've reached the end of the headers */ - void finishHeaders(); + void finishHeaders(const char* aContentType, const char* aBody); // Number of milliseconds that we wait each time there isn't any data // available to be read (during status code and header processing) From 4b44568cb7f4fe3e567b410cc3a1b89cb9b1efd7 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 14 May 2015 10:20:35 -0400 Subject: [PATCH 2/6] Tabs to spaces Fixed formatting. Tabs to spaces (fixing previous commit). --- HttpClient.cpp | 25 +++++++++++++++---------- HttpClient.h | 16 ++++++++-------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 2e427e6..0744897 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -274,17 +274,22 @@ void HttpClient::sendBasicAuth(const char* aUser, const char* aPassword) void HttpClient::finishHeaders(const char* aContentType, const char* aBody) { - if (aContentType) - sendHeader(HTTP_HEADER_CONTENT_TYPE, aContentType); - - if (aBody) - sendHeader(HTTP_HEADER_CONTENT_LENGTH, strlen(aBody)); - + if (aContentType) + { + sendHeader(HTTP_HEADER_CONTENT_TYPE, aContentType); + } + + if (aBody) + { + sendHeader(HTTP_HEADER_CONTENT_LENGTH, strlen(aBody)); + } + iClient->println(); - - if (aBody) - iClient->println(aBody); - + if (aBody) + { + iClient->println(aBody); + } + iState = eRequestSent; } diff --git a/HttpClient.h b/HttpClient.h index 803c0fe..ef978df 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -134,8 +134,8 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL, - const char* aContentType =NULL, - const char* aBody =NULL) + const char* aContentType =NULL, + const char* aBody =NULL) { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a POST request. @@ -149,8 +149,8 @@ class HttpClient : public Client int post(const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL, - const char* aContentType =NULL, - const char* aBody =NULL) + const char* aContentType =NULL, + const char* aBody =NULL) { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a POST request. This version connects @@ -169,8 +169,8 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL, - const char* aContentType =NULL, - const char* aBody =NULL) + const char* aContentType =NULL, + const char* aBody =NULL) { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a POST request. This version connects @@ -187,8 +187,8 @@ class HttpClient : public Client const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL, - const char* aContentType =NULL, - const char* aBody =NULL) + const char* aContentType =NULL, + const char* aBody =NULL) { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); } /** Connect to the server and start to send a PUT request. From c64175308bfad9be223a8505617197f301758ec9 Mon Sep 17 00:00:00 2001 From: Pablo Rodiz Obaya Date: Wed, 16 Mar 2016 21:46:14 +0100 Subject: [PATCH 3/6] Added variables to store body and content type --- HttpClient.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HttpClient.h b/HttpClient.h index ef978df..801ccb2 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -457,6 +457,8 @@ class HttpClient : public Client IPAddress iProxyAddress; uint16_t iProxyPort; uint32_t iHttpResponseTimeout; + static char* pBody; + static char* pContentType; }; #endif From 086f562f27c667bbc2e29336433d27af35f7ff10 Mon Sep 17 00:00:00 2001 From: Pablo Rodiz Obaya Date: Wed, 16 Mar 2016 21:51:22 +0100 Subject: [PATCH 4/6] Added mechanism to store body and content type Added mechanism to store body and content type on startRequest so they can be sent on endRequest for complex http post operations which need additional headers --- HttpClient.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 0744897..ff01eb1 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -11,6 +11,10 @@ // Initialize constants const char* HttpClient::kUserAgent = "Arduino/2.1"; const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": "; +// Store body and content type pointers here so they can be sent also from a complex +// request with additional headers +char* HttpClient::pBody = NULL; +char* HttpClient::pContentType = NULL; #ifdef PROXY_ENABLED // currently disabled as introduces dependency on Dns.h in Ethernet HttpClient::HttpClient(Client& aClient, const char* aProxy, uint16_t aProxyPort) @@ -95,6 +99,10 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons finishHeaders(aContentType, aBody); } // else we'll call it in endRequest or in the first call to print, etc. + else { + pBody = (char *)aBody; + pContentType = (char *)aContentType; + } return ret; } @@ -138,6 +146,10 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServe finishHeaders(aContentType, aBody); } // else we'll call it in endRequest or in the first call to print, etc. + else { + pBody = (char *)aBody; + pContentType = (char *)aContentType; + } return ret; } @@ -298,7 +310,9 @@ void HttpClient::endRequest() if (iState < eRequestSent) { // We still need to finish off the headers - finishHeaders(NULL, NULL); + finishHeaders(pContentType, pBody); + pBody = NULL; + pContentType = NULL; } // else the end of headers has already been sent, so nothing to do here } From 57c768aa4b5f6be1cabd8cbd49c441eb8fa7d6a3 Mon Sep 17 00:00:00 2001 From: Pablo Rodiz Obaya Date: Thu, 19 May 2016 21:20:44 +0200 Subject: [PATCH 5/6] Reduce wait for data delay Waiting for 1 second when no data is available for reading is too much and makes the communication very slow. I have reduced it to 20 miliseconds. --- HttpClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient.h b/HttpClient.h index 801ccb2..8473bf0 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -424,7 +424,7 @@ class HttpClient : public Client // 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; + static const int kHttpWaitForDataDelay = 20; // Number of milliseconds that we'll wait in total without receiveing any // data before returning HTTP_ERROR_TIMED_OUT (during status code and header // processing) From 256d3d84543d22c3173f8d6ea4d88ca44a33609c Mon Sep 17 00:00:00 2001 From: pablorodiz Date: Wed, 25 May 2016 15:44:31 +0200 Subject: [PATCH 6/6] Added forceEndRequest to allow building and sending requests outside the library, but still waiting and parsing responses using the library. This is useful if you need to speed up communications by sending the whole request in only one packet, as is need if you want to communicate two ESP8266 devices without endless waiting for packet ACKs. --- HttpClient.cpp | 12 ++++++++++-- HttpClient.h | 7 ++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index ff01eb1..51702c7 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -311,12 +311,20 @@ void HttpClient::endRequest() { // We still need to finish off the headers finishHeaders(pContentType, pBody); - pBody = NULL; - pContentType = NULL; + pBody = NULL; + pContentType = NULL; } // else the end of headers has already been sent, so nothing to do here } +void HttpClient::forceEndRequest() +{ + if (iState < eRequestSent) + { + iState = eRequestSent; + } +} + int HttpClient::responseStatusCode() { if (iState < eRequestSent) diff --git a/HttpClient.h b/HttpClient.h index 8473bf0..def2e7b 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -62,7 +62,12 @@ class HttpClient : public Client but you will also need to call beginRequest() at the start. */ void endRequest(); - + /** End an even more complex request. + Use this when you need to create and send the request using connect and write, + avoiding the use of the library, but still want to receive the response by + means of this library. + */ + void forceEndRequest(); /** Connect to the server and start to send a GET request. @param aServerName Name of the server being connected to. If NULL, the "Host" header line won't be sent