Server-Sent Events using Poco::Net::HTTPRequestHandler - javascript

I'm trying to "stream" data to an HTML5 page using server-sent events.
This tutorial http://www.html5rocks.com/en/tutorials/eventsource/basics/ was quite helpful to get the client side working.
But for the server side, I'm doing something similar to the HTTPServer example in http://pocoproject.org/slides/200-Network.pdf
The html5rocks.com tutorial gave me the following idea for the request handler's code:
void MyRequestHandler::handleRequest (HTTPServerRequest &req, HTTPServerResponse &resp)
{
resp.setStatus(HTTPResponse::HTTP_OK);
resp.add("Content-Type", "text/event-stream");
resp.add("Cache-Control", "no-cache");
ostream& out = resp.send();
while (out.good())
{
out << "data: " << "some data" << "\n\n";
out.flush();
Poco::Thread::sleep(500)
}
}
and the HTML5 page's source:
<!DOCTYPE html>
<html>
<head>
<title>HTLM5Application</title>
</head>
<body>
<p id="demo">hello</p>
<script>
var msgCounter = 0;
var source;
var data;
if(typeof(EventSource) !== "undefined")
{
source = new EventSource('/stream');
document.getElementById("demo").innerHTML = "Event source created";
}
else
{
document.getElementById("demo").innerHTML = "Are you using IE ?";
}
source.addEventListener('message', function(e)
{
msgCounter++;
document.getElementById("demo").innerHTML = "Message received (" + msgCounter + ") !<br/>"+ e.data;
}, false);
</script>
</body>
</html>
The good thing is that, when opening the html page, the data gets streamed and I get a correct outpout (the text between the tag gets updated as expected.
The problem is that when I close the page in the browser, the POCO program crashes, and I get the following message in the console:
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Process returned 3 (0x3) execution time : 22.234 s
Press any key to continue.
(I'm using Code::Blocks, that's why the return value and the execution time are displayed)
Event when I put the while() loop between try{ }catch(...){} the program still crashes without entering the catch (same thing happens when I put the entire main()'s content in between try/catch )
The main program contains only these instructions:
int main(int argc, char* argv[])
{
MyServerApp myServer;
myServer.run(argc, argv);
return 0;
}
I want to know what could cause that crash and how I can fix it, please.
Thank you in advance for your help :)

For anyone interested, I was able to deal with this issue by registering my own error handler that simply ignores the exception thrown when an SSE-client disconnects:
#include <Poco\ErrorHandler.h>
// Other includes, using namespace..., etc.
class ServerErrorHandler : public ErrorHandler
{
public:
void exception(const Exception& e)
{
// Ignore an exception that's thrown when an SSE connection is closed.
//
// Info: When the server is handling an SSE request, it keeps a persistent connection through a forever loop.
// In order to handle when a client disconnects, the request handler must detect such an event. Alas, this
// is not possible with the current request handler in Poco (we only have 2 params: request and response).
// The only hack for now is to simply ignore the exception generated when the client disconnects :(
//
if (string(e.className()).find("ConnectionAbortedException") == string::npos)
poco_debugger_msg(e.what());
}
};
class ServerApp : public ServerApplication
{
protected:
int main(const vector<string>& args)
{
// Create and register our error handler
ServerErrorHandler error_handler;
ErrorHandler::set(&error_handler);
// Normal server code, for example:
HTTPServer server(new RequestHandlerFactory, 80, new HTTPServerParams);
server.start();
waitForTerminationRequest();
server.stop();
return Application::EXIT_OK;
}
};
POCO_SERVER_MAIN(ServerApp);
However, I must say that this is an ugly hack. Moreover, the error handler is global to the application which makes it even less desirable as a solution. The correct way would be detect the disconnection and handle it. For that Poco must pass the SocketStream to the request handler.

You can change your code to catch Poco Exceptions:
try {
MyServerApp myServer;
return myServer.run(argc, argv);
}catch(const Poco::Exception& ex) {
std::cout << ex.displayText() << std::endl;
return Poco::Util::Application::EXIT_SOFTWARE;
}

Related

Why is Net.Socket.Write() not sending the full string to my TCP client?

EDIT: Im desperate to get this thing done so I can move onto a new project, heres the source: https://github.com/eanlockwood/TalkmonClient
Everything else works fine. The server is well aware of the usernames associated with the clients and it sends information to them accordingly, but the weird thing is the string cuts off after the first variable. Here is the loop for a typical send message:
function SendMessage(msg, client)
{
const clientName = ClientNames.get(client);
let recieverMsg = `${clientName}: ${msg}`;
console.log(recieverMsg);
Clients.forEach(elm => {
if(elm != client)
{
elm.write(recieverMsg);
}
else {
elm.write("You: " + msg);
}
})
}
msg is the chunk.toString() in the socket.on('data') event, again, node picks up what this string means, it debugs fine but in the client (imagine the windows cmd) itll just print the username and go to the next line.
The loop for the client side is pretty simple too,
char buff[4090];
do
{
ZeroMemory(buff, 4090);
int messageRevieved = recv(sock, buff, 4090, 0);
if (messageRevieved > 0)
{
userInput->FreezeInput();
cout << buff << endl;
userInput->UnFreezeInput();
}
} while (0 == 0);
User input is handled in its own class on a seperate thread, again, working just fine.
I think it has to do with a misunderstanding of what socket.write and recv actually do or maybe I just dont understand javascript strings enough. Either way this problem is annoying because its the last step in creating my app
Ive done some extensive tests too, it really just doesnt like the concat strings. Itll print everything up until the first variable, meaning I could have socket.write("hehehehehehe " + variable1 + " kadjgkdgad"); and it would print hehehehehe [variable1 value] and just stop
Tl;dr: The server will write to the sockets up to the first variable in a concat'd string and then stop, its so weird.
EDIT: The dependencies used serverside are Net and dotnet if that makes a difference.
EDIT 2: I found another issue. After sending a few messages the client who sent the messages will stop printing the "you: " part and will only print the message, it will do this server side too but its weird because the receiving clients will still print out who the message is from.

Executing JavaScript on C# with CefSharp WPF causes Error

Whenever I try to execute JavaScript through C# using CefSharp (Stable 57.0), I get an error. I am simply trying to execute the alert function, so I can make sure that works and later test it out with my own function. However, I seem to be getting errors trying to do so.
public partial class WebBrowserWindow : Window
{
public WebBrowserWindow()
{
InitializeComponent();
webBrowser.MenuHandler = new ContextMenuHandler();
webBrowser.RequestHandler = new RequestHandler();
}
//Trying to execute this with either method gives me an error.
public void ExecuteJavaScript()
{
//webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
//webBrowser.ExecuteScriptAsync("alert('test');");
}
}
I have tried both ways of executing the script.
The first one:
webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
Gives me this error:
The second:
webBrowser.ExecuteScriptAsync("alert('test');");
Gives me this error:
My objective is to create a C# function that can execute a JavaScript function in my CefSharp Browser.
I tried many links/references and there weren't that many on stack overflow. I also read The FAQ for CefSharp and couldn't find any simple examples that allow me to execute JavaScript at will through C#.
In addition, I've verified the events where the Frame is loaded (it finishes loading), and unloaded (it does not unload), and if the webbrowser is null (which it's not), and the message from the:
webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
still causes the first error to occur.
I tested for GetMainFrame(). It always returns null. ALWAYS. Doesn't matter how long I wait, or what conditions I check for.
IMPORTANT
I forgot to add one crucial piece of information, I have 2 assemblies in my project. Both of them compile into separate executables:
Helper.exe
Main.exe
main.exe has a window "CallUI" that, when a button gets clicked, it executes the method I created "ExecuteJavaScript()", which is inside of my window "BrowserWindow". The CallUI window is declared and initialized in Helper.exe.
So basically I am trying to use a separate program to open a window, click a button that calls the method and execute javascript. So I think because they are different processes, it tells me the browser is null. However, when I do it all in Main.exe it works fine. Is there a workaround that allows me to use the separate process to create the window from Helper.exe and execute the Javascript from Main.exe?
It has come to my attention that I was handling the problem the wrong way.
My problem, in fact, doesn't exist if it's just a single process holding all the code together. However, the fact that my project has an executable that was trying to communicate with another was the problem. I actually never had a way for my helper.exe to talk to my main.exe appropriately.
What I learned from this is that the processes were trying to talk to each other without any sort of shared address access. They live in separate address spaces, so whenever my helper.exe tried to execute that javascript portion that belonged in Main.exe, it was trying to execute the script in an uninitialized version of a browser that belonged in its own address space and not main.exe.
So how did I solve that problem? I had to include an important piece that allowed the helper.exe process to talk to the main.exe process. As I googled how processes can talk to each other, I found out about MemoryMappedFiles. So I decided to implement a simple example into my program that allows Helper.exe to send messages to Main.exe.
Here is the example. This is a file I created called "MemoryMappedHandler.cs"
public class MemoryMappedHandler
{
MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen("mmf1", 512);
MemoryMappedViewStream stream;
MemoryMappedViewAccessor accessor;
BinaryReader reader;
public static Message message = new Message();
public MemoryMappedHandler()
{
stream = mmf.CreateViewStream();
accessor = mmf.CreateViewAccessor();
reader = new BinaryReader(stream);
new Thread(() =>
{
while (stream.CanRead)
{
Thread.Sleep(500);
message.MyStringWithEvent = reader.ReadString();
accessor.Write(0, 0);
stream.Position = 0;
}
}).Start();
}
public static void PassMessage(string message)
{
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("mmf1"))
{
using (MemoryMappedViewStream stream = mmf.CreateViewStream(0, 512))
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(message);
}
}
}
catch (FileNotFoundException)
{
MessageBox.Show("Cannot Send a Message. Please open Main.exe");
}
}
}
This is compiled into a dll that both Main.exe and Helper.exe can use.
Helper.exe uses the method PassMessage() to send the message to a Memory Mapped File called "mmf1". Main.exe, which must be open at all times, takes care of creating that file that can receive the messages from Helper.exe. I sends that Message to a class that holds that message and every time it receives it, it activates an event.
Here is what the Message class looks like:
[Serializable]
public class Message
{
public event EventHandler HasMessage;
public string _myStringWithEvent;
public string MyStringWithEvent
{
get { return _myStringWithEvent; }
set
{
_myStringWithEvent = value;
if (value != null && value != String.Empty)
{
if (HasMessage != null)
HasMessage(this, EventArgs.Empty);
}
}
}
}
Finally, I had to initialize Message in my WebBrowserWindow class like this:
public partial class WebBrowserWindow : Window
{
public WebBrowserWindow()
{
InitializeComponent();
webBrowser.MenuHandler = new ContextMenuHandler();
webBrowser.RequestHandler = new RequestHandler();
MemoryMappedHandler.message.HasMessage += Message_HasMessage;
}
private void Message_HasMessage(object sender, EventArgs e)
{
ExecuteJavaScript(MemoryMappedHandler.message.MyStringWithEvent);
}
public void ExecuteJavaScript(string message)
{
//webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
//webBrowser.ExecuteScriptAsync("alert('test');");
}
}
And now it allows me to execute the javascript I need by sending a message from the Helper.exe to the Main.exe.
Have you tried this link? Contains a snippet that checks if the browser is initialised first.
cefsharp execute javascript
private void OnIsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs args)
{
if(args.IsBrowserInitialized)
{
browser.ExecuteScriptAsync("alert('test');");
}
}

Event source in asp.net has response with one turn delay

After hours of googling i found only one sample about event source using for asp.net (Not MVC). Firstly i must say i want to learn it and my final goal is to creating a friendly poker website. SignalR is very very good for my purpose but i do not want to use this because i heard:
SignalR is bad in performance
isn't it?(i hope not). My problem is when server sends response to client it sends the previous text not current:
$("#btnListen").click(function ()
{
var source = new EventSource('SSEHandler.ashx');
source.addEventListener("open", function (event)
{
$('#headerDiv').append('Latest 5 values');
}, false);
source.addEventListener("error", function (event)
{
if (event.eventPhase == EventSource.CLOSED)
{
$('#footerDiv').append('Connection Closed!');
}
}, false);
source.addEventListener("message", function (event)
{
console.log(event.data);
}, false);
});
And this is SSEHandler:
public class SSEHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
HttpResponse Response;
Response = context.Response;
Response.ContentType = "text/event-stream";
Response.Write(string.Format("data: {0}\n\n", "first"));
Response.Flush(); //client has no response received yet
Response.Write(string.Format("data: {0}\n\n", "second"));
Response.Flush(); //now client get "first".
Response.Close();
}
}
After executing this cods client console only have "first". And if i add this to end of SSEHandler:
Response.Write(string.Format("data: {0}\n\n", "third"));
Response.Flush();
In client console we have "first", "Second".
Thanks for reading my long post.
Its been a while since you asked the question, but after struggling with this for a while myself I found a workaround I thought could be useful to share for others having the same issue.
Simply adding a comment (line that starts with colon) after each event will make the events appear when they should.
Response.Write("data: first\n\n")
Response.Write(":comment\n")
Response.Write("data: second\n\n")
Response.Write(":comment\n")
Note: The problem is more apparent when working with events that comes dynamically, since at that point the first event wont produce anything on the client, then when the second event hits, the first is displayed in the client. And this goes on with second and third etc..

C# WebBrowser control - document does not contain html input control [duplicate]

Most of the answers I have read concerning this subject point to either the System.Windows.Forms.WebBrowser class or the COM interface mshtml.HTMLDocument from the Microsoft HTML Object Library assembly.
The WebBrowser class did not lead me anywhere. The following code fails to retrieve the HTML code as rendered by my web browser:
[STAThread]
public static void Main()
{
WebBrowser wb = new WebBrowser();
wb.Navigate("https://www.google.com/#q=where+am+i");
wb.DocumentCompleted += delegate(object sender, WebBrowserDocumentCompletedEventArgs e)
{
mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)wb.Document.DomDocument;
foreach (IHTMLElement element in doc.all)
{
System.Diagnostics.Debug.WriteLine(element.outerHTML);
}
};
Form f = new Form();
f.Controls.Add(wb);
Application.Run(f);
}
The above is just an example. I'm not really interested in finding a workaround for figuring out the name of the town where I am located. I simply need to understand how to retrieve that kind of dynamically generated data programmatically.
(Call new System.Net.WebClient.DownloadString("https://www.google.com/#q=where+am+i"), save the resulting text somewhere, search for the name of the town where you are currently located, and let me know if you were able to find it.)
But yet when I access "https://www.google.com/#q=where+am+i" from my Web Browser (ie or firefox) I see the name of my town written on the web page. In Firefox, if I right click on the name of the town and select "Inspect Element (Q)" I clearly see the name of the town written in the HTML code which happens to look quite different from the raw HTML that is returned by WebClient.
After I got tired of playing System.Net.WebBrowser, I decided to give mshtml.HTMLDocument a shot, just to end up with the same useless raw HTML:
public static void Main()
{
mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)new mshtml.HTMLDocument();
doc.write(new System.Net.WebClient().DownloadString("https://www.google.com/#q=where+am+i"));
foreach (IHTMLElement e in doc.all)
{
System.Diagnostics.Debug.WriteLine(e.outerHTML);
}
}
I suppose there must be an elegant way to obtain this kind of information. Right now all I can think of is add a WebBrowser control to a form, have it navigate to the URL in question, send the keys "CLRL, A", and copy whatever happens to be displayed on the page to the clipboard and attempt to parse it. That's horrible solution, though.
I'd like to contribute some code to Alexei's answer. A few points:
Strictly speaking, it may not always be possible to determine when the page has finished rendering with 100% probability. Some pages
are quite complex and use continuous AJAX updates. But we
can get quite close, by polling the page's current HTML snapshot for changes
and checking the WebBrowser.IsBusy property. That's what
LoadDynamicPage does below.
Some time-out logic has to be present on top of the above, in case the page rendering is never-ending (note CancellationTokenSource).
Async/await is a great tool for coding this, as it gives the linear
code flow to our asynchronous polling logic, which greatly simplifies it.
It's important to enable HTML5 rendering using Browser Feature
Control, as WebBrowser runs in IE7 emulation mode by default.
That's what SetFeatureBrowserEmulation does below.
This is a WinForms app, but the concept can be easily converted into a console app.
This logic works well on the URL you've specifically mentioned: https://www.google.com/#q=where+am+i.
using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WbFetchPage
{
public partial class MainForm : Form
{
public MainForm()
{
SetFeatureBrowserEmulation();
InitializeComponent();
this.Load += MainForm_Load;
}
// start the task
async void MainForm_Load(object sender, EventArgs e)
{
try
{
var cts = new CancellationTokenSource(10000); // cancel in 10s
var html = await LoadDynamicPage("https://www.google.com/#q=where+am+i", cts.Token);
MessageBox.Show(html.Substring(0, 1024) + "..." ); // it's too long!
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
// navigate and download
async Task<string> LoadDynamicPage(string url, CancellationToken token)
{
// navigate and await DocumentCompleted
var tcs = new TaskCompletionSource<bool>();
WebBrowserDocumentCompletedEventHandler handler = (s, arg) =>
tcs.TrySetResult(true);
using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
{
this.webBrowser.DocumentCompleted += handler;
try
{
this.webBrowser.Navigate(url);
await tcs.Task; // wait for DocumentCompleted
}
finally
{
this.webBrowser.DocumentCompleted -= handler;
}
}
// get the root element
var documentElement = this.webBrowser.Document.GetElementsByTagName("html")[0];
// poll the current HTML for changes asynchronosly
var html = documentElement.OuterHtml;
while (true)
{
// wait asynchronously, this will throw if cancellation requested
await Task.Delay(500, token);
// continue polling if the WebBrowser is still busy
if (this.webBrowser.IsBusy)
continue;
var htmlNow = documentElement.OuterHtml;
if (html == htmlNow)
break; // no changes detected, end the poll loop
html = htmlNow;
}
// consider the page fully rendered
token.ThrowIfCancellationRequested();
return html;
}
// enable HTML5 (assuming we're running IE10+)
// more info: https://stackoverflow.com/a/18333982/1768303
static void SetFeatureBrowserEmulation()
{
if (LicenseManager.UsageMode != LicenseUsageMode.Runtime)
return;
var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
appName, 10000, RegistryValueKind.DWord);
}
}
}
Your web-browser code looks reasonable - wait for something, that grab current content. Unfortunately there is no official "I'm done executing JavaScript, feel free to steal content" notification from browser nor JavaScript.
Some sort of active wait (not Sleep but Timer) may be necessary and page-specific. Even if you use headless browser (i.e. PhantomJS) you'll have the same issue.

Get notified when JS breaks?

I have configured PHP to send me mails whenever there is an error. I would like to do the same with Javascript.
Also given the fact that this will be client side it is open to abuse.
What are good ways to get notified by mail when JS breaks in a web application?
Update:
Just to give some perspective, i usually load several js files including libraries (most of the time jQuery).
You can listen to the global onError event.
Note that you need to make sure it doesn't loop infinitely when it raises an error.
<script type="text/javascript">
var handlingError = false;
window.onerror = function() {
if(handlingError) return;
handlingError = true;
// process error
handlingError = false;
};
</script>
The code below relies on the global onError event, it does not require any external library and will work in any browser.
You should load it before any other script and make sure you have a server-side jserrorlogger.php script that picks up the error.
The code includes a very simple self-limiting mechanism: it will stop sending errors to the server after the 10th error. This comes in handy if your code gets stuck in a loop generating zillions of errors.
To avoid abuse you should include a similar self-limiting mechanism in your PHP code, for example by:
saving and updating a session variable with the error count and stop sending emails after X errors per session (while still writing them all down in your logs)
saving and updating a global variable with the errors-per-minute and stop sending emails when the threshold is exceeded
allowing only requests coming from authenticated users (applies only if your
application requires authentication)
you name it :)
Note that to better trace javascript errors you should wrap your relevant code in try/catch blocks and possibly use the printstacktrace function found here:
https://github.com/eriwen/javascript-stacktrace
<script type="text/javascript">
var globalOnError = (function() {
var logErrorCount = 0;
return function(err, url, line) {
logErrorCount++;
if (logErrorCount < 10) {
var msg = "";
if (typeof(err) === "object") {
if (err.message) {
// Extract data from webkit ErrorEvent object
url = err.filename;
line = err.lineno;
err = err.message;
} else {
// Handle strange cases where err is an object but not an ErrorEvent
buf = "";
for (var name in err) {
if (err.hasOwnProperty(name)) {
buf += name + "=" + err[name] + "&";
}
}
err = "(url encoded object): " + buf;
}
}
msg = "Unhandled exception ["+err+"] at line ["+line+"] url ["+url+"]";
var sc = document.createElement('script'); sc.type = 'text/javascript';
sc.src = 'jserrorlogger.php?msg='+encodeURIComponent(msg.substring(0, Math.min(800, msg.length)));
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(sc, s);
}
return false;
}
})();
window.onerror = globalOnError;
</script>
You would wrap your entire program in a try/catch and send caught exceptions over AJAX to the server where an email could be generated. Short of that (and I wouldn't do that) the answer is "not really."
JA Auide has the basic idea. You could also go somewhat in between, ie.:
Write an AJAX "errorNotify" function that sends error details to the server so that they can be emailed to you.
Wrap certain parts of your code (the chunks you expect might someday have issues) with a try/catch which invokes errorNotify in the catch block.
If you were truly concerned about having 0 errors whatsoever, you'd then be stuff with try/catching your whole app, but I think just try/catching the key blocks will give you 80% of the value for 20% of the effort.
Just a note from a person that logs JavaScript errors.
The info that comes from window.onerror is very generic. Makes debugging hard and you have no idea what caused it.
User's plugins can also cause the issue. A very common one in certain Firebug versions was toString().
You want to make sure that you do not flood your server with calls, limit the amount of errors that can be sent page per page load.
Make sure to log page url with the error call, grab any other information you can too to make your life easier to debug.

Categories

Resources