/* * This file is part of the OWASP Proxy, a free intercepting proxy library. * Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to: * The Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.owasp.proxy.http.server; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.net.InetAddress; import org.owasp.proxy.http.BufferedRequest; import org.owasp.proxy.http.MessageFormatException; import org.owasp.proxy.http.MessageUtils; import org.owasp.proxy.http.MutableBufferedRequest; import org.owasp.proxy.http.MutableBufferedResponse; import org.owasp.proxy.http.RequestHeader; import org.owasp.proxy.http.StreamingRequest; import org.owasp.proxy.http.StreamingResponse; import org.owasp.proxy.http.server.BufferedMessageInterceptor.Action; import org.owasp.proxy.io.CountingInputStream; import org.owasp.proxy.io.SizeLimitExceededException; import org.owasp.proxy.util.AsciiString; public class BufferingHttpRequestHandler implements HttpRequestHandler { private static final byte[] CONTINUE = AsciiString .getBytes("HTTP/1.1 100 Continue\r\n\r\n"); private final HttpRequestHandler next; protected int max = 0; private BufferedMessageInterceptor interceptor; public BufferingHttpRequestHandler(final HttpRequestHandler next, BufferedMessageInterceptor interceptor) { this.next = next; this.interceptor = interceptor; } public BufferingHttpRequestHandler(final HttpRequestHandler next, BufferedMessageInterceptor interceptor, final int max) { this.next = next; this.interceptor = interceptor; this.max = max; } public void setMaximumContentSize(int max) { this.max = max; } /* * (non-Javadoc) * * @see org.owasp.proxy.daemon.HttpRequestHandler#dispose() */ public final void dispose() throws IOException { next.dispose(); } private BufferedRequest handleRequest(StreamingRequest request) throws IOException, MessageFormatException { final Action action = interceptor.directRequest(request); final MutableBufferedRequest brq; if (Action.BUFFER.equals(action)) { brq = new MutableBufferedRequest.Impl(); try { MessageUtils.buffer(request, brq, max); interceptor.processRequest(brq); MessageUtils.stream(brq, request); } catch (SizeLimitExceededException slee) { final InputStream buffered = new ByteArrayInputStream(brq .getContent()); InputStream content = request.getContent(); content = new SequenceInputStream(buffered, content); content = new CountingInputStream(content) { protected void eof() { interceptor.requestContentSizeExceeded(brq, getCount()); } }; request.setContent(content); } } else if (Action.STREAM.equals(action)) { brq = new MutableBufferedRequest.Impl(); MessageUtils.delayedCopy(request, brq, max, new MessageUtils.DelayedCopyObserver() { @Override public void copyCompleted(boolean overflow, int size) { if (overflow) { interceptor.requestContentSizeExceeded(brq, size); } else { interceptor.requestStreamed(brq); } } }); } else { brq = null; } return brq; } private void handleResponse(final BufferedRequest request, final StreamingResponse response) throws IOException, MessageFormatException { Action action = interceptor.directResponse(request, response); final MutableBufferedResponse brs; if (Action.BUFFER.equals(action)) { brs = new MutableBufferedResponse.Impl(); try { MessageUtils.buffer(response, brs, max); interceptor.processResponse(request, brs); new String(brs.getDecodedContent(), "utf-8"); MessageUtils.stream(brs, response); } catch (SizeLimitExceededException slee) { InputStream buffered = new ByteArrayInputStream(brs .getContent()); InputStream content = response.getContent(); content = new SequenceInputStream(buffered, content); content = new CountingInputStream(content) { protected void eof() { interceptor.responseContentSizeExceeded(request, brs, getCount()); } }; response.setContent(content); } } else if (Action.STREAM.equals(action)) { brs = new MutableBufferedResponse.Impl(); MessageUtils.delayedCopy(response, brs, max, new MessageUtils.DelayedCopyObserver() { @Override public void copyCompleted(boolean overflow, int size) { if (overflow) { interceptor.responseContentSizeExceeded( request, brs, size); } else { interceptor.responseStreamed(request, brs); } } }); } } /* * (non-Javadoc) * * @see org.owasp.proxy.daemon.HttpRequestHandler#handleRequest(java.net.InetAddress , * org.owasp.httpclient.StreamingRequest) */ final public StreamingResponse handleRequest(final InetAddress source, final StreamingRequest request, boolean isContinue) throws IOException, MessageFormatException { if (!isContinue && isExpectContinue(request)) { return get100Continue(); } BufferedRequest brq = handleRequest(request); isContinue = false; StreamingResponse response = null; if (isExpectContinue(request)) { StreamingRequest cont = new StreamingRequest.Impl(request); response = next.handleRequest(source, cont, false); isContinue = isContinue(response); if (!isContinue) { return response; } } response = next.handleRequest(source, request, isContinue); if (brq != null) handleResponse(brq, response); return response; } private boolean isExpectContinue(final RequestHeader request) throws MessageFormatException { return "100-continue".equalsIgnoreCase(request.getHeader("Expect")); } private boolean isContinue(StreamingResponse response) throws MessageFormatException { return "100".equals(response.getStatus()); } private StreamingResponse get100Continue() { StreamingResponse response = new StreamingResponse.Impl(); response.setHeader(CONTINUE); return response; } }