Archive for the ‘Web Technologies’ Category

Website thumbnails

Generating website thumbnails was a pretty hot topic a few years ago with the rise of services like websnapr, thumbalizr, and, perhaps the most well-known, snap shots. The popularity of doing this has faded somewhat, most likely due to the realizations that services like snap shots are not all that helpful and more of an annoyance than anything else.

I did my own thumbnail generator app a few years ago for a CentOS system. It was painful. I believe I was using gtkmozembed and just going through hell to resolve all the dependencies to get things running on a command line system.

With the WebKit stuff I recently put up, I decided to revisit the idea under .NET, and things were surprisingly easy. This is due to the fact that WinForms 2.0 has the Control.DrawToBitmap() method which makes capturing an image of the client area of a control relatively easy. I should mention, .NET 2.0 has the WebBrowser control, but I could never get the Control.DrawToBitmap() method to work; I always got a blank (white) image. The WebBrowser control is also undesirable because it’s based on IE6, so its certainly far from up-to-date or accurate rendering, even more-so than the outdated version of WebKit I’m using.

So let’s say we’re running a WebKit instance in a Panel (panel1), we can capture what’s displayed as follows,

Bitmap bmpOut = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmpOut, panel1.ClientRectangle);
bmpOut.Save(
"test.png");

Here’s an example of a capture:

website thumbnail reddit.com

There is one critical limitation; only the visible portion of the web page is captured. However, if a component to scroll and capture different portions of the page were implemented, and the final image was pieced together from these portions, a full page would be captured.

Another limitation is there there is no way to tell when the page is finished loading. Figuring this out requires digging into the depths of the WebKit codebase, I’m certainly not up for it, and it’s not for the faint of heart.

Safari 5 form submission bug

This applies specifically to Safari 5 (no problems in Safari 4) and forms with an enctype of multipart/form-data, submitted with a POST request built manually (for an AJAX [XMLHttpRequest] call).

Safari 5 injects a “charset=UTF-8” name/value pair into the ContentType field after the boundary string. This generates an invalid request. On the server-side of things, this resulted in no data in PHP’s $_POST global variable.

I tracked down the issues thanks to this post. The bug itself is a WebKit bug, described here.

The simple fix is to prevent Safari from automatically putting the charset parameter in by putting it in manually – before the boundary string. Here’s some jQuery code that demonstrates the issue/fix:

function ajaxSubmitForm(servlet, theForm, extraFunc)
{
var boundaryString = 'AaB03x';
var boundary = '--' + boundaryString;

var requestBody = new Array();

requestBody.push(boundary);

for (var i=0; i<theForm.length; i++)
{
requestBody.push('Content-Disposition: form-data; name="' + theForm.elements[i].name + '"');
requestBody.push('');
requestBody.push(theForm.elements[i].value);
requestBody.push(boundary);
}

var reqBodyText = requestBody.join('\r\n');

$.ajax({
url: servlet,
type: 'POST',
contentType: 'multipart/form-data; charset=UTF-8; boundary=' + boundaryString + '',
data: reqBodyText,
error: function(reqobj, errType, exceptionObj){
alert('Failed to submit form data.\r\nStatus = ' + reqobj.statusText);
},

success: function(xml)
{
if(extraFunc != null)
extraFunc();
}

});
}

Broken comments

h/t to Dave, the guy who contacted me and mentioned that he was unable to post comments on this blog; I didn’t realize the comments system was not functioning.

Now why the WordPress comment system would go down was a bit confusing and frustrating to diagnose. WP simply sent you to a blank page (wp-comments-post.php#comment-). After ruling out it was not an issue with the theme or a problem with a blank line in wp-comments-post.php (the first 2 cases mentioned here). I tried repairing the wp_comments table in the DB, which didn’t work (the post linked to mentions going further and wiping out the data and recreating the table, but I didn’t want to go that far). I ran across a few posts (such as this one) on the WP forums about similar issues, but nothing that led to a solution.

I decided to dig into wp-comments-post.php and started playing around with a few echo statements to see where things were going wrong. Turns out, wp_new_comment() was always returning a comment_id of 0. Not good. Assuming the WP code was correct (I had no reason to suspect otherwise), it had to be a problem with the database. The problem and solution turned out to be pretty trivial: the comment_ID field of the wp_comments table had the auto_increment attribute missing (which needs to be set; you can see the WP database scheme here). So all new comments were being assigned the default value of 0.

I’m not sure why this would happen; maybe an issue resulting from an upgrade my host did a while back or perhaps an issue with the WP auto-update process.

Facebook API and login for desktop apps

I was pretty disappointed today to discover the required login procedure for desktop apps using the Facebook API.

facebook api, desktop app login

Having a user go to a web browser to do the login then come back to the app is a whole lot of grunt work that could easily be eliminated by having login functionality in the API. Why is this not done? I’m not sure. Security may seem the obvious answer, but that’s assuming app developers are completely inept and won’t properly encrypt, store, or transfer credentials. Even if that is the case, it is the trust between the user and the app that is the basis for security here.

There is a workaround available in the facebook-c-sharp library. However, as explain in this thread, actually using the library will result in your app breaking Facebook’s Developer Terms of Service.

Windows Cloud

A few days ago I came across Microsoft’s announcement (or pre-announcement, as the launch is actually in 4 weeks) of Windows Cloud – an “operating system” for the “cloud.” (Note: there are certain things Ballmer says which seem vague or just don’t seem to make technical sense; I’m not sure what Ballmer means by .NET model or “operating system” in the given context. My overall assumption is that this is software for distributed computing of a web app)

There’s been a lot of hype surrounding cloud technologies in recent months with many looking forward to a future where most, perhaps all, of our data and software services are provided via. web servers. The hype is interesting as cloud computing already exists in many forms (facebook, internet email, Amazon S3, Amazon EC2, etc.) and it’s pretty much inevitable that we will continue to see similar technologies – so predicting we’ll see cloud technologies in the future is like predicting it’ll rain at some point in the future. As for whether this will completely supplant desktop software, I’m doubtful, there are a lot of issues that come with having your data and services on a vendor’s web server, not the least of which is that you don’t have access to them if your internet service goes down. That being said, I’m sure many companies are salivating at the thought of subscription-based SaaS applications and getting customers to pay a continual service fee to use their software. If that happens, we’re in for a pretty bleak future.

What’s interesting about Microsoft in all this is that while MS boasts a new “operating system for the cloud” and launches yet another web technology (they already have like a million “Live” services), it’s latest desktop operating system has encountered a slow and painful adoption due to issues which it seems to be totally ignored. Why is Microsoft ignoring its base and trying to jump on every new technology trend that hits the web? It doesn’t make sense, this does not seem to be how a company in Microsoft’s position should be acting. Microsoft built the bulk of its reputation through its operating system, even through all the growing pains of Windows 95 and Windows ME, why squander that now? Especially after hitting a high-note with Windows XP. With the way things are going Microsoft’s reputation will be one of a impotent juggernaut with a mediocre presence in every segment of the IT market. Microsoft seems to be a company that’s lost focus and direction. Perhaps it’s just gotten too big for its own good.

A great writeup I found after the announcement is here (I think I just stumbled upon this by googling “Windows Cloud”). I particularly like the closing paragraph,

This is not a company that knows what it’s doing. Ballmer and Gates were once masters of their universe. But nothing lasts forever. Ask Lehman Brothers.

Trials and tribulations with WebKit

This post is about issues that pop up after you’ve got WebKit compiled and can get an application up and running within initialization errors.

(fyi, these are issues I’ve had on Win32. Things may be different on other platforms)

Issue 1: Safari theme doesn’t work, causes crash
If, like me, you’ve just copied the other necessary DLLs needed by WebKit from your Safari directory, SafariTheme.dll will cause you trouble (crash) unless you copy over the \SafariTheme.resources folder as well.

Note that WebKit will work fine without the Safari theme. Simply, get rid of the SafariTheme.dll file and a default theme will be used (it’s ugly, but it’s functional). Also, note that I’m not sure what the copyrights/license is for the Safari theme, there may be restrictions on using and/or distributing it.

Issue 2: “localized string not found” in context menus
Go to folder where you have the WebKit source. Navigate to WebKit\win. There you’ll find the \WebKit.resources folder, copy it to the folder with your WebKit DLL. Next, copy \English.lproj into the copied \WebKit.resources folder.

So, in the directory with your WebKit DLL, you should have:
\WebKit.resources
\WebKit.resources\English.lproj

Issue 3: loadURL() does nothing
If your using the WinLauncher application as guide, you’ll notice the loadURL() function doesn’t seem to work. This is because the timeout interval passed to the initWithURL() member is 0. A value of 60 (seconds?) seems to work well.

request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60);

That’s it for now. In the next few days, I’ll post how to wrap WebKit and embed it within a WinForms application; screenshot below.

WebKit in C# WinForms application

Compiling Webkit on Win32

Compiling WebKit on Windows is far from trivial. In the process of getting it compiled and linked successfully, I took some notes which may help others struggling to getting it done.

First, a few precautions, don’t try to be smart. Follow the instructions on the site closely, this means:
  • Don’t try to compile w/ Visual C++ 2008, it won’t work. Use VC++ 2005.
  • For VC++ 2005 Express Ed., make sure you have SP1, compilation will fail w/o it.
  • For Vista, make sure you have the additional SP update.
  • Don’t try to compile outside of cygwin directory structure.
Next, you need to get the webkit source.
  • Get the source from a nightly build (make sure to download the source and not one of the platform specific builds). You can also get the files from the subversion repository, but I had issues with this and discovered missing files. It may have been fixed, but in general, I think just getting the nightly build is simpler.
  • The source is in a .bz2 file. So you’ll need a bzip2 decompressor.
  • The bz2 file decompresses to a .tar file (wtf?!), so you’ll also need a tar decompressor.
  • Next, download the WebKit Support Libraries.
  • Put the source under your cygwin/home/<username> directory (e.g. \cygwin\home\<username>\WebKit)
  • Finally, update, by running the update-webkit script.
Preparing for compilation.

Note: I tried to build from the cygwin shell, as demonstrated on webkit.org, but it failed. Failing in this way and then having to dig thru build logs is insane, so I diverted to building from within VC++ so I could easily spot and fix errors as they occurred.

Note: I failed to realize that I didn’t have SP1 for VC++ 2005 Express when I started this whole process and didn’t figure it out until I hit a few perplexing errors related to the linker failing because it detected different versions of the compiler were used for the 2 parts of compilation on a few object files (yea, it’s weird, I have no clue what was going on internally here). I found a few quick and dirty solutions to this problem by playing around with optimization settings, but eventually hit a brick wall, where no amount of fidgeting with optimization parameters resulted in compilation/linking going forward. Installing SP1 solved the issue and may have solved the earlier issues as well without me having to play with optimization settings.

So, onwards we go,
  • I found that after opening the WebKit solution, none of the projects were loaded. This is because the project files are looking for *.vsprops files in WebKit\WebKitLibraries\tools\vsprops, but the vsprops files are actually in WebKit\WebKitLibraries\win\tools\vsprops. The simplest solution is just copy over what’s in the /win directory into the parent directory (WebKit\WebKitLibraries). Looking at WebKit\WebKitLibraries now, I copied over the win/tools folder and the files in /win. Alternatively, you can edit the project files (they’re XML files, you can open them up in a text editor).
  • Set the 2 environment variables necessary for compiling within VC++,
    • WEBKITLIBRARIESDIR = cygwin\home\<user>\WebKit\WebKitLibraries
    • WEBKITOUTPUTDIR = cygwin\home\<user>\WebKit\WebKitBuild
  • Get the Platform SDK, specifically the Windows Server 2003 Ed. of the Platform SDK. I did not have luck getting it to work with an older or newer version of the SDK. I didn’t install the R2 update; I’m not sure what effect it would have.
  • Update VC++ directories:
    • Executables >> add cygwin/bin, windows/system32, Platform SDK/bin
    • Includes >> Platform SDK/include
    • Library Files >> Platform SDK/lib
  • Update VC++ directories for the WebKit Support Library:
    • Includes >> WebKit\WebKitSupportLibrary\WebKitSupportLibrary\win\include
    • Library Files >> WebKit\WebKitSupportLibrary\WebKitSupportLibrary\win\lib
  • Update VC++ directories for JavaScriptCore/icu:
    • Includes >> WebKit\JavaScriptCore\icu
  • Update VC++ directories for WebCoreSQLite3:
    • Includes >> WebKit\WebKitLibraries\WebCoreSQLite3
  • Update VC++ directories for JavaScriptCore:
    • Includes >> WebKit\JavaScriptCore
  • I had issues with the ARRAYSIZE macro not being defined, so in WebCore/config.h, add the following:

    #ifndef ARRAYSIZE
    #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
    #endif

    right before the line,

    #endif /* PLATFORM(WIN_OS) */

  • Get rid of cygwin’s link.exe in cygwin/bin (rename it or delete it). This causes a conflict with the real linker (VC++’s link.exe). It was likely caused by the order in which VC++ executable directories were set, so if you need it, you might be able to keep it.
  • For the QtMovieWin project, edit all source files (there’s only 2) so that windows.h is included first (this is due to macro above, which will now cause a macro redefinition by the preprocessor).
  • For QtMovieWin, also rearrange the order of include, so that #include <wtf/Vector.h> is included before config.h and windows.h to prevent some min/max macro nonsense.
  • For QtMovieWin, take off prompt error reporting for linking (ERRORREPORT:PROMPT) project (see Linker >> Advanced page in project setting).
  • Make a new config file by copying WebCore/config.h and making WebCore/config_qt.h. Remove the ARRAYSIZE macro defintions from config_qt.h. Update all files in QtMovieWin project so that config_qt.h is included instead of config.h.
  • Install the QuickTime SDK.
  • Update VC++ directories:
    • Includes >> QuickTime 7.3 SDK\CIncludes
    • Library Files >> QuickTime 7.3 SDK\Libraries
  • For QtMovieWin, make sure you linker inputs are set correctly for QuickTime libraries and VC++ can find them.
  • For QtMovieWin, add “CoreFoundation.lib” to linker inputs.
  • (This may have been an issue caused by not having SP1, you might not have to do this, try compiling first) Turn off whole program optimization for all projects.
  • (This may have been an issue caused by not having SP1, you might not have to do this, try compiling first) Turn off treat warnings as errors for JavaScriptCore, WebKit, WebKitGUID, WebCore, and WTF projects.
That should do it.

Some general advice, work from within VC++ and compile as you make changes; make it a touch-and-go operation. In this way you see errors as they occur and can more easily spot and fix issues. Don’t simply follow what I’ve written above as tutorial thinking it’s a sure-fire solution for compilation, things may very likely change with different iterations of the code.