diff --git a/HttpClient.cpp b/HttpClient.cpp index c095f76..51702c7 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) @@ -56,7 +60,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 +96,18 @@ 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. + else { + pBody = (char *)aBody; + pContentType = (char *)aContentType; + } 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,9 +143,13 @@ 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. + else { + pBody = (char *)aBody; + pContentType = (char *)aContentType; + } return ret; } @@ -272,9 +284,24 @@ 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,11 +310,21 @@ void HttpClient::endRequest() if (iState < eRequestSent) { // We still need to finish off the headers - finishHeaders(); + finishHeaders(pContentType, pBody); + 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 b4c3974..def2e7b 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 { @@ -61,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 @@ -73,7 +79,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 +90,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 +108,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 +124,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 +137,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 +153,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 +173,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 +191,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 +209,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 +222,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 +240,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 +256,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 +271,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 +291,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 +379,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,11 +425,11 @@ 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) - 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) @@ -444,6 +462,8 @@ class HttpClient : public Client IPAddress iProxyAddress; uint16_t iProxyPort; uint32_t iHttpResponseTimeout; + static char* pBody; + static char* pContentType; }; #endif