Beispiel #1
0
static void proxy_send_headers(liVRequest *vr, proxy_connection *pcon) {
	GString *head = g_string_sized_new(4095);
	liHttpHeader *header;
	GList *iter;
	gchar *enc_path;

	g_string_append_len(head, GSTR_LEN(vr->request.http_method_str));
	g_string_append_len(head, CONST_STR_LEN(" "));

	enc_path = g_uri_escape_string(vr->request.uri.path->str, "/", FALSE);
	g_string_append(head, enc_path);
	g_free(enc_path);

	if (vr->request.uri.query->len > 0) {
		g_string_append_len(head, CONST_STR_LEN("?"));
		g_string_append_len(head, GSTR_LEN(vr->request.uri.query));
	}

	switch (vr->request.http_version) {
	case LI_HTTP_VERSION_1_1:
		/* g_string_append_len(head, CONST_STR_LEN(" HTTP/1.1\r\n")); */
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	case LI_HTTP_VERSION_1_0:
	default:
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	}

	for (iter = g_queue_peek_head_link(&vr->request.headers->entries); iter; iter = g_list_next(iter)) {
		header = (liHttpHeader*) iter->data;
		if (li_http_header_key_is(header, CONST_STR_LEN("Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Proxy-Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-Proto"))) continue;
		g_string_append_len(head, GSTR_LEN(header->data));
		g_string_append_len(head, CONST_STR_LEN("\r\n"));
	}

	g_string_append_len(head, CONST_STR_LEN("X-Forwarded-For: "));
	g_string_append_len(head, GSTR_LEN(vr->coninfo->remote_addr_str));
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	if (vr->coninfo->is_ssl) {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: https\r\n"));
	} else {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: http\r\n"));
	}

	/* terminate http header */
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	li_chunkqueue_append_string(pcon->proxy_out, head);
}
Beispiel #2
0
/** uses/modifies wrk->tmp_str */
static void try_append_file(liVRequest *vr, GString **curbuf, const gchar *filename, gboolean encode_html) {
	GString *f = vr->wrk->tmp_str;
	g_string_truncate(f, 0);
	g_string_append_len(f, GSTR_LEN(vr->physical.path));
	li_path_append_slash(f);
	g_string_append(f, filename);

	if (!encode_html) {
		int fd;
		struct stat st;

		while (-1 == (fd = open(f->str, O_RDONLY))) {
			if (errno == EINTR)
				continue;
			return; /* failed to open, ignore */
		}
		if (-1 == fstat(fd, &st)) {
			close(fd);
			return; /* failed to open, ignore */
		}
		if (st.st_size > MAX_INCLUDE_FILE_SIZE) {
			close(fd);
			return; /* file too big, ignore */
		}

		/* flush current buffer and append file */
		li_chunkqueue_append_string(vr->direct_out, *curbuf);
		*curbuf = g_string_sized_new(4*1024-1);
		li_chunkqueue_append_file_fd(vr->direct_out, NULL, 0, st.st_size, fd);
	} else {
		GError *error = NULL;
		gchar *contents;
		gsize length;

		if (!g_file_get_contents(f->str, &contents, &length, &error)) {
			g_error_free(error);
			return; /* ignore errors */
		}
		if (length > MAX_INCLUDE_FILE_SIZE) {
			g_free(contents);
			return; /* file too big, ignore */
		}

		g_string_append_len(*curbuf, CONST_STR_LEN("<pre>"));
		li_string_encode_append(contents, *curbuf, LI_ENCODING_HTML);
		g_string_append_len(*curbuf, CONST_STR_LEN("</pre>"));
		g_free(contents);
	}
}
Beispiel #3
0
static liHandlerResult dirlist(liVRequest *vr, gpointer param, gpointer *context) {
	GString *listing;
	liStatCacheEntry *sce;
	dirlist_data *dd;

	UNUSED(context);

	switch (vr->request.http_method) {
	case LI_HTTP_METHOD_GET:
	case LI_HTTP_METHOD_HEAD:
		break;
	default:
		return LI_HANDLER_GO_ON;
	}

	if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON;

	if (vr->physical.path->len == 0) return LI_HANDLER_GO_ON;

	switch (li_stat_cache_get_dirlist(vr, vr->physical.path, &sce)) {
	case LI_HANDLER_GO_ON: break;
	case LI_HANDLER_WAIT_FOR_EVENT: return LI_HANDLER_WAIT_FOR_EVENT;
	default: return LI_HANDLER_ERROR;
	}

	dd = param;

	if (sce->data.failed) {
		/* stat failed */
		int e = sce->data.err;

		li_stat_cache_entry_release(vr, sce);

		switch (e) {
		case ENOENT:
		case ENOTDIR:
			return LI_HANDLER_GO_ON;
		case EACCES:
			if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR;
			vr->response.http_status = 403;
			return LI_HANDLER_GO_ON;
		default:
			VR_ERROR(vr, "stat('%s') failed: %s", sce->data.path->str, g_strerror(sce->data.err));
			return LI_HANDLER_ERROR;
		}
	} else if (!S_ISDIR(sce->data.st.st_mode)) {
		li_stat_cache_entry_release(vr, sce);
		return LI_HANDLER_GO_ON;
	} else if (vr->request.uri.path->len == 0 || vr->request.uri.path->str[vr->request.uri.path->len-1] != '/') {
		li_stat_cache_entry_release(vr, sce);
		li_vrequest_redirect_directory(vr);
		return LI_HANDLER_GO_ON;
	} else {
		/* everything ok, we have the directory listing */
		gboolean cachable;
		guint i, j;
		liStatCacheEntryData *sced;
		GString *mime_str, *encoded;
		GArray *directories, *files;
		gchar sizebuf[sizeof("999.9K")+1];
		gchar datebuf[sizeof("2005-Jan-01 22:23:24")+1];
		guint datebuflen;
		struct tm tm;
		gboolean hide;

		if (!li_vrequest_handle_direct(vr)) {
			li_stat_cache_entry_release(vr, sce);
			return LI_HANDLER_ERROR;
		}
		vr->response.http_status = 200;

		if (dd->debug)
			VR_DEBUG(vr, "dirlist for \"%s\", %u entries", sce->data.path->str, sce->dirlist->len);

		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), GSTR_LEN(dd->content_type));
		li_etag_set_header(vr, &sce->data.st, &cachable);
		if (cachable) {
			vr->response.http_status = 304;
			li_stat_cache_entry_release(vr, sce);
			return LI_HANDLER_GO_ON;
		}

		/* temporary string for encoded names */
		encoded = g_string_sized_new(64-1);

		/* seperate directories from other files */
		directories = g_array_sized_new(FALSE, FALSE, sizeof(guint), 16);
		files = g_array_sized_new(FALSE, FALSE, sizeof(guint), sce->dirlist->len);
		for (i = 0; i < sce->dirlist->len; i++) {
			sced = &g_array_index(sce->dirlist, liStatCacheEntryData, i);
			hide = FALSE;

			/* ingore entries where the stat() failed */
			if (sced->failed)
				continue;

			if (dd->hide_dotfiles && sced->path->str[0] == '.')
				continue;

			if (dd->hide_tildefiles && sced->path->str[sced->path->len-1] == '~')
				continue;

			for (j = 0; j < dd->exclude_suffix->len; j++) {
				if (li_string_suffix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_suffix, j)))) {
					hide = TRUE;
					break;
				}
			}

			if (hide)
				continue;

			for (j = 0; j < dd->exclude_prefix->len; j++) {
				if (li_string_prefix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_prefix, j)))) {
					hide = TRUE;
					break;
				}
			}

			if (hide)
				continue;

			if (S_ISDIR(sced->st.st_mode)) {
				if (dd->hide_directories) continue;
				g_array_append_val(directories, i);
			} else {
				if ((dd->include_header || dd->hide_header) && g_str_equal(sced->path, "HEADER.txt")) {
					if (dd->hide_header) continue;
				} else if ((dd->include_readme || dd->hide_readme) && g_str_equal(sced->path, "README.txt")) {
					if (dd->hide_readme) continue;
				}
				g_array_append_val(files, i);
			}
		}

		listing = g_string_sized_new(4*1024-1);
		g_string_append_printf(listing, html_header_start, vr->request.uri.path->str);

		if (dd->css) {
			/* custom css */
			g_string_append_len(listing, CONST_STR_LEN("		<link rel=\"stylesheet\" type=\"text/css\" href=\""));
			g_string_append_len(listing, GSTR_LEN(dd->css));
			g_string_append_len(listing, CONST_STR_LEN("\" />\n"));
		} else {
			/* default css */
			g_string_append_len(listing, CONST_STR_LEN(html_css));
		}
		g_string_append_len(listing, CONST_STR_LEN(html_header_end));

		try_append_file(vr, &listing, "HEADER.txt", dd->encode_header);

		g_string_append_printf(listing, html_table_start, vr->request.uri.path->str);

		if (0 != strcmp("/", vr->request.uri.path->str)) {
			g_string_append_printf(listing, html_table_row, '0', "../",
				"Parent Directory", (gint64)0, "", (gint64)0, "-", "Directory");
		}

		/* list directories */
		if (!dd->hide_directories) {
			for (i = 0; i < directories->len; i++) {
				sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(directories, guint, i));

				localtime_r(&(sced->st.st_mtime), &tm);
				datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
				datebuf[datebuflen] = '\0';

				g_string_append_len(listing, CONST_STR_LEN("				<tr group=\"1\"><td><a href=\""));
				li_string_encode(sced->path->str, encoded, LI_ENCODING_URI);
				g_string_append_len(listing, GSTR_LEN(encoded));
				g_string_append_len(listing, CONST_STR_LEN("/\">"));
				li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML);
				g_string_append_len(listing, GSTR_LEN(encoded));
				g_string_append_len(listing, CONST_STR_LEN("</a></td><td class=\"modified\" val=\""));
				li_string_append_int(listing, sced->st.st_mtime);
				g_string_append_len(listing, CONST_STR_LEN("\">"));
				g_string_append_len(listing, datebuf, datebuflen);
				g_string_append_len(listing, CONST_STR_LEN("</td>"
					"<td class=\"size\" val=\"0\">-</td>"
					"<td class=\"type\">Directory</td></tr>\n"));
			}
		}

		/*g_string_append_len(listing, CONST_STR_LEN("<tr><td colspan=\"4\">&nbsp;</td></tr>\n"));*/

		/* list files */
		for (i = 0; i < files->len; i++) {
			sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(files, guint, i));
			mime_str = li_mimetype_get(vr, sced->path);

			localtime_r(&(sced->st.st_mtime), &tm);
			datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
			datebuf[datebuflen] = '\0';

			dirlist_format_size(sizebuf, sced->st.st_size);

			g_string_append_len(listing, CONST_STR_LEN("				<tr group=\"2\"><td><a href=\""));
			li_string_encode(sced->path->str, encoded, LI_ENCODING_URI);
			g_string_append_len(listing, GSTR_LEN(encoded));
			g_string_append_len(listing, CONST_STR_LEN("\">"));
			li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML);
			g_string_append_len(listing, GSTR_LEN(encoded));
			g_string_append_len(listing, CONST_STR_LEN(
				"</a></td>"
				"<td class=\"modified\" val=\""));
			li_string_append_int(listing, sced->st.st_mtime);
			g_string_append_len(listing, CONST_STR_LEN("\">"));
			g_string_append_len(listing, datebuf, datebuflen);
			g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"size\" val=\""));
			li_string_append_int(listing, sced->st.st_size);
			g_string_append_len(listing, CONST_STR_LEN("\">"));
			g_string_append(listing, sizebuf);
			g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"type\">"));
			if (mime_str) {
				g_string_append_len(listing, GSTR_LEN(mime_str));
			} else {
				g_string_append_len(listing, CONST_STR_LEN("application/octet-stream"));
			}
			g_string_append_len(listing, CONST_STR_LEN("</td></tr>\n"));

			/*
			g_string_append_printf(listing, html_table_row,
				sced->path->str, sced->path->str,
				(gint64)sced->st.st_mtime, datebuf,
				sced->st.st_size, sizebuf,
				mime_str ? mime_str->str : "application/octet-stream");
			*/
		}

		g_string_append_len(listing, CONST_STR_LEN(html_table_end));

		try_append_file(vr, &listing, "README.txt", dd->encode_readme);

		if (dd->include_sort) {
			g_string_append_len(listing, CONST_STR_LEN(javascript_sort));
		}

		g_string_append_printf(listing, html_footer, CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string->str);

		li_chunkqueue_append_string(vr->direct_out, listing);
		g_string_free(encoded, TRUE);
		g_array_free(directories, TRUE);
		g_array_free(files, TRUE);
	}

	li_stat_cache_entry_release(vr, sce);

	return LI_HANDLER_GO_ON;
}
Beispiel #4
0
/* the CollectCallback */
static void progress_collect_cb(gpointer cbdata, gpointer fdata, GPtrArray *result, gboolean complete) {
	guint i;
	GString *output;
	mod_progress_node *node = NULL;
	mod_progress_job *job = fdata;
	liVRequest *vr = job->vr;
	gboolean debug = job->debug;
	mod_progress_format format = job->format;

	UNUSED(cbdata);

	if (complete) {
		/* clear context so it doesn't get cleaned up anymore */
		*(job->context) = NULL;

		for (i = 0; i < result->len; i++) {
			node = g_ptr_array_index(result, i);
			if (node)
				break;
		}

		output = g_string_sized_new(128);

		/* send mime-type. there seems to be no standard for javascript... using the most commong */
		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/x-javascript"));

		if (format == PROGRESS_FORMAT_LEGACY) {
			g_string_append_len(output, CONST_STR_LEN("new Object("));
		} else if (format == PROGRESS_FORMAT_JSONP) {
			gchar *val;
			guint len;

			if (li_querystring_find(vr->request.uri.query, CONST_STR_LEN("X-Progress-Callback"), &val, &len)) {
				/* X-Progress-Callback specified, need to check for xss */
				gchar *c;

				for (c = val; c != val+len; c++) {
					if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '.' || *c == '_')
						continue;
					break;
				}

				/* was there a bad char? */
				if (c != val+len) {
					g_string_append_len(output, CONST_STR_LEN("progress("));
				} else {
					g_string_append_len(output,val, len);
					g_string_append_c(output, '(');
				}
			} else {
				g_string_append_len(output, CONST_STR_LEN("progress("));
			}
		}

		if (!node) {
			/* progress id not known */
			if (debug)
				VR_DEBUG(vr, "progress.show: progress id \"%s\" unknown", job->id);
			
			g_string_append_len(output, CONST_STR_LEN("{\"state\": \"unknown\"}"));
		} else {
			if (debug)
				VR_DEBUG(vr, "progress.show: progress id \"%s\" found", job->id);

			if (node->vr) {
				/* still in progress */
				g_string_append_printf(output,
					"{\"state\": \"running\", \"received\": %"G_GUINT64_FORMAT", \"sent\": %"G_GUINT64_FORMAT", \"request_size\": %"G_GUINT64_FORMAT", \"response_size\": %"G_GUINT64_FORMAT"}",
					node->bytes_in, node->bytes_out, node->request_size, node->response_size
				);
			} else if (node->status_code == 200) {
				/* done, success */
				g_string_append_printf(output,
					"{\"state\": \"done\", \"received\": %"G_GUINT64_FORMAT", \"sent\": %"G_GUINT64_FORMAT", \"request_size\": %"G_GUINT64_FORMAT", \"response_size\": %"G_GUINT64_FORMAT"}",
					node->bytes_in, node->bytes_out, node->request_size, node->response_size
				);
			} else {
				/* done, error */
				g_string_append_printf(output,
					"{\"state\": \"error\", \"status\": %d}",
					node->status_code
				);
			}
		}

		if (format == PROGRESS_FORMAT_LEGACY || format == PROGRESS_FORMAT_JSONP) {
			g_string_append_c(output, ')');
		}

		vr->response.http_status = 200;
		li_chunkqueue_append_string(vr->out, output);
		li_vrequest_handle_direct(vr);
		li_vrequest_joblist_append(vr);
	}

	/* free results */
	for (i = 0; i < result->len; i++) {
		if (g_ptr_array_index(result, i))
			g_slice_free(mod_progress_node, g_ptr_array_index(result, i));
	}

	g_free(job->id);
	g_slice_free(mod_progress_job, job);
}
Beispiel #5
0
static void proxy_send_headers(liVRequest *vr, liChunkQueue *out) {
	GString *head = g_string_sized_new(4095);
	liHttpHeader *header;
	GList *iter;
	liHttpHeaderTokenizer header_tokenizer;
	GString *tmp_str = vr->wrk->tmp_str;

	g_string_append_len(head, GSTR_LEN(vr->request.http_method_str));
	g_string_append_len(head, CONST_STR_LEN(" "));

	g_string_append_len(head, GSTR_LEN(vr->request.uri.raw_path));

	switch (vr->request.http_version) {
	case LI_HTTP_VERSION_1_1:
		/* g_string_append_len(head, CONST_STR_LEN(" HTTP/1.1\r\n")); */
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	case LI_HTTP_VERSION_1_0:
	default:
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	}

	li_http_header_tokenizer_start(&header_tokenizer, vr->request.headers, CONST_STR_LEN("Connection"));
	while (li_http_header_tokenizer_next(&header_tokenizer, tmp_str)) {
		if (0 == g_ascii_strcasecmp(tmp_str->str, "Upgrade")) {
			g_string_append_len(head, CONST_STR_LEN("Connection: Upgrade\r\n"));
		}
	}

	if (LI_HTTP_METHOD_GET != vr->request.http_method && LI_HTTP_METHOD_HEAD != vr->request.http_method) {
		g_string_append_printf(head, "Content-Length: %" LI_GOFFSET_MODIFIER "i\r\n", vr->request.content_length);
	}

	for (iter = g_queue_peek_head_link(&vr->request.headers->entries); iter; iter = g_list_next(iter)) {
		header = (liHttpHeader*) iter->data;
		if (li_http_header_key_is(header, CONST_STR_LEN("Content-Length"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Transfer-Encoding"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("TE"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Proxy-Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-Proto"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-For"))) continue;
		g_string_append_len(head, GSTR_LEN(header->data));
		g_string_append_len(head, CONST_STR_LEN("\r\n"));
	}

	g_string_append_len(head, CONST_STR_LEN("X-Forwarded-For: "));
	g_string_append_len(head, GSTR_LEN(vr->coninfo->remote_addr_str));
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	if (vr->coninfo->is_ssl) {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: https\r\n"));
	} else {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: http\r\n"));
	}

	/* terminate http header */
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	li_chunkqueue_append_string(out, head);
}
Beispiel #6
0
gboolean li_response_send_headers(liConnection *con) {
	GString *head;
	liVRequest *vr = con->mainvr;

	if (vr->response.http_status < 100 || vr->response.http_status > 999) {
		VR_ERROR(vr, "wrong status: %i", vr->response.http_status);
		return FALSE;
	}

	head = g_string_sized_new(8*1024-1);

	if (0 == con->out->length && con->mainvr->backend == NULL
		&& vr->response.http_status >= 400 && vr->response.http_status < 600) {
		li_response_send_error_page(con);
	}

	if ((vr->response.http_status >= 100 && vr->response.http_status < 200) ||
	     vr->response.http_status == 204 ||
	     vr->response.http_status == 205 ||
	     vr->response.http_status == 304) {
		/* They never have a content-body/length */
		li_chunkqueue_reset(con->out);
		con->out->is_closed = TRUE;
		con->raw_out->is_closed = TRUE;
	} else if (con->out->is_closed) {
		if (vr->request.http_method != LI_HTTP_METHOD_HEAD || con->out->length > 0) {
			/* do not send content-length: 0 if backend already skipped content generation for HEAD */
			g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, con->out->length);
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Length"), GSTR_LEN(con->wrk->tmp_str));
		}
	} else if (con->info.keep_alive && vr->request.http_version == LI_HTTP_VERSION_1_1) {
		/* TODO: maybe someone set a content length header? */
		if (!(vr->response.transfer_encoding & LI_HTTP_TRANSFER_ENCODING_CHUNKED)) {
			vr->response.transfer_encoding |= LI_HTTP_TRANSFER_ENCODING_CHUNKED;
			li_http_header_append(vr->response.headers, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
		}
	} else {
		/* Unknown content length, no chunked encoding */
		con->info.keep_alive = FALSE;
	}

	if (vr->request.http_method == LI_HTTP_METHOD_HEAD) {
		/* content-length is set, but no body */
		li_chunkqueue_reset(con->out);
		con->out->is_closed = TRUE;
		con->raw_out->is_closed = TRUE;
	}

	/* Status line */
	if (vr->request.http_version == LI_HTTP_VERSION_1_1) {
		g_string_append_len(head, CONST_STR_LEN("HTTP/1.1 "));
		if (!con->info.keep_alive)
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
	} else {
		g_string_append_len(head, CONST_STR_LEN("HTTP/1.0 "));
		if (con->info.keep_alive)
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
	}

	{
		guint len;
		gchar status_str[4];
		gchar *str = li_http_status_string(vr->response.http_status, &len);
		li_http_status_to_str(vr->response.http_status, status_str);
		status_str[3] = ' ';
		g_string_append_len(head, status_str, 4);
		g_string_append_len(head, str, len);
		g_string_append_len(head, CONST_STR_LEN("\r\n"));
	}

	/* Append headers */
	{
		liHttpHeader *header;
		GList *iter;
		gboolean have_date = FALSE, have_server = FALSE;

		for (iter = g_queue_peek_head_link(&vr->response.headers->entries); iter; iter = g_list_next(iter)) {
			header = (liHttpHeader*) iter->data;
			g_string_append_len(head, GSTR_LEN(header->data));
			g_string_append_len(head, CONST_STR_LEN("\r\n"));
			if (!have_date && li_http_header_key_is(header, CONST_STR_LEN("date"))) have_date = TRUE;
			if (!have_server && li_http_header_key_is(header, CONST_STR_LEN("server"))) have_server = TRUE;
		}

		if (!have_date) {
			GString *d = li_worker_current_timestamp(con->wrk, LI_GMTIME, LI_TS_FORMAT_HEADER);
			/* HTTP/1.1 requires a Date: header */
			g_string_append_len(head, CONST_STR_LEN("Date: "));
			g_string_append_len(head, GSTR_LEN(d));
			g_string_append_len(head, CONST_STR_LEN("\r\n"));
		}

		if (!have_server) {
			GString *tag = CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string;

			if (tag->len) {
				g_string_append_len(head, CONST_STR_LEN("Server: "));
				g_string_append_len(head, GSTR_LEN(tag));
				g_string_append_len(head, CONST_STR_LEN("\r\n"));
			}
		}
	}

	g_string_append_len(head, CONST_STR_LEN("\r\n"));
	li_chunkqueue_append_string(con->raw_out, head);

	return TRUE;
}
Beispiel #7
0
void li_response_send_error_page(liConnection *con) {
	liVRequest *vr = con->mainvr;
	gchar status_code[3];
	guint len;
	gchar *str;
	GString *html;

	html = g_string_sized_new(1023);

	g_string_append_len(html, CONST_STR_LEN(
		"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
		"<html>\n"
		"	<head>\n"
		"		<title>"
	));

	li_http_status_to_str(con->mainvr->response.http_status, status_code);

	g_string_append_len(html, status_code, 3);
	g_string_append_len(html, CONST_STR_LEN(" - "));
	str = li_http_status_string(con->mainvr->response.http_status, &len);
	g_string_append_len(html, str, len);

	g_string_append_len(html, CONST_STR_LEN(
		"</title>\n"
		"		<style type=\"text/css\">\n"
		"			body { font-size: 62.5%; }\n"
		"			#container {\n"
		"				font-size: 62.5%;\n"
		"				max-width: 600px;\n"
		"				margin: auto;\n"
		"				margin-top: 2%;\n"
		"				border: 4px solid #efefef;\n"
		"				padding: 0px 20px;\n"
		"				color: #444;\n"
		"				font-family: Verdana,helvetica,sans-serif;\n"
		"				font-size: 1.25em;\n"
		"			}\n"
		"			h1 { color: #6D84B4; font-size: 1.5em; }\n"
		"			#footer { text-align: right; margin-top: 25px; }\n"
		"		</style>\n"
		"	</head>\n"
		"	<body>\n"
		"		<div id=\"container\">\n"
		"			<h1>Error "
	));

	g_string_append_len(html, status_code, 3);
	g_string_append_len(html, CONST_STR_LEN(" - "));
	g_string_append_len(html, str, len);
	g_string_append_len(html, CONST_STR_LEN("</h1>\n"));

	str = li_response_error_description(con->mainvr->response.http_status, &len);
	g_string_append_len(html, str, len);
	
	g_string_append_len(html, CONST_STR_LEN("			<p id=\"footer\">"));
	g_string_append_len(html, GSTR_LEN(CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string));
	g_string_append_len(html, CONST_STR_LEN(
		"</p>\n"
		"		</div>\n"
		"	</body>\n"
		"</html>\n"
	));

	li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html; charset=utf-8"));

	li_chunkqueue_append_string(con->out, html);
	li_http_header_remove(vr->response.headers, CONST_STR_LEN("transfer-encoding"));
	li_http_header_remove(vr->response.headers, CONST_STR_LEN("content-encoding"));
	li_http_header_remove(vr->response.headers, CONST_STR_LEN("etag"));
}