John Smith's Blog

Ramblings (mostly) about technical stuff

Enhanced version of Python's SimpleHTTPServer that supports HTTP Range

Posted by John Smith on

I've just uploaded a small personal project to GitHub here. It's basically a very crude webserver that allows me to share audio files on my Linux boxes to my iOS devices, using Mobile Safari.

The main reason for noting this is that the code may be of more general interest because it implements an improved version of Python stdlib's SimpleHTTPServer module, that implements basic support for the Range header in HTTP requests, which is necessary for Mobile Safari on some MP3 files.

During early development, I found that some MP3 files would refuse to play in Mobile Safari when served by SimpleHTTPServer. The same file would play fine if served by Apache. Because debugging mobile web browsers is a PITA (caveat: I've haven't kept up with the latest-and-greatest in this area), I ended up resorting to Wireshark to see what was going on.

Wireshark indicated that Mobile Safari would request chunks of the MP3 file (initially just the first couple of bytes), but SimpleHTTPServer would always serve the entire file, because it never checked for the existence of the Range header. On certain files, this wouldn't bother Mobile Safari, but on others it would cause the audio player widget to show an unhelpful generic error.

Once I understood what the problem was, I found that I'm not the first person to get caught out by this, and that Apple themselves state that servers need to support Range to keep Mobile Safari happy.

To solve the problem, I wrote a new class HTTPRangeRequestHandler that is a direct replacement for SimpleHTTPServer. In my app code proper, I then (try to) pull in my enhanced handler as follows: try: import HTTPRangeServer inherited_server = HTTPRangeServer.HTTPRangeRequestHandler except ImportError: logging.warning("Unable to import HTTPRangeServer, using stdlib's " + "SimpleHTTPServer") import SimpleHTTPServer inherited_server = SimpleHTTPServer.SimpleHTTPRequestHandler ... class MySpecificHandler(inherited_server): ... def main(port=12345): Handler = EnhancedRequestHandler httpd = SocketServer.TCPServer(("", port), Handler) Arguably it might be better for the code to die if HTTPRangeServer cannot be imported, but as the stdlib SimpleHTTPServer is good enough for many browser clients, it doesn't seem too unreasonable to use it as a fallback.

This code is currently OK for most uses, but currently it doesn't support all variations of the Range header as described at aforementioned W3C spec page. It does however support all the requests variants I've seen in my - admittedly very cursory - browser testing, and any requests that it can't parse will instead get the full file served, which is the same behaviour as SimpleHTTPServer.

The musicsharer application that's built on this class is even rougher, but as it's really just intended for my own personal use, you shouldn't hold your breath waiting for me to tart it up...

What's the best way of including SVGs in a responsive web page?

Posted by John Smith on

TL; DR: <object> seems the best bet - although Safari 5.1 has issues compared to the other browsers. Second choice is having the SVG inline in the HTML, but that has issues for WebKit and IE.

As a diversion from my more usual diet of Python, I've spent a fair bit of time over the past week or so revisiting SVG. My previous experiments have usually been done using fixed sizes, but I've always wanted to do something that fits in better with what these days is called "responsive design", especially given as these are supposed to be scalable vector graphics.

For an example of the sort of thing I've been aiming for, take a look at the main chart on a Google Finance page. This Flash chart resizes horizontally as you change the size of the browser window. (NB: the chart makes extra data visible as you make the browser window wider, which isn't exactly what I want, but you should get the idea.)

Unless I've been particularly boneheaded about the way I've investigated this, this isn't as straightforward a problem as it first seemed. If you put a regular bitmap image in an HTML page with something like <img src="whatever.png" width="100%" /> the image will scale as you'd hope when the browser window is resized. This isn't necessarily the case with SVG.

As outlined in the W3C docs, there are five ways that you can pull SVGs into a page in a modern browser:

  • <embed>
  • <frame> / <iframe>
  • <object>
  • <img>
  • Inline <svg>
(You can also create an SVG via DOM function calls, but I'm not particularly interested in that approach right now.)

I've built tests for each of these, and run them through the latest versions of the five main browsers. This obviously ignores a lot of issues with older browsers and mobile browsers, many of which don't even support SVG at all, but as it turns out, the "big 5" are enough to worry about on their own :-(

In the following sections, when I refer to a particular browser, the tests were done in the following versions, which (AFAIK) are the current ones as of early April 2012:

  • Firefox 10
  • Opera 11.62
  • Chromium 17 or 19 (I didn't notice any difference between the two
  • Internet Explorer 9
  • Safari 5.1
Where relevant, issues are illustrated with screengrabs from the Windows version of a browser, but much of my testing was done with Linux versions - except in the case of IE and Safari. I also tested whether JavaScript functionality worked - both within the SVG itself, and from the enclosing document trying to manipulate the SVG.

Just for clarity's sake: all of this messing around is (probably?) only needed if you want an SVG to be scalable within your web page. If you're happy for it to be a fixed size, then you shouldn't have to worry about any of the following stuff.

<embed>

Test link: http://js-test.appspot.com/svg/embedscaling.html

The image gets scaled correctly in Firefox, Chromium and IE. The image does not get scaled correctly in Opera or Safari.

Screengrab of SVGs using the embed tag in Opera 11.62 Screengrab of SVGs using the embed tag in Safari 5.1

<iframe>

Test link: http://js-test.appspot.com/svg/iframescaling.html

(I've assumed <frame>s behave the same; I couldn't be bothered to write a separate test for them.)

Only Chromium rendered the page completely as desired. Screengrab of SVGs using the iframe tag in Chromium 19

IE and Safari both failed to scale the images properly, but were able to modify the SVGs from the enclosing document's JavaScript. Screengrab of SVGs using the iframe tag in IE9 Screengrab of SVGs using the iframe tag in Safari 5.1

Firefox and Opera failed to scale the images, or modify them via the JavaScript in the enclosing document. I'm not sure if the JS issue is down to some DOM API difference and/or security problem - but as the scaling is broken, I couldn't be bothered to investigate further. Screengrab of SVGs using the iframe tag in Firefox 10 Screengrab of SVGs using the iframe tag in Opera 11.72

(All browsers did at least run the JavaScript contained within the SVG files.)

<object>

Test link: http://js-test.appspot.com/svg/objectscaling.html

Only Safari lets the side down, by failing to scale the SVGs. All other browsers work as desired. Screengrab of SVGs using the iframe tag in Safari 5.1

<img>

Test link: http://js-test.appspot.com/svg/imgscaling.html

If you have any JavaScript-based interactivity, forget about using <img> tags - the JS in the SVGs won't be run, and the JS in the document doesn't do anything either. WebKit-based browsers also have weird issues with additional padding and squashed images. You might hope that the preserveAspectRatio might be able to solve that, but I was unable to find any value which fixed things. Screengrab of SVGs using the img tag in Chromium 19 Screengrab of SVGs using the img tag in Safari 5.1

Inline <svg>

Test link: http://js-test.appspot.com/svg/inlinexhtmlscaling.html

This method is what the BBC uses for the position chart in its football tables, which is the highest profile use of SVG in a mainstream site that I know of.

Scaling works in all browsers, except IE. Screengrab of SVGs using inline SVG in IE9

However, WebKit browsers suffer from excessive vertical padding - it seems that WebKit assumes the height of the image is the same as the browser window, rather than the viewBox attribute in the <svg>. A slightly messy fix is to manually alter the height of the SVG elements after the page has loaded - this wasn't incorporated into this particular test, but an example from another test is here, and other people have documented similar workarounds. There are some open bugs on the WebKit tracker that might be related, here and here. Screengrab of SVGs using inline SVG in Chromium 19 Screengrab of SVGs using inline SVG in Safari 5.1

Whilst doing some earlier tests in this area, I also found a couple of bugs in Opera where

  • An HTML5 page wouldn't properly render, and would never trigger the load event - but an effectively identical XHTML page was fine. Warning: this bug also causes Opera to consume 100% CPU on the processor it is running on Screengrab showing bug in Opera in HTML5 page with embedded SVGs
  • If a page had multiple copies of the same SVG pulled in via the <img> tag, then if the page was reloaded, most of the duplicates would not appear: Screengrab showing bug in Opera after a page with duplicate SVGs is reloaded
Both of these have been reported to Opera via the tool built into their browser

Summary

As can be seen, of the five methods available, none is 100% foolproof. It seems to me that the best bet is <object>, as it works fine on all browsers except Safari, without need for JavaScript hacks. Second-place is embedding the SVG into the HTML, which entails a simple hack for WebKit browsers - but unfortunately is still broken in IE.

Experimental rhythm action game using HTML5 video and Safari 3D CSS3 transforms

Posted by John Smith on

UPDATE: this is currently broken on my iPad, suspect it's iOS 4.2 related. I think I might be able to do a hacky fix, but I'm still working on it. It should work OK on regular Safari though.

It's probably not the most sensible thing in the world to publicize a >10MB video file that's being hosted on an Amazon EC2 'micro' instance, but let's see how long this lasts before I take it down to avoid too much damage to my credit card...

Photo of an iPad running the game

One of the things that surprised me when I got an iPad was that in Mobile Safari, embedded YouTube videos would play within the browser, rather than launching the standalone app as they do on the iPhone/iPod Touch. (Assuming that they've been embedded using the iframe method, rather than a Flash video.) This inspired me to start playing with HTML5 video, which previously hadn't struck me as that interesting.

Unfortunately, the embedding of YouTube video in an <iframe>, coupled with the way the underlying video file URLs are uniquely signed - presumably to inhibit hotlinking - means that it's difficult to impossible to have a lot of customized interaction with the YT video itself, but by hosting the video myself, I've able to build something really, simple but (hopefully) effective.

Anyway, at http://bit.ly/aRoq3V is a very basic rhythm action game. It's primarily aimed at the iPad, but will work acceptably on Mac/Windows Safari. Other browsers will have mixed results, as currently none of them support the 3D transformations added into WebKit's CSS, not even Chrome. The 3D stuff is super-simple, and could probably be 90% faked using regular CSS/JS/images, but as this is purely experimental, I've not been inclined to try. If this was a serious project, I'd probably do it in Objective-C, but I was really only interested in the HTML5/CSS3 aspects.

Tweet me to let me know how much you hate it...

So the majority of web video is available in HTML5? Not from where I'm sitting

Posted by John Smith on

A recent survey that says "54% of web video is now available for playback in HTML5" has been widely reported in the past couple days. From that figure, one might think that those of us who prefer not to install Flash on our computers can now watch more skateboarding dogs than we can shake a stick at.

However, a quick test of some of the sites mentioned in that survey tells a somewhat different story...

blip.tv

Screen grab of Firefox 4 browser being told by blip.tv that Flash is required to video their video content

Dailymotion

Screen grab of Firefox 4 browser showing a black rectangle rather than a video

Vimeo

Screen grab of Firefox 4 browser being told by Vimeo that Flash is required to video their video content

YouTube

Screen grab of Firefox 4 browser being told by YouTube that Flash is required to video their video content

The above tests were done on a Fedora 12 machine running the nightly Firefox 4 beta (aka Minefield), which is quite capable of running videos such as the one at html5video.org.

I've yet to do a more thorough investigation as to what's happening with these sites, but one or more of the following seem possible:

  • By default, they all assume anyone visiting from a desktop browser will have Flash installed. There's definitely a strong feeling out there that you only need to provide Flash-free versions of sites for mobile devices, like this for example.
  • HTML5 video is only offered if a user explicitly requests it. Last time I checked, on YouTube you had to explicitly go to a page which gave you a cookie to enter their HTML5 "beta". Although if you do have to jump through such hoops, why don't these sites provide a link to the relevant page to set the options, rather than merely linking to Adobe's download page?
  • The sites only have the video in H.264 format. They detect that Minefield doesn't have a plug-in to handle it, and so don't offer any HTML5 video. If so, does this merely mean that we're replacing Adobe with MPEG-LA as the overlord of online video content - in which case, I'm not actually sure that's a positive step. The original report does mention H.264, but perhaps any follow-up survey should go further, and break HTML5 video availability into the stats for how much H.264 vs OGV vs WebM are all supported?
  • The sites don't recognize Minefield 's User-Agent string, and so don't realize it can handle HTML5 video, and just fall back to the perceived lowest common denominator. (I don't think this is likely, but it's possible.)

Based on this sort of thing, I don't see Flash video going away any time soon...

About this blog

This blog (mostly) covers technology and software development.

Note: I've recently ported the content from my old blog hosted on Google App Engine using some custom code I wrote, to a static site built using Pelican. I've put in place various URL manipulation rules in the webserver config to try to support the old URLs, but it's likely that I've missed some (probably meta ones related to pagination or tagging), so apologies for any 404 errors that you get served.

RSS icon, courtesy of www.feedicons.com RSS feed for this blog

About the author

I'm a software developer who's worked with a variety of platforms and technologies over the past couple of decades, but for the past 7 or so years I've focussed on web development. Whilst I've always nominally been a "full-stack" developer, I feel more attachment to the back-end side of things.

I'm a web developer for a London-based equities exchange. I've worked at organizations such as News Corporation and Google and BATS Global Markets. Projects I've been involved in have been covered in outlets such as The Guardian, The Telegraph, the Financial Times, The Register and TechCrunch.

Twitter | LinkedIn | GitHub | My CV | Mail

Popular tags

Other sites I've built or been involved with

Work

Most of these have changed quite a bit since my involvement in them...

Personal/fun/experimentation