2121#include "wolfip.h"
2222#include "httpd.h"
2323#include <ctype.h>
24+ #include <string.h>
2425
2526static const char * http_status_text (int status_code ) {
2627 switch (status_code ) {
@@ -187,7 +188,6 @@ void http_send_response_chunk_end(struct http_client *hc) {
187188 hc -> ssl = NULL ;
188189 wolfIP_sock_close (hc -> httpd -> ipstack , hc -> client_sd );
189190 hc -> client_sd = 0 ;
190- return ;
191191 }
192192 } else {
193193 if (wolfIP_sock_send (hc -> httpd -> ipstack , hc -> client_sd , "0\r\n\r\n" , 5 , 0 ) <= 0 ) {
@@ -217,27 +217,47 @@ void http_send_418_teapot(struct http_client *hc) {
217217 http_status_text (HTTP_STATUS_TEAPOT ), "text/plain" , 0 );
218218}
219219
220- int http_url_decode (char * buf , size_t len ) {
220+ static int http_hex_value (char c )
221+ {
222+ if (c >= '0' && c <= '9' )
223+ return c - '0' ;
224+ c = (char )tolower ((unsigned char )c );
225+ if (c >= 'a' && c <= 'f' )
226+ return 10 + (c - 'a' );
227+ return -1 ;
228+ }
229+
230+ int http_url_decode (char * buf , size_t len )
231+ {
221232 char * p = buf ;
222- char * q ;
223- while (p < buf + len ) {
224- q = strchr (p , '%' );
225- if (!q ) {
226- break ;
227- }
228- /* Ensure we have two more hex digits */
229- if (q + 2 >= buf + len ) {
230- break ; /* Malformed escape */
231- }
232- /* Validate hex characters before conversion */
233- if (!isxdigit ((unsigned char )q [1 ]) || !isxdigit ((unsigned char )q [2 ])) {
233+ char * end = buf + len ;
234+ int hi ;
235+ int lo ;
236+ size_t tail ;
237+
238+ while (p < end ) {
239+ char * percent = memchr (p , '%' , (size_t )(end - p ));
240+ if (!percent )
234241 break ;
235- }
236- * q = (char ) strtol (q + 1 , NULL , 16 );
237- memmove (q + 1 , q + 3 , len - (q + 3 - buf ));
242+
243+ if (percent + 2 >= end )
244+ return HTTP_URL_DECODE_ERR_TRUNCATED ;
245+
246+ hi = http_hex_value (percent [1 ]);
247+ lo = http_hex_value (percent [2 ]);
248+ if (hi < 0 || lo < 0 )
249+ return HTTP_URL_DECODE_ERR_BAD_ESCAPE ;
250+
251+ * percent = (char )((hi << 4 ) | lo );
252+
253+ tail = (size_t )(end - (percent + 3 ));
254+ memmove (percent + 1 , percent + 3 , tail );
255+ end -= 2 ;
238256 len -= 2 ;
257+ p = percent + 1 ;
239258 }
240- return len ;
259+
260+ return (int )len ;
241261}
242262
243263int http_url_encode (char * buf , size_t len , size_t max_len ) {
@@ -258,8 +278,11 @@ int http_url_encode(char *buf, size_t len, size_t max_len) {
258278 * (q + 2 ) = '0' ;
259279 len += 2 ;
260280 }
261- if (q && (len < max_len ))
281+ if (q ) {
282+ if (len >= max_len )
283+ return -1 ; /* No space for the null terminator */
262284 q [len ] = '\0' ;
285+ }
263286 return len ;
264287}
265288
@@ -269,10 +292,18 @@ static int parse_http_request(struct http_client *hc, uint8_t *buf, size_t len)
269292 char * q ;
270293 size_t n ;
271294 int ret ;
295+ int decoded_len ;
272296 struct http_request req ;
273297 struct http_url * url = NULL ;
274298 memset (& req , 0 , sizeof (struct http_request ));
275- http_url_decode (p , len ); /* Decode can be done in place */
299+ decoded_len = http_url_decode (p , len ); /* Decode can be done in place */
300+ if (decoded_len < 0 ) {
301+ http_send_response_headers (hc , HTTP_STATUS_BAD_REQUEST ,
302+ http_status_text (HTTP_STATUS_BAD_REQUEST ), "text/plain" , 0 );
303+ return decoded_len ;
304+ }
305+ len = (size_t )decoded_len ;
306+ end = p + len ;
276307 if (len < 4 )
277308 goto bad_request ;
278309 /* Parse the request line */
0 commit comments