Example #1
0
static int http_chunk_append_len(server *srv, connection *con, size_t len) {
	size_t i, olen = len, j;
	buffer *b;

	b = srv->tmp_chunk_len;

	if (len == 0) {
		buffer_copy_string_len(b, CONST_STR_LEN("0"));
	} else {
		for (i = 0; i < 8 && len; i++) {
			len >>= 4;
		}

		/* i is the number of hex digits we have */
		buffer_prepare_copy(b, i + 1);

		for (j = i-1, len = olen; j+1 > 0; j--) {
			b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
			len >>= 4;
		}
		b->used = i;
		b->ptr[b->used++] = '\0';
	}

	buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
	chunkqueue_append_buffer(con->write_queue, b);

	return 0;
}
Example #2
0
static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
	buffer *b;
	size_t i;
	array *st = srv->status;
	UNUSED(p_d);

	if (0 == st->used) {
		/* we have nothing to send */
		con->http_status = 204;
		con->file_finished = 1;

		return HANDLER_FINISHED;
	}

	b = buffer_init();
	for (i = 0; i < st->used; i++) {
		size_t ndx = st->sorted[i];

		buffer_append_string_buffer(b, st->data[ndx]->key);
		buffer_append_string_len(b, CONST_STR_LEN(": "));
		buffer_append_int(b, ((data_integer *)(st->data[ndx]))->value);
		buffer_append_string_len(b, CONST_STR_LEN("\n"));
	}

	chunkqueue_append_buffer(con->write_queue, b);
	buffer_free(b);

	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));

	con->http_status = 200;
	con->file_finished = 1;

	return HANDLER_FINISHED;
}
Example #3
0
static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) {
	plugin_data *p = p_d;
	buffer *b = buffer_init();
	double avg;
	time_t ts;
	char buf[32];
	unsigned int k;
	unsigned int l;

	/* output total number of requests */
	buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: "));
	avg = p->abs_requests;
	snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
	buffer_append_string(b, buf);
	buffer_append_string_len(b, CONST_STR_LEN("\n"));

	/* output total traffic out in kbytes */
	buffer_append_string_len(b, CONST_STR_LEN("Total kBytes: "));
	avg = p->abs_traffic_out / 1024;
	snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
	buffer_append_string(b, buf);
	buffer_append_string_len(b, CONST_STR_LEN("\n"));

	/* output uptime */
	buffer_append_string_len(b, CONST_STR_LEN("Uptime: "));
	ts = srv->cur_ts - srv->startup_ts;
	buffer_append_int(b, ts);
	buffer_append_string_len(b, CONST_STR_LEN("\n"));

	/* output busy servers */
	buffer_append_string_len(b, CONST_STR_LEN("BusyServers: "));
	buffer_append_int(b, srv->conns->used);
	buffer_append_string_len(b, CONST_STR_LEN("\n"));

	buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
	buffer_append_int(b, srv->conns->size - srv->conns->used);
	buffer_append_string_len(b, CONST_STR_LEN("\n"));

	/* output scoreboard */
	buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: "));
	for (k = 0; k < srv->conns->used; k++) {
		connection *c = srv->conns->ptr[k];
		const char *state = connection_get_short_state(c->state);
		buffer_append_string_len(b, state, 1);
	}
	for (l = 0; l < srv->conns->size - srv->conns->used; l++) {
		buffer_append_string_len(b, CONST_STR_LEN("_"));
	}
	buffer_append_string_len(b, CONST_STR_LEN("\n"));

	chunkqueue_append_buffer(con->write_queue, b);
	buffer_free(b);

	/* set text/plain output */
	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));

	return 0;
}
Example #4
0
static int proxy_create_env(server *srv, handler_ctx *hctx) {
	size_t i;

	connection *con   = hctx->remote_conn;
	buffer *b;

	/* build header */

	b = buffer_init();

	/* request line */
	buffer_copy_string(b, get_http_method_name(con->request.http_method));
	buffer_append_string_len(b, CONST_STR_LEN(" "));

	buffer_append_string_buffer(b, con->request.uri);
	buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));

	proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
	/* http_host is NOT is just a pointer to a buffer
	 * which is NULL if it is not set */
	if (!buffer_string_is_empty(con->request.http_host)) {
		proxy_set_header(con, "X-Host", con->request.http_host->ptr);
	}
	proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr);

	/* request header */
	for (i = 0; i < con->request.headers->used; i++) {
		data_string *ds;

		ds = (data_string *)con->request.headers->data[i];

		if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
			if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
			if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;

			buffer_append_string_buffer(b, ds->key);
			buffer_append_string_len(b, CONST_STR_LEN(": "));
			buffer_append_string_buffer(b, ds->value);
			buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
		}
	}

	buffer_append_string_len(b, CONST_STR_LEN("\r\n"));

	hctx->wb->bytes_in += buffer_string_length(b);
	chunkqueue_append_buffer(hctx->wb, b);
	buffer_free(b);

	/* body */

	if (con->request.content_length) {
		chunkqueue *req_cq = con->request_content_queue;

		chunkqueue_steal(hctx->wb, req_cq, req_cq->bytes_in);
	}

	return 0;
}
Example #5
0
static void http_chunk_append_len(server *srv, connection *con, uintmax_t len) {
	buffer *b;

	force_assert(NULL != srv);

	b = srv->tmp_chunk_len;

	buffer_string_set_length(b, 0);
	buffer_append_uint_hex(b, len);
	buffer_append_string_len(b, CONST_STR_LEN("\r\n"));

	chunkqueue_append_buffer(con->write_queue, b);
}
Example #6
0
int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
	chunkqueue *cq;

	if (!con) return -1;

	cq = con->write_queue;

	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
		http_chunk_append_len(srv, con, mem->used - 1);
	}

	chunkqueue_append_buffer(cq, mem);

	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
		chunkqueue_append_mem(cq, "\r\n", 2 + 1);
	}

	return 0;
}
Example #7
0
static int http_chunk_append_data(server *srv, connection *con, buffer *b, const char * mem, size_t len) {

	chunkqueue * const cq = con->write_queue;
	chunk *c = cq->last;
	if (0 == len) return 0;

	/* current usage does not append_mem or append_buffer after appending
	 * file, so not checking if users of this interface have appended large
	 * (references to) files to chunkqueue, which would not be in memory */

	/*(allow slightly larger mem use if FDEVENT_STREAM_RESPONSE_BUFMIN
	 * to reduce creation of temp files when backend producer will be
	 * blocked until more data is sent to network to client)*/

	if ((c && c->type == FILE_CHUNK && c->file.is_temp)
	    || cq->bytes_in - cq->bytes_out + len
		> 1024 * ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) ? 128 : 64)) {
		return http_chunk_append_to_tempfile(srv, con, b ? b->ptr : mem, len);
	}

	/* not appending to prior mem chunk just in case using openssl
	 * and need to resubmit same args as prior call to openssl (required?)*/

	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
		http_chunk_append_len(srv, con, len);
	}

	/*(chunkqueue_append_buffer() might steal buffer contents)*/
	b ? chunkqueue_append_buffer(cq, b) : chunkqueue_append_mem(cq, mem, len);

	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
		chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
	}

	return 0;
}
Example #8
0
static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) {
	DIR *dp;
	buffer *out;
	struct dirent *dent;
	struct stat st;
	char *path, *path_file;
	size_t i;
	int hide_dotfiles = p->conf.hide_dot_files;
	dirls_list_t dirs, files, *list;
	dirls_entry_t *tmp;
	char sizebuf[sizeof("999.9K")];
	char datebuf[sizeof("2005-Jan-01 22:23:24")];
	size_t k;
	const char *content_type;
	long name_max;
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
	char attrval[128];
	int attrlen;
#endif
#ifdef HAVE_LOCALTIME_R
	struct tm tm;
#endif

	if (buffer_string_is_empty(dir)) return -1;

	i = buffer_string_length(dir);

#ifdef HAVE_PATHCONF
	if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
		/* some broken fs (fuse) return 0 instead of -1 */
#ifdef NAME_MAX
		name_max = NAME_MAX;
#else
		name_max = 255; /* stupid default */
#endif
	}
#elif defined __WIN32
	name_max = FILENAME_MAX;
#else
	name_max = NAME_MAX;
#endif

	path = malloc(i + name_max + 1);
	force_assert(NULL != path);
	memcpy(path, dir->ptr, i+1);
	path_file = path + i;

	if (NULL == (dp = opendir(path))) {
		log_error_write(srv, __FILE__, __LINE__, "sbs",
			"opendir failed:", dir, strerror(errno));

		free(path);
		return -1;
	}

	dirs.ent   = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
	force_assert(dirs.ent);
	dirs.size  = DIRLIST_BLOB_SIZE;
	dirs.used  = 0;
	files.ent  = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
	force_assert(files.ent);
	files.size = DIRLIST_BLOB_SIZE;
	files.used = 0;

	while ((dent = readdir(dp)) != NULL) {
		unsigned short exclude_match = 0;

		if (dent->d_name[0] == '.') {
			if (hide_dotfiles)
				continue;
			if (dent->d_name[1] == '\0')
				continue;
			if (dent->d_name[1] == '.' && dent->d_name[2] == '\0')
				continue;
		}

		if (p->conf.hide_readme_file && !buffer_string_is_empty(p->conf.show_readme)) {
			if (strcmp(dent->d_name, p->conf.show_readme->ptr) == 0)
				continue;
		}
		if (p->conf.hide_header_file && !buffer_string_is_empty(p->conf.show_header)) {
			if (strcmp(dent->d_name, p->conf.show_header->ptr) == 0)
				continue;
		}

		/* compare d_name against excludes array
		 * elements, skipping any that match.
		 */
#ifdef HAVE_PCRE_H
		for(i = 0; i < p->conf.excludes->used; i++) {
			int n;
#define N 10
			int ovec[N * 3];
			pcre *regex = p->conf.excludes->ptr[i]->regex;

			if ((n = pcre_exec(regex, NULL, dent->d_name,
				    strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) {
				if (n != PCRE_ERROR_NOMATCH) {
					log_error_write(srv, __FILE__, __LINE__, "sd",
						"execution error while matching:", n);

					/* aborting would require a lot of manual cleanup here.
					 * skip instead (to not leak names that break pcre matching)
					 */
					exclude_match = 1;
					break;
				}
			}
			else {
				exclude_match = 1;
				break;
			}
		}

		if (exclude_match) {
			continue;
		}
#endif

		i = strlen(dent->d_name);

		/* NOTE: the manual says, d_name is never more than NAME_MAX
		 *       so this should actually not be a buffer-overflow-risk
		 */
		if (i > (size_t)name_max) continue;

		memcpy(path_file, dent->d_name, i + 1);
		if (stat(path, &st) != 0)
			continue;

		list = &files;
		if (S_ISDIR(st.st_mode))
			list = &dirs;

		if (list->used == list->size) {
			list->size += DIRLIST_BLOB_SIZE;
			list->ent   = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size);
			force_assert(list->ent);
		}

		tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i);
		tmp->mtime = st.st_mtime;
		tmp->size  = st.st_size;
		tmp->namelen = i;
		memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1);

		list->ent[list->used++] = tmp;
	}
	closedir(dp);

	if (dirs.used) http_dirls_sort(dirs.ent, dirs.used);

	if (files.used) http_dirls_sort(files.ent, files.used);

	out = buffer_init();
	http_list_directory_header(srv, con, p, out);

	/* directories */
	for (i = 0; i < dirs.used; i++) {
		tmp = dirs.ent[i];

#ifdef HAVE_LOCALTIME_R
		localtime_r(&(tmp->mtime), &tm);
		strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
#else
		strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
#endif

		buffer_append_string_len(out, CONST_STR_LEN("<tr class=\"d\"><td class=\"n\"><a href=\""));
		buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
		buffer_append_string_len(out, CONST_STR_LEN("/\">"));
		buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
		buffer_append_string_len(out, CONST_STR_LEN("</a>/</td><td class=\"m\">"));
		buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
		buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n"));

		free(tmp);
	}

	/* files */
	for (i = 0; i < files.used; i++) {
		tmp = files.ent[i];

		content_type = NULL;
#if defined(HAVE_XATTR)
		if (con->conf.use_xattr) {
			memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
			attrlen = sizeof(attrval) - 1;
			if (attr_get(path, srv->srvconf.xattr_name->ptr, attrval, &attrlen, 0) == 0) {
				attrval[attrlen] = '\0';
				content_type = attrval;
			}
		}
#elif defined(HAVE_EXTATTR)
		if (con->conf.use_xattr) {
			memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
			if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, srv->srvconf.xattr_name->ptr, attrval, sizeof(attrval)-1))) {
				attrval[attrlen] = '\0';
				content_type = attrval;
			}
		}
#endif

		if (content_type == NULL) {
			content_type = "application/octet-stream";
			for (k = 0; k < con->conf.mimetypes->used; k++) {
				data_string *ds = (data_string *)con->conf.mimetypes->data[k];
				size_t ct_len;

				if (buffer_is_empty(ds->key))
					continue;

				ct_len = buffer_string_length(ds->key);
				if (tmp->namelen < ct_len)
					continue;

				if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) {
					content_type = ds->value->ptr;
					break;
				}
			}
		}

#ifdef HAVE_LOCALTIME_R
		localtime_r(&(tmp->mtime), &tm);
		strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
#else
		strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
#endif
		http_list_directory_sizefmt(sizebuf, sizeof(sizebuf), tmp->size);

		buffer_append_string_len(out, CONST_STR_LEN("<tr><td class=\"n\"><a href=\""));
		buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
		buffer_append_string_len(out, CONST_STR_LEN("\">"));
		buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
		buffer_append_string_len(out, CONST_STR_LEN("</a></td><td class=\"m\">"));
		buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
		buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">"));
		buffer_append_string(out, sizebuf);
		buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"t\">"));
		buffer_append_string(out, content_type);
		buffer_append_string_len(out, CONST_STR_LEN("</td></tr>\n"));

		free(tmp);
	}

	free(files.ent);
	free(dirs.ent);
	free(path);

	http_list_directory_footer(srv, con, p, out);

	/* Insert possible charset to Content-Type */
	if (buffer_string_is_empty(p->conf.encoding)) {
		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
	} else {
		buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset="));
		buffer_append_string_buffer(p->content_charset, p->conf.encoding);
		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
	}

	con->file_finished = 1;
	chunkqueue_append_buffer(con->write_queue, out);
	buffer_free(out);

	return 0;
}
Example #9
0
static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) {
	plugin_data *p = p_d;
	buffer *b = buffer_init();
	buffer *m = p->module_list;
	size_t i;

	struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
	{
		/* - epoll is most reliable
		 * - select works everywhere
		 */
#ifdef USE_LINUX_EPOLL
		{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
#endif
#ifdef USE_POLL
		{ FDEVENT_HANDLER_POLL,           "poll" },
#endif
#ifdef USE_SELECT
		{ FDEVENT_HANDLER_SELECT,         "select" },
#endif
#ifdef USE_LIBEV
		{ FDEVENT_HANDLER_LIBEV,          "libev" },
#endif
#ifdef USE_SOLARIS_DEVPOLL
		{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
#endif
#ifdef USE_SOLARIS_PORT
		{ FDEVENT_HANDLER_SOLARIS_PORT,   "solaris-eventports" },
#endif
#ifdef USE_FREEBSD_KQUEUE
		{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
#endif
		{ FDEVENT_HANDLER_UNSET,          NULL }
	};

	buffer_copy_string_len(b, CONST_STR_LEN(
			   "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
			   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
			   "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
			   "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
			   " <head>\n"
			   "  <title>Status</title>\n"
			   " </head>\n"
			   " <body>\n"
			   "  <h1>" PACKAGE_DESC "</h1>\n"
			   "  <table summary=\"status\" border=\"1\">\n"));

	mod_status_header_append(b, "Server-Features");
#ifdef HAVE_PCRE_H
	mod_status_row_append(b, "RegEx Conditionals", "enabled");
#else
	mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
#endif
	mod_status_header_append(b, "Network Engine");

	for (i = 0; event_handlers[i].name; i++) {
		if (event_handlers[i].et == srv->event_handler) {
			mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
			break;
		}
	}

	mod_status_header_append(b, "Config-File-Settings");

	for (i = 0; i < srv->plugins.used; i++) {
		plugin **ps = srv->plugins.ptr;

		plugin *pl = ps[i];

		if (i == 0) {
			buffer_copy_buffer(m, pl->name);
		} else {
			buffer_append_string_len(m, CONST_STR_LEN("<br />"));
			buffer_append_string_buffer(m, pl->name);
		}
	}

	mod_status_row_append(b, "Loaded Modules", m->ptr);

	buffer_append_string_len(b, CONST_STR_LEN("  </table>\n"));

	buffer_append_string_len(b, CONST_STR_LEN(
		      " </body>\n"
		      "</html>\n"
		      ));

	chunkqueue_append_buffer(con->write_queue, b);
	buffer_free(b);

	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));

	con->http_status = 200;
	con->file_finished = 1;

	return HANDLER_FINISHED;
}
Example #10
0
static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) {
	plugin_data *p = p_d;
	buffer *b = buffer_init();
	size_t j;
	double avg;
	char multiplier = '\0';
	char buf[32];
	time_t ts;

	int days, hours, mins, seconds;

	buffer_copy_string_len(b, CONST_STR_LEN(
				 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
				 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
				 "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
				 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
				 " <head>\n"
				 "  <title>Status</title>\n"

				   "  <style type=\"text/css\">\n"
				   "    table.status { border: black solid thin; }\n"
				   "    td { white-space: nowrap; }\n"
				   "    td.int { background-color: #f0f0f0; text-align: right }\n"
				   "    td.string { background-color: #f0f0f0; text-align: left }\n"
				   "    th.status { background-color: black; color: white; font-weight: bold; }\n"
				   "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
				   "    span.sortarrow { color: white; text-decoration: none; }\n"
				   "  </style>\n"));

	if (p->conf.sort) {
		buffer_append_string_len(b, CONST_STR_LEN(
					   "<script type=\"text/javascript\">\n"
					   "// <!--\n"
					   "var sort_column;\n"
					   "var prev_span = null;\n"

					   "function get_inner_text(el) {\n"
					   " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
					   "  return el;\n"
					   " if(el.innerText)\n"
					   "  return el.innerText;\n"
					   " else {\n"
					   "  var str = \"\";\n"
					   "  var cs = el.childNodes;\n"
					   "  var l = cs.length;\n"
					   "  for (i=0;i<l;i++) {\n"
					   "   if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n"
					   "   else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n"
					   "  }\n"
					   " }\n"
					   " return str;\n"
					   "}\n"

					   "function sortfn(a,b) {\n"
					   " var at = get_inner_text(a.cells[sort_column]);\n"
					   " var bt = get_inner_text(b.cells[sort_column]);\n"
					   " if (a.cells[sort_column].className == 'int') {\n"
					   "  return parseInt(at)-parseInt(bt);\n"
					   " } else {\n"
					   "  aa = at.toLowerCase();\n"
					   "  bb = bt.toLowerCase();\n"
					   "  if (aa==bb) return 0;\n"
					   "  else if (aa<bb) return -1;\n"
					   "  else return 1;\n"
					   " }\n"
					   "}\n"

					   "function resort(lnk) {\n"
					   " var span = lnk.childNodes[1];\n"
					   " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n"
					   " var rows = new Array();\n"
					   " for (j=1;j<table.rows.length;j++)\n"
					   "  rows[j-1] = table.rows[j];\n"
					   " sort_column = lnk.parentNode.cellIndex;\n"
					   " rows.sort(sortfn);\n"

					   " if (prev_span != null) prev_span.innerHTML = '';\n"
					   " if (span.getAttribute('sortdir')=='down') {\n"
					   "  span.innerHTML = '&uarr;';\n"
					   "  span.setAttribute('sortdir','up');\n"
					   "  rows.reverse();\n"
					   " } else {\n"
					   "  span.innerHTML = '&darr;';\n"
					   "  span.setAttribute('sortdir','down');\n"
					   " }\n"
					   " for (i=0;i<rows.length;i++)\n"
					   "  table.tBodies[0].appendChild(rows[i]);\n"
					   " prev_span = span;\n"
					   "}\n"
					   "// -->\n"
					   "</script>\n"));
	}

	buffer_append_string_len(b, CONST_STR_LEN(
				 " </head>\n"
				 " <body>\n"));



	/* connection listing */
	buffer_append_string_len(b, CONST_STR_LEN("<h1>Server-Status (" PACKAGE_NAME " " PACKAGE_VERSION ")</h1>"));

	buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">"));
	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Hostname</td><td class=\"string\">"));
	buffer_append_string_buffer(b, con->uri.authority);
	buffer_append_string_len(b, CONST_STR_LEN(" ("));
	buffer_append_string_buffer(b, con->server_name);
	buffer_append_string_len(b, CONST_STR_LEN(")</td></tr>\n"));
	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Uptime</td><td class=\"string\">"));

	ts = srv->cur_ts - srv->startup_ts;

	days = ts / (60 * 60 * 24);
	ts %= (60 * 60 * 24);

	hours = ts / (60 * 60);
	ts %= (60 * 60);

	mins = ts / (60);
	ts %= (60);

	seconds = ts;

	if (days) {
		buffer_append_int(b, days);
		buffer_append_string_len(b, CONST_STR_LEN(" days "));
	}

	if (hours) {
		buffer_append_int(b, hours);
		buffer_append_string_len(b, CONST_STR_LEN(" hours "));
	}

	if (mins) {
		buffer_append_int(b, mins);
		buffer_append_string_len(b, CONST_STR_LEN(" min "));
	}

	buffer_append_int(b, seconds);
	buffer_append_string_len(b, CONST_STR_LEN(" s"));

	buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Started at</td><td class=\"string\">"));

	ts = srv->startup_ts;

	strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
	buffer_append_string(b, buf);
	buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));


	buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"));

	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
	avg = p->abs_requests;

	mod_status_get_multiplier(&avg, &multiplier, 1000);

	buffer_append_int(b, avg);
	buffer_append_string_len(b, CONST_STR_LEN(" "));
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	buffer_append_string_len(b, CONST_STR_LEN("req</td></tr>\n"));

	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
	avg = p->abs_traffic_out;

	mod_status_get_multiplier(&avg, &multiplier, 1024);

	sprintf(buf, "%.2f", avg);
	buffer_append_string(b, buf);
	buffer_append_string_len(b, CONST_STR_LEN(" "));
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	buffer_append_string_len(b, CONST_STR_LEN("byte</td></tr>\n"));



	buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (since start)</th></tr>\n"));

	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
	avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);

	mod_status_get_multiplier(&avg, &multiplier, 1000);

	buffer_append_int(b, avg);
	buffer_append_string_len(b, CONST_STR_LEN(" "));
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));

	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
	avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);

	mod_status_get_multiplier(&avg, &multiplier, 1024);

	sprintf(buf, "%.2f", avg);
	buffer_append_string(b, buf);
	buffer_append_string_len(b, CONST_STR_LEN(" "));
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));



	buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"));
	for (j = 0, avg = 0; j < 5; j++) {
		avg += p->mod_5s_requests[j];
	}

	avg /= 5;

	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));

	mod_status_get_multiplier(&avg, &multiplier, 1000);

	buffer_append_int(b, avg);
	buffer_append_string_len(b, CONST_STR_LEN(" "));
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);

	buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));

	for (j = 0, avg = 0; j < 5; j++) {
		avg += p->mod_5s_traffic_out[j];
	}

	avg /= 5;

	buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));

	mod_status_get_multiplier(&avg, &multiplier, 1024);

	sprintf(buf, "%.2f", avg);
	buffer_append_string(b, buf);
	buffer_append_string_len(b, CONST_STR_LEN(" "));
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));

	buffer_append_string_len(b, CONST_STR_LEN("</table>\n"));


	buffer_append_string_len(b, CONST_STR_LEN(
		"<hr />\n<pre><b>legend</b>\n"
		". = connect, C = close, E = hard error, k = keep-alive\n"
		"r = read, R = read-POST, W = write, h = handle-request\n"
		"q = request-start,  Q = request-end\n"
		"s = response-start, S = response-end\n"));

	buffer_append_string_len(b, CONST_STR_LEN("<b>"));
	buffer_append_int(b, srv->conns->used);
	buffer_append_string_len(b, CONST_STR_LEN(" connections</b>\n"));

	for (j = 0; j < srv->conns->used; j++) {
		connection *c = srv->conns->ptr[j];
		const char *state;

		if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri)) {
			state = "k";
		} else {
			state = connection_get_short_state(c->state);
		}

		buffer_append_string_len(b, state, 1);

		if (((j + 1) % 50) == 0) {
			buffer_append_string_len(b, CONST_STR_LEN("\n"));
		}
	}

	buffer_append_string_len(b, CONST_STR_LEN("\n</pre><hr />\n<h2>Connections</h2>\n"));

	buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">\n"));
	buffer_append_string_len(b, CONST_STR_LEN("<tr>"));
	mod_status_header_append_sort(b, p_d, "Client IP");
	mod_status_header_append_sort(b, p_d, "Read");
	mod_status_header_append_sort(b, p_d, "Written");
	mod_status_header_append_sort(b, p_d, "State");
	mod_status_header_append_sort(b, p_d, "Time");
	mod_status_header_append_sort(b, p_d, "Host");
	mod_status_header_append_sort(b, p_d, "URI");
	mod_status_header_append_sort(b, p_d, "File");
	buffer_append_string_len(b, CONST_STR_LEN("</tr>\n"));

	for (j = 0; j < srv->conns->used; j++) {
		connection *c = srv->conns->ptr[j];

		buffer_append_string_len(b, CONST_STR_LEN("<tr><td class=\"string\">"));

		buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));

		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));

		if (c->request.content_length) {
			buffer_append_int(b, c->request_content_queue->bytes_in);
			buffer_append_string_len(b, CONST_STR_LEN("/"));
			buffer_append_int(b, c->request.content_length);
		} else {
			buffer_append_string_len(b, CONST_STR_LEN("0/0"));
		}

		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));

		buffer_append_int(b, c->write_queue->bytes_out);
		buffer_append_string_len(b, CONST_STR_LEN("/"));
		buffer_append_int(b, c->write_queue->bytes_out + chunkqueue_length(c->write_queue));

		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));

		if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri)) {
			buffer_append_string_len(b, CONST_STR_LEN("keep-alive"));
		} else {
			buffer_append_string(b, connection_get_state(c->state));
		}

		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));

		buffer_append_int(b, srv->cur_ts - c->request_start);

		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));

		if (buffer_string_is_empty(c->server_name)) {
			buffer_append_string_buffer(b, c->uri.authority);
		}
		else {
			buffer_append_string_buffer(b, c->server_name);
		}

		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));

		if (!buffer_string_is_empty(c->uri.path)) {
			buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
		}

		if (!buffer_string_is_empty(c->uri.query)) {
			buffer_append_string_len(b, CONST_STR_LEN("?"));
			buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.query), ENCODING_HTML);
		}

		if (!buffer_string_is_empty(c->request.orig_uri)) {
			buffer_append_string_len(b, CONST_STR_LEN(" ("));
			buffer_append_string_encoded(b, CONST_BUF_LEN(c->request.orig_uri), ENCODING_HTML);
			buffer_append_string_len(b, CONST_STR_LEN(")"));
		}
		buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));

		buffer_append_string_buffer(b, c->physical.path);

		buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
	}


	buffer_append_string_len(b, CONST_STR_LEN(
		      "</table>\n"));


	buffer_append_string_len(b, CONST_STR_LEN(
		      " </body>\n"
		      "</html>\n"
		      ));

	chunkqueue_append_buffer(con->write_queue, b);
	buffer_free(b);

	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));

	return 0;
}
Example #11
0
static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
	int multipart = 0;
	int error;
	off_t start, end;
	const char *s, *minus;
	char *boundary = "fkj49sn38dcn3";
	data_string *ds;
	stat_cache_entry *sce = NULL;
	buffer *content_type = NULL;

	if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
		SEGFAULT();
	}

	start = 0;
	end = sce->st.st_size - 1;

	con->response.content_length = 0;

	if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
		content_type = ds->value;
	}

	for (s = con->request.http_range, error = 0;
	     !error && *s && NULL != (minus = strchr(s, '-')); ) {
		char *err;
		off_t la, le;

		if (s == minus) {
			/* -<stop> */

			le = strtoll(s, &err, 10);

			if (le == 0) {
				/* RFC 2616 - 14.35.1 */

				con->http_status = 416;
				error = 1;
			} else if (*err == '\0') {
				/* end */
				s = err;

				end = sce->st.st_size - 1;
				start = sce->st.st_size + le;
			} else if (*err == ',') {
				multipart = 1;
				s = err + 1;

				end = sce->st.st_size - 1;
				start = sce->st.st_size + le;
			} else {
				error = 1;
			}

		} else if (*(minus+1) == '\0' || *(minus+1) == ',') {
			/* <start>- */

			la = strtoll(s, &err, 10);

			if (err == minus) {
				/* ok */

				if (*(err + 1) == '\0') {
					s = err + 1;

					end = sce->st.st_size - 1;
					start = la;

				} else if (*(err + 1) == ',') {
					multipart = 1;
					s = err + 2;

					end = sce->st.st_size - 1;
					start = la;
				} else {
					error = 1;
				}
			} else {
				/* error */
				error = 1;
			}
		} else {
			/* <start>-<stop> */

			la = strtoll(s, &err, 10);

			if (err == minus) {
				le = strtoll(minus+1, &err, 10);

				/* RFC 2616 - 14.35.1 */
				if (la > le) {
					error = 1;
				}

				if (*err == '\0') {
					/* ok, end*/
					s = err;

					end = le;
					start = la;
				} else if (*err == ',') {
					multipart = 1;
					s = err + 1;

					end = le;
					start = la;
				} else {
					/* error */

					error = 1;
				}
			} else {
				/* error */

				error = 1;
			}
		}

		if (!error) {
			if (start < 0) start = 0;

			/* RFC 2616 - 14.35.1 */
			if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;

			if (start > sce->st.st_size - 1) {
				error = 1;

				con->http_status = 416;
			}
		}

		if (!error) {
			if (multipart) {
				/* write boundary-header */
				buffer *b = buffer_init();

				buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));
				buffer_append_string(b, boundary);

				/* write Content-Range */
				buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));
				buffer_append_int(b, start);
				buffer_append_string_len(b, CONST_STR_LEN("-"));
				buffer_append_int(b, end);
				buffer_append_string_len(b, CONST_STR_LEN("/"));
				buffer_append_int(b, sce->st.st_size);

				buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: "));
				buffer_append_string_buffer(b, content_type);

				/* write END-OF-HEADER */
				buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));

				con->response.content_length += buffer_string_length(b);
				chunkqueue_append_buffer(con->write_queue, b);
				buffer_free(b);
			}

			chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
			con->response.content_length += end - start + 1;
		}
	}

	/* something went wrong */
	if (error) return -1;

	if (multipart) {
		/* add boundary end */
		buffer *b = buffer_init();

		buffer_copy_string_len(b, "\r\n--", 4);
		buffer_append_string(b, boundary);
		buffer_append_string_len(b, "--\r\n", 4);

		con->response.content_length += buffer_string_length(b);
		chunkqueue_append_buffer(con->write_queue, b);
		buffer_free(b);

		/* set header-fields */

		buffer_copy_string_len(p->range_buf, CONST_STR_LEN("multipart/byteranges; boundary="));
		buffer_append_string(p->range_buf, boundary);

		/* overwrite content-type */
		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
	} else {
		/* add Content-Range-header */

		buffer_copy_string_len(p->range_buf, CONST_STR_LEN("bytes "));
		buffer_append_int(p->range_buf, start);
		buffer_append_string_len(p->range_buf, CONST_STR_LEN("-"));
		buffer_append_int(p->range_buf, end);
		buffer_append_string_len(p->range_buf, CONST_STR_LEN("/"));
		buffer_append_int(p->range_buf, sce->st.st_size);

		response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
	}

	/* ok, the file is set-up */
	return 0;
}