added: generating Content-Length header when text answer is sent to the client
added: now we are able to use the html filter for the whole out_streams (when ajax is used the output is filtered too) splitted FilterCompressSend() function -- first we are making the filtering (after filtering we know the size of the content to send) added: to Compress: Compressing(const char * source, size_t source_len, BinaryPage & out_stream, int encoding); changed: some refactoring in App git-svn-id: svn://ttmath.org/publicrep/winix/trunk@942 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
209
core/app.cpp
209
core/app.cpp
@@ -339,7 +339,7 @@ void App::ProcessRequest()
|
||||
log << log2 << config.log_delimiter << logend;
|
||||
|
||||
ProcessRequestThrow();
|
||||
SaveSessionsIfNeeded(); // !! przerzucic to na watek sesji
|
||||
SaveSessionsIfNeeded(); // !! IMPROVE ME move to the session's thread
|
||||
|
||||
system.load_avg.StopRequest();
|
||||
}
|
||||
@@ -356,25 +356,48 @@ void App::ProcessRequest()
|
||||
log << log1 << "App: there was an unknown exception" << logend;
|
||||
}
|
||||
|
||||
ClearAfterRequest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::ClearAfterRequest()
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.Call(WINIX_END_REQUEST);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
log << log1 << "App: an exception when clearing after a request (exception from a plugin)" << logend;
|
||||
log << log1 << "App: an exception from a plugin when clearing after a request" << logend;
|
||||
}
|
||||
|
||||
// simple operations which should not throw an exception
|
||||
templates.RequestEnd();
|
||||
cur.request->Clear();
|
||||
cur.session->ClearOnEndRequest();
|
||||
cur.session = session_manager.GetTmpSession();
|
||||
log << logendrequest;
|
||||
|
||||
try
|
||||
{
|
||||
// simple operations which should not throw an exception
|
||||
json_out_stream.Clear();
|
||||
templates.ClearAfterRequest();
|
||||
cur.request->Clear();
|
||||
cur.session->ClearAfterRequest();
|
||||
cur.session = session_manager.GetTmpSession();
|
||||
output_8bit.clear();
|
||||
compressed_output.clear();
|
||||
html_filtered.clear();
|
||||
aheader_name.clear();
|
||||
aheader_value.clear();
|
||||
// send_data_buf doesn't have to be cleared and it is better to not clear it (optimizing)
|
||||
|
||||
log << logendrequest;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
log << log1 << "App: an exception when clearing after a request" << logend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::Start()
|
||||
{
|
||||
while( !synchro.was_stop_signal && FCGX_Accept_r(&fcgi_request) == 0 )
|
||||
@@ -475,12 +498,6 @@ bool sent = false;
|
||||
{
|
||||
templates.Generate();
|
||||
}
|
||||
|
||||
|
||||
if( cur.request->return_json )
|
||||
{
|
||||
CreateJSONAnswer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -915,7 +932,7 @@ void App::PrepareHeadersCompression(int compress_encoding)
|
||||
}
|
||||
|
||||
|
||||
void App::PrepareHeadersNormal(Header header)
|
||||
void App::PrepareHeadersNormal(Header header, size_t output_size)
|
||||
{
|
||||
switch( header )
|
||||
{
|
||||
@@ -932,6 +949,9 @@ void App::PrepareHeadersNormal(Header header)
|
||||
cur.request->out_headers.Add(L"Status", L"200 OK");
|
||||
PrepareHeaderContentType();
|
||||
}
|
||||
|
||||
if( output_size != static_cast<size_t>(-1) )
|
||||
cur.request->out_headers.Add(L"Content-Length", output_size);
|
||||
}
|
||||
|
||||
|
||||
@@ -986,7 +1006,7 @@ void App::SendCookies()
|
||||
}
|
||||
|
||||
|
||||
void App::PrepareHeaders(bool compressing, int compress_encoding, Header header)
|
||||
void App::PrepareHeaders(bool compressing, int compress_encoding, Header header, size_t output_size)
|
||||
{
|
||||
PrepareSessionCookie();
|
||||
|
||||
@@ -1009,7 +1029,7 @@ void App::PrepareHeaders(bool compressing, int compress_encoding, Header header)
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareHeadersNormal(header);
|
||||
PrepareHeadersNormal(header, output_size);
|
||||
}
|
||||
|
||||
if( compressing )
|
||||
@@ -1018,41 +1038,42 @@ void App::PrepareHeaders(bool compressing, int compress_encoding, Header header)
|
||||
|
||||
|
||||
|
||||
|
||||
void App::FilterCompressSend(bool compressing, int compress_encoding, const std::wstring & source_ref)
|
||||
void App::FilterContent()
|
||||
{
|
||||
const std::wstring * source = &source_ref;
|
||||
Request & req = *cur.request;
|
||||
bool raw = req.is_item && req.item.content_type == Item::ct_raw &&
|
||||
req.status == WINIX_ERR_OK && req.function &&
|
||||
(req.function == &functions.fun_cat || req.function == &functions.fun_run);
|
||||
|
||||
bool raw = cur.request->is_item && cur.request->item.content_type == Item::ct_raw && cur.request->status == WINIX_ERR_OK &&
|
||||
cur.request->function && (cur.request->function == &functions.fun_cat || cur.request->function == &functions.fun_run);
|
||||
size_t start = req.out_streams.size(); // default nothing should be filtered
|
||||
size_t end = req.out_streams.size();
|
||||
|
||||
if( config.html_filter && cur.request->use_html_filter && !raw && !cur.request->return_json )
|
||||
if( config.html_filter && !req.send_bin_stream && !raw )
|
||||
{
|
||||
TemplatesFunctions::html_filter.Filter(*source, clean_html);
|
||||
source = &clean_html;
|
||||
}
|
||||
else
|
||||
{
|
||||
html_with_debug = *source;
|
||||
source = &html_with_debug;
|
||||
if( req.return_json )
|
||||
{
|
||||
if( !req.return_info_only )
|
||||
{
|
||||
start = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start = 0;
|
||||
end = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( config.utf8 )
|
||||
PT::WideToUTF8(*source, source_a);
|
||||
else
|
||||
AssignString(*source, source_a);
|
||||
|
||||
// !! IMPROVE ME add to log the binary stream as well
|
||||
if( config.log_server_answer )
|
||||
log << log1 << "App: the server's answer is:\n" << source_a << "\nApp: end of the server's answer" << logend;
|
||||
|
||||
if( compressing )
|
||||
compress.CompressAndPut(source_a.c_str(), source_a.length(), fcgi_request.out, compress_encoding);
|
||||
else
|
||||
FCGX_PutS(source_a.c_str(), fcgi_request.out);
|
||||
|
||||
if( cur.request->return_json )
|
||||
json_out_stream.Clear();
|
||||
for(size_t i=start ; i<end ; ++i)
|
||||
{
|
||||
if( req.use_html_filter[i] )
|
||||
{
|
||||
// !! IMPROVE ME may some kind of html_filtered.reserve() here? (optimization)
|
||||
TemplatesFunctions::html_filter.Filter(req.out_streams[i].Str(), html_filtered);
|
||||
req.out_streams[i].Str(std::move(html_filtered));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1067,6 +1088,7 @@ int App::SelectDeflateVersion()
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::SelectCompression(size_t source_len, bool & compression_allowed, int & compression_encoding)
|
||||
{
|
||||
compression_allowed = false;
|
||||
@@ -1114,7 +1136,7 @@ void App::SelectCompression(size_t source_len, bool & compression_allowed, int &
|
||||
|
||||
|
||||
|
||||
bool App::CanSendContent(Header header)
|
||||
bool App::CanSendContent()
|
||||
{
|
||||
if( !cur.request->redirect_to.empty() || !cur.request->x_sendfile.empty() )
|
||||
// if there is a redirect or a file to send then we do not send a content
|
||||
@@ -1132,22 +1154,10 @@ return true;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void App::SendTextAnswer()
|
||||
App::Header App::GetHTTPStatusCode()
|
||||
{
|
||||
const std::wstring * source;
|
||||
Header header = h_200;
|
||||
Error status = cur.request->status;
|
||||
bool compressing;
|
||||
int compress_encoding;
|
||||
|
||||
if( cur.request->return_json )
|
||||
source = &json_out_stream.Str();
|
||||
else
|
||||
source = &cur.request->out_streams[0].Str();
|
||||
|
||||
SelectCompression(source->length(), compressing, compress_encoding);
|
||||
Error status = cur.request->status;
|
||||
Header header = h_200;
|
||||
|
||||
if( status == WINIX_ERR_NO_ITEM || status == WINIX_ERR_NO_FUNCTION || status == WINIX_ERR_UNKNOWN_PARAM )
|
||||
{
|
||||
@@ -1167,15 +1177,67 @@ int compress_encoding;
|
||||
header = h_200;
|
||||
}
|
||||
|
||||
PrepareHeaders(compressing, compress_encoding, header);
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::SendTextAnswer()
|
||||
{
|
||||
const std::wstring * source;
|
||||
bool compressing = false;
|
||||
int compress_encoding = 0;
|
||||
size_t output_size = 0;
|
||||
|
||||
Header header = GetHTTPStatusCode();
|
||||
|
||||
if( CanSendContent() )
|
||||
{
|
||||
FilterContent();
|
||||
|
||||
if( cur.request->return_json )
|
||||
{
|
||||
CreateJSONAnswer();
|
||||
source = &json_out_stream.Str(); // json_out_stream was prepared by CreateJSONAnswer()
|
||||
}
|
||||
else
|
||||
{
|
||||
source = &cur.request->out_streams[0].Str();
|
||||
}
|
||||
|
||||
SelectCompression(source->length(), compressing, compress_encoding);
|
||||
|
||||
if( config.utf8 )
|
||||
PT::WideToUTF8(*source, output_8bit);
|
||||
else
|
||||
AssignString(*source, output_8bit);
|
||||
|
||||
// !! IMPROVE ME add to log the binary stream as well
|
||||
if( config.log_server_answer )
|
||||
log << log1 << "App: the server's answer is:\n" << output_8bit << "\nApp: end of the server's answer" << logend;
|
||||
|
||||
if( compressing )
|
||||
{
|
||||
compress.Compressing(output_8bit.c_str(), output_8bit.length(), compressed_output, compress_encoding);
|
||||
output_size = compressed_output.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
output_size = output_8bit.size();
|
||||
}
|
||||
}
|
||||
|
||||
PrepareHeaders(compressing, compress_encoding, header, output_size);
|
||||
SendHeaders();
|
||||
SendCookies();
|
||||
FCGX_PutS("\r\n", fcgi_request.out);
|
||||
|
||||
if( CanSendContent(header) )
|
||||
if( CanSendContent() )
|
||||
{
|
||||
// filtering (html), compressing and sending back to the web browser
|
||||
FilterCompressSend(compressing, compress_encoding, *source);
|
||||
if( compressing )
|
||||
SendData(compressed_output, fcgi_request.out);
|
||||
else
|
||||
FCGX_PutStr(output_8bit.c_str(), output_8bit.size(), fcgi_request.out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1187,7 +1249,7 @@ void App::SendData(const BinaryPage & page, FCGX_Stream * out)
|
||||
if( send_data_buf.size() != buf_size )
|
||||
send_data_buf.resize(buf_size);
|
||||
|
||||
BinaryPage::const_iterator i = page.begin();
|
||||
BinaryPage::const_iterator i = page.begin();
|
||||
BinaryPage::const_iterator end = page.end();
|
||||
|
||||
while( i != end )
|
||||
@@ -1219,18 +1281,19 @@ int compress_encoding;
|
||||
if( status == WINIX_ERR_PERMISSION_DENIED || status == WINIX_ERR_CANT_CHANGE_USER || status == WINIX_ERR_CANT_CHANGE_GROUP )
|
||||
header = h_403;
|
||||
|
||||
// !! IMPROVE ME add header: content-size
|
||||
|
||||
PrepareHeaders(compressing, compress_encoding, header);
|
||||
// !! IMPROVE ME add header: content-length (size from Item struct)
|
||||
// warning: if someone changed a file on the disk (in the real os)
|
||||
// then winix would send an incorrect content-lenght header,
|
||||
// we are waiting for the fsck winix function to be implemented
|
||||
PrepareHeaders(compressing, compress_encoding, header, static_cast<size_t>(-1));
|
||||
|
||||
if( CanSendContent(header) )
|
||||
if( CanSendContent() )
|
||||
{
|
||||
if( compressing )
|
||||
{
|
||||
out_bin_stream_compressed.clear(); // !! IMPROVE ME add to the end of a request
|
||||
compress.Compressing(source, out_bin_stream_compressed, compress_encoding);
|
||||
SendData(out_bin_stream_compressed, fcgi_request.out);
|
||||
out_bin_stream_compressed.clear();
|
||||
compress.Compressing(source, compressed_output, compress_encoding);
|
||||
SendData(compressed_output, fcgi_request.out);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Reference in New Issue
Block a user