How can I start a download from c++ code compiled web assembly? - c++

I've been trying to not do this javascript side and I haven't found anything satisfying yet.
Fetch API seems to be a good lead, but I can't seem to find a way to start the download in the browser so it can download a zip file.
This is emscripten code snippet, but it seems to be a local file of some sort.
#include <stdio.h>
#include <string.h>
#include <emscripten/fetch.h>
void downloadSucceeded(emscripten_fetch_t *fetch) {
printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
// The data is now available at fetch->data[0] through fetch->data[fetch->numBytes-1];
emscripten_fetch_close(fetch); // Free data associated with the fetch.
}
void downloadFailed(emscripten_fetch_t *fetch) {
printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status);
emscripten_fetch_close(fetch); // Also free data on failure.
}
int main() {
emscripten_fetch_attr_t attr;
emscripten_fetch_attr_init(&attr);
strcpy(attr.requestMethod, "GET");
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
attr.onsuccess = downloadSucceeded;
attr.onerror = downloadFailed;
emscripten_fetch(&attr, "myfile.dat");
}

Add this to your cpp file.
EM_JS(void, DownloadUrl, (const char* str),
{
url = UTF8ToString(str);
var hiddenIFrameID = 'hiddenDownloader';
var iframe = document.getElementById(hiddenIFrameID);
if (iframe === null)
{
iframe = document.createElement('iframe');
iframe.id = hiddenIFrameID;
iframe.style.display = 'none';
document.body.appendChild(iframe);
}
iframe.src = url;
});
And an example on how to use it.
void Device::DrawContent()
{
ImGui::Begin("DW Store");
if (ImGui::Button("Download"))
{
DownloadUrl("https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-5.0.402-macos-x64-installer");
}
ImGui::End();
}

Related

Integrate Google Crashpad with Linux application

I'm trying to integrate Google's Crashpad into my application running on Ubuntu.
As per it's overview design
I create one handler process on ubuntu by following this link
Now for the client process, I should register it with the handler via a socket connection.
Linux/Android
On Linux, a registration is a connected socket pair between a client process and the Crashpad handler. This socket pair may be private or shared among many client processes.
How do I do that?
There is not much information available on internet related to crashpad. Can someone provide link to any working example
Unless you have a special use case that isn't listed here you shouldn't have to do anything with sockets manually. Just create a new instance of CrashpadClient at the entry point of your program and call StartHandler.
Here's a snippet from BugSplat's myUbuntuCrasher sample:
// Start crash handler
CrashpadClient *client = new CrashpadClient();
bool status = client->StartHandler(handler, reportsDir, metricsDir, url, annotations, arguments, true, false, attachments);
Here's the full example from main.cpp:
#include <stdio.h>
#include <unistd.h>
#include "client/crashpad_client.h"
#include "client/crash_report_database.h"
#include "client/settings.h"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#if defined(OS_POSIX)
typedef std::string StringType;
#elif defined(OS_WIN)
typedef std::wstring StringType;
#endif
using namespace base;
using namespace crashpad;
using namespace std;
bool initializeCrashpad(void);
StringType getExecutableDir(void);
void crash(void);
int main(int argc, char **argv) {
initializeCrashpad();
crash();
}
void crash() {
*(volatile int *)0 = 0;
}
bool initializeCrashpad() {
// Get directory where the exe lives so we can pass a full path to handler, reportsDir and metricsDir
StringType exeDir = getExecutableDir();
// Ensure that handler is shipped with your application
FilePath handler(exeDir + "/../crashpad/bin/crashpad_handler");
// Directory where reports will be saved. Important! Must be writable or crashpad_handler will crash.
FilePath reportsDir(exeDir);
// Directory where metrics will be saved. Important! Must be writable or crashpad_handler will crash.
FilePath metricsDir(exeDir);
// Configure url with BugSplat’s public fred database. Replace 'fred' with the name of your BugSplat database.
StringType url = "http://fred.bugsplat.com/post/bp/crash/crashpad.php";
// Metadata that will be posted to the server with the crash report map
map<StringType, StringType> annotations;
annotations["format"] = "minidump"; // Required: Crashpad setting to save crash as a minidump
annotations["database"] = "fred"; // Required: BugSplat database
annotations["product"] = "myUbuntuCrasher"; // Required: BugSplat appName
annotations["version"] = "1.0.0"; // Required: BugSplat appVersion
annotations["key"] = "Sample key"; // Optional: BugSplat key field
annotations["user"] = "fred#bugsplat.com"; // Optional: BugSplat user email
annotations["list_annotations"] = "Sample comment"; // Optional: BugSplat crash description
// Disable crashpad rate limiting so that all crashes have dmp files
vector<StringType> arguments;
arguments.push_back("--no-rate-limit");
// File paths of attachments to be uploaded with the minidump file at crash time - default bundle limit is 2MB
vector<FilePath> attachments;
FilePath attachment(exeDir + "/attachment.txt");
attachments.push_back(attachment);
// Initialize Crashpad database
unique_ptr<CrashReportDatabase> database = CrashReportDatabase::Initialize(reportsDir);
if (database == NULL) return false;
// Enable automated crash uploads
Settings *settings = database->GetSettings();
if (settings == NULL) return false;
settings->SetUploadsEnabled(true);
// Start crash handler
CrashpadClient *client = new CrashpadClient();
bool status = client->StartHandler(handler, reportsDir, metricsDir, url, annotations, arguments, true, false, attachments);
return status;
}
StringType getExecutableDir() {
char pBuf[FILENAME_MAX];
int len = sizeof(pBuf);
int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if (bytes >= 0) {
pBuf[bytes] = '\0';
}
char* lastForwardSlash = strrchr(&pBuf[0], '/');
if (lastForwardSlash == NULL) return NULL;
*lastForwardSlash = '\0';
return pBuf;
}
More information about configuring Crashpad in Ubuntu can be found here.

Mounting samba share in C++

I'm working on a project which has to mount samba shares on Ubuntu. This project will be used by non-root users. At now I'm using an application called gvfs-mount because that doesn't require the root password for mounting.
My application runs that executable with specific command line arguments and it works, but the error checking is difficult. I'm using a library called pstreams to launch the gvfs-mount and to write and read to it's stdin/out, but I can predict when the application will write something to stdout. And that is a problem, because if I want to read something from the gvfs-mount's output, but the application doesn't wrote anything, the host application will be blocked, because that will wait for something that will never come.
I know that I could use the mount function from sys/mount.h, but that would require root privileges. My question is: Is there any API, library or tutorial about this topic in C++?
Edit:
As filmor mentioned I had a look to gvfs-mount's source code and I converted to C++. Here is my very basic code:
#include <gtkmm.h>
#include <stdexcept>
#include <iostream>
Glib::RefPtr<Gio::File> file;
Glib::RefPtr<Glib::MainLoop> main_loop;
void on_async_ready(Glib::RefPtr<Gio::AsyncResult>& result)
{
file->mount_enclosing_volume_finish(result);
main_loop->quit();
}
int main()
{
Gio::init();
Glib::init();
main_loop = Glib::MainLoop::create(false);
file = Gio::File::create_for_commandline_arg("smb://192.168.1.3/Memory\\ core");
Glib::RefPtr<Gio::MountOperation> mount_operation = Gio::MountOperation::create();
mount_operation->set_domain("domain");
mount_operation->set_username("user");
mount_operation->set_password("password");
try
{
file->mount_enclosing_volume(mount_operation, &on_async_ready);
}
catch(const Glib::Error& ex)
{
std::cerr << ex.what() << std::endl;
}
main_loop->run();
return 0;
}
The problem is that when I run this code as normal user I get this output:
(process:5816): glibmm-CRITICAL **:
unhandled exception (type Glib::Error) in signal handler:
domain: g-io-error-quark
code : 0
what : Failed to mount Windows share: Operation not permitted
When I run as sudo I get this:
(process:5862): glibmm-CRITICAL **:
unhandled exception (type Glib::Error) in signal handler:
domain: g-io-error-quark
code : 15
what : volume doesn't implement mount
Any suggestion about solving this? The code should work with normal user privileges.
Edit 2:
I updated the source code, because it was an error in uri. I found that if I run the gvfs-mount as sudo, I get the same error message like in my application. So my idea is that there is something wrong with permissions. My username belongs to fuse group it that matters.
#include <gtkmm.h>
#include <iostream>
Glib::RefPtr<Gio::File> file;
Glib::RefPtr<Glib::MainLoop> main_loop;
void on_async_ready(Glib::RefPtr<Gio::AsyncResult>& result)
{
try
{
file->mount_enclosing_volume_finish(result);
}
catch(const Glib::Error& ex)
{
std::cerr << ex.what() << std::endl;
}
main_loop->quit();
}
int main()
{
Gio::init();
Glib::init();
main_loop = Glib::MainLoop::create(false);
file = Gio::File::create_for_commandline_arg("smb://192.168.1.3/Memory core");
Glib::RefPtr<Gio::MountOperation> mount_operation = Gio::MountOperation::create();
mount_operation->set_domain("domain");
mount_operation->set_username("user");
mount_operation->set_password("password");
file->mount_enclosing_volume(mount_operation, &on_async_ready);
main_loop->run();
return 0;
}
I was able to resolve this problem in my Rust application which at first showed the same behaviour as reported in this question.
The solution was to register a callback for the ask-password signal, use this code path to fill in the credentials and then - most importantly - call reply on the mount operation with the Handled flag.
PoC in Rust attached, should transfer easily to C++, too:
use gio::prelude::*;
use glib::{self, clone};
use futures::prelude::*;
use gio::{AskPasswordFlags, MountMountFlags, MountOperation, MountOperationResult};
// read_file taken from https://github.com/gtk-rs/gtk-rs-core/blob/master/examples/gio_futures_await/main.rs#L29
async fn read_file(file: gio::File) -> Result<(), String> {
// Try to open the file.
let strm = file
.read_future(glib::PRIORITY_DEFAULT)
.map_err(|err| format!("Failed to open file: {}", err))
.await?;
// If opening the file succeeds, we asynchronously loop and
// read the file in up to 64 byte chunks and re-use the same
// vec for each read.
let mut buf = vec![0; 64];
let mut idx = 0;
loop {
let (b, len) = strm
.read_future(buf, glib::PRIORITY_DEFAULT)
.map_err(|(_buf, err)| format!("Failed to read from stream: {}", err))
.await?;
// Once 0 is returned, we know that we're done with reading, otherwise
// loop again and read another chunk.
if len == 0 {
break;
}
buf = b;
println!("line {}: {:?}", idx, std::str::from_utf8(&buf[0..len]).unwrap());
idx += 1;
}
// Asynchronously close the stream in the end.
let _ = strm
.close_future(glib::PRIORITY_DEFAULT)
.map_err(|err| format!("Failed to close stream: {}", err))
.await?;
Ok(())
}
// one could probably also use glib to drive the futures
// but this was more familiar to me
#[tokio::main]
async fn main() {
env_logger::init();
let c = glib::MainContext::default();
let file = gio::File::for_uri("smb://host/users/username/Desktop/test.txt");
// check whether the surrounding share is already mounted
let cancellable = gio::Cancellable::new();
if file.find_enclosing_mount(Some(&cancellable)).is_err() {
log::info!("Enclosing share not mounted, trying to mount it");
let mount_op = MountOperation::new();
mount_op.connect_ask_password(|op, msg, default_user, default_domain, flags| {
op.set_anonymous(false);
if flags.contains(AskPasswordFlags::NEED_USERNAME) {
op.set_username(Some("my-user"));
}
if flags.contains(AskPasswordFlags::NEED_PASSWORD) {
op.set_password(Some("my-password"));
}
if flags.contains(AskPasswordFlags::NEED_DOMAIN) {
op.set_domain(Some(default_domain)); // should not be required, let's see
}
// this is the important part!
op.reply(MountOperationResult::Handled);
});
let mount_result = file.mount_enclosing_volume_future(MountMountFlags::empty(), Some(&mount_op));
let mount_result = c.block_on(mount_result);
if let Err(err) = mount_result {
log::error!("Failed to mount: {}", err);
return
}
}
let future = async {
match read_file(file).await {
Ok(()) => (),
Err(err) => eprintln!("Got error: {}", err),
}
};
c.block_on(future);
}

Mongoose should render an html file

I observed that when the Mongoose server event handler is NULL, an HTML file (for example, localhost:8080/index.html) is rendered without any hassles at out.
Here's the code taken from the example of the Mongoose Github repo at https://github.com/cesanta/mongoose.
int main(void) {
struct mg_server *server = mg_create_server(NULL, NULL);
mg_set_option(server, "listening_port", "8080");
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
I want to use the event handler of Mongoose to handle requests. Saw a tutorial here: https://github.com/cesanta/mongoose/blob/master/examples/post.c. The only problem is that I can't access my index.html file unless it is initialized as embedded file as shown in the code below. I want to remove the embedded file version and render the actual html file.
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
static const char *html_form =
"<html><body>"
"<form action=\"/handle_request\">"
"<input type=\"text\" name=\"request_value\" /> <br/>"
"<input type=\"submit\" />"
"</form></body></html>";
static void send_reply(struct mg_connection *conn) {
char value[500];
if(strcmp(conn->uri, "/handle_request") == 0) {
mg_get_var(conn, "request_value", value, sizeof(value));
mg_send_header(conn, "Content-Type", "text/plain");
mg_printf_data( conn, value );
} if(strcmp(conn->uri, "/index.html") == 0) {
// #######################
// HELP ME HERE
// #######################
// Render the html file.
// #######################
} else {
mg_send_data(conn, html_form, strlen(html_form));
}
}
static int ev_handler( struct mg_connection *conn, enum mg_event ev ) {
if ( ev == MG_REQUEST ) {
send_reply( conn );
return MG_TRUE;
} else if ( ev == MG_AUTH ) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
int main(void) {
struct mg_server *server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
Any suggestions? Thanks in advance.
Set document_root option.
Change // HELP ME HERE to return MG_FALSE;
The rule of thumb is: if event handler returns MG_FALSE, then mongoose does the default action. For MG_REQUEST event the default action is to serve requested file.

Node.JS C++ Native Addon read/write file?

The current problem I am facing with my project is that I do not know how to read/write files from the native node.js addon.
I have to build a type of encryption decryption ( RC6 algorithm ) program. But in order to encrypt files, i should be able to somehow read and write to them from "node-webkit". I am building the .cc file with nw-gyp, and tried multiple possibilities but none worked.
I am building my project with "grunt-node-webkit-builder" and I simply want to read/write one file from the build folder "nw" where nw.exe is located.
The Structure looks like this:
.webkitbuilds
.releases
.nw
.win
.nw
encrypt.txt
ffmpegsumo.dll
icudt.dll
libEGL.dll
libGLESv2.dll
nw.exe
nw.pak
How can I read in my c++ native node.js addon that "encrypt.txt" file.
Help ?
Edit:
Is there any way to use libuv with crypto ++ ?
EDIT 2:
I have the following code. The moment I execute it, the window freezes.
hello.cc:
#include <node.h>
#include <v8.h>
#include <stdio.h>
#include <fcntl.h>
using namespace v8;
#define __S_IREAD 0400 /* Read by owner. */
#define __S_IWRITE 0200 /* Write by owner. */
#define __S_IEXEC 0100 /* Execute by owner. */
#define S_IRUSR __S_IREAD /* Read by owner. */
uv_loop_t* loop;
uv_fs_t open_req;
void open_cb(uv_fs_t* req);
const char* path = "encrypt.txt";
void open_cb(uv_fs_t* req) {
int result = req->result;
if (result == -1) {
fprintf(stderr, "Error at opening file: %s\n",
uv_strerror(uv_last_error(loop)));
}
uv_fs_req_cleanup(req);
printf("Successfully opened file.\n");
}
char *get(v8::Local<v8::Value> value, const char *fallback = "") {
if (value->IsString()) {
v8::String::AsciiValue string(value);
char *str = (char *) malloc(string.length() + 1);
strcpy(str, *string);
return str;
}
char *str = (char *) malloc(strlen(fallback) + 1);
strcpy(str, fallback);
return str;
}
Handle<Value> Encrypt(const Arguments& args) {
HandleScope scope;
char* textToEncrypt = get(args[0], "str");
char* password = get(args[1], "str");
loop = uv_default_loop();
int r = uv_fs_open(loop, &open_req, path, O_RDONLY, S_IRUSR, open_cb);
if (r) {
fprintf(stderr, "Error at opening file: %s\n",
uv_strerror(uv_last_error(loop)));
}
uv_run(loop, UV_RUN_DEFAULT);
return scope.Close(String::New("done"));
}
void Init(Handle<Object> exports) {
exports->Set(String::NewSymbol("Encrypt"),
FunctionTemplate::New(Encrypt)->GetFunction());
}
NODE_MODULE(hello, Init)
In Javascript :
var application = require('./js/build/Release/hello');
var encrypted_data = "";
$(document).ready(function() {
$('#btn_encrypt').on('click', function() {
encrypted_data = application.Encrypt("val","val");
console.log(encrypted_data);
})
});

mongoose web server helloworld program

I came across an embedded web server named mongoose and http://code.google.com/p/mongoose/ and I read the wiki it was great and i searched for some sample hello world program but i couldn't find it... i found some example but that was written in c++ for windows and can any one provide an example c program to run this webserver..
It is quite simple, first you need to implement the call back function:
void *event_handler(enum mg_event event,
struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
static void* done = "done";
if (event == MG_NEW_REQUEST) {
if (strcmp(request_info->uri, "/hello") == 0) {
// handle c[renderer] request
if(strcmp(request_info->request_method, "GET") != 0) {
// send error (we only care about HTTP GET)
mg_printf(conn, "HTTP/1.1 %d Error (%s)\r\n\r\n%s",
500,
"we only care about HTTP GET",
"we only care about HTTP GET");
// return not null means we handled the request
return done;
}
// handle your GET request to /hello
char* content = "Hello World!";
char* mimeType = "text/plain";
int contentLength = strlen(content);
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Cache: no-cache\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"\r\n",
mimeType,
contentLength);
mg_write(conn, content, contentLength);
return done;
}
}
// in this example i only handle /hello
mg_printf(conn, "HTTP/1.1 %d Error (%s)\r\n\r\n%s",
500, /* This the error code you want to send back*/
"Invalid Request.",
"Invalid Request.");
return done;
}
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
return NULL;
}
Then you need to start the server:
int main(int argc, char **argv) {
/* Default options for the HTTP server */
const char *options[] = {
"listening_ports", "8081",
"num_threads", "10",
NULL
};
/* Initialize HTTP layer */
static struct mg_context *ctx;
ctx = mg_start(&event_handler, options);
if(ctx == NULL) {
exit(EXIT_FAILURE);
}
puts("Server running, press enter to exit\n");
getchar();
mg_stop(ctx);
return EXIT_SUCCESS;
}
I wrote a C++ REST service library that uses Mongoose. Here's a simple example:
#include <iostream>
#include <server/server.hpp>
int main()
{
using namespace pwned::server;
Server server;
server.Get("/", [](mg_event*, Params const &) {
return Server::response("Hello!");
});
std::cin.get();
}
Based on
https://github.com/nurettin/pwned/blob/master/examples/server/basics/server.cpp
Compile application: $ cc my_app.c mongoose.c
#include "mongoose.h" // Include Mongoose API definitions
static const char *s_http_port = "8089";
// Define an event handler function
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
struct mbuf *io = &nc->recv_mbuf;
switch (ev)
{
case MG_EV_RECV:
// This event handler implements simple TCP echo server
mg_send(nc, io->buf, io->len); // Echo received data back
mbuf_remove(io, io->len); // Discard data from recv buffer
break;
default:
break;
}
}
int main(void)
{
struct mg_mgr mgr;
mg_mgr_init(&mgr, NULL); // Initialize event manager object
// Note that many connections can be added to a single event manager
// Connections can be created at any point, e.g. in event handler function
mg_bind(&mgr, s_http_port, ev_handler); // Create listening connection and add it to the event manager
for (;;)
{
// Start infinite event loop
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
For anyone looking at this thread - from the mongoose library author (me).
Mongoose web server has long ago moved to https://github.com/cesanta/mongoose
It has a comprehensive list of examples, starting from a simplest ones, to the more complex ones, see examples directory in the repository. The minimal static HTTP server goes as follows:
#include "mongoose.h"
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve local dir
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, &opts);
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
mg_mgr_init(&mgr); // Init manager
mg_http_listen(&mgr, "http://localhost:8000", fn, &mgr); // Setup listener
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
mg_mgr_free(&mgr); // Cleanup
return 0;
}