util.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright (c) 2023 Markus Hennecke <markus-hennecke@markus-hennecke.de>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <sys/types.h>
  17. #include <ctype.h>
  18. #include <stdarg.h>
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #include <kcgi.h>
  24. #include "util.h"
  25. #include <stdio.h>
  26. #define TS_PARSE_FMT "%FT%T%z"
  27. /*
  28. * Check a timestamp formed like
  29. * YYYY-MM-DDTHH:MM(:SS)?(.msec)?(+[0-9]{2}:[0-9]{2}|Z)?
  30. */
  31. int
  32. validate_timestamp(struct kpair *_kp)
  33. {
  34. /* At least 10 characters requiered for a timestamp */
  35. if (_kp->valsz < 10)
  36. return 0;
  37. /* Check for date only if the strlen is 10 */
  38. if (_kp->valsz == 10)
  39. return kvalid_date(_kp);
  40. /* Between 10 and 16 characters can't be avalid timestamp */
  41. /* Next minimal timestamp has 16 characters */
  42. if (_kp->valsz < 16)
  43. return 0;
  44. /* Could be a timestamp with timezone, don't parse it by hand but
  45. * use strptime instead */
  46. if (_kp->valsz >= 20) {
  47. if (_kp->valsz != strlen(_kp->val))
  48. return 0;
  49. struct tm tm;
  50. char *parse_end = strptime(_kp->val, TS_PARSE_FMT, &tm);
  51. if (parse_end == NULL || *parse_end != '\0')
  52. return 0;
  53. fprintf(stderr, "tm_gmtoff = %ld\n", tm.tm_gmtoff);
  54. _kp->parsed.i = (int64_t )timegm(&tm) - tm.tm_gmtoff;
  55. _kp->type = KPAIR_INTEGER;
  56. return 1;
  57. }
  58. if (!isdigit(_kp->val[0]) ||
  59. !isdigit(_kp->val[1]) ||
  60. !isdigit(_kp->val[2]) ||
  61. !isdigit(_kp->val[3]) ||
  62. ('-' != _kp->val[4]) ||
  63. !isdigit(_kp->val[5]) ||
  64. !isdigit(_kp->val[6]) ||
  65. ('-' != _kp->val[7]) ||
  66. !isdigit(_kp->val[8]) ||
  67. !isdigit(_kp->val[9]) ||
  68. ('T' != _kp->val[10]) ||
  69. !isdigit(_kp->val[11]) ||
  70. !isdigit(_kp->val[12]) ||
  71. (':' != _kp->val[13]) ||
  72. !isdigit(_kp->val[14]) ||
  73. !isdigit(_kp->val[15]))
  74. return 0;
  75. if ((_kp->valsz == 16) && ('\0' != _kp->val[16]))
  76. return 0;
  77. const int year = atoi(&_kp->val[0]);
  78. const int month = atoi(&_kp->val[5]);
  79. const int day = atoi(&_kp->val[8]);
  80. const int hour = atoi(&_kp->val[11]);
  81. const int minute = atoi(&_kp->val[14]);
  82. int seconds = 0;
  83. if (_kp->valsz >= 19) {
  84. if ((':' != _kp->val[16]) ||
  85. !isdigit(_kp->val[17]) ||
  86. !isdigit(_kp->val[18]))
  87. return 0;
  88. if ((_kp->valsz == 19) && ('\0' != _kp->val[19]))
  89. return 0;
  90. seconds = atoi(&_kp->val[17]);
  91. }
  92. if (! khttp_datetime2epoch(&_kp->parsed.i, day, month, year, hour,
  93. minute, seconds))
  94. return 0;
  95. _kp->type = KPAIR_INTEGER;
  96. return 1;
  97. }
  98. /*
  99. * Check the device ID to fit into 36 characters, e.g. it is a UUID or an
  100. * ID string.
  101. */
  102. int
  103. validate_device(struct kpair *_kp)
  104. {
  105. if (_kp->valsz > 36)
  106. return 0;
  107. // XXX change this to kvalid_stringne if it becomes mandatory
  108. return kvalid_string(_kp);
  109. }
  110. const char *
  111. parameter(struct kreq *r, const int param_idx)
  112. {
  113. return (r->fieldmap[param_idx]) ? r->fieldmap[param_idx]->val : NULL;
  114. }
  115. void
  116. response(struct kreq *r, const int status, const int content_type,
  117. const char *body) {
  118. khttp_head(r, kresps[KRESP_STATUS], "%s", khttps[status]);
  119. khttp_head(r, kresps[KRESP_CONTENT_TYPE],
  120. "%s", kmimetypes[content_type]);
  121. khttp_body(r);
  122. if (body)
  123. khttp_puts(r, body);
  124. }