Taking Notes

Dec. 17, 2011, 9:05 p.m.

Something I never did as a student was taking notes. I just didn't think it was cool. But things change and I now take a lot of notes. Most of them I take at work during meetings, interviews, trainings etc but my notebook is also full of spontaneous ideas, scribbles, numbers, code snippets, stack traces, quotes and other things.

Obviously I don't carry around a pen and something made out of paper all day long. I type fast enough to protect the trees and read and write my notes digitally. When I started digital note-taking, I looked at evernote and its type of software and was shocked by the feature overload in some of these tools.

Here's what I need from a note-taking application:

  • a (big) plaintextbox to enter my note
  • store a timestamp for each note
  • tags
  • search

That's it. No video, no Facebook, no Foursquare, no Twitter. Google Notebook called tags 'labels' and had richtext but was otherwise exactly what I wanted. It also worked on every device that supported HTML and I used it every single day. And then this happened:

Screenshot

This sucked. I guess when a Google application gets less than five million users they say "noone is using this" and just turn it off. And sure enough it was in read-only mode a few days later. Coming back from #gdd11, I decided to give the Google App Engine a try and implemented my own notebook within a few hours:

Screenshot

Nothing fancy but it does everything Google Notebook did for me. It works and I've used it every day since. Feel free to use it with your own Google account:

Also, the codez are on github, in case you need another GAE sample :)



A Memory Leak brought to you by XmlSerializer

Oct. 26, 2011, 6:16 p.m.

We ran into an interesting memory leak the other day. When one of my colleagues analyzed the memory dump from production, he saw an unusual amount of types in *.GeneratedAssembly.* namespaces, one instance each:

0:007> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
000007ff0024da98        1           24 System.Xml.Serialization.TempAssemblyCache
000007ff002474f8        1           24 System.Xml.Serialization.Configuration.RootedPathValidator
...
000007ff00441d98        1           40 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract
000007ff004412c8        1           40 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract
000007ff004407f8        1           40 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract
000007ff003ef9b0        1           40 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract
000007ff003eeee0        1           40 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract
... and more

He also found the method XmlSerializer.GenerateTempAssembly in call stacks and soon thereafter the explanation online:

To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when using the following constructors:

XmlSerializer.XmlSerializer(Type)

XmlSerializer.XmlSerializer(Type, String)

If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned two constructors. Otherwise, you must cache the assemblies in a Hashtable, as shown in the following example.

from MSDN

Turned out we were (indirectly) using one of the XmlSerializer constructors that cause this documented memory leak. This also popped up in many other places online and can be easily reproduced with a few lines of code:

public class Brick { }

while(true)
{
    var s = new XmlSerializer(typeof(Brick), new Type[] {});
    s.Serialize(Stream.Null, new Brick { });
}

Isn't that some very fine memory leaking code? Not only is it eating up memory, it is also generating, loading (and deleting) *.dll files in your temp-path (e.g. C:\Users\josef\AppData\Local\Temp) and is therefore incredibly slow. The Hanselman already taught us how we can make the generated code visible:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.diagnostics>
      <switches>
         <add name="XmlSerialization.Compilation" value="1" />
      </switches>
   </system.diagnostics>
</configuration>

With this switch set to 1, the C# code for each generated assembly will be written into *.cs files so if you run the code above, your temp-dir will be flooded:

C:\Users\josef\AppData\Local\Temp>dir *.cs
 Volume in drive C has no label.
 Volume Serial Number is ####-####

 Directory of C:\Users\josef\AppData\Local\Temp

10/26/2011  05:11 PM             9,260 0r2upaee.0.cs
10/26/2011  05:11 PM             9,260 0wvlt0sz.0.cs
10/26/2011  05:11 PM             9,260 12x20ris.0.cs
10/26/2011  05:11 PM             9,260 1bsq04ge.0.cs
10/26/2011  05:11 PM             9,260 1wvkuolg.0.cs
10/26/2011  05:11 PM             9,260 1y4yyetd.0.cs
10/26/2011  05:11 PM             9,260 20yixjrc.0.cs
10/26/2011  05:11 PM             9,243 23qz4yru.0.cs
10/26/2011  05:11 PM             9,260 2vt3hznp.0.cs
...
         101 File(s)        926,038 bytes
           0 Dir(s)  91,353,591,808 bytes free

The recommended way to get around this issue is to use one of the two safe constructors (see above) if you can, or cache the XmlSerializer instances by yourself. We went for the latter.



Force CORS Firefox Extension

Aug. 1, 2011, 2:05 a.m.

I've created a very simple extension for Firefox that adds the Cross Origin Resource Sharing (CORS) Access-Control- HTTP headers to all responses before they're processed by the browser. This essentially disables the browser's same origin policy and allows cross domain calls even if the web server does not support CORS.

The default setting adds the following headers to every response:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST

This can be customized in the forcecors.headers setting via about:config, the values are separated by spaces (and yes, you may add arbitrary, cors-unrelated headers :).

Force CORS is going to be very helpful for my numerous Javascript/HTML5 hacks (diagnostic scripts, little helpers, mashups, etc.) that load data from websites I don't control :)

The code is available on github, feel free to fork it.

And here's the link to Mozilla's "AMO":

https://addons.mozilla.org/en-US/firefox/addon/forcecors/

Oh, and a warning: Force CORS circumvents the browser's same origin policy, so be careful (i.e. don't use it if you don't know what you're doing).



Cannot add graphics to virtual machine

July 31, 2011, 12:22 p.m.

I use libvirt and kvm to run two virtual machines (a linux and a windows guest) on a debian host. Both guests run without a <graphics/> section in their config because I use ssh and rdp to admin these systems.

Last night I broke the network for the windows guest while upgrading the host from lenny to squeeze so I wanted to temporarily enable <graphics type='vnc'/> for troubleshooting. I virsh edit the windows domain and added the following line to the <devices/> section in its config:

<graphics type='vnc' listen='0.0.0.0:0'/>

However, saving the config always resulted in the following error message:

virsh # edit windows
error: internal error unable to reserve PCI address 0:0:2

I tried to run kvm directly by passing a -vnc :0 switch instead of -nographic but that didn't work either:

TUNGETIFF ioctl() failed: Bad file descriptor

Turns out I had run into a bug ("qemu: Always reserves slot 0x02 for primary VGA. (Osier Yang)") that always took pci slot 0x02 for vga. Since my guest already had its network interface configured to that slot, things did not work out.

The fix was to move around the pci slot assignments in the config and allow <graphics/> to use 0x02 (irrelevant sections omitted):

<devices>
  <!-- emulator, disk, etc. omitted -->
  <controller type='ide' index='0'>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
  </controller>
  <interface type='bridge'>
    <!-- mac, source, target, model, etc. omitted -->
    <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
  </interface>
  <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0:0'/>
  <video>
    <model type='cirrus' vram='9216' heads='1'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
  </video>
  <memballoon model='virtio'>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
  </memballoon>
</devices>

That allowed me to boot the guest and connect to it on display :0 via vnc.

The bug was fixed in libvirt 0.9.2-1.el6 but since the host is on squeeze, it is using libvirt 0.8.3-5.



CORS and IIS

July 17, 2011, 8:05 p.m.

Last time, I wrote about Cross-Origin Resource Sharing (CORS). This time I'll show how it can be implemented with Microsoft's Internet Information Services (IIS), ASP.Net and jQuery.

Let's assume we have two very separate web applications:

  • http://cooking/, a website that is full of delicous cooking recipes
  • http://shopping/, a website that allows users to make shopping lists

First, we implement http://shopping/ by adding 127.0.0.1 shopping to the hostfile and creating an empty ASP.NET web application with only one file (list.aspx):

<%@ Page Language="C#" ContentType="application/json" %>
[
    { "amount": "2", "name": "Apples" },
    { "amount": "4", "name": "Bananas" },
    { "amount": "8", "name": "Cookies" }
]

That was fast.

Now the guys from http://cooking/ would like to show shopping lists on their site and allow users to add ingredients for the recipe they're looking at to their list. They add the following Javascript to their recipe-detail page to retrieve a user's current shopping list:

$.ajax({
    url: 'http://shopping/list.aspx',
    dataType: 'json',
    success: function(data) {
        // render shopping list items to page
    }
});

Unfortunately this call is blocked due to the same origin policy. Luckily the girls from http://shopping/ want the whole world to use their shopping lists so they add an HTTP Header Access-Control-Allow-Origin: * to their response. This can be done in the IIS Manager

  • IIS6: in the Web's properties dialog under 'HTTP Headers'
  • IIS7: in the 'HTTP Response Headers' section of the 'Features View', or web.config

Here is what the response from http://shopping/list.aspx looks like after the change:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Date: Sun, 17 Jul 2011 14:21:59 GMT
Content-Length: 124

[
    { "amount": "2", "name": "Apples" },
    { "amount": "4", "name": "Bananas" },
    { "amount": "8", "name": "Cookies" }
]

Now everybody, including the script on http://cooking, is allowed to retrieve the shopping list.

Additionally it should be possible for users on http://cooking to click a link 'add to shopping list' while they browse the ingredients for a recipe. The cooking-guys add the following Javascript to their site and have it run when users click on these links.

$.ajax({
    type: 'POST',
    url: 'http://shopping/list.aspx',
    contentType: 'json',
    dataType: 'json',
    data: JSON.stringify({
        amount: 16,
        name: 'Dark Chocolates'
    }),
    success: function (data) {
        // render shopping list items to page
    },
});

This will POST the new item (16 Dark Chocolates) to the list but since it is a different domain, the browser will first query Access-Control with an OPTIONS request:

OPTIONS http://shopping/list.aspx HTTP/1.1
Host: shopping
Origin: http://cooking
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type

In particular it checks for the permission to POST with a header content-type. Fortunately the http://shopping site responds with

HTTP/1.1 200 OK
Allow: OPTIONS, TRACE, GET, HEAD, POST
Server: Microsoft-IIS/7.5
Public: OPTIONS, TRACE, GET, HEAD, POST
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: Content-Type
Date: Sun, 17 Jul 2011 17:49:22 GMT
Content-Length: 0

so the browser goes ahead with the original POST:

POST http://shopping/list.aspx HTTP/1.1
Host: shopping
Content-Type: json; charset=UTF-8
Referer: http://cooking/
Content-Length: 38
Origin: http://cooking

{"amount":16,"name":"Dark Chocolates"}

It is possible that everything already works for you after configuring the two additional Access-Control- headers (-Allow-Methods and -Allow-Headers). IIS7 has an OPTIONSVerbHandler configured by default that will respond with all configured custom headers, including the Access-Control- headers. In IIS6, there is no such mapping and depending on your setup it is likely that you need to explicitly allow the OPTIONS verb. In IIS6 this setting is certainly not obvious but you can find it in the website's Properties -> Home Directory -> Configuration... -> Mappings -> .aspx -> Verbs -> Limit to. If you're using a different handler (e.g. WCF) you'll have to add it to the appropriate mapping (e.g. '.svc'). This will allow your ASP.Net application to receive OPTIONS requests. One way to handle these requests is to simply end the response in the Global.asax's Application_BeginRequest method, optionally also setting the Access-Control- headers:

void Application_BeginRequest(object sender, EventArgs e)
{
    var ctx = HttpContext.Current;
    if (ctx.Request.HttpMethod == "OPTIONS")
    {
        //ctx.Response.AddHeader("Access-Control-Allow-Origin", "*");
        ctx.Response.End();
    }
}

Some other things to look out for when it doesn't work:

  • Don't just rely on your browser plugins (Firebug etc.) to find out what happened. Use a debugging proxy (e.g. Fiddler, Charles, etc.) or network tools (e.g. Wireshark). There is a really fine line between request-blocked-by-browser (i.e. no request actually happened), OPTIONS request problems and GET or POST problems. The plugins' error messages are not always helpful (e.g. '405 Method not allowed')
  • Depending on your ajax-call setup and content type (json, xml, etc.) you might have to add the Accept header to the list of -Allow-Headers.
  • If there is a problem with the OPTIONS request, check the <system.webServer><handlers> section, there may be handlers with verb limits configured (IIS7 only)
  • If there are still problems with the OPTIONS request, check the <system.web><httpHandlers> section for custom handlers
  • Don't forget about any firewall or security tools that are filtering requests with specific (or unknown) verbs or headers (e.g. UrlScan)

Here is the full sample code: cors-and-iis.zip



about

subscribe