diff options
Diffstat (limited to 'src/http-header-glue.c')
-rw-r--r-- | src/http-header-glue.c | 384 |
1 files changed, 0 insertions, 384 deletions
diff --git a/src/http-header-glue.c b/src/http-header-glue.c deleted file mode 100644 index a16eec49..00000000 --- a/src/http-header-glue.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * make sure _GNU_SOURCE is defined - */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <string.h> -#include <errno.h> -#include <time.h> - -#include "base.h" -#include "array.h" -#include "buffer.h" -#include "log.h" -#include "etag.h" -#include "response.h" - -/* - * This was 'borrowed' from tcpdump. - * - * - * This is fun. - * - * In older BSD systems, socket addresses were fixed-length, and - * "sizeof (struct sockaddr)" gave the size of the structure. - * All addresses fit within a "struct sockaddr". - * - * In newer BSD systems, the socket address is variable-length, and - * there's an "sa_len" field giving the length of the structure; - * this allows socket addresses to be longer than 2 bytes of family - * and 14 bytes of data. - * - * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 - * variant of the old BSD scheme (with "struct sockaddr_storage" rather - * than "struct sockaddr"), and some use the new BSD scheme. - * - * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" - * macro that determines the size based on the address family. Other - * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 - * but not in the final version). On the latter systems, we explicitly - * check the AF_ type to determine the length; we assume that on - * all those systems we have "struct sockaddr_storage". - */ - -#ifdef HAVE_IPV6 -# ifndef SA_LEN -# ifdef HAVE_SOCKADDR_SA_LEN -# define SA_LEN(addr) ((addr)->sa_len) -# else /* HAVE_SOCKADDR_SA_LEN */ -# ifdef HAVE_STRUCT_SOCKADDR_STORAGE -static size_t get_sa_len(const struct sockaddr *addr) { - switch (addr->sa_family) { - -# ifdef AF_INET - case AF_INET: - return (sizeof (struct sockaddr_in)); -# endif - -# ifdef AF_INET6 - case AF_INET6: - return (sizeof (struct sockaddr_in6)); -# endif - - default: - return (sizeof (struct sockaddr)); - - } -} -# define SA_LEN(addr) (get_sa_len(addr)) -# else /* HAVE_SOCKADDR_STORAGE */ -# define SA_LEN(addr) (sizeof (struct sockaddr)) -# endif /* HAVE_SOCKADDR_STORAGE */ -# endif /* HAVE_SOCKADDR_SA_LEN */ -# endif /* SA_LEN */ -#endif - - - - -int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) { - data_string *ds; - - UNUSED(srv); - - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { - ds = data_response_init(); - } - buffer_copy_string_len(ds->key, key, keylen); - buffer_copy_string_len(ds->value, value, vallen); - - array_insert_unique(con->response.headers, (data_unset *)ds); - - return 0; -} - -int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) { - data_string *ds; - - UNUSED(srv); - - /* if there already is a key by this name overwrite the value */ - if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key, keylen))) { - buffer_copy_string(ds->value, value); - - return 0; - } - - return response_header_insert(srv, con, key, keylen, value, vallen); -} - - -int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) { - data_string *ds; - - UNUSED(srv); - - /* if there already is a key by this name append the value */ - if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key, keylen))) { - buffer_append_string_len(ds->value, CONST_STR_LEN(", ")); - buffer_append_string_len(ds->value, value, vallen); - return 0; - } - - return response_header_insert(srv, con, key, keylen, value, vallen); -} - -int http_response_redirect_to_directory(server *srv, connection *con) { - buffer *o; - - o = buffer_init(); - - if (con->conf.is_ssl) { - buffer_copy_string_len(o, CONST_STR_LEN("https://")); - } else { - buffer_copy_string_len(o, CONST_STR_LEN("http://")); - } - if (con->uri.authority->used) { - buffer_append_string_buffer(o, con->uri.authority); - } else { - /* get the name of the currently connected socket */ - struct hostent *he; -#ifdef HAVE_IPV6 - char hbuf[256]; -#endif - sock_addr our_addr; - socklen_t our_addr_len; - - our_addr_len = sizeof(our_addr); - - if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) { - con->http_status = 500; - - log_error_write(srv, __FILE__, __LINE__, "ss", - "can't get sockname", strerror(errno)); - - buffer_free(o); - return 0; - } - - - /* Lookup name: secondly try to get hostname for bind address */ - switch(our_addr.plain.sa_family) { -#ifdef HAVE_IPV6 - case AF_INET6: - if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), - SA_LEN((const struct sockaddr *)&our_addr.ipv6), - hbuf, sizeof(hbuf), NULL, 0, 0)) { - - char dst[INET6_ADDRSTRLEN]; - - ERROR("NOTICE: getnameinfo() failed: %s, using ip-address instead", - strerror(errno)); - - buffer_append_string(o, - inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, - dst, sizeof(dst))); - } else { - buffer_append_string(o, hbuf); - } - break; -#endif - case AF_INET: - if (NULL == (he = gethostbyaddr((char *)&our_addr.ipv4.sin_addr, sizeof(struct in_addr), AF_INET))) { - ERROR("NOTICE: gethostbyaddr() failed: %d, using ip-address instead", - h_errno); - - buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr)); - } else { - buffer_append_string(o, he->h_name); - } - break; - default: - ERROR("ERROR: unsupported address-type, %d", our_addr.plain.sa_family); - - buffer_free(o); - return -1; - } - - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || - (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) { - buffer_append_string_len(o, CONST_STR_LEN(":")); - buffer_append_long(o, srv->srvconf.port); - } - } - buffer_append_string_buffer(o, con->uri.path); - buffer_append_string_len(o, CONST_STR_LEN("/")); - if (!buffer_is_empty(con->uri.query)) { - buffer_append_string_len(o, CONST_STR_LEN("?")); - buffer_append_string_buffer(o, con->uri.query); - } - - response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o)); - - con->http_status = 301; - con->send->is_closed = 1; /* no content */ - - buffer_free(o); - - return 0; -} - -buffer * strftime_cache_get(server *srv, time_t last_mod) { - struct tm *tm; - size_t i; - - for (i = 0; i < FILE_CACHE_MAX; i++) { - /* found cache-entry */ - if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str; - - /* found empty slot */ - if (srv->mtime_cache[i].mtime == 0) break; - } - - if (i == FILE_CACHE_MAX) { - i = 0; - } - - srv->mtime_cache[i].mtime = last_mod; - buffer_prepare_copy(srv->mtime_cache[i].str, 1024); - tm = gmtime(&(srv->mtime_cache[i].mtime)); - srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, - srv->mtime_cache[i].str->size - 1, - "%a, %d %b %Y %H:%M:%S GMT", tm); - srv->mtime_cache[i].str->used++; - - return srv->mtime_cache[i].str; -} - - -int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) { - data_string *http_if_none_match; - data_string *http_if_modified_since; - - UNUSED(srv); - - /* - * 14.26 If-None-Match - * [...] - * If none of the entity tags match, then the server MAY perform the - * requested method as if the If-None-Match header field did not exist, - * but MUST also ignore any If-Modified-Since header field(s) in the - * request. That is, if no entity tags match, then the server MUST NOT - * return a 304 (Not Modified) response. - */ - - http_if_none_match = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("if-none-match")); - http_if_modified_since = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("if-modified-since")); - - /* last-modified handling */ - if (http_if_none_match) { - if (etag_is_equal(con->physical.etag, BUF_STR(http_if_none_match->value))) { - if (con->request.http_method == HTTP_METHOD_GET || - con->request.http_method == HTTP_METHOD_HEAD) { - - /* check if etag + last-modified */ - if (http_if_modified_since) { - size_t used_len; - char *semicolon; - - if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) { - used_len = http_if_modified_since->value->used - 1; - } else { - used_len = semicolon - BUF_STR(http_if_modified_since->value); - } - - if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) { - if ('\0' == mtime->ptr[used_len]) con->http_status = 304; - return HANDLER_FINISHED; - } else { -#ifdef HAVE_STRPTIME - char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; - time_t t_header, t_file; - struct tm tm; - - /* check if we can safely copy the string */ - if (used_len >= sizeof(buf)) { - TRACE("last-mod check failed as timestamp was too long: %s: %zu, %zu", - SAFE_BUF_STR(http_if_modified_since->value), - used_len, sizeof(buf) - 1); - - con->http_status = 412; - return HANDLER_FINISHED; - } - - - strncpy(buf, BUF_STR(http_if_modified_since->value), used_len); - buf[used_len] = '\0'; - - if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) { - con->http_status = 412; - return HANDLER_FINISHED; - } - tm.tm_isdst = 0; - t_header = mktime(&tm); - - strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); - tm.tm_isdst = 0; - t_file = mktime(&tm); - - if (t_file > t_header) return HANDLER_GO_ON; - - con->http_status = 304; - return HANDLER_FINISHED; -#else - return HANDLER_GO_ON; -#endif - } - } else { - con->http_status = 304; - return HANDLER_FINISHED; - } - } else { - con->http_status = 412; - return HANDLER_FINISHED; - } - } - } else if (http_if_modified_since) { - size_t used_len; - char *semicolon; - - if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) { - used_len = http_if_modified_since->value->used - 1; - } else { - used_len = semicolon - BUF_STR(http_if_modified_since->value); - } - - if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) { - if ('\0' == mtime->ptr[used_len]) con->http_status = 304; - return HANDLER_FINISHED; - } else { -#ifdef HAVE_STRPTIME - char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; - time_t t_header, t_file; - struct tm tm; - - /* convert to timestamp */ - if (used_len >= sizeof(buf)) return HANDLER_GO_ON; - - strncpy(buf, BUF_STR(http_if_modified_since->value), used_len); - buf[used_len] = '\0'; - - if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) { - return HANDLER_GO_ON; - } - tm.tm_isdst = 0; - t_header = mktime(&tm); - - strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); - tm.tm_isdst = 0; - t_file = mktime(&tm); - - if (t_file > t_header) return HANDLER_GO_ON; - - con->http_status = 304; - return HANDLER_FINISHED; -#else - return HANDLER_GO_ON; -#endif - } - } - - return HANDLER_GO_ON; -} |