http_common.c
Go to the documentation of this file.
1 /**
2  * @file http_common.c
3  * @brief Definitions common to HTTP client and server
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL HTTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "http/http_common.h"
37 #include "debug.h"
38 
39 
40 /**
41  * @brief Check whether a string contains valid characters
42  * @param[in] s Pointer to the string
43  * @param[in] length Length of the string
44  * @param[in] charset Acceptable charset
45  * @return Error code
46  **/
47 
48 error_t httpCheckCharset(const char_t *s, size_t length, uint_t charset)
49 {
50  error_t error;
51  size_t i;
52  uint8_t c;
53  uint_t m;
54 
55  //Initialize status code
56  error = NO_ERROR;
57 
58  //Parse string
59  for(i = 0; i < length; i++)
60  {
61  //Get current character
62  c = (uint8_t) s[i];
63 
64  //Any 8-bit sequence of data
66 
67  //Check if character is a control character
68  if(iscntrl(c))
70 
71  //Check if character is printable
72  if(isprint(c) && c <= 126)
74 
75  //Check if character is blank
76  if(c == ' ' || c == '\t')
78 
79  //Check if character is alphabetic
80  if(isalpha(c))
82 
83  //Check if character is decimal digit
84  if(osIsdigit(c))
86 
87  //Check if character is hexadecimal digit
88  if(isxdigit(c))
90 
91  //Check if character is in the extended character set
92  if(c >= 128)
94 
95  //Check if character is a token character
96  if(osStrchr("!#$%&'*+-.^_`|~", c))
98 
99  //Invalid character?
100  if((m & charset) == 0)
101  error = ERROR_INVALID_SYNTAX;
102  }
103 
104  //Return status code
105  return error;
106 }
107 
108 
109 /**
110  * @brief Parse a list of parameters
111  * @param[in,out] pos Actual position if the list of parameters
112  * @param[out] param Structure that contains the parameter name and value
113  * @return Error code
114  **/
115 
117 {
118  error_t error;
119  size_t i;
120  uint8_t c;
121  bool_t escapeFlag;
122  bool_t separatorFound;
123  const char_t *p;
124 
125  //Check parameters
126  if(pos == NULL || param == NULL)
128 
129  //Initialize structure
130  param->name = NULL;
131  param->nameLen = 0;
132  param->value = NULL;
133  param->valueLen = 0;
134 
135  //Initialize variables
136  escapeFlag = FALSE;
137  separatorFound = FALSE;
138 
139  //Initialize status code
140  error = ERROR_IN_PROGRESS;
141 
142  //Point to the first character
143  i = 0;
144  p = *pos;
145 
146  //Loop through the list of parameters
147  while(error == ERROR_IN_PROGRESS)
148  {
149  //Get current character
150  c = (uint8_t) p[i];
151 
152  //Check current state
153  if(param->name == NULL)
154  {
155  //Check current character
156  if(c == '\0')
157  {
158  //The list of parameters is empty
159  error = ERROR_NOT_FOUND;
160  }
161  else if(c == ' ' || c == '\t' || c == ',' || c == ';')
162  {
163  //Discard whitespace and separator characters
164  }
165  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
166  {
167  //Point to the first character of the parameter name
168  param->name = p + i;
169  }
170  else
171  {
172  //Invalid character
173  error = ERROR_INVALID_SYNTAX;
174  }
175  }
176  else if(param->nameLen == 0)
177  {
178  //Check current character
179  if(c == '\0' || c == ',' || c == ';')
180  {
181  //Save the length of the parameter name
182  param->nameLen = p + i - param->name;
183  //Successful processing
184  error = NO_ERROR;
185  }
186  else if(c == ' ' || c == '\t')
187  {
188  //Save the length of the parameter name
189  param->nameLen = p + i - param->name;
190  }
191  else if(c == '=')
192  {
193  //The key/value separator has been found
194  separatorFound = TRUE;
195  //Save the length of the parameter name
196  param->nameLen = p + i - param->name;
197  }
198  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
199  {
200  //Advance data pointer
201  }
202  else
203  {
204  //Invalid character
205  error = ERROR_INVALID_SYNTAX;
206  }
207  }
208  else if(!separatorFound)
209  {
210  //Check current character
211  if(c == '\0' || c == ',' || c == ';')
212  {
213  //Successful processing
214  error = NO_ERROR;
215  }
216  else if(c == ' ' || c == '\t')
217  {
218  //Discard whitespace characters
219  }
220  else if(c == '=')
221  {
222  //The key/value separator has been found
223  separatorFound = TRUE;
224  }
225  else if(c == '\"')
226  {
227  //Point to the first character that follows the parameter name
228  i = param->name + param->nameLen - p;
229  //Successful processing
230  error = NO_ERROR;
231  }
232  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
233  {
234  //Point to the first character that follows the parameter name
235  i = param->name + param->nameLen - p;
236  //Successful processing
237  error = NO_ERROR;
238  }
239  else
240  {
241  //Invalid character
242  error = ERROR_INVALID_SYNTAX;
243  }
244  }
245  else if(param->value == NULL)
246  {
247  //Check current character
248  if(c == '\0' || c == ',' || c == ';')
249  {
250  //Successful processing
251  error = NO_ERROR;
252  }
253  else if(c == ' ' || c == '\t')
254  {
255  //Discard whitespace characters
256  }
257  else if(c == '\"')
258  {
259  //A string of text is parsed as a single word if it is quoted
260  //using double-quote marks (refer to RFC 7230, section 3.2.6)
261  param->value = p + i;
262  }
263  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
264  {
265  //Point to the first character of the parameter value
266  param->value = p + i;
267  }
268  else
269  {
270  //Invalid character
271  error = ERROR_INVALID_SYNTAX;
272  }
273  }
274  else
275  {
276  //Quoted string?
277  if(param->value[0] == '\"')
278  {
279  //Check current character
280  if(c == '\0')
281  {
282  //The second double quote is missing
283  error = ERROR_INVALID_SYNTAX;
284  }
285  else if(escapeFlag)
286  {
287  //Recipients that process the value of a quoted-string must
288  //handle a quoted-pair as if it were replaced by the octet
289  //following the backslash
290  escapeFlag = FALSE;
291  }
292  else if(c == '\\')
293  {
294  //The backslash octet can be used as a single-octet quoting
295  //mechanism within quoted-string and comment constructs
296  escapeFlag = TRUE;
297  }
298  else if(c == '\"')
299  {
300  //Advance pointer over the double quote
301  i++;
302  //Save the length of the parameter value
303  param->valueLen = p + i - param->value;
304  //Successful processing
305  error = NO_ERROR;
306  }
307  else if(isprint(c) || c == '\t' || c >= 128)
308  {
309  //Advance data pointer
310  }
311  else
312  {
313  //Invalid character
314  error = ERROR_INVALID_SYNTAX;
315  }
316  }
317  else
318  {
319  //Check current character
320  if(c == '\0' || c == ' ' || c == '\t' || c == ',' || c == ';')
321  {
322  //Save the length of the parameter value
323  param->valueLen = p + i - param->value;
324  //Successful processing
325  error = NO_ERROR;
326  }
327  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
328  {
329  //Advance data pointer
330  }
331  else
332  {
333  //Invalid character
334  error = ERROR_INVALID_SYNTAX;
335  }
336  }
337  }
338 
339  //Point to the next character of the string
340  if(error == ERROR_IN_PROGRESS)
341  i++;
342  }
343 
344  //Check whether the parameter value is a quoted string
345  if(param->valueLen >= 2 && param->value[0] == '\"')
346  {
347  //Discard the surrounding quotes
348  param->value++;
349  param->valueLen -= 2;
350  }
351 
352  //Actual position if the list of parameters
353  *pos = p + i;
354 
355  //Return status code
356  return error;
357 }
358 
359 
360 /**
361  * @brief Compare parameter name with the supplied string
362  * @param[in] param Pointer to the parameter
363  * @param[in] name NULL-terminated string
364  * @return Comparison result
365  **/
366 
368 {
369  bool_t res;
370  size_t n;
371 
372  //Initialize flag
373  res = FALSE;
374 
375  //Determine the length of the string
376  n = osStrlen(name);
377 
378  //Check the length of the parameter name
379  if(param->name != NULL && param->nameLen == n)
380  {
381  //Compare names
382  if(osStrncasecmp(param->name, name, n) == 0)
383  {
384  res = TRUE;
385  }
386  }
387 
388  //Return comparison result
389  return res;
390 }
391 
392 
393 /**
394  * @brief Compare parameter name with the supplied string
395  * @param[in] param Pointer to the parameter
396  * @param[in] value NULL-terminated string
397  * @return Comparison result
398  **/
399 
401 {
402  bool_t res;
403  size_t n;
404 
405  //Initialize flag
406  res = FALSE;
407 
408  //Determine the length of the string
409  n = osStrlen(value);
410 
411  //Check the length of the parameter value
412  if(param->value != NULL && param->valueLen == n)
413  {
414  //Perform case-insensitive comparison
415  if(osStrncasecmp(param->value, value, n) == 0)
416  {
417  res = TRUE;
418  }
419  }
420 
421  //Return comparison result
422  return res;
423 }
424 
425 
426 /**
427  * @brief Copy the value of a parameter
428  * @param[in] param Pointer to the parameter
429  * @param[out] value Pointer to the buffer where to copy the parameter value
430  * @param[out] maxLen Maximum number of characters the buffer can hold
431  * @return Error code
432  **/
433 
435  size_t maxLen)
436 {
437  error_t error;
438  size_t n;
439 
440  //Initialize status code
441  error = NO_ERROR;
442 
443  //Check the length of the parameter value
444  if(param->valueLen <= maxLen)
445  {
446  //Get the length of the string
447  n = param->valueLen;
448  }
449  else
450  {
451  //Limit the number of characters to copy
452  n = maxLen;
453  //Report an error
454  error = ERROR_BUFFER_OVERFLOW;
455  }
456 
457  //Copy the value of the parameter
458  osMemcpy(value, param->value, n);
459  //Properly terminate the string with a NULL character
460  value[n] = '\0';
461 
462  //Return status code
463  return error;
464 }
465 
466 
467 /**
468  * @brief Convert byte array to hex string
469  * @param[in] input Point to the byte array
470  * @param[in] inputLen Length of the byte array
471  * @param[out] output NULL-terminated string resulting from the conversion
472  **/
473 
474 void httpEncodeHexString(const uint8_t *input, size_t inputLen, char_t *output)
475 {
476  int_t i;
477 
478  //Hex conversion table
479  static const char_t hexDigit[16] =
480  {
481  '0', '1', '2', '3', '4', '5', '6', '7',
482  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
483  };
484 
485  //Process byte array
486  for(i = inputLen - 1; i >= 0; i--)
487  {
488  //Convert lower nibble
489  output[i * 2 + 1] = hexDigit[input[i] & 0x0F];
490  //Then convert upper nibble
491  output[i * 2] = hexDigit[(input[i] >> 4) & 0x0F];
492  }
493 
494  //Properly terminate the string with a NULL character
495  output[inputLen * 2] = '\0';
496 }
@ HTTP_CHARSET_DIGIT
Definition: http_common.h:143
#define osStrchr(s, c)
Definition: os_port.h:198
int bool_t
Definition: compiler_port.h:61
@ ERROR_NOT_FOUND
Definition: error.h:148
@ HTTP_CHARSET_HEX
Definition: http_common.h:144
signed int int_t
Definition: compiler_port.h:56
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:143
uint8_t p
Definition: ndp.h:300
error_t httpCopyParamValue(const HttpParam *param, char_t *value, size_t maxLen)
Copy the value of a parameter.
Definition: http_common.c:434
#define TRUE
Definition: os_port.h:50
void httpEncodeHexString(const uint8_t *input, size_t inputLen, char_t *output)
Convert byte array to hex string.
Definition: http_common.c:474
char_t name[]
#define osStrlen(s)
Definition: os_port.h:168
const uint8_t res[]
const char_t * value
Definition: http_common.h:160
@ HTTP_CHARSET_TCHAR
Definition: http_common.h:146
bool_t httpCompareParamName(const HttpParam *param, const char_t *name)
Compare parameter name with the supplied string.
Definition: http_common.c:367
bool_t httpCompareParamValue(const HttpParam *param, const char_t *value)
Compare parameter name with the supplied string.
Definition: http_common.c:400
@ ERROR_IN_PROGRESS
Definition: error.h:214
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osStrncasecmp(s1, s2, length)
Definition: os_port.h:192
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
const char_t * name
Definition: http_common.h:158
error_t
Error codes.
Definition: error.h:43
@ HTTP_CHARSET_OCTET
Definition: http_common.h:139
#define osIsdigit(c)
Definition: os_port.h:288
uint8_t length
Definition: tcp.h:375
@ HTTP_CHARSET_OBS_TEXT
Definition: http_common.h:148
@ HTTP_CHARSET_LWS
Definition: http_common.h:141
Definitions common to HTTP client and server.
Attribute-value pair.
Definition: http_common.h:157
char char_t
Definition: compiler_port.h:55
@ HTTP_CHARSET_ALPHA
Definition: http_common.h:142
uint8_t m
Definition: ndp.h:304
@ HTTP_CHARSET_VCHAR
Definition: http_common.h:145
uint8_t n
error_t httpCheckCharset(const char_t *s, size_t length, uint_t charset)
Check whether a string contains valid characters.
Definition: http_common.c:48
uint8_t value[]
Definition: tcp.h:376
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
uint8_t s
Definition: igmp_common.h:234
@ HTTP_CHARSET_CTL
Definition: http_common.h:140
size_t valueLen
Definition: http_common.h:161
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
@ HTTP_CHARSET_TEXT
Definition: http_common.h:147
size_t nameLen
Definition: http_common.h:159
error_t httpParseParam(const char_t **pos, HttpParam *param)
Parse a list of parameters.
Definition: http_common.c:116
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.