cancel
Showing results for 
Search instead for 
Did you mean: 

Need help with STM32F407 HTTPD POST function

Raymond Buck
Senior

I've been working with STM32F407 httpd POST for the last week. I've got everything with the POST working but I have one problem that I can't resolve. I don't know if it is a C problem or an LwIP problem, but I suspect it is LwIP.

I have code that I send to the POST functions that check the password that I enter on the login page. If the password matches the system password that is stored in EEPROM, I advance to the next web page of my app. If the password is incorrect, I simply return to the login page. That process works as designed as long as a good password and a bad password are the same length.

The POST function that handles the login is this:

err_t httpd_post_receive_data(void *connection, struct pbuf *p)
{
   p->payload holds the password when function is called
   password check code.
   at end of check code:
   pbuf_free(p);
}

Assume the good password is test123. I enter a bad password of test4567 which is one character longer than test123. I return to the login page and enter test123 and POST that to the server. The login fails and returns me to the login page. If I stop the debugger in the function after entering the good password I see p->payload now holds test1237 as the password. It appears pbuf_free(p) doesn't clear the payload buffer.

Completely closing the browser and re-opening it doesn't solve the issue. I am now blocked from logging into the board. However, if I use a different browser I can login. The only way to login from the first browser is to restart the board.

Has anyone had a similar problem? I believe very few people use the STM32 POST function since no one really understands how it works. Any suggestions on how to clear the p->payload part of the struct?

1 ACCEPTED SOLUTION

Accepted Solutions

After several days of testing, it turns out that this:

response_uri = 0; // this is needed to clear p->payload from previous call

is not the solution. It only works sometimes.

The actual solution is this:

char tmpval[48];
uint8_t x;
	
for(x = 0; x < p->tot_len; x++)
{
  strcpy(&tmpval[x], "0");
}
strcpy((char *)p, tmpval);
pbuf_free(p);
 
return ERR_OK;

This code should be placed at then end of the "err_t httpd_post_receive_data(void *connection, struct pbuf *p)" function.

I have tested it over 50 times and it never fails to clear the p->payload buffer.

View solution in original post

7 REPLIES 7

> It appears pbuf_free(p) doesn't clear the payload buffer.

Is it supposed to, according to accompanying documentation or to the source code (lwip is open source so you can debug it yourself)?

Is this in any way STM32-specific? You may want to ask at https://lists.nongnu.org/mailman/listinfo/lwip-users .

JW

Raymond Buck
Senior

Jan, according to the documentation pbuf_free(p) should clear the payload buffer. I guess I am going to have to dig into the LwIP code to try to find where they are supposed to be clearing the buffer.

It is specific to the STM32 as I believe ST made modifications to the LwIP code to enable STM32CubeIDE IOC tool to generate the code to work with the STM32F407. I was hoping someone else had seen a similar problem and found a solution.

Thanks for the link. I will join the mailing list and see if someone there has any ideas.

Raymond Buck
Senior

Jan, I found that if I added "response_uri = NULL;" to the httpd_post_begin function it clears the p->payload buffer. I can now enter an incorrect password which returns me to the login page. I then enter the correct password and the system logs me in.

err_t httpd_post_begin(void *connection, const char *uri, const char *http_request,
                       uint16_t http_request_len, int content_len, char *response_uri,
                       uint16_t response_uri_len, uint8_t *post_auto_wnd)
{
	response_uri = NULL;    // this is needed to clear p->payload from previous call.
	current_connection = connection; // p->payload is used in httpd_post_receive function
	valid_connection = connection;
	return ERR_OK;
}

Maybe this will help someone in the future.

So this is *the* solution? Thanks for coming back with it and please select your post as Best so that thread is marked as solved.

JW

After several days of testing, it turns out that this:

response_uri = 0; // this is needed to clear p->payload from previous call

is not the solution. It only works sometimes.

The actual solution is this:

char tmpval[48];
uint8_t x;
	
for(x = 0; x < p->tot_len; x++)
{
  strcpy(&tmpval[x], "0");
}
strcpy((char *)p, tmpval);
pbuf_free(p);
 
return ERR_OK;

This code should be placed at then end of the "err_t httpd_post_receive_data(void *connection, struct pbuf *p)" function.

I have tested it over 50 times and it never fails to clear the p->payload buffer.

>The actual solution is this

That is really not good code. x is uint8_t, p->tot_len is uint16_t, if p->tot_len > 255 the loop never ends, if p->tot_len > sizeof(tmpval) tmpval is overrun, strcpy should be memset and then no loop is required, after writing some number of '0's ('0' char, not '\0' zero) over tmpval and possibly beyond, its writing that to p and p is the pbuf, not the buffer.

>If the password matches <skip> advance to the next web page of my app. If the password is incorrect, I simply return to the login page

So why are you trying to clear the buffer? You're wanting to generate a POST response to indicate the password is good or another one to return to the login page.

>appears pbuf_free(p) doesn't clear the payload buffer

No and it shouldn't. It decrements the ref count and deallocates the pbuf if that's zero. No reason for it to clear a buffer, ever.

>That process works as designed as long as a good password and a bad password are the same length.

Check you're evaluating the Content-Length header of the HTTP POST response properly. Ref https://tools.ietf.org/html/rfc7230.

BTW httpd overwrites the CRLF of the last header of received POST requests. Ref https://savannah.nongnu.org/bugs/?58754.

alister, I have everything working.

Ref the uint8_t loop. The payload will never be over 12 characters long as I limit the length of the password. The reason I used the loop is because pbuf_free was not clearing the buffer. For instance if I had a password of test12345A and then I changed it to tess9876 and stopped the debugger to examine at the payload, it would show tess9876A. The loop was the only way I could get the payload to hold the actual data being sent.

Ref the POST comment. I decided not to use a POST response as I could never get it to work. I ended up checking the password within the code on the STM32.

I haven't found any LwIP documentation that indicates POST works. Everything I found said it was experimental. I looked at a couple of other ARM chip suppliers POST code. They all had their own implementation. I think I saw the same thing in the IAR Embedded Workbench IDE.