You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

http_util.c 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*-
  2. * Copyright 2019 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "libserver/http/http_util.h"
  17. #include "libutil/printf.h"
  18. #include "libutil/util.h"
  19. static const char *http_week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  20. static const char *http_month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  21. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  22. /*
  23. * Obtained from nginx
  24. * Copyright (C) Igor Sysoev
  25. */
  26. static unsigned int mday[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  27. time_t
  28. rspamd_http_parse_date(const char *header, gsize len)
  29. {
  30. const char *p, *end;
  31. int month;
  32. unsigned int day, year, hour, min, sec;
  33. uint64_t time;
  34. enum {
  35. no = 0,
  36. rfc822, /* Tue, 10 Nov 2002 23:50:13 */
  37. rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
  38. isoc /* Tue Dec 10 23:50:13 2002 */
  39. } fmt;
  40. fmt = 0;
  41. if (len > 0) {
  42. end = header + len;
  43. }
  44. else {
  45. end = header + strlen(header);
  46. }
  47. day = 32;
  48. year = 2038;
  49. for (p = header; p < end; p++) {
  50. if (*p == ',') {
  51. break;
  52. }
  53. if (*p == ' ') {
  54. fmt = isoc;
  55. break;
  56. }
  57. }
  58. for (p++; p < end; p++)
  59. if (*p != ' ') {
  60. break;
  61. }
  62. if (end - p < 18) {
  63. return (time_t) -1;
  64. }
  65. if (fmt != isoc) {
  66. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
  67. return (time_t) -1;
  68. }
  69. day = (*p - '0') * 10 + *(p + 1) - '0';
  70. p += 2;
  71. if (*p == ' ') {
  72. if (end - p < 18) {
  73. return (time_t) -1;
  74. }
  75. fmt = rfc822;
  76. }
  77. else if (*p == '-') {
  78. fmt = rfc850;
  79. }
  80. else {
  81. return (time_t) -1;
  82. }
  83. p++;
  84. }
  85. switch (*p) {
  86. case 'J':
  87. month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5
  88. : 6;
  89. break;
  90. case 'F':
  91. month = 1;
  92. break;
  93. case 'M':
  94. month = *(p + 2) == 'r' ? 2 : 4;
  95. break;
  96. case 'A':
  97. month = *(p + 1) == 'p' ? 3 : 7;
  98. break;
  99. case 'S':
  100. month = 8;
  101. break;
  102. case 'O':
  103. month = 9;
  104. break;
  105. case 'N':
  106. month = 10;
  107. break;
  108. case 'D':
  109. month = 11;
  110. break;
  111. default:
  112. return (time_t) -1;
  113. }
  114. p += 3;
  115. if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
  116. return (time_t) -1;
  117. }
  118. p++;
  119. if (fmt == rfc822) {
  120. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9' || *(p + 2) < '0' || *(p + 2) > '9' || *(p + 3) < '0' || *(p + 3) > '9') {
  121. return (time_t) -1;
  122. }
  123. year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
  124. p += 4;
  125. }
  126. else if (fmt == rfc850) {
  127. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
  128. return (time_t) -1;
  129. }
  130. year = (*p - '0') * 10 + *(p + 1) - '0';
  131. year += (year < 70) ? 2000 : 1900;
  132. p += 2;
  133. }
  134. if (fmt == isoc) {
  135. if (*p == ' ') {
  136. p++;
  137. }
  138. if (*p < '0' || *p > '9') {
  139. return (time_t) -1;
  140. }
  141. day = *p++ - '0';
  142. if (*p != ' ') {
  143. if (*p < '0' || *p > '9') {
  144. return (time_t) -1;
  145. }
  146. day = day * 10 + *p++ - '0';
  147. }
  148. if (end - p < 14) {
  149. return (time_t) -1;
  150. }
  151. }
  152. if (*p++ != ' ') {
  153. return (time_t) -1;
  154. }
  155. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
  156. return (time_t) -1;
  157. }
  158. hour = (*p - '0') * 10 + *(p + 1) - '0';
  159. p += 2;
  160. if (*p++ != ':') {
  161. return (time_t) -1;
  162. }
  163. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
  164. return (time_t) -1;
  165. }
  166. min = (*p - '0') * 10 + *(p + 1) - '0';
  167. p += 2;
  168. if (*p++ != ':') {
  169. return (time_t) -1;
  170. }
  171. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
  172. return (time_t) -1;
  173. }
  174. sec = (*p - '0') * 10 + *(p + 1) - '0';
  175. if (fmt == isoc) {
  176. p += 2;
  177. if (*p++ != ' ') {
  178. return (time_t) -1;
  179. }
  180. if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9' || *(p + 2) < '0' || *(p + 2) > '9' || *(p + 3) < '0' || *(p + 3) > '9') {
  181. return (time_t) -1;
  182. }
  183. year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
  184. }
  185. if (hour > 23 || min > 59 || sec > 59) {
  186. return (time_t) -1;
  187. }
  188. if (day == 29 && month == 1) {
  189. if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
  190. return (time_t) -1;
  191. }
  192. }
  193. else if (day > mday[month]) {
  194. return (time_t) -1;
  195. }
  196. /*
  197. * shift new year to March 1 and start months from 1 (not 0),
  198. * it is needed for Gauss' formula
  199. */
  200. if (--month <= 0) {
  201. month += 12;
  202. year -= 1;
  203. }
  204. /* Gauss' formula for Gregorian days since March 1, 1 BC */
  205. time = (uint64_t) (
  206. /* days in years including leap years since March 1, 1 BC */
  207. 365 * year + year / 4 - year / 100 + year / 400
  208. /* days before the month */
  209. + 367 * month / 12 - 30
  210. /* days before the day */
  211. + day - 1
  212. /*
  213. * 719527 days were between March 1, 1 BC and March 1, 1970,
  214. * 31 and 28 days were in January and February 1970
  215. */
  216. - 719527 + 31 + 28) *
  217. 86400 +
  218. hour * 3600 + min * 60 + sec;
  219. return (time_t) time;
  220. }
  221. glong rspamd_http_date_format(char *buf, gsize len, time_t time)
  222. {
  223. struct tm tms;
  224. rspamd_gmtime(time, &tms);
  225. return rspamd_snprintf(buf, len, "%s, %02d %s %4d %02d:%02d:%02d GMT",
  226. http_week[tms.tm_wday], tms.tm_mday,
  227. http_month[tms.tm_mon], tms.tm_year + 1900,
  228. tms.tm_hour, tms.tm_min, tms.tm_sec);
  229. }