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
get_sa_len(const struct sockaddr * addr)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 
response_header_insert(server * srv,connection * con,const char * key,size_t keylen,const char * value,size_t vallen)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 
response_header_overwrite(server * srv,connection * con,const char * key,size_t keylen,const char * value,size_t vallen)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 
response_header_append(server * srv,connection * con,const char * key,size_t keylen,const char * value,size_t vallen)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 
http_response_redirect_to_directory(server * srv,connection * con)121 int http_response_redirect_to_directory(server *srv, connection *con) {
122 	buffer *o;
123 
124 	o = buffer_init();
125 
126 	if (con->conf.is_ssl) {
127 		buffer_copy_string_len(o, CONST_STR_LEN("https://"));
128 	} else {
129 		buffer_copy_string_len(o, CONST_STR_LEN("http://"));
130 	}
131 	if (con->uri.authority->used) {
132 		buffer_append_string_buffer(o, con->uri.authority);
133 	} else {
134 		/* get the name of the currently connected socket */
135 		struct hostent *he;
136 #ifdef HAVE_IPV6
137 		char hbuf[256];
138 #endif
139 		sock_addr our_addr;
140 		socklen_t our_addr_len;
141 
142 		our_addr_len = sizeof(our_addr);
143 
144 		if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
145 			con->http_status = 500;
146 
147 			log_error_write(srv, __FILE__, __LINE__, "ss",
148 					"can't get sockname", strerror(errno));
149 
150 			buffer_free(o);
151 			return 0;
152 		}
153 
154 
155 		/* Lookup name: secondly try to get hostname for bind address */
156 		switch(our_addr.plain.sa_family) {
157 #ifdef HAVE_IPV6
158 		case AF_INET6:
159 			if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
160 					     SA_LEN((const struct sockaddr *)&our_addr.ipv6),
161 					     hbuf, sizeof(hbuf), NULL, 0, 0)) {
162 
163 				char dst[INET6_ADDRSTRLEN];
164 
165 				log_error_write(srv, __FILE__, __LINE__,
166 						"SSS", "NOTICE: getnameinfo failed: ",
167 						strerror(errno), ", using ip-address instead");
168 
169 				buffer_append_string(o,
170 						     inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
171 							       dst, sizeof(dst)));
172 			} else {
173 				buffer_append_string(o, hbuf);
174 			}
175 			break;
176 #endif
177 		case AF_INET:
178 			if (NULL == (he = gethostbyaddr((char *)&our_addr.ipv4.sin_addr, sizeof(struct in_addr), AF_INET))) {
179 				log_error_write(srv, __FILE__, __LINE__,
180 						"SdS", "NOTICE: gethostbyaddr failed: ",
181 						h_errno, ", using ip-address instead");
182 
183 				buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
184 			} else {
185 				buffer_append_string(o, he->h_name);
186 			}
187 			break;
188 		default:
189 			log_error_write(srv, __FILE__, __LINE__,
190 					"S", "ERROR: unsupported address-type");
191 
192 			buffer_free(o);
193 			return -1;
194 		}
195 
196 		if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
197 		      (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
198 			buffer_append_string_len(o, CONST_STR_LEN(":"));
199 			buffer_append_long(o, srv->srvconf.port);
200 		}
201 	}
202 	buffer_append_string_buffer(o, con->uri.path);
203 	buffer_append_string_len(o, CONST_STR_LEN("/"));
204 	if (!buffer_is_empty(con->uri.query)) {
205 		buffer_append_string_len(o, CONST_STR_LEN("?"));
206 		buffer_append_string_buffer(o, con->uri.query);
207 	}
208 
209 	response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
210 
211 	con->http_status = 301;
212 	con->file_finished = 1;
213 
214 	buffer_free(o);
215 
216 	return 0;
217 }
218 
strftime_cache_get(server * srv,time_t last_mod)219 buffer * strftime_cache_get(server *srv, time_t last_mod) {
220 	struct tm *tm;
221 	size_t i;
222 
223 	for (i = 0; i < FILE_CACHE_MAX; i++) {
224 		/* found cache-entry */
225 		if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
226 
227 		/* found empty slot */
228 		if (srv->mtime_cache[i].mtime == 0) break;
229 	}
230 
231 	if (i == FILE_CACHE_MAX) {
232 		i = 0;
233 	}
234 
235 	srv->mtime_cache[i].mtime = last_mod;
236 	buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
237 	tm = gmtime(&(srv->mtime_cache[i].mtime));
238 	srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
239 						 srv->mtime_cache[i].str->size - 1,
240 						 "%a, %d %b %Y %H:%M:%S GMT", tm);
241 	srv->mtime_cache[i].str->used++;
242 
243 	return srv->mtime_cache[i].str;
244 }
245 
246 
http_response_handle_cachable(server * srv,connection * con,buffer * mtime)247 int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
248 	/*
249 	 * 14.26 If-None-Match
250 	 *    [...]
251 	 *    If none of the entity tags match, then the server MAY perform the
252 	 *    requested method as if the If-None-Match header field did not exist,
253 	 *    but MUST also ignore any If-Modified-Since header field(s) in the
254 	 *    request. That is, if no entity tags match, then the server MUST NOT
255 	 *    return a 304 (Not Modified) response.
256 	 */
257 
258 	/* last-modified handling */
259 	if (con->request.http_if_none_match) {
260 		if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
261 			if (con->request.http_method == HTTP_METHOD_GET ||
262 			    con->request.http_method == HTTP_METHOD_HEAD) {
263 
264 				/* check if etag + last-modified */
265 				if (con->request.http_if_modified_since) {
266 					size_t used_len;
267 					char *semicolon;
268 
269 					if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
270 						used_len = strlen(con->request.http_if_modified_since);
271 					} else {
272 						used_len = semicolon - con->request.http_if_modified_since;
273 					}
274 
275 					if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
276 						if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
277 						return HANDLER_FINISHED;
278 					} else {
279 						char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
280 						time_t t_header, t_file;
281 						struct tm tm;
282 
283 						/* check if we can safely copy the string */
284 						if (used_len >= sizeof(buf)) {
285 							log_error_write(srv, __FILE__, __LINE__, "ssdd",
286 									"DEBUG: Last-Modified check failed as the received timestamp was too long:",
287 									con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
288 
289 							con->http_status = 412;
290 							con->mode = DIRECT;
291 							return HANDLER_FINISHED;
292 						}
293 
294 
295 						strncpy(buf, con->request.http_if_modified_since, used_len);
296 						buf[used_len] = '\0';
297 
298 						if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
299 							con->http_status = 412;
300 							con->mode = DIRECT;
301 							return HANDLER_FINISHED;
302 						}
303 						tm.tm_isdst = 0;
304 						t_header = mktime(&tm);
305 
306 						strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
307 						tm.tm_isdst = 0;
308 						t_file = mktime(&tm);
309 
310 						if (t_file > t_header) return HANDLER_GO_ON;
311 
312 						con->http_status = 304;
313 						return HANDLER_FINISHED;
314 					}
315 				} else {
316 					con->http_status = 304;
317 					return HANDLER_FINISHED;
318 				}
319 			} else {
320 				con->http_status = 412;
321 				con->mode = DIRECT;
322 				return HANDLER_FINISHED;
323 			}
324 		}
325 	} else if (con->request.http_if_modified_since) {
326 		size_t used_len;
327 		char *semicolon;
328 
329 		if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
330 			used_len = strlen(con->request.http_if_modified_since);
331 		} else {
332 			used_len = semicolon - con->request.http_if_modified_since;
333 		}
334 
335 		if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
336 			if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
337 			return HANDLER_FINISHED;
338 		} else {
339 			char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
340 			time_t t_header, t_file;
341 			struct tm tm;
342 
343 			/* convert to timestamp */
344 			if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
345 
346 			strncpy(buf, con->request.http_if_modified_since, used_len);
347 			buf[used_len] = '\0';
348 
349 			if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
350 				/**
351 				 * parsing failed, let's get out of here
352 				 */
353 				return HANDLER_GO_ON;
354 			}
355 			tm.tm_isdst = 0;
356 			t_header = mktime(&tm);
357 
358 			strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
359 			tm.tm_isdst = 0;
360 			t_file = mktime(&tm);
361 
362 			if (t_file > t_header) return HANDLER_GO_ON;
363 
364 			con->http_status = 304;
365 			return HANDLER_FINISHED;
366 		}
367 	}
368 
369 	return HANDLER_GO_ON;
370 }
371