lighttpd 1.4.x https://www.lighttpd.net/
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.
 
 
 
 
 
 

184 lines
3.8 KiB

  1. #include "first.h"
  2. #include "algo_md.h"
  3. #include "buffer.h"
  4. #include "etag.h"
  5. #include <sys/stat.h>
  6. int etag_is_equal(const buffer *etag, const char *line, int weak_ok) {
  7. enum {
  8. START = 0,
  9. CHECK,
  10. CHECK_QUOTED,
  11. SKIP,
  12. SKIP_QUOTED,
  13. TAIL
  14. } state = START;
  15. const char *current;
  16. const char *tok_start;
  17. const char *tok = NULL;
  18. int matched;
  19. if ('*' == line[0] && '\0' == line[1]) {
  20. return 1;
  21. }
  22. if (!etag || buffer_string_is_empty(etag)) return 0;
  23. tok_start = etag->ptr;
  24. if ('W' == tok_start[0]) {
  25. if (!weak_ok || '/' != tok_start[1]) return 0; /* bad etag */
  26. tok_start = tok_start + 2;
  27. }
  28. if ('"' != tok_start[0]) return 0; /* bad etag */
  29. /* we start comparing after the first '"' */
  30. ++tok_start;
  31. for (current = line; *current; ++current) {
  32. switch (state) {
  33. case START:
  34. /* wait for etag to start; ignore whitespace and ',' */
  35. switch (*current) {
  36. case 'W':
  37. /* weak etag always starts with 'W/"' */
  38. if ('/' != *++current) return 0; /* bad etag list */
  39. if ('"' != *++current) return 0; /* bad etag list */
  40. if (!weak_ok) {
  41. state = SKIP;
  42. } else {
  43. state = CHECK;
  44. tok = tok_start;
  45. }
  46. break;
  47. case '"':
  48. /* strong etag starts with '"' */
  49. state = CHECK;
  50. tok = tok_start;
  51. break;
  52. case ' ':
  53. case ',':
  54. case '\t':
  55. case '\r':
  56. case '\n':
  57. break;
  58. default:
  59. return 0; /* bad etag list */
  60. }
  61. break;
  62. case CHECK:
  63. /* compare etags (after the beginning '"')
  64. * quoted-pairs must match too (i.e. quoted in both strings):
  65. * > (RFC 2616:) both validators MUST be identical in every way
  66. */
  67. matched = *tok && *tok == *current;
  68. ++tok;
  69. switch (*current) {
  70. case '\\':
  71. state = matched ? CHECK_QUOTED : SKIP_QUOTED;
  72. break;
  73. case '"':
  74. if (*tok) {
  75. /* bad etag - string should end after '"' */
  76. return 0;
  77. }
  78. if (matched) {
  79. /* matching etag: strings were equal */
  80. return 1;
  81. }
  82. state = TAIL;
  83. break;
  84. default:
  85. if (!matched) {
  86. /* strings not matching, skip remainder of etag */
  87. state = SKIP;
  88. }
  89. break;
  90. }
  91. break;
  92. case CHECK_QUOTED:
  93. if (!*tok || *tok != *current) {
  94. /* strings not matching, skip remainder of etag */
  95. state = SKIP;
  96. break;
  97. }
  98. ++tok;
  99. state = CHECK;
  100. break;
  101. case SKIP:
  102. /* wait for final (not quoted) '"' */
  103. switch (*current) {
  104. case '\\':
  105. state = SKIP_QUOTED;
  106. break;
  107. case '"':
  108. state = TAIL;
  109. break;
  110. }
  111. break;
  112. case SKIP_QUOTED:
  113. state = SKIP;
  114. break;
  115. case TAIL:
  116. /* search for ',', ignore white space */
  117. switch (*current) {
  118. case ',':
  119. state = START;
  120. break;
  121. case ' ':
  122. case '\t':
  123. case '\r':
  124. case '\n':
  125. break;
  126. default:
  127. return 0; /* bad etag list */
  128. }
  129. break;
  130. }
  131. }
  132. /* no matching etag found */
  133. return 0;
  134. }
  135. int etag_create(buffer *etag, const struct stat *st, int flags) {
  136. if (0 == flags) return 0;
  137. buffer_clear(etag);
  138. if (flags & ETAG_USE_INODE) {
  139. buffer_append_int(etag, st->st_ino);
  140. buffer_append_string_len(etag, CONST_STR_LEN("-"));
  141. }
  142. if (flags & ETAG_USE_SIZE) {
  143. buffer_append_int(etag, st->st_size);
  144. buffer_append_string_len(etag, CONST_STR_LEN("-"));
  145. }
  146. if (flags & ETAG_USE_MTIME) {
  147. buffer_append_int(etag, st->st_mtime);
  148. #ifdef st_mtime /* use high-precision timestamp if available */
  149. #if defined(__APPLE__) && defined(__MACH__)
  150. buffer_append_int(etag, st->st_mtimespec.tv_nsec);
  151. #else
  152. buffer_append_int(etag, st->st_mtim.tv_nsec);
  153. #endif
  154. #endif
  155. }
  156. return 0;
  157. }
  158. void
  159. etag_mutate (buffer * const mut, const buffer * const etag) {
  160. /* mut and etag may be the same, so calculate hash before modifying mut */
  161. const uint32_t h = dekhash(CONST_BUF_LEN(etag));
  162. buffer_copy_string_len(mut, CONST_STR_LEN("\""));
  163. buffer_append_int(mut, h);
  164. buffer_append_string_len(mut, CONST_STR_LEN("\""));
  165. }