Skip to content

Commit 6e8d284

Browse files
committed
Updated to use the new generic Client API (rather than the Ethernet-specific one) and added ability to connect via an HTTP proxy
1 parent a9a0821 commit 6e8d284

File tree

3 files changed

+106
-25
lines changed

3 files changed

+106
-25
lines changed

HttpClient.cpp

Lines changed: 85 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
#include "HttpClient.h"
66
#include <../b64/b64.h>
7+
#include <Dns.h>
78
#include <string.h>
89
#include <ctype.h>
9-
#include "wiring.h"
1010

1111
// Initialize constants
1212
const char* HttpClient::kUserAgent = "Arduino/2.0";
@@ -16,10 +16,19 @@ const char* HttpClient::kPut = "PUT";
1616
const char* HttpClient::kDelete = "DELETE";
1717
const char* HttpClient::kContentLengthPrefix = "Content-Length: ";
1818

19-
HttpClient::HttpClient(Client& aClient)
20-
: iClient(&aClient)
19+
HttpClient::HttpClient(Client& aClient, const char* aProxy, uint16_t aProxyPort)
20+
: iClient(&aClient), iProxyPort(aProxyPort)
2121
{
2222
resetState();
23+
if (aProxy)
24+
{
25+
// Resolve the IP address for the proxy
26+
DNSClient dns;
27+
dns.begin(Ethernet.dnsServerIP());
28+
// Not ideal that we discard any errors here, but not a lot we can do in the ctor
29+
// and we'll get a connect error later anyway
30+
(void)dns.getHostByName(aProxy, iProxyAddress);
31+
}
2332
}
2433

2534
void HttpClient::resetState()
@@ -44,16 +53,29 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons
4453
return HttpErrAPI;
4554
}
4655

47-
if (!iClient->connect(aServerName, aServerPort))
56+
if (iProxyPort)
4857
{
58+
if (!iClient->connect(iProxyAddress, iProxyPort))
59+
{
60+
#ifdef LOGGING
61+
Serial.println("Proxy connection failed");
62+
#endif
63+
return HttpErrConnectionFailed;
64+
}
65+
}
66+
else
67+
{
68+
if (!iClient->connect(aServerName, aServerPort))
69+
{
4970
#ifdef LOGGING
50-
Serial.println("Connection failed");
71+
Serial.println("Connection failed");
5172
#endif
52-
return HttpErrConnectionFailed;
73+
return HttpErrConnectionFailed;
74+
}
5375
}
5476

5577
// Now we're connected, send the first part of the request
56-
return sendInitialHeaders(aServerName, aURLPath, aHttpMethod, aUserAgent, aAcceptList);
78+
return sendInitialHeaders(aServerName, IPAddress(0,0,0,0), aServerPort, aURLPath, aHttpMethod, aUserAgent, aAcceptList);
5779
}
5880

5981
int HttpClient::startRequest(const IPAddress& aServerAddress, uint16_t aServerPort, const char* aServerName, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aAcceptList)
@@ -63,33 +85,66 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, uint16_t aServerPo
6385
return HttpErrAPI;
6486
}
6587

66-
if (!iClient->connect(aServerAddress, aServerPort))
88+
if (iProxyPort)
89+
{
90+
if (!iClient->connect(iProxyAddress, iProxyPort))
91+
{
92+
#ifdef LOGGING
93+
Serial.println("Proxy connection failed");
94+
#endif
95+
return HttpErrConnectionFailed;
96+
}
97+
}
98+
else
6799
{
100+
if (!iClient->connect(aServerAddress, aServerPort))
101+
{
68102
#ifdef LOGGING
69-
Serial.println("Connection failed");
103+
Serial.println("Connection failed");
70104
#endif
71-
return HttpErrConnectionFailed;
105+
return HttpErrConnectionFailed;
106+
}
72107
}
73108

74109
// Now we're connected, send the first part of the request
75-
return sendInitialHeaders(aServerName, aURLPath, aHttpMethod, aUserAgent, aAcceptList);
110+
return sendInitialHeaders(aServerName, aServerAddress, aServerPort, aURLPath, aHttpMethod, aUserAgent, aAcceptList);
76111
}
77112

78-
int HttpClient::sendInitialHeaders(const char* aServerName, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aAcceptList)
113+
int HttpClient::sendInitialHeaders(const char* aServerName, IPAddress aServerIP, uint16_t aPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aAcceptList)
79114
{
80115
#ifdef LOGGING
81116
Serial.println("Connected");
82117
#endif
83118
// Send the HTTP command, i.e. "GET /somepath/ HTTP/1.0"
84119
print(aHttpMethod);
85120
print(" ");
121+
if (iProxyPort)
122+
{
123+
// We're going through a proxy, send a full URL
124+
print("http://");
125+
if (aServerName)
126+
{
127+
// We've got a server name, so use it
128+
print(aServerName);
129+
}
130+
else
131+
{
132+
// We'll have to use the IP address
133+
print(aServerIP);
134+
}
135+
if (aPort != kHttpPort)
136+
{
137+
print(":");
138+
print(aPort);
139+
}
140+
}
86141
print(aURLPath);
87142
println(" HTTP/1.0");
88143
// The host header, if required
89144
if (aServerName)
90145
{
91-
print("Host: ");
92-
println(aServerName);
146+
// print("Host: ");
147+
// println(aServerName);
93148
}
94149
// And user-agent string
95150
print("User-Agent: ");
@@ -339,14 +394,28 @@ bool HttpClient::endOfBodyReached()
339394

340395
int HttpClient::read()
341396
{
342-
int ret =iClient->read();
397+
uint8_t b[1];
398+
int ret = read(b, 1);
399+
if (ret == 1)
400+
{
401+
return b[0];
402+
}
403+
else
404+
{
405+
return -1;
406+
}
407+
}
408+
409+
int HttpClient::read(uint8_t *buf, size_t size)
410+
{
411+
int ret =iClient->read(buf, size);
343412
if (endOfHeadersReached() && iContentLength > 0)
344413
{
345414
// We're outputting the body now and we've seen a Content-Length header
346415
// So keep track of how many bytes are left
347416
if (ret >= 0)
348417
{
349-
iBodyLengthConsumed++;
418+
iBodyLengthConsumed += ret;
350419
}
351420
}
352421
return ret;

HttpClient.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
#ifndef HttpClient_h
66
#define HttpClient_h
77

8+
#include <Arduino.h>
89
#include <IPAddress.h>
910
#include "Ethernet.h"
1011
#include "Client.h"
11-
#include <../b64.h>
12+
#include <b64.h>
1213

1314
class HttpClient : public Client
1415
{
@@ -31,13 +32,14 @@ class HttpClient : public Client
3132
};
3233

3334
static const int kNoContentLengthHeader =-1;
35+
static const int kHttpPort =80;
3436
static const char* kUserAgent;
3537
static const char* kGet;
3638
static const char* kPost;
3739
static const char* kPut;
3840
static const char* kDelete;
3941

40-
HttpClient(Client& aClient);
42+
HttpClient(Client& aClient, const char* aProxy =NULL, uint16_t aProxyPort =0);
4143

4244
/** Connect to the server and start to send a GET request.
4345
@param aServerName Name of the server being connected to. If NULL, the
@@ -274,15 +276,16 @@ class HttpClient : public Client
274276
int contentLength() { return iContentLength; };
275277

276278
// Inherited from Print
277-
virtual void write(uint8_t aByte) { iClient-> write(aByte); };
278-
virtual void write(const char *aStr) { iClient->write(aStr); };
279-
virtual void write(const uint8_t *aBuffer, size_t aSize) { iClient->write(aBuffer, aSize); };
279+
virtual size_t write(uint8_t aByte) { return iClient-> write(aByte); };
280+
virtual size_t write(const char *aStr) { return iClient->write(aStr); };
281+
virtual size_t write(const uint8_t *aBuffer, size_t aSize) { return iClient->write(aBuffer, aSize); };
280282
// Inherited from Stream
281283
virtual int available() { return iClient->available(); };
282284
/** Read the next byte from the server.
283285
@return Byte read or -1 if there are no bytes available.
284286
*/
285287
virtual int read();
288+
virtual int read(uint8_t *buf, size_t size);
286289
virtual int peek() { return iClient->peek(); };
287290
virtual void flush() { return iClient->flush(); };
288291

@@ -291,13 +294,17 @@ class HttpClient : public Client
291294
virtual int connect(const char *host, uint16_t port) { return iClient->connect(host, port); };
292295
virtual void stop();
293296
virtual uint8_t connected() { iClient->connected(); };
297+
virtual operator bool() { return bool(iClient); };
294298
protected:
295299
/** Reset internal state data back to the "just initialised" state
296300
*/
297301
void resetState();
298302
/** Send the first part of the request and the initial headers.
299303
@param aServerName Name of the server being connected to. If NULL, the
300304
"Host" header line won't be sent
305+
@param aServerIP IP address of the server (only used if we're going through a
306+
proxy and aServerName is NULL
307+
@param aServerPort Port of the server being connected to.
301308
@param aURLPath Url to request
302309
@param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc.
303310
@param aUserAgent User-Agent string to send. If NULL the default
@@ -307,6 +314,8 @@ class HttpClient : public Client
307314
@return 0 if successful, else error
308315
*/
309316
int sendInitialHeaders(const char* aServerName,
317+
IPAddress aServerIP,
318+
uint16_t aPort,
310319
const char* aURLPath,
311320
const char* aHttpMethod,
312321
const char* aUserAgent,
@@ -343,6 +352,9 @@ class HttpClient : public Client
343352
int iBodyLengthConsumed;
344353
// How far through a Content-Length header prefix we are
345354
const char* iContentLengthPtr;
355+
// Address of the proxy to use, if we're using one
356+
IPAddress iProxyAddress;
357+
uint16_t iProxyPort;
346358
};
347359

348360
#endif

examples/SimpleHttpExample/SimpleHttpExample.pde renamed to examples/SimpleHttpExample/SimpleHttpExample.ino

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <HttpClient.h>
1010
#include <b64.h>
1111
#include <Ethernet.h>
12-
#include <Client.h>
12+
#include <EthernetClient.h>
1313

1414
// This example downloads the URL "http://arduino.cc/"
1515

@@ -44,7 +44,7 @@ void loop()
4444
{
4545
int err =0;
4646

47-
Client c;
47+
EthernetClient c;
4848
HttpClient http(c);
4949

5050
err = http.get(kHostname, 80, kPath);
@@ -77,8 +77,8 @@ void loop()
7777
unsigned long timeoutStart = millis();
7878
char c;
7979
// Whilst we haven't timed out & haven't reached the end of the body
80-
while (http.connected() &&
81-
( (millis() - timeoutStart) < kNetworkTimeout ))
80+
while ( (http.connected() || http.available()) &&
81+
((millis() - timeoutStart) < kNetworkTimeout) )
8282
{
8383
if (http.available())
8484
{

0 commit comments

Comments
 (0)