From 4076ba18adbd492c47ef6a817586f038aea1412b Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sat, 23 Nov 2013 11:24:19 +0000 Subject: [PATCH 1/9] Updated README with new installation instructions --- README | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README b/README index d223d80..e6c3a7d 100644 --- a/README +++ b/README @@ -3,6 +3,13 @@ HttpClient is a library to make it easier to interact with web servers from Ardu Dependencies: - Requires the new Ethernet library API (with DHCP and DNS) which is in Arduino 1.0. +Installation: +- Click the "Download Zip" button on the right-hand-side of https://github.com/amcewen/HttpClient and save the file somewhere +- Run the Arduino IDE +- In the IDE, go to the Sketch -> Import Library -> Add Library... menu option +- Find the zip file that you saved in the first step, and choose that +- Check that it has been successfully added by opening the Sketch -> Import Library menu. You should now see HttpClient listed among the available libraries. + 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). From 476406b1bc83445aaa6eefcf3a0b38d08387875e Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sat, 23 Nov 2013 11:31:26 +0000 Subject: [PATCH 2/9] Reworked the explanation to use markdown, for prettier formatting --- README | 15 --------------- README.md | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 15 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index e6c3a7d..0000000 --- a/README +++ /dev/null @@ -1,15 +0,0 @@ -HttpClient is a library to make it easier to interact with web servers from Arduino. - -Dependencies: -- Requires the new Ethernet library API (with DHCP and DNS) which is in Arduino 1.0. - -Installation: -- Click the "Download Zip" button on the right-hand-side of https://github.com/amcewen/HttpClient and save the file somewhere -- Run the Arduino IDE -- In the IDE, go to the Sketch -> Import Library -> Add Library... menu option -- Find the zip file that you saved in the first step, and choose that -- Check that it has been successfully added by opening the Sketch -> Import Library menu. You should now see HttpClient listed among the available libraries. - -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). - diff --git a/README.md b/README.md new file mode 100644 index 0000000..81fce7c --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# HttpClient + +HttpClient is a library to make it easier to interact with web servers from Arduino. + +## Dependencies + +- Requires the new Ethernet library API (with DHCP and DNS) which is in Arduino 1.0 and later + +## Installation + +1. Click the "Download Zip" button on the right-hand-side of https://github.com/amcewen/HttpClient and save the file somewhere +1. Run the Arduino IDE +1. In the 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. + +## 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. + +See the examples for more detail on how the library is used. + From 881fd8f12f269b4cdb7babd17389f80be936dd04 Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sat, 23 Nov 2013 11:35:05 +0000 Subject: [PATCH 3/9] Moved files into an HttpClient subdirectory for easier installation via the Arduino IDE --- HttpClient.cpp => HttpClient/HttpClient.cpp | 0 HttpClient.h => HttpClient/HttpClient.h | 0 b64.cpp => HttpClient/b64.cpp | 0 b64.h => HttpClient/b64.h | 0 .../examples}/SimpleHttpExample/SimpleHttpExample.ino | 0 keywords.txt => HttpClient/keywords.txt | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename HttpClient.cpp => HttpClient/HttpClient.cpp (100%) rename HttpClient.h => HttpClient/HttpClient.h (100%) rename b64.cpp => HttpClient/b64.cpp (100%) rename b64.h => HttpClient/b64.h (100%) rename {examples => HttpClient/examples}/SimpleHttpExample/SimpleHttpExample.ino (100%) rename keywords.txt => HttpClient/keywords.txt (100%) diff --git a/HttpClient.cpp b/HttpClient/HttpClient.cpp similarity index 100% rename from HttpClient.cpp rename to HttpClient/HttpClient.cpp diff --git a/HttpClient.h b/HttpClient/HttpClient.h similarity index 100% rename from HttpClient.h rename to HttpClient/HttpClient.h diff --git a/b64.cpp b/HttpClient/b64.cpp similarity index 100% rename from b64.cpp rename to HttpClient/b64.cpp diff --git a/b64.h b/HttpClient/b64.h similarity index 100% rename from b64.h rename to HttpClient/b64.h diff --git a/examples/SimpleHttpExample/SimpleHttpExample.ino b/HttpClient/examples/SimpleHttpExample/SimpleHttpExample.ino similarity index 100% rename from examples/SimpleHttpExample/SimpleHttpExample.ino rename to HttpClient/examples/SimpleHttpExample/SimpleHttpExample.ino diff --git a/keywords.txt b/HttpClient/keywords.txt similarity index 100% rename from keywords.txt rename to HttpClient/keywords.txt From 9fddcdc12159d7c6b84a9831bc79c61687fcf24f Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sat, 23 Nov 2013 12:24:11 +0000 Subject: [PATCH 4/9] Undo moving files because that wasn't actually causing problems with adding the library via the Arduino IDE - it was a hard-to-notice error about the naming, which sadly means the "Download Zip" button won't ever work directly (at least until Arduino/Processing IDE accepts "-" in library names) --- HttpClient/HttpClient.cpp => HttpClient.cpp | 0 HttpClient/HttpClient.h => HttpClient.h | 0 HttpClient/b64.cpp => b64.cpp | 0 HttpClient/b64.h => b64.h | 0 .../examples => examples}/SimpleHttpExample/SimpleHttpExample.ino | 0 HttpClient/keywords.txt => keywords.txt | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename HttpClient/HttpClient.cpp => HttpClient.cpp (100%) rename HttpClient/HttpClient.h => HttpClient.h (100%) rename HttpClient/b64.cpp => b64.cpp (100%) rename HttpClient/b64.h => b64.h (100%) rename {HttpClient/examples => examples}/SimpleHttpExample/SimpleHttpExample.ino (100%) rename HttpClient/keywords.txt => keywords.txt (100%) diff --git a/HttpClient/HttpClient.cpp b/HttpClient.cpp similarity index 100% rename from HttpClient/HttpClient.cpp rename to HttpClient.cpp diff --git a/HttpClient/HttpClient.h b/HttpClient.h similarity index 100% rename from HttpClient/HttpClient.h rename to HttpClient.h diff --git a/HttpClient/b64.cpp b/b64.cpp similarity index 100% rename from HttpClient/b64.cpp rename to b64.cpp diff --git a/HttpClient/b64.h b/b64.h similarity index 100% rename from HttpClient/b64.h rename to b64.h diff --git a/HttpClient/examples/SimpleHttpExample/SimpleHttpExample.ino b/examples/SimpleHttpExample/SimpleHttpExample.ino similarity index 100% rename from HttpClient/examples/SimpleHttpExample/SimpleHttpExample.ino rename to examples/SimpleHttpExample/SimpleHttpExample.ino diff --git a/HttpClient/keywords.txt b/keywords.txt similarity index 100% rename from HttpClient/keywords.txt rename to keywords.txt From fa50bfdbdb3f848bbc88378d3f06d28655d902db Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sat, 23 Nov 2013 12:28:37 +0000 Subject: [PATCH 5/9] Installation instructions updated to use releases area --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 81fce7c..d55dfa4 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,8 @@ HttpClient is a library to make it easier to interact with web servers from Ardu ## Installation -1. Click the "Download Zip" button on the right-hand-side of https://github.com/amcewen/HttpClient and save the file somewhere -1. Run the Arduino IDE -1. In the IDE, go to the Sketch -> Import Library -> Add Library... menu option +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. From 53cc49f1c8a9fb6ce3bf97de394791315ff6ac62 Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sun, 24 Nov 2013 21:39:10 +0000 Subject: [PATCH 6/9] Reworked to trim down the code size of sketches using HttpClient --- HttpClient.cpp | 21 ++++++++++----------- HttpClient.h | 39 +++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 39a9ab7..d30af58 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -7,16 +7,10 @@ #ifdef PROXY_ENABLED // currently disabled as introduces dependency on Dns.h in Ethernet #include #endif -#include -#include // Initialize constants -const char* HttpClient::kUserAgent = "Arduino/2.0"; -const char* HttpClient::kGet = "GET"; -const char* HttpClient::kPost = "POST"; -const char* HttpClient::kPut = "PUT"; -const char* HttpClient::kDelete = "DELETE"; -const char* HttpClient::kContentLengthPrefix = "Content-Length: "; +const char* HttpClient::kUserAgent = "Arduino/2.1"; +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) @@ -70,6 +64,7 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons return HTTP_ERROR_API; } +#ifdef PROXY_ENABLED if (iProxyPort) { if (!iClient->connect(iProxyAddress, iProxyPort) > 0) @@ -81,6 +76,7 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons } } else +#endif { if (!iClient->connect(aServerName, aServerPort) > 0) { @@ -111,6 +107,7 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServe return HTTP_ERROR_API; } +#ifdef PROXY_ENABLED if (iProxyPort) { if (!iClient->connect(iProxyAddress, iProxyPort) > 0) @@ -122,6 +119,7 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServe } } else +#endif { if (!iClient->connect(aServerAddress, aServerPort) > 0) { @@ -152,6 +150,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 @@ -172,6 +171,7 @@ int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, iClient->print(aPort); } } +#endif iClient->print(aURLPath); iClient->println(" HTTP/1.1"); // The host header, if required @@ -187,14 +187,13 @@ int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, iClient->println(); } // And user-agent string - iClient->print("User-Agent: "); if (aUserAgent) { - iClient->println(aUserAgent); + sendHeader(HTTP_HEADER_USER_AGENT, aUserAgent); } else { - iClient->println(kUserAgent); + sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent); } // Everything has gone well diff --git a/HttpClient.h b/HttpClient.h index e7cb624..b4c3974 100644 --- a/HttpClient.h +++ b/HttpClient.h @@ -23,16 +23,23 @@ static const int HTTP_ERROR_TIMED_OUT =-3; // server? static const int HTTP_ERROR_INVALID_RESPONSE =-4; +// Define some of the common methods and headers here +// That lets other code reuse them without having to declare another copy +// of them, so saves code space and RAM +#define HTTP_METHOD_GET "GET" +#define HTTP_METHOD_POST "POST" +#define HTTP_METHOD_PUT "PUT" +#define HTTP_METHOD_DELETE "DELETE" +#define HTTP_HEADER_CONTENT_LENGTH "Content-Length" +#define HTTP_HEADER_CONNECTION "Connection" +#define HTTP_HEADER_USER_AGENT "User-Agent" + class HttpClient : public Client { public: static const int kNoContentLengthHeader =-1; static const int kHttpPort =80; static const char* kUserAgent; - static const char* kGet; - static const char* kPost; - static const char* kPut; - static const char* kDelete; // FIXME Write longer API request, using port and user-agent, example // FIXME Update tempToPachube example to calculate Content-Length correctly @@ -66,7 +73,7 @@ class HttpClient : public Client */ int get(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, kGet, aUserAgent); } + { 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 @@ -77,7 +84,7 @@ class HttpClient : public Client @return 0 if successful, else error */ int get(const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, kGet, aUserAgent); } + { 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. @@ -95,7 +102,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, kGet, aUserAgent); } + { 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. @@ -111,7 +118,7 @@ class HttpClient : public Client const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, kGet, aUserAgent); } + { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent); } /** Connect to the server and start to send a POST request. @param aServerName Name of the server being connected to. If NULL, the @@ -126,7 +133,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, kPost, aUserAgent); } + { 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 @@ -139,7 +146,7 @@ class HttpClient : public Client int post(const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, kPost, aUserAgent); } + { 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. @@ -157,7 +164,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, kPost, aUserAgent); } + { 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. @@ -173,7 +180,7 @@ class HttpClient : public Client const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, kPost, aUserAgent); } + { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent); } /** Connect to the server and start to send a PUT request. @param aServerName Name of the server being connected to. If NULL, the @@ -188,7 +195,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, aServerPort, aURLPath, kPut, aUserAgent); } + { 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 @@ -201,7 +208,7 @@ class HttpClient : public Client int put(const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerName, kHttpPort, aURLPath, kPut, aUserAgent); } + { 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. @@ -219,7 +226,7 @@ class HttpClient : public Client uint16_t aServerPort, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, kPut, aUserAgent); } + { 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. @@ -235,7 +242,7 @@ class HttpClient : public Client const char* aServerName, const char* aURLPath, const char* aUserAgent =NULL) - { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, kPut, aUserAgent); } + { return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); } /** Connect to the server and start to send the request. @param aServerName Name of the server being connected to. From 522108f64e83321a63dcbe4ccbe18e1b0972948d Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Sun, 24 Nov 2013 21:39:54 +0000 Subject: [PATCH 7/9] Added sending "Connection: close" header to fix hang when talking to some servers (first spotted with Xively's servers) --- HttpClient.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HttpClient.cpp b/HttpClient.cpp index d30af58..65fdf05 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -195,6 +195,9 @@ int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, { 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"); // Everything has gone well iState = eRequestStarted; From 4bb288dd8678fd457e93accbd9240a746a4c2a06 Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Tue, 5 May 2015 22:56:12 +0100 Subject: [PATCH 8/9] Fixes issue #10 where the library would crash on Intel Galileo and Edison. --- HttpClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient.cpp b/HttpClient.cpp index 65fdf05..c095f76 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -41,7 +41,7 @@ void HttpClient::resetState() iStatusCode = 0; iContentLength = 0; iBodyLengthConsumed = 0; - iContentLengthPtr = 0; + iContentLengthPtr = kContentLengthPrefix; iHttpResponseTimeout = kHttpResponseTimeout; } From 4a2222d2107daf1ef03fc3b7e8e3381de88bfb71 Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Fri, 3 Jul 2015 14:59:41 +0100 Subject: [PATCH 9/9] Changes so this can be added to the Arduino 1.5+ library manager --- HttpClient.cpp | 2 +- library.properties | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 library.properties diff --git a/HttpClient.cpp b/HttpClient.cpp index c095f76..5a11a45 100644 --- a/HttpClient.cpp +++ b/HttpClient.cpp @@ -9,7 +9,7 @@ #endif // Initialize constants -const char* HttpClient::kUserAgent = "Arduino/2.1"; +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 diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..577c5d9 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=HttpClient +version=2.2.0 +author=Adrian McEwen +maintainer=Adrian McEwen +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 +architectures=*