Skip to content
This repository has been archived by the owner on Nov 11, 2024. It is now read-only.

Commit

Permalink
HTTP Client change only: chunked API.
Browse files Browse the repository at this point in the history
The HTTP Client API is extended to support chunked PUT, POST and GET operations, allowing the application to use smaller buffers for both uplink and downlink transfers.

Note: this commit contains the API only, purely for an API review, there is as yet no implementation.
  • Loading branch information
RobMeades committed May 29, 2024
1 parent 7590200 commit 3adc8f2
Showing 1 changed file with 175 additions and 3 deletions.
178 changes: 175 additions & 3 deletions common/http_client/api/u_http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,22 @@ extern "C" {
# define U_HTTP_CLIENT_RESPONSE_WAIT_SECONDS 30
#endif

#ifndef U_HTTP_CLIENT_CHUNK_LENGTH_BYTES
/** The default chunk-length of a HTTP PUT/POST/GET when a
* chunked API is used.
*/
# define U_HTTP_CLIENT_CHUNK_LENGTH_BYTES 128
#endif

/** The defaults for an HTTP connection, see #uHttpClientConnection_t.
* Whenever an instance of #uHttpClientConnection_t is created it
* should be assigned to this to ensure the correct default
* settings.
*/
#define U_HTTP_CLIENT_CONNECTION_DEFAULT {NULL, NULL, NULL, \
U_HTTP_CLIENT_RESPONSE_WAIT_SECONDS, \
NULL, NULL, false, NULL}
NULL, NULL, false, NULL, \
U_HTTP_CLIENT_CHUNK_LENGTH_BYTES}

#ifndef U_HTTP_CLIENT_CONTENT_TYPE_LENGTH_BYTES
/** The maximum length of a content-type string, including room
Expand Down Expand Up @@ -100,6 +108,65 @@ typedef void (uHttpClientResponseCallback_t)(uDeviceHandle_t devHandle,
size_t responseSize,
void *pResponseCallbackParam);

/** Callback to deliver data into a PUT or POST request, used by
* uHttpClientPutRequestChunked() and uHttpClientPostRequestChunked().
*
* This callback will be called repeatedly until it returns 0,
* indicating the end of the HTTP request data. Should something go
* wrong with the transfer this callback will be called with pData
* set to NULL to indicate that it will not be called again for the
* given HTTP request.
*
* @param devHandle the device handle.
* @param[out] pData a pointer to a place to put the data to be sent,
* NULL will be used to indicate that it is no longer
* possible to send any more data.
* @param size the amount of storage at pData; will only be zero
* if pData is NULL, will not be more than the
* maxChunkLengthBytes parameter passed to
* pUHttpClientOpen() in #uHttpClientConnection_t.
* @return the number of bytes that the callback has copied
* into pData, may be up to size bytes; if the data
* happens to be a string that is ending the
* null-terminator should NOT be copied or included
* in the count; the end of a string is indicated
* by this callback returning zero.
*/
typedef size_t (uHttpClientDataCallback_t)(uDeviceHandle_t devHandle,
char *pData, size_t size);

/** Callback to receive response data from a GET or a POST request, used
* by uHttpClientPostRequestChunked() and uHttpClientGetRequestChunked().
*
* This callback will be called repeatedly when a response arrives, while
* the callback returns true; if the callback returns false then it will
* not be called again for the given response. When the response is over
* the callback will be called once more with pResponseBody set to NULL
* to indicate that the response is over.
*
* @param devHandle the device handle.
* @param[in] pResponseBody a pointer to the next chunk of HTTP response
* data; the data may be binary data. This data
* should be copied out before returning, it will
* not be valid once the callback has returned.
* If this parameter is NULL, that indicates the
* end of the response body; should the response
* body be a string, no null terminator will be
* included in pResponseBody.
* @param size the amount of data at pResponseBody; zero if
* pResponseBody is NULL, will not be more than
* the maxChunkLengthBytes parameter passed to
* pUHttpClientOpen() in #uHttpClientConnection_t.
* @return true if the callback may be called again for
* this HTTP response; set this to false if, for
* some reason, no more data is wanted, and then
* the callback will not be called again for this
* HTTP response.
*/
typedef bool (uHttpClientResponseBodyCallback_t)(uDeviceHandle_t devHandle,
const char *pResponseBody,
size_t size);

/** HTTP client connection information. Note that the maximum length
* of the string fields may differ between modules.
* NOTE: if this structure is modified be sure to modify
Expand Down Expand Up @@ -179,6 +246,8 @@ typedef struct {
the HTTP request functions will continue
to wait until success or timeoutSeconds
have elapsed. */
size_t maxChunkLengthBytes; /**< the maximum chunk length in bytes, used
by the chunked APIs. */
} uHttpClientConnection_t;

/** HTTP context data, used internally by this code and
Expand Down Expand Up @@ -280,7 +349,8 @@ void uHttpClientClose(uHttpClientContext_t *pContext);
* to the module or you might experience data loss. If you do not have
* flow control connected when using HTTP with a cellular module this code
* will try to detect that data has been lost and, if so, return the error
* #U_ERROR_COMMON_TRUNCATED.
* #U_ERROR_COMMON_TRUNCATED. You might also take a look at
* uHttpClientPutRequestChunked().
*
* @param[in] pContext a pointer to the internal HTTP context
* structure that was originally returned by
Expand Down Expand Up @@ -308,6 +378,33 @@ int32_t uHttpClientPutRequest(uHttpClientContext_t *pContext,
const char *pData, size_t size,
const char *pContentType);

/** As uHttpClientPutRequest() but with a callback for the data, permitting it
* to be sent in chunks.
*
* @param[in] pContext a pointer to the internal HTTP context
* structure that was originally returned by
* pUHttpClientOpen().
* @param[in] pPath the null-terminated path on the HTTP server
* to PUT the data to, for example
* "/thing/upload.html"; cannot be NULL.
* @param[in] pDataCallback the callback that delivers data into the
* PUT request.
* @param[in] pContentType the null-terminated content type, for example
* "application/text"; must be non-NULL if
* pData is non-NULL.
* @return in the blocking case the HTTP status code or
* negative error code; in the non-blocking case
* zero or negative error code. If
* #U_ERROR_COMMON_UNKNOWN is reported then the
* module has indicated that the HTTP request
* has not worked; in this case it may be worth
* re-trying.
*/
int32_t uHttpClientPutRequestChunked(uHttpClientContext_t *pContext,
const char *pPath,
uHttpClientDataCallback_t *pDataCallback,
const char *pContentType);

/** Make an HTTP POST request. If this is a blocking call (i.e.
* pResponseCallback in the pConnection structure passed to pUHttpClientOpen()
* was NULL) and a pKeepGoingCallback() was provided in pConnection
Expand All @@ -325,6 +422,10 @@ int32_t uHttpClientPutRequest(uHttpClientContext_t *pContext,
* will try to detect that data has been lost and, if so, return the error
* #U_ERROR_COMMON_TRUNCATED.
*
* If you have large amounts of data to POST, or you expect to get large
* amounts of data back from a POST request, you may prefer to use
* uHttpClientPostRequestChunked().
*
* @param[in] pContext a pointer to the internal HTTP context
* structure that was originally returned by
* pUHttpClientOpen().
Expand Down Expand Up @@ -375,6 +476,44 @@ int32_t uHttpClientPostRequest(uHttpClientContext_t *pContext,
char *pResponseBody, size_t *pResponseSize,
char *pResponseContentType);

/** As uHttpClientPostRequest() but with callbacks for the uplink data and
* downlink response, permitting them to be sent and received in chunks.
*
* @param[in] pContext a pointer to the internal HTTP context
* structure that was originally returned by
* pUHttpClientOpen().
* @param[in] pPath the null-terminated path on the HTTP server
* to POST the data to, for example
* "/thing/form.html"; cannot be NULL.
* @param[in] pDataCallback the callback that delivers data into the
* POST request.
* @param[in] pContentType null-terminated content type, for example
* "application/text"; must be non-NULL if
* pData is non-NULL.
* @param[out] pResponseBodyCallback the callback that receives the POST response.
* @param[out] pResponseContentType a place to put the content type of the response,
* for example "application/text". In the non-blocking
* case this storage MUST REMAIN VALID until
* pResponseCallback is called, which will happen on
* a timeout, as well as in the success case. Will
* always be null-terminated. AT LEAST
* #U_HTTP_CLIENT_CONTENT_TYPE_LENGTH_BYTES of storage
* must be provided.
* @return in the blocking case the HTTP status code or
* negative error code; in the non-blocking case
* zero or negative error code. If
* #U_ERROR_COMMON_UNKNOWN is reported then the
* module has indicated that the HTTP request
* has not worked; in this case it may be worth
* re-trying.
*/
int32_t uHttpClientPostRequestChunked(uHttpClientContext_t *pContext,
const char *pPath,
uHttpClientDataCallback_t *pDataCallback,
const char *pContentType,
uHttpClientResponseBodyCallback_t *pResponseBodyCallback,
char *pResponseContentType);

/** Make an HTTP GET request. If this is a blocking call (i.e.
* pResponseCallback in the pConnection structure passed to pUHttpClientOpen()
* was NULL) and a pKeepGoingCallback() was provided in pConnection then
Expand All @@ -390,7 +529,8 @@ int32_t uHttpClientPostRequest(uHttpClientContext_t *pContext,
*
* If you are going to perform large GET requests (e.g. more than 1024
* bytes) then you should ensure that you have flow control on the interface
* to the module or you might experience data loss.
* to the module or you might experience data loss. You might also take
* a look at uHttpClientGetRequestChunked().
*
* @param[in] pContext a pointer to the internal HTTP context
* structure that was originally returned by
Expand Down Expand Up @@ -431,6 +571,38 @@ int32_t uHttpClientGetRequest(uHttpClientContext_t *pContext,
char *pResponseBody, size_t *pSize,
char *pContentType);

/** As uHttpClientGetRequest() but with a callback that permits the response
* to be received in chunks.
*
* @param[in] pContext a pointer to the internal HTTP context
* structure that was originally returned by
* pUHttpClientOpen().
* @param[in] pPath the null-terminated path on the HTTP server
* to GET the data from, for example
* "/thing/download/1.html"; cannot be NULL.
* @param[out] pResponseBodyCallback the callback that receives the body of the
* response to the GET request.
* @param[out] pContentType a place to put the content type of the response,
* for example "application/text". In the non-blocking
* case this storage MUST REMAIN VALID until
* pResponseCallback is called, which will happen on
* a timeout, as well as in the success case. Will
* always be null-terminated. AT LEAST
* #U_HTTP_CLIENT_CONTENT_TYPE_LENGTH_BYTES of storage
* must be provided.
* @return in the blocking case the HTTP status code or
* negative error code; in the non-blocking case
* zero or negative error code. If
* #U_ERROR_COMMON_UNKNOWN is reported then the
* module has indicated that the HTTP request
* has not worked; in this case it may be worth
* re-trying.
*/
int32_t uHttpClientGetRequestChunked(uHttpClientContext_t *pContext,
const char *pPath,
uHttpClientResponseBodyCallback_t *pResponseBodyCallback,
char *pContentType);

/** Make a request for an HTTP header. If this is a blocking call (i.e.
* pResponseCallback in the pConnection structure passed to pUHttpClientOpen()
* was NULL) and a pKeepGoingCallback() was provided in pConnection then
Expand Down

0 comments on commit 3adc8f2

Please sign in to comment.