CppCMS Blog http://blog.cppcms.com/ A blog on CppCMS - C++ Web Development Framework Session Sharing with Non-CppCMS technologies http://blog.cppcms.com/post/117 http://blog.cppcms.com/post/117 <div style="direction:ltr"> <p>One of the problems in integrating different technologies on same web site is sharing the data between them, in particular sharing session data.</p> <p>For example you have a huge web platform written in PHP or Java and you want to improve performance of certain subsystems poring them to CppCMS. On of the first issues you'd encounter is how to share the session between them - so every side would know who is the user, what permissions he has, etc.</p> <p>So I made <code>cppcms::session_pool</code> and <code>cppcms::session_interface</code> accessible outside the usual request/response scope and wrapped it with <a href="http://sourceforge.net/p/cppcms/code/HEAD/tree/framework/trunk/cppcms/capi/session.h">pure C API</a> - such that no C++ exceptions are thrown and every function is resolvable via <code>dlopen</code>/<code>GetProcAddress</code>- to make it more accessible for integration with different languages.</p> <p>Several modules for different programming languages were implemented allowing smooth integration with their web frameworks and APIs:</p> <ul> <li>PHP - using <a href="http://swig.org">Swig</a></li> <li>Java/Servlet - using <a href="https://jna.java.net/javadoc/overview-summary.html">JNA</a></li> <li>Python/Django - using <a href="https://docs.python.org/2/library/ctypes.html">ctypes</a> (but not limited to Django)</li> <li>Asp.Net - using <a href="https://msdn.microsoft.com/en-us/library/aa288468%28v%3Dvs.71%29.aspx">PInvoke</a></li> </ul> <p>Actually there is no particular limits regarding technology - just a question of implementing loadable module for a specific language/platform.</p> <p>In general it consists of a SessionPool object that is created from a configuration file and exists globally. It generates a special Session objects that is loaded from Http Request cookies, updated and saved to the Http Response object.</p> <p>It looks like this:</p> <p>PHP:</p> <pre><code>// pool initialization $pool=CppCMS_SessionPool::from_config('cppcms-config.js'); // per request session access $session=$pool-&gt;session(); $session-&gt;load(); $x=0; if($session-&gt;is_set('x')) { $x=$session['x']; } $x=intval($x)+1; $session['x']=$x; $session-&gt;save(); ... </code></pre> <p>Java/Servlet:</p> <pre><code>static SessionPool pool; public void init() throws ServletException { pool = SessionPool.openFromConfig("/path/to/cppcms-config.js"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Session session = pool.getSession(); session.load(request); String x="0"; if(session.isSet("x")) x=session.get("x"); x=Integer.toString(Integer.parseInt(x)+1); session.set("x",x); session.save(response); session.close(); ... } </code></pre> <p>Python with Django:</p> <pre><code># Create global pool pool=cppcms.SessionPool('/path/to/cppcms-config.js') # Actual view def home(request): s=pool.session() s.load(django_request=request) v='0' if 'x' in s: v= s['x'] s['x']=str(int(v)+1) response = HttpResponse() s.save(django_response=response) ... </code></pre> <p>C#/ASP.Net:</p> <pre><code>static SessionPool pool; static Example() { pool = SessionPool.FromConfig("cppcms-config.js"); } protected void Page_Load(object sender,EventArgs e) { using(Session s = pool.Session()) { s.Load(Request); string v="0"; if(s.IsSet("x")) v=s["x"]; v = (int.Parse(v) + 1).ToString(); s["x"]=v; s.Save(Response); } ... } </code></pre> <p>So basically you have a full access to CppCMS session from 3rd party most popular technologies.</p> <p>Still thinking of implementing a module for Ruby on Rails but I have never written a line of code in Ruby so it is quite challenging for me. I'll probably wait till somebody contributes one.</p> </div> Serving All Israeli News Web Sites from a Single EC2 instance... http://blog.cppcms.com/post/114 http://blog.cppcms.com/post/114 <div style="direction:ltr"> <p>For the last year the development of the CppCMS project was less active. The vast majority of the work hours were spent on a customer's project that used CppCMS to create an outstanding advertisement system.</p> <p>The project is called <a href="http://linicom.co.il">Linicom</a>.</p> <p>Today, when Linicom is up, running and maintained by a larger team, so I can resume the activity on the core CppCMS project itself.</p> <p>Few words about Linicom:</p> <p>Linicom is an engine that provides content and visitor sensitive advertisements for almost all large Israeli news web sites: including Ynet, Haaretz, Jerusalem Post, Mako, Walla and other significant web sites in Israel and abroad.</p> <p>Here some interesting facts:</p> <ul> <li>Linicom is based on CppCMS technology.</li> <li>The system serves around 10,000,000 <em>custom</em> requests a day, i.e ~115 req./s.</li> <li>During peak hours, it servers around 160 requests per second.</li> <li>Its typical network output is around 11 megabit per second.</li> <li>Its total memory consumption (web server, database, applications, OS) is only around 350Mb.</li> <li>The server's average CPU load is around 5%</li> <li>The server runs on a <code>c1.medium</code> Amazon EC2 instance.</li> </ul> <p>The system runs behind Lighttpd and uses PostgreSQL for persistent data storage. Also PostgreSQL is used extensively, all real time data is stored in memory.</p> <p>Almost every request needs data processing in order to provide highly customized advertisements. In technical terms it means that almost no request can be "outsourced" to a static files - every request for every customer should be processed explicitly.</p> <p>This system is probably one of the classic applications of CppCMS technology - web based system that required to be fast and efficient, being able to handle outstanding and sometimes unexpectedly changing loads without problems and provide high QoS.</p> <p>Use of in-memory data storage, caching and efficient handing of the data that can't be cached is were CppCMS shines. Having a big growth potential with a minimal required maintenance and high reliability allows the to handle the business-end safely without worrying about performance issues.</p> </div> CppCMS 1.0.5 Released http://blog.cppcms.com/post/116 http://blog.cppcms.com/post/116 <div style="direction:ltr"> <p>Bug Fixes:</p> <ul> <li>Fixed 121, 98 - bug caused invalid year formatting/parsing by icu backend - fixed incorrect use of year of the week instead year</li> <li>Fixed 122 - memory leak in Win32 threading library</li> <li>Fixed 105 - string_key.h has a bad operator '!='</li> <li>Fixed 119 - bad html formatting.</li> <li>Fixed 106 - IPv6 support on Winows</li> <li>Fixed 129 - cppcms_make_key - invalid option name</li> <li>Fixed 97 - impossible to use upper case in namespace in <code>&lt;% include %&gt;</code></li> <li>Fixed 84 - 64K fd limit</li> <li>Fixed 108 - test_locale_boundary &amp; booster_locale_formatting failure</li> <li>Fixed various issues libc++/clang support</li> <li>Significantly improved multipart parsing closing f.r. 27</li> <li>Removed reuse_address socket option use at Windows</li> </ul> <p>Minor Security Improvements:</p> <ul> <li>Issue 117: possibility of Timing Attack Vulnerability</li> </ul> <p>Platform Support:</p> <ul> <li>NetBSD is supported platform</li> <li>FreeBSD added support of POSIX locale &amp; clang/libc++</li> </ul> <p>The code is downloadable from sourceforge. Binary RPM releases already available at The Open Build Service repository. Debian packages would be published soon.</p> <p><strong>Update:</strong> Debian and Ubuntu packages are ready at the repository.</p> </div> CppCMS 1.0.4 Released http://blog.cppcms.com/post/115 http://blog.cppcms.com/post/115 <div style="direction:ltr"> <p>This is a critical bug fix release that relates to session handing in Internet Explorer.</p> <p>Added "Expires" to cookie expiration time handling that is supported by IE.</p> <p>Prior to this release, cppcms session cookies used max-age option, that IE does not recognize. Starting from this release the session cookies would have both Expires and Max-Age options. All browsers that use Max-Age would ignore Expires if both given.</p> <p>New options that control the session cookie properties are added, see <a href="http://cppcms.com/wikipp/en/page/cppcms_1x_config#session.cookies.expiration_method">expiration_method</a> that would allow to alter the behavior and handle possible clock skew issues</p> <p>Special thanks to Saikumar Gandapodi who reported me this issue.</p> </div> Security bug fix release - CppCMS 1.0.3 http://blog.cppcms.com/post/113 http://blog.cppcms.com/post/113 <div style="direction:ltr"> <p>CppCMS 1.0.3 was released today, it includes security bug fix.</p> <p>This bug allowed CppCMS encoding validation to accept some invalid UTF-8 sequences which could potentially lead to various security problems like XSS and more.</p> <p>It is strongly recommended to upgrade to latest version.</p> <p><strong>Note:</strong> for thous who used <code>booster::locale::utf::utf_traits</code> or functions <code>booster::locale::conv::utf_to_utf</code> directly rather than using built in CppCMS forms validation/XSS validation, you may need to recompile the application to get the updates.</p> <p>The release is available on sourceforge and in the official repositories for Ubuntu oneiric, precise and quantal, Debian squeeze, Fedora 16 and 17, Centos 6 and Open Suse 11.4 and 12.1</p> </div> We are under attack... http://blog.cppcms.com/post/112 http://blog.cppcms.com/post/112 <div style="direction:ltr"> <p>Here in Israel...</p> <p>I hear explosions of Grad rockets fired by Hamas to our cities. I hear sirens that gives us <a href="http://youtu.be/gsm-mEy38pQ">short</a> alarms to run for shelters.</p> <p>This is daily routine...</p> <div style="text-align:center"><iframe width="420" height="315" src="http://www.youtube.com/embed/86FdnMIcS1A" frameborder="0" allowfullscreen></iframe></div> <p><a href="http://www.youtube.com/watch?NR=1&amp;v=LxX6f5R4-3E">What Gives Israel the Right to Defend Itself?</a></p> <p><strong>Artyom Beilis,</strong></p> <p><strong>Lead CppCMS Developer, from Israel</strong></p> </div> SVN Repositories Had Moved to New Location http://blog.cppcms.com/post/111 http://blog.cppcms.com/post/111 <div style="direction:ltr"> <p>Due to upgrades on sourceforge the svn repositories had moved. If you are using the version from SVN-Trunk, please checkout them once again:</p> <p>CppCMS</p> <ul> <li><strong>HTTP-Protocol:</strong> http://svn.code.sf.net/p/cppcms/code/framework/trunk</li> <li><strong>SVN-Protocol:</strong> svn://svn.code.sf.net/p/cppcms/code/framework/trunk</li> </ul> <p>CppDB</p> <ul> <li><strong>HTTP-Protocol:</strong> http://svn.code.sf.net/p/cppcms/code/cppdb/trunk</li> <li><strong>SVN-Protocol:</strong> svn://svn.code.sf.net/p/cppcms/code/cppdb/trunk</li> </ul> </div> Server-Sent Events in CppCMS Trunk http://blog.cppcms.com/post/110 http://blog.cppcms.com/post/110 <div style="direction:ltr"> <p>There is a simple class added to the contrib section in trunk.</p> <p><a href="https://cppcms.svn.sourceforge.net/svnroot/cppcms/framework/trunk/contrib/server_side/sse/">https://cppcms.svn.sourceforge.net/svnroot/cppcms/framework/trunk/contrib/server_side/sse/</a></p> <p>The Server-Sent Events support is provide in form of a generic class <code>sse::event_source</code> that the user expected to derive from.</p> <p>Also two simple event source objects with a predefined policy:</p> <ul> <li>Queue bounded up to certain capacity: <code>sse::bounded_event_queue</code></li> <li>Real time state updates that allows to keep clients updated with the latest events - rather than sending all the events from the beginning: <code>sse::state_stream</code></li> </ul> <p>Examples of a simple chat and a stock ticker are provided.</p> <p>Notes:</p> <ul> <li>the <code>sse::event_source</code> supports falling back to long polling using XHR by sending a special header, notifying the server that the connection should be closed rather than kept open.</li> <li>Also the code resides withing trunk, it is fully useful with current stable CppCMS release - 1.0.2.</li> <li>This code does nothing exceptional, you don't really have to use it to create SSE, it is just makes it easy to handle them without knowing too much about server-side event driven programming.</li> </ul> </div> CppCMS 1.0.2 - Bug Fix Release http://blog.cppcms.com/post/109 http://blog.cppcms.com/post/109 <div style="direction:ltr"> <p>CppCMS 1.0.2 Released, it is a bug fix release.</p> <p>Fixed Bugs:</p> <ul> <li>Fixed incorrect HTML generation using <code>as_table</code></li> <li>Fixed build issues with latest ICU: 3540278</li> <li>Fixed some warnings in Boost.Locale</li> <li>Fixed missing error report in case of running out of disk space in file upload: 3542469</li> <li>Fixed visual studio 11 build issues: 3527712,3527702</li> <li>Fixed problem with using automatic type detection in C++11 mode with gcc 3537374</li> <li>Fixed bugs that made stackstream useless</li> <li>Fixed issues build issues on Mac OS X: 3513865</li> <li>Fixed OpenSSL detection on Windows: 3515712</li> <li>Fixed incorrect scgi configuration for nginx in <code>cppcms_run</code></li> </ul> </div> Easy Comet: Server-Sent Events http://blog.cppcms.com/post/107 http://blog.cppcms.com/post/107 <div style="direction:ltr"> <h3>HTML5 Comet Technologies</h3> <p>Today there are two major technologies for efficient implementation of Comet applications using HTML5:</p> <ul> <li><a href="http://en.wikipedia.org/wiki/WebSocket">WebSockets (WS)</a></li> <li><a href="http://www.w3.org/TR/eventsource/">Server-Sent Events (SSE)</a></li> </ul> <p>The first ones - WS - provide full-duplex communication such that both client and server can send each other events without creating a new connection. The second ones - SSE - provide real time notification in a single direction, server to client.</p> <p>It seems that WS is much more popular. Indeed, WS are much more powerful and their support is <a href="http://cppcms.com/wikipp/en/page/cppcms_1x_tasks#Provide.WebSockets.support">scheduled</a> for an implementation in CppCMS. On the other hand, WS have very significant limitation: WS protocol <strong>is not HTTP</strong>. It may look like HTTP and its hand-shake is done at HTTP level, but afterwards, the communication is done using different protocol that is not compatible with HTTP.</p> <p>As a result, there is no way to implement WS over existing web server API as FastCGI or SCGI. More than that, even if the application uses HTTP directly, not every web server would be able to proxy web sockets communication.</p> <p>So, despite that WS is very promising technology, it is very hard to deploy it today in the real production environment.</p> <p>On the other hand, SSE are implemented over plain HTTP without any changes. The protocol is very simple and supported by most browsers, Firefox, Opera, Safari, Chrome and expected to be supported by IE10.</p> <p>There is no special changes required to underlying web server APIs, thus FastCGI or SCGI would work perfectly well. For example, SSE can be easily implemented using stable version of CppCMS without any special tools.</p> <p>Additionally SSE support stream synchronization in case of disconnect. The fall-back to long-polling using XHR can be easily implemented.</p> <h3>An Example</h3> <p>‎Lets implement a simple page that receives stock price updates.</p> <p>First, we create an EventSource object and then we attach a handler that would update the appropriate html filed upon notification from the server side:</p> <pre><code>function read_data() { var stream = new EventSource('/ticker'); stream.onmessage = function(e){ document.getElementById('price').innerHTML=e.data; }; stream.onerror = function(e){ console.log(e); }; } read_data(); </code></pre> <p>The code is very simple and trivial, disconnects are handled automatically and transparently. Now lets take a look on the server side that is little bit more challenging:</p> <p>Upon request we prepare our content type as required and fetch the ID of the last known price that was sent to the client.</p> <pre><code>void main(std::string /*url*/) { response().set_content_header("text/event-stream"); response().set_header("Cache-Control", "no-cache"); auto last_id = atoi(request().cgetenv("HTTP_LAST_EVENT_ID")); </code></pre> <p>After that we detach the HTTP context object from the application, such that we will be able to handle multiple connections simultaneously.</p> <pre><code> auto context=release_context(); </code></pre> <p>The idle connections would be stored in a special <code>waiters_</code> set. We add a special callback that allows us to cleanup the clients that had disconnected:</p> <pre><code> context-&gt;async_on_peer_reset([=](){ this-&gt;waiters_.erase(context); }); </code></pre> <p>Note, we use C++11 lambda expressions that make the code much more simple and clear.</p> <p>Then we check if the last price id that is known to the client and if it differs we send the client an update asynchronously, otherwise we add the client to the waiting list:</p> <pre><code> if(last_id != counter_) { async_send(context); } else waiters_.insert(context); } </code></pre> <p>The code that sends the request to the client is quite simple, we send the last price id - simple counter that would use us for synchronization in case of disconnect and send an actual data.</p> <pre><code>void async_send(booster::shared_ptr&lt;cppcms::http::context&gt; waiter) { waiter-&gt;response().out() &lt;&lt; "id:" &lt;&lt; counter_ &lt;&lt;"\n" "data:" &lt;&lt; price_ &lt;&lt; "\n" "\n"; </code></pre> <p>Then we setup a completion callback, if the operation fails (client had disconnected), we just exit, and the context would be automatically destroyed.</p> <pre><code> waiter-&gt;async_flush_output([=,counter_](cppcms::http::context::completion_type status){ if(status!=0) return; </code></pre> <p>Otherwise we check if there were an updates since the data was sent, and if yes we send the latest price once again, otherwise we add the client to the waiting list.</p> <pre><code> if(counter_ != this-&gt;counter_) { this-&gt;async_send(waiter); } else { this-&gt;waiters_.insert(waiter); } }); </code></pre> <p>This completes our function.</p> <pre><code>} </code></pre> <p>Note: that our lambda expression captures the <code>waiter</code> variable and keeps it alive till the handler is executed.</p> <p>Now the last and the simplest thing - updating the price. Upon price update, we increase the identification counter and notify all objects in the waiting list.</p> <pre><code>void update_price(double new_one) { counter_++; price_ = new_one; for(auto waiter : waiters_) { async_send(waiter); } </code></pre> <p>Afterwards we clear the list - now the callback object owns the context and would destroy it in case of an error.</p> <pre><code> waiters_.clear(); } </code></pre> <p>The full code of the sample including simple timer based random price generation can be found <a href="http://cppcms.com/files/ticker/">there</a>.</p> <h3>Falling Back to Long Polling</h3> <p>Is very simple. We would use the same protocol, but when the event is ready we would close the connection. In order to let the server to distinguish between EventSource and XHR long polling we would add a special header like <code>X-Event-Source-Simulate: Long-Polling</code></p> <p>Then we would change a little our <code>async_send</code> function by adding the following lines:</p> <pre><code> if(waiter-&gt;request().getenv("HTTP_X_EVENT_SOURCE_SIMULATE")=="Long-Polling") { waiter-&gt;async_complete_response(); return; } </code></pre> <p>Such that our function would look like:</p> <pre><code> waiter-&gt;response().out() &lt;&lt; "id:" &lt;&lt; counter_ &lt;&lt;"\n" "data:" &lt;&lt; price_ &lt;&lt; "\n" "\n"; if(waiter-&gt;request().getenv("HTTP_X_EVENT_SOURCE_SIMULATE")=="Long-Polling") { waiter-&gt;async_complete_response(); return; } waiter-&gt;async_flush_output(...) ... </code></pre> <p>Of course XHR simulation would have to send and manage <code>Last-Event-Id</code> header and parse the response, but the server side would look almost identically.</p> <h3>Connecting to the web server</h3> <p>When it is coming to configuring a web server you should make sure that it does not buffer out-coming request and sends them immediately to the client:</p> <ul> <li>Lighttpd does this by default for FastCGI, SCGI and HTTP protocols.</li> <li>Apache does this by default for SCGI and HTTP, but for FastCGI (mod_fastcgi) it requires <code>-flush</code> option to work correctly.</li> </ul> <p>Now once again Nginx shows us its problems:</p> <ul> <li>SCGI requires option <code>scgi_buffering off</code></li> <li>HTTP requires option <code>http_buffering off</code></li> </ul> <p>However, FastCGI does not implement such an option! <a href="http://trac.nginx.org/nginx/ticket/159">See this ticket</a></p> <p>So don't even try to use Nginx with FastCGI for Server-Sent Events.</p> <p>Once again, give yourself a favor, <a href="http://blog.cppcms.com/post/99">use lighttpd</a></p> <h3>Thanks</h3> <p>Special thanks to Barbu Paul - Gheorghe,that had brought to my attention such a powerful and useful HTML5 feature.</p> </div>