Annotation of embedaddon/lighttpd/src/etag.c, revision 1.1.1.2

1.1.1.2 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       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: 
1.1.1.2 ! misho      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 */
1.1       misho     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) {
1.1.1.2 ! misho     157:                buffer_append_int(etag, st->st_ino);
1.1       misho     158:                buffer_append_string_len(etag, CONST_STR_LEN("-"));
                    159:        }
                    160:        
                    161:        if (flags & ETAG_USE_SIZE) {
1.1.1.2 ! misho     162:                buffer_append_int(etag, st->st_size);
1.1       misho     163:                buffer_append_string_len(etag, CONST_STR_LEN("-"));
                    164:        }
                    165:        
                    166:        if (flags & ETAG_USE_MTIME) {
1.1.1.2 ! misho     167:                buffer_append_int(etag, st->st_mtime);
1.1       misho     168:        }
                    169: 
                    170:        return 0;
                    171: }
                    172: 
                    173: int etag_mutate(buffer *mut, buffer *etag) {
1.1.1.2 ! misho     174:        size_t i, len;
1.1       misho     175:        uint32_t h;
                    176: 
1.1.1.2 ! misho     177:        len = buffer_string_length(etag);
        !           178:        for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
1.1       misho     179: 
                    180:        buffer_reset(mut);
                    181:        buffer_copy_string_len(mut, CONST_STR_LEN("\""));
1.1.1.2 ! misho     182:        buffer_append_int(mut, h);
1.1       misho     183:        buffer_append_string_len(mut, CONST_STR_LEN("\""));
                    184: 
                    185:        return 0;
                    186: }

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