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.net.SocketTimeoutException;
034import java.nio.charset.CharsetDecoder;
035import java.nio.charset.CharsetEncoder;
036
037import org.apache.http.HttpClientConnection;
038import org.apache.http.HttpEntity;
039import org.apache.http.HttpEntityEnclosingRequest;
040import org.apache.http.HttpException;
041import org.apache.http.HttpRequest;
042import org.apache.http.HttpResponse;
043import org.apache.http.HttpStatus;
044import org.apache.http.config.MessageConstraints;
045import org.apache.http.entity.ContentLengthStrategy;
046import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
047import org.apache.http.impl.io.DefaultHttpResponseParserFactory;
048import org.apache.http.io.HttpMessageParser;
049import org.apache.http.io.HttpMessageParserFactory;
050import org.apache.http.io.HttpMessageWriter;
051import org.apache.http.io.HttpMessageWriterFactory;
052import org.apache.http.util.Args;
053
054/**
055 * Default implementation of {@link HttpClientConnection}.
056 *
057 * @since 4.3
058 */
059public class DefaultBHttpClientConnection extends BHttpConnectionBase
060                                                   implements HttpClientConnection {
061
062    private final HttpMessageParser<HttpResponse> responseParser;
063    private final HttpMessageWriter<HttpRequest> requestWriter;
064
065    /**
066     * Creates new instance of DefaultBHttpClientConnection.
067     *
068     * @param buffersize buffer size. Must be a positive number.
069     * @param fragmentSizeHint fragment size hint.
070     * @param chardecoder decoder to be used for decoding HTTP protocol elements.
071     *   If {@code null} simple type cast will be used for byte to char conversion.
072     * @param charencoder encoder to be used for encoding HTTP protocol elements.
073     *   If {@code null} simple type cast will be used for char to byte conversion.
074     * @param constraints Message constraints. If {@code null}
075     *   {@link MessageConstraints#DEFAULT} will be used.
076     * @param incomingContentStrategy incoming content length strategy. If {@code null}
077     *   {@link org.apache.http.impl.entity.LaxContentLengthStrategy#INSTANCE} will be used.
078     * @param outgoingContentStrategy outgoing content length strategy. If {@code null}
079     *   {@link org.apache.http.impl.entity.StrictContentLengthStrategy#INSTANCE} will be used.
080     * @param requestWriterFactory request writer factory. If {@code null}
081     *   {@link DefaultHttpRequestWriterFactory#INSTANCE} will be used.
082     * @param responseParserFactory response parser factory. If {@code null}
083     *   {@link DefaultHttpResponseParserFactory#INSTANCE} will be used.
084     */
085    public DefaultBHttpClientConnection(
086            final int buffersize,
087            final int fragmentSizeHint,
088            final CharsetDecoder chardecoder,
089            final CharsetEncoder charencoder,
090            final MessageConstraints constraints,
091            final ContentLengthStrategy incomingContentStrategy,
092            final ContentLengthStrategy outgoingContentStrategy,
093            final HttpMessageWriterFactory<HttpRequest> requestWriterFactory,
094            final HttpMessageParserFactory<HttpResponse> responseParserFactory) {
095        super(buffersize, fragmentSizeHint, chardecoder, charencoder,
096                constraints, incomingContentStrategy, outgoingContentStrategy);
097        this.requestWriter = (requestWriterFactory != null ? requestWriterFactory :
098            DefaultHttpRequestWriterFactory.INSTANCE).create(getSessionOutputBuffer());
099        this.responseParser = (responseParserFactory != null ? responseParserFactory :
100            DefaultHttpResponseParserFactory.INSTANCE).create(getSessionInputBuffer(), constraints);
101    }
102
103    public DefaultBHttpClientConnection(
104            final int buffersize,
105            final CharsetDecoder chardecoder,
106            final CharsetEncoder charencoder,
107            final MessageConstraints constraints) {
108        this(buffersize, buffersize, chardecoder, charencoder, constraints, null, null, null, null);
109    }
110
111    public DefaultBHttpClientConnection(final int buffersize) {
112        this(buffersize, buffersize, null, null, null, null, null, null, null);
113    }
114
115    protected void onResponseReceived(final HttpResponse response) {
116    }
117
118    protected void onRequestSubmitted(final HttpRequest request) {
119    }
120
121    @Override
122    public void bind(final Socket socket) throws IOException {
123        super.bind(socket);
124    }
125
126    @Override
127    public boolean isResponseAvailable(final int timeout) throws IOException {
128        ensureOpen();
129        try {
130            return awaitInput(timeout);
131        } catch (final SocketTimeoutException ex) {
132            return false;
133        }
134    }
135
136    @Override
137    public void sendRequestHeader(final HttpRequest request)
138            throws HttpException, IOException {
139        Args.notNull(request, "HTTP request");
140        ensureOpen();
141        this.requestWriter.write(request);
142        onRequestSubmitted(request);
143        incrementRequestCount();
144    }
145
146    @Override
147    public void sendRequestEntity(final HttpEntityEnclosingRequest request)
148            throws HttpException, IOException {
149        Args.notNull(request, "HTTP request");
150        ensureOpen();
151        final HttpEntity entity = request.getEntity();
152        if (entity == null) {
153            return;
154        }
155        final OutputStream outstream = prepareOutput(request);
156        entity.writeTo(outstream);
157        outstream.close();
158    }
159
160    @Override
161    public HttpResponse receiveResponseHeader() throws HttpException, IOException {
162        ensureOpen();
163        final HttpResponse response = this.responseParser.parse();
164        onResponseReceived(response);
165        if (response.getStatusLine().getStatusCode() >= HttpStatus.SC_OK) {
166            incrementResponseCount();
167        }
168        return response;
169    }
170
171    @Override
172    public void receiveResponseEntity(
173            final HttpResponse response) throws HttpException, IOException {
174        Args.notNull(response, "HTTP response");
175        ensureOpen();
176        final HttpEntity entity = prepareInput(response);
177        response.setEntity(entity);
178    }
179
180    @Override
181    public void flush() throws IOException {
182        ensureOpen();
183        doFlush();
184    }
185
186}