Wrong UserAgent (Opera, Chrome, Chromium, Safari) behavior with WResource
Added by Łukasz Matuszewski almost 14 years ago
I have my own WResource, and i use it in my own WItemDelegate on WTableView. Here is a main use mir_sp_explorercontrols.cpp:
this->m_tv = new WTableView(cell);
m_session.setConnection(m_firebird);
m_session.mapClass<NazArtNazAlbItp>("MIR_NAZARTNAZALBITP");
dbo::Transaction transaction(m_session);
m_query =
m_session.query< dbo::ptr<NazArtNazAlbItp> >
("select u "\
" from MIR_NAZARTNAZALBITP u "\
);
m_model = new NazArtNazAlbItpModel(this->m_dm, this);
m_model->setQuery(m_query, true);
m_model->addColumn("ART_NAZWA_ARTYSTY", tr(MIR_TABLE_EXP_ARTIST_NAME));
m_model->addColumn("ALB_NAZWA_ALBUMU", tr(MIR_TABLE_EXP_ALBUM_NAME));
//...
this->m_tv->setModel(m_model);
this->m_tv->setItemDelegateForColumn(6, new MusicItemDelegate(this));
//...
this->m_tv->setItemDelegateForColumn(7, new MusicItemDelegate(this));
What i really done is taken code from WStandardItemDelegate and modified the lines with anchor in method update:
WResource *res = NULL;
if (index.column() == 7)
res = boost::any_cast<MusicResource *>(index.data(MusicResourceRole));
if (!res && index.column() == 6)
res = boost::any_cast<ParamsResource *>(index.data(ParamsResourceRole));
if (!internalPath.empty() || !url.empty()) {
WAnchor *a = anchorWidget(widgetRef);
if (!internalPath.empty())
a->setRefInternalPath(internalPath);
else
a->setRef(url);
if (res)
a->setResource(res);
}
else if (res)
{
WAnchor *a = anchorWidget(widgetRef);
a->setResource(res);
}
Source of WResource is in mir_sp_musicresource.cpp and mir_sp_paramsresource.cpp. Here is a typical use:
void MusicResource::handleRequest(const Wt::Http::Request& request,
Wt::Http::Response& response)
{
Wt::Http::ResponseContinuation *continuation = request.continuation();
ostringstream oss;
wstring generic_wstr;
bool isIE = false;
bool isChrome = false;
string ext;
bool audioFetched = false;
try
{
if (m_sciezka_do_pliku.empty())
{
Transaction tr = this->m_dm->createTransaction(amRead,
ilReadCommitted, lrWait);
tr->Start();
ostringstream sql;
sql << "select u.UTW_SCIEZKA_UTWORU, g.GAT_GATUNEK, ar.ART_NAZWA_ARTYSTY "
" , a.ALB_NAZWA_ALBUMU, u.UTW_TYTUL_UTWORU"
" from MIR_UTWOR u "
" inner join MIR_ALBUM a on a.ALB_ID = u.UTW_ALB_ID "
" inner join MIR_ARTYSTA ar on ar.ART_ID = u.UTW_ART_ID"
" inner join MIR_GATUNEK g on g.GAT_ID = u.UTW_GAT_ID"
" where u.UTW_ID = " << this->m_utwId;
string sqlstmt = sql.str();
Statement stmt = this->m_dm->createStatement(&tr);
stmt->Prepare(sqlstmt);
stmt->Execute();
isIE = request.userAgent().find("MSIE") != std::string::npos;
isChrome = request.userAgent().find("Chrome") != std::string::npos;
if (stmt->Fetch())
{
stmt->Get(1, m_sciezka_do_pliku);
if (SyNaTPGApp::mcs_osid == POCO_OS_WINDOWS_NT)
m_sciezka_do_pliku = SyNaT::MIR::SP::SyNaTPGApp::mcs_root_elem
+ m_sciezka_do_pliku;
ext = m_sciezka_do_pliku.substr(m_sciezka_do_pliku.find_last_of(".")).substr(1);
if (!(isIE || isChrome))
{
string dbS;
stmt->Get(2, dbS);
oss << dbS << "_";
stmt->Get(3, dbS);
oss << dbS << "_";
stmt->Get(4, dbS);
oss << dbS << "_";
stmt->Get(5, dbS);
oss << dbS << "." << ext;
}
else
{
oss << "utwor" << this->m_utwId << "." << ext;
}
m_suggestedFileName = oss.str();
UnicodeString icusuggestedFileName = UnicodeString::fromUTF8(m_suggestedFileName).findAndReplace("\"", "_");
m_suggestedFileName.clear();
icusuggestedFileName.toUTF8String(m_suggestedFileName);
}
generic_wstr = ZenLib::Ztring(((SyNaT::MIR::SP::SyNaTPGApp::mcs_osid == POCO_OS_WINDOWS_NT ? "\\\\?\\" : "") + Poco::Path(m_sciezka_do_pliku, Poco::Path::PATH_UNIX).toString()).c_str()).To_Unicode();
m_file_size = file_size(generic_wstr);
tr->Commit();
audioFetched = true;
}
}
catch(std::exception &e)
{
WApplication::instance()->log("error") << e.what();
}
if (audioFetched)
{
// this is taken from void WResource::handle(WebRequest *webRequest, WebResponse *webResponse, Http::ResponseContinuation *continuation) source file...
if (!continuation && !m_suggestedFileName.empty())
{
std::string fileField;
if (isIE || isChrome)
{
fileField = "filename=\""
+ Wt::Utils::urlEncode(m_suggestedFileName, " ") + "\";";
}
else
{
fileField = "filename=\"" + m_suggestedFileName + "\";";
}
// Next will be picked by RFC 5987 in favour of the
// one without specified encoding (Chrome9,
fileField+= Wt::Utils::EncodeHttpHeaderField("filename", WString::fromUTF8(m_suggestedFileName));
response.addHeader("Content-Disposition", "attachment;" + fileField);
}
// calculate the current start
int iteration =
continuation ? boost::any_cast<int>(continuation->data()) : 0;
if (iteration == 0)
{
response.setContentLength(this->m_file_size);
string mime_type = Utils::findContentTypeByExt(ext);
if (!mime_type.empty())
response.setMimeType(mime_type);
}
boost::filesystem::ifstream f(generic_wstr, boost::filesystem::ifstream::binary);
f.seekg((m_file_size / m_iterations) * iteration, ios_base::beg);
char *buf = new char[m_file_size / m_iterations];
f.read(buf, m_file_size / m_iterations);
// if we have not yet finished, create a continuation to serve more
if (!f.eof())
{
continuation = response.createContinuation();
// remember what to do next
continuation->setData(++iteration);
}
f.close();
response.out().write(buf, m_file_size / m_iterations);
delete[] buf;
}
}
}
The working example of this behavior is on http://synat.eti.pg.gda.pl where you can login as lukasz and password of anakin or you can register. There you will see WTreeView with link in last column to vector of MPEG-7 parameters of given audio sample (csv file). The application is in early development stage so there is not much to see.
YOU MUST USE MENTIONED BROWSERS AS TESTING ENVIRONMENT. On Debian Squeeze you can use package chromium-browser.
Thanks kindly for any help on this...
Greetings
Lukasz Matuszewskie
SyNaTPG.zip (135 KB) SyNaTPG.zip |
Replies (5)
RE: Wrong UserAgent (Opera, Chrome, Chromium, Safari) behavior with WResource - Added by Wim Dumon almost 14 years ago
Hello Lukasz,
What exactly is the problem?
BR,
Wim.
RE: Wrong UserAgent (Opera, Chrome, Chromium, Safari) behavior with WResource - Added by Łukasz Matuszewski almost 14 years ago
The problem is that when i left click on the 6th or 7th column in WTableView (that is where my custom WItemDelegate is set, based on WStandardItemDelegate) the file of MPEG-7 parameters are downloaded (with Content-Disposition, mime type and content lenght headers set) and on mentioned browsers (Google Chrome, Safari, Opera maybe others but not Firefox, IE 7 and up (maybe IE 6) and even lynx) just triggers "Loading..." indicator just after click on mentioned WAnchor with custom WResource (MIR::SP::MusicResource, MIR::SP::ParamsResource). After downloading the file "Loading..." indicator still remains and app is useless (menu doesn't work).
My solution for this problem is:
I have blocked left mouse click on mentioned WAnchor with JavaScript, and allowed olny right mouse click. It works becouse "Save As..." or "Open in New Tab" just works, without mentioned "Loading..." indicator.
To reproduce this error you should create WTableView with custom WItemDelegate, custom Wt::Dbo::QueryModel, custom WResource just like code above in my first post (pushind some bytes from WResource, just for simplicity) and open such application by newest Opera, newest Google Chrome, newest Safari.
RE: Wrong UserAgent (Opera, Chrome, Chromium, Safari) behavior with WResource - Added by Koen Deforche almost 14 years ago
Hey,
This is a known problem: you need to indicate that the download should start in a new window, using anchor->setTarget(NewWindow).
Since you are already modifying WItemDelegate, you should add this there. The problem with the default behavior is that some browsers seem to cancel ajax communication for the current page in preparation of donwloading the file in the current window (without proper error propagation), for reasons I do not very well understand, since I would expect that content-disposition actually prevents that.
Btw. in the git, we have consolidated the resource/url/internalpath overloads in a new WLink class, so you would no longer need to specialize WItemDelegate to pass a link to a resource. But I would be interested in hearing if the 'setTarget(NewWindow)' works, and perhaps we should add it there in case the link is to a resource.
Regards,
koen
RE: Wrong UserAgent (Opera, Chrome, Chromium, Safari) behavior with WResource - Added by Łukasz Matuszewski almost 14 years ago
The trick with setTarget(NewWindow) will work, becouse i have emulate new windows with right_click->open in new tab.
Thanks again for awsome answer.
BR,
Lukasz
RE: Wrong UserAgent (Opera, Chrome, Chromium, Safari) behavior with WResource - Added by Łukasz Matuszewski almost 14 years ago
Yes you should add it there in case the link is to a resource.
BR,
Lukasz Matuszewski