source: trunk/autoquest-httpmonitor/src/main/java/de/ugoe/cs/autoquest/httpmonitor/proxy/HttpMonitoringProxyServlet.java @ 1389

Last change on this file since 1389 was 1389, checked in by pharms, 10 years ago
  • corrected handling of context paths
File size: 8.7 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.httpmonitor.proxy;
16
17import java.io.IOException;
18import java.net.URI;
19import java.net.URISyntaxException;
20import java.nio.ByteBuffer;
21import java.util.Iterator;
22
23import javax.servlet.http.HttpServletRequest;
24import javax.servlet.http.HttpServletResponse;
25
26import org.eclipse.jetty.client.api.ContentProvider;
27import org.eclipse.jetty.client.api.Request;
28import org.eclipse.jetty.client.api.Response;
29import org.eclipse.jetty.proxy.ProxyServlet;
30
31import de.ugoe.cs.autoquest.httpmonitor.exchange.Status;
32import de.ugoe.cs.util.console.Console;
33
34/**
35 * <p>
36 * the servlet deployed in the web server of the proxy that proxies all incoming messages and
37 * forwards a copy of recorded exchanges to the exchange listener manager. It is based on the
38 * proxy servlet provided by jetty. It extends the servlet and implements all hooks required to
39 * get access to the exchanged requests and responses. Each hook forwards the tracked data to the
40 * exchange listener. On exchange completion, the exchange listener ensures a logging of the
41 * recorded exchange.
42 * </p>
43 *
44 * @author Patrick Harms
45 */
46class HttpMonitoringProxyServlet extends ProxyServlet {
47
48    /**  */
49    private static final long serialVersionUID = 1L;
50
51    /**
52     * the proxied server
53     */
54    private String proxiedServer;
55   
56    /**
57     * the port of the proxied server
58     */
59    private int proxiedPort;
60
61    /**
62     * the exchange listener to handle the different events happening when an exchange is proxied
63     */
64    private transient ExchangeListenerManager exchangeListenerManager;
65   
66    /**
67     * <p>
68     * initializes the servlet with the proxied server and the exchange listener
69     * </p>
70     *
71     * @param proxiedServer           the proxied server
72     * @param proxiedPort             the port of the proxied server
73     * @param exchangeListenerManager the exchange listener to handle the different events
74     *                                happening when an exchange is proxied
75     */
76    HttpMonitoringProxyServlet(String                  proxiedServer,
77                               int                     proxiedPort,
78                               ExchangeListenerManager exchangeListenerManager)
79    {
80        this.proxiedServer = proxiedServer;
81        this.proxiedPort = proxiedPort;
82        this.exchangeListenerManager = exchangeListenerManager;
83    }
84
85    /* (non-Javadoc)
86     * @see org.eclipse.jetty.proxy.ProxyServlet#rewriteURI(HttpServletRequest)
87     */
88    @Override
89    protected URI rewriteURI(HttpServletRequest request) {
90        try {
91            return new URI(request.getScheme(), null, proxiedServer, proxiedPort,
92                           request.getPathInfo(), request.getQueryString(), null);
93        }
94        catch (URISyntaxException e) {
95            Console.printerrln("could not rewrite URI: " + e);
96            Console.logException(e);
97            return null;
98        }
99    }
100
101    /* (non-Javadoc)
102     * @see org.eclipse.jetty.proxy.ProxyServlet#customizeProxyRequest(Request, HttpServletRequest)
103     */
104    @Override
105    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) {
106        super.customizeProxyRequest(proxyRequest, request);
107       
108        exchangeListenerManager.onRequest(request);
109        proxyRequest.content(new DubbingContentProvider(request, proxyRequest.getContent()));
110    }
111
112    /* (non-Javadoc)
113     * @see ProxyServlet#onResponseContent(HttpServletRequest, HttpServletResponse, Response, byte[], int, int)
114     */
115    @Override
116    protected void onResponseContent(HttpServletRequest  request,
117                                     HttpServletResponse response,
118                                     Response            proxyResponse,
119                                     byte[]              buffer,
120                                     int                 offset,
121                                     int                 length)
122        throws IOException
123    {
124        super.onResponseContent(request, response, proxyResponse, buffer, offset, length);
125       
126        exchangeListenerManager.onResponseContent(request, ByteBuffer.wrap(buffer, offset, length));
127    }
128
129    /* (non-Javadoc)
130     * @see ProxyServlet#onResponseSuccess(HttpServletRequest, HttpServletResponse, Response)
131     */
132    @Override
133    protected void onResponseSuccess(HttpServletRequest  request,
134                                     HttpServletResponse response,
135                                     Response            proxyResponse)
136    {
137        exchangeListenerManager.onResponse(request, response);
138        exchangeListenerManager.onFinish(request, Status.SUCCESS);
139       
140        super.onResponseSuccess(request, response, proxyResponse);
141    }
142
143    /* (non-Javadoc)
144     * @see ProxyServlet#onResponseFailure(HttpServletRequest, HttpServletResponse, Response, Throwable)
145     */
146    @Override
147    protected void onResponseFailure(HttpServletRequest  request,
148                                     HttpServletResponse response,
149                                     Response            proxyResponse,
150                                     Throwable           failure)
151    {
152        exchangeListenerManager.onResponse(request, response);
153        exchangeListenerManager.onFinish(request, Status.FAILURE);
154       
155        super.onResponseFailure(request, response, proxyResponse, failure);
156    }
157
158    /**
159     * This content provided is required to copy the content of a proxied request. It uses
160     * delegation to wrap the original content provided but to also copy the data and forward
161     * it to the exchange listener manager.
162     */
163    private class DubbingContentProvider implements ContentProvider {
164
165        /**
166         * the dubbed request
167         */
168        private HttpServletRequest request;
169       
170        /**
171         * the original content provider of which the data is copied
172         */
173        private ContentProvider delegate;
174
175        /**
176         * initializes this content provider with the copied request and the delegate.
177         */
178        public DubbingContentProvider(HttpServletRequest request, ContentProvider delegate) {
179            this.request = request;
180            this.delegate = delegate;
181        }
182
183        /* (non-Javadoc)
184         * @see java.lang.Iterable#iterator()
185         */
186        @Override
187        public Iterator<ByteBuffer> iterator() {
188            return new DubbingByteBufferIterator(request, delegate.iterator());
189        }
190
191        /* (non-Javadoc)
192         * @see org.eclipse.jetty.client.api.ContentProvider#getLength()
193         */
194        @Override
195        public long getLength() {
196            return delegate.getLength();
197        }
198
199    }
200
201    /**
202     * This iterator is used to implement the {@link DubbingContentProvider}. It works in the
203     * same manner and uses delegation for wrapping the original iterator and forwards all copied
204     * data to the exchange listener manager.
205     */
206    public class DubbingByteBufferIterator implements Iterator<ByteBuffer> {
207
208        /**
209         * the dubbed request
210         */
211        private HttpServletRequest request;
212       
213        /**
214         * the original iterator of which the data is copied
215         */
216        private Iterator<ByteBuffer> delegate;
217       
218        /**
219         * initializes this iterator with the copied request and the delegate.
220         */
221        public DubbingByteBufferIterator(HttpServletRequest request, Iterator<ByteBuffer> delegate) {
222            this.request = request;
223            this.delegate = delegate;
224        }
225
226        /* (non-Javadoc)
227         * @see java.util.Iterator#hasNext()
228         */
229        @Override
230        public boolean hasNext() {
231            return delegate.hasNext();
232        }
233
234        /* (non-Javadoc)
235         * @see java.util.Iterator#next()
236         */
237        @Override
238        public ByteBuffer next() {
239            ByteBuffer next = delegate.next();
240            exchangeListenerManager.onRequestContent(request, next.duplicate());
241            return next;
242        }
243
244        /* (non-Javadoc)
245         * @see java.util.Iterator#remove()
246         */
247        @Override
248        public void remove() {
249            delegate.remove();
250        }
251
252    }
253
254}
Note: See TracBrowser for help on using the repository browser.