Wednesday 30 September 2009

Enabling private cross site scripting with a XMLHttpRequest proxy servlet

The problem

You have a list of URLs and want to interrogate them for their Content-Type using javascript in the browser.

You cannot do this because the javascript security model forbids this activity, called cross site scripting, as it could be used to invoke malign code.

The solution

Install a proxy on your server which can make the request on your behalf and relay it back to you. You have not violated the javascript security model and you are free to invoke any url on the net by a call to your own, originating, server.

However the proxy does need to be protected otherwise it could be abused by other sites. To protect the proxy we ensure that it can only be accessed from a page generated by our server, indeed one which has set a named session variable.

The code As implemented within the Melati framework, which wraps the HttpRequest and HttpResponse objects in a Melati object:
private String proxy(Melati melati, ServletTemplateContext context) {
  if (melati.getSession().getAttribute("generatedByMelatiClass") == null)
    throw new AnticipatedException("Only available from within an Admin generated page");
  String method = melati.getRequest().getMethod();
  String url =  melati.getRequest().getQueryString();
  HttpServletResponse response = melati.getResponse();
  HttpMethod httpMethod = null;
  try {

    HttpClient client = new HttpClient();
    if (method.equals("GET"))
      httpMethod = new GetMethod(url);
    else if (method.equals("POST"))
      httpMethod = new PostMethod(url);
    else if (method.equals("PUT"))
      httpMethod = new PutMethod(url);
    else if (method.equals("HEAD"))
      httpMethod = new HeadMethod(url);
    else
      throw new RuntimeException("Unexpected method '" + method + "'");
    try {
      httpMethod.setFollowRedirects(true);
      client.executeMethod(httpMethod);
      for (Header h : httpMethod.getResponseHeaders()) {
        response.setHeader(h.getName(), h.getValue());
      }
      response.setStatus(httpMethod.getStatusCode());
      response.setHeader("Cache-Control", "no-cache");
      byte[] outputBytes = httpMethod.getResponseBody();
      if (outputBytes != null) {
        response.setBufferSize(outputBytes.length);
        response.getWriter().write(new String(outputBytes));
        response.getWriter().flush();
      }
    } catch (Exception e) {
      throw new MelatiIOException(e);
    }
  } finally {
    httpMethod.releaseConnection();
  }
  return null;
}

Friday 4 September 2009

Software Development with Certainty

My most recent project was to turn an impressive prototype developed by one person into a library, and applications based upon it, that can be simultaneously developed and used by a team.

The development process gains a new dimension once you have published your first version or have your first user. The task is made more tricky due to the absence of the original author.
In other words: situation normal, don't start from here.

The Erewhon applications, Gaboto library and its main dependencies ng4j and Jena are all changing rapidly. New functionality is being added and code and dependencies are being refactored and changed. The challenge is to enable this change without breaking installed systems or at least not breaking them unknowingly. This is ensured by establishing a contract between the code and the design by the use of tests. The tests guarantee that the system actually does do what it claims. Or, more properly, the tests are exactly what the system claims to do.