File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / http-header-glue.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 10:32:48 2013 UTC (10 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, v1_4_33, HEAD
1.4.33

    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>