adapters/httpapi_tirtos.c (253 lines of code) (raw):
// Copyright (c) Texas Instruments. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ti/net/http/httpcli.h>
#include "azure_c_shared_utility/httpapi.h"
#include "azure_c_shared_utility/strings.h"
#include "azure_c_shared_utility/xlogging.h"
#include "azure_c_shared_utility/safe_math.h"
#define CONTENT_BUF_LEN 128
static const char* getHttpMethod(HTTPAPI_REQUEST_TYPE requestType)
{
switch (requestType) {
case HTTPAPI_REQUEST_GET:
return (HTTPStd_GET);
case HTTPAPI_REQUEST_POST:
return (HTTPStd_POST);
case HTTPAPI_REQUEST_PUT:
return (HTTPStd_PUT);
case HTTPAPI_REQUEST_DELETE:
return (HTTPStd_DELETE);
case HTTPAPI_REQUEST_PATCH:
return (HTTPStd_PATCH);
default:
return (NULL);
}
}
static int splitHeader(char *headerName, char **headerValue)
{
*headerValue = strchr(headerName, ':');
if (*headerValue == NULL) {
return (-1);
}
**headerValue = '\0';
(*headerValue)++;
while (**headerValue == ' ') {
(*headerValue)++;
}
return (0);
}
HTTPAPI_RESULT HTTPAPI_Init(void)
{
return (HTTPAPI_OK);
}
void HTTPAPI_Deinit(void)
{
}
HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
{
int ret;
struct sockaddr addr;
HTTPCli_Handle cli;
ret = HTTPCli_initSockAddr(&addr, hostName, 0);
if (ret < 0) {
LogError("HTTPCli_initSockAddr failed, ret=%d", ret);
return (NULL);
}
((struct sockaddr_in *) (&addr))->sin_port = htons(HTTPStd_SECURE_PORT);
cli = HTTPCli_create();
if (cli == NULL) {
LogError("HTTPCli_create failed");
return (NULL);
}
ret = HTTPCli_connect(cli, &addr, HTTPCli_TYPE_TLS, NULL);
if (ret < 0) {
LogError("HTTPCli_connect failed, ret=%d", ret);
HTTPCli_delete(&cli);
return (NULL);
}
return ((HTTP_HANDLE) cli);
}
void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
{
HTTPCli_Handle cli = (HTTPCli_Handle) handle;
if (cli) {
HTTPCli_disconnect(cli);
HTTPCli_delete(&cli);
}
}
HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle,
HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content,
size_t contentLength, unsigned int* statusCode,
HTTP_HEADERS_HANDLE responseHeadersHandle,
BUFFER_HANDLE responseContent)
{
HTTPCli_Handle cli = (HTTPCli_Handle) handle;
int ret;
int offset;
size_t cnt;
char contentBuf[CONTENT_BUF_LEN] = {0};
char *hname;
char *hvalue;
const char *method;
bool moreFlag;
method = getHttpMethod(requestType);
if ((cli == NULL) || (method == NULL) || (relativePath == NULL)
|| (statusCode == NULL) || (responseHeadersHandle == NULL)) {
LogError("Invalid arguments: handle=%p, requestType=%d, relativePath=%p, statusCode=%p, responseHeadersHandle=%p",
handle, (int)requestType, relativePath, statusCode, responseHeadersHandle);
return (HTTPAPI_INVALID_ARG);
}
else if (HTTPHeaders_GetHeaderCount(httpHeadersHandle, &cnt)
!= HTTP_HEADERS_OK) {
LogError("Cannot get header count");
return (HTTPAPI_QUERY_HEADERS_FAILED);
}
/* Send the request line */
ret = HTTPCli_sendRequest(cli, method, relativePath, true);
if (ret < 0) {
LogError("HTTPCli_sendRequest failed, ret=%d", ret);
return (HTTPAPI_SEND_REQUEST_FAILED);
}
/* Send the request headers */
while (cnt--) {
ret = HTTPHeaders_GetHeader(httpHeadersHandle, cnt, &hname);
if (ret != HTTP_HEADERS_OK) {
LogError("Cannot get request header %d", cnt);
return (HTTPAPI_QUERY_HEADERS_FAILED);
}
ret = splitHeader(hname, &hvalue);
if (ret == 0) {
ret = HTTPCli_sendField(cli, hname, hvalue, false);
}
free(hname);
hname = NULL;
if (ret < 0) {
LogError("HTTP send field failed, ret=%d", ret);
return (HTTPAPI_SEND_REQUEST_FAILED);
}
}
/* Send the last header and request body */
ret = HTTPCli_sendField(cli, NULL, NULL, true);
if (ret < 0) {
LogError("HTTP send empty field failed, ret=%d", ret);
return (HTTPAPI_SEND_REQUEST_FAILED);
}
if (content && contentLength != 0) {
ret = HTTPCli_sendRequestBody(cli, (const char *)content,
contentLength);
if (ret < 0) {
LogError("HTTP send request body failed, ret=%d", ret);
return (HTTPAPI_SEND_REQUEST_FAILED);
}
}
/* Get the response status code */
ret = HTTPCli_getResponseStatus(cli);
if (ret < 0) {
LogError("HTTP receive response failed, ret=%d", ret);
return (HTTPAPI_RECEIVE_RESPONSE_FAILED);
}
*statusCode = (unsigned int)ret;
/* Get the response headers */
hname = NULL;
cnt = 0;
offset = 0;
do {
ret = HTTPCli_readResponseHeader(cli, contentBuf, CONTENT_BUF_LEN,
&moreFlag);
if (ret < 0) {
LogError("HTTP read response header failed, ret=%d", ret);
ret = HTTPAPI_RECEIVE_RESPONSE_FAILED;
goto headersDone;
}
else if (ret == 0) {
/* All headers read */
goto headersDone;
}
if (cnt < offset + ret) {
size_t malloc_size = safe_add_size_t(offset, ret);
if (malloc_size == SIZE_MAX)
{
LogError("invalid realloc size");
hname = NULL;
}
else
{
hname = (char*)realloc(hname, malloc_size);
}
if (hname == NULL) {
LogError("Failed reallocating memory");
ret = HTTPAPI_ALLOC_FAILED;
goto headersDone;
}
cnt = offset + ret;
}
memcpy(hname + offset, contentBuf, ret);
offset += ret;
if (moreFlag) {
continue;
}
ret = splitHeader(hname, &hvalue);
if (ret < 0) {
LogError("HTTP split header failed, ret=%d", ret);
ret = HTTPAPI_HTTP_HEADERS_FAILED;
goto headersDone;
}
ret = HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle,
hname, hvalue);
if (ret != HTTP_HEADERS_OK) {
LogError("Adding the response header failed");
ret = HTTPAPI_HTTP_HEADERS_FAILED;
goto headersDone;
}
offset = 0;
} while (1);
headersDone:
free(hname);
hname = NULL;
if (ret != 0) {
return ((HTTPAPI_RESULT)ret);
}
/* Get response body */
if (responseContent != NULL) {
offset = 0;
cnt = 0;
do {
ret = HTTPCli_readResponseBody(cli, contentBuf, CONTENT_BUF_LEN,
&moreFlag);
if (ret < 0) {
LogError("HTTP read response body failed, ret=%d", ret);
ret = HTTPAPI_RECEIVE_RESPONSE_FAILED;
goto contentDone;
}
if (ret != 0) {
cnt = ret;
ret = BUFFER_enlarge(responseContent, cnt);
if (ret != 0) {
LogError("Failed enlarging response buffer");
ret = HTTPAPI_ALLOC_FAILED;
goto contentDone;
}
ret = BUFFER_content(responseContent,
(const unsigned char **)&hname);
if (ret != 0) {
LogError("Failed getting the response buffer content");
ret = HTTPAPI_ALLOC_FAILED;
goto contentDone;
}
memcpy(hname + offset, contentBuf, cnt);
offset += cnt;
}
} while (moreFlag);
contentDone:
if (ret < 0) {
BUFFER_unbuild(responseContent);
return ((HTTPAPI_RESULT)ret);
}
}
return (HTTPAPI_OK);
}
HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName,
const void* value)
{
return (HTTPAPI_INVALID_ARG);
}
HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value,
const void** savedValue)
{
return (HTTPAPI_INVALID_ARG);
}