Get header value in c++ - Smart pointer (http)

Gitprodenv
Posts: 12
Joined: Mon Jun 06, 2022 1:32 pm

Get header value in c++ - Smart pointer (http)

Postby Gitprodenv » Wed Jul 20, 2022 8:23 am

I'm working in c++ and I have a small question of how to write the `get_header` method in the http protocol.

I want to create a small helper function

Code: Select all

/**
* @param [in] req
* @param [in] key The header key on which we want the value back
* @param [out] buf The header value written to.
**/
esp_err_t get_header(httpd_req_t *req, const char *key, char *buf) {
  size_t buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
  if (buf_len > 1) {
    buf = new char[buf_len];
    if (!buf) {
       ESP_LOGE(TAG, "No enough memory for basic authorization");
       return ESP_ERR_NO_MEM;
    }        
    return  httpd_req_get_hdr_value_str(req, key, buf, buf_len);  
  }
  return ESP_ERR_NOT_FOUND ;
}
I want to just use it as

Code: Select all

char *header_value{nullptr}; 
esp_err_t status = get_header(req, "Authorization", header_value);
// use it outside
if (header_value ..... // makes a condition on the header value
But preferably as a smart pointer such that it will free up the resources automatically instead of calling delete manually every time, which could be prone to human errors.
Or as a sd::string. Whatever is more performant.

Thanks for your help.

ESP_jakob
Posts: 49
Joined: Mon Jun 01, 2020 6:28 am

Re: Get header value in c++ - Smart pointer (http)

Postby ESP_jakob » Fri Jul 22, 2022 3:43 am

You have several options. You can just wrap the buffer created by new into a smart pointer and return it. You can also use an std::string, but then you need to allocate twice (once for passing a char pointer to the http method, once to allocate the actual std::string to which you'll copy the data). You can also use std::array<char> and return that. Obviously, you need to take care of the null character at the end then.

Some comments about the code:
1. It'll not return the buffer with the string, see 2.:
2. It will leak memory because buf is a pointer and you're only overwriting the local argument. Returning a pointer via arguments is done using pointer-to-pointer (i.e., char **buf), then accessing the object behind the pointer (i.e, *buf = ...).
3. The new in your code will throw an exception in case of insufficient memory. The check afterwards will never be reached. If you want an exception-free new, you need to use the (std::nothrow) overload.
4. If you are able to use exceptions AND you only expect ESP_ERR_NOT_FOUND for error conditions, e.g. only if there is wrong user input, then you can also return the smart pointer and throw exceptions in case of an error. You'll have a cleaner function interface.

Gitprodenv
Posts: 12
Joined: Mon Jun 06, 2022 1:32 pm

Re: Get header value in c++ - Smart pointer (http)

Postby Gitprodenv » Mon Jul 25, 2022 4:13 pm

Thank you @ESP_jakob,

you gave me valuable hints. A big thank you. Memory leaks :twisted: :twisted:

I now implemented two different versions. One with a raw pointer (which you have delete manually) and the other with a std::string. Based on my C++ knowledge I'm not quite sure if I can implement your other suggested variants.

1. Raw pointer approach

Code: Select all

/**
* @param [in] req
* @param [in] key The header key on which we want the value back
* @param [out] buf The header value written to.
**/
esp_err_t get_header(httpd_req_t *req, const char *key, char **buf) {
  size_t buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
  if (buf_len > 1) {
    *buf = new(std::nothrow) char[buf_len];
    if (!(*buf)) {
       ESP_LOGE(TAG, "No enough memory for basic authorization");
       return ESP_ERR_NO_MEM;
    }        
    return httpd_req_get_hdr_value_str(req, key, *buf, buf_len);  
  }
  return ESP_ERR_NOT_FOUND ;
}
2. Std::string approach

Code: Select all

/**
 * @brief Struct returning the status and value of the returned header.
 * 
 * @param err esp_err_t 
 *   - ESP_OK - Everything is ok, the header value could be found.
 *   - ESP_ERR_NO_MEM
 *   - ESP_ERR_NOT_FOUND
 * @param res The return value of the header. Empty if the header could not
 *            be found. 
 */
struct get_header_res {
    esp_err_t status; 
    std::string res;
};

/**
* @param [in] req
* @param [in] key The header key on which we want the value back
**/
get_header_res get_header(httpd_req_t *req, const char *key) {
  size_t buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
  std::string header_value;

  esp_err_t status{ESP_OK};
  if (buf_len > 1) {      
    status = httpd_req_get_hdr_value_str(req, key, header_value.c_str(), buf_len);  
  } else {
    status = ESP_ERR_NOT_FOUND;
  }  
  
  return { status, std::move(header_value) };
}

Code: Select all

get_header_res header_value_res = get_header(req, "Authorization");

if (ESP_OK == header_value_res.status) {
	std::string header_value = header_value_res.res;
	....
}

Who is online

Users browsing this forum: Bing [Bot] and 96 guests