Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 62 additions & 21 deletions HTTPClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <string.h>
#include <avr/pgmspace.h>
#include <HardwareSerial.h>
#include "HTTPClient.h"
#include <HTTPClient.h>

//a struct to store the uriEncoder & the handle to the http client
typedef struct
Expand All @@ -41,18 +41,58 @@ typedef struct
#define URI_ALLOWED(byte) ((byte>='A' && byte<='Z') || (byte>='a' && byte<='z') || (byte>='0' && byte<='9') || byte == '-' || byte == '_' || byte == '.' || byte == '~')
#define URI_RESERVED(byte) (byte == '!' || byte == '*' || byte == '\'' || byte == '(' || byte == ')' || byte == ';' || byte == ':' || byte == '&' || byte == '=' || byte == '+' || byte == '$' || byte == ',' || byte == '/' || byte == '?' || byte == '#' || byte == '[' || byte == ']')

HTTPClient::HTTPClient(char* host) :
_theClient(new EthernetClient()), _selfInitializedTheClient(true), hostName(host), debugCommunication(0), _useIp(false), port(80)
{
//nothing else to do
}

HTTPClient::HTTPClient(char* host, uint16_t port) :
_theClient(new EthernetClient()), _selfInitializedTheClient(true), hostName(host), debugCommunication(0), _useIp(false), port(port)
{
//nothing else to do
}

HTTPClient::HTTPClient(char* host, uint8_t* ip) :
EthernetClient(), hostName(host), debugCommunication(0), ip(ip), port(80)
_theClient(new EthernetClient()), _selfInitializedTheClient(true), hostName(host), debugCommunication(0), ip(ip), _useIp(true), port(80)
{
//nothing else to do
}

HTTPClient::HTTPClient(char* host, uint8_t* ip, uint16_t port) :
EthernetClient(), hostName(host), debugCommunication(0), ip(ip), port(port)
_theClient(new EthernetClient()), _selfInitializedTheClient(true), hostName(host), debugCommunication(0), ip(ip), _useIp(true), port(port)
{
//nothing else to do
}

HTTPClient::HTTPClient(Client& client, char* host) :
_theClient(&client), hostName(host), debugCommunication(0), _useIp(false), port(80)
{
//nothing else to do
}

HTTPClient::HTTPClient(Client& client, char* host, uint16_t port) :
_theClient(&client), hostName(host), debugCommunication(0), _useIp(false), port(port)
{
//nothing else to do
}

HTTPClient::HTTPClient(Client& client, char* host, uint8_t* ip) :
_theClient(&client), hostName(host), debugCommunication(0), ip(ip), _useIp(true), port(80)
{
//nothing else to do
}

HTTPClient::HTTPClient(Client& client, char* host, uint8_t* ip, uint16_t port) :
_theClient(&client), hostName(host), debugCommunication(0), ip(ip), _useIp(true), port(port)
{
//nothing else to do
}

HTTPClient::~HTTPClient() {
if (_selfInitializedTheClient) delete _theClient;
}

FILE*
HTTPClient::getURI(char* uri)
{
Expand Down Expand Up @@ -184,11 +224,12 @@ HTTPClient::openClientFile()
fdev_set_udata(result,udata);
udata->client = this;
udata->encode = 0;
if (connected())
{
stop();
}
if (connect(ip,port))
_theClient->stop();

int connectRes;
if (_useIp) connectRes=_theClient->connect(ip,port);
else connectRes=_theClient->connect(hostName,port);
if (connectRes)
{
return result;
}
Expand Down Expand Up @@ -291,14 +332,14 @@ HTTPClient::clientWrite(char byte, FILE* stream)
}
http_stream_udata* udata = (http_stream_udata*) fdev_get_udata(stream);
HTTPClient* client = udata->client;
if (client->connected() == 0)
if (client->_theClient->connected() == 0)
{
closeStream(stream);
return EOF;
}
if (udata->encode == 0)
{
client->write(byte);
client->_theClient->write(byte);
if (client->debugCommunication)
{
Serial.print(byte);
Expand All @@ -309,7 +350,7 @@ HTTPClient::clientWrite(char byte, FILE* stream)
if (URI_ALLOWED(byte) || ((URI_RESERVED(byte) && (udata->encode
& URI_ENCODE_RESERVED) == 0)))
{
client->write(byte);
client->_theClient->write(byte);
if (client->debugCommunication)
{
Serial.print(byte);
Expand All @@ -323,7 +364,7 @@ HTTPClient::clientWrite(char byte, FILE* stream)
// Write only the first three bytes, not the trailing null
for (char i = 0; i < 3; i++)
{
client->write(encoded[i]);
client->_theClient->write(encoded[i]);
if (client->debugCommunication)
{
Serial.print(encoded[i]);
Expand All @@ -343,19 +384,19 @@ HTTPClient::clientRead(FILE* stream)
}
http_stream_udata* udata = (http_stream_udata*) fdev_get_udata(stream);
HTTPClient* client = udata->client;
if (!client->connected())
if (!client->_theClient->connected())
{
return EOF;
}
//block until we got a byte
while (client->available() == 0)
while (client->_theClient->available() == 0)
{
if (client->connected() == 0)
if (client->_theClient->connected() == 0)
{
return EOF;
}
};
int result = client->read();
int result = client->_theClient->read();
if (result == EOF)
{
return EOF;
Expand All @@ -372,17 +413,17 @@ HTTPClient::clientRead(FILE* stream)
else
{
//block until we got the needed bytes
while (client->available() >= 2)
while (client->_theClient->available() >= 2)
{
if (client->connected() == 0)
if (client->_theClient->connected() == 0)
{
return EOF;
}
};
char return_value = 0;
for (char i = 0; i < 2; i++)
{
result = client->read();
result = client->_theClient->read();
if (result == EOF)
{
return EOF;
Expand Down Expand Up @@ -417,7 +458,7 @@ HTTPClient::skipHeader(FILE* stream)

int delayReadHeaderCount=0;
// check if at least the first HTTP-response available, up to 1000ms=1s
while ((client->available()<17) && (delayReadHeaderCount++<HTTPCLIENT_HEADER_READ_DELAY_MAXCOUNT))
while ((client->_theClient->available()<17) && (delayReadHeaderCount++<HTTPCLIENT_HEADER_READ_DELAY_MAXCOUNT))
delay(HTTPCLIENT_HEADER_READ_DELAY_ONCE);

int res=fscanf_P(stream, PSTR("HTTP/1.1 %i"), &httpReturnCode);
Expand Down Expand Up @@ -450,7 +491,7 @@ HTTPClient::closeStream(FILE* stream)
if (stream != NULL)
{
http_stream_udata* udata = (http_stream_udata*) fdev_get_udata(stream);
udata->client->stop();
udata->client->_theClient->stop();
free(udata);
fclose(stream);
}
Expand Down
56 changes: 51 additions & 5 deletions HTTPClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define HTTPCLIENT_H_

#include <inttypes.h>
#include <Client.h>
#include <EthernetClient.h>

/* With this we try a delay of 20 ms before checking again if content is available
Expand All @@ -50,18 +51,56 @@ typedef struct
* To construct a HTTP client you have to provide the IP AND the name of the server � else
* the virtual host management of most internet servers will fail. Sorry for the inconvenience.
*/
class HTTPClient : private EthernetClient
class HTTPClient
{
public:
/*
* create a HTTP client that connects to the default port 80.
* create a HTTP client that connects to the default port 80 using hostname (and dhcp lookup).
* An internal EthernetClient instance is used for the communication.
*/
HTTPClient(char* host);
/*
* create a HTTP client that connects to another port using hostname (and dhcp lookup). HTTPS is not supported.
* An internal EthernetClient instance is used for the communication.
*/
HTTPClient(char* host, uint16_t port);
/*
* create a HTTP Ethernet client that connects to the default port 80 using provided ip. hostname is used in HTTP message.
* An internal EthernetClient instance is used for the communication.
*/
HTTPClient(char* host, uint8_t* ip );
/*
* create a HTTP client that connects to another port. HTTPS is not supported.
* create a HTTP Ethernet client that connects to another port using provided ip. hostname is used in HTTP message. HTTPS is not supported.
* An internal EthernetClient instance is used for the communication.
*/
HTTPClient(char* host, uint8_t* ip, uint16_t port);

/*
* create a HTTP client that connects to the default port 80 using hostname (and dhcp lookup).
* The given instance of a Client (e.g. EthernetClient, WifiClient or such) is used for communication.
*/
HTTPClient(Client& client, char* host);
/*
* create a HTTP client that connects to another port using hostname (and dhcp lookup). HTTPS is not supported.
* The given instance of a Client (e.g. EthernetClient, WifiClient or such) is used for communication.
*/
HTTPClient(Client& client, char* host, uint16_t port);
/*
* create a HTTP client that connects to the default port 80 using provided ip. hostname is used in HTTP message..
* The given instance of a Client (e.g. EthernetClient, WifiClient or such) is used for communication.
*/
HTTPClient(Client& client, char* host, uint8_t* ip );
/*
* create a HTTP client that connects to another port using provided ip. hostname is used in HTTP message. HTTPS is not supported.
* The given instance of a Client (e.g. EthernetClient, WifiClient or such) is used for communication.
*/
HTTPClient(Client& client, char* host, uint8_t* ip, uint16_t port);

/*
* the destructor
*/
~HTTPClient();

/*
* Post a GET request to the server.
* The result is a file handle or null is an error occured.
Expand Down Expand Up @@ -167,12 +206,19 @@ class HTTPClient : private EthernetClient
* And that is the internal stuff of the HTTP client
*/
private:
//client-instance to use
Client* _theClient;
//flag if Client was self-generated by compatibility constructors and needs to be removed
bool _selfInitializedTheClient=false;

//the name of the host we are talking to
char* hostName;
//the ip of the host
uint8_t* ip;
//the port we are talking to
uint16_t port;
//use ip instead of hostname
bool _useIp;
//the port we are talking to
uint16_t port;
//the HTTP return code of the last request
int lastReturnCode;
//print to serial?
Expand Down
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
# HTTPClient for Arduino
# HTTPClient for Arduino (Enhanced)

## Not about this version:

This is an enhanced version of the HTTPClient library originally from Interactive-Matter
(https://github.com/interactive-matter/HTTPClient). Additionally changes from Salanki's
fork (https://github.com/salanki/HTTPClient) were incorporated.

The main differences are:
* The used communication client instance can be specified with new constructors. With
this it can be used with nearly any kind of Client-inherited class (e.g. EthernetClient,
WifiClient, GSMCLient and many more). The old constructor methods without providing a
Client instance are still available and an EthernetClient instance is created then. So
this version should be a drop-in replacement for the original "HTTPClient"
* Additionally some new constructors were introduced that allow the connection to be
done by just providing the hostname and DHCP is used then. To prevent DNS lookup and
such simply use the original constructor versions where IP is provided additionally
to Hostname - then the IP is used for the connection without the need of a lookup.
* My optimizations that are in Pull-request #15 on original library are incorporated as
well:
* make sure connection is correctly closed at end of communication so that reuse of
one Client instance is possible
* check success of parsing for last HTTP returncode and only set the variable on success

### Open Todos
* add examples for new Client-Feature ...

## Overview

Expand Down