From bb9bd9b42287c2a5c37ab0054d10430705faaf5f Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 09:31:49 -0400 Subject: [PATCH 01/27] Rename to ArduinoHttpClient, and other metadata updates --- README.md | 6 ++++-- library.properties | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d55dfa4..5536b55 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# HttpClient +# ArduinoHttpClient -HttpClient is a library to make it easier to interact with web servers from Arduino. +ArduinoHttpClient is a library to make it easier to interact with web servers from Arduino. + +Derived from [Adrian McEwen's HttpClient library](https://github.com/amcewen/HttpClient) ## Dependencies diff --git a/library.properties b/library.properties index 577c5d9..35c75cc 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=HttpClient +name=ArduinoHttpClient version=2.2.0 author=Adrian McEwen -maintainer=Adrian McEwen +maintainer=Arduino sentence=Library to easily make HTTP GET, POST and PUT requests to a web server. paragraph=Works with any class derived from Client - so switching between Ethernet, WiFi and GSMClient requires minimal code changes. category=Communication -url=http://github.com/amcewen/HttpClient +url=https://github.com/arduino-libraries/ArduinoHttpClient architectures=* From e057c073d9759f0dd14feba55962e43553f76932 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 09:32:05 -0400 Subject: [PATCH 02/27] Add ArduinoHttpClient.h --- ArduinoHttpClient.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 ArduinoHttpClient.h diff --git a/ArduinoHttpClient.h b/ArduinoHttpClient.h new file mode 100644 index 0000000..f43f59a --- /dev/null +++ b/ArduinoHttpClient.h @@ -0,0 +1,10 @@ +// Class to simplify HTTP fetching on Arduino +// (c) Copyright Arduino. 2016 +// Released under Apache License, version 2.0 + +#ifndef ArduinoHttpClient_h +#define ArduinoHttpClient_h + +#include "HttpClient.h" + +#endif From b72b7056a966a60149ce3ba697225d46a380dd2d Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 09:41:12 -0400 Subject: [PATCH 03/27] Update example to use WiFi101 --- .../SimpleHttpExample/SimpleHttpExample.ino | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino index f12f987..351ff2b 100644 --- a/examples/SimpleHttpExample/SimpleHttpExample.ino +++ b/examples/SimpleHttpExample/SimpleHttpExample.ino @@ -6,20 +6,20 @@ // outputs the content to the serial port #include -#include -#include -#include +#include +#include // This example downloads the URL "http://arduino.cc/" +char ssid[] = "yourNetwork"; // your network SSID (name) +char pass[] = "secretPassword"; // your network password + // Name of the server we want to connect to const char kHostname[] = "arduino.cc"; // Path to download (this is the bit after the hostname in the URL // that you want to download const char kPath[] = "/"; -byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; - // Number of milliseconds to wait without receiving any data before we give up const int kNetworkTimeout = 30*1000; // Number of milliseconds to wait if no data is available before trying again @@ -27,21 +27,30 @@ const int kNetworkDelay = 1000; void setup() { - // initialize serial communications at 9600 bps: - Serial.begin(9600); + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } - while (Ethernet.begin(mac) != 1) - { - Serial.println("Error getting IP address via DHCP, trying again..."); - delay(15000); - } + // attempt to connect to Wifi network: + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + while (WiFi.begin(ssid, pass) != WL_CONNECTED) { + // unsuccessful, retry in 4 seconds + Serial.print("failed ... "); + delay(4000); + Serial.print("retrying ... "); + } + + Serial.println("connected"); } void loop() { int err =0; - EthernetClient c; + WiFiClient c; HttpClient http(c); err = http.get(kHostname, kPath); From ad9bd941367f0ae0cb53e6c069161644681f4a74 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 10:02:32 -0400 Subject: [PATCH 04/27] Wrap proxy member var declarations in #ifdef --- HttpClient.cpp | 2 +- HttpClient.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 5a11a45..6efc4ea 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -29,7 +29,7 @@ HttpClient::HttpClient(Client& aClient, const char* aProxy, uint16_t aProxyPort) } #else HttpClient::HttpClient(Client& aClient) - : iClient(&aClient), iProxyPort(0) + : iClient(&aClient) { resetState(); } diff --git a/HttpClient.h b/HttpClient.h index b4c3974..ff00083 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -440,9 +440,11 @@ protected: int iBodyLengthConsumed; // How far through a Content-Length header prefix we are const char* iContentLengthPtr; +#ifdef PROXY_ENABLED // Address of the proxy to use, if we're using one IPAddress iProxyAddress; uint16_t iProxyPort; +#endif uint32_t iHttpResponseTimeout; }; From e3a6c20cd99517bfbd0e1781998f2285425e20a1 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 10:13:56 -0400 Subject: [PATCH 05/27] Remove proxy support (for now) --- HttpClient.cpp | 85 +++++--------------------------------------------- HttpClient.h | 9 ------ 2 files changed, 7 insertions(+), 87 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 6efc4ea..3e7c852 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -4,36 +4,16 @@ #include "HttpClient.h" #include "b64.h" -#ifdef PROXY_ENABLED // currently disabled as introduces dependency on Dns.h in Ethernet -#include -#endif // Initialize constants const char* HttpClient::kUserAgent = "Arduino/2.2.0"; const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": "; -#ifdef PROXY_ENABLED // currently disabled as introduces dependency on Dns.h in Ethernet -HttpClient::HttpClient(Client& aClient, const char* aProxy, uint16_t aProxyPort) - : iClient(&aClient), iProxyPort(aProxyPort) -{ - resetState(); - if (aProxy) - { - // Resolve the IP address for the proxy - DNSClient dns; - dns.begin(Ethernet.dnsServerIP()); - // Not ideal that we discard any errors here, but not a lot we can do in the ctor - // and we'll get a connect error later anyway - (void)dns.getHostByName(aProxy, iProxyAddress); - } -} -#else HttpClient::HttpClient(Client& aClient) : iClient(&aClient) { resetState(); } -#endif void HttpClient::resetState() { @@ -64,27 +44,12 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons return HTTP_ERROR_API; } -#ifdef PROXY_ENABLED - if (iProxyPort) + if (!iClient->connect(aServerName, aServerPort) > 0) { - if (!iClient->connect(iProxyAddress, iProxyPort) > 0) - { #ifdef LOGGING - Serial.println("Proxy connection failed"); + Serial.println("Connection failed"); #endif - return HTTP_ERROR_CONNECTION_FAILED; - } - } - else -#endif - { - if (!iClient->connect(aServerName, aServerPort) > 0) - { -#ifdef LOGGING - Serial.println("Connection failed"); -#endif - return HTTP_ERROR_CONNECTION_FAILED; - } + return HTTP_ERROR_CONNECTION_FAILED; } // Now we're connected, send the first part of the request @@ -107,27 +72,12 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServe return HTTP_ERROR_API; } -#ifdef PROXY_ENABLED - if (iProxyPort) + if (!iClient->connect(aServerAddress, aServerPort) > 0) { - if (!iClient->connect(iProxyAddress, iProxyPort) > 0) - { #ifdef LOGGING - Serial.println("Proxy connection failed"); + Serial.println("Connection failed"); #endif - return HTTP_ERROR_CONNECTION_FAILED; - } - } - else -#endif - { - if (!iClient->connect(aServerAddress, aServerPort) > 0) - { -#ifdef LOGGING - Serial.println("Connection failed"); -#endif - return HTTP_ERROR_CONNECTION_FAILED; - } + return HTTP_ERROR_CONNECTION_FAILED; } // Now we're connected, send the first part of the request @@ -150,28 +100,7 @@ int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, // Send the HTTP command, i.e. "GET /somepath/ HTTP/1.0" iClient->print(aHttpMethod); iClient->print(" "); -#ifdef PROXY_ENABLED - if (iProxyPort) - { - // We're going through a proxy, send a full URL - iClient->print("http://"); - if (aServerName) - { - // We've got a server name, so use it - iClient->print(aServerName); - } - else - { - // We'll have to use the IP address - iClient->print(aServerIP); - } - if (aPort != kHttpPort) - { - iClient->print(":"); - iClient->print(aPort); - } - } -#endif + iClient->print(aURLPath); iClient->println(" HTTP/1.1"); // The host header, if required diff --git a/HttpClient.h b/HttpClient.h index ff00083..d4d980c 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -44,11 +44,7 @@ public: // FIXME Write longer API request, using port and user-agent, example // FIXME Update tempToPachube example to calculate Content-Length correctly -#ifdef PROXY_ENABLED // currently disabled as introduces dependency on Dns.h in Ethernet - HttpClient(Client& aClient, const char* aProxy =NULL, uint16_t aProxyPort =0); -#else HttpClient(Client& aClient); -#endif /** Start a more complex request. Use this when you need to send additional headers in the request, @@ -440,11 +436,6 @@ protected: int iBodyLengthConsumed; // How far through a Content-Length header prefix we are const char* iContentLengthPtr; -#ifdef PROXY_ENABLED - // Address of the proxy to use, if we're using one - IPAddress iProxyAddress; - uint16_t iProxyPort; -#endif uint32_t iHttpResponseTimeout; }; From 0030d412876add1418e4d3efa2995bd50b2a9bc0 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 10:56:27 -0400 Subject: [PATCH 06/27] Make server name/address and port constructor arguments --- HttpClient.cpp | 84 +++---- HttpClient.h | 227 ++---------------- .../SimpleHttpExample/SimpleHttpExample.ino | 4 +- 3 files changed, 53 insertions(+), 262 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 3e7c852..a96ef80 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -9,8 +9,14 @@ const char* HttpClient::kUserAgent = "Arduino/2.2.0"; const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": "; -HttpClient::HttpClient(Client& aClient) - : iClient(&aClient) +HttpClient::HttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort) + : iClient(&aClient), iServerName(aServerName), iServerAddress(), iServerPort(aServerPort) +{ + resetState(); +} + +HttpClient::HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort) + : iClient(&aClient), iServerName(NULL), iServerAddress(aServerAddress), iServerPort(aServerPort) { resetState(); } @@ -36,7 +42,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* aURLPath, const char* aHttpMethod) { tHttpState initialState = iState; if ((eIdle != iState) && (eRequestStarted != iState)) @@ -44,16 +50,26 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons return HTTP_ERROR_API; } - if (!iClient->connect(aServerName, aServerPort) > 0) - { -#ifdef LOGGING - Serial.println("Connection failed"); -#endif - return HTTP_ERROR_CONNECTION_FAILED; + 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; + } } // Now we're connected, send the first part of the request - int ret = sendInitialHeaders(aServerName, IPAddress(0,0,0,0), aServerPort, aURLPath, aHttpMethod, aUserAgent); + int ret = sendInitialHeaders(aURLPath, aHttpMethod); if ((initialState == eIdle) && (HTTP_SUCCESS == ret)) { // This was a simple version of the API, so terminate the headers now @@ -64,35 +80,7 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons return ret; } -int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent) -{ - tHttpState initialState = iState; - if ((eIdle != iState) && (eRequestStarted != iState)) - { - return HTTP_ERROR_API; - } - - if (!iClient->connect(aServerAddress, aServerPort) > 0) - { -#ifdef LOGGING - Serial.println("Connection failed"); -#endif - return HTTP_ERROR_CONNECTION_FAILED; - } - - // Now we're connected, send the first part of the request - int ret = sendInitialHeaders(aServerName, aServerAddress, aServerPort, aURLPath, aHttpMethod, aUserAgent); - if ((initialState == eIdle) && (HTTP_SUCCESS == ret)) - { - // 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. - - return ret; -} - -int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, uint16_t aPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent) +int HttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod) { #ifdef LOGGING Serial.println("Connected"); @@ -104,26 +92,20 @@ int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, iClient->print(aURLPath); iClient->println(" HTTP/1.1"); // The host header, if required - if (aServerName) + if (iServerName) { iClient->print("Host: "); - iClient->print(aServerName); - if (aPort != kHttpPort) + iClient->print(iServerName); + if (iServerPort != kHttpPort) { iClient->print(":"); - iClient->print(aPort); + iClient->print(iServerPort); } iClient->println(); } // And user-agent string - if (aUserAgent) - { - sendHeader(HTTP_HEADER_USER_AGENT, aUserAgent); - } - else - { - sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent); - } + 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"); diff --git a/HttpClient.h b/HttpClient.h index d4d980c..677bb55 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -44,7 +44,8 @@ public: // FIXME Write longer API request, using port and user-agent, example // FIXME Update tempToPachube example to calculate Content-Length correctly - HttpClient(Client& aClient); + HttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort = kHttpPort); + HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = kHttpPort); /** Start a more complex request. Use this when you need to send additional headers in the request, @@ -59,219 +60,33 @@ public: void endRequest(); /** 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 - @param aServerPort Port to connect to on the server @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent @return 0 if successful, else error */ - int get(const char* aServerName, uint16_t aServerPort, const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } - - /** 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 - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @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); } - - /** 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. - @param aServerAddress IP address of the server to connect to - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerPort Port to connect to on the server - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int get(const IPAddress& aServerAddress, - const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } - - /** 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. - @param aServerAddress IP address of the server to connect to - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int get(const IPAddress& aServerAddress, - const char* aServerName, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } + int get(const char* aURLPath) + { return startRequest(aURLPath, HTTP_METHOD_GET); } /** Connect to the server and start to send a POST request. - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerPort Port to connect to on the server @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent @return 0 if successful, else error */ - int post(const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } - - /** Connect to the server and start to send a POST request. - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int post(const char* aServerName, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } - - /** 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. - @param aServerAddress IP address of the server to connect to - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerPort Port to connect to on the server - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int post(const IPAddress& aServerAddress, - const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } - - /** 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. - @param aServerAddress IP address of the server to connect to - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - 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); } + int post(const char* aURLPath) + { return startRequest(aURLPath, HTTP_METHOD_POST); } /** Connect to the server and start to send a PUT request. - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerPort Port to connect to on the server @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent @return 0 if successful, else error */ - int put(const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } - - /** Connect to the server and start to send a PUT request. - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int put(const char* aServerName, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } - - /** 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. - @param aServerAddress IP address of the server to connect to - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerPort Port to connect to on the server - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int put(const IPAddress& aServerAddress, - const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } - - /** 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. - @param aServerAddress IP address of the server to connect to - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aURLPath Url to request - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int put(const IPAddress& aServerAddress, - const char* aServerName, - const char* aURLPath, - const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } + int put(const char* aURLPath) + { return startRequest(aURLPath, HTTP_METHOD_PUT); } /** Connect to the server and start to send the request. - @param aServerName Name of the server being connected to. - @param aServerPort Port to connect to on the server @param aURLPath Url to request @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent @return 0 if successful, else error */ - int startRequest(const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aHttpMethod, - const char* aUserAgent); - - /** Connect to the server and start to send the request. - @param aServerAddress IP address of the server to connect to. - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerPort Port to connect to on the server - @param aURLPath Url to request - @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent - @return 0 if successful, else error - */ - int startRequest(const IPAddress& aServerAddress, - const char* aServerName, - uint16_t aServerPort, - const char* aURLPath, - const char* aHttpMethod, - const char* aUserAgent); + int startRequest(const char* aURLPath, + const char* aHttpMethod); /** Send an additional header line. This can only be called in between the calls to startRequest and finishRequest. @@ -383,23 +198,12 @@ protected: void resetState(); /** Send the first part of the request and the initial headers. - @param aServerName Name of the server being connected to. If NULL, the - "Host" header line won't be sent - @param aServerIP IP address of the server (only used if we're going through a - proxy and aServerName is NULL - @param aServerPort Port of the server being connected to. @param aURLPath Url to request @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. - @param aUserAgent User-Agent string to send. If NULL the default - user-agent kUserAgent will be sent @return 0 if successful, else error */ - int sendInitialHeaders(const char* aServerName, - IPAddress aServerIP, - uint16_t aPort, - const char* aURLPath, - const char* aHttpMethod, - const char* aUserAgent); + int sendInitialHeaders(const char* aURLPath, + const char* aHttpMethod); /* Let the server know that we've reached the end of the headers */ @@ -424,8 +228,13 @@ protected: eLineStartingCRFound, eReadingBody } tHttpState; - // Ethernet client we're using + // Client we're using Client* iClient; + // Server we are connecting to + const char* iServerName; + IPAddress iServerAddress; + // Port of server we are connecting to + uint16_t iServerPort; // Current state of the finite-state-machine tHttpState iState; // Stores the status code for the response, once known diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino index 351ff2b..dd8cb10 100644 --- a/examples/SimpleHttpExample/SimpleHttpExample.ino +++ b/examples/SimpleHttpExample/SimpleHttpExample.ino @@ -51,9 +51,9 @@ void loop() int err =0; WiFiClient c; - HttpClient http(c); + HttpClient http(c, kHostname); - err = http.get(kHostname, kPath); + err = http.get(kPath); if (err == 0) { Serial.println("startedRequest ok"); From 3beefd981a3b3def8ebf5948699a36971bfe054f Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 11:01:38 -0400 Subject: [PATCH 07/27] Add support for String parameter types for host and URL path --- HttpClient.cpp | 5 +++++ HttpClient.h | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/HttpClient.cpp b/HttpClient.cpp index a96ef80..0cbf083 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -15,6 +15,11 @@ HttpClient::HttpClient(Client& aClient, const char* aServerName, uint16_t aServe resetState(); } +HttpClient::HttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort) + : HttpClient(aClient, aServerName.c_str(), aServerPort) +{ +} + HttpClient::HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort) : iClient(&aClient), iServerName(NULL), iServerAddress(aServerAddress), iServerPort(aServerPort) { diff --git a/HttpClient.h b/HttpClient.h index 677bb55..5d48008 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -45,6 +45,7 @@ public: // FIXME Update tempToPachube example to calculate Content-Length correctly HttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort = kHttpPort); + HttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort = kHttpPort); HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = kHttpPort); /** Start a more complex request. @@ -66,6 +67,9 @@ public: int get(const char* aURLPath) { return startRequest(aURLPath, HTTP_METHOD_GET); } + int get(const String& aURLPath) + { return get(aURLPath.c_str()); } + /** Connect to the server and start to send a POST request. @param aURLPath Url to request @return 0 if successful, else error @@ -73,6 +77,9 @@ public: int post(const char* aURLPath) { return startRequest(aURLPath, HTTP_METHOD_POST); } + int post(const String& aURLPath) + { return post(aURLPath.c_str()); } + /** Connect to the server and start to send a PUT request. @param aURLPath Url to request @return 0 if successful, else error @@ -80,6 +87,9 @@ public: int put(const char* aURLPath) { return startRequest(aURLPath, HTTP_METHOD_PUT); } + int put(const String& aURLPath) + { return put(aURLPath.c_str()); } + /** 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. From 777b561cc539983d7b84903237e53c8527e47fbe Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 11:09:14 -0400 Subject: [PATCH 08/27] Make white space consistent --- HttpClient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 0cbf083..65099e1 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -375,11 +375,11 @@ int HttpClient::read() if (ret >= 0) { if (endOfHeadersReached() && iContentLength > 0) - { + { // We're outputting the body now and we've seen a Content-Length header // So keep track of how many bytes are left iBodyLengthConsumed++; - } + } } return ret; #endif @@ -393,9 +393,9 @@ int HttpClient::read(uint8_t *buf, size_t size) // We're outputting the body now and we've seen a Content-Length header // So keep track of how many bytes are left if (ret >= 0) - { + { iBodyLengthConsumed += ret; - } + } } return ret; } From 625154754a009bcab987154689ce6b277266de9b Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 11:09:37 -0400 Subject: [PATCH 09/27] Remove unused code --- HttpClient.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 65099e1..600820f 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -359,18 +359,6 @@ bool HttpClient::endOfBodyReached() int HttpClient::read() { -#if 0 // Fails on WiFi because multi-byte read seems to be broken - uint8_t b[1]; - int ret = read(b, 1); - if (ret == 1) - { - return b[0]; - } - else - { - return -1; - } -#else int ret = iClient->read(); if (ret >= 0) { @@ -382,7 +370,6 @@ int HttpClient::read() } } return ret; -#endif } int HttpClient::read(uint8_t *buf, size_t size) From 9ab55ef6e2da26d72c9f41a63e8abe4bdbce1199 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 12:48:49 -0400 Subject: [PATCH 10/27] New API's to read header name and value as String's --- HttpClient.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ HttpClient.h | 17 ++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/HttpClient.cpp b/HttpClient.cpp index 600820f..d969ce4 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -372,6 +372,68 @@ int HttpClient::read() return ret; } +bool HttpClient::headerAvailable() +{ + // clear the currently store header line + iHeaderLine = ""; + + while (!endOfHeadersReached()) + { + // read a byte from the header + int c = readHeader(); + + if (c == '\r' || c == '\n') + { + if (iHeaderLine.length()) + { + // end of the line, all done + break; + } + else + { + // ignore any CR or LF characters + continue; + } + } + + // append byte to header line + iHeaderLine += (char)c; + } + + return (iHeaderLine.length() > 0); +} + +String HttpClient::readHeaderName() +{ + int colonIndex = iHeaderLine.indexOf(':'); + + if (colonIndex == -1) + { + return ""; + } + + return iHeaderLine.substring(0, colonIndex); +} + +String HttpClient::readHeaderValue() +{ + int colonIndex = iHeaderLine.indexOf(':'); + int startIndex = colonIndex + 1; + + if (colonIndex == -1) + { + return ""; + } + + // trim any leading whitespace + while (startIndex < (int)iHeaderLine.length() && isSpace(iHeaderLine[startIndex])) + { + startIndex++; + } + + return iHeaderLine.substring(startIndex); +} + int HttpClient::read(uint8_t *buf, size_t size) { int ret =iClient->read(buf, size); diff --git a/HttpClient.h b/HttpClient.h index 5d48008..e8312f8 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -142,6 +142,22 @@ public: */ int responseStatusCode(); + /** Check if a header is available to be read. + Use readHeaderName() to read header name, and readHeaderValue() to + read the header value + */ + bool headerAvailable(); + + /** Read the name of the current response header. + Returns empty string if a header is not available. + */ + String readHeaderName(); + + /** Read the vallue of the current response header. + Returns empty string if a header is not available. + */ + String readHeaderValue(); + /** Read the next character of the response headers. This functions in the same way as read() but to be used when reading through the headers. Check whether or not the end of the headers has @@ -256,6 +272,7 @@ protected: // How far through a Content-Length header prefix we are const char* iContentLengthPtr; uint32_t iHttpResponseTimeout; + String iHeaderLine; }; #endif From 33804d4534dbd4b04ba589849525f8aaa027a2e7 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 12:55:17 -0400 Subject: [PATCH 11/27] Add support for String parameters to sendHeader and sendHeader --- HttpClient.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/HttpClient.h b/HttpClient.h index e8312f8..ce6a761 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -105,6 +105,9 @@ public: */ void sendHeader(const char* aHeader); + void sendHeader(const String& aHeader) + { sendHeader(aHeader.c_str()); } + /** Send an additional header line. This is an alternate form of sendHeader() which takes the header name and content as separate strings. The call will add the ": " to separate the header, so for example, to @@ -114,6 +117,9 @@ public: */ void sendHeader(const char* aHeaderName, const char* aHeaderValue); + void sendHeader(const String& aHeaderName, const String& aHeaderValue) + { sendHeader(aHeaderName.c_str(), aHeaderValue.c_str()); } + /** Send an additional header line. This is an alternate form of sendHeader() which takes the header name and content separately but where the value is provided as an integer. @@ -124,6 +130,9 @@ public: */ void sendHeader(const char* aHeaderName, const int aHeaderValue); + void sendHeader(const String& aHeaderName, const int aHeaderValue) + { sendHeader(aHeaderName.c_str(), aHeaderValue); } + /** Send a basic authentication header. This will encode the given username and password, and send them in suitable header line for doing Basic Authentication. @@ -132,6 +141,9 @@ public: */ void sendBasicAuth(const char* aUser, const char* aPassword); + void sendBasicAuth(const String& aUser, const String& aPassword) + { sendBasicAuth(aUser.c_str(), aPassword.c_str()); } + /** Finish sending the HTTP request. This basically just sends the blank line to signify the end of the request */ From bfedff87c1641a57b9fc47d3346c0de14e39bb53 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 14:18:11 -0400 Subject: [PATCH 12/27] 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; }; From 4b6f4dfa2912d77bd58e8f386fdbd8bda31766ea Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 14:37:51 -0400 Subject: [PATCH 13/27] Add check for bodyLen in read loop --- examples/SimpleHttpExample/SimpleHttpExample.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino index dd8cb10..d409b42 100644 --- a/examples/SimpleHttpExample/SimpleHttpExample.ino +++ b/examples/SimpleHttpExample/SimpleHttpExample.ino @@ -6,8 +6,8 @@ // outputs the content to the serial port #include -#include #include +#include // This example downloads the URL "http://arduino.cc/" @@ -82,6 +82,7 @@ void loop() char c; // Whilst we haven't timed out & haven't reached the end of the body while ( (http.connected() || http.available()) && + (bodyLen > 0 || bodyLen != HttpClient::kNoContentLengthHeader) && ((millis() - timeoutStart) < kNetworkTimeout) ) { if (http.available()) From 255118660bcc84253fae507b6ea8b749bb79509b Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 14:55:03 -0400 Subject: [PATCH 14/27] Make skipResponseHeaders() optional, if contentLength() is called first --- HttpClient.cpp | 11 +++ HttpClient.h | 7 +- .../SimpleHttpExample/SimpleHttpExample.ino | 75 +++++++++---------- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 055c121..dc1bb5a 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -384,6 +384,17 @@ int HttpClient::skipResponseHeaders() } } +int HttpClient::contentLength() +{ + // skip the response headers, if they haven't been read already + if (!endOfHeadersReached()) + { + skipResponseHeaders(); + } + + return iContentLength; +} + bool HttpClient::endOfBodyReached() { if (endOfHeadersReached() && (contentLength() != kNoContentLengthHeader)) diff --git a/HttpClient.h b/HttpClient.h index 79ad889..0066bbc 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -159,6 +159,7 @@ public: /** Check if a header is available to be read. Use readHeaderName() to read header name, and readHeaderValue() to read the header value + MUST be called after responseStatusCode() and before contentLength() */ bool headerAvailable(); @@ -177,6 +178,7 @@ public: through the headers. Check whether or not the end of the headers has been reached by calling endOfHeadersReached(), although after that point this will still return data as read() would, but slightly less efficiently + MUST be called after responseStatusCode() and before contentLength() @return The next character of the response headers */ int readHeader(); @@ -186,6 +188,7 @@ public: returned in the response. You can also use it after you've found all of the headers you're interested in, and just want to get on with processing the body. + MUST be called after responseStatusCode() @return HTTP_SUCCESS if successful, else an error code */ int skipResponseHeaders(); @@ -204,10 +207,12 @@ public: virtual bool completed() { return endOfBodyReached(); }; /** Return the length of the body. + Also skips response headers if they have not been read already + MUST be called after responseStatusCode() @return Length of the body, in bytes, or kNoContentLengthHeader if no Content-Length header was returned by the server */ - int contentLength() { return iContentLength; }; + int contentLength(); // Inherited from Print // Note: 1st call to these indicates the user is sending the body, so if need diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino index d409b42..79ac237 100644 --- a/examples/SimpleHttpExample/SimpleHttpExample.ino +++ b/examples/SimpleHttpExample/SimpleHttpExample.ino @@ -68,45 +68,44 @@ void loop() // similar "success" code (200-299) before carrying on, // but we'll print out whatever response we get - err = http.skipResponseHeaders(); - if (err >= 0) + // If you are interesting in the response headers, you + // can read them here: + //while(http.headerAvailable()) + //{ + // String headerName = http.readHeaderName(); + // String headerValue = http.readHeaderValue(); + //} + + int bodyLen = http.contentLength(); + Serial.print("Content length is: "); + Serial.println(bodyLen); + Serial.println(); + Serial.println("Body returned follows:"); + + // Now we've got to the body, so we can print it out + unsigned long timeoutStart = millis(); + char c; + // Whilst we haven't timed out & haven't reached the end of the body + while ( (http.connected() || http.available()) && + (bodyLen > 0 || bodyLen != HttpClient::kNoContentLengthHeader) && + ((millis() - timeoutStart) < kNetworkTimeout) ) { - int bodyLen = http.contentLength(); - Serial.print("Content length is: "); - Serial.println(bodyLen); - Serial.println(); - Serial.println("Body returned follows:"); - - // Now we've got to the body, so we can print it out - unsigned long timeoutStart = millis(); - char c; - // Whilst we haven't timed out & haven't reached the end of the body - while ( (http.connected() || http.available()) && - (bodyLen > 0 || bodyLen != HttpClient::kNoContentLengthHeader) && - ((millis() - timeoutStart) < kNetworkTimeout) ) - { - if (http.available()) - { - c = http.read(); - // Print out this character - Serial.print(c); - - bodyLen--; - // We read something, reset the timeout counter - timeoutStart = millis(); - } - else - { - // We haven't got any data, so let's pause to allow some to - // arrive - delay(kNetworkDelay); - } - } - } - else - { - Serial.print("Failed to skip response headers: "); - Serial.println(err); + if (http.available()) + { + c = http.read(); + // Print out this character + Serial.print(c); + + bodyLen--; + // We read something, reset the timeout counter + timeoutStart = millis(); + } + else + { + // We haven't got any data, so let's pause to allow some to + // arrive + delay(kNetworkDelay); + } } } else From 7ee216f4aaaa633aa26a1dcf3658dd51a042010e Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 14:58:17 -0400 Subject: [PATCH 15/27] Use http.endOfBodyReached() in example instead of tracking body len --- examples/SimpleHttpExample/SimpleHttpExample.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino index 79ac237..550015a 100644 --- a/examples/SimpleHttpExample/SimpleHttpExample.ino +++ b/examples/SimpleHttpExample/SimpleHttpExample.ino @@ -87,7 +87,7 @@ void loop() char c; // Whilst we haven't timed out & haven't reached the end of the body while ( (http.connected() || http.available()) && - (bodyLen > 0 || bodyLen != HttpClient::kNoContentLengthHeader) && + (!http.endOfBodyReached()) && ((millis() - timeoutStart) < kNetworkTimeout) ) { if (http.available()) @@ -96,7 +96,6 @@ void loop() // Print out this character Serial.print(c); - bodyLen--; // We read something, reset the timeout counter timeoutStart = millis(); } From 343a417d1b866f21b9a72a7f49177e6287442c85 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 14:59:37 -0400 Subject: [PATCH 16/27] Update header comment --- ArduinoHttpClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArduinoHttpClient.h b/ArduinoHttpClient.h index f43f59a..2064028 100644 --- a/ArduinoHttpClient.h +++ b/ArduinoHttpClient.h @@ -1,4 +1,4 @@ -// Class to simplify HTTP fetching on Arduino +// Library to simplify HTTP fetching on Arduino // (c) Copyright Arduino. 2016 // Released under Apache License, version 2.0 From c5484daee912f8ae8fda9cf3b45e379f9230f501 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 15:08:11 -0400 Subject: [PATCH 17/27] Update keywords.txt for new API's --- keywords.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/keywords.txt b/keywords.txt index cdefda4..66489d6 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,6 +6,7 @@ # Datatypes (KEYWORD1) ####################################### +ArduinoHttpClient KEYWORD1 HttpClient KEYWORD1 ####################################### @@ -27,6 +28,9 @@ endOfHeadersReached KEYWORD2 endOfBodyReached KEYWORD2 completed KEYWORD2 contentLength KEYWORD2 +headerAvailable KEYWORD2 +readHeaderName KEYWORD2 +readHeaderValue KEYWORD2 ####################################### # Constants (LITERAL1) From 91ea1fd8fa867e541785943458d77e395e1a3d7c Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 15:10:32 -0400 Subject: [PATCH 18/27] Remove installation instructions, update dependencies --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5536b55..655b618 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,17 @@ Derived from [Adrian McEwen's HttpClient library](https://github.com/amcewen/Htt ## Dependencies -- Requires the new Ethernet library API (with DHCP and DNS) which is in Arduino 1.0 and later - -## Installation - -1. Download the latest version of the library from https://github.com/amcewen/HttpClient/releases and save the file somewhere -1. In the Arduino IDE, go to the Sketch -> Import Library -> Add Library... menu option -1. Find the zip file that you saved in the first step, and choose that -1. Check that it has been successfully added by opening the Sketch -> Import Library menu. You should now see HttpClient listed among the available libraries. +- Requires a networking hardware and a library that provides transport specific `Client` instance, such as: + - [WiFi101](https://github.com/arduino-libraries/WiFi101) + - [Ethernet](https://github.com/arduino-libraries/Ethernet) + - [WiFi](https://github.com/arduino-libraries/WiFi) + - [GSM](https://github.com/arduino-libraries/GSM) ## Usage In normal usage, handles the outgoing request and Host header. The returned status code is parsed for you, as is the Content-Length header (if present). -Because it expects an object of type Client, you can use it with any of the networking classes that derive from that. Which means it will work with EthernetClient, WiFiClient and GSMClient. +Because it expects an object of type Client, you can use it with any of the networking classes that derive from that. Which means it will work with WiFiClient, EthernetClient and GSMClient. See the examples for more detail on how the library is used. From f12a797fb3184e6672404710d16ef86c6ddfc341 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 15:20:16 -0400 Subject: [PATCH 19/27] Add connectionKeepAlive to keywords.txt and add comment for it --- HttpClient.h | 2 ++ keywords.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/HttpClient.h b/HttpClient.h index 0066bbc..e03b3ed 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); + /** Enables connection keep-alive mode + */ void connectionKeepAlive(); /** Start a more complex request. diff --git a/keywords.txt b/keywords.txt index 66489d6..16c8a2d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -28,6 +28,7 @@ endOfHeadersReached KEYWORD2 endOfBodyReached KEYWORD2 completed KEYWORD2 contentLength KEYWORD2 +connectionKeepAlive KEYWORD2 headerAvailable KEYWORD2 readHeaderName KEYWORD2 readHeaderValue KEYWORD2 From 5df9084d8e484372b8c3a7d238d0be45620c3d81 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 15:34:49 -0400 Subject: [PATCH 20/27] Correct some warnings --- HttpClient.cpp | 5 ++++- b64.cpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index dc1bb5a..3dcf252 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -252,7 +252,7 @@ int HttpClient::responseStatusCode() // Where HTTP-Version is of the form: // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT - char c = '\0'; + int c = '\0'; do { // Make sure the status code is reset, and likewise the state. This @@ -311,6 +311,9 @@ int HttpClient::responseStatusCode() case eStatusCodeRead: // We're just waiting for the end of the line now break; + + default: + break; }; // We read something, reset the timeout counter timeoutStart = millis(); diff --git a/b64.cpp b/b64.cpp index b926cad..683d60a 100644 --- a/b64.cpp +++ b/b64.cpp @@ -66,5 +66,7 @@ int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutpu b64_encode(&aInput[i*3], aInputLen % 3, &aOutput[i*4], aOutputLen - (i*4)); } } + + return ((aInputLen+2)/3)*4; } From 70dc5ee44ea9a99d07ae45bbaed85705126bb76b Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 16:37:32 -0400 Subject: [PATCH 21/27] Remove unimplemented finishRequest from header --- HttpClient.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/HttpClient.h b/HttpClient.h index e03b3ed..ab88408 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -148,11 +148,6 @@ public: void sendBasicAuth(const String& aUser, const String& aPassword) { sendBasicAuth(aUser.c_str(), aPassword.c_str()); } - /** Finish sending the HTTP request. This basically just sends the blank - line to signify the end of the request - */ - void finishRequest(); - /** Get the HTTP status code contained in the response. For example, 200 for successful request, 404 for file not found, etc. */ From 0bcba913fd441ec56cd1611c9db1b6550f476436 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 16:38:09 -0400 Subject: [PATCH 22/27] Move storing of initialState in startRequest to the start --- HttpClient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 3dcf252..db0879d 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -56,6 +56,8 @@ void HttpClient::beginRequest() int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod) { + tHttpState initialState = iState; + if (!iConnectionClose) { flushClientRx(); @@ -63,7 +65,6 @@ int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod) resetState(); } - tHttpState initialState = iState; if ((eIdle != iState) && (eRequestStarted != iState)) { return HTTP_ERROR_API; From 8012c8dace3e629cf160f19197fa1acbb138fb90 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 16:49:52 -0400 Subject: [PATCH 23/27] Add noDefaultRequestHeaders API to turn off sending default headers --- HttpClient.cpp | 32 ++++++++++++++++++++------------ HttpClient.h | 5 +++++ keywords.txt | 1 + 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index db0879d..9176108 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -11,7 +11,7 @@ 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), - iConnectionClose(true) + iConnectionClose(true), iSendDefaultRequestHeaders(true) { resetState(); } @@ -23,7 +23,7 @@ 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), - iConnectionClose(true) + iConnectionClose(true), iSendDefaultRequestHeaders(true) { resetState(); } @@ -49,6 +49,11 @@ void HttpClient::connectionKeepAlive() iConnectionClose = false; } +void HttpClient::noDefaultRequestHeaders() +{ + iSendDefaultRequestHeaders = false; +} + void HttpClient::beginRequest() { iState = eRequestStarted; @@ -120,20 +125,23 @@ int HttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod iClient->print(aURLPath); iClient->println(" HTTP/1.1"); - // The host header, if required - if (iServerName) + if (iSendDefaultRequestHeaders) { - iClient->print("Host: "); - iClient->print(iServerName); - if (iServerPort != kHttpPort) + // The host header, if required + if (iServerName) { - iClient->print(":"); - iClient->print(iServerPort); + iClient->print("Host: "); + iClient->print(iServerName); + if (iServerPort != kHttpPort) + { + iClient->print(":"); + iClient->print(iServerPort); + } + iClient->println(); } - iClient->println(); + // And user-agent string + sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent); } - // And user-agent string - sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent); if (iConnectionClose) { diff --git a/HttpClient.h b/HttpClient.h index ab88408..2394c46 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -52,6 +52,10 @@ public: */ void connectionKeepAlive(); + /** Disables sending the default request headers (Host and User Agent) + */ + void noDefaultRequestHeaders(); + /** 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. @@ -293,6 +297,7 @@ protected: const char* iContentLengthPtr; uint32_t iHttpResponseTimeout; bool iConnectionClose; + bool iSendDefaultRequestHeaders; String iHeaderLine; }; diff --git a/keywords.txt b/keywords.txt index 16c8a2d..dc1140e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -29,6 +29,7 @@ endOfBodyReached KEYWORD2 completed KEYWORD2 contentLength KEYWORD2 connectionKeepAlive KEYWORD2 +noDefaultRequestHeaders KEYWORD2 headerAvailable KEYWORD2 readHeaderName KEYWORD2 readHeaderValue KEYWORD2 From 9f0078440fe2c2137bef3c8ad181901e345404c4 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 16:50:43 -0400 Subject: [PATCH 24/27] Move new API definitions down a bit in header --- HttpClient.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/HttpClient.h b/HttpClient.h index 2394c46..4b51ca3 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -48,14 +48,6 @@ public: HttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort = kHttpPort); HttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = kHttpPort); - /** Enables connection keep-alive mode - */ - void connectionKeepAlive(); - - /** Disables sending the default request headers (Host and User Agent) - */ - void noDefaultRequestHeaders(); - /** 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. @@ -215,6 +207,14 @@ public: */ int contentLength(); + /** Enables connection keep-alive mode + */ + void connectionKeepAlive(); + + /** Disables sending the default request headers (Host and User Agent) + */ + void noDefaultRequestHeaders(); + // 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 From 94a8723420b6e984835232dd46a6b9a3880b0aa3 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 17 Jun 2016 17:29:47 -0400 Subject: [PATCH 25/27] Make WiFiClient and HttpClient global var in example --- examples/SimpleHttpExample/SimpleHttpExample.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino index 550015a..a6aa6b6 100644 --- a/examples/SimpleHttpExample/SimpleHttpExample.ino +++ b/examples/SimpleHttpExample/SimpleHttpExample.ino @@ -25,6 +25,9 @@ const int kNetworkTimeout = 30*1000; // Number of milliseconds to wait if no data is available before trying again const int kNetworkDelay = 1000; +WiFiClient c; +HttpClient http(c, kHostname); + void setup() { //Initialize serial and wait for port to open: @@ -50,9 +53,6 @@ void loop() { int err =0; - WiFiClient c; - HttpClient http(c, kHostname); - err = http.get(kPath); if (err == 0) { From fc3e6c6fe740eaa48e79aa6d08a45fbdfcb0f07d Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 21 Jun 2016 14:10:43 -0400 Subject: [PATCH 26/27] Initial port of examples from RestClient --- examples/DweetGet/DweetGet.ino | 121 ++++++++++++++++++ examples/DweetGet/config.h | 2 + examples/DweetPost/DweetPost.ino | 93 ++++++++++++++ examples/DweetPost/config.h | 2 + examples/HueBlink/HueBlink.ino | 110 ++++++++++++++++ examples/HueBlink/config.h | 2 + examples/SimpleDelete/SimpleDelete.ino | 80 ++++++++++++ examples/SimpleDelete/config.h | 2 + examples/SimpleGet/SimpleGet.ino | 74 +++++++++++ examples/SimpleGet/config.h | 2 + examples/SimplePost/SimplePost.ino | 80 ++++++++++++ examples/SimplePost/config.h | 2 + examples/SimplePut/SimplePut.ino | 80 ++++++++++++ examples/SimplePut/config.h | 2 + examples/node_test_server/getPostPutDelete.js | 42 ++++++ examples/node_test_server/package.json | 16 +++ 16 files changed, 710 insertions(+) create mode 100644 examples/DweetGet/DweetGet.ino create mode 100644 examples/DweetGet/config.h create mode 100644 examples/DweetPost/DweetPost.ino create mode 100644 examples/DweetPost/config.h create mode 100644 examples/HueBlink/HueBlink.ino create mode 100644 examples/HueBlink/config.h create mode 100644 examples/SimpleDelete/SimpleDelete.ino create mode 100644 examples/SimpleDelete/config.h create mode 100644 examples/SimpleGet/SimpleGet.ino create mode 100644 examples/SimpleGet/config.h create mode 100644 examples/SimplePost/SimplePost.ino create mode 100644 examples/SimplePost/config.h create mode 100644 examples/SimplePut/SimplePut.ino create mode 100644 examples/SimplePut/config.h create mode 100644 examples/node_test_server/getPostPutDelete.js create mode 100644 examples/node_test_server/package.json diff --git a/examples/DweetGet/DweetGet.ino b/examples/DweetGet/DweetGet.ino new file mode 100644 index 0000000..11d3daa --- /dev/null +++ b/examples/DweetGet/DweetGet.ino @@ -0,0 +1,121 @@ +/* + Dweet.io GET client for ArduinoHttpClient library + Connects to dweet.io once every ten seconds, + sends a GET request and a request body. Uses SSL + + Shows how to use Strings to assemble path and parse content + from response. dweet.io expects: + https://dweet.io/get/latest/dweet/for/thingName + + For more on dweet.io, see https://dweet.io/play/ + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + created 15 Feb 2016 + updated 16 Feb 2016 + by Tom Igoe + + this example is in the public domain +*/ +#include +#include +#include "config.h" + +const char serverAddress[] = "dweet.io"; // server address +int port = 80; +String dweetName = "scandalous-cheese-hoarder"; // use your own thing name here + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; +int statusCode = 0; +int contentLength = 0; +String response; + +void setup() { + Serial.begin(9600); + while (!Serial); + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); +} + +void loop() { + // assemble the path for the GET message: + String path = "/get/latest/dweet/for/" + dweetName; + + // send the GET request + Serial.println("making GET request"); + client.beginRequest(); + client.get(path); + client.endRequest(); + + // read the status code of the response + statusCode = client.responseStatusCode(); + 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); + + /* + Typical response is: + {"this":"succeeded", + "by":"getting", + "the":"dweets", + "with":[{"thing":"my-thing-name", + "created":"2016-02-16T05:10:36.589Z", + "content":{"sensorValue":456}}]} + + You want "content": numberValue + */ + // now parse the response looking for "content": + int labelStart = response.indexOf("content\":"); + // find the first { after "content": + int contentStart = response.indexOf("{", labelStart); + // find the following } and get what's between the braces: + int contentEnd = response.indexOf("}", labelStart); + String content = response.substring(contentStart + 1, contentEnd); + Serial.println(content); + + // now get the value after the colon, and convert to an int: + int valueStart = content.indexOf(":"); + String valueString = content.substring(valueStart + 1); + int number = valueString.toInt(); + Serial.print("Value string: "); + Serial.println(valueString); + Serial.print("Actual value: "); + Serial.println(number); + + Serial.println("Wait ten seconds\n"); + delay(10000); +} diff --git a/examples/DweetGet/config.h b/examples/DweetGet/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/DweetGet/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/DweetPost/DweetPost.ino b/examples/DweetPost/DweetPost.ino new file mode 100644 index 0000000..04b5f3e --- /dev/null +++ b/examples/DweetPost/DweetPost.ino @@ -0,0 +1,93 @@ +/* + Dweet.io POST client for ArduinoHttpClient library + Connects to dweet.io once every ten seconds, + sends a POST request and a request body. + + Shows how to use Strings to assemble path and body + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + created 15 Feb 2016 + by Tom Igoe + + this example is in the public domain +*/ +#include +#include +#include "config.h" + +const char serverAddress[] = "dweet.io"; // server address +int port = 80; + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; +int statusCode = 0; +int contentLength = 0; +String response; + +void setup() { + Serial.begin(9600); + while(!Serial); + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); +} + +void loop() { + // assemble the path for the POST message: + String dweetName = "scandalous-cheese-hoarder"; + String path = "/dweet/for/" + dweetName; + + // assemble the body of the POST message: + int sensorValue = analogRead(A0); + String postData = "{\"sensorValue\":\""; + postData += sensorValue; + postData += "\"}"; + + 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()); + + // read the status code and content length of the response + statusCode = client.responseStatusCode(); + contentLength = client.contentLength(); + + // read the response body + response = ""; + response.reserve(contentLength); + while (client.available()) { + response += (char)client.read(); + } + + Serial.print("Status code: "); + Serial.println(statusCode); + Serial.print("Response: "); + Serial.println(response); + + Serial.println("Wait ten seconds\n"); + delay(10000); +} diff --git a/examples/DweetPost/config.h b/examples/DweetPost/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/DweetPost/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/HueBlink/HueBlink.ino b/examples/HueBlink/HueBlink.ino new file mode 100644 index 0000000..3d6a028 --- /dev/null +++ b/examples/HueBlink/HueBlink.ino @@ -0,0 +1,110 @@ +/* HueBlink example for ArduinoHttpClient library + + Uses ArduinoHttpClient library to control Philips Hue + For more on Hue developer API see http://developer.meethue.com + + To control a light, the Hue expects a HTTP PUT request to: + + http://hue.hub.address/api/hueUserName/lights/lightNumber/state + + The body of the PUT request looks like this: + {"on": true} or {"on":false} + + This example shows how to concatenate Strings to assemble the + PUT request and the body of the request. + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + modified 15 Feb 2016 + by Tom Igoe (tigoe) to match new API +*/ + +#include +#include +#include +#include "config.h" + +int status = WL_IDLE_STATUS; // the Wifi radio's status +char hueHubIP[] = "192.168.0.3"; // IP address of the HUE bridge +String hueUserName = "huebridgeusername"; // hue bridge username + +// make a wifi instance and a HttpClient instance: +WiFiClient wifi; +HttpClient httpClient = HttpClient(wifi, hueHubIP); + + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial); // wait for serial port to connect. + + // attempt to connect to Wifi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // you're connected now, so print out the data: + Serial.print("You're connected to the network IP = "); + IPAddress ip = WiFi.localIP(); + Serial.println(ip); +} + +void loop() { + sendRequest(3, "on", "true"); // turn light on + delay(2000); // wait 2 seconds + sendRequest(3, "on", "false"); // turn light off + delay(2000); // wait 2 seconds +} + +void sendRequest(int light, String cmd, String value) { + // make a String for the HTTP request path: + String request = "/api/" + hueUserName; + request += "/lights/"; + request += light; + request += "/state/"; + + // make a string for the JSON command: + String hueCmd = "{\"" + cmd; + hueCmd += "\":"; + hueCmd += value; + hueCmd += "}"; + // see what you assembled to send: + Serial.print("PUT request to server: "); + Serial.println(request); + 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()); + + // read the status code and content length 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(); + } + + Serial.println(hueCmd); + Serial.print("Status code from server: "); + Serial.println(statusCode); + Serial.print("Server response: "); + Serial.println(response); + Serial.println(); +} + + diff --git a/examples/HueBlink/config.h b/examples/HueBlink/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/HueBlink/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/SimpleDelete/SimpleDelete.ino b/examples/SimpleDelete/SimpleDelete.ino new file mode 100644 index 0000000..591f4de --- /dev/null +++ b/examples/SimpleDelete/SimpleDelete.ino @@ -0,0 +1,80 @@ +/* + Simple DELETE client for ArduinoHttpClient library + Connects to server once every five seconds, sends a DELETE request + and a request body + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + created 14 Feb 2016 + by Tom Igoe + + this example is in the public domain + */ +#include +#include +#include "config.h" + +char serverAddress[] = "192.168.0.3"; // server address +int port = 8080; + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; +String response; +int statusCode = 0; +int contentLength = 0; + +void setup() { + Serial.begin(9600); + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); +} + +void loop() { + Serial.println("making DELETE request"); + 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()); + + // read the status code and content length of the response + statusCode = client.responseStatusCode(); + contentLength = client.contentLength(); + + // read the response body + response = ""; + response.reserve(contentLength); + while (client.available()) { + response += (char)client.read(); + } + + Serial.print("Status code: "); + Serial.println(statusCode); + Serial.print("Response: "); + Serial.println(response); + + Serial.println("Wait five seconds"); + delay(5000); +} diff --git a/examples/SimpleDelete/config.h b/examples/SimpleDelete/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/SimpleDelete/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/SimpleGet/SimpleGet.ino b/examples/SimpleGet/SimpleGet.ino new file mode 100644 index 0000000..86cdb9d --- /dev/null +++ b/examples/SimpleGet/SimpleGet.ino @@ -0,0 +1,74 @@ +/* + Simple GET client for ArduinoHttpClient library + Connects to server once every five seconds, sends a GET request + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + created 14 Feb 2016 + by Tom Igoe + + this example is in the public domain + */ +#include +#include +#include "config.h" + +char serverAddress[] = "192.168.0.3"; // server address +int port = 8080; + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; +String response; +int statusCode = 0; +int contentLength = 0; + +void setup() { + Serial.begin(9600); + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); +} + +void loop() { + Serial.println("making GET request"); + + // read the status code and content length of the response + client.beginRequest(); + client.get("/"); + client.endRequest(); + + statusCode = client.responseStatusCode(); + contentLength = client.contentLength(); + + // read the response body + response = ""; + response.reserve(contentLength); + while (client.available()) { + response += (char)client.read(); + } + + Serial.print("Status code: "); + Serial.println(statusCode); + Serial.print("Response: "); + Serial.println(response); + Serial.println("Wait five seconds"); + delay(5000); +} diff --git a/examples/SimpleGet/config.h b/examples/SimpleGet/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/SimpleGet/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/SimplePost/SimplePost.ino b/examples/SimplePost/SimplePost.ino new file mode 100644 index 0000000..46982ca --- /dev/null +++ b/examples/SimplePost/SimplePost.ino @@ -0,0 +1,80 @@ +/* + Simple POST client for ArduinoHttpClient library + Connects to server once every five seconds, sends a POST request + and a request body + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + created 14 Feb 2016 + by Tom Igoe + + this example is in the public domain + */ +#include +#include +#include "config.h" + +char serverAddress[] = "192.168.0.3"; // server address +int port = 8080; + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; +String response; +int statusCode = 0; +int contentLength = 0; + +void setup() { + Serial.begin(9600); + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); +} + +void loop() { + Serial.println("making POST request"); + 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()); + + // read the status code and content length of the response + statusCode = client.responseStatusCode(); + contentLength = client.contentLength(); + + // read the response body + response = ""; + response.reserve(contentLength); + while (client.available()) { + response += (char)client.read(); + } + + Serial.print("Status code: "); + Serial.println(statusCode); + Serial.print("Response: "); + Serial.println(response); + + Serial.println("Wait five seconds"); + delay(5000); +} diff --git a/examples/SimplePost/config.h b/examples/SimplePost/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/SimplePost/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/SimplePut/SimplePut.ino b/examples/SimplePut/SimplePut.ino new file mode 100644 index 0000000..611f55c --- /dev/null +++ b/examples/SimplePut/SimplePut.ino @@ -0,0 +1,80 @@ +/* + Simple PUT client for ArduinoHttpClient library + Connects to server once every five seconds, sends a PUT request + and a request body + + note: WiFi SSID and password are stored in config.h file. + If it is not present, add a new tab, call it "config.h" + and add the following variables: + char ssid[] = "ssid"; // your network SSID (name) + char pass[] = "password"; // your network password + + created 14 Feb 2016 + by Tom Igoe + + this example is in the public domain + */ +#include +#include +#include "config.h" + +char serverAddress[] = "192.168.0.3"; // server address +int port = 8080; + +WiFiClient wifi; +HttpClient client = HttpClient(wifi, serverAddress, port); +int status = WL_IDLE_STATUS; +String response; +int statusCode = 0; +int contentLength = 0; + +void setup() { + Serial.begin(9600); + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + } + + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); +} + +void loop() { + Serial.println("making PUT request"); + 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()); + + // read the status code and content length of the response + statusCode = client.responseStatusCode(); + contentLength = client.contentLength(); + + // read the response body + response = ""; + response.reserve(contentLength); + while (client.available()) { + response += (char)client.read(); + } + + Serial.print("Status code: "); + Serial.println(statusCode); + Serial.print("Response: "); + Serial.println(response); + + Serial.println("Wait five seconds"); + delay(5000); +} diff --git a/examples/SimplePut/config.h b/examples/SimplePut/config.h new file mode 100644 index 0000000..c263766 --- /dev/null +++ b/examples/SimplePut/config.h @@ -0,0 +1,2 @@ +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password diff --git a/examples/node_test_server/getPostPutDelete.js b/examples/node_test_server/getPostPutDelete.js new file mode 100644 index 0000000..ec58f82 --- /dev/null +++ b/examples/node_test_server/getPostPutDelete.js @@ -0,0 +1,42 @@ +/* + Express.js GET/POST example + Shows how handle GET, POST, PUT, DELETE + in Express.js 4.0 + + created 14 Feb 2016 + by Tom Igoe +*/ + +var express = require('express'); // include express.js +var app = express(); // a local instance of it +var bodyParser = require('body-parser'); // include body-parser + +// you need a body parser: +app.use(bodyParser.urlencoded({extended: false})); // for application/x-www-form-urlencoded + +// this runs after the server successfully starts: +function serverStart() { + var port = server.address().port; + console.log('Server listening on port '+ port); +} + +// this is the POST handler: +app.all('/*', function (request, response) { + console.log('Got a ' + request.method + ' request'); + // the parameters of a GET request are passed in + // request.body. Pass that to formatResponse() + // for formatting: + console.log(request.headers); + if (request.method == 'GET') { + console.log(request.query); + } else { + console.log(request.body); + } + + // send the response: + response.send('OK'); + response.end(); +}); + +// start the server: +var server = app.listen(8080, serverStart); diff --git a/examples/node_test_server/package.json b/examples/node_test_server/package.json new file mode 100644 index 0000000..d6fb7cc --- /dev/null +++ b/examples/node_test_server/package.json @@ -0,0 +1,16 @@ +{ + "name": "node_test_server", + "version": "0.0.1", + "author": { + "name":"Tom Igoe" + }, + "dependencies": { + "express": ">=4.0.0", + "body-parser" : ">=1.11.0", + "multer" : "*" + }, + "engines": { + "node": "0.10.x", + "npm": "1.3.x" + } +} From 248841e827b61218edac9e9b43d38bf8aa229dfe Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 21 Jun 2016 14:11:39 -0400 Subject: [PATCH 27/27] Add .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89d225a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.development +examples/node_test_server/node_modules/