Annotation of embedaddon/lighttpd/src/http-header-glue.c, revision 1.1.1.1

1.1       misho       1: #include "base.h"
                      2: #include "array.h"
                      3: #include "buffer.h"
                      4: #include "log.h"
                      5: #include "etag.h"
                      6: #include "response.h"
                      7: 
                      8: #include <string.h>
                      9: #include <errno.h>
                     10: 
                     11: #include <time.h>
                     12: 
                     13: /*
                     14:  * This was 'borrowed' from tcpdump.
                     15:  *
                     16:  *
                     17:  * This is fun.
                     18:  *
                     19:  * In older BSD systems, socket addresses were fixed-length, and
                     20:  * "sizeof (struct sockaddr)" gave the size of the structure.
                     21:  * All addresses fit within a "struct sockaddr".
                     22:  *
                     23:  * In newer BSD systems, the socket address is variable-length, and
                     24:  * there's an "sa_len" field giving the length of the structure;
                     25:  * this allows socket addresses to be longer than 2 bytes of family
                     26:  * and 14 bytes of data.
                     27:  *
                     28:  * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
                     29:  * variant of the old BSD scheme (with "struct sockaddr_storage" rather
                     30:  * than "struct sockaddr"), and some use the new BSD scheme.
                     31:  *
                     32:  * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
                     33:  * macro that determines the size based on the address family.  Other
                     34:  * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
                     35:  * but not in the final version).  On the latter systems, we explicitly
                     36:  * check the AF_ type to determine the length; we assume that on
                     37:  * all those systems we have "struct sockaddr_storage".
                     38:  */
                     39: 
                     40: #ifdef HAVE_IPV6
                     41: # ifndef SA_LEN
                     42: #  ifdef HAVE_SOCKADDR_SA_LEN
                     43: #   define SA_LEN(addr)   ((addr)->sa_len)
                     44: #  else /* HAVE_SOCKADDR_SA_LEN */
                     45: #   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
                     46: static size_t get_sa_len(const struct sockaddr *addr) {
                     47:        switch (addr->sa_family) {
                     48: 
                     49: #    ifdef AF_INET
                     50:        case AF_INET:
                     51:                return (sizeof (struct sockaddr_in));
                     52: #    endif
                     53: 
                     54: #    ifdef AF_INET6
                     55:        case AF_INET6:
                     56:                return (sizeof (struct sockaddr_in6));
                     57: #    endif
                     58: 
                     59:        default:
                     60:                return (sizeof (struct sockaddr));
                     61: 
                     62:        }
                     63: }
                     64: #    define SA_LEN(addr)   (get_sa_len(addr))
                     65: #   else /* HAVE_SOCKADDR_STORAGE */
                     66: #    define SA_LEN(addr)   (sizeof (struct sockaddr))
                     67: #   endif /* HAVE_SOCKADDR_STORAGE */
                     68: #  endif /* HAVE_SOCKADDR_SA_LEN */
                     69: # endif /* SA_LEN */
                     70: #endif
                     71: 
                     72: 
                     73: 
                     74: 
                     75: int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
                     76:        data_string *ds;
                     77: 
                     78:        UNUSED(srv);
                     79: 
                     80:        if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                     81:                ds = data_response_init();
                     82:        }
                     83:        buffer_copy_string_len(ds->key, key, keylen);
                     84:        buffer_copy_string_len(ds->value, value, vallen);
                     85: 
                     86:        array_insert_unique(con->response.headers, (data_unset *)ds);
                     87: 
                     88:        return 0;
                     89: }
                     90: 
                     91: int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
                     92:        data_string *ds;
                     93: 
                     94:        UNUSED(srv);
                     95: 
                     96:        /* if there already is a key by this name overwrite the value */
                     97:        if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
                     98:                buffer_copy_string(ds->value, value);
                     99: 
                    100:                return 0;
                    101:        }
                    102: 
                    103:        return response_header_insert(srv, con, key, keylen, value, vallen);
                    104: }
                    105: 
                    106: int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
                    107:        data_string *ds;
                    108: 
                    109:        UNUSED(srv);
                    110: 
                    111:        /* if there already is a key by this name append the value */
                    112:        if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
                    113:                buffer_append_string_len(ds->value, CONST_STR_LEN(", "));
                    114:                buffer_append_string_len(ds->value, value, vallen);
                    115:                return 0;
                    116:        }
                    117: 
                    118:        return response_header_insert(srv, con, key, keylen, value, vallen);
                    119: }
                    120: 
                    121: int http_response_redirect_to_directory(server *srv, connection *con) {
                    122:        buffer *o;
                    123: 
                    124:        o = buffer_init();
                    125: 
                    126:        buffer_copy_string_buffer(o, con->uri.scheme);
                    127:        buffer_append_string_len(o, CONST_STR_LEN("://"));
                    128:        if (con->uri.authority->used) {
                    129:                buffer_append_string_buffer(o, con->uri.authority);
                    130:        } else {
                    131:                /* get the name of the currently connected socket */
                    132:                struct hostent *he;
                    133: #ifdef HAVE_IPV6
                    134:                char hbuf[256];
                    135: #endif
                    136:                sock_addr our_addr;
                    137:                socklen_t our_addr_len;
                    138: 
                    139:                our_addr_len = sizeof(our_addr);
                    140: 
                    141:                if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
                    142:                        con->http_status = 500;
                    143: 
                    144:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                    145:                                        "can't get sockname", strerror(errno));
                    146: 
                    147:                        buffer_free(o);
                    148:                        return 0;
                    149:                }
                    150: 
                    151: 
                    152:                /* Lookup name: secondly try to get hostname for bind address */
                    153:                switch(our_addr.plain.sa_family) {
                    154: #ifdef HAVE_IPV6
                    155:                case AF_INET6:
                    156:                        if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
                    157:                                             SA_LEN((const struct sockaddr *)&our_addr.ipv6),
                    158:                                             hbuf, sizeof(hbuf), NULL, 0, 0)) {
                    159: 
                    160:                                char dst[INET6_ADDRSTRLEN];
                    161: 
                    162:                                log_error_write(srv, __FILE__, __LINE__,
                    163:                                                "SSS", "NOTICE: getnameinfo failed: ",
                    164:                                                strerror(errno), ", using ip-address instead");
                    165: 
                    166:                                buffer_append_string(o,
                    167:                                                     inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
                    168:                                                               dst, sizeof(dst)));
                    169:                        } else {
                    170:                                buffer_append_string(o, hbuf);
                    171:                        }
                    172:                        break;
                    173: #endif
                    174:                case AF_INET:
                    175:                        if (NULL == (he = gethostbyaddr((char *)&our_addr.ipv4.sin_addr, sizeof(struct in_addr), AF_INET))) {
                    176:                                log_error_write(srv, __FILE__, __LINE__,
                    177:                                                "SdS", "NOTICE: gethostbyaddr failed: ",
                    178:                                                h_errno, ", using ip-address instead");
                    179: 
                    180:                                buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
                    181:                        } else {
                    182:                                buffer_append_string(o, he->h_name);
                    183:                        }
                    184:                        break;
                    185:                default:
                    186:                        log_error_write(srv, __FILE__, __LINE__,
                    187:                                        "S", "ERROR: unsupported address-type");
                    188: 
                    189:                        buffer_free(o);
                    190:                        return -1;
                    191:                }
                    192: 
                    193:                {
                    194:                        unsigned short default_port = 80;
                    195:                        if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
                    196:                                default_port = 443;
                    197:                        }
                    198:                        if (default_port != srv->srvconf.port) {
                    199:                                buffer_append_string_len(o, CONST_STR_LEN(":"));
                    200:                                buffer_append_long(o, srv->srvconf.port);
                    201:                        }
                    202:                }
                    203:        }
                    204:        buffer_append_string_buffer(o, con->uri.path);
                    205:        buffer_append_string_len(o, CONST_STR_LEN("/"));
                    206:        if (!buffer_is_empty(con->uri.query)) {
                    207:                buffer_append_string_len(o, CONST_STR_LEN("?"));
                    208:                buffer_append_string_buffer(o, con->uri.query);
                    209:        }
                    210: 
                    211:        response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
                    212: 
                    213:        con->http_status = 301;
                    214:        con->file_finished = 1;
                    215: 
                    216:        buffer_free(o);
                    217: 
                    218:        return 0;
                    219: }
                    220: 
                    221: buffer * strftime_cache_get(server *srv, time_t last_mod) {
                    222:        struct tm *tm;
                    223:        size_t i;
                    224: 
                    225:        for (i = 0; i < FILE_CACHE_MAX; i++) {
                    226:                /* found cache-entry */
                    227:                if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
                    228: 
                    229:                /* found empty slot */
                    230:                if (srv->mtime_cache[i].mtime == 0) break;
                    231:        }
                    232: 
                    233:        if (i == FILE_CACHE_MAX) {
                    234:                i = 0;
                    235:        }
                    236: 
                    237:        srv->mtime_cache[i].mtime = last_mod;
                    238:        buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
                    239:        tm = gmtime(&(srv->mtime_cache[i].mtime));
                    240:        srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
                    241:                                                 srv->mtime_cache[i].str->size - 1,
                    242:                                                 "%a, %d %b %Y %H:%M:%S GMT", tm);
                    243:        srv->mtime_cache[i].str->used++;
                    244: 
                    245:        return srv->mtime_cache[i].str;
                    246: }
                    247: 
                    248: 
                    249: int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
                    250:        UNUSED(srv);
                    251:        /*
                    252:         * 14.26 If-None-Match
                    253:         *    [...]
                    254:         *    If none of the entity tags match, then the server MAY perform the
                    255:         *    requested method as if the If-None-Match header field did not exist,
                    256:         *    but MUST also ignore any If-Modified-Since header field(s) in the
                    257:         *    request. That is, if no entity tags match, then the server MUST NOT
                    258:         *    return a 304 (Not Modified) response.
                    259:         */
                    260: 
                    261:        /* last-modified handling */
                    262:        if (con->request.http_if_none_match) {
                    263:                if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
                    264:                        if (con->request.http_method == HTTP_METHOD_GET ||
                    265:                            con->request.http_method == HTTP_METHOD_HEAD) {
                    266: 
                    267:                                con->http_status = 304;
                    268:                                return HANDLER_FINISHED;
                    269:                        } else {
                    270:                                con->http_status = 412;
                    271:                                con->mode = DIRECT;
                    272:                                return HANDLER_FINISHED;
                    273:                        }
                    274:                }
                    275:        } else if (con->request.http_if_modified_since &&
                    276:                   (con->request.http_method == HTTP_METHOD_GET ||
                    277:                    con->request.http_method == HTTP_METHOD_HEAD)) {
                    278:                size_t used_len;
                    279:                char *semicolon;
                    280: 
                    281:                if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
                    282:                        used_len = strlen(con->request.http_if_modified_since);
                    283:                } else {
                    284:                        used_len = semicolon - con->request.http_if_modified_since;
                    285:                }
                    286: 
                    287:                if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
                    288:                        if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
                    289:                        return HANDLER_FINISHED;
                    290:                } else {
                    291:                        char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
                    292:                        time_t t_header, t_file;
                    293:                        struct tm tm;
                    294: 
                    295:                        /* convert to timestamp */
                    296:                        if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
                    297: 
                    298:                        strncpy(buf, con->request.http_if_modified_since, used_len);
                    299:                        buf[used_len] = '\0';
                    300: 
                    301:                        if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
                    302:                                /**
                    303:                                 * parsing failed, let's get out of here 
                    304:                                 */
                    305:                                return HANDLER_GO_ON;
                    306:                        }
                    307:                        tm.tm_isdst = 0;
                    308:                        t_header = mktime(&tm);
                    309: 
                    310:                        strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
                    311:                        tm.tm_isdst = 0;
                    312:                        t_file = mktime(&tm);
                    313: 
                    314:                        if (t_file > t_header) return HANDLER_GO_ON;
                    315: 
                    316:                        con->http_status = 304;
                    317:                        return HANDLER_FINISHED;
                    318:                }
                    319:        }
                    320: 
                    321:        return HANDLER_GO_ON;
                    322: }

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