http_client
IHTTPClient is simple HTTP client.
File information
Functions
Helper functions
inline const char * HTTPShutdownReasonToStr(http_shutdown_reason_t reason)
Helper function to convert a http_shutdown_reason_t to a string. Helpful for debugging and logging purposes.
HTTPShutdownReasonToStr
Parameters
http_shutdown_reason_t reason | The shutdown reason to get the string for. |
Return value
The name of the shutdown reason. Will be the same as the name of the num itself.
Classes
IHTTPClient
class IHTTPClient {
public:
virtual ~IHTTPClient() {}
static IHTTPClient * Create(class IIoMux * const iomux,
class ISocketProvider * const tcpSocketProvider,
class ISocketProvider * const tlsSocketProvider,
class UHTTPClient * const user,
class IInstanceLog * const log,
class IDns * const dns = nullptr,
class ISocketContext * const socketContext = nullptr);
virtual void Connect(const char * address,
const char * user = NULL,
const char * pwd = NULL,
int authMethods = HTTP_AUTH_ALL) = 0;
virtual void Recv(byte * buffer, size_t size, bool recvPartitial = false);
virtual void Send(const byte * data = NULL, size_t size = 0, bool last = false);
virtual void Shutdown();
virtual void Reconnect();
virtual void PassErrorToUser(http_error_t err);
virtual void SendContentForAuthentication(bool doSend);
virtual void SetRequestType(http_request_type_t reqType, const char * resourceName, size_t contentLength = 0, const char * contentType = "text/xml; charset=utf-8");
virtual void SetCustomHeaderField(const char * field, const char * value);
virtual http_result_t GetHTTPResult();
virtual size_t GetContentLength(bool & chunked);
virtual size_t GetHeaderFieldValueCount(const char * headerField);
virtual const char * GetHeaderFieldValue(const char * headerField, size_t index = 0);
virtual bool Connected();
};
This is the main class of the HTTP client functionality. Please note that IHTTPClient is not a fully-fledged HTTP client. For now only GET, PUT and POST requests can be used.
However, the generally used authentication variants are supported by the Client (basic, digest and NTLM). Connections can be established by a TCP or a TLS socket. This depends
on the address given to connect (HTTP for normal TCP connections, HTTPS for a TLS connection).
Public functions
Create (static function)
Creates an IHTTPClient instance.
Parameters
IIoMux * const iomux | The iomux instance needed for socket communication. |
ISocketProvider * const tcpSocketProvider | A socket provider to create a TCP socket. |
ISocketProvider * const tlsSocketProvider | A socket provider to create a TLS socket. |
UHTTPClient * const user | An UHTTPClient instance to receive the callbakcs from IHTTPClient. |
IInstanceLog * const log | The log instance for logging. |
IDns * const dns | The optional dns instance for dns requests. If specified, the same DNS instance is used for DNS requests which saves performance. |
ISocketContext * const socketContext | An optional socketContext which can be used for the socket which is created by the httpclient. You can disable sending of a client certificate with this socketContext or send a specific own client certificate. |
Return Value
The IHTTPClient instance created. Must be deleted if no longer used.
Connect
Connects to the given address (wich can be an IPv4 or IPv6 address, as well asn an URI). If the address is a URI and that URI starts with HTTPS,
an TLS connection will be established instead of the default TCP connection.
Parameters
const char * address | The address to connect to. Can be an IPv4 / IPv6 address or an valid URI. |
const char * user | (Default: nullptr) The user for authentication if requested by the server. |
const char * pwd | (Default: nullptr) The password for authentication if requested by the server. |
int authMethods | (Default: HTTP_AUTH_ALL) The autentications to accept as bit field Can be a combination of HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST and HTTP_AUTH_NTLM. Or HTTP_AUTH_ALL to accept all of them. |
Callbacks
On success, UTHHPClient::HTTPClientConnectComplete() will be called. If an error occurres, the connection will be closed, which leads to a call to UHTTPClient::HTTPClientShutdown().
Remarks
If using an URI to connect, an username and password for authentication can also be given wiht the URI itself ("http://user::pwd@mysite.com").
Recv
Let the HTTP Client receive data. Must be called after sending a GET request and receiving the callback, that the request is completed (which means, the response header
had ben read and interpreted). Recv() also should only be called after checking, if the request result actually delivers data.
Parameters
byte * buffer | The buffer to write the received data to. |
size_t size | The size of the buffer. |
bool recvPartitial |
(Default: false) If true, the function will call the callback as soon as a couple of bytes had been received. If false,
the HTTP client waits until received the number of bytes given in size.
|
Callbacks
UHTTPClient::HTTPClientRecvResult() will be called after the data had been read or UHTTPClient::HTTPClientRecvCanceled(), if the Recv() call had been canceled for whatever reason.
Remarks
Be careful with calling Recv() and readPartitial set to false. Because if the data received will be less than size, Recv() will never lead to a callback.
Send
Sends the request by building a correct header and sending that it. So Send() must be called even if there is no need to send additional data, too. If there is additional data,
it can be given to Send() and will be send after the header. If the data to send is chunked encoded, Send() can be called multiple times until all of the data had been send.
To end a chunck encoded transfer, set the last flag to true.
Parameters
const byte * data | (Default: nullptr) The buffer holding additional data to send or nullptr to send nothing else. |
size_t size | (Default: 0) The number of bytes to send. |
bool last | (Default: false) If true, that send call indicates the end of a chunk encoded transfer. |
Callbacks
UHTTPClient::HTTPClientSendResult() will be called after the data had been send. After the request had been completed, UTHHPClient::HTTPClientRequestComplete() will be called.
Remarks
To respect the flow control nescessary for the asynchronous kind of communication used by the IHTTPClient, continous send calles should be made after receiving a
UHTTPClient::HTTPClientSendResult() callback.
Shutdown
Closes the HTTP conenction. If there is data left inside the IHTTPClient that still must be send, it will be send first before closing the connection.
Callbacks
After the connection had been closed, UHTTPClient::HTTPClientShutdown() will be called.
Reconnect
After the connection had been closed (because of a call to IHTTPConnection::Shutdown() or because of a close initiated by the server), it can be restablished by calling
Reconnect() using the same optiones (request type, server address, ...) as given for the first request.
Callbacks
On success, UTHHPClient::HTTPClientConnectComplete() will be called. If an error occurres, the connection will be closed, which leads to a call to UHTTPClient::HTTPClientShutdown().
PassErrorToUser
Generally an error leads to a shutdown of the IHTTPClient. But sometimes it it useful to not closed the error and pass it the the app instead. This can be activated with
PassErrorToUser(). In case of an error that should be passed to the user, the error case will be redirected to a normal UHTTPClient::HTTPClientRequestComplete() callback.
The UHTTPClient must than check the HTTP result by calling IHTTPClient::GetHTTPResult().
Parameters
http_error_t err | The HTTP Error to pass to the user. Can be a bit field. |
Callbacks
In case of one of the given errors occurres, UHTTPClient::HTTPClientReqeustComplete() will be called anyway.
Remarks
Even if PassErrorToUser() can theoreticaly called multiple times, the better way will be to call it once giving a bit filed of flags, cobined using or.
Valid flags ar HTTP_CL_ERR_NOT_FOUND, HTTP_CL_ERR_BAD_REQUEST, HTTP_CL_ERR_INTERNAL_SERVER and HTTP_CL_ERR_REDIRECT. See the data type section below for details.
SendContentForAuthentication
When connecting to a server that needs authentication, the IHTTPClient at first sends a request without the conent (if a POST request need to be send). This
helps to prevend sending data that won't be needed. But it can be, that the server won't accept such a request. An example for that is the Microsoft Exchange
365 server, which will respond with an bad request. For that case, SendContentFoprAuthentication() can be used, so that the data for the POST request will
be send even if the HTTP client needs to authenticate first.
Parameters
bool doSend | True, to send the request content for autnehtication, too. |
Remarks
The default is, that no content will be send for authentication.
SetRequestType
Befor sending the request, the application first needs to set the type of the request as well as the resourceName it wants to access. If the request is not a GET
request, data can be or need to send. In that case, the datatype (aka mime-type) must be defined as well as the content length. If the content length is unkown,
HTTP_CLIENT_CHUNKED_TRANSFER can be used to enabled chuncked transfer of the data.
Parameters
http_request_type_t reqType | The request type - must be HTTP_GET, HTTP_POST or HTTP_PUT. |
const char * resourceName | The resource name for the request. |
size_t contentLength | (Default: 0) The content length of additional data to send (HTTP_POST & HTTP_PUT only). |
const char * contentType | (Default: "text/xml; charset=utf-8") The mime-type of the additional data to send (HTTP_POST & HTTP_PUT only). |
SetCustomHeaderField
Adds the given header field with the given value to the HTTP header to send. Because of this, SetCustomHeaderField() must be called before calling Send().
Parameters
const char * field | The name of the field to set. |
const char * value | The value to set for that field. |
GetHTTPResult
Return Value
The result of the last completed request. See the data types section of this document for details on http_result_t.
GetContentLength
Returns the size of the content sent with the requests response. It can be that the content is chunk encoded. In that case, the given bool
variable will set to true.
Parameters
bool & chunked | If the received data is chunk encoded, true will be stored to the chuncked variable. |
Return Value
The size of the content sent with the response or 0, if no data is available or if the received data is chunk encoded.
Remarks
The return value must be intepreted as follows:
- If the returned value is > 0, the app must read that amount of data using Recv().
- If the retunred value is 0 and the flag chunked is set, the app must read data until the end of the stream had been reached.
- If the returned value is 0 and the flag chunked is not set, there is not data sent with the response.
GetHeaderFieldValueCount
A headerfield can be set more then once in the HTTP header. To get the number of occurrences, GetHeaderFieldValueCount() must be called.
Parameters
const char * headerField | The name of the requested header field. |
Return Value
The number of occurrences of that field or 0, if that field won't exist.
GetHeaderFieldValue
Can be used to access the values of the HTTP header fields send with the last response.
Parameters
const char * headerField | The name of the requested header field. |
size_t index | (Default: 0) The index of the header field, must be between 0 and GetHeaderFieldValueCount(headerField) - 1. |
Return Value
The value of the header field.
Remarks
Don't save the pointer itself for later use, because after sending an new request, the returned pointer becomes invalid. If the value of that header field needs to
be used later, it must be copied.
Connected
Return Value
True, if the HTTP client is connected, else false.
UHTTPClient
class UHTTPClient {
public:
~UHTTPClient() {}
virtual void HTTPClientConnectComplete(IHTTPClient * const httpClient);
virtual void HTTPClientShutdown(IHTTPClient * const httpClient, http_shutdown_reason_t reason);
virtual void HTTPClientSendResult(IHTTPClient * const httpClient);
virtual void HTTPClientRecvResult(IHTTPClient * const httpClient, byte * buffer, size_t len, bool transferComplete);
virtual void HTTPClientRecvCanceled(IHTTPClient * const httpClient, byte * buffer);
virtual void HTTPClientRequestComplete(IHTTPClient * const httpClient);
};
This class is for receiving callbacks from the IHTTPClient. You must pass as subclass of UHTTPClient to an IHTTPClient as user.
HTTPClientConnectComplete
Will be called after the connection to the server had been successfully established. Here is the right place to setup up the request type
(by calling ITTHClient::SetRequestType()) and send the request.
Parameters
IHTTPClient * const httpClient | The calling IHTTPClient instance. |
HTTPClientShutdown
Will be called after the IHTTPClient connection had been shutdown because of Shutdown() had been called or because of the connection had been closed by the server.
Parameters
IHTTPClient * const httpClient | The calling IHTTPClient instance. |
http_shutdown_reason_t reason | The reason for the shutdown. See the data types section below for details. |
HTTPClientSendResult
Will be called after the Send() had been completed, which means that the header and an eventuell given additional data to send had been send. If there is more data to send,
this will be the right place for sending the next part to respect the asynchronous flow control.
Parameters
IHTTPClient * const httpClient | The calling IHTTPClient instance. |
HTTPClientRequestComplete
Will be called if the HTTP request has been successfully completed. A completed request means, that everything for the request had been send and the result header had been
received and interpreted. So this callback function will be the right place to check for data thay maybe available with the response and call IHTTPClient::Recv() to receive it.
Parameters
IHTTPClient * const httpClient | The calling IHTTPClient instance. |
HTTPClientRecvResult
Will be called after the application called IHTTPClient::Recv() and data had been received. The flag transferComplete indicates, if the data of the response
had been received completley or not (which counts for both, streamed and chunk encoded transfer). If false, additional Recv() calls must follow until the flag
is set to true.
Parameters
IHTTPClient * const httpClient | The calling IHTTPClient instance. |
byte * buffer | The buffer holding the received data. |
size_t len | The number of bytes received. |
bool transferComplete | true, if the transfer is completed (all data received), else false. |
HTTPClientRecvCanceled
Will be called before UHTTPClient::HTTPClientShutdown(), if a receive data buffer had been passed through IHTTPClient::Recv() and not returned back via
UHTTPClient::HTTPClientRecvResult(). If the buffer was allocated individually this gives the opportunity to free it.
Parameters
IHTTPClient * const httpClient | The calling IHTTPClient instance. |
byte * buffer | The buffer given to Recv() to free it (if needed). |
Data types
Defines
#define HTTP_AUTH_NONE 0
#define HTTP_AUTH_NTLM 1
#define HTTP_AUTH_DIGEST 2
#define HTTP_AUTH_BASIC 4
#define HTTP_AUTH_ALL HTTP_AUTH_NTLM | HTTP_AUTH_DIGEST | HTTP_AUTH_BASIC
#define HTTP_CLIENT_CHUNKED_TRANSFER 0xffffffff
HTTP_AUTH_NONE | (Use with IHTTPClient::Connect()) Don't support authentication. |
HTTP_AUTH_NTLM | (Use with IHTTPClient::Connect()) Accept NTLM authentication. |
HTTP_AUTH_DIGEST | (Use with IHTTPClient::Connect()) Accept digest authentication. |
HTTP_AUTH_BASIC | (Use with IHTTPClient::Connect()) Accept basic authentication. |
HTTP_AUTH_ALL | (Use with IHTTPClient::Connect()) Accept all supported authentications. This is the default. |
HTTP_CLIENT_CHUNKED_TRANSFER | The end of line, used inside the HTTP header. The Header ends with on empty line, which is a line that only holds CLRF. |
http_request_type_t
typedef enum {
HTTP_GET,
HTTP_POST,
HTTP_PUT
} http_request_type_t;
This enum defines the request types supported by the IHTTPClient. One of them must be given to IHTTP::SetRequestType(). The supported request types by the IHTTPClient are GET, POST and PUT.
http_shutdown_reason_t
typedef enum {
HTTP_SHUTDOWN_NORMAL,
HTTP_SOCKET_LOST,
HTTP_ADDRESS_INVALID,
HTTP_SOCKET_ERROR,
HTTP_CONNECT_FAILED,
HTTP_BYTE_STREAM_BROKEN,
HTTP_UNHANDLED_HTTP_RESULT,
HTTP_FAILURE,
HTTP_AUTHENTICATION_FAILED,
HTTP_NOT_FOUND,
HTTP_BAD_REQUEST,
HTTP_INTERNAL_SERVER_ERROR
} http_shutdown_reason_t;
This enum defines the reasons for a shutdown. The following reason can lead to a IHTTPClient shutdown:
HTTP_SHUTDOWN_NORMAL | A normal shutdown initiated by the application itself by calling IHTTPClient::Shutdown(). |
HTTP_SOCKET_LOST | The socket had been lost. |
HTTP_ADDRESS_INVALID | The address given to IHTTPClient::Connect() was invalid. |
HTTP_SOCKET_ERROR | An unexpected socket error occured. |
HTTP_CONNECT_FAILED | Creating the connection failed. |
HTTP_BYTE_STREAM_BROKEN | There was an error inside the byte stream while authenticating or receiving data. |
HTTP_UNHANDLED_HTTP_RESULT | An not expected HTTP result had been returned by the server. |
HTTP_FAILURE | En error had been found in the response http header, sent by the server. |
HTTP_AUTHENTICATION_FAILED | The authentication failed (e. G. because of wrong username / password or an unsupported authentication method). |
HTTP_NOT_FOUND | The requested resource for the request could not be found on the server. |
HTTP_BAD_REQUEST | The request was bad or malformed (e. g. a custom header field was wrong). |
HTTP_INTERNAL_SERVER_ERROR | An internal error occured on the server side. |
http_result_t
typedef enum {
HTTP_RESULT_OK,
HTTP_RESULT_NOT_FOUND,
HTTP_RESULT_BAD_REQUEST,
HTTP_RESULT_INTERNAL_SERVER_ERROR
} http_result_t;
This enum defines the results of a HTTP request. That results can be get by calling IHTTPClient::GetHTTPResult(). The following results are supported
by that function:
HTTP_RESULT_OK | (HTTP 200) The request was correct and an appropriate response had been send. |
HTTP_RESULT_NOT_FOUND | (HTTP 404) The requested resource could not be found on the server. |
HTTP_RESULT_BAD_REQUEST | (HTTP 400) The request was malformed (e. g. a custom header field was used incorrectly). |
HTTP_RESULT_INTERNAL_SERVER_ERROR | (HTTP 500) An internal error occurred on the server. |
http_error_t
typedef enum {
HTTP_CL_ERR_NOT_FOUND = 0x0001,
HTTP_CL_ERR_BAD_REQUEST = 0x0002,
HTTP_CL_ERR_INTERNAL_SERVER = 0x0004
} http_error_t;
This enum defines the errors that should be passed to the UHTTPClient user. Instead of shutting down the IHTTPClient, the request will be accepted
and UHTTPClient::HTTPClientRequestComplete() will be called. The user must check the error code (by calling IHTTPClient::GetHTTPResult()) and
handle it properly. The flags of http_error_t can be combined to a bitfield by a binary or operator. The following flags are supported:
HTTP_CL_ERR_NOT_FOUND | (HTTP 404) requested resource could not be found on the server. |
HTTP_CL_ERR_BAD_REQUEST | (HTTP 400) The request was malformed (e. g. a custom header field was used incorrectly). |
HTTP_CL_ERR_INTERNAL_SERVER | (HTTP 500) An internal error occurred on the server. |
Code Example
app::app(IIoMux * iomux)
: iomux(iomux)
{
// you can optionally create a socketContext, if you e.g. want to disable sending of a client certificate
class ISocketContext * socketContext = aTlsSocketProvider->CreateSocketContext(this);
socketContext->DisableClientCertificate();
// create the httpClient instance
this->httpClient = IHTTPClient::Create(iomux, aTcpSocketProvider, aTlsSocketProvider, this, this, nullptr, socketContext);
this->httpClient->Connect("https://google.de");
}
void app::HTTPClientConnectComplete(IHTTPClient * const httpClient)
{
this->httpClient->SetRequestType(HTTP_GET, "/index.html");
this->httpClient->Send();
}
void app::HTTPClientSendResult(IHTTPClient * const httpClient)
{
// for GET we can simply ignore the send result and wait for HTTPClientRequestComplete
}
void app::HTTPClientRequestComplete(IHTTPClient * const httpClient)
{
this->httpClient->Recv((byte *)malloc(1024), 1024);
}
void app::HTTPClientRecvResult(IHTTPClient * const httpClient, byte * buffer, size_t len, bool transferComplete)
{
printf("%.*s", len, (char *)buffer);
if (transferComplete) {
free(buffer);
this->httpClient->Shutdown();
}
else
this->httpClient->Recv(buffer, 1024);
}
void app::HTTPClientShutdown(IHTTPClient * const httpClient, http_shutdown_reason_t reason)
{
delete this->httpClient;
}