Anonymous avatar Anonymous committed b477624

fixed write, added dispatch_once, separated default 404 handler

Comments (0)

Files changed (3)

 local eio = require("eio")
 
 function http_handler(r)
-	print(r.req)
+	print(r.uri)
 	r:write("hello, root")
 end
 
 function http_handler_index(r)
-	print(r.req)
+	print(r.uri)
 	r:write("hello, index")
 end
 
 
 	EIO_GET_NUMBER(L, fd, 1);
 	s = lua_tostring(L, 2);
-	r = write(fd, s, lua_strlen(L, 2));
+	r = write(fd, s, lua_strlen(L,2));
 	EIO_RETURN(L, r, errno);
 }
 
 	nfds = lua_objlen(L, 2);
 	for (i = 1; i <= nfds; i++) {
 		lua_pushnumber(L, i);
-		lua_gettable(L, 1); // get rfds[i]
+		lua_gettable(L, 2); // get wfds[i]
 		fd = lua_tonumber(L, -1);
 		if (fd > maxfd) maxfd = fd;
 		FD_SET(fd, &wfds);
 
 	r = select(maxfd+1, &rfds, &wfds, NULL, NULL);
 
-
 	if (r < 0) {
 		lua_pushnumber(L, -errno);
 		return 1;
 -- 
 function libeio.http_server(port, handlers)
 	local f = libeio.listen(port)
-	if f < 0 then error("listen(): "..f) end
+	if f < 0 then
+		return nil, f
+	end
 
 	local s = {}
 	s.fd = f
 end
 
 --
+-- Run server loop once and dispatch all events
+--
+function http:dispatch_once()
+	local n
+	local rfds, wfds = {}, {}
+	-- add listening socket itself
+	table.insert(rfds, self.fd)
+
+	-- add other file descriptors to rfds/wfds
+	for _, fd in pairs(self.fds) do
+		if fd.r then table.insert(rfds, fd.fd) end
+		if fd.w then table.insert(wfds, fd.fd) end
+	end
+
+	-- wait for the events
+	n, rfds, wfds = libeio.select(rfds, wfds)
+	if n < 0 then error("select(): "..n) end
+
+	-- special case: read on listening socket (accept event)
+	if rfds[self.fd] ~= nil then
+		self:accept()
+	end
+
+	-- dispatch the rest of the events
+	n = 0
+	for fd, cr in pairs(self.crs) do
+		self.fds[fd].can_read = (rfds[fd] ~= nil)
+		self.fds[fd].can_write = (wfds[fd] ~= nil)
+		coroutine.resume(cr)
+		n = n + 1
+		if coroutine.status(cr) == 'dead' then
+			libeio.close(fd)
+			self.crs[fd] = nil
+			self.fds[fd] = nil
+		end
+	end
+	return n
+end
+
+--
 -- Dispatch HTTP clients in an endless loop
 --
 function http:serve()
 	while true do 
-		local n
-		local rfds, wfds = {}, {}
-		-- add listening socket
-		table.insert(self.fds, self.fd, {fd=self.fd, r=true})
-
-		-- add other file descriptors to rfds/wfds
-		for _, fd in pairs(self.fds) do
-			if fd.r then 
-				table.insert(rfds, fd.fd)
-			end
-			if fd.w then
-				table.insert(wfds, fd.fd)
-			end
-		end
-
-		-- wait for the events
-		n, rfds, wfds = libeio.select(rfds, wfds)
-		if n < 0 then error("select(): "..n) end
-
-		-- special case: read on listening socket (accept event)
-		if rfds[self.fd] ~= nil then
-			self:accept()
-		end
-
-		-- dispatch the rest of the events
-		for fd, cr in pairs(self.crs) do
-			self.fds[fd].can_read = (rfds[fd] ~= nil)
-			self.fds[fd].can_write = (wfds[fd] ~= nil)
-			coroutine.resume(cr)
-			if coroutine.status(cr) == 'dead' then
-				libeio.close(fd)
-				self.crs[fd] = nil
-				self.fds[fd] = nil
-			end
+		if self:dispatch_once() < 0 then
+			break
 		end
 	end
 end
 	-- the first line is "METHOD URI VERSION"
 	local header = {}
 	local method, uri = h:match("^(%w+)%s+([^%s]+)")
-	print(method, uri)
 	h = h:sub(h:find("\n")+1) -- skip 1st line
 
 	for k,v in h:gmatch("([%w-]+)%s*:%s*(.-)\r\n") do
 	return method, uri, header
 end
 
+local function default_http_404_handler(r)
+	r:write("HTTP 404 Not Found\r\n\r\n")
+end
+
 --
 -- Process new HTTP connection
 --
 function http:accept()
 	local fd = libeio.accept(self.fd)
-	print('accept')
 
 	self.fds[fd] = {fd = fd}
 
 			method = m,
 			uri = u,
 			header = h,
-			read = function(self,n) return self:read(fd, n) end,
-			write = function(self,s) return libeio.write(fd, s) end
+			read = function(r,n) return self:read(fd, n) end,
+			write = function(r,s) return self:write(fd, s) end
 		}
 
-		local handler = function(r) r:write("404 Not Found\r\n") end
+		local handler = default_http_404_handler
 		local len = 0
 		for uri, h in pairs(self.handlers) do
 			-- check if URI starts with handler URI
 	end
 end
 
+--
+-- Write to the HTTP client socket in co-routine
+--
+function http:write(fd, buf)
+	while true do
+		if self.fds[fd].can_write then
+			self.fds[fd].can_write = false
+			self.fds[fd].w = false
+			print("writing"..#buf)
+			local n = libeio.write(fd, buf)
+			if n < 0 then return n end
+			if n == #buf then return 0 end
+			buf = buf:sub(n+1)
+		else
+			print("write yield")
+			self.fds[fd].w = true
+			coroutine.yield()
+		end
+	end
+end
+
 return libeio
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.