mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
HTTPClient: decouple transport layer handling
This commit is contained in:
parent
93d57fabe2
commit
cae4039225
@ -30,76 +30,100 @@
|
||||
|
||||
#include "ESP8266HTTPClient.h"
|
||||
|
||||
class TransportTraits {
|
||||
public:
|
||||
virtual std::unique_ptr<WiFiClient> create()
|
||||
{
|
||||
return std::unique_ptr<WiFiClient>(new WiFiClient());
|
||||
}
|
||||
|
||||
virtual bool verify(WiFiClient& client, const char* host)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TLSTraits : public TransportTraits {
|
||||
public:
|
||||
TLSTraits(const String& fingerprint) :
|
||||
_fingerprint(fingerprint)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<WiFiClient> create() override
|
||||
{
|
||||
return std::unique_ptr<WiFiClient>(new WiFiClientSecure());
|
||||
}
|
||||
|
||||
bool verify(WiFiClient& client, const char* host) override
|
||||
{
|
||||
auto wcs = reinterpret_cast<WiFiClientSecure&>(client);
|
||||
return wcs.verify(_fingerprint.c_str(), host);
|
||||
}
|
||||
|
||||
protected:
|
||||
String _fingerprint;
|
||||
};
|
||||
|
||||
/**
|
||||
* constractor
|
||||
* constructor
|
||||
*/
|
||||
HTTPClient::HTTPClient() {
|
||||
_tcp = NULL;
|
||||
_tcps = NULL;
|
||||
|
||||
_port = 0;
|
||||
|
||||
_reuse = false;
|
||||
_tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||
_useHTTP10 = false;
|
||||
|
||||
_https = false;
|
||||
|
||||
_userAgent = "ESP8266HTTPClient";
|
||||
|
||||
_headerKeysCount = 0;
|
||||
_currentHeaders = NULL;
|
||||
|
||||
_returnCode = 0;
|
||||
_size = -1;
|
||||
_canReuse = false;
|
||||
_transferEncoding = HTTPC_TE_IDENTITY;
|
||||
|
||||
HTTPClient::HTTPClient()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* deconstractor
|
||||
* destructor
|
||||
*/
|
||||
HTTPClient::~HTTPClient() {
|
||||
|
||||
if(_tcps) {
|
||||
_tcps->stop();
|
||||
delete _tcps;
|
||||
_tcps = NULL;
|
||||
_tcp = NULL;
|
||||
} else if(_tcp) {
|
||||
HTTPClient::~HTTPClient()
|
||||
{
|
||||
if(_tcp) {
|
||||
_tcp->stop();
|
||||
delete _tcp;
|
||||
_tcp = NULL;
|
||||
}
|
||||
|
||||
if(_currentHeaders) {
|
||||
delete[] _currentHeaders;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* phasing the url for all needed informations
|
||||
* @param url String
|
||||
* @param httpsFingerprint String
|
||||
*/
|
||||
void HTTPClient::begin(String url, String httpsFingerprint) {
|
||||
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] url: %s\n", url.c_str());
|
||||
bool HTTPClient::begin(String url, String httpsFingerprint) {
|
||||
if (httpsFingerprint.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!begin(url)) {
|
||||
return false;
|
||||
}
|
||||
_transportTraits = TransportTraitsPtr(new TLSTraits(httpsFingerprint));
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] httpsFingerprint: %s\n", httpsFingerprint.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
_httpsFingerprint = httpsFingerprint;
|
||||
void HTTPClient::clear()
|
||||
{
|
||||
_returnCode = 0;
|
||||
_size = -1;
|
||||
_headers = "";
|
||||
}
|
||||
|
||||
_Headers = "";
|
||||
|
||||
String protocol;
|
||||
/**
|
||||
* parsing the url for all needed parameters
|
||||
* @param url String
|
||||
*/
|
||||
bool HTTPClient::begin(String url)
|
||||
{
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] url: %s\n", url.c_str());
|
||||
bool hasPort = false;
|
||||
clear();
|
||||
|
||||
// check for : (http: or https:
|
||||
int index = url.indexOf(':');
|
||||
//int index2;
|
||||
bool hasPort = false;
|
||||
if(index >= 0) {
|
||||
protocol = url.substring(0, index);
|
||||
if(index < 0) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] failed to parse protocol\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
_protocol = url.substring(0, index);
|
||||
url.remove(0, (index + 3)); // remove http:// or https://
|
||||
|
||||
index = url.indexOf('/');
|
||||
@ -125,43 +149,59 @@ void HTTPClient::begin(String url, String httpsFingerprint) {
|
||||
} else {
|
||||
_host = host;
|
||||
}
|
||||
_uri = url;
|
||||
|
||||
_url = url;
|
||||
|
||||
if(protocol.equalsIgnoreCase("http")) {
|
||||
_https = false;
|
||||
if(_protocol.equalsIgnoreCase("http")) {
|
||||
if(!hasPort) {
|
||||
_port = 80;
|
||||
}
|
||||
} else if(protocol.equalsIgnoreCase("https")) {
|
||||
_https = true;
|
||||
} else if(_protocol.equalsIgnoreCase("https")) {
|
||||
if(!hasPort) {
|
||||
_port = 443;
|
||||
}
|
||||
} else {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] protocol: %s unknown?!\n", protocol.c_str());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
_transportTraits = TransportTraitsPtr(new TransportTraits());
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d url: %s\n", _host.c_str(), _port, _uri.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d url: %s https: %d httpsFingerprint: %s\n", _host.c_str(), _port, _url.c_str(), _https, _httpsFingerprint.c_str());
|
||||
|
||||
}
|
||||
|
||||
void HTTPClient::begin(String host, uint16_t port, String url, bool https, String httpsFingerprint) {
|
||||
bool HTTPClient::begin(String host, uint16_t port, String uri)
|
||||
{
|
||||
clear();
|
||||
_host = host;
|
||||
_port = port;
|
||||
_url = url;
|
||||
_https = https;
|
||||
_httpsFingerprint = httpsFingerprint;
|
||||
_uri = uri;
|
||||
_transportTraits = TransportTraitsPtr(new TransportTraits());
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d uri: %s\n", host.c_str(), port, uri.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
_returnCode = 0;
|
||||
_size = -1;
|
||||
bool HTTPClient::begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint)
|
||||
{
|
||||
if (https) {
|
||||
return begin(host, port, uri, httpsFingerprint);
|
||||
}
|
||||
else {
|
||||
return begin(host, port, uri);
|
||||
}
|
||||
}
|
||||
|
||||
_Headers = "";
|
||||
bool HTTPClient::begin(String host, uint16_t port, String uri, String httpsFingerprint)
|
||||
{
|
||||
clear();
|
||||
_host = host;
|
||||
_port = port;
|
||||
_uri = uri;
|
||||
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port:%d url: %s https: %d httpsFingerprint: %s\n", host, port, url, https, httpsFingerprint);
|
||||
if (httpsFingerprint.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
_transportTraits = TransportTraitsPtr(new TLSTraits(httpsFingerprint));
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d url: %s httpsFingerprint: %s\n", host.c_str(), port, uri.c_str(), httpsFingerprint.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -469,7 +509,6 @@ int HTTPClient::getSize(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* deprecated Note: this is not working with https!
|
||||
* returns the stream of the tcp connection
|
||||
* @return WiFiClient
|
||||
*/
|
||||
@ -478,9 +517,9 @@ WiFiClient & HTTPClient::getStream(void) {
|
||||
return *_tcp;
|
||||
}
|
||||
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] no stream to return!?\n");
|
||||
|
||||
// todo return error?
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] getStream: not connected\n");
|
||||
static WiFiClient empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -489,11 +528,11 @@ WiFiClient & HTTPClient::getStream(void) {
|
||||
*/
|
||||
WiFiClient* HTTPClient::getStreamPtr(void) {
|
||||
if(connected()) {
|
||||
return _tcp;
|
||||
return _tcp.get();
|
||||
}
|
||||
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] no stream to return!?\n");
|
||||
return NULL;
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] getStreamPtr: not connected\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -642,9 +681,9 @@ void HTTPClient::addHeader(const String& name, const String& value, bool first)
|
||||
headerLine += "\r\n";
|
||||
|
||||
if(first) {
|
||||
_Headers = headerLine + _Headers;
|
||||
_headers = headerLine + _headers;
|
||||
} else {
|
||||
_Headers += headerLine;
|
||||
_headers += headerLine;
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,24 +745,13 @@ bool HTTPClient::connect(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(_https) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] connect https...\n");
|
||||
if(_tcps) {
|
||||
delete _tcps;
|
||||
_tcps = NULL;
|
||||
_tcp = NULL;
|
||||
}
|
||||
_tcps = new WiFiClientSecure();
|
||||
_tcp = _tcps;
|
||||
} else {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] connect http...\n");
|
||||
if(_tcp) {
|
||||
delete _tcp;
|
||||
_tcp = NULL;
|
||||
}
|
||||
_tcp = new WiFiClient();
|
||||
if (!_transportTraits) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] _transportTraits is null (HTTPClient::begin not called?)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
_tcp = _transportTraits->create();
|
||||
|
||||
if(!_tcp->connect(_host.c_str(), _port)) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u\n", _host.c_str(), _port);
|
||||
return false;
|
||||
@ -731,15 +759,11 @@ bool HTTPClient::connect(void) {
|
||||
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u\n", _host.c_str(), _port);
|
||||
|
||||
if(_https && _httpsFingerprint.length() > 0) {
|
||||
if(_tcps->verify(_httpsFingerprint.c_str(), _host.c_str())) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] https certificate matches\n");
|
||||
} else {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] https certificate doesn't match!\n");
|
||||
if (!_transportTraits->verify(*_tcp, _host.c_str())) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] transport level verify failed\n");
|
||||
_tcp->stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// set Timeout for readBytesUntil and readStringUntil
|
||||
_tcp->setTimeout(_tcpTimeout);
|
||||
@ -760,7 +784,7 @@ bool HTTPClient::sendHeader(const char * type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String header = String(type) + " " + _url + " HTTP/1.";
|
||||
String header = String(type) + " " + _uri + " HTTP/1.";
|
||||
|
||||
if(_useHTTP10) {
|
||||
header += "0";
|
||||
@ -788,7 +812,7 @@ bool HTTPClient::sendHeader(const char * type) {
|
||||
header += "Authorization: Basic " + _base64Authorization + "\r\n";
|
||||
}
|
||||
|
||||
header += _Headers + "\r\n";
|
||||
header += _headers + "\r\n";
|
||||
|
||||
return (_tcp->write(header.c_str(), header.length()) == header.length());
|
||||
}
|
||||
|
@ -25,6 +25,10 @@
|
||||
#ifndef ESP8266HTTPClient_H_
|
||||
#define ESP8266HTTPClient_H_
|
||||
|
||||
#include <memory>
|
||||
#include <Arduino.h>
|
||||
#include <WiFiClient.h>
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_CLIENT
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_HTTPCLIENT(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ )
|
||||
@ -120,13 +124,20 @@ typedef enum {
|
||||
HTTPC_TE_CHUNKED
|
||||
} transferEncoding_t;
|
||||
|
||||
class TransportTraits;
|
||||
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
|
||||
|
||||
class HTTPClient {
|
||||
public:
|
||||
HTTPClient();
|
||||
~HTTPClient();
|
||||
|
||||
void begin(String url, String httpsFingerprint = "");
|
||||
void begin(String host, uint16_t port, String url = "/", bool https = false, String httpsFingerprint = "");
|
||||
bool begin(String url);
|
||||
bool begin(String url, String httpsFingerprint);
|
||||
bool begin(String host, uint16_t port, String uri = "/");
|
||||
bool begin(String host, uint16_t port, String uri, String httpsFingerprint);
|
||||
// deprecated, use the overload above instead
|
||||
bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__ ((deprecated));
|
||||
|
||||
void end(void);
|
||||
|
||||
@ -161,7 +172,7 @@ class HTTPClient {
|
||||
|
||||
int getSize(void);
|
||||
|
||||
WiFiClient & getStream(void) __attribute__ ((deprecated)) ;
|
||||
WiFiClient& getStream(void);
|
||||
WiFiClient* getStreamPtr(void);
|
||||
int writeToStream(Stream* stream);
|
||||
String getString(void);
|
||||
@ -169,45 +180,43 @@ class HTTPClient {
|
||||
static String errorToString(int error);
|
||||
|
||||
protected:
|
||||
|
||||
struct RequestArgument {
|
||||
String key;
|
||||
String value;
|
||||
};
|
||||
|
||||
|
||||
WiFiClient * _tcp;
|
||||
WiFiClientSecure * _tcps;
|
||||
|
||||
/// request handling
|
||||
String _host;
|
||||
uint16_t _port;
|
||||
bool _reuse;
|
||||
uint16_t _tcpTimeout;
|
||||
bool _useHTTP10;
|
||||
|
||||
String _url;
|
||||
bool _https;
|
||||
String _httpsFingerprint;
|
||||
|
||||
String _Headers;
|
||||
String _userAgent;
|
||||
String _base64Authorization;
|
||||
|
||||
/// Response handling
|
||||
RequestArgument* _currentHeaders;
|
||||
size_t _headerKeysCount;
|
||||
|
||||
int _returnCode;
|
||||
int _size;
|
||||
bool _canReuse;
|
||||
transferEncoding_t _transferEncoding;
|
||||
|
||||
void clear();
|
||||
int returnError(int error);
|
||||
bool connect(void);
|
||||
bool sendHeader(const char * type);
|
||||
int handleHeaderResponse();
|
||||
int writeToStreamDataBlock(Stream * stream, int len);
|
||||
|
||||
|
||||
TransportTraitsPtr _transportTraits;
|
||||
std::unique_ptr<WiFiClient> _tcp;
|
||||
|
||||
/// request handling
|
||||
String _host;
|
||||
uint16_t _port = 0;
|
||||
bool _reuse = false;
|
||||
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||
bool _useHTTP10 = false;
|
||||
|
||||
String _uri;
|
||||
String _protocol;
|
||||
String _headers;
|
||||
String _userAgent = "ESP8266HTTPClient";
|
||||
String _base64Authorization;
|
||||
|
||||
/// Response handling
|
||||
RequestArgument* _currentHeaders = nullptr;
|
||||
size_t _headerKeysCount = 0;
|
||||
|
||||
int _returnCode = 0;
|
||||
int _size = -1;
|
||||
bool _canReuse = false;
|
||||
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user