[webkit-gtk] Using a custom protocol to load resources

Rena hyperhacker at gmail.com
Mon Feb 25 21:17:04 PST 2013

I'm using WebKitGTK in Lua (via lgi) and I want to set up some kind of
communication channel between JS and Lua, that can be used to pass
data back and forth between them and load resources.

The best approach to me looks like using AJAX (via jQuery) to place
requests to a custom protocol, and handling those requests on the Lua
side. I can catch those requests in Lua in the
resource-request-starting signal, but I can't seem to push a response
- regardless of what I do in the handler, it only triggers the AJAX
error handler, with a response code of 0 and empty error string.

The Lua code is:
#!/usr/bin/env lua5.1
package.path = './src/?.lua;' .. package.path
package.cpath = './src/?/build/?.so;' .. package.cpath
lgi = require('lgi')
gtk = lgi.require('Gtk', '3.0')
gdk = lgi.require('Gdk', '3.0')
gio = lgi.require('Gio', '2.0')
webkit = lgi.require('WebKit', '3.0') --requires libwebkitgtk-3.0-dev
glib = lgi.GLib
gobject = lgi.GObject
pango = lgi.Pango
cairo = lgi.cairo --lowercase for some reason
soup = lgi.Soup

--create the main window and webview
local webview = webkit.WebView.new()
local window = gtk.Window {
	title = "Web View",
	resizable = true,
	type = gtk.WindowType.TOPLEVEL,
	type_hint = gdk.WindowTypeHint.NORMAL,
	default_width = 200,
	default_height = 200,
	decorated = true,
	resizable = true,
	gtk.ScrolledWindow { expand = true, webview },
	on_destroy = function() os.exit(0) end,

--configure the webview
local settings = webkit.WebSettings.new()
settings.enable_accelerated_compositing = true
settings.enable_webaudio = true --enable some experimental JS APIs
settings.enable_webgl = true

--required to allow scripts in file:///* to access http://* and our custom
--protocols used for JS/Lua communication
settings.enable_universal_access_from_file_uris = true

--log JS console messages
--the default handler logs them too, but it's ugly.
webview.on_console_message = function(webview, message, line, source)
	print(('<JS> %s:%d: %s'):format(source, line, message))
	return true

webview.on_load_error = function(webview, frame, uri, err)
	io.stderr:write(("Load error: %s: %s\n"):format(uri, err.message))

webview.on_resource_load_failed = function(webview, frame, resource, err)
	local uri = resource:get_uri()
	io.stderr:write(("Resource load failed: %s: %s\n"):format(uri, err.message))

--set up URI request handler
webview.on_resource_request_starting =
	function(webview, frame, resource, request, response)
		print("Request", request:get_uri())
		local msg = request:get_message()
		msg.response_headers:append('Access-Control-Allow-Origin', '*')

		if request:get_uri():sub(1, 6) == 'lol://' then
			--this doesn't seem to work; the message is never received by the
			--client and it fails with error code 0
			local str = "bananas"
			msg:set_response("text/plain", soup.MemoryUse.COPY, str, #str)

			--returning true or false here makes no difference

--load main page
webview:load_uri('file://' .. os.getenv('PWD') .. '/data/main.html')

local ok, err = xpcall(gtk.main, debug.traceback)
if not ok then
	io.stderr:write(tostring(err) .. '\n')

The Javascript code is:

var n = 0
$(document).ready(function() {

		url: "lol://wtf?hax=yup",
		isLocal: true, //makes no difference
		success: function(data, status, jqXHR) {
			console.log("AJAX recv:" + data)
		error: function(jqXHR, status, err) {
			console.log("AJAX error: " + status + "; " + err +
				"; resp=" + jqXHR.status)

	setInterval(function() {
		n = n + 1
	}, 1000)

It logs an error: "AJAX error: error; ; resp=0" - i.e. status =
"error", err = "", jqXHR.status = 0. Is there more I need to do in my
handler to return a data string and have it consider the request

Sent from my Game Boy.

More information about the webkit-gtk mailing list