001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl;
029
030import java.io.IOException;
031import java.io.OutputStream;
032import java.net.Socket;
033import java.nio.charset.CharsetDecoder;
034import java.nio.charset.CharsetEncoder;
035
036import org.apache.http.HttpEntity;
037import org.apache.http.HttpEntityEnclosingRequest;
038import org.apache.http.HttpException;
039import org.apache.http.HttpRequest;
040import org.apache.http.HttpResponse;
041import org.apache.http.HttpServerConnection;
042import org.apache.http.config.MessageConstraints;
043import org.apache.http.entity.ContentLengthStrategy;
044import org.apache.http.impl.entity.DisallowIdentityContentLengthStrategy;
045import org.apache.http.impl.io.DefaultHttpRequestParserFactory;
046import org.apache.http.impl.io.DefaultHttpResponseWriterFactory;
047import org.apache.http.io.HttpMessageParser;
048import org.apache.http.io.HttpMessageParserFactory;
049import org.apache.http.io.HttpMessageWriter;
050import org.apache.http.io.HttpMessageWriterFactory;
051import org.apache.http.util.Args;
052
053/**
054 * Default implementation of {@link HttpServerConnection}.
055 *
056 * @since 4.3
057 */
058public class DefaultBHttpServerConnection extends BHttpConnectionBase implements HttpServerConnection {
059
060    private final HttpMessageParser<HttpRequest> requestParser;
061    private final HttpMessageWriter<HttpResponse> responseWriter;
062
063    /**
064     * Creates new instance of DefaultBHttpServerConnection.
065     *
066     * @param buffersize buffer size. Must be a positive number.
067     * @param fragmentSizeHint fragment size hint.
068     * @param chardecoder decoder to be used for decoding HTTP protocol elements.
069     *   If {@code null} simple type cast will be used for byte to char conversion.
070     * @param charencoder encoder to be used for encoding HTTP protocol elements.
071     *   If {@code null} simple type cast will be used for char to byte conversion.
072     * @param constraints Message constraints. If {@code null}
073     *   {@link MessageConstraints#DEFAULT} will be used.
074     * @param incomingContentStrategy incoming content length strategy. If {@code null}
075     *   {@link DisallowIdentityContentLengthStrategy#INSTANCE} will be used.
076     * @param outgoingContentStrategy outgoing content length strategy. If {@code null}
077     *   {@link org.apache.http.impl.entity.StrictContentLengthStrategy#INSTANCE} will be used.
078     * @param requestParserFactory request parser factory. If {@code null}
079     *   {@link DefaultHttpRequestParserFactory#INSTANCE} will be used.
080     * @param responseWriterFactory response writer factory. If {@code null}
081     *   {@link DefaultHttpResponseWriterFactory#INSTANCE} will be used.
082     */
083    public DefaultBHttpServerConnection(
084            final int buffersize,
085            final int fragmentSizeHint,
086            final CharsetDecoder chardecoder,
087            final CharsetEncoder charencoder,
088            final MessageConstraints constraints,
089            final ContentLengthStrategy incomingContentStrategy,
090            final ContentLengthStrategy outgoingContentStrategy,
091            final HttpMessageParserFactory<HttpRequest> requestParserFactory,
092            final HttpMessageWriterFactory<HttpResponse> responseWriterFactory) {
093        super(buffersize, fragmentSizeHint, chardecoder, charencoder, constraints,
094                incomingContentStrategy != null ? incomingContentStrategy :
095                    DisallowIdentityContentLengthStrategy.INSTANCE, outgoingContentStrategy);
096        this.requestParser = (requestParserFactory != null ? requestParserFactory :
097            DefaultHttpRequestParserFactory.INSTANCE).create(getSessionInputBuffer(), constraints);
098        this.responseWriter = (responseWriterFactory != null ? responseWriterFactory :
099            DefaultHttpResponseWriterFactory.INSTANCE).create(getSessionOutputBuffer());
100    }
101
102    public DefaultBHttpServerConnection(
103            final int buffersize,
104            final CharsetDecoder chardecoder,
105            final CharsetEncoder charencoder,
106            final MessageConstraints constraints) {
107        this(buffersize, buffersize, chardecoder, charencoder, constraints, null, null, null, null);
108    }
109
110    public DefaultBHttpServerConnection(final int buffersize) {
111        this(buffersize, buffersize, null, null, null, null, null, null, null);
112    }
113
114    protected void onRequestReceived(final HttpRequest request) {
115    }
116
117    protected void onResponseSubmitted(final HttpResponse response) {
118    }
119
120    @Override
121    public void bind(final Socket socket) throws IOException {
122        super.bind(socket);
123    }
124
125    @Override
126    public HttpRequest receiveRequestHeader()
127            throws HttpException, IOException {
128        ensureOpen();
129        final HttpRequest request = this.requestParser.parse();
130        onRequestReceived(request);
131        incrementRequestCount();
132        return request;
133    }
134
135    @Override
136    public void receiveRequestEntity(final HttpEntityEnclosingRequest request)
137            throws HttpException, IOException {
138        Args.notNull(request, "HTTP request");
139        ensureOpen();
140        final HttpEntity entity = prepareInput(request);
141        request.setEntity(entity);
142    }
143
144    @Override
145    public void sendResponseHeader(final HttpResponse response)
146            throws HttpException, IOException {
147        Args.notNull(response, "HTTP response");
148        ensureOpen();
149        this.responseWriter.write(response);
150        onResponseSubmitted(response);
151        if (response.getStatusLine().getStatusCode() >= 200) {
152            incrementResponseCount();
153        }
154    }
155
156    @Override
157    public void sendResponseEntity(final HttpResponse response)
158            throws HttpException, IOException {
159        Args.notNull(response, "HTTP response");
160        ensureOpen();
161        final HttpEntity entity = response.getEntity();
162        if (entity == null) {
163            return;
164        }
165        final OutputStream outstream = prepareOutput(response);
166        entity.writeTo(outstream);
167        outstream.close();
168    }
169
170    @Override
171    public void flush() throws IOException {
172        ensureOpen();
173        doFlush();
174    }
175
176}