Skip to content
This repository has been archived by the owner on Aug 24, 2023. It is now read-only.

Commit

Permalink
Changed the way filters operate
Browse files Browse the repository at this point in the history
  • Loading branch information
javaConductor committed Jan 11, 2015
1 parent 53772b6 commit ccfe4c7
Show file tree
Hide file tree
Showing 17 changed files with 244 additions and 90 deletions.
34 changes: 28 additions & 6 deletions src/main/groovy/io/github/javaconductor/gserv/GServ.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ package io.github.javaconductor.gserv
import io.github.javaconductor.gserv.configuration.GServConfig
import io.github.javaconductor.gserv.events.EventManager
import io.github.javaconductor.gserv.events.Events
import io.github.javaconductor.gserv.filters.FilterMatcher
import io.github.javaconductor.gserv.filters.FilterOptions
import io.github.javaconductor.gserv.filters.FilterRunner
import io.github.javaconductor.gserv.plugins.IPlugin
import io.github.javaconductor.gserv.requesthandler.AsyncHandler
import io.github.javaconductor.gserv.requesthandler.RequestContext
Expand Down Expand Up @@ -225,7 +228,8 @@ class gServHandler implements HttpHandler {
private def _nuHandler, _nuDispatcher
Calendar cal = new GregorianCalendar();
Long reqId = 1;

FilterMatcher m = new FilterMatcher()
FilterRunner filterRunner
/**
* Create a handler with a specific configuration
*
Expand All @@ -234,6 +238,7 @@ class gServHandler implements HttpHandler {
*/
def gServHandler(GServConfig cfg) {
_cfg = cfg;
filterRunner = new FilterRunner(_cfg)
this._actions = cfg.actions()
this._staticRoots = cfg.staticRoots()
this._templateEngineName = cfg.templateEngineName()
Expand All @@ -251,20 +256,36 @@ class gServHandler implements HttpHandler {
_dispatcher.start()
}

static long requestId = 0L
/**
* This method is called for each request
* This is called after the Filters and done.
*
* @param httpExchange
*/
void handle(HttpExchange httpExchange) {
RequestContext context = new GServFactory().createRequestContext(httpExchange)
synchronized (requestId){
context.setAttribute(GServ.contextAttributes.requestId, requestId++)
log.trace("ServerHandler.handle(${httpExchange.requestURI.path}) #$requestId")
}
// log.trace("ServerHandler.handle(${httpExchange.requestURI.path}) #")

context.setAttribute(GServ.contextAttributes.serverConfig, _cfg)
boolean matched = _cfg.requestMatched(context)
def filters = m.matchFilters(_cfg.filters(),context)
filters = filters.findAll {theFilter ->
(!theFilter.options()[FilterOptions.MatchedActionsOnly]) ||
(theFilter.options()[FilterOptions.MatchedActionsOnly] && matched)
}

context = filterRunner.runFilters(filters, context)

if (context.isClosed())
return;

log.trace("ServerHandler.handle(${httpExchange.requestURI.path})")
// log.debug("ServerHandler.handle(${httpExchange.requestURI.path}) instream: ${httpExchange.requestBody} outstream: ${httpExchange.responseBody}")
RequestContext context =
httpExchange.getAttribute(GServ.contextAttributes.requestContext) ?:
_factory.createRequestContext( httpExchange )
assert context
context.setAttribute(GServ.contextAttributes.serverConfig, _cfg)
def currentReqId = context.getAttribute(GServ.contextAttributes.requestId)
try {
// httpExchange.setAttribute(GServ.contextAttributes.serverConfig, _cfg)
Expand Down Expand Up @@ -292,6 +313,7 @@ class gServHandler implements HttpHandler {
context.sendResponseHeaders(500, msg.bytes.size())
context.responseBody.write(msg.bytes)
context.responseBody.close()
context.close()
}
}

Expand Down
30 changes: 8 additions & 22 deletions src/main/groovy/io/github/javaconductor/gserv/GServInstance.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package io.github.javaconductor.gserv

import com.sun.net.httpserver.HttpContext
import com.sun.net.httpserver.HttpExchange
import com.sun.net.httpserver.HttpServer
import com.sun.net.httpserver.HttpsServer
import groovy.jmx.builder.JmxBuilder
Expand Down Expand Up @@ -96,14 +97,10 @@ class GServInstance {
this.mbean
}


def createInitFilter(){
def initFilter = ResourceActionFactory.createBeforeFilter("gServInit", "*", "/*", [:], -1) { ->
synchronized (requestId) {
log.trace("initFilter: new request #$requestId")
requestContext.setAttribute(GServ.contextAttributes.requestId, requestId)
++requestId
}
def requestId = requestContext.getAttribute(GServ.contextAttributes.requestId)
log.trace("initFilter(#${requestId} context: $requestContext")
/// here we should check for a blank file name
/// if file name is blank and we have a defaultResource then we use that.
URI uri = applyDefaultResourceToURI(config().defaultResource(),
Expand All @@ -114,7 +111,7 @@ class GServInstance {
rc.requestURI = uri
rc.setAttribute(GServ.contextAttributes.postProcessList, [])
def baos = new FilterByteArrayOutputStream({ _this ->
log.trace "Running ppList for ${uri.path} - req #${rc.getAttribute(GServ.contextAttributes.requestId)}"
log.trace "Running ppList for ${uri.path} - req #${requestId}"
/// run the PostProcess List
def ppList = rc.getAttribute(GServ.contextAttributes.postProcessList).toList()

Expand All @@ -131,7 +128,8 @@ class GServInstance {
ex.printStackTrace(System.err)
}
}
rc.writeIt(bytes)
rc.responseBody.write(bytes)
rc.close()
})
rc.setStreams(rc.requestBody, baos)
nextFilter(rc)
Expand Down Expand Up @@ -163,13 +161,7 @@ class GServInstance {
_filters = _filters ?: []
_filters.add(initFilter);

// if we have filters then create the proxies
if (_filters) {
_filters.sort({ a, b -> a.order - b.order }).each {
// each FilterProxy represents ONE GServ Filter -- this may change
context.filters.add(new io.github.javaconductor.gserv.filters.FilterProxy([it], _cfg))
}
}
_cfg._filters = _filters.sort({ a, b -> a.order - b.order })
context.authenticator = _authenticator;
server.executor = _executor;
def appName = _cfg.name() ?: "gserv"
Expand Down Expand Up @@ -302,13 +294,7 @@ class gServHttpsInstance extends GServInstance {
_filters = _filters ?: []
_filters.add(initFilter);

// if we have filters then create the proxies
if (_filters) {
_filters.sort({ a, b -> a.order - b.order }).each {
// each FilterProxy represents ONE GServ Filter -- this may change
context.filters.add(new io.github.javaconductor.gserv.filters.FilterProxy([it], _cfg))
}
}
_cfg._filters = _filters.sort({ a, b -> a.order - b.order })
context.authenticator = _authenticator;
server.executor = _executor;
def appName = _cfg.name() ?: "gserv"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class GServRunner {
CliBuilder cli = new CliBuilder(
usage: 'gserv [options]',
header: '\nAvailable options (use -h for help):\n',
footer: '\ngServ © 2014 Lee Collins. All rights reserved.'
footer: '\ngServ © 2014-2015 Lee Collins. All rights reserved.'
);

def GServRunner() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ class GServConfig {
matcher.matchAction(_actions, context)
}

boolean requestMatched(exchange) {
!!(matchAction(exchange) || _staticFileHandler.resolveStaticResource(
exchange.requestURI.path,
boolean requestMatched(RequestContext context ) {
!!(matchAction(context) || _staticFileHandler.resolveStaticResource(
context.requestURI.path,
_staticRoots,
bUseResourceDocs))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@

package io.github.javaconductor.gserv.delegates

import com.sun.net.httpserver.Filter.Chain
import groovy.util.logging.Log4j
import io.github.javaconductor.gserv.configuration.GServConfig
import io.github.javaconductor.gserv.converters.InputStreamTypeConverter
import io.github.javaconductor.gserv.delegates.functions.FilterFn
import io.github.javaconductor.gserv.delegates.functions.ResourceFn
import io.github.javaconductor.gserv.delegates.functions.ResourceHandlerFn
import io.github.javaconductor.gserv.events.EventManager
import io.github.javaconductor.gserv.filters.Filter
import io.github.javaconductor.gserv.requesthandler.RequestContext

/**
*
Expand All @@ -45,11 +47,10 @@ import io.github.javaconductor.gserv.events.EventManager
class FilterDelegate extends DelegateFunctions implements ResourceHandlerFn, FilterFn, ResourceFn {
//def exchange
def $this
def eventManager = EventManager.instance()
def requestContext
def FilterDelegate(filter, requestContext, Chain chain, serverConfig, templateEngineName) {
def FilterDelegate(Filter filter, RequestContext requestContext, GServConfig serverConfig, String templateEngineName) {
assert requestContext
value("chain", chain);
// value("chain", chain);
value("linkBuilder", serverConfig.linkBuilder());
value("staticRoots", serverConfig.staticRoots());
value("templateEngineName", serverConfig.templateEngineName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,8 @@ trait FilterFn {
}

def nextFilter(RequestContext e) {
def currentRequestId = e.getAttribute(GServ.contextAttributes.requestId)
if (_nextFilterCalled)
throw new IllegalStateException("nextFilter() has already been called.")
e.nativeObject()?.setAttribute(GServ.contextAttributes.requestContext, e)
log.trace "FilterDelegate: Request($currentRequestId) :Filter.nextFilter calling chain."
//TODO in the tester context i do not have a nativeObject
value("chain").doFilter( e.nativeObject() )
log.trace "FilterDelegate: Request($currentRequestId) :Filter.nextFilter called chain."
_nextFilterCalled = true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@

package io.github.javaconductor.gserv.delegates.functions

import org.apache.commons.io.IOUtils
import io.github.javaconductor.gserv.GServ
import io.github.javaconductor.gserv.GServResource
import io.github.javaconductor.gserv.ResourceObject
import io.github.javaconductor.gserv.ResourceActionFactory
import io.github.javaconductor.gserv.ResourceObject
import io.github.javaconductor.gserv.events.EventManager
import io.github.javaconductor.gserv.events.Events
import io.github.javaconductor.gserv.filters.FilterOptions
import io.github.javaconductor.gserv.utils.LinkBuilder
import io.github.javaconductor.gserv.utils.StaticFileHandler
import org.apache.commons.io.IOUtils
import sun.misc.BASE64Decoder

/**
Expand All @@ -42,16 +42,16 @@ import sun.misc.BASE64Decoder
*/
trait ServerConfigFn {

def name(nm) {
this.value "name", nm
this
}
def name(nm) {
this.value "name", nm
this
}

def name() {
this.value("name")
}
def name() {
this.value("name")
}

def addAction(action) {
def addAction(action) {
this.value("actionList").add(action)
this
}
Expand Down Expand Up @@ -137,7 +137,7 @@ trait ServerConfigFn {
* @param clozure Filter behavior
*
*/
def filter(name, url, method, options, clozure, order) {
def filter(name, url, method, options, clozure, order) {
method = method ?: '*'
//println("serverInitClosure: filter($name) $method, url=$url")
addFilter(ResourceActionFactory.createFilter(name, method, url, options, clozure))
Expand All @@ -153,7 +153,7 @@ trait ServerConfigFn {
* @return
*
*/
def after(name, url, method, options, order, clozure) {
def after(name, url, method, options, order, clozure) {
method = method ?: '*'
//println("serverInitClosure: after($name) $method, url=$url, list=${this._filterList}")
def theFilter = ResourceActionFactory.createAfterFilter(name, method, url, options, order, clozure)
Expand All @@ -170,7 +170,7 @@ trait ServerConfigFn {
* @param closure fn(requestContext, byte[] data)
* @return this
*/
def before(name, url, method, options, order, clozure) {
def before(name, url, method, options, order, clozure) {
method = method ?: '*'
def theFilter = ResourceActionFactory.createBeforeFilter(name, method, url, options, order, clozure)
addFilter(theFilter)
Expand All @@ -188,22 +188,20 @@ trait ServerConfigFn {

def userPswd = getBasicAuthUserPswd(requestContext);
log.trace("basicAuth before(): userPswd:$userPswd");
if (!userPswd || userPswd.length < 2) {
requestContext.responseHeaders.add("WWW-Authenticate", "Basic realm=$realm")
if (!userPswd || userPswd.length < 2) {
(requestContext).responseHeaders.put("WWW-Authenticate", "Basic realm=$realm")
error(401, "Authentication Required");
} else {
def bAuthenticated = _authenticated(userPswd[0], userPswd[1], challengeFn);
if (bAuthenticated) {
nextFilter();
return (requestContext);
} else {
if (!bAuthenticated) {
error(403, "Bad credentials for path ${requestContext.requestURI.path}.");
}
}
return (requestContext);
}
}
this
}//basicAuthentication
}
//basicAuthentication

def getBasicAuthUserPswd(requestContext) {
def basic = requestContext.requestHeaders.get("Authorization");
Expand All @@ -221,7 +219,7 @@ trait ServerConfigFn {
return (challengeFn(user, pswd));
}

/**
/**
* Creates a closure that returns file 'filename'
*
* @param filename
Expand Down Expand Up @@ -266,6 +264,7 @@ trait ServerConfigFn {
}
requestContext.responseBody.close();
requestContext.close()
requestContext
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ class Filter extends ResourceAction {
def Filter(name, method, urlPatterns, qryPattern, opts, beforeClosure) {
super(name, method, urlPatterns, qryPattern, opts, beforeClosure);
}

@Override
String toString() {
name +"->"+ super.toString()
}

}
/**
* Supported Filter Types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
* THE SOFTWARE.
*/

package io.github.javaconductor.gserv
package io.github.javaconductor.gserv.filters

import io.github.javaconductor.gserv.Matcher
import io.github.javaconductor.gserv.ResourceAction
import io.github.javaconductor.gserv.requesthandler.RequestContext

/**
Expand All @@ -43,6 +45,17 @@ class FilterMatcher extends Matcher {
return ret;
}

List<Filter> matchFilters(List<Filter> filterList, RequestContext requestContext) {
//loop thru the actionList calling match(pattern,uri) where the method matches til one returns true then returning that pattern
def ret = filterList.findAll { p ->
def rmethod = p.method()
def methodOk = (rmethod == '*' || rmethod == requestContext.requestMethod)
def b = (methodOk && match(p, requestContext.requestURI))
b
}
return ret;
}

@Override
ResourceAction matchAction(List<ResourceAction> filterList, URI uri, String method) {
//loop thru the actionList calling match(pattern,uri) where the method matches til one returns true then returning that pattern
Expand Down
Loading

0 comments on commit ccfe4c7

Please sign in to comment.