Skip to content
Closed
9 changes: 8 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,14 @@
"ut_control_plane.h": "c",
"ut.h": "c",
"ut_log.h": "c",
"tuple": "c"
"tuple": "c",
"array": "c",
"compare": "c",
"functional": "c",
"type_traits": "c",
"utility": "c",
"istream": "c",
"ostream": "c"
},
"cmake.configureOnOpen": true
}
10 changes: 10 additions & 0 deletions include/ut_kvp.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,16 @@ uint32_t ut_kvp_getListCount( ut_kvp_instance_t *pInstance, const char *pszKey);
*/
unsigned char* ut_kvp_getDataBytes(ut_kvp_instance_t *pInstance, const char *pszKey, int *size);

/**
* @brief Get the data block from the instance based on the type requested by user.
* User to free the instance where the data is invalid, no output will be provided
* Also caller needs to ensure, that they free the pointer to the data block
*
* @param pInstance - pointer to the KVP instance
* @param pszType - type of data to be retrieved. Currently supported types are "json" and "yaml"
*/
char* ut_kvp_getDataOfType( ut_kvp_instance_t *pInstance, const char *pszType );

/* TODO:
* - Implement functions for getting signed integer values (`ut_kvp_getInt8Field`, `ut_kvp_getInt16Field`, `ut_kvp_getInt32Field`,
*`ut_kvp_getInt64Field`
Expand Down
236 changes: 229 additions & 7 deletions src/ut_control_plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,26 +288,246 @@ static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void
return 0;
}
#else

static char* create_response(ut_cp_instance_internal_t *pInternal, const char* key, const char* type)
{
ut_kvp_instance_t *pkvpInstance = NULL;
ut_kvp_status_t status;
char result_kvp[UT_KVP_MAX_ELEMENT_SIZE] = {0xff};
char* response = NULL;

for (uint32_t i = 0; i < pInternal->callback_entry_index; i++)
{
CallbackEntry_t entry = pInternal->callbackEntryList[i];
void *userData = malloc(strlen(entry.userData) + 1); // +1 for null terminator
if (userData == NULL)
{
UT_CONTROL_PLANE_ERROR("Memory allocation failed\n");
return NULL; // Handle memory allocation failure
}
memcpy(userData, entry.userData, strlen(entry.userData) + 1);

pkvpInstance = ut_kvp_createInstance();

/* Note: userData data will be freed by the destoryInstance() function */
status = ut_kvp_openMemory(pkvpInstance, userData, strlen(entry.userData));
if (status != UT_KVP_STATUS_SUCCESS)
{
UT_CONTROL_PLANE_ERROR("ut_kvp_open() - Read Failure\n");
ut_kvp_destroyInstance(pkvpInstance);
return NULL;
}
if (UT_KVP_STATUS_SUCCESS == ut_kvp_getStringField(pkvpInstance, key, result_kvp, UT_KVP_MAX_ELEMENT_SIZE))
{
response = ut_kvp_getDataOfType(pkvpInstance, type);
}
ut_kvp_destroyInstance(pkvpInstance);
}

return response;
}

// Helper function to send error response
static int send_error_response(struct lws *wsi, int status, const char *content_type, const char *body)
{
unsigned char buffer[LWS_PRE + 1024];
unsigned char *p = buffer + LWS_PRE, *end = buffer + sizeof(buffer);

// Add HTTP headers
if (lws_add_http_common_headers(wsi, status, content_type, strlen(body), &p, end) < 0)
return -1;

// Finalize headers
if (lws_finalize_http_header(wsi, &p, end) < 0)
return -1;

// Write headers
if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
return -1;

// Write body
if (lws_write(wsi, (unsigned char *)body, strlen(body), LWS_WRITE_HTTP_FINAL) < 0)
return -1;

return 0;
}

static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{
cp_message_t msg;
ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t* )lws_context_user(lws_get_context(wsi));
ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)lws_context_user(lws_get_context(wsi));
struct per_session_data__http *perSessionData = (struct per_session_data__http *)user;

switch (reason)
{
case LWS_CALLBACK_HTTP: {

case LWS_CALLBACK_HTTP:
{
UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n");
char *requested_uri = (char *)in;

char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI
char query_string[256] = {0}; // Buffer for the query string
char accept_header[256] = {0}; // Buffer for the Accept header
char *response = NULL;
char *key = NULL;
unsigned char buffer[LWS_PRE + 1024]; // Allocate buffer for headers and body
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is very large for a local stack variable, on 8k stacks or 4k stacks you may have an issue. You should really allocate blocks bigger than 256 bytes as a general rule. and free it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsigned char *p = buffer + LWS_PRE; // Pointer to start of usable buffer space
unsigned char *end = buffer + sizeof(buffer); // Pointer to end of buffer


UT_CONTROL_PLANE_DEBUG("Requested URI: %s\n", requested_uri);

// Handle GET request for /api/getKVP
if (strcmp(requested_uri, "/api/getKVP") == 0)
{
// Extract the query string (if any)
if (lws_hdr_copy(wsi, query_string, sizeof(query_string), WSI_TOKEN_HTTP_URI_ARGS) > 0)
{
UT_CONTROL_PLANE_DEBUG("Query String: %s\n", query_string);

// Directly look for the "key=" prefix in the query string
char *key_param = strstr(query_string, "key=");
if (key_param != NULL)
{
key = key_param + 4; // Extract the value part (skip "key=")
UT_CONTROL_PLANE_DEBUG("Parsed Query Parameter: key=%s\n", key);
}
else
{
UT_CONTROL_PLANE_ERROR("Query parameter 'key' not found\n");
key = NULL; // Ensure key is NULL if not found
}
}
else
{
UT_CONTROL_PLANE_ERROR("Failed to extract query string\n");
key = NULL; // Ensure key is NULL if query string is absent
}

// Extract the Accept header
if (lws_hdr_copy(wsi, accept_header, sizeof(accept_header), WSI_TOKEN_HTTP_ACCEPT) > 0)
{
UT_CONTROL_PLANE_DEBUG("Accept Header: %s\n", accept_header);
}
else
{
UT_CONTROL_PLANE_ERROR("Missing Accept header\n");
const char *error_response = "{\"error\": \"Missing Accept header\"}";
if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, "application/json", error_response) < 0)
return -1;
return -1;
}

// Check for valid key parameter
if (key)
{
if (strncmp(accept_header, "application/json", 16) == 0)
{
response = create_response(pInternal, key, "json");

if (response == NULL)
{
UT_CONTROL_PLANE_ERROR("Failed to create response\n");
const char *error_response = "{\"error\": \"Internal Server Error\"}";
if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, "application/json", error_response) < 0)
return -1;
return -1;
}

// Add HTTP headers
if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0)
{
return -1; // Failed to add headers
}

// Finalize headers
if (lws_finalize_http_header(wsi, &p, end) < 0)
{
return -1; // Failed to finalize headers
}

// Write headers
if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
{
return -1; // Failed to write headers
}

// Write body
if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0)
{
return -1; // Failed to write body
}

free(response);

return 1; // HTTP request handled
}
else if (strncmp(accept_header, "application/x-yaml", 18) == 0)
{
response = create_response(pInternal, key, "yaml");

if (response == NULL)
{
UT_CONTROL_PLANE_ERROR("Failed to create response\n");
const char *error_response = "error: Internal Server Error\n";
if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, "application/x-yaml", error_response) < 0)
return -1;
return -1;
}

// Add HTTP headers
if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0)
{
return -1; // Failed to add headers
}

// Finalize headers
if (lws_finalize_http_header(wsi, &p, end) < 0)
{
return -1; // Failed to finalize headers
}

// Write headers
if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
{
return -1; // Failed to write headers
}

// Write body
if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0)
{
return -1; // Failed to write body
}

free(response);

return 1; // HTTP request handled
}
else
{
UT_CONTROL_PLANE_ERROR("Invalid key value or unsupported Accept header\n");
const char *error_response = "{\"error\": \"Unsupported Accept header or invalid type\"}";
if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, "application/json", error_response) < 0)
return -1;
return -1;
}
}
else
{
UT_CONTROL_PLANE_ERROR("Missing or invalid key parameter\n");
lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL);
return -1;
}
}
// Handle POST request for /api/postKVP
if (strcmp(requested_uri, "/api/postKVP") == 0)
{
lws_callback_on_writable(wsi);
return 0;
return 0; // Let the body handling process continue
}

break;
}

case LWS_CALLBACK_HTTP_BODY:
{
UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n");
Expand All @@ -322,6 +542,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void
else
{
// POST data too large
UT_CONTROL_PLANE_ERROR("POST data too large\n");
return -1;
}
}
Expand Down Expand Up @@ -351,12 +572,13 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void
// lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP);
return 1; // HTTP request handled
}
break;
}

default:
break;
}
return 0;
}
return 0;
}

#endif
Expand Down
43 changes: 43 additions & 0 deletions src/ut_kvp.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,49 @@ unsigned char* ut_kvp_getDataBytes(ut_kvp_instance_t *pInstance, const char *psz
return output_bytes;
}

char* ut_kvp_getDataOfType( ut_kvp_instance_t *pInstance, const char *pszType )
{
ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance);
char *kvp_yaml_output = NULL;

if (pInternal == NULL)
{
return NULL;
}

if ( pInternal->fy_handle == NULL)
{
return NULL;
}

if (pszType == NULL)
{
UT_LOG_ERROR("Invalid Param - type");
return NULL;
}

if (strncmp(pszType, "json", 4) == 0)
{
kvp_yaml_output = fy_emit_document_to_string(pInternal->fy_handle, FYECF_MODE_JSON);
}
else if (strncmp(pszType, "yaml", 4) == 0)
{
kvp_yaml_output = fy_emit_document_to_string(pInternal->fy_handle, FYECF_DEFAULT);
}
else
{
UT_LOG_ERROR("Invalid type");
return NULL;
}

if (kvp_yaml_output == NULL)
{
UT_LOG_ERROR("Failed to emit YAML document\n");
return NULL;
}
return kvp_yaml_output;
}

/** Static Functions */
static ut_kvp_instance_internal_t *validateInstance(ut_kvp_instance_t *pInstance)
{
Expand Down
2 changes: 1 addition & 1 deletion tests/src/ut_test_control_plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ void run_client_function()
UT_LOG("Please Run the command `./python-client-send-json.py or/& ./python-client-send-yaml.py` from another terminal and press return;'\n");
UT_LOG("In order to pass the test you need to run each of the python scripts'\n");
#else
UT_LOG("Please Run the command `./curl-client-json.sh or/& ./curl-client-yaml.sh or/& ./curl-client-binary.sh` from another terminal and press return;'\n");
UT_LOG("Please Run the command `./curl-requests-script.sh` or `test_script_for_curl_request.sh` from another terminal and press return;'\n");
UT_LOG("In order to pass the test you need to run each of the curl scripts'\n");
#endif

Expand Down
Loading