private void handleJfnikiRequest(HTTPRequest request, ToadletContext ctx)
        throws ToadletContextClosedException,  IOException, PluginHTTPException {
        // djk: why is SFA doing this on every request?
    	// SFA: afaik this should not be needed, feel free to move this elsewhere.
        mWikiApp.setContainerPrefix(mNameSpace.substring(0, mNameSpace.length() - 1));
        try {
            mWikiApp.setRequest(new PluginRequest(request, mNameSpace));
            WikiContext context = mWikiApp.getContext();
            ChildContainerResult appResult = mWikiApp.handle(context);
            if (appResult.getMimeType().equals("text/html")) {
                PageNode pageNode = ctx.getPageMaker().getPageNode("jFniki", true, ctx);
                pageNode.addCustomStyleSheet(mNameSpace + "jfniki.css");
                pageNode.content.addChild("%", new String(appResult.getData(), "UTF-8"));
                if (appResult.getMetaRefreshSeconds() > 0) {
                    pageNode.headNode.addChild("meta", "http-equiv", "Refresh").
                        addAttribute("content","" + appResult.getMetaRefreshSeconds());
                }
                writeHTMLReply(ctx, 200, "OK", pageNode.outer.generate());
            } else {
                // i.e. for stuff like jfniki.css, images (none yet).
                writeReply(ctx, 200, appResult.getMimeType(), "OK",
                           appResult.getData(), 0, appResult.getData().length);
            }
            // IMPORTANT: Look at these catch blocks carefully. They bypass the freenet ContentFilter.
            // SeekingForAttention: This could be insecure code because I have no clue and no documentation.
            //                      Do not use it if you don't know what you are doing.
            // djk: All I meant is that the my code runs the content filter over the html which is returned
            //      by handle() above, but  not  over whatever you return from the catch blocks below.
            // SFA: so i guess this comment block but the first line can be removed.
        } catch(AccessDeniedException accessDenied) {
            // FIXME: Check. This doesn't need to be HTML escaped because it is text/plain, right?
            writeReply(ctx, 403, "text/plain", "Forbidden", accessDenied.getMessage());
        } catch(RedirectException redirected) {
            writeTemporaryRedirect(ctx, redirected.getLocalizedMessage(), redirected.getLocation());
        } catch(DownloadException forceDownload) {
            // This is to allow exporting files. e.g. configuration, archive exports.

            MultiValueTable<String, String> headers
                = new MultiValueTable<String, String>();
            // Required to set the suggested file name.
            headers.put("Content-disposition",
                        String.format("attachment; filename=%s",
                                      forceDownload.mFilename));
            ctx.sendReplyHeaders(200, "sending file", headers,
                                 forceDownload.mMimeType,
                                 forceDownload.mData.length);
	    ctx.writeData(forceDownload.mData, 0,
                          forceDownload.mData.length);

            // Can't do this for Toadlet's.
            // throw new DownloadPluginHTTPException(forceDownload.mData,
            //                                       forceDownload.mFilename,
            //                                       forceDownload.mMimeType);
	    	// SFA: so this can be removed too i guess?

        } catch(ChildContainerException childError) {
            writeReply(ctx, 500, "text/plain", "Internal Server Error", childError.getMessage());
        }
    }