diff --git a/HttpClient.cpp b/HttpClient.cpp index 9176108..4159b9f 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -59,17 +59,18 @@ void HttpClient::beginRequest() iState = eRequestStarted; } -int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod) +int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod, + const char* aContentType, int aContentLength, const byte aBody[]) { - tHttpState initialState = iState; - - if (!iConnectionClose) + if (iState == eReadingBody) { flushClientRx(); resetState(); } + tHttpState initialState = iState; + if ((eIdle != iState) && (eRequestStarted != iState)) { return HTTP_ERROR_API; @@ -104,12 +105,33 @@ int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod) // Now we're connected, send the first part of the request int ret = sendInitialHeaders(aURLPath, aHttpMethod); - if ((initialState == eIdle) && (HTTP_SUCCESS == ret)) + + if (HTTP_SUCCESS == ret) { - // This was a simple version of the API, so terminate the headers now - finishHeaders(); + if (aContentType) + { + sendHeader(HTTP_HEADER_CONTENT_TYPE, aContentType); + } + + if (aContentLength > 0) + { + sendHeader(HTTP_HEADER_CONTENT_LENGTH, aContentLength); + } + + bool hasBody = (aBody && aContentLength > 0); + + if (initialState == eIdle || hasBody) + { + // This was a simple version of the API, so terminate the headers now + finishHeaders(); + } + // else we'll call it in endRequest or in the first call to print, etc. + + if (hasBody) + { + write(aBody, aContentLength); + } } - // else we'll call it in endRequest or in the first call to print, etc. return ret; } @@ -231,12 +253,9 @@ void HttpClient::finishHeaders() void HttpClient::flushClientRx() { - if (iClient->connected()) + while (iClient->available()) { - while (iClient->available()) - { - iClient->read(); - } + iClient->read(); } } @@ -250,6 +269,91 @@ void HttpClient::endRequest() // else the end of headers has already been sent, so nothing to do here } +int HttpClient::get(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_GET); +} + +int HttpClient::get(const String& aURLPath) +{ + return get(aURLPath.c_str()); +} + +int HttpClient::post(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_POST); +} + +int HttpClient::post(const String& aURLPath) +{ + return post(aURLPath.c_str()); +} + +int HttpClient::post(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return post(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +int HttpClient::post(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return post(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +int HttpClient::post(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_POST, aContentType, aContentLength, aBody); +} + +int HttpClient::put(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_PUT); +} + +int HttpClient::put(const String& aURLPath) +{ + return put(aURLPath.c_str()); +} + +int HttpClient::put(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return put(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +int HttpClient::put(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return put(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +int HttpClient::put(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_PUT, aContentType, aContentLength, aBody); +} + +int HttpClient::del(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_DELETE); +} + +int HttpClient::del(const String& aURLPath) +{ + return del(aURLPath.c_str()); +} + +int HttpClient::del(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return del(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +int HttpClient::del(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return del(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +int HttpClient::del(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_DELETE, aContentType, aContentLength, aBody); +} + int HttpClient::responseStatusCode() { if (iState < eRequestSent) @@ -407,6 +511,24 @@ int HttpClient::contentLength() return iContentLength; } +String HttpClient::responseBody() +{ + int bodyLength = contentLength(); + String response; + + if (bodyLength > 0) + { + response.reserve(bodyLength); + } + + while (available()) + { + response += (char)read(); + } + + return response; +} + bool HttpClient::endOfBodyReached() { if (endOfHeadersReached() && (contentLength() != kNoContentLengthHeader)) diff --git a/HttpClient.h b/HttpClient.h index 4b51ca3..141b2df 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -31,6 +31,7 @@ static const int HTTP_ERROR_INVALID_RESPONSE =-4; #define HTTP_METHOD_PUT "PUT" #define HTTP_METHOD_DELETE "DELETE" #define HTTP_HEADER_CONTENT_LENGTH "Content-Length" +#define HTTP_HEADER_CONTENT_TYPE "Content-Type" #define HTTP_HEADER_CONNECTION "Connection" #define HTTP_HEADER_USER_AGENT "User-Agent" @@ -64,39 +65,77 @@ public: @param aURLPath Url to request @return 0 if successful, else error */ - int get(const char* aURLPath) - { return startRequest(aURLPath, HTTP_METHOD_GET); } - - int get(const String& aURLPath) - { return get(aURLPath.c_str()); } + int get(const char* aURLPath); + int get(const String& aURLPath); /** Connect to the server and start to send a POST request. @param aURLPath Url to request @return 0 if successful, else error */ - int post(const char* aURLPath) - { return startRequest(aURLPath, HTTP_METHOD_POST); } + int post(const char* aURLPath); + int post(const String& aURLPath); - int post(const String& aURLPath) - { return post(aURLPath.c_str()); } + /** Connect to the server and send a POST request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int post(const char* aURLPath, const char* aContentType, const char* aBody); + int post(const String& aURLPath, const String& aContentType, const String& aBody); + int post(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); /** Connect to the server and start to send a PUT request. @param aURLPath Url to request @return 0 if successful, else error */ - int put(const char* aURLPath) - { return startRequest(aURLPath, HTTP_METHOD_PUT); } + int put(const char* aURLPath); + int put(const String& aURLPath); - int put(const String& aURLPath) - { return put(aURLPath.c_str()); } + /** Connect to the server and send a PUT request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int put(const char* aURLPath, const char* aContentType, const char* aBody); + int put(const String& aURLPath, const String& aContentType, const String& aBody); + int put(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); + + /** Connect to the server and start to send a DELETE request. + @param aURLPath Url to request + @return 0 if successful, else error + */ + int del(const char* aURLPath); + int del(const String& aURLPath); + + /** Connect to the server and send a DELETE request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int del(const char* aURLPath, const char* aContentType, const char* aBody); + int del(const String& aURLPath, const String& aContentType, const String& aBody); + int del(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); /** Connect to the server and start to send the request. - @param aURLPath Url to request - @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. + If a body is provided, the entire request (including headers and body) will be sent + @param aURLPath Url to request + @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. + @param aContentType Content type of request body (optional) + @param aContentLength Length of request body (optional) + @param aBody Body of request (optional) @return 0 if successful, else error */ int startRequest(const char* aURLPath, - const char* aHttpMethod); + const char* aHttpMethod, + const char* aContentType = NULL, + int aContentLength = -1, + const byte aBody[] = NULL); /** Send an additional header line. This can only be called in between the calls to startRequest and finishRequest. @@ -207,6 +246,13 @@ public: */ int contentLength(); + /** Return the response body as a String + Also skips response headers if they have not been read already + MUST be called after responseStatusCode() + @return response body of request as a String + */ + String responseBody(); + /** Enables connection keep-alive mode */ void connectionKeepAlive(); diff --git a/examples/DweetGet/DweetGet.ino b/examples/DweetGet/DweetGet.ino index 11d3daa..96f698d 100644 --- a/examples/DweetGet/DweetGet.ino +++ b/examples/DweetGet/DweetGet.ino @@ -33,7 +33,6 @@ WiFiClient wifi; HttpClient client = HttpClient(wifi, serverAddress, port); int status = WL_IDLE_STATUS; int statusCode = 0; -int contentLength = 0; String response; void setup() { @@ -63,27 +62,13 @@ void loop() { // send the GET request Serial.println("making GET request"); - client.beginRequest(); client.get(path); - client.endRequest(); - // read the status code of the response + // read the status code and body of the response statusCode = client.responseStatusCode(); + response = client.responseBody(); Serial.print("Status code: "); Serial.println(statusCode); - - // read the content length of the response - contentLength = client.contentLength(); - Serial.print("Content Length: "); - Serial.println(contentLength); - - // read the response body - response = ""; - response.reserve(contentLength); - while (client.available()) { - response += (char)client.read(); - } - Serial.print("Response: "); Serial.println(response); diff --git a/examples/DweetPost/DweetPost.ino b/examples/DweetPost/DweetPost.ino index 04b5f3e..201e76c 100644 --- a/examples/DweetPost/DweetPost.ino +++ b/examples/DweetPost/DweetPost.ino @@ -27,7 +27,6 @@ WiFiClient wifi; HttpClient client = HttpClient(wifi, serverAddress, port); int status = WL_IDLE_STATUS; int statusCode = 0; -int contentLength = 0; String response; void setup() { @@ -56,6 +55,8 @@ void loop() { String dweetName = "scandalous-cheese-hoarder"; String path = "/dweet/for/" + dweetName; + String contentType = "application/json"; + // assemble the body of the POST message: int sensorValue = analogRead(A0); String postData = "{\"sensorValue\":\""; @@ -65,23 +66,11 @@ void loop() { Serial.println("making POST request"); // send the POST request - client.beginRequest(); - client.post(path); - client.sendHeader("Content-Type", "application/json"); - client.sendHeader("Content-Length", postData.length()); - client.endRequest(); - client.write((const byte*)postData.c_str(), postData.length()); + client.post(path, contentType, postData); - // read the status code and content length of the response + // read the status code and body of the response statusCode = client.responseStatusCode(); - contentLength = client.contentLength(); - - // read the response body - response = ""; - response.reserve(contentLength); - while (client.available()) { - response += (char)client.read(); - } + response = client.responseBody(); Serial.print("Status code: "); Serial.println(statusCode); diff --git a/examples/HueBlink/HueBlink.ino b/examples/HueBlink/HueBlink.ino index 3d6a028..a88bec9 100644 --- a/examples/HueBlink/HueBlink.ino +++ b/examples/HueBlink/HueBlink.ino @@ -70,6 +70,8 @@ void sendRequest(int light, String cmd, String value) { request += light; request += "/state/"; + String contentType = "application/json"; + // make a string for the JSON command: String hueCmd = "{\"" + cmd; hueCmd += "\":"; @@ -81,23 +83,11 @@ void sendRequest(int light, String cmd, String value) { Serial.print("JSON command to server: "); // make the PUT request to the hub: - httpClient.beginRequest(); - httpClient.put(request); - httpClient.sendHeader("Content-Type", "application/json"); - httpClient.sendHeader("Content-Length", hueCmd.length()); - httpClient.endRequest(); - httpClient.write((const byte*)hueCmd.c_str(), hueCmd.length()); + httpClient.put(request, contentType, hueCmd); - // read the status code and content length of the response + // read the status code and body of the response int statusCode = httpClient.responseStatusCode(); - int contentLength = httpClient.contentLength(); - - // read the response body - String response = ""; - response.reserve(contentLength); - while (httpClient.available()) { - response += (char)httpClient.read(); - } + String response = httpClient.responseBody(); Serial.println(hueCmd); Serial.print("Status code from server: "); diff --git a/examples/SimpleDelete/SimpleDelete.ino b/examples/SimpleDelete/SimpleDelete.ino index 591f4de..9304be0 100644 --- a/examples/SimpleDelete/SimpleDelete.ino +++ b/examples/SimpleDelete/SimpleDelete.ino @@ -26,7 +26,6 @@ HttpClient client = HttpClient(wifi, serverAddress, port); int status = WL_IDLE_STATUS; String response; int statusCode = 0; -int contentLength = 0; void setup() { Serial.begin(9600); @@ -50,25 +49,14 @@ void setup() { void loop() { Serial.println("making DELETE request"); + String contentType = "application/x-www-form-urlencoded"; String delData = "name=light&age=46"; - client.beginRequest(); - client.startRequest("/", HTTP_METHOD_DELETE); - client.sendHeader("Content-Type", "application/x-www-form-urlencoded"); - client.sendHeader("Content-Length", delData.length()); - client.endRequest(); - client.write((const byte*)delData.c_str(), delData.length()); + client.del("/", contentType, delData); - // read the status code and content length of the response + // read the status code and body of the response statusCode = client.responseStatusCode(); - contentLength = client.contentLength(); - - // read the response body - response = ""; - response.reserve(contentLength); - while (client.available()) { - response += (char)client.read(); - } + response = client.responseBody(); Serial.print("Status code: "); Serial.println(statusCode); diff --git a/examples/SimpleGet/SimpleGet.ino b/examples/SimpleGet/SimpleGet.ino index 86cdb9d..dc68eda 100644 --- a/examples/SimpleGet/SimpleGet.ino +++ b/examples/SimpleGet/SimpleGet.ino @@ -25,7 +25,6 @@ HttpClient client = HttpClient(wifi, serverAddress, port); int status = WL_IDLE_STATUS; String response; int statusCode = 0; -int contentLength = 0; void setup() { Serial.begin(9600); @@ -49,21 +48,11 @@ void setup() { void loop() { Serial.println("making GET request"); - - // read the status code and content length of the response - client.beginRequest(); client.get("/"); - client.endRequest(); + // read the status code and body of the response statusCode = client.responseStatusCode(); - contentLength = client.contentLength(); - - // read the response body - response = ""; - response.reserve(contentLength); - while (client.available()) { - response += (char)client.read(); - } + response = client.responseBody(); Serial.print("Status code: "); Serial.println(statusCode); diff --git a/examples/SimplePost/SimplePost.ino b/examples/SimplePost/SimplePost.ino index 46982ca..42dfea8 100644 --- a/examples/SimplePost/SimplePost.ino +++ b/examples/SimplePost/SimplePost.ino @@ -26,7 +26,6 @@ HttpClient client = HttpClient(wifi, serverAddress, port); int status = WL_IDLE_STATUS; String response; int statusCode = 0; -int contentLength = 0; void setup() { Serial.begin(9600); @@ -50,25 +49,14 @@ void setup() { void loop() { Serial.println("making POST request"); + String contentType = "application/x-www-form-urlencoded"; String postData = "name=Alice&age=12"; - client.beginRequest(); - client.post("/"); - client.sendHeader("Content-Type", "application/x-www-form-urlencoded"); - client.sendHeader("Content-Length", postData.length()); - client.endRequest(); - client.write((const byte*)postData.c_str(), postData.length()); + client.post("/", contentType, postData); - // read the status code and content length of the response + // read the status code and body of the response statusCode = client.responseStatusCode(); - contentLength = client.contentLength(); - - // read the response body - response = ""; - response.reserve(contentLength); - while (client.available()) { - response += (char)client.read(); - } + response = client.responseBody(); Serial.print("Status code: "); Serial.println(statusCode); diff --git a/examples/SimplePut/SimplePut.ino b/examples/SimplePut/SimplePut.ino index 611f55c..30da9c0 100644 --- a/examples/SimplePut/SimplePut.ino +++ b/examples/SimplePut/SimplePut.ino @@ -26,7 +26,6 @@ HttpClient client = HttpClient(wifi, serverAddress, port); int status = WL_IDLE_STATUS; String response; int statusCode = 0; -int contentLength = 0; void setup() { Serial.begin(9600); @@ -50,25 +49,14 @@ void setup() { void loop() { Serial.println("making PUT request"); + String contentType = "application/x-www-form-urlencoded"; String putData = "name=light&age=46"; - client.beginRequest(); - client.put("/"); - client.sendHeader("Content-Type", "application/x-www-form-urlencoded"); - client.sendHeader("Content-Length", putData.length()); - client.endRequest(); - client.write((const byte*)putData.c_str(), putData.length()); + client.put("/", contentType, putData); - // read the status code and content length of the response + // read the status code and body of the response statusCode = client.responseStatusCode(); - contentLength = client.contentLength(); - - // read the response body - response = ""; - response.reserve(contentLength); - while (client.available()) { - response += (char)client.read(); - } + response = client.responseBody(); Serial.print("Status code: "); Serial.println(statusCode); diff --git a/keywords.txt b/keywords.txt index dc1140e..00bf130 100644 --- a/keywords.txt +++ b/keywords.txt @@ -33,6 +33,7 @@ noDefaultRequestHeaders KEYWORD2 headerAvailable KEYWORD2 readHeaderName KEYWORD2 readHeaderValue KEYWORD2 +responseBody KEYWORD2 ####################################### # Constants (LITERAL1)