How to get detailed error message when QTWebKit fails to load a page? - qtwebkit

QtWebKit calls QWebPage::loadFinished ( false ) when a web page failed to load - but gives no clue as to why it failed.
How do I get a detailed error message, like HTTP response code or other message?

It turns out there are a couple ways to get more detail about failures:
Implement the onResourceRequested and onResourceReceived callbacks on page:
page.onResourceRequested = function (resource) {
log('resource requested: ' + resource.url);
}
page.onResourceReceived = function (resource) {
log('resource received: ' + resource.status + ' ' + resource.statusText + ' ' +
resource.contentType + ' ' + resource.url);
}
If you are looking for more detail still, you need to patch PhantomJS internals. Update its CustomPage object (in WebPage.cpp) to implement QTWebKit's ErrorExtension. Here is code you can add that does that:
protected:
bool supportsExtension(Extension extension) const {
if (extension == QWebPage::ErrorPageExtension)
{
return true;
}
return false;
}
bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0)
{
if (extension != QWebPage::ErrorPageExtension)
return false;
ErrorPageExtensionOption *errorOption = (ErrorPageExtensionOption*) option;
std::cerr << "Error loading " << qPrintable(errorOption->url.toString()) << std::endl;
if(errorOption->domain == QWebPage::QtNetwork)
std::cerr << "Network error (" << errorOption->error << "): ";
else if(errorOption->domain == QWebPage::Http)
std::cerr << "HTTP error (" << errorOption->error << "): ";
else if(errorOption->domain == QWebPage::WebKit)
std::cerr << "WebKit error (" << errorOption->error << "): ";
std::cerr << qPrintable(errorOption->errorString) << std::endl;
return false;
}
This will give you most of the error information, but you can still get onLoadFinished(success=false) events without getting more detail. From my research, the primary cause of those is canceled load requests. QTWebKit sends a fail notification for cancellations, but doesn't report any detail.

Related

Input/output error after first read from pseudo terminal

I have created pseudo terminal master/slave and read on master side using select with the following code:
fd_set read_fd;
struct timeval timeout;
while (is_running) {
FD_ZERO(&read_fd);
FD_SET(fd, &read_fd);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
int ret = select(fd + 1, &read_fd, NULL, NULL, &timeout);
std::cout << "select return:" << ret << std::endl;
if (ret == -1) {
std::cerr << "select error:" << strerror(errno) << " code:" << errno << std::endl;
is_running = false;
}
if (FD_ISSET(fd, &read_fd)) {
if (read(fd, buff, size) == -1) {
if (EIO == errno) {
// After first read - Input/output error code:5
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::cerr << "read error:" << strerror(errno) << " code:" << errno << std::endl;
} else {
std::cout << "read:" << buff << std::endl;
}
}
}
std::cout << "read exit" << std::endl;
In terminal I send data from slave to master using
echo "22222222222222" > /dev/pts/23
In case if data send on master side read operation work fine - I see that select returns 1 and data got read but on next iterations in while loop select also returns 1 but read function constantly fails with error EIO and it is not clear for me.
select return:1
read:22222222222222 <------------------------ data read: OK
select return:1
alloc:8 write:7 buff:hello14
read error:Input/output error code:5 <------------------- EIO
select return:1
read error:Input/output error code:5 <------------------- EIO
Could you please help me to understood on why after first read (echo "22222222222222" > /dev/pts/23 on slave) select returns 1 but all read operations fails with EIO error.

yaml-cpp always creates a scalar node with size 0

I'd like to use yaml-cpp for storeing some config-values. In order to get in touch with yaml-cpp, I've written a method which creates a node (_config is from Type YAML::Node), put some values in it and write it into a file:
void write_config()
{
std::ofstream fout("/home/user/config.yaml");
_config["Foo"]["0"] = "0";
_config["Foo"]["1"] = "1";
_config["Foo"]["2"] = "2";
_config["Foo"]["3"] = "3";
_config["Foo"]["4"] = "4";
_config["Foo"]["5"] = "5";
fout << _config;
}
after running this Method, a valid yaml file is created:
Foo:
1: 1
3: 3
0: 0
5: 5
4: 4
2: 2
After that, I have created a Method to read the file and print some information:
void load_config()
{
_config = YAML::Node("/home/user/config.yaml");
cout << "_config: " << _config << endl;
cout << "doc.Type(): " << _config.Type() << "\n";
cout << "doc.size(): " << _config.size() << "\n";
for (const auto& kv : _config)
{
std::cout << kv.first.as<std::string>() << "\n"; // prints Foo
std::cout << kv.second.as<std::string>() << "\n"; // prints Foo
}
}
but the output is:
_config: /home/user/config.yaml
doc.Type(): 2
doc.size(): 0
could someone tell me why the Node is empty (size == 0) and how I can read the file properly?
Thank you in advance!
I've found my Mistake...
_config = YAML::Node("/home/user/config.yaml");
should be
_config = YAML::LoadFile("/home/user/config.yaml");

asio use_future instead of yield[ec]

i want to make container of futures ,each future is void result of a task so that i could use wait_for_any on the container ,each task is coroutine which i currently implement using yield_context,and inside this coroutine there initiating function which returns ec and result where i use ec to analyze result.and then another coroutine is called passes same yield_context .
i want to know how to make this design.
and if i ll use use_future ,how can i pass error code to ec not throwing it unless there is no way except throwing it ,in this case i ll put try and catch around async initiating functions.
all these tasks will be posted ,spawned ... on asio io_service .
this is my main parts of code:
this is the spawn of task
boost::asio::spawn(GetServiceReference(), boost::bind(&HTTPRequest::Execute, boost::placeholders::_1, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map()));
and this is the coroutine using yield_context
void HTTPRequest::Execute(boost::asio::yield_context yield_r, std::string request_name, std::map<std::string, boost::shared_ptr<HTTPResponse>>& mHTTPClient_Responses_Map)
{
resolver_iterator iterator_connect = boost::asio::async_connect(mSock, iterator_resolve, yield_r[ec]);
}
and inside Execute we use ec to analyze
if (ec == boost::system::errc::errc_t::success){}
and here we start another coroutine passing same yield_context
SendRequest(yield_r);
}
i want to change this so i have container of futures for all spawned Execute,i do not care about results of Execute because i put them to member class Response.
But i need result in future so that i can use wait_any on the container .
If you can change your implementation, use the async_result pattern.
This makes it so you can use your method with any of the approaches (completion handler, yield context or use_future).
I reproduce the self-contained example from here for inspiration:
Comprehensive Demo
Showing how to use it with with
coro's and yield[ec]
coro's and yield + exceptions
std::future
completion handlers
Live On Coliru
#define BOOST_COROUTINES_NO_DEPRECATION_WARNING
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp>
using boost::system::error_code;
namespace asio = boost::asio;
template <typename Token>
auto async_meaning_of_life(bool success, Token&& token)
{
#if BOOST_VERSION >= 106600
using result_type = typename asio::async_result<std::decay_t<Token>, void(error_code, int)>;
typename result_type::completion_handler_type handler(std::forward<Token>(token));
result_type result(handler);
#else
typename asio::handler_type<Token, void(error_code, int)>::type
handler(std::forward<Token>(token));
asio::async_result<decltype (handler)> result (handler);
#endif
if (success)
handler(error_code{}, 42);
else
handler(asio::error::operation_aborted, 0);
return result.get ();
}
void using_yield_ec(asio::yield_context yield) {
for (bool success : { true, false }) {
boost::system::error_code ec;
auto answer = async_meaning_of_life(success, yield[ec]);
std::cout << __FUNCTION__ << ": Result: " << ec.message() << "\n";
std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
}
}
void using_yield_catch(asio::yield_context yield) {
for (bool success : { true, false })
try {
auto answer = async_meaning_of_life(success, yield);
std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
} catch(boost::system::system_error const& e) {
std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
}
}
void using_future() {
for (bool success : { true, false })
try {
auto answer = async_meaning_of_life(success, asio::use_future);
std::cout << __FUNCTION__ << ": Answer: " << answer.get() << "\n";
} catch(boost::system::system_error const& e) {
std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
}
}
void using_handler() {
for (bool success : { true, false })
async_meaning_of_life(success, [](error_code ec, int answer) {
std::cout << "using_handler: Result: " << ec.message() << "\n";
std::cout << "using_handler: Answer: " << answer << "\n";
});
}
int main() {
asio::io_service svc;
spawn(svc, using_yield_ec);
spawn(svc, using_yield_catch);
std::thread work([] {
using_future();
using_handler();
});
svc.run();
work.join();
}
Prints:
using_yield_ec: Result: Success
using_yield_ec: Answer: 42
using_yield_ec: Result: Operation canceled
using_yield_ec: Answer: 0
using_future: Answer: 42
using_yield_catch: Answer: 42
using_yield_catch: Caught: Operation canceled
using_future: Caught: Operation canceled
using_handler: Result: Success
using_handler: Answer: 42
using_handler: Result: Operation canceled
using_handler: Answer: 0
Note: for simplicity I have not added output synchronization, so the output can become intermingled depending on runtime execution order

How to upload the Image to server in blackberry 10 cascades?

I have tried the following code for image uploading,in this code am able to get the response from server but the image size is always zero in server.Can anyone help me about this regards,
void App::uploadImage(){
QString path(QDir::currentPath() + "/app/native/assets/Icon/img.jpg");
QNetworkRequest request(
QUrl( "http://domain.com?type=uploadimages&deviceid=12323"));
QByteArray boundary = "-------------------------32142544626177";
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "error read image";
return;
}
QByteArray fileContent(file.readAll());
QByteArray data = "--" + boundary + "\r\n";
data +=
"Content-Disposition: form-data; name=\"data\"; filename=\"img.jpg\";\r\n";
data += "Content-Type: image/jpg\r\n\r\n" + fileContent + "\r\n";
data += "--" + boundary + "--\r\n";
request.setRawHeader("Content-Type",
"multipart/form-data; boundary=" + boundary);
request.setRawHeader("Content-Length",
QString::number(data.size()).toAscii());
file.close();
qDebug() << "data" << data.size();
QNetworkAccessManager *am = new QNetworkAccessManager(this);
QNetworkReply *reply = am->post(request, "&data=" +data);
QObject::connect(am, SIGNAL(finished(QNetworkReply*)), this,
SLOT(replyFinished(QNetworkReply*)));
}
void App::replyFinished(QNetworkReply* reply) {
reply->open(QIODevice::ReadOnly);
if (reply->error() == QNetworkReply::NoError) {
QByteArray str = (reply->readAll());
QString response = QString::fromUtf8(str.data(), str.size());
qDebug() << " response " << response;
}
else{
qDebug() << "error response server";
}
}
QString body = "" ;
const QUrl url("http://someurl.to/make/the/post" );
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart textPartData;
body = "" ;
QTextStream(&body) << "";
textPartData.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=utf-8");
textPartData.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"data\""));
textPartData.setBody(body.toAscii());
for(int i=0; i< number_of_files_to_send ; i++){
QHttpPart imagePart;
QString header_body = "";
QTextStream(&header_body) << "form-data; name=\"" << name_of_the_file << "\"; filename=\"" << name_of_the_file << ".jpg\"" ;
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(header_body));
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
//prepare file for upload
QString filepath;
QTextStream(&filepath) << FunkyPigeonBlackberry::getInstance()->dataModelProductDetails()->custom_image(i).value("cut_image").toString();
// pack the new file
QFile *file = new QFile(filepath);
file->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(file);
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
multiPart->append(imagePart);
}
multiPart->append(textPartData);
multiPart->append(textPartProductDetails);
multiPart->append(textPartDataDelivery);
QNetworkRequest request(url);
QNetworkReply* reply = m_networkAccessManager->post(request, multiPart);
connect(reply, SIGNAL(finished()), this, SLOT(onNetworkResponse()));

Issue Parsing File with YAML-CPP

In the following code, I'm having some sort of issue getting my .yaml file parsed using parser.GetNextDocument(doc);. After much gross debugging, I've found that the (main) issue here is that my for loop is not running, due to doc.size() == 0; What am I doing wrong?
void
BookView::load()
{
aBook.clear();
QString fileName =
QFileDialog::getOpenFileName(this, tr("Load Address Book"),
"", tr("Address Book (*.yaml);;All Files (*)"));
if(fileName.isEmpty())
{
return;
}
else
{
try
{
std::ifstream fin(fileName.toStdString().c_str());
YAML::Parser parser(fin);
YAML::Node doc;
std::map< std::string, std::string > entry;
parser.GetNextDocument(doc);
std::cout << doc.size();
for( YAML::Iterator it = doc.begin(); it != doc.end(); it++ )
{
*it >> entry;
aBook.push_back(entry);
}
}
catch(YAML::ParserException &e)
{
std::cout << "YAML Exception caught: "
<< e.what()
<< std::endl;
}
}
updateLayout( Navigating );
}
The .yaml file being read was generated using yaml-cpp, so I assume it is correctly formed YAML, but just in case, here's the file anyways.
^#^#^#\230---
-
address: ******************
comment: None.
email: andrew(dot)levenson(at)gmail(dot)com
name: Andrew Levenson
phone: **********^#
Edit: By request, the emitting code:
void
BookView::save()
{
QString fileName =
QFileDialog::getSaveFileName(this, tr("Save Address Book"), "",
tr("Address Book (*.yaml);;All Files (*)"));
if (fileName.isEmpty())
{
return;
}
else
{
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly))
{
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
std::vector< std::map< std::string, std::string > >::iterator itr;
std::map< std::string, std::string >::iterator mItr;
YAML::Emitter yaml;
yaml << YAML::BeginSeq;
for( itr = aBook.begin(); itr < aBook.end(); itr++ )
{
yaml << YAML::BeginMap;
for( mItr = (*itr).begin(); mItr != (*itr).end(); mItr++ )
{
yaml << YAML::Key << (*mItr).first << YAML::Value << (*mItr).second;
}
yaml << YAML::EndMap;
}
yaml << YAML::EndSeq;
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_5);
out << yaml.c_str();
}
}
Along the lines of what you thought, the problem is that you're writing using QDataStream but reading using plain std::ifstream. You need to do either one or the other.
If you want to use the QDataStream, you'll need to read it in as well. Check out the doc for more detail, but it looks like you can just grab the YAML string:
QDataStream in(&file);
QString str;
in >> str;
and then pass it to yaml-cpp:
std::stringstream stream; // remember to include <sstream>
stream << str; // or str.toStdString() - I'm not sure about how QString works
YAML::Parser parser(stream);
// etc.
The point of a std::stringstream is to transform your string containing YAML into a stream that the YAML parser can read.