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