File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / etag.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>