// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed 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 de.ugoe.cs.autoquest.httpmonitor.proxy; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler; import de.ugoe.cs.autoquest.httpmonitor.exchange.Address; import de.ugoe.cs.autoquest.httpmonitor.exchange.Content; import de.ugoe.cs.autoquest.httpmonitor.exchange.Cookie; import de.ugoe.cs.autoquest.httpmonitor.exchange.Cookies; import de.ugoe.cs.autoquest.httpmonitor.exchange.Header; import de.ugoe.cs.autoquest.httpmonitor.exchange.Headers; import de.ugoe.cs.autoquest.httpmonitor.exchange.HttpExchange; import de.ugoe.cs.autoquest.httpmonitor.exchange.HttpRequest; import de.ugoe.cs.autoquest.httpmonitor.exchange.HttpResponse; import de.ugoe.cs.autoquest.httpmonitor.exchange.Method; import de.ugoe.cs.autoquest.httpmonitor.exchange.ObjectFactory; import de.ugoe.cs.autoquest.httpmonitor.exchange.Protocol; import de.ugoe.cs.autoquest.httpmonitor.exchange.Status; import de.ugoe.cs.util.console.Console; /** *
* recording an exchange can not be done in one step. This is due to the fact, that the proxy * servlet notifies different processing states for requests and response. An exchange listener * records all these event. On the occurrence of the final event, it compiles an * {@link HttpExchange} and forwards it to the exchange handler. *
* * @author Patrick Harms */ class ExchangeListener { /** ** the exchange handler to forward compiles exchanges to *
*/ private HttpMonitorExchangeHandler exchangeHandler; /** ** the request of compiled exchange *
*/ private HttpServletRequest request; /** ** the content of the request of compiled exchange *
*/ private List* the response of compiled exchange *
*/ private HttpServletResponse response; /** ** the content of the response of compiled exchange *
*/ private List* the last time an event for the exchange was received (used for supporting timeouts) *
*/ private long lastUpdate = System.currentTimeMillis(); /** ** initialized the exchange listener with the exchange handler to forward compiled exchanges to *
* * @param exchangeHandler the exchange handler to forward compiled exchanges to */ ExchangeListener(HttpMonitorExchangeHandler exchangeHandler) { this.exchangeHandler = exchangeHandler; } /** ** called, when the request was received by the proxy *
* * @param request the request of the exchange */ public void onRequest(HttpServletRequest request) throws IllegalStateException { Console.traceln(Level.FINEST, this + ": onRequest " + request); if (request == null) { throw new IllegalArgumentException("request must not be null"); } lastUpdate = System.currentTimeMillis(); this.request = request; } /** ** called, when some content of the request was processed by the proxy *
* * @param data the processed content of the request of the exchange */ public void onRequestContent(ByteBuffer data) { Console.traceln(Level.FINEST, this + ": onRequestContent " + data); if (data == null) { throw new IllegalArgumentException("data must not be null"); } lastUpdate = System.currentTimeMillis(); requestData.add(data); } /** ** called, when the response is to be returned by the proxy *
* * @param response the response of the exchange */ public void onResponse(HttpServletResponse response) { Console.traceln(Level.FINEST, this + ": onResponse " + response); if (response == null) { throw new IllegalArgumentException("response must not be null"); } lastUpdate = System.currentTimeMillis(); this.response = response; } /** ** called, when some content of the response was processed by the proxy *
* * @param data the processed content of the response of the exchange */ public void onResponseContent(ByteBuffer data) { Console.traceln(Level.FINEST, this + ": onResponseContent " + data); if (data == null) { throw new IllegalArgumentException("data must not be null"); } lastUpdate = System.currentTimeMillis(); responseData.add(data); } /** ** called, when proxy finished proxying a request *
* * @param status the status of the proxying after finalization */ public void onFinish(Status status) { Console.traceln(Level.FINEST, this + ": onFinish " + status); if (status == null) { throw new IllegalArgumentException("status must not be null"); } lastUpdate = System.currentTimeMillis(); sendToExchangeHandler(status); } /** * @return the request of the exchange */ HttpServletRequest getRequest() { return request; } /** * @return the last time this listener received an event */ long getLastUpdate() { return lastUpdate; } /** ** convenience method to compile an {@link HttpExchange} and send it to the exchange handler * after finalization of the exchange. *
* * @param status the status of the proxying after finalization */ private void sendToExchangeHandler(Status status) { ObjectFactory eventObjectFactory = new ObjectFactory(); HttpExchange exchange = eventObjectFactory.createHttpExchange(); exchange.setStatus(status); // the remote address Address address = eventObjectFactory.createAddress(); address.setIp(request.getRemoteAddr()); address.setHost(request.getRemoteHost()); address.setPort(BigInteger.valueOf(request.getRemotePort())); exchange.setSender(address); // the local address address = eventObjectFactory.createAddress(); address.setIp(request.getLocalAddr()); address.setHost(request.getLocalName()); address.setPort(BigInteger.valueOf(request.getLocalPort())); exchange.setReceiver(address); exchange.setRequest(map(request, eventObjectFactory)); exchange.setResponse(map(response, eventObjectFactory)); exchangeHandler.handleHttpExchange(exchange); } /** ** convenience method to map an {@link HttpServletRequest} to an {@link HttpRequest} *
*/ private HttpRequest map(HttpServletRequest request, ObjectFactory eventObjectFactory) { HttpRequest eventRequest = eventObjectFactory.createHttpRequest(); eventRequest.setMethod(Method.fromValue(request.getMethod())); eventRequest.setProtocol(Protocol.fromValue(request.getProtocol())); eventRequest.setUrl(request.getRequestURL().toString()); eventRequest.setQuery(request.getQueryString()); Headers headers = eventObjectFactory.createHeaders(); Enumeration* convenience method to map an {@link HttpServletResponse} to an {@link HttpResponse} *
*/ private HttpResponse map(HttpServletResponse response, ObjectFactory eventObjectFactory) { HttpResponse eventResponse = eventObjectFactory.createHttpResponse(); eventResponse.setStatus(BigInteger.valueOf(response.getStatus())); Headers headers = eventObjectFactory.createHeaders(); Collection* convenience method to create a string out of recorded request or response content *
*/ private String createString(List