diff --git a/src/main/groovy/io/github/javaconductor/gserv/GServ.groovy b/src/main/groovy/io/github/javaconductor/gserv/GServ.groovy index 6f49563..b79b8fe 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/GServ.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/GServ.groovy @@ -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 @@ -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 * @@ -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() @@ -251,6 +256,7 @@ 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. @@ -258,13 +264,28 @@ class gServHandler implements HttpHandler { * @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) @@ -292,6 +313,7 @@ class gServHandler implements HttpHandler { context.sendResponseHeaders(500, msg.bytes.size()) context.responseBody.write(msg.bytes) context.responseBody.close() + context.close() } } diff --git a/src/main/groovy/io/github/javaconductor/gserv/GServInstance.groovy b/src/main/groovy/io/github/javaconductor/gserv/GServInstance.groovy index 9d545f9..501c9c8 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/GServInstance.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/GServInstance.groovy @@ -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 @@ -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(), @@ -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() @@ -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) @@ -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" @@ -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" diff --git a/src/main/groovy/io/github/javaconductor/gserv/GServRunner.groovy b/src/main/groovy/io/github/javaconductor/gserv/GServRunner.groovy index 6dcfa32..48f898a 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/GServRunner.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/GServRunner.groovy @@ -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() { diff --git a/src/main/groovy/io/github/javaconductor/gserv/configuration/GServConfig.groovy b/src/main/groovy/io/github/javaconductor/gserv/configuration/GServConfig.groovy index 2b563bd..b649eca 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/configuration/GServConfig.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/configuration/GServConfig.groovy @@ -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)) } diff --git a/src/main/groovy/io/github/javaconductor/gserv/delegates/FilterDelegate.groovy b/src/main/groovy/io/github/javaconductor/gserv/delegates/FilterDelegate.groovy index b590ce2..713930e 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/delegates/FilterDelegate.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/delegates/FilterDelegate.groovy @@ -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 /** * @@ -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()); diff --git a/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/FilterFn.groovy b/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/FilterFn.groovy index 5a58a44..479f415 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/FilterFn.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/FilterFn.groovy @@ -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 } } diff --git a/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/ServerConfigFn.groovy b/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/ServerConfigFn.groovy index 09cdd74..6442cc5 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/ServerConfigFn.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/delegates/functions/ServerConfigFn.groovy @@ -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 /** @@ -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 } @@ -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)) @@ -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) @@ -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) @@ -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"); @@ -221,7 +219,7 @@ trait ServerConfigFn { return (challengeFn(user, pswd)); } - /** + /** * Creates a closure that returns file 'filename' * * @param filename @@ -266,6 +264,7 @@ trait ServerConfigFn { } requestContext.responseBody.close(); requestContext.close() + requestContext } } diff --git a/src/main/groovy/io/github/javaconductor/gserv/filters/Filter.groovy b/src/main/groovy/io/github/javaconductor/gserv/filters/Filter.groovy index 4323b82..850995b 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/filters/Filter.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/filters/Filter.groovy @@ -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 diff --git a/src/main/groovy/io/github/javaconductor/gserv/FilterMatcher.groovy b/src/main/groovy/io/github/javaconductor/gserv/filters/FilterMatcher.groovy similarity index 82% rename from src/main/groovy/io/github/javaconductor/gserv/FilterMatcher.groovy rename to src/main/groovy/io/github/javaconductor/gserv/filters/FilterMatcher.groovy index 0d16e19..9059443 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/FilterMatcher.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/filters/FilterMatcher.groovy @@ -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 /** @@ -43,6 +45,17 @@ class FilterMatcher extends Matcher { return ret; } + List matchFilters(List 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 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 diff --git a/src/main/groovy/io/github/javaconductor/gserv/filters/FilterProxy.groovy b/src/main/groovy/io/github/javaconductor/gserv/filters/FilterProxy.groovy index d5bd5fb..79f8285 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/filters/FilterProxy.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/filters/FilterProxy.groovy @@ -27,7 +27,6 @@ package io.github.javaconductor.gserv.filters import com.sun.net.httpserver.Filter import com.sun.net.httpserver.HttpExchange import groovy.util.logging.Log4j -import io.github.javaconductor.gserv.FilterMatcher import io.github.javaconductor.gserv.GServ import io.github.javaconductor.gserv.GServFactory import io.github.javaconductor.gserv.Utils @@ -66,12 +65,10 @@ class FilterProxy extends Filter { */ @Override void doFilter(HttpExchange httpExchange, com.sun.net.httpserver.Filter.Chain chain) throws IOException { - - /// here we do the get the ResourceContect from the Exchange RequestContext requestContext = httpExchange.getAttribute(GServ.contextAttributes.requestContext) - - // if none create it - if ( !requestContext ){ + // if none or its an old one create it + if (!requestContext || requestContext.isClosed()){ + /// here we do the get the ResourceContext from the Exchange requestContext = new GServFactory().createRequestContext(httpExchange) httpExchange.setAttribute(GServ.contextAttributes.requestContext, requestContext) requestContext.setAttribute(GServ.contextAttributes.receivedMS, "" + new Date().time) @@ -80,13 +77,12 @@ class FilterProxy extends Filter { } } + log.trace("FilterProxy: DO Filter: ${httpExchange.requestURI.path} context: ${requestContext}") def currentRequestId = requestContext.getAttribute(GServ.contextAttributes.requestId) //println requestContext.properties // log.trace "FilterProxy: Request($currentRequestId) : instream ${httpExchange.requestBody} outstream ${httpExchange.responseBody}" - - def theFilter = m.matchAction ( _filterList, requestContext ) if (theFilter) { eventMgr.publish(Events.RequestMatchedFilter, [ @@ -102,7 +98,7 @@ class FilterProxy extends Filter { if (!_serverConfig.requestMatched(requestContext)) { log.trace "FilterProxy: Request($currentRequestId) : Not matched. Calling chain." chain.doFilter(httpExchange); - log.trace "FilterProxy: Request($currentRequestId) :Not matched. Called chain:" + log.trace "FilterProxy: Request($currentRequestId) : Not matched. Called chain:" return } } @@ -138,8 +134,8 @@ class FilterProxy extends Filter { httpExchange.setAttribute(GServ.contextAttributes.requestContext, requestContext) } catch (Throwable ex) { - log.trace( "Filter $theFilter threw exception: ${ex.message}.", ex ) - log.error( "Filter $theFilter threw exception: ${ex.message}." ) + log.trace( "FilterProxy: $theFilter threw exception: ${ex.message}.", ex ) + log.error( "FilterProxy: $theFilter threw exception: ${ex.message}." ) eventMgr.publish(Events.FilterError, [ filter : (theFilter.name ?: "-"), requestTimeMs: requestContext.getAttribute(GServ.contextAttributes.receivedMS), diff --git a/src/main/groovy/io/github/javaconductor/gserv/filters/FilterRunner.groovy b/src/main/groovy/io/github/javaconductor/gserv/filters/FilterRunner.groovy new file mode 100644 index 0000000..3b44faa --- /dev/null +++ b/src/main/groovy/io/github/javaconductor/gserv/filters/FilterRunner.groovy @@ -0,0 +1,133 @@ +package io.github.javaconductor.gserv.filters + +import groovy.util.logging.Log4j +import io.github.javaconductor.gserv.GServ +import io.github.javaconductor.gserv.Utils +import io.github.javaconductor.gserv.configuration.GServConfig +import io.github.javaconductor.gserv.delegates.FilterDelegate +import io.github.javaconductor.gserv.events.EventManager +import io.github.javaconductor.gserv.events.Events +import io.github.javaconductor.gserv.requesthandler.RequestContext + +/** + * Created by lcollins on 1/11/2015. + */ +@Log4j +class FilterRunner { + def _serverConfig + def FilterRunner(GServConfig config){ + _serverConfig = config + } + + RequestContext runFilters(List filters, RequestContext c) { + RequestContext context = c + for ( Filter f: filters){ + context = runFilter(f,context) ?: context + if ( context.isClosed()) + return context + } + context + } + + RequestContext runFilter(Filter theFilter, RequestContext requestContext){ + + switch (theFilter.filterType) { + case FilterType.After: + ////////////////////////////////////////////////////////////////////// + /// We will set the delegate for the closure before we put in the list + ////////////////////////////////////////////////////////////////////// + + def fn = theFilter.requestHandler() + //TODO the After filter will have a potentially OLD exchange injected but the current one passed in + fn.delegate = prepareDelegate(theFilter, requestContext) + + /// add after closure to PostProcessList + def ppList = requestContext.getAttribute(GServ.contextAttributes.postProcessList) ?: [] + log.trace "FilterRunner: Scheduling after filter ${theFilter.name} for req #${requestContext.getAttribute(GServ.contextAttributes.requestId)} " + ppList << fn + requestContext.setAttribute( GServ.contextAttributes.postProcessList, ppList ) + return requestContext + + case FilterType.Before: + case FilterType.Normal: + try { + // run the filter + // replace with new context if returned + requestContext = process(theFilter, requestContext) ?: requestContext + //httpExchange.setAttribute(GServ.contextAttributes.requestContext, requestContext) + } catch (Throwable ex) { + //TODO must handle this better - + log.trace( "FilterRunner: $theFilter threw exception: ${ex.message}.", ex ) + log.error( "FilterRunner: $theFilter threw exception: ${ex.message}." ) + } finally { + } + return requestContext + + }//switch + } + + RequestContext process(Filter theFilter, RequestContext context){ + Closure cl = theFilter.requestHandler()//_handler + def options = theFilter.options() + FilterDelegate dgt = prepareDelegate(theFilter, context) + def errorHandlingWrapper = { clozure, List argList -> + try { + return clozure(*argList) + } catch (Throwable e) { + log.error("FilterRunner error: ${e.message}", e) + e.printStackTrace(System.err) + dgt.error(500, e.message) + context + } + } + + //TODO Should be a cleaner way to do this + cl.delegate = dgt + cl.resolveStrategy = Closure.DELEGATE_FIRST + /// Pass the route variables to the behavior if option is set + /// Else there will be no args + List args = options[FilterOptions.PassRouteParams] ? prepareArguments(context,theFilter) : []; + /// Execute the behavior for this filter + def ret = errorHandlingWrapper(cl, args) + ret + } + + private def prepareDelegate(filter, requestContext, templateEngineName ="") { + new FilterDelegate(filter, requestContext, _serverConfig, templateEngineName) + } + + /** + * Set up the args to be sent to a FilterBehaviorClosure + * + * @param context + * @param theFilter + * @return + */ + private def prepareArguments(context, theFilter) { + def uri = context.requestURI + def args = [] + def method = theFilter.method() + if (method == "PUT" || method == "POST") { + // add the data before the other args + // data is a byte[] + args.add(context.getRequestBody()) + } + + def pathElements = uri.path.split("/").findAll { !(!it) } + //// loop thru the Patterns getting the corresponding uri path elements + for (int i = 0; i != theFilter.pathSize(); ++i) { + def p = theFilter.path(i) + def pathElement = pathElements[i]; + if (p.isVariable()) { + args.add(pathElement) + } + } + + def qmap = Utils.queryStringToMap(uri.query) + theFilter.queryPattern().queryKeys().each { k -> + args.add(qmap[k]) + } + args + } + +} diff --git a/src/main/groovy/io/github/javaconductor/gserv/plugins/caching/CachingPlugin.groovy b/src/main/groovy/io/github/javaconductor/gserv/plugins/caching/CachingPlugin.groovy index f219ceb..5e82810 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/plugins/caching/CachingPlugin.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/plugins/caching/CachingPlugin.groovy @@ -85,10 +85,11 @@ class CachingPlugin extends AbstractPlugin { //exchange.responseHeaders["ETag"] = calcETag nextFilter() } - requestContext + return requestContext } // add it to the config addFilter(f) + requestContext } }/// method diff --git a/src/main/groovy/io/github/javaconductor/gserv/plugins/cors/CorsPlugin.groovy b/src/main/groovy/io/github/javaconductor/gserv/plugins/cors/CorsPlugin.groovy index 5a47488..dbf7de4 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/plugins/cors/CorsPlugin.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/plugins/cors/CorsPlugin.groovy @@ -45,7 +45,6 @@ class CORSMode { class CorsPlugin extends AbstractPlugin { def allowAllHandler = { CORSConfig corsConfig -> -// println "CorsPlugin.allowAllHandler(): ${exchange.requestMethod}(${exchange.requestURI})" switch (requestContext.requestMethod) { case "OPTIONS": @@ -166,7 +165,7 @@ class CorsPlugin extends AbstractPlugin { } /** - * @return a closure - fn(chain) + * @return a closure - fn() * the closure MUSt be a valid Before-Filter closure * @param corsConfig */ diff --git a/src/main/groovy/io/github/javaconductor/gserv/requesthandler/AsyncDispatcher.groovy b/src/main/groovy/io/github/javaconductor/gserv/requesthandler/AsyncDispatcher.groovy index bd610f5..d1f3db7 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/requesthandler/AsyncDispatcher.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/requesthandler/AsyncDispatcher.groovy @@ -55,7 +55,7 @@ class AsyncDispatcher extends DynamicDispatchActor { private GServConfig _config def AsyncDispatcher(ActorPool actorPool, GServConfig config) { - this.setParallelGroup(new DefaultPGroup(new ResizeablePool(false, 10))) + this.setParallelGroup(new DefaultPGroup(new ResizeablePool(false, 1))) _actorPool = actorPool _config = config; } @@ -136,7 +136,7 @@ class AsyncDispatcher extends DynamicDispatchActor { //TODO test this well!! def mimeType = MimeTypes.getMimeType(fileExtensionFromPath(context.requestURI.path)) //header("Content-Type", mimeType) - context.getResponseHeaders().put("Content-Type", mimeType) + context.getResponseHeaders().put("Content-Type", [mimeType]) evtMgr.publish(Events.RequestMatchedStatic, [requestId: currentReqId, actionPath: context.requestURI.path, method: context.getRequestMethod()]) // println "AsyncDispatcher.process(): Found static resource: ${httpExchange.requestURI.path}: seems to be ${istream.available()} bytes." diff --git a/src/main/groovy/io/github/javaconductor/gserv/requesthandler/wrapper/RequestContextWrapper.groovy b/src/main/groovy/io/github/javaconductor/gserv/requesthandler/wrapper/RequestContextWrapper.groovy index 132e580..82350d0 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/requesthandler/wrapper/RequestContextWrapper.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/requesthandler/wrapper/RequestContextWrapper.groovy @@ -51,6 +51,9 @@ class RequestContextWrapper extends AbstractRequestContext { if (!context) throw new IllegalArgumentException("context must NOT be null. Should be valid RequestContext impl.") + if (context instanceof RequestContextWrapper) + throw new IllegalArgumentException("context must NOT be Wrapper.") + _context = context this.requestURI = _context.requestURI this.principal = _context.principal @@ -68,7 +71,7 @@ class RequestContextWrapper extends AbstractRequestContext { def currentReqId = getAttribute(GServ.contextAttributes.requestId) this.responseBody = _responseBody = new ByteArrayOutputStream() - log.trace("RequestContext(#$currentReqId) ${_context.responseBody} -->> ${this.responseBody}") + log.trace("RequestContext(#$currentReqId) -> $_context ") setAttribute(GServ.contextAttributes.isWrapper, true) } diff --git a/src/main/groovy/io/github/javaconductor/gserv/utils/StaticFilehandler.groovy b/src/main/groovy/io/github/javaconductor/gserv/utils/StaticFilehandler.groovy index 22bbd62..cd43659 100644 --- a/src/main/groovy/io/github/javaconductor/gserv/utils/StaticFilehandler.groovy +++ b/src/main/groovy/io/github/javaconductor/gserv/utils/StaticFilehandler.groovy @@ -62,17 +62,18 @@ class StaticFileHandler { InputStream is = getFile(_staticRoots, filename) if (is) { def sz = is.available(); - exchange.responseHeaders.add("Content-Type", mimeType) - exchange.sendResponseHeaders(200, sz) - IOUtils.copy(is, exchange.responseBody) + requestContext.responseHeaders.add("Content-Type", mimeType) + requestContext.sendResponseHeaders(200, sz) + IOUtils.copy(is, requestContext.responseBody) } else { def msg = "No such file: $filename" def ab = msg.getBytes() - exchange.sendResponseHeaders(404, ab.size()) - exchange.responseBody.write(ab); + requestContext.sendResponseHeaders(404, ab.size()) + requestContext.responseBody.write(ab); } - exchange.responseBody.close() - } + requestContext.responseBody.close() + requestContext.close() + }//fn } /** diff --git a/src/test/groovy/org/groovyrest/gserv/test/FilterMatcherTest.groovy b/src/test/groovy/org/groovyrest/gserv/test/FilterMatcherTest.groovy index 8cdac16..2c7f71e 100644 --- a/src/test/groovy/org/groovyrest/gserv/test/FilterMatcherTest.groovy +++ b/src/test/groovy/org/groovyrest/gserv/test/FilterMatcherTest.groovy @@ -24,7 +24,7 @@ package io.github.javaconductor.gserv.test -import io.github.javaconductor.gserv.FilterMatcher +import io.github.javaconductor.gserv.filters.FilterMatcher import io.github.javaconductor.gserv.Matcher import io.github.javaconductor.gserv.ResourceAction import io.github.javaconductor.gserv.ResourceActionFactory