memory arenas (sort of)
This commit is contained in:
Binary file not shown.
+194
-192
@@ -61,24 +61,14 @@ FastCGIServer::Connection::Connection() :
|
|||||||
close_responsibility(false),
|
close_responsibility(false),
|
||||||
close_socket(false)
|
close_socket(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FastCGIServer::FastCGIServer()
|
||||||
int
|
|
||||||
FastCGIServer::HandlerBase::operator()(FastCGIRequest&)
|
|
||||||
{
|
{
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FastCGIServer::FastCGIServer() :
|
|
||||||
handle_request(new HandlerBase),
|
|
||||||
handle_data(new HandlerBase),
|
|
||||||
handle_complete(new HandlerBase)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FastCGIServer::~FastCGIServer()
|
FastCGIServer::~FastCGIServer()
|
||||||
{
|
{
|
||||||
if(my_pid != parent_pid) // if we're a child process, we must not close the handles
|
if(my_pid != parent_pid) // if we're a child process, we must not close the handles
|
||||||
@@ -101,38 +91,6 @@ FastCGIServer::~FastCGIServer()
|
|||||||
delete it->second;
|
delete it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete handle_request;
|
|
||||||
delete handle_data;
|
|
||||||
delete handle_complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FastCGIServer::request_handler(int (* function)(FastCGIRequest&))
|
|
||||||
{
|
|
||||||
handle_request = new StaticHandler(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FastCGIServer::data_handler(int (* function)(FastCGIRequest&))
|
|
||||||
{
|
|
||||||
handle_data = new StaticHandler(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FastCGIServer::complete_handler(int (* function)(FastCGIRequest&))
|
|
||||||
{
|
|
||||||
handle_complete = new StaticHandler(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FastCGIServer::set_handler(HandlerBase*& handler, HandlerBase* new_handler)
|
|
||||||
{
|
|
||||||
delete handler;
|
|
||||||
handler = new_handler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -313,6 +271,15 @@ FastCGIServer::process_forever()
|
|||||||
process();
|
process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
FastCGIServer::call_completion_handler(FastCGIRequest& request)
|
||||||
|
{
|
||||||
|
//printf("- request complete\n");
|
||||||
|
switch_to_arena(request.mem);
|
||||||
|
auto result = on_complete(request);
|
||||||
|
switch_to_system_alloc();
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FastCGIServer::process_connection_read(Connection& connection)
|
FastCGIServer::process_connection_read(Connection& connection)
|
||||||
@@ -336,153 +303,172 @@ FastCGIServer::process_connection_read(Connection& connection)
|
|||||||
|
|
||||||
RequestID request_id = (header.requestIdB1 << 8) + header.requestIdB0;
|
RequestID request_id = (header.requestIdB1 << 8) + header.requestIdB0;
|
||||||
|
|
||||||
switch (header.type) {
|
switch (header.type)
|
||||||
case FCGI_GET_VALUES: {
|
{
|
||||||
Pairs pairs = parse_pairs(content, content_length);
|
case FCGI_GET_VALUES:
|
||||||
|
{
|
||||||
|
Pairs pairs = parse_pairs(content, content_length);
|
||||||
|
|
||||||
std::string::size_type base = connection.output_buffer.size();
|
std::string::size_type base = connection.output_buffer.size();
|
||||||
connection.output_buffer.push_back(FCGI_VERSION_1);
|
connection.output_buffer.push_back(FCGI_VERSION_1);
|
||||||
connection.output_buffer.push_back(FCGI_GET_VALUES_RESULT);
|
connection.output_buffer.push_back(FCGI_GET_VALUES_RESULT);
|
||||||
connection.output_buffer.append(FCGI_HEADER_LEN - 2, 0);
|
connection.output_buffer.append(FCGI_HEADER_LEN - 2, 0);
|
||||||
|
|
||||||
for (Pairs::iterator it = pairs.begin(); it != pairs.end(); ++it)
|
for (Pairs::iterator it = pairs.begin(); it != pairs.end(); ++it)
|
||||||
if (it->first == FCGI_MAX_CONNS)
|
if (it->first == FCGI_MAX_CONNS)
|
||||||
write_pair(connection.output_buffer,
|
write_pair(connection.output_buffer,
|
||||||
it->first, std::string("100"));
|
it->first, std::string("100"));
|
||||||
else if (it->first == FCGI_MAX_REQS)
|
else if (it->first == FCGI_MAX_REQS)
|
||||||
write_pair(connection.output_buffer,
|
write_pair(connection.output_buffer,
|
||||||
it->first, std::string("1000"));
|
it->first, std::string("1000"));
|
||||||
else if (it->first == FCGI_MPXS_CONNS)
|
else if (it->first == FCGI_MPXS_CONNS)
|
||||||
write_pair(connection.output_buffer,
|
write_pair(connection.output_buffer,
|
||||||
it->first, std::string("1"));
|
it->first, std::string("1"));
|
||||||
|
|
||||||
std::string::size_type len = connection.output_buffer.size() - base;
|
std::string::size_type len = connection.output_buffer.size() - base;
|
||||||
connection.output_buffer[base + 4] = (len >> 8) & 0xff;
|
connection.output_buffer[base + 4] = (len >> 8) & 0xff;
|
||||||
connection.output_buffer[base + 5] = len & 0xff;
|
connection.output_buffer[base + 5] = len & 0xff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FCGI_BEGIN_REQUEST:
|
||||||
|
{
|
||||||
|
if (content_length < sizeof(FCGI_BeginRequestBody))
|
||||||
break;
|
break;
|
||||||
}
|
const FCGI_BeginRequestBody& body =
|
||||||
case FCGI_BEGIN_REQUEST: {
|
*reinterpret_cast<const FCGI_BeginRequestBody*>(content);
|
||||||
if (content_length < sizeof(FCGI_BeginRequestBody))
|
|
||||||
break;
|
|
||||||
const FCGI_BeginRequestBody& body =
|
|
||||||
*reinterpret_cast<const FCGI_BeginRequestBody*>(content);
|
|
||||||
|
|
||||||
if (!(body.flags & FCGI_KEEP_CONN))
|
if (!(body.flags & FCGI_KEEP_CONN))
|
||||||
connection.close_responsibility = true;
|
connection.close_responsibility = true;
|
||||||
|
|
||||||
unsigned role = (body.roleB1 << 8) + body.roleB0;
|
unsigned role = (body.roleB1 << 8) + body.roleB0;
|
||||||
if (role != FCGI_RESPONDER) {
|
if (role != FCGI_RESPONDER)
|
||||||
FCGI_EndRequestRecord unknown;
|
{
|
||||||
bzero(&unknown, sizeof(unknown));
|
FCGI_EndRequestRecord unknown;
|
||||||
unknown.header.version = FCGI_VERSION_1;
|
|
||||||
unknown.header.type = FCGI_END_REQUEST;
|
|
||||||
unknown.header.contentLengthB0 = sizeof(unknown.body);
|
|
||||||
unknown.body.protocolStatus = FCGI_UNKNOWN_ROLE;
|
|
||||||
connection.output_buffer.append(
|
|
||||||
reinterpret_cast<const char*>(&unknown), sizeof(unknown));
|
|
||||||
if (connection.close_responsibility)
|
|
||||||
connection.close_socket = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
RequestList::iterator it = connection.requests.find(request_id);
|
|
||||||
if (it != connection.requests.end()) {
|
|
||||||
delete it->second;
|
|
||||||
connection.requests.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestInfo* new_request = new RequestInfo;
|
|
||||||
try {
|
|
||||||
connection.requests.insert(RequestList::value_type(
|
|
||||||
request_id, new_request));
|
|
||||||
} catch (...) {
|
|
||||||
delete new_request;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FCGI_ABORT_REQUEST: {
|
|
||||||
RequestList::iterator it = connection.requests.find(request_id);
|
|
||||||
if (it == connection.requests.end())
|
|
||||||
break;
|
|
||||||
|
|
||||||
FCGI_EndRequestRecord aborted;
|
|
||||||
bzero(&aborted, sizeof(aborted));
|
|
||||||
aborted.header.version = FCGI_VERSION_1;
|
|
||||||
aborted.header.type = FCGI_END_REQUEST;
|
|
||||||
aborted.header.contentLengthB0 = sizeof(aborted.body);
|
|
||||||
aborted.body.appStatusB0 = 1;
|
|
||||||
aborted.body.protocolStatus = FCGI_REQUEST_COMPLETE;
|
|
||||||
connection.output_buffer.append(
|
|
||||||
reinterpret_cast<const char*>(&aborted), sizeof(aborted));
|
|
||||||
if (connection.close_responsibility)
|
|
||||||
connection.close_socket = true;
|
|
||||||
|
|
||||||
delete it->second;
|
|
||||||
connection.requests.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FCGI_PARAMS: {
|
|
||||||
RequestList::iterator it = connection.requests.find(request_id);
|
|
||||||
if (it == connection.requests.end())
|
|
||||||
break;
|
|
||||||
|
|
||||||
RequestInfo& request = *it->second;
|
|
||||||
if (!request.params_closed)
|
|
||||||
if (content_length != 0)
|
|
||||||
request.params_buffer.append(content, content_length);
|
|
||||||
else {
|
|
||||||
request.params = parse_pairs(request.params_buffer.data(),
|
|
||||||
request.params_buffer.size());
|
|
||||||
request.params_buffer.clear();
|
|
||||||
request.params_closed = true;
|
|
||||||
|
|
||||||
request.status = (*handle_request)(request);
|
|
||||||
if (request.status == 0 && !request.in.empty()) {
|
|
||||||
request.status = (*handle_data)(request);
|
|
||||||
if (request.status == 0 && request.in_closed)
|
|
||||||
request.status = (*handle_complete)(request);
|
|
||||||
}
|
|
||||||
process_write_request(connection, request_id, request);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FCGI_STDIN: {
|
|
||||||
RequestList::iterator it = connection.requests.find(request_id);
|
|
||||||
if (it == connection.requests.end())
|
|
||||||
break;
|
|
||||||
|
|
||||||
RequestInfo& request = *it->second;
|
|
||||||
if (!request.in_closed)
|
|
||||||
if (content_length != 0) {
|
|
||||||
request.in.append(content, content_length);
|
|
||||||
if (request.params_closed && request.status == 0) {
|
|
||||||
request.status = (*handle_data)(request);
|
|
||||||
process_write_request(connection, request_id, request);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
request.in_closed = true;
|
|
||||||
if (request.params_closed && request.status == 0) {
|
|
||||||
request.status = (*handle_complete)(request);
|
|
||||||
process_write_request(connection, request_id, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FCGI_DATA:
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
FCGI_UnknownTypeRecord unknown;
|
|
||||||
bzero(&unknown, sizeof(unknown));
|
bzero(&unknown, sizeof(unknown));
|
||||||
unknown.header.version = FCGI_VERSION_1;
|
unknown.header.version = FCGI_VERSION_1;
|
||||||
unknown.header.type = FCGI_UNKNOWN_TYPE;
|
unknown.header.type = FCGI_END_REQUEST;
|
||||||
unknown.header.contentLengthB0 = sizeof(unknown.body);
|
unknown.header.contentLengthB0 = sizeof(unknown.body);
|
||||||
unknown.body.type = header.type;
|
unknown.body.protocolStatus = FCGI_UNKNOWN_ROLE;
|
||||||
connection.output_buffer.append(
|
connection.output_buffer.append(
|
||||||
reinterpret_cast<const char*>(&unknown), sizeof(unknown));
|
reinterpret_cast<const char*>(&unknown), sizeof(unknown));
|
||||||
}
|
if (connection.close_responsibility)
|
||||||
|
connection.close_socket = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RequestList::iterator it = connection.requests.find(request_id);
|
||||||
|
if (it != connection.requests.end())
|
||||||
|
{
|
||||||
|
//printf("- delete request object\n");
|
||||||
|
switch_to_arena(it->second->mem);
|
||||||
|
delete it->second;
|
||||||
|
switch_to_system_alloc();
|
||||||
|
connection.requests.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//auto arena = new MemoryArena(server_state.config.MAX_MEMORY, "request");
|
||||||
|
request_arena->clear();
|
||||||
|
switch_to_arena(request_arena);
|
||||||
|
RequestInfo* new_request = new RequestInfo();
|
||||||
|
new_request->mem = request_arena;
|
||||||
|
new_request->stats.time_init = microtime();
|
||||||
|
switch_to_system_alloc();
|
||||||
|
connection.requests[request_id] = new_request;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FCGI_ABORT_REQUEST:
|
||||||
|
{
|
||||||
|
RequestList::iterator it = connection.requests.find(request_id);
|
||||||
|
if (it == connection.requests.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
FCGI_EndRequestRecord aborted;
|
||||||
|
bzero(&aborted, sizeof(aborted));
|
||||||
|
aborted.header.version = FCGI_VERSION_1;
|
||||||
|
aborted.header.type = FCGI_END_REQUEST;
|
||||||
|
aborted.header.contentLengthB0 = sizeof(aborted.body);
|
||||||
|
aborted.body.appStatusB0 = 1;
|
||||||
|
aborted.body.protocolStatus = FCGI_REQUEST_COMPLETE;
|
||||||
|
connection.output_buffer.append(
|
||||||
|
reinterpret_cast<const char*>(&aborted), sizeof(aborted));
|
||||||
|
if (connection.close_responsibility)
|
||||||
|
connection.close_socket = true;
|
||||||
|
|
||||||
|
delete it->second;
|
||||||
|
connection.requests.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FCGI_PARAMS:
|
||||||
|
{
|
||||||
|
RequestList::iterator it = connection.requests.find(request_id);
|
||||||
|
if (it == connection.requests.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
RequestInfo& request = *it->second;
|
||||||
|
switch_to_arena(it->second->mem);
|
||||||
|
if (!request.params_closed)
|
||||||
|
if (content_length != 0)
|
||||||
|
request.params_buffer.append(content, content_length);
|
||||||
|
else {
|
||||||
|
request.params = parse_pairs(request.params_buffer.data(),
|
||||||
|
request.params_buffer.size());
|
||||||
|
request.params_buffer.clear();
|
||||||
|
request.params_closed = true;
|
||||||
|
|
||||||
|
request.status = on_request(request);
|
||||||
|
if (request.status == 0 && !request.in.empty())
|
||||||
|
{
|
||||||
|
request.status = on_data(request);
|
||||||
|
if (request.status == 0 && request.in_closed)
|
||||||
|
request.status = call_completion_handler(request);
|
||||||
|
}
|
||||||
|
process_write_request(connection, request_id, request);
|
||||||
|
}
|
||||||
|
switch_to_system_alloc();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FCGI_STDIN:
|
||||||
|
{
|
||||||
|
RequestList::iterator it = connection.requests.find(request_id);
|
||||||
|
if (it == connection.requests.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
RequestInfo& request = *it->second;
|
||||||
|
switch_to_arena(it->second->mem);
|
||||||
|
if (!request.in_closed)
|
||||||
|
if (content_length != 0) {
|
||||||
|
request.in.append(content, content_length);
|
||||||
|
if (request.params_closed && request.status == 0)
|
||||||
|
{
|
||||||
|
request.status = on_data(request);
|
||||||
|
process_write_request(connection, request_id, request);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request.in_closed = true;
|
||||||
|
if (request.params_closed && request.status == 0) {
|
||||||
|
request.status = call_completion_handler(request);
|
||||||
|
process_write_request(connection, request_id, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch_to_system_alloc();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FCGI_DATA:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
FCGI_UnknownTypeRecord unknown;
|
||||||
|
bzero(&unknown, sizeof(unknown));
|
||||||
|
unknown.header.version = FCGI_VERSION_1;
|
||||||
|
unknown.header.type = FCGI_UNKNOWN_TYPE;
|
||||||
|
unknown.header.contentLengthB0 = sizeof(unknown.body);
|
||||||
|
unknown.body.type = header.type;
|
||||||
|
connection.output_buffer.append(
|
||||||
|
reinterpret_cast<const char*>(&unknown), sizeof(unknown));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n += FCGI_HEADER_LEN + content_length + header.paddingLength;
|
n += FCGI_HEADER_LEN + content_length + header.paddingLength;
|
||||||
@@ -499,16 +485,21 @@ FastCGIServer::process_write_request(Connection& connection, RequestID id,
|
|||||||
if (!request.out.empty())
|
if (!request.out.empty())
|
||||||
{
|
{
|
||||||
write_data(connection.output_buffer, id, request.out, FCGI_STDOUT);
|
write_data(connection.output_buffer, id, request.out, FCGI_STDOUT);
|
||||||
|
switch_to_arena(request.mem);
|
||||||
request.out.clear();
|
request.out.clear();
|
||||||
|
switch_to_system_alloc();
|
||||||
}
|
}
|
||||||
if (!request.err.empty())
|
if (!request.err.empty())
|
||||||
{
|
{
|
||||||
write_data(connection.output_buffer, id, request.err, FCGI_STDERR);
|
write_data(connection.output_buffer, id, request.err, FCGI_STDERR);
|
||||||
|
switch_to_arena(request.mem);
|
||||||
request.err.clear();
|
request.err.clear();
|
||||||
|
switch_to_system_alloc();
|
||||||
}
|
}
|
||||||
if ((request.in_closed || request.status != 0) &&
|
if ((request.in_closed || request.status != 0) &&
|
||||||
!request.output_closed)
|
!request.output_closed)
|
||||||
{
|
{
|
||||||
|
switch_to_arena(request.mem);
|
||||||
request.out =
|
request.out =
|
||||||
var_dump(request.header, "", "\r\n") +
|
var_dump(request.header, "", "\r\n") +
|
||||||
var_dump(request.set_cookies, "", "\r\n") +
|
var_dump(request.set_cookies, "", "\r\n") +
|
||||||
@@ -521,15 +512,19 @@ FastCGIServer::process_write_request(Connection& connection, RequestID id,
|
|||||||
}
|
}
|
||||||
request.ob_stack.clear();
|
request.ob_stack.clear();
|
||||||
|
|
||||||
|
switch_to_system_alloc();
|
||||||
write_data(connection.output_buffer, id, request.out, FCGI_STDOUT);
|
write_data(connection.output_buffer, id, request.out, FCGI_STDOUT);
|
||||||
write_data(connection.output_buffer, id, request.err, FCGI_STDERR);
|
write_data(connection.output_buffer, id, request.err, FCGI_STDERR);
|
||||||
|
|
||||||
request.stats.time_end = microtime();
|
request.stats.time_end = microtime();
|
||||||
printf("(r) pid:%i\t%s\t%0.6fs\t%0.1fkB\n",
|
printf("(r) pid:%i\t%s\t%0.6fs\tfps:%0.0f\tout:%0.1fkB\tmem:%0.0f/%0.0fkB\n",
|
||||||
my_pid,
|
my_pid,
|
||||||
request.params["REQUEST_URI"].c_str(),
|
request.params["REQUEST_URI"].c_str(),
|
||||||
request.stats.time_end - request.stats.time_start,
|
request.stats.time_end - request.stats.time_start,
|
||||||
(f32)(request.out.length()/1024)
|
1.0 / (request.stats.time_end - request.stats.time_start),
|
||||||
|
(f32)(request.out.length()/1024),
|
||||||
|
(f32)(request.mem->size/1024),
|
||||||
|
(f32)(request.mem->capacity/1024)
|
||||||
);
|
);
|
||||||
|
|
||||||
FCGI_EndRequestRecord complete;
|
FCGI_EndRequestRecord complete;
|
||||||
@@ -550,7 +545,9 @@ FastCGIServer::process_write_request(Connection& connection, RequestID id,
|
|||||||
connection.close_socket = true;
|
connection.close_socket = true;
|
||||||
|
|
||||||
request.output_closed = true;
|
request.output_closed = true;
|
||||||
|
//printf("- output done\n");
|
||||||
}
|
}
|
||||||
|
switch_to_system_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -558,14 +555,19 @@ void
|
|||||||
FastCGIServer::process_connection_write(Connection& connection)
|
FastCGIServer::process_connection_write(Connection& connection)
|
||||||
{
|
{
|
||||||
for (RequestList::iterator it = connection.requests.begin();
|
for (RequestList::iterator it = connection.requests.begin();
|
||||||
it != connection.requests.end();) {
|
it != connection.requests.end();)
|
||||||
process_write_request(connection, it->first, *it->second);
|
{
|
||||||
if (it->second->params_closed && it->second->in_closed) {
|
process_write_request(connection, it->first, *it->second);
|
||||||
RequestInfo* request = it->second;
|
if (it->second->params_closed && it->second->in_closed)
|
||||||
connection.requests.erase(it++);
|
{
|
||||||
delete request;
|
switch_to_arena(it->second->mem);
|
||||||
} else
|
//printf("- process_connection_write close\n");
|
||||||
++it;
|
delete it->second;
|
||||||
|
switch_to_system_alloc();
|
||||||
|
connection.requests.erase(it++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,25 +45,9 @@ public:
|
|||||||
~FastCGIServer();
|
~FastCGIServer();
|
||||||
|
|
||||||
// called when the parameters and standard input have been receieved
|
// called when the parameters and standard input have been receieved
|
||||||
void request_handler(int (* function)(FastCGIRequest&));
|
std::function<int(FastCGIRequest&)> on_request = 0;
|
||||||
template<class C>
|
std::function<int(FastCGIRequest&)> on_data = 0;
|
||||||
void request_handler(C& object, int (C::* function)(FastCGIRequest&)) {
|
std::function<int(FastCGIRequest&)> on_complete = 0;
|
||||||
set_handler(handle_request, new Handler<C>(object, function));
|
|
||||||
}
|
|
||||||
|
|
||||||
// called when new data appears on stdin
|
|
||||||
void data_handler(int (* function)(FastCGIRequest&));
|
|
||||||
template<class C>
|
|
||||||
void data_handler(C& object, int (C::* function)(FastCGIRequest&)) {
|
|
||||||
set_handler(handle_data, new Handler<C>(object, function));
|
|
||||||
}
|
|
||||||
|
|
||||||
// called when the complete request has been received
|
|
||||||
void complete_handler(int (* function)(FastCGIRequest&));
|
|
||||||
template<class C>
|
|
||||||
void complete_handler(C& object, int (C::* function)(FastCGIRequest&)) {
|
|
||||||
set_handler(handle_complete, new Handler<C>(object, function));
|
|
||||||
}
|
|
||||||
|
|
||||||
void listen(unsigned tcp_port);
|
void listen(unsigned tcp_port);
|
||||||
void listen(const std::string& local_path);
|
void listen(const std::string& local_path);
|
||||||
@@ -72,6 +56,8 @@ public:
|
|||||||
void process(int timeout_ms = -1); // timeout_ms<0 blocks forever
|
void process(int timeout_ms = -1); // timeout_ms<0 blocks forever
|
||||||
void process_forever();
|
void process_forever();
|
||||||
|
|
||||||
|
int call_completion_handler(FastCGIRequest& request);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct RequestInfo : FastCGIRequest {
|
struct RequestInfo : FastCGIRequest {
|
||||||
RequestInfo();
|
RequestInfo();
|
||||||
@@ -113,38 +99,6 @@ protected:
|
|||||||
static void write_data(std::string& buffer, RequestID id,
|
static void write_data(std::string& buffer, RequestID id,
|
||||||
const std::string& input, unsigned char type);
|
const std::string& input, unsigned char type);
|
||||||
|
|
||||||
|
|
||||||
struct HandlerBase {
|
|
||||||
virtual int operator()(FastCGIRequest&);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StaticHandler : public HandlerBase {
|
|
||||||
StaticHandler(int (* p_function)(FastCGIRequest&)) :
|
|
||||||
function(p_function) {}
|
|
||||||
int operator()(FastCGIRequest& request) {
|
|
||||||
return function(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
int (* function)(FastCGIRequest&);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
struct Handler : public HandlerBase {
|
|
||||||
Handler(C& p_object, int (C::* p_function)(FastCGIRequest&)) :
|
|
||||||
object(p_object), function(p_function) {}
|
|
||||||
int operator()(FastCGIRequest& request) {
|
|
||||||
return (object.*function)(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
C& object;
|
|
||||||
int (C::* function)(FastCGIRequest&);
|
|
||||||
};
|
|
||||||
|
|
||||||
void set_handler(HandlerBase*&, HandlerBase*);
|
|
||||||
|
|
||||||
HandlerBase* handle_request;
|
|
||||||
HandlerBase* handle_data;
|
|
||||||
HandlerBase* handle_complete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !FCGICC_H
|
#endif // !FCGICC_H
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ void compiler_invoke(Request* context, String file_name, DTree& call_param)
|
|||||||
//printf("(i) invoke(%s)\n", file_name.c_str());
|
//printf("(i) invoke(%s)\n", file_name.c_str());
|
||||||
switch_to_system_alloc();
|
switch_to_system_alloc();
|
||||||
auto su = get_shared_unit(context, file_name);
|
auto su = get_shared_unit(context, file_name);
|
||||||
switch_to_arena(context->request_arena);
|
switch_to_arena(context->mem);
|
||||||
if(!su)
|
if(!su)
|
||||||
{
|
{
|
||||||
printf("Error loading unit %s\n", file_name.c_str());
|
printf("Error loading unit %s\n", file_name.c_str());
|
||||||
|
|||||||
@@ -5,22 +5,28 @@
|
|||||||
|
|
||||||
bool MySQL::connect(String host, String username, String password)
|
bool MySQL::connect(String host, String username, String password)
|
||||||
{
|
{
|
||||||
|
switch_to_system_alloc();
|
||||||
connection = mysql_init(NULL);
|
connection = mysql_init(NULL);
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s\n", mysql_error((MYSQL*)connection));
|
auto e = mysql_error((MYSQL*)connection);
|
||||||
|
fprintf(stderr, "%s\n", e);
|
||||||
|
switch_to_arena(context->mem);
|
||||||
|
statement_info.assign(e);
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mysql_real_connect((MYSQL*)connection, host.c_str(), username.c_str(), password.c_str(),
|
if (mysql_real_connect((MYSQL*)connection, host.c_str(), username.c_str(), password.c_str(),
|
||||||
NULL, 0, NULL, 0) == NULL)
|
NULL, 0, NULL, 0) == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s\n", mysql_error((MYSQL*)connection));
|
auto e = mysql_error((MYSQL*)connection);
|
||||||
|
fprintf(stderr, "%s\n", e);
|
||||||
mysql_close((MYSQL*)connection);
|
mysql_close((MYSQL*)connection);
|
||||||
|
switch_to_arena(context->mem);
|
||||||
|
statement_info.assign(e);
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("(i) MySQL Connection established to %s\n", host.c_str());
|
|
||||||
/*
|
/*
|
||||||
if (mysql_query(con, "CREATE DATABASE testdb"))
|
if (mysql_query(con, "CREATE DATABASE testdb"))
|
||||||
{
|
{
|
||||||
@@ -29,6 +35,8 @@ bool MySQL::connect(String host, String username, String password)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
switch_to_arena(context->mem);
|
||||||
|
statement_info = String("connected");
|
||||||
context->resources.mysql_connections.push_back(connection);
|
context->resources.mysql_connections.push_back(connection);
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
@@ -282,6 +290,8 @@ String MySQL::error()
|
|||||||
|
|
||||||
void cleanup_mysql_connections()
|
void cleanup_mysql_connections()
|
||||||
{
|
{
|
||||||
|
switch_to_system_alloc();
|
||||||
for(auto& con : context->resources.mysql_connections)
|
for(auto& con : context->resources.mysql_connections)
|
||||||
mysql_close((MYSQL*)con);
|
mysql_close((MYSQL*)con);
|
||||||
|
switch_to_arena(context->mem);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -42,8 +42,8 @@ String operator+(String lhs, f32 rhs) {
|
|||||||
return(lhs + std::to_string(rhs));
|
return(lhs + std::to_string(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEBUG_MEMORY_OFF;
|
#define DEBUG_MEMORY_OFF
|
||||||
#define NO_GLOBAL_ARENA_ALLOCATOR;
|
#define GLOBAL_ARENA_ALLOCATOR
|
||||||
|
|
||||||
struct MemoryArena {
|
struct MemoryArena {
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ struct MemoryArena {
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
size += size_aligned;
|
size += size_aligned;
|
||||||
#ifdef DEBUG_MEMORY
|
#ifdef DEBUG_MEMORY_DETAILED
|
||||||
printf("(i) memory arena '%s' [+%llu]:%p alloc %llu/%llu bytes\n", name.c_str(), size, result, size_needed, size_aligned);
|
printf("(i) memory arena '%s' [+%llu]:%p alloc %llu/%llu bytes\n", name.c_str(), size, result, size_needed, size_aligned);
|
||||||
#endif
|
#endif
|
||||||
return(result);
|
return(result);
|
||||||
@@ -96,12 +96,16 @@ MemoryArena* current_memory_arena = 0;
|
|||||||
|
|
||||||
void switch_to_system_alloc()
|
void switch_to_system_alloc()
|
||||||
{
|
{
|
||||||
|
#ifdef GLOBAL_ARENA_ALLOCATOR
|
||||||
current_memory_arena = 0;
|
current_memory_arena = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_to_arena(MemoryArena* a)
|
void switch_to_arena(MemoryArena* a)
|
||||||
{
|
{
|
||||||
|
#ifdef GLOBAL_ARENA_ALLOCATOR
|
||||||
current_memory_arena = a;
|
current_memory_arena = a;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GLOBAL_ARENA_ALLOCATOR
|
#ifdef GLOBAL_ARENA_ALLOCATOR
|
||||||
@@ -239,7 +243,7 @@ struct Request {
|
|||||||
u64 random_seed;
|
u64 random_seed;
|
||||||
u64 random_index;
|
u64 random_index;
|
||||||
|
|
||||||
MemoryArena* request_arena;
|
MemoryArena* mem;
|
||||||
|
|
||||||
String in;
|
String in;
|
||||||
std::vector<std::ostringstream*> ob_stack;
|
std::vector<std::ostringstream*> ob_stack;
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
#include "lib/uce_lib.cpp"
|
#include "lib/uce_lib.cpp"
|
||||||
|
|
||||||
|
ServerState server_state;
|
||||||
|
MemoryArena* request_arena = new MemoryArena(server_state.config.MAX_MEMORY, "request");
|
||||||
|
|
||||||
#include "fastcgi/src/fcgicc.cc"
|
#include "fastcgi/src/fcgicc.cc"
|
||||||
|
|
||||||
FastCGIServer server;
|
FastCGIServer server;
|
||||||
ServerState server_state;
|
|
||||||
MemoryArena* request_arena = 0;
|
|
||||||
|
|
||||||
int handle_request(FastCGIRequest& request) {
|
int handle_request(FastCGIRequest& request) {
|
||||||
// This is always the first event to occur. It occurs when the
|
// This is always the first event to occur. It occurs when the
|
||||||
// server receives all parameters. There may be more data coming on the
|
// server receives all parameters. There may be more data coming on the
|
||||||
// standard input stream.
|
// standard input stream.
|
||||||
request.request_arena = request_arena;
|
|
||||||
request.stats.time_init = microtime();
|
|
||||||
request.ob_start(); // this one is for the headers
|
|
||||||
request.ob_start(); // this one is for the content
|
|
||||||
if (request.params.count("REQUEST_URI"))
|
if (request.params.count("REQUEST_URI"))
|
||||||
return 0; // OK, continue processing
|
return 0; // OK, continue processing
|
||||||
else
|
else
|
||||||
@@ -50,6 +47,7 @@ int handle_complete(FastCGIRequest& request) {
|
|||||||
request.get = parse_query(request.params["QUERY_String"]);
|
request.get = parse_query(request.params["QUERY_String"]);
|
||||||
request.random_index = 0;
|
request.random_index = 0;
|
||||||
request.random_seed = noise64(*reinterpret_cast<u64*>(&request.stats.time_start));
|
request.random_seed = noise64(*reinterpret_cast<u64*>(&request.stats.time_start));
|
||||||
|
request.ob_start();
|
||||||
|
|
||||||
if(request.params["HTTP_COOKIE"].length() > 0)
|
if(request.params["HTTP_COOKIE"].length() > 0)
|
||||||
request.cookies = parse_cookies(request.params["HTTP_COOKIE"]);
|
request.cookies = parse_cookies(request.params["HTTP_COOKIE"]);
|
||||||
@@ -72,7 +70,6 @@ int handle_complete(FastCGIRequest& request) {
|
|||||||
|
|
||||||
// printf("(i) request ready\n");
|
// printf("(i) request ready\n");
|
||||||
request.invoke(request.params["SCRIPT_FILENAME"]);
|
request.invoke(request.params["SCRIPT_FILENAME"]);
|
||||||
switch_to_system_alloc();
|
|
||||||
|
|
||||||
for( auto &f : request.uploaded_files)
|
for( auto &f : request.uploaded_files)
|
||||||
{
|
{
|
||||||
@@ -89,11 +86,15 @@ int handle_complete(FastCGIRequest& request) {
|
|||||||
|
|
||||||
void listen_for_connections()
|
void listen_for_connections()
|
||||||
{
|
{
|
||||||
//request_arena = new MemoryArena(server_state.config.MAX_MEMORY, "request");
|
|
||||||
signal(SIGSEGV, on_segfault);
|
signal(SIGSEGV, on_segfault);
|
||||||
|
server.on_request = &handle_request;
|
||||||
|
server.on_data = &handle_data;
|
||||||
|
server.on_complete = &handle_complete;
|
||||||
|
/*
|
||||||
server.request_handler(&handle_request);
|
server.request_handler(&handle_request);
|
||||||
server.data_handler(&handle_data);
|
server.data_handler(&handle_data);
|
||||||
server.complete_handler(&handle_complete);
|
server.complete_handler(&handle_complete);
|
||||||
|
*/
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
//if(request_arena) request_arena->clear();
|
//if(request_arena) request_arena->clear();
|
||||||
|
|||||||
@@ -29,8 +29,12 @@ RENDER()
|
|||||||
<pre><?
|
<pre><?
|
||||||
print("Worker PID: ", my_pid, "\n");
|
print("Worker PID: ", my_pid, "\n");
|
||||||
print("Parent PID: ", parent_pid, " \n");
|
print("Parent PID: ", parent_pid, " \n");
|
||||||
|
print("Output buffer size: ", context->ob->str().length(), " \n");
|
||||||
?></pre>
|
?></pre>
|
||||||
<pre><?= (var_dump(p)) ?></pre>
|
<pre><?= (var_dump(p)) ?></pre>
|
||||||
|
<div><?
|
||||||
|
print("Output buffer size: ", context->ob->str().length(), " \n");
|
||||||
|
?></div>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
String test;
|
String test;
|
||||||
|
|||||||
+5
-1
@@ -21,7 +21,6 @@ RENDER()
|
|||||||
MySQL con;
|
MySQL con;
|
||||||
if(con.connect("localhost", "root", ""))
|
if(con.connect("localhost", "root", ""))
|
||||||
{
|
{
|
||||||
print("connection established\n");
|
|
||||||
print("error: "+con.error()+"\n");
|
print("error: "+con.error()+"\n");
|
||||||
print("quotation test: "+con.escape("‘\"' or 1=1;–.")+"\n");
|
print("quotation test: "+con.escape("‘\"' or 1=1;–.")+"\n");
|
||||||
print("query parse: "+con.parse_query_parameters(query, params)+"\n");
|
print("query parse: "+con.parse_query_parameters(query, params)+"\n");
|
||||||
@@ -38,8 +37,13 @@ RENDER()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
?></pre>
|
?></pre>
|
||||||
|
|
||||||
|
<div><?
|
||||||
|
print("connection status: ", con.statement_info, "\n");
|
||||||
|
?></div>
|
||||||
|
|
||||||
<label>CGI Params</label>
|
<label>CGI Params</label>
|
||||||
<pre><?= var_dump(context->params) ?></pre>
|
<pre><?= var_dump(context->params) ?></pre>
|
||||||
</html></>
|
</html></>
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
RENDER()
|
RENDER()
|
||||||
{
|
{
|
||||||
echo("Sub-Invoke Working dir: " + get_cwd() + "\n");
|
print("Sub-Invoke Working dir: ", get_cwd(), "\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user