cancel
Showing results for 
Search instead for 
Did you mean: 

nucleo 67w61m1 issues sending binary data (including 0x00)

_rk_
Associate II

 

Hey,

I’m currently working with the X-CUBE-ST67W61 Expansion Software Package and the Nucleo-W67x61 board and I am trying to perform an HTTP POST request that sends binary data. For this purpose, I’m using W6X_HTTP_Client_Request together with the content type W6X_HTTP_CONTENT_TYPE_OCTET_STREAM.

The payload I want to transmit contains arbitrary bytes, including 0x00. However, I’ve encountered a problem: as soon as the payload includes a null byte, the HTTP request body seems to be truncated exactly at that point. The server only receives the bytes up to the first 0x00, not the complete buffer. This strongly suggests that the underlying implementation treats the payload as a C-string and therefore stops processing at the first null terminator.

 

I would like to ask whether this is expected behavior or whether it may be a limitation or bug in the current implementation of the HTTP client. Does W6X_HTTP_Client_Request support sending binary payloads that may contain null bytes or do i need to send my data in ascii?

 

int32_t http_post_binary_example(void){
ip_addr_t addr = {0};
W6X_HTTP_connection_t settings = {0};
uint8_t server_ip[4] = {192, 0, 2, 1};

const char *method = "POST";
char server_name[] = "example.local";
char uri[] = "/api/echo";
uint16_t port = 11001;

addr.u_addr.ip4 = ATON_R(server_ip);

settings.https_certificate = NULL;
settings.https_certificate_len = 0;
settings.server_name = server_name;
settings.recv_fn = HTTPS_recv_cb_test;

uint8_t bin_payload[6] = { 0x10, 0x00, 0x33, 0x34, 0x35, 0x36 };

W6X_HTTP_Post_Data_t postData = {0};
postData.data = bin_payload;
postData.type = W6X_HTTP_CONTENT_TYPE_OCTET_STREAM;

W6X_Status_t ret = W6X_HTTP_Client_Request(
&addr,
port,
uri,
method,
(const void *)&postData,
sizeof(bin_payload),
NULL, NULL,
NULL, NULL,
&settings
);

if (ret != W6X_STATUS_OK) {
LogError("HTTP request failed\n");
return -1;
}

return 0;
}

 


Edited to apply source code formatting - please see How to insert source code for future reference.

1 ACCEPTED SOLUTION

Accepted Solutions
EPASZ.1
ST Employee

Hello,

as you have correctly deduced, the driver is designed to work with strings. This is based on the underlying protocol (host MCU <-> NCP) using string AT commands over SPI. This leads to the natural choice to use C string methods while handling the buffers in the upper layers.

You can, of course, modify the driver / Middleware layer to reflect your actual application needs - on the lowest SPI level, this limitation is not present (the driver simply sends a byte buffer with set length). This might be time-consuming. The simpler choice (in my opinion) would be to define a sort of escape character which would not contain 0x00 directly, but the HTTP server would know to parse it as a zero. Alternatively, you can send the data as ASCII - with an increase in the total amount of data that is transmitted, of course.

View solution in original post

4 REPLIES 4
EPASZ.1
ST Employee

Hello,

as you have correctly deduced, the driver is designed to work with strings. This is based on the underlying protocol (host MCU <-> NCP) using string AT commands over SPI. This leads to the natural choice to use C string methods while handling the buffers in the upper layers.

You can, of course, modify the driver / Middleware layer to reflect your actual application needs - on the lowest SPI level, this limitation is not present (the driver simply sends a byte buffer with set length). This might be time-consuming. The simpler choice (in my opinion) would be to define a sort of escape character which would not contain 0x00 directly, but the HTTP server would know to parse it as a zero. Alternatively, you can send the data as ASCII - with an increase in the total amount of data that is transmitted, of course.

Andrew Neil
Super User

HTTP is text-based.

AIUI, the application/octet-stream content type doesn't allow you to just put arbitrary binary data into HTTP - you would have to encode it; eg, using Base64 encoding ?

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

The HTTP body can contain arbitrary binary data, and application/octet-stream is explicitly defined for that purpose. You don’t need Base64 unless the implementation you’re usingonly supports text payloads. Modem vendors allow sending raw binary without any encoding, which is fully compliant with the HTTP spec.

_rk_
Associate II

I found a simple solution to fix the issue in w6x_http.c. The key is to change how the request buffer is prepared, so that binary POST data (which may contain 0x00 bytes) is handled correctly.

Instead of using snprintf to write both the header and the body into the buffer, you generate the HTTP header normally as a text string, and then append the binary payload using memcpy(). This avoids any premature termination caused by null bytes inside the POST data.

Here is the working approach:

  • Build the HTTP header using snprintf

  • Copy the binary POST body into the buffer after the header

  • Set the final request length accordingly

 

#define HTTPC_REQ_POST_PUT_11_HEADER_ONLY                                              \
  "%s %s HTTP/1.1\r\n"                                                                 \
  "User-Agent: %s\r\n"              /* User-Agent */                                   \
  "Accept: */*\r\n"                                                                    \
  "Accept-Encoding: deflate, gzip\r\n"                                                 \
  "Host: %s\r\n"                                                                       \
  "Content-Type: %s\r\n"                                                               \
  "Content-Length: %d\r\n"                                                             \
  "Connection: keep-alive"          /* we don't support persistent connections, yet */ \
	"\r\n\r\n"

 

  else if (strncmp(Obj->method, "POST", 4) == 0)
  {
  	
    method = W6X_HTTP_REQ_TYPE_POST;
    int header_len;
    
    /* Get the length of the HTTP request */
    req_len = strlen(HTTPC_REQ_POST_PUT_11_HEADER_ONLY)
              + strlen(Obj->uri)
              + strlen(Obj->method)
              + strlen(W6X_HTTP_CLIENT_AGENT)
              + strlen(host_name)
              + strlen(content_type)
              + Obj->post_data_len;

    /* Allocate dynamically the HTTP request based on previous result */
    req_buffer = pvPortMalloc(req_len);
    if (req_buffer == NULL)
    {
      goto _err;
    }

    /* 1: prepare Header in req_buffer */
    header_len = snprintf((char *)req_buffer, req_len,
    											HTTPC_REQ_POST_PUT_11_HEADER_ONLY,
                          Obj->method,            /* %s */
                          Obj->uri,               /* %s */
                          W6X_HTTP_CLIENT_AGENT,  /* %s */
                          host_name,              /* %s */
                          content_type,           /* %s */
                          Obj->post_data_len);    /* %d */

    if (header_len < 0 || header_len >= req_len)
        goto _err;

    /* 2: put POST Body in req_buffer */
    memcpy((uint8_t*)req_buffer + header_len,
           Obj->post_data.data,
           Obj->post_data_len);

    /* 3: full length */
    req_len2 = header_len + Obj->post_data_len;
  }