io.milton.http.HttpManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of milton-server-ce Show documentation
Show all versions of milton-server-ce Show documentation
Milton Community Edition: Supports DAV level 1 and is available on Apache2 license
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.milton.http;
import io.milton.common.Stoppable;
import io.milton.common.Utils;
import io.milton.event.EventManager;
import io.milton.event.RequestEvent;
import io.milton.event.ResponseEvent;
import io.milton.http.Request.Method;
import io.milton.http.entity.EntityTransport;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.http11.CustomPostHandler;
import io.milton.http.http11.Http11ResponseHandler;
import io.milton.http.webdav.WebDavResponseHandler;
import io.milton.resource.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Milton's main class. All the servlets and stuff is just fluff, this is where
* stuff really starts to happen
*
* @author brad
*/
public class HttpManager {
private static final Logger log = LoggerFactory.getLogger(HttpManager.class);
private static final ThreadLocal tlRequest = new ThreadLocal<>();
private static final ThreadLocal tlResponse = new ThreadLocal<>();
private static final Map mapOfRequestsByThread = new ConcurrentHashMap<>();
public static RequestInfo getRequestDataForThread(Thread th) {
return mapOfRequestsByThread.get(th);
}
public static String decodeUrl(String s) {
return Utils.decodePath(s);
}
public static Request request() {
return tlRequest.get();
}
public static Response response() {
return tlResponse.get();
}
private final ProtocolHandlers handlers;
private final List filters;
private final List eventListeners = new ArrayList<>();
private final ResourceFactory resourceFactory;
private final Http11ResponseHandler responseHandler;
private final EventManager eventManager;
private final List shutdownHandlers;
private final EntityTransport entityTransport;
private Map methodHandlers;
/**
* Instead of using this constructor directly, consider using the
* HttpManagerConfig builder class
*
* @param resourceFactory
* @param responseHandler
* @param handlers
* @param entityTransport
* @param filters
* @param eventManager
* @param shutdownHandlers
*/
public HttpManager(ResourceFactory resourceFactory, WebDavResponseHandler responseHandler, ProtocolHandlers handlers, EntityTransport entityTransport, List filters, EventManager eventManager, List shutdownHandlers) {
this.responseHandler = responseHandler;
this.handlers = handlers;
this.resourceFactory = resourceFactory;
this.entityTransport = entityTransport;
this.filters = filters;
this.eventManager = eventManager;
this.shutdownHandlers = shutdownHandlers;
initHandlers();
}
private void initHandlers() {
this.methodHandlers = new ConcurrentHashMap<>();
for (HttpExtension ext : handlers) {
for (Handler h : ext.getHandlers()) {
for (String m : h.getMethods()) {
this.methodHandlers.put(m, h);
}
}
}
}
public void sendResponseEntity(Response response) throws Exception {
entityTransport.sendResponseEntity(response);
}
public void closeResponse(Response response) {
entityTransport.closeResponse(response);
}
public Handler getMethodHandler(Request.Method m) {
return methodHandlers.get(m.code);
}
public ResourceFactory getResourceFactory() {
return resourceFactory;
}
public void process(Request request, Response response) {
if (request == null) {
throw new RuntimeException("request is null");
}
String host = request.getHostHeader();
if (host == null) {
host = "";
}
if (log.isInfoEnabled()) {
log.info(request.getMethod() + " :: " + host + "//" + request.getAbsolutePath() + " start");
}
try {
setThreadAffinityData(request, response);
try {
fireRequestEvent(request);
} catch (ConflictException ex) {
responseHandler.respondConflict(null, response, request, null);
} catch (BadRequestException ex) {
responseHandler.respondBadRequest(null, response, request);
} catch (NotAuthorizedException ex) {
responseHandler.respondUnauthorised(null, response, request);
}
FilterChain chain = new FilterChain(this);
long tm = System.currentTimeMillis();
chain.process(request, response);
try {
tm = System.currentTimeMillis() - tm;
if (log.isInfoEnabled()) {
log.info(request.getMethod() + " :: " + host + "//" + request.getAbsolutePath() + " finished " + tm + "ms, Status:" + response.getStatus() + ", Length:" + response.getContentLength());
}
fireResponseEvent(request, response, tm);
} catch (ConflictException | NotAuthorizedException | BadRequestException ex) {
log.warn("exception thrown from event handler after response is complete", ex);
}
} finally {
clearThreadAffinity();
}
}
private void clearThreadAffinity() {
tlRequest.remove();
tlResponse.remove();
try {
mapOfRequestsByThread.remove(Thread.currentThread());
} catch (Throwable e) {
log.info("Couldnt clear thread affinity request data");
}
}
private void setThreadAffinityData(Request request, Response response) {
tlRequest.set(request);
tlResponse.set(response);
try {
RequestInfo info = new RequestInfo(request.getMethod(), request.getAbsoluteUrl(), new Date());
mapOfRequestsByThread.put(Thread.currentThread(), info);
} catch (Throwable e) {
log.info("Couldnt set thread affinity request data");
}
}
public void addEventListener(EventListener l) {
eventListeners.add(l);
}
public void removeEventListener(EventListener l) {
eventListeners.remove(l);
}
public void onProcessResourceFinish(Request request, Response response, Resource resource, long duration) {
for (EventListener l : eventListeners) {
l.onProcessResourceFinish(request, response, resource, duration);
}
}
public void onProcessResourceStart(Request request, Response response, Resource resource) {
for (EventListener l : eventListeners) {
l.onProcessResourceStart(request, response, resource);
}
}
public void onPost(Request request, Response response, Resource resource, Map params, Map files) {
for (EventListener l : eventListeners) {
l.onPost(request, response, resource, params, files);
}
}
public void onGet(Request request, Response response, Resource resource, Map params) {
for (EventListener l : eventListeners) {
l.onGet(request, response, resource, params);
}
}
public List getFilters() {
return new ArrayList(filters);
}
public Collection getAllHandlers() {
return this.methodHandlers.values();
}
public Http11ResponseHandler getResponseHandler() {
return responseHandler;
}
public ProtocolHandlers getHandlers() {
return handlers;
}
public boolean isEnableExpectContinue() {
return handlers.isEnableExpectContinue();
}
public void setEnableExpectContinue(boolean enableExpectContinue) {
handlers.setEnableExpectContinue(enableExpectContinue);
}
public EventManager getEventManager() {
return eventManager;
}
private void fireRequestEvent(Request request) throws ConflictException, BadRequestException, NotAuthorizedException {
if (eventManager == null) {
return;
}
eventManager.fireEvent(new RequestEvent(request));
}
private void fireResponseEvent(Request request, Response response, long duration) throws ConflictException, BadRequestException, NotAuthorizedException {
if (eventManager == null) {
return;
}
eventManager.fireEvent(new ResponseEvent(request, response, duration));
}
public List getCustomPostHandlers() {
List list = new ArrayList<>();
for (HttpExtension p : this.handlers) {
if (p.getCustomPostHandlers() != null) {
list.addAll(p.getCustomPostHandlers());
}
}
return list;
}
public final void shutdown() {
for (Stoppable stoppable : shutdownHandlers) {
try {
stoppable.stop();
} catch (Throwable e) {
log.warn("Exception stopping: " + stoppable.getClass(), e);
}
}
}
public EntityTransport getEntityTransport() {
return entityTransport;
}
public static class RequestInfo {
private final Method method;
private final String url;
private final Date started;
public RequestInfo(Method method, String url, Date started) {
this.method = method;
this.url = url;
this.started = started;
}
public Method getMethod() {
return method;
}
public Date getStarted() {
return started;
}
public String getUrl() {
return url;
}
public long getDurationMillis() {
return System.currentTimeMillis() - started.getTime();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy