Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send an option body with a POST request (enhanced) #21

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
49 changes: 43 additions & 6 deletions HttpClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
// Initialize constants
const char* HttpClient::kUserAgent = "Arduino/2.1";
const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": ";
// Store body and content type pointers here so they can be sent also from a complex
// request with additional headers
char* HttpClient::pBody = NULL;
char* HttpClient::pContentType = NULL;

#ifdef PROXY_ENABLED // currently disabled as introduces dependency on Dns.h in Ethernet
HttpClient::HttpClient(Client& aClient, const char* aProxy, uint16_t aProxyPort)
Expand Down Expand Up @@ -56,7 +60,7 @@ void HttpClient::beginRequest()
iState = eRequestStarted;
}

int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent)
int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aContentType, const char* aBody)
{
tHttpState initialState = iState;
if ((eIdle != iState) && (eRequestStarted != iState))
Expand Down Expand Up @@ -92,14 +96,18 @@ int HttpClient::startRequest(const char* aServerName, uint16_t aServerPort, cons
if ((initialState == eIdle) && (HTTP_SUCCESS == ret))
{
// This was a simple version of the API, so terminate the headers now
finishHeaders();
finishHeaders(aContentType, aBody);
}
// else we'll call it in endRequest or in the first call to print, etc.
else {
pBody = (char *)aBody;
pContentType = (char *)aContentType;
}

return ret;
}

int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent)
int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent, const char* aContentType, const char* aBody)
{
tHttpState initialState = iState;
if ((eIdle != iState) && (eRequestStarted != iState))
Expand Down Expand Up @@ -135,9 +143,13 @@ int HttpClient::startRequest(const IPAddress& aServerAddress, const char* aServe
if ((initialState == eIdle) && (HTTP_SUCCESS == ret))
{
// This was a simple version of the API, so terminate the headers now
finishHeaders();
finishHeaders(aContentType, aBody);
}
// else we'll call it in endRequest or in the first call to print, etc.
else {
pBody = (char *)aBody;
pContentType = (char *)aContentType;
}

return ret;
}
Expand Down Expand Up @@ -272,9 +284,24 @@ void HttpClient::sendBasicAuth(const char* aUser, const char* aPassword)
iClient->println();
}

void HttpClient::finishHeaders()
void HttpClient::finishHeaders(const char* aContentType, const char* aBody)
{
if (aContentType)
{
sendHeader(HTTP_HEADER_CONTENT_TYPE, aContentType);
}

if (aBody)
{
sendHeader(HTTP_HEADER_CONTENT_LENGTH, strlen(aBody));
}

iClient->println();
if (aBody)
{
iClient->println(aBody);
}

iState = eRequestSent;
}

Expand All @@ -283,11 +310,21 @@ void HttpClient::endRequest()
if (iState < eRequestSent)
{
// We still need to finish off the headers
finishHeaders();
finishHeaders(pContentType, pBody);
pBody = NULL;
pContentType = NULL;
}
// else the end of headers has already been sent, so nothing to do here
}

void HttpClient::forceEndRequest()
{
if (iState < eRequestSent)
{
iState = eRequestSent;
}
}

int HttpClient::responseStatusCode()
{
if (iState < eRequestSent)
Expand Down
68 changes: 44 additions & 24 deletions HttpClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ static const int HTTP_ERROR_INVALID_RESPONSE =-4;
#define HTTP_HEADER_CONTENT_LENGTH "Content-Length"
#define HTTP_HEADER_CONNECTION "Connection"
#define HTTP_HEADER_USER_AGENT "User-Agent"
#define HTTP_HEADER_CONTENT_TYPE "Content-Type"

class HttpClient : public Client
{
Expand Down Expand Up @@ -61,7 +62,12 @@ class HttpClient : public Client
but you will also need to call beginRequest() at the start.
*/
void endRequest();

/** End an even more complex request.
Use this when you need to create and send the request using connect and write,
avoiding the use of the library, but still want to receive the response by
means of this library.
*/
void forceEndRequest();
/** Connect to the server and start to send a GET request.
@param aServerName Name of the server being connected to. If NULL, the
"Host" header line won't be sent
Expand All @@ -73,7 +79,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, HTTP_METHOD_GET, aUserAgent); }
{ return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); }

/** Connect to the server and start to send a GET request.
@param aServerName Name of the server being connected to. If NULL, the
Expand All @@ -84,7 +90,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, HTTP_METHOD_GET, aUserAgent); }
{ return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); }

/** 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.
Expand All @@ -102,7 +108,7 @@ class HttpClient : public Client
uint16_t aServerPort,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent); }
{ return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); }

/** 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.
Expand All @@ -118,7 +124,7 @@ class HttpClient : public Client
const char* aServerName,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent); }
{ return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_GET, aUserAgent, NULL, NULL); }

/** Connect to the server and start to send a POST request.
@param aServerName Name of the server being connected to. If NULL, the
Expand All @@ -131,9 +137,11 @@ class HttpClient : public Client
*/
int post(const char* aServerName,
uint16_t aServerPort,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent); }
const char* aURLPath,
const char* aUserAgent =NULL,
const char* aContentType =NULL,
const char* aBody =NULL)
{ return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); }

/** Connect to the server and start to send a POST request.
@param aServerName Name of the server being connected to. If NULL, the
Expand All @@ -145,8 +153,10 @@ class HttpClient : public Client
*/
int post(const char* aServerName,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent); }
const char* aUserAgent =NULL,
const char* aContentType =NULL,
const char* aBody =NULL)
{ return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); }

/** 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.
Expand All @@ -163,8 +173,10 @@ class HttpClient : public Client
const char* aServerName,
uint16_t aServerPort,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent); }
const char* aUserAgent =NULL,
const char* aContentType =NULL,
const char* aBody =NULL)
{ return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); }

/** 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.
Expand All @@ -179,8 +191,10 @@ class HttpClient : public Client
int post(const IPAddress& aServerAddress,
const char* aServerName,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent); }
const char* aUserAgent =NULL,
const char* aContentType =NULL,
const char* aBody =NULL)
{ return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_POST, aUserAgent, aContentType, aBody); }

/** Connect to the server and start to send a PUT request.
@param aServerName Name of the server being connected to. If NULL, the
Expand All @@ -195,7 +209,7 @@ class HttpClient : public Client
uint16_t aServerPort,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); }
{ return startRequest(aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); }

/** Connect to the server and start to send a PUT request.
@param aServerName Name of the server being connected to. If NULL, the
Expand All @@ -208,7 +222,7 @@ class HttpClient : public Client
int put(const char* aServerName,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); }
{ return startRequest(aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); }

/** 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.
Expand All @@ -226,7 +240,7 @@ class HttpClient : public Client
uint16_t aServerPort,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); }
{ return startRequest(aServerAddress, aServerName, aServerPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); }

/** 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.
Expand All @@ -242,7 +256,7 @@ class HttpClient : public Client
const char* aServerName,
const char* aURLPath,
const char* aUserAgent =NULL)
{ return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent); }
{ return startRequest(aServerAddress, aServerName, kHttpPort, aURLPath, HTTP_METHOD_PUT, aUserAgent, NULL, NULL); }

/** Connect to the server and start to send the request.
@param aServerName Name of the server being connected to.
Expand All @@ -257,7 +271,9 @@ class HttpClient : public Client
uint16_t aServerPort,
const char* aURLPath,
const char* aHttpMethod,
const char* aUserAgent);
const char* aUserAgent,
const char* aContentType,
const char* aBody);

/** Connect to the server and start to send the request.
@param aServerAddress IP address of the server to connect to.
Expand All @@ -275,7 +291,9 @@ class HttpClient : public Client
uint16_t aServerPort,
const char* aURLPath,
const char* aHttpMethod,
const char* aUserAgent);
const char* aUserAgent,
const char* aContentType,
const char* aBody);

/** Send an additional header line. This can only be called in between the
calls to startRequest and finishRequest.
Expand Down Expand Up @@ -361,8 +379,8 @@ class HttpClient : public Client
// Inherited from Print
// Note: 1st call to these indicates the user is sending the body, so if need
// Note: be we should finish the header first
virtual size_t write(uint8_t aByte) { if (iState < eRequestSent) { finishHeaders(); }; return iClient-> write(aByte); };
virtual size_t write(const uint8_t *aBuffer, size_t aSize) { if (iState < eRequestSent) { finishHeaders(); }; return iClient->write(aBuffer, aSize); };
virtual size_t write(uint8_t aByte) { if (iState < eRequestSent) { finishHeaders(NULL, NULL); }; return iClient-> write(aByte); };
virtual size_t write(const uint8_t *aBuffer, size_t aSize) { if (iState < eRequestSent) { finishHeaders(NULL, NULL); }; return iClient->write(aBuffer, aSize); };
// Inherited from Stream
virtual int available() { return iClient->available(); };
/** Read the next byte from the server.
Expand Down Expand Up @@ -407,11 +425,11 @@ class HttpClient : public Client

/* Let the server know that we've reached the end of the headers
*/
void finishHeaders();
void finishHeaders(const char* aContentType, const char* aBody);

// Number of milliseconds that we wait each time there isn't any data
// available to be read (during status code and header processing)
static const int kHttpWaitForDataDelay = 1000;
static const int kHttpWaitForDataDelay = 20;
// Number of milliseconds that we'll wait in total without receiveing any
// data before returning HTTP_ERROR_TIMED_OUT (during status code and header
// processing)
Expand Down Expand Up @@ -444,6 +462,8 @@ class HttpClient : public Client
IPAddress iProxyAddress;
uint16_t iProxyPort;
uint32_t iHttpResponseTimeout;
static char* pBody;
static char* pContentType;
};

#endif