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-2026 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.6.4
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))
69  {
71  }
72 
73  //Check if character is printable
74  if(isprint(c) && c <= 126)
75  {
77  }
78 
79  //Check if character is blank
80  if(c == ' ' || c == '\t')
81  {
83  }
84 
85  //Check if character is alphabetic
86  if(isalpha(c))
87  {
89  }
90 
91  //Check if character is decimal digit
92  if(osIsdigit(c))
93  {
95  }
96 
97  //Check if character is hexadecimal digit
98  if(isxdigit(c))
99  {
100  m |= HTTP_CHARSET_HEX;
101  }
102 
103  //Check if character is in the extended character set
104  if(c >= 128)
105  {
107  }
108 
109  //Check if character is a token character
110  if(osStrchr("!#$%&'*+-.^_`|~", c))
111  {
113  }
114 
115  //Invalid character?
116  if((m & charset) == 0)
117  {
118  error = ERROR_INVALID_SYNTAX;
119  }
120  }
121 
122  //Return status code
123  return error;
124 }
125 
126 
127 /**
128  * @brief Parse a list of parameters
129  * @param[in,out] pos Actual position if the list of parameters
130  * @param[out] param Structure that contains the parameter name and value
131  * @return Error code
132  **/
133 
135 {
136  error_t error;
137  size_t i;
138  uint8_t c;
139  bool_t escapeFlag;
140  bool_t separatorFound;
141  const char_t *p;
142 
143  //Check parameters
144  if(pos == NULL || param == NULL)
146 
147  //Initialize structure
148  param->name = NULL;
149  param->nameLen = 0;
150  param->value = NULL;
151  param->valueLen = 0;
152 
153  //Initialize variables
154  escapeFlag = FALSE;
155  separatorFound = FALSE;
156 
157  //Initialize status code
158  error = ERROR_IN_PROGRESS;
159 
160  //Point to the first character
161  i = 0;
162  p = *pos;
163 
164  //Loop through the list of parameters
165  while(error == ERROR_IN_PROGRESS)
166  {
167  //Get current character
168  c = (uint8_t) p[i];
169 
170  //Check current state
171  if(param->name == NULL)
172  {
173  //Check current character
174  if(c == '\0')
175  {
176  //The list of parameters is empty
177  error = ERROR_NOT_FOUND;
178  }
179  else if(c == ' ' || c == '\t' || c == ',' || c == ';')
180  {
181  //Discard whitespace and separator characters
182  }
183  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
184  {
185  //Point to the first character of the parameter name
186  param->name = p + i;
187  }
188  else
189  {
190  //Invalid character
191  error = ERROR_INVALID_SYNTAX;
192  }
193  }
194  else if(param->nameLen == 0)
195  {
196  //Check current character
197  if(c == '\0' || c == ',' || c == ';')
198  {
199  //Save the length of the parameter name
200  param->nameLen = p + i - param->name;
201  //Successful processing
202  error = NO_ERROR;
203  }
204  else if(c == ' ' || c == '\t')
205  {
206  //Save the length of the parameter name
207  param->nameLen = p + i - param->name;
208  }
209  else if(c == '=')
210  {
211  //The key/value separator has been found
212  separatorFound = TRUE;
213  //Save the length of the parameter name
214  param->nameLen = p + i - param->name;
215  }
216  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
217  {
218  //Advance data pointer
219  }
220  else
221  {
222  //Invalid character
223  error = ERROR_INVALID_SYNTAX;
224  }
225  }
226  else if(!separatorFound)
227  {
228  //Check current character
229  if(c == '\0' || c == ',' || c == ';')
230  {
231  //Successful processing
232  error = NO_ERROR;
233  }
234  else if(c == ' ' || c == '\t')
235  {
236  //Discard whitespace characters
237  }
238  else if(c == '=')
239  {
240  //The key/value separator has been found
241  separatorFound = TRUE;
242  }
243  else if(c == '\"')
244  {
245  //Point to the first character that follows the parameter name
246  i = param->name + param->nameLen - p;
247  //Successful processing
248  error = NO_ERROR;
249  }
250  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
251  {
252  //Point to the first character that follows the parameter name
253  i = param->name + param->nameLen - p;
254  //Successful processing
255  error = NO_ERROR;
256  }
257  else
258  {
259  //Invalid character
260  error = ERROR_INVALID_SYNTAX;
261  }
262  }
263  else if(param->value == NULL)
264  {
265  //Check current character
266  if(c == '\0' || c == ',' || c == ';')
267  {
268  //Successful processing
269  error = NO_ERROR;
270  }
271  else if(c == ' ' || c == '\t')
272  {
273  //Discard whitespace characters
274  }
275  else if(c == '\"')
276  {
277  //A string of text is parsed as a single word if it is quoted
278  //using double-quote marks (refer to RFC 7230, section 3.2.6)
279  param->value = p + i;
280  }
281  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
282  {
283  //Point to the first character of the parameter value
284  param->value = p + i;
285  }
286  else
287  {
288  //Invalid character
289  error = ERROR_INVALID_SYNTAX;
290  }
291  }
292  else
293  {
294  //Quoted string?
295  if(param->value[0] == '\"')
296  {
297  //Check current character
298  if(c == '\0')
299  {
300  //The second double quote is missing
301  error = ERROR_INVALID_SYNTAX;
302  }
303  else if(escapeFlag)
304  {
305  //Recipients that process the value of a quoted-string must
306  //handle a quoted-pair as if it were replaced by the octet
307  //following the backslash
308  escapeFlag = FALSE;
309  }
310  else if(c == '\\')
311  {
312  //The backslash octet can be used as a single-octet quoting
313  //mechanism within quoted-string and comment constructs
314  escapeFlag = TRUE;
315  }
316  else if(c == '\"')
317  {
318  //Advance pointer over the double quote
319  i++;
320  //Save the length of the parameter value
321  param->valueLen = p + i - param->value;
322  //Successful processing
323  error = NO_ERROR;
324  }
325  else if(isprint(c) || c == '\t' || c >= 128)
326  {
327  //Advance data pointer
328  }
329  else
330  {
331  //Invalid character
332  error = ERROR_INVALID_SYNTAX;
333  }
334  }
335  else
336  {
337  //Check current character
338  if(c == '\0' || c == ' ' || c == '\t' || c == ',' || c == ';')
339  {
340  //Save the length of the parameter value
341  param->valueLen = p + i - param->value;
342  //Successful processing
343  error = NO_ERROR;
344  }
345  else if(isalnum(c) || osStrchr("!#$%&'*+-.^_`|~", c) != NULL || c >= 128)
346  {
347  //Advance data pointer
348  }
349  else
350  {
351  //Invalid character
352  error = ERROR_INVALID_SYNTAX;
353  }
354  }
355  }
356 
357  //Point to the next character of the string
358  if(error == ERROR_IN_PROGRESS)
359  {
360  i++;
361  }
362  }
363 
364  //Check whether the parameter value is a quoted string
365  if(param->valueLen >= 2 && param->value[0] == '\"')
366  {
367  //Discard the surrounding quotes
368  param->value++;
369  param->valueLen -= 2;
370  }
371 
372  //Actual position if the list of parameters
373  *pos = p + i;
374 
375  //Return status code
376  return error;
377 }
378 
379 
380 /**
381  * @brief Compare parameter name with the supplied string
382  * @param[in] param Pointer to the parameter
383  * @param[in] name NULL-terminated string
384  * @return Comparison result
385  **/
386 
388 {
389  bool_t res;
390  size_t n;
391 
392  //Initialize flag
393  res = FALSE;
394 
395  //Determine the length of the string
396  n = osStrlen(name);
397 
398  //Check the length of the parameter name
399  if(param->name != NULL && param->nameLen == n)
400  {
401  //Compare names
402  if(osStrncasecmp(param->name, name, n) == 0)
403  {
404  res = TRUE;
405  }
406  }
407 
408  //Return comparison result
409  return res;
410 }
411 
412 
413 /**
414  * @brief Compare parameter name with the supplied string
415  * @param[in] param Pointer to the parameter
416  * @param[in] value NULL-terminated string
417  * @return Comparison result
418  **/
419 
421 {
422  bool_t res;
423  size_t n;
424 
425  //Initialize flag
426  res = FALSE;
427 
428  //Determine the length of the string
429  n = osStrlen(value);
430 
431  //Check the length of the parameter value
432  if(param->value != NULL && param->valueLen == n)
433  {
434  //Perform case-insensitive comparison
435  if(osStrncasecmp(param->value, value, n) == 0)
436  {
437  res = TRUE;
438  }
439  }
440 
441  //Return comparison result
442  return res;
443 }
444 
445 
446 /**
447  * @brief Copy the value of a parameter
448  * @param[in] param Pointer to the parameter
449  * @param[out] value Pointer to the buffer where to copy the parameter value
450  * @param[out] maxLen Maximum number of characters the buffer can hold
451  * @return Error code
452  **/
453 
455  size_t maxLen)
456 {
457  error_t error;
458  size_t n;
459 
460  //Initialize status code
461  error = NO_ERROR;
462 
463  //Check the length of the parameter value
464  if(param->valueLen <= maxLen)
465  {
466  //Get the length of the string
467  n = param->valueLen;
468  }
469  else
470  {
471  //Limit the number of characters to copy
472  n = maxLen;
473  //Report an error
474  error = ERROR_BUFFER_OVERFLOW;
475  }
476 
477  //Copy the value of the parameter
478  osMemcpy(value, param->value, n);
479  //Properly terminate the string with a NULL character
480  value[n] = '\0';
481 
482  //Return status code
483  return error;
484 }
485 
486 
487 /**
488  * @brief Convert byte array to hex string
489  * @param[in] input Point to the byte array
490  * @param[in] inputLen Length of the byte array
491  * @param[out] output NULL-terminated string resulting from the conversion
492  **/
493 
494 void httpEncodeHexString(const uint8_t *input, size_t inputLen, char_t *output)
495 {
496  int_t i;
497 
498  //Hex conversion table
499  static const char_t hexDigit[16] =
500  {
501  '0', '1', '2', '3', '4', '5', '6', '7',
502  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
503  };
504 
505  //Process byte array
506  for(i = inputLen - 1; i >= 0; i--)
507  {
508  //Convert lower nibble
509  output[i * 2 + 1] = hexDigit[input[i] & 0x0F];
510  //Then convert upper nibble
511  output[i * 2] = hexDigit[(input[i] >> 4) & 0x0F];
512  }
513 
514  //Properly terminate the string with a NULL character
515  output[inputLen * 2] = '\0';
516 }
@ HTTP_CHARSET_DIGIT
Definition: http_common.h:143
#define osStrchr(s, c)
Definition: os_port.h:201
int bool_t
Definition: compiler_port.h:63
@ 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:454
#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:494
char_t name[]
#define osStrlen(s)
Definition: os_port.h:171
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:387
bool_t httpCompareParamValue(const HttpParam *param, const char_t *value)
Compare parameter name with the supplied string.
Definition: http_common.c:420
@ 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:195
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
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:291
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:134
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.