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:
2013-12-04 01:21:57 +00:00
parent c04874397b
commit ee9c68b04e
12 changed files with 213 additions and 129 deletions

View File

@@ -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
{