-------------------------------------------------------------------------------- -- Title: LWService.lua -- Description: Like a square peg in a round hole -- Author: Raphaël Szwarc http://alt.textdrive.com/lua/ -- Creation Date: February 1, 2005 -- Legal: Copyright (C) 2005 Raphaël Szwarc -------------------------------------------------------------------------------- -- import dependencies local LUObject = require( "LUObject" ) local LUBundle = require( "LUBundle" ) local LUList = require( "LUList" ) local LUMap = require( "LUMap" ) local LUString = require( "LUString" ) local SocketWriter = require( "SocketWriter" ) -- define the class local super = LUObject local self = super() -- class variable(s) local _default = nil local _methods = nil -- initialization method function self:init( aPrefix, anAuthenticator ) self = super.init( self ) self._prefix = aPrefix self._authenticator = anAuthenticator return self end -- method to access this service allowed methods function self:allowedMethods() local aBuffer = LUList() local someMethods = self:methods() for aKey, aValue in someMethods:iterator() do if self:respondsTo( aValue ) == true then aBuffer:add( aKey ) end end return aBuffer:join( ", " ) end -- method to access this service authenticator function self:authenticator() return self._authenticator end -- method to access this service path for the given context function self:pathWithContext( aContext ) local anURI = aContext:request():uri() local aPath = anURI:path() if aPath ~= nil then local somePrefixComponents = anURI:componentsWithPath( self:prefix() ) local somePathComponents = anURI:pathComponents() for anIndex, aValue in somePrefixComponents:iterator() do local aPathValue = somePathComponents:get() if aPathValue ~= nil and aPathValue:lower() == aValue:lower() then somePathComponents:remove() else break end end if somePathComponents:hasData() == true then return somePathComponents:join( "/" ) end end return nil end -- method to access this service prefix function self:prefix() return self._prefix end -- method to handle a GET method function self:handleGet( aContext, hasContent ) aContext:response():writeStatus( 404, hasContent ) return self end -- method to handle a DELETE method function self:handleDelete( aContext ) aContext:response():writeStatus( 403 ) return self end -- method to handle a HEAD method function self:handleHead( aContext ) self:handleGet( aContext, false ) return self end -- method to handle a OPTIONS method function self:handleOptions( aContext ) local aResponse = aContext:response() aResponse:headers():put( "allow", self:allowedMethods() ) aResponse:writeContent( nil, false ) return self end -- method to handle a POST method function self:handlePost( aContext ) aContext:response():writeStatus( 403 ) return self end -- method to handle a PUT method function self:handlePut( aContext ) aContext:response():writeStatus( 403 ) return self end -- method to handle a TRACE method function self:handleTrace( aContext ) local aBuffer = LUList() local aResponse = aContext:response() local aRequest = aContext:request() local aLine = ( "%s %s %s" ):format( aRequest:method(), aRequest:rawURI(), aRequest:version() ) aBuffer:add( aLine ) for aKey, aValue in aRequest:headers():iterator() do aBuffer:add( ( "%s: %s" ):format( aKey, aValue ) ) end aBuffer:add( "" ) if aRequest:content() ~= nil then aBuffer:add( aRequest:content() ) end aResponse:headers():put( "content-type", "message/http" ) aResponse:writeContent( aBuffer:join( SocketWriter:eol() ) ) return self end -- method to run this service function self:run( aContext ) local aResponse = aContext:response() local aMethod = self:methods():get( aContext:request():method() ) if aMethod ~= nil then if self:respondsTo( aMethod ) == true then local anAuthenticator = self:authenticator() aContext:setService( self ) if anAuthenticator == nil or anAuthenticator:authenticate( aContext ) == true then self:invoke( aMethod, aContext ) end else aResponse:headers():put( "allow", self:allowedMethods() ) aResponse:writeStatus( 405 ) end else aResponse:writeStatus( 501 ) end return self end -- method for string representation function self:toString() return ( "%s@%s" ):format( self:className(), self:prefix() ) end -- method to access the default service function self:default() if _default == nil then _default = self:new( "/" ) end return _default end -- method to access the response methods function self:methods() if _methods == nil then local aBundle = LUBundle:bundleWithName( "LWService" ) local aFile = aBundle:fileWithName( "LWServiceMethods", "txt" ) _methods = LUMap():load( aFile ) end return _methods end return self