static bool_t getPage(EFSRepoRef const repo, HTTPConnectionRef const conn, HTTPMethod const method, strarg_t const URI) {
	if(HTTP_GET != method) return false;
	size_t pathlen = prefix("/", URI);
	if(!pathlen) return false;
	if(!pathterm(URI, (size_t)pathlen)) return false;
	EFSSessionRef const session = auth(repo, conn, method, URI+pathlen);
	if(!session) {
		HTTPConnectionSendStatus(conn, 403);
		return true;
	}

	// TODO: Parse querystring `q` parameter
	EFSFilterRef const filter = EFSFilterCreate(EFSTypeFilter);
	EFSFilterAddStringArg(filter, "text/html; charset=utf-8");

	EFSFileInfo *const files = EFSSessionCreateFileInfoList(session, filter, RESULTS_MAX);

	HTTPConnectionWriteResponse(conn, 200, "OK");
	HTTPConnectionWriteHeader(conn, "Content-Type", "text/html; charset=utf-8");
	HTTPConnectionWriteHeader(conn, "Transfer-Encoding", "chunked");
	HTTPConnectionBeginBody(conn);

	// TODO: Page header

	uv_fs_t req = { .data = co_active(); }
	for(index_t i = 0; i < files->count; ++i) {
		uv_fs_open(loop, &req, path, O_RDONLY, 0400, async_fs_cb);
		co_switch(yield);
		uv_fs_req_cleanup(&req);
		uv_file const file = req.result;
		if(file < 0) continue;
		HTTPConnectionWriteChunkLength(conn, files->items[i].size);
		HTTPConnectionWriteFile(conn, file);
		uv_fs_close(loop, &req, file, async_fs_cb);
		co_switch(yield);
		uv_fs_req_cleanup(&req);
		HTTPConnectionWrite(conn, "\r\n", 2);
	}

	// TODO: Page trailer

	HTTPConnectionWriteChunkLength(conn, 0);
	HTTPConnectionWrite(conn, "\r\n", 2);
	HTTPConnectionEnd(conn);

	EFSFileInfoListFree(files);
	return true;
}
Example #2
0
int HTTPConnectionWriteChunkFile(HTTPConnectionRef const conn, strarg_t const path) {
	bool worker = false;
	uv_file file = -1;
	byte_t *buf = NULL;
	int rc;

	async_pool_enter(NULL); worker = true;
	rc = async_fs_open(path, O_RDONLY, 0000);
	if(rc < 0) goto cleanup;
	file = rc;

	buf = malloc(BUFFER_SIZE);
	if(!buf) rc = UV_ENOMEM;
	if(rc < 0) goto cleanup;

	uv_buf_t const chunk = uv_buf_init((char *)buf, BUFFER_SIZE);
	ssize_t len = async_fs_readall_simple(file, &chunk);
	if(len < 0) rc = len;
	if(rc < 0) goto cleanup;

	// Fast path for small files.
	if(len < BUFFER_SIZE) {
		str_t pfx[16];
		int const pfxlen = snprintf(pfx, sizeof(pfx), "%llx\r\n", (unsigned long long)len);
		if(pfxlen < 0) rc = UV_UNKNOWN;
		if(rc < 0) goto cleanup;

		uv_buf_t parts[] = {
			uv_buf_init(pfx, pfxlen),
			uv_buf_init((char *)buf, len),
			uv_buf_init((char *)STR_LEN("\r\n")),
		};
		async_fs_close(file); file = -1;
		async_pool_leave(NULL); worker = false;
		rc = HTTPConnectionWritev(conn, parts, numberof(parts));
		goto cleanup;
	}

	uv_fs_t req[1];
	rc = async_fs_fstat(file, req);
	if(rc < 0) goto cleanup;
	if(0 == req->statbuf.st_size) goto cleanup;

	async_pool_leave(NULL); worker = false;

	// TODO: HACK, WriteFile continues from where we left off
	rc = rc < 0 ? rc : HTTPConnectionWriteChunkLength(conn, req->statbuf.st_size);
	rc = rc < 0 ? rc : HTTPConnectionWritev(conn, &chunk, 1);
	rc = rc < 0 ? rc : HTTPConnectionWriteFile(conn, file);
	rc = rc < 0 ? rc : HTTPConnectionWrite(conn, (byte_t const *)STR_LEN("\r\n"));

cleanup:
	FREE(&buf);
	if(file >= 0) { async_fs_close(file); file = -1; }
	if(worker) { async_pool_leave(NULL); worker = false; }
	assert(file < 0);
	assert(!worker);
	return rc;
}
Example #3
0
int HTTPConnectionWriteChunkv(HTTPConnectionRef const conn, uv_buf_t const parts[], unsigned int const count) {
	if(!conn) return 0;
	uint64_t total = 0;
	for(size_t i = 0; i < count; i++) total += parts[i].len;
	if(total <= 0) return 0;
	int rc = 0;
	rc = rc < 0 ? rc : HTTPConnectionWriteChunkLength(conn, total);
	rc = rc < 0 ? rc : async_write((uv_stream_t *)conn->stream, parts, count);
	rc = rc < 0 ? rc : HTTPConnectionWrite(conn, (byte_t const *)STR_LEN("\r\n"));
	return rc;
}