removed: ezn patterns for rawcontent and ajaxcontent:

index_rawcontent.html, index_ajaxcontent.html
         now we have out_streams in Request and some special
         keyword in ezc templates for sending content to the 
         specified streams
changed: the way how winix answers to the client's browsers:
         info from Request class:
	                                   winix answer send to the client's browser
	                                                       |
	                                                       |
	                                          depending on send_bin_stream
	                               -------------------------------------------------
	                               |                                               |
	                          text answer                                     binary answer
	                               |                                               |
	                   depending on return_json                          sending out_bin_stream
	             ------------------------------------
	             |                                  |
	       normal request                     ajax request
	             |                                  |
	   sending out_streams[0]           depending on return_info_only
	                              ------------------------------------------------------
	                              |                                                    |
	                 generating JSON object from:                   generating JSON object only from info
	                 out_streams and info, e.g.:                    e.g.:
	                 {                                              { info object serialized here }
	                  "stream_1": "some html content",
	                  "stream_2": "some other html content",
	                  "info": { info object serialized here }
	                 }
	                 note that out_streams[0] is not sent
	                 in JSON answers
	
	




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@937 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2013-11-14 20:59:23 +00:00
parent d801f53154
commit 3af3ac3f6f
15 changed files with 303 additions and 115 deletions

View File

@ -317,6 +317,7 @@ void App::ProcessRequestThrow()
plugin.Call(WINIX_SESSION_CHANGED);
functions.Parse(); // parsing directories,files,functions and parameters
cur.mount = system.mounts.CalcCurMount();
if( cur.mount->type != system.mounts.MountTypeStatic() )
@ -400,13 +401,51 @@ void App::SaveSessionsIfNeeded()
void App::CreateJSONAnswer()
{
Request & req = *cur.request;
json_out_stream.Clear();
if( !req.return_info_only )
{
json_out_stream << L"{\n";
for(size_t i=1 ; i<req.out_streams.size() ; ++i)
{
json_out_stream << L"\"stream_" << i << L"\": \"";
JSONescape(json_out_stream, req.out_streams[i].Str());
json_out_stream << L"\",\n";
}
json_out_stream << L"\"info\": ";
}
if( req.info_serializer )
{
req.info_serializer->Serialize(req.info, json_out_stream, true);
}
else
{
json_out_stream << L"{}";
log << log1 << "App: Request::info_serializer not defined" << logend;
}
log << log3 << "App: sending JSON answer";
if( !req.return_info_only )
json_out_stream << L"}\n";
else
log << " (Request::info only)";
log << logend;
}
// !! zmienic na lepsza nazwe
void App::MakePage()
{
bool sent = false;
if( cur.request->page_generated || !cur.request->redirect_to.empty() || !cur.request->x_sendfile.empty() )
return;
@ -419,7 +458,7 @@ bool sent = false;
{
if( cur.request->function == &functions.fun_cat )
{
cur.request->page << cur.request->item.content;
cur.request->out_streams[0] << cur.request->item.content; // !! CHECK ME is it ok?
sent = true;
}
else
@ -436,12 +475,9 @@ bool sent = false;
}
if( cur.request->ajax_serializer )
if( cur.request->return_json )
{
log << log3 << "App: sending JSON" << logend;
std::wstring & ajax_content = cur.request->ajax.Add(L"content", L"");
ajax_content = cur.request->page.Str();
cur.request->ajax_serializer->Serialize(cur.request->ajax, cur.request->ajaxpage, true);
CreateJSONAnswer();
}
}
@ -476,6 +512,9 @@ void App::Make()
return;
}
if( cur.request->ParamValue(L"reqtype") == L"json" )
cur.request->return_json = true;
if( cur.session->ip_ban && cur.session->ip_ban->IsIPBanned() )
{
PT::Date date(cur.session->ip_ban->expires);
@ -525,11 +564,10 @@ void App::Make()
return;
}
if( !cur.request->ajax_serializer && cur.request->ParamValue(L"reqtype") == L"json")
if( !cur.request->info_serializer )
{
log << log3 << "App: using generic JSON serializer" << logend;
ajax_generic_serializer.Clear();
cur.request->ajax_serializer = &ajax_generic_serializer;
json_generic_serializer.Clear(); // !! IMPROVE ME add to the end of a request
cur.request->info_serializer = &json_generic_serializer;
}
plugin.Call(WINIX_CONTENT_MAKE);
@ -728,6 +766,7 @@ void App::CheckKonqueror()
void App::PrepareSessionCookie()
{
if( !cur.session || cur.session->id==0 )
@ -812,7 +851,7 @@ void App::SendHeadersStatic()
void App::SendHeaderContentType()
{
if( cur.request->ajax_serializer )
if( cur.request->return_json )
{
FCGX_PutS("Content-Type: application/json", fcgi_request.out);
}
@ -967,7 +1006,7 @@ void App::FilterCompressSend(bool compressing, int compress_encoding, const std:
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);
if( config.html_filter && cur.request->use_html_filter && !raw && !cur.request->ajax_serializer )
if( config.html_filter && cur.request->use_html_filter && !raw && !cur.request->return_json )
{
TemplatesFunctions::html_filter.Filter(*source, clean_html);
AddDebugInfo(clean_html);
@ -992,6 +1031,9 @@ void App::FilterCompressSend(bool compressing, int compress_encoding, const std:
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();
}
@ -1098,10 +1140,10 @@ Error status = cur.request->status;
bool compressing;
int compress_encoding;
if( cur.request->ajax_serializer )
source = &cur.request->ajaxpage.Str();
if( cur.request->return_json )
source = &json_out_stream.Str();
else
source = &cur.request->page.Str();
source = &cur.request->out_streams[0].Str();
SelectCompression(source->length(), compressing, compress_encoding);
@ -1158,14 +1200,12 @@ void App::SendData(const BinaryPage & page, FCGX_Stream * out)
void App::SendBinaryAnswer()
{
BinaryPage & source = cur.request->binary_page;
BinaryPage & compressed_page = cur.request->compressed_page;
BinaryPage & source = cur.request->out_bin_stream;
Header header = h_200;
Error status = cur.request->status;
bool compressing;
int compress_encoding;
SelectCompression(source.size(), compressing, compress_encoding);
if( status == WINIX_ERR_NO_ITEM || status == WINIX_ERR_NO_FUNCTION || status == WINIX_ERR_UNKNOWN_PARAM )
@ -1182,8 +1222,10 @@ int compress_encoding;
{
if( compressing )
{
compress.Compressing(source, compressed_page, compress_encoding);
SendData(compressed_page, fcgi_request.out);
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();
}
else
{
@ -1195,10 +1237,10 @@ int compress_encoding;
void App::SendAnswer()
{
if( cur.request->use_text_page )
SendTextAnswer();
else
if( cur.request->send_bin_stream )
SendBinaryAnswer();
else
SendTextAnswer();
}

View File

@ -122,7 +122,9 @@ private:
std::string sendh_t, sendh_t2, sendh_t3;
std::string sendfilea, sendfile2a;
std::string send_data_buf;
PT::SpaceToJSON ajax_generic_serializer;
PT::SpaceToJSON json_generic_serializer;
TextStream<std::wstring> json_out_stream;
BinaryPage out_bin_stream_compressed;
bool CheckAccessFromPlugins();
void ProcessRequestThrow();
@ -137,6 +139,7 @@ private:
void SaveSessionsIfNeeded(); // !! wywalic do menagera sesji??
void LogAccess();
void SendData(const BinaryPage & page, FCGX_Stream * out);
void CreateJSONAnswer();
void ReadRequest();
void SendTextAnswer();
@ -156,6 +159,7 @@ private:
void CheckSSL();
void SetSubdomain();
void PrepareSessionCookie();
void AddDebugInfo(std::wstring & out);
void FilterCompressSend(bool compressing, int compress_encoding, const std::wstring & source_ref);

View File

@ -1014,4 +1014,34 @@ void SetMinMax(IntType & val, IntType min_val, IntType max_val)
template<class Stream, class StringType>
void JSONescape(Stream & out, const StringType & str)
{
// !! IMPROVE ME (optimizing)
// it is better to not write one by one character
// but use write method insted
for(size_t i=0 ; i<str.size() ; ++i)
{
switch(str[i])
{
case 0: out << '\\'; out << '0'; break;
case '\r': out << '\\'; out << 'r'; break;
case '\n': out << '\\'; out << 'n'; break;
case '\t': out << '\\'; out << 't'; break;
case 0x08: out << '\\'; out << 'b'; break;
case 0x0c: out << '\\'; out << 'f'; break;
case '\\': out << '\\'; out << '\\'; break;
//case '/': out << '\\'; out << '/'; break; // slash doesn't have to be escaped
case '"': out << '\\'; out << '\"'; break;
default:
out << str[i];
}
}
}
#endif

View File

@ -30,34 +30,15 @@ void Request::SetConfig(Config * pconfig)
}
void Request::ClearAjax()
void Request::ClearOutputStreams()
{
size_t i = ajax.spaces.size();
out_streams.resize(16); // !! IMPROVE ME add as a constant somewhere
while( i-- > 0 )
ajax.RemoveSpace(i);
ajax.table.clear();
PT::Space::TableSingle::iterator s = ajax.table_single.begin();
while( s != ajax.table_single.end() )
{
if( s->first != L"content" && s->first != L"http_status" )
{
ajax.table_single.erase(s++);
for(size_t i=0 ; i<out_streams.size() ; ++i)
out_streams[i].Clear();
}
else
{
// small optimization when deleting
// the memory for "content" and "http_status" will be reused
s->second.clear();
++s;
}
}
}
void Request::Clear()
@ -67,6 +48,7 @@ void Request::Clear()
++id;
RemovePostFileTmp(post_file_tab);
ClearOutputStreams();
post_tab.clear();
post_file_tab.clear();
@ -76,8 +58,8 @@ void Request::Clear()
role = responder;
headers.Clear();
page.Clear();
ajaxpage.Clear();
debug.Clear();
page_generated = false;
@ -117,12 +99,13 @@ void Request::Clear()
start_date.Clear();
subdomain.clear();
ClearAjax();
ajax_serializer = 0;
return_info_only = false;
info.Clear();
info_serializer = 0;
return_json = false;
binary_page.clear();
compressed_page.clear();
use_text_page = true;
out_bin_stream.clear();
send_bin_stream = false;
gen_trim_white = false;
gen_skip_new_line = false;

View File

@ -44,20 +44,100 @@ struct Request
// headers, page and debug
//std::ostringstream headers, page, debug;
// !! IMPROVE ME change headers to some kind of a map, may PT::Space ?
TextStream<std::string> headers;
HtmlTextStream page, debug;
TextStream<std::wstring> ajaxpage;
HtmlTextStream debug;
// binary page
BinaryPage binary_page;
// a compressed page ready to send to the client
BinaryPage compressed_page;
// winix can return either a text answer or a binary answer
// if send_bin_stream is true then the binary answer is sent (out_bin_stream)
// or if send_bin_stream is false then the text answer is sent
// default: false
//
//
//
// winix answer send to the client's browser
// |
// |
// depending on send_bin_stream
// -------------------------------------------------
// | |
// text answer binary answer
// | |
// depending on return_json sending out_bin_stream
// ------------------------------------
// | |
// normal request ajax request
// | |
// sending out_streams[0] depending on return_info_only
// ------------------------------------------------------
// | |
// generating JSON object from: generating JSON object only from info
// out_streams and info, e.g.: e.g.:
// { { info object serialized here }
// "stream_1": "some html content",
// "stream_2": "some other html content",
// "info": { info object serialized here }
// }
// note that out_streams[0] is not sent
// in JSON answers
//
//
bool send_bin_stream;
// -------------------------------------------------------------------------------------
// binary answer
//
// binary page sent to the client if send_bin_stream is true
BinaryPage out_bin_stream;
//
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
// text answer
//
// when returning the text answer we can either return the whole html page (normal requests)
// or a JSON object (for requests generated from AJAX)
// if return_json is false then we return the whole html page (which is in out_streams[0])
// if return_json is true we are creating an JSON object from out_streams
// (zero stream is ignored) and from info space (see above picture)
// (or just only from info if return_info_only is true)
// default: false
// return_json is set to true by App at the beginning of a request
// if reqtype:json parameter is present (in the url)
// note: return_json is only valid if send_bin_stream is false
bool return_json;
// main text output streams where the html otput is generated from ezc templates
// the zero stream (out_streams[0]) is used as the main stream
// to which the whole html page (with doctype, head, body) is generated
// the rest streams can be only used in ajax requests (send in JSON format to the client)
// in ezc templates you can use [ezc stream ...] keyword
// to switch between streams e.g. [ezc stream "0" "2"]
std::vector<HtmlTextStream> out_streams;
// if true the JSON object is generated only from info (out_streams are not used)
// default: false
bool return_info_only;
// additional info added when sending the JSON answer
PT::Space info;
// info serializer
// if not set then the json_generic_serializer from App will be used
// default: null (json_generic_serializer used)
PT::SpaceToJSON * info_serializer;
//
// -------------------------------------------------------------------------------------
// if true then either page or ajaxpage will be sent to the client
// if false then binary_page is sent
// default: true
bool use_text_page;
// if set to true then the standard template system will not be generated
// default: false
@ -67,6 +147,10 @@ struct Request
// default: true
bool use_html_filter;
// raw parameters
PostTab post_tab;
PostFileTab post_file_tab;
@ -157,15 +241,6 @@ struct Request
// subdomain = HTTP_HOST environment variable - config->base_url
std::wstring subdomain;
// used as a JSON output (when ajax_serializer is defined)
// it will be serialized and have at least:
// 'content' string - the whole html content
// 'http_status' integer - http status code (e.g. 200) !! FIXME this is not added at the moment
PT::Space ajax;
// if not null then the request will have a JSON as an output
PT::SpaceToJSON * ajax_serializer;
// if this variable is true then winix always return 200 OK header
// when the status would be 404 (not found) or 403 (permission denied)
// default: false
@ -222,7 +297,7 @@ private:
// used in ParamValue() and PostVar() when there is no such a param
const std::wstring str_empty;
void ClearAjax();
void ClearOutputStreams();
};

View File

@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010-2012, Tomasz Sowa
* Copyright (c) 2010-2013, Tomasz Sowa
* All rights reserved.
*
*/
@ -144,6 +144,30 @@ bool ssl = false;
}
void System::CreateItemLink(long parent_id, const std::wstring & url, const std::wstring & subdomain,
std::wstring & link, bool clear_str)
{
PutUrlProto(config->use_ssl, link, clear_str);
if( !subdomain.empty() )
{
link += subdomain;
link += '.';
}
link += config->base_url;
dirs.MakePath(parent_id, link, false); // !! IMPROVE ME may some kind of error checks here?
link += url;
}
void System::CreateItemLink(const Item & item, std::wstring & link, bool clear_str)
{
CreateItemLink(item.parent_id, item.url, cur->request->subdomain, link, clear_str);
}
// !! IMPROVE ME
// !! mozna zrobic jakas obsluge kiedy nie mozemy sie redirectnac, np gdy wystapil blad
// !! moze zwracac jakas wartosc?

View File

@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010-2012, Tomasz Sowa
* Copyright (c) 2010-2013, Tomasz Sowa
* All rights reserved.
*
*/
@ -171,6 +171,13 @@ public:
// reloading time zones
void ReadTimeZones();
void CreateItemLink(long parent_id, const std::wstring & url, const std::wstring & subdomain,
std::wstring & link, bool clear_str = true);
void CreateItemLink(const Item & item, std::wstring & link, bool clear_str = true);
private:
Cur * cur;

View File

@ -13,7 +13,7 @@
#define WINIX_VER_MAJOR 0
#define WINIX_VER_MINOR 5
#define WINIX_VER_REVISION 5
#define WINIX_VER_REVISION 6
#endif

View File

@ -464,9 +464,9 @@ void Rm::Clear()
void Rm::CreateJSON(bool status)
{
if( status )
cur->request->page << "[true]\n";
cur->request->out_streams[0] << "[true]\n";
else
cur->request->page << "[false]\n";
cur->request->out_streams[0] << "[false]\n";
cur->request->page_generated = true;
cur->request->use_html_filter = false;

View File

@ -29,6 +29,12 @@ Upload::Upload()
}
void Upload::Init()
{
json_serializer.TreatAsTable(L"infospace");
json_serializer.TreatAsNumeric(L"size");
}
bool Upload::HasAccess(const Item & item)
{
@ -188,7 +194,7 @@ void Upload::UploadMulti()
}
if( is_jquery_upload )
CreateJSON();
CreateAnswer();
else
system->RedirectToLastDir();
}
@ -224,7 +230,7 @@ void Upload::UploadSingle()
post_file.tmp_filename.clear();
if( is_jquery_upload )
CreateJSON();
CreateAnswer();
else
if( cur->request->status == WINIX_ERR_OK )
system->RedirectTo(cur->request->item, L"/cat");
@ -255,19 +261,40 @@ void Upload::MakePost()
void Upload::CreateJSON()
void Upload::CreateAnswer()
{
size_t loc = TemplatesFunctions::locale.GetCurLang();
Ezc::Pattern * pat = TemplatesFunctions::patterns.Get(template_index, loc);
Request & req = *cur->request;
req.info.name = L"infospace"; // 'infospace' will be serialized to an array
if( pat )
for(size_t i=0 ; i<req.item_tab.size() ; ++i)
{
templates->Generate(*pat);
cur->request->page_generated = true;
cur->request->use_html_filter = false;
PT::Space & file = req.info.AddSpace(L"");
file.Add(L"name", req.item_tab[i].url);
file.Add(L"size", req.item_tab[i].file_size);
std::wstring & link = file.Add(L"url", L"");
system->CreateItemLink(req.item_tab[i], link);
std::wstring & del_url = file.Add(L"delete_url", link);
del_url += L"/rm/jquery_upload";
file.Add(L"delete_type", L"POST");
if( req.item_tab[i].file_type == WINIX_ITEM_FILETYPE_IMAGE )
{
std::wstring & thumb = file.Add(L"thumbnail_url", link);
if( req.item_tab[i].has_thumb )
thumb += L"/-/thumb";
}
}
cur->request->return_json = true;
cur->request->return_info_only = true;
cur->request->info_serializer = &json_serializer;
}
void Upload::MakeGet()
{
@ -280,7 +307,7 @@ void Upload::MakeGet()
db->GetItems(cur->request->item_tab, query);
CreateJSON();
CreateAnswer();
}
}

View File

@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* Copyright (c) 2010-2013, Tomasz Sowa
* All rights reserved.
*
*/
@ -11,7 +11,7 @@
#define headerfile_winix_functions_upload
#include "functionbase.h"
#include "space/spacetojson.h"
namespace Fun
@ -35,6 +35,13 @@ private:
DbItemQuery query;
bool is_jquery_upload;
// this object is used in App at the end of a request
// for serializing Request::info to JSON
// this will make a problem if in the future we'll use multithread requests
PT::SpaceToJSON json_serializer;
void Init();
bool HasAccess(const Item & item);
bool UploadSaveStaticFile(const Item & item, const std::wstring & tmp_filename);
bool FunUploadCheckAbuse();
@ -42,7 +49,7 @@ private:
void UploadSingle();
void ResizeImage(Item & item);
void CreateThumb(Item & item);
void CreateJSON();
void CreateAnswer();
};

View File

@ -1 +0,0 @@
[content]

View File

@ -1 +0,0 @@
[content]

View File

@ -20,13 +20,11 @@ namespace TemplatesFunctions
size_t pat_index; // main index pattern
size_t pat_index_fullscreen; // an empty pattern (without menus etc. but with all rest html tags, used for ckeditor images browser)
size_t pat_index_rawcontent; // completly empty pattern (only content, without html tags such as <html>, <body>)
size_t pat_index_ajaxcontent; // ajax pattern (only content, similar as pat_index_rawcontent)
size_t pat_err_404; // 404 error
size_t pat_err_per_denied; // permission denied error
Patterns patterns; // all html patterns
IndexPatterns index_patterns; // patterns for main index template (those from mountpoint)
IndexPatterns index_patterns; // patterns for main index templates (those from mountpoint)
// index_patterns uses patterns as a storage
ChangePatterns change_patterns; // patterns for change_template mount option (storage is in 'patterns' too)
PatternCacher pattern_cacher; // patterns for user items (files with an executable bit set)
@ -822,8 +820,6 @@ using namespace TemplatesFunctions;
pat_index = patterns.Add(config->templates_index);
pat_index_fullscreen = patterns.Add(L"index_fullscreen.html");
pat_index_rawcontent = patterns.Add(L"index_rawcontent.html");
pat_index_ajaxcontent = patterns.Add(L"index_ajaxcontent.html");
pat_err_404 = patterns.Add(L"err_404.html");
pat_err_per_denied = patterns.Add(L"err_per_denied.html");
@ -910,12 +906,6 @@ using namespace TemplatesFunctions;
Ezc::Pattern * index = 0;
if( cur->request->ajax_serializer )
index = patterns.Get(pat_index_ajaxcontent, locale.GetCurLang());
else
if( cur->request->IsParam(L"rawcontent") )
index = patterns.Get(pat_index_rawcontent, locale.GetCurLang());
else
if( cur->request->IsParam(L"fullscreen") )
index = patterns.Get(pat_index_fullscreen, locale.GetCurLang());
else
@ -954,7 +944,7 @@ using namespace TemplatesFunctions;
generator.SkipNewLine(gen_skip_new_line);
generator.RecognizeSpecialChars(gen_use_special_chars);
generator.SetMax(config->ezc_max_elements, config->ezc_max_loop_elements);
generator.Generate(cur->request->page, *index);
generator.Generate(cur->request->out_streams, *index);
}
else
{
@ -971,7 +961,10 @@ using namespace TemplatesFunctions;
if( !empty_pars.empty() )
empty_pars.clear();
Info info(cur->request->page, empty_pars, empty_string, empty_stream);
// !! FIX ME
// at the moment stream 0 is used
// here should be something other
Info info(cur->request->out_streams[0], empty_pars, empty_string, empty_stream);
info.iter = 0;
info.res = false;
@ -988,7 +981,7 @@ using namespace TemplatesFunctions;
generator.SkipNewLine(gen_skip_new_line);
generator.RecognizeSpecialChars(gen_use_special_chars);
generator.SetMax(config->ezc_max_elements, config->ezc_max_loop_elements);
generator.Generate(cur->request->page, pattern);
generator.Generate(cur->request->out_streams, pattern);
}

View File

@ -37,9 +37,7 @@ class Functions;
namespace TemplatesFunctions
{
extern size_t pat_index;
extern size_t pat_index_ajaxcontent;
extern size_t pat_index_fullscreen;
extern size_t pat_index_rawcontent;
extern size_t pat_err_404;
extern size_t pat_err_per_denied;