2
* $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0.1/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java $
4
* $Date: 2009-02-14 18:20:23 +0100 (Sat, 14 Feb 2009) $
6
* ====================================================================
7
* Licensed to the Apache Software Foundation (ASF) under one
8
* or more contributor license agreements. See the NOTICE file
9
* distributed with this work for additional information
10
* regarding copyright ownership. The ASF licenses this file
11
* to you under the Apache License, Version 2.0 (the
12
* "License"); you may not use this file except in compliance
13
* with the License. You may obtain a copy of the License at
15
* http://www.apache.org/licenses/LICENSE-2.0
17
* Unless required by applicable law or agreed to in writing,
18
* software distributed under the License is distributed on an
19
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
* KIND, either express or implied. See the License for the
21
* specific language governing permissions and limitations
23
* ====================================================================
25
* This software consists of voluntary contributions made by many
26
* individuals on behalf of the Apache Software Foundation. For more
27
* information on the Apache Software Foundation, please see
28
* <http://www.apache.org/>.
32
package org.apache.http.impl.nio.codecs;
34
import java.io.IOException;
35
import java.nio.ByteBuffer;
36
import java.nio.channels.FileChannel;
37
import java.nio.channels.ReadableByteChannel;
39
import org.apache.http.impl.io.HttpTransportMetricsImpl;
40
import org.apache.http.nio.FileContentDecoder;
41
import org.apache.http.nio.reactor.SessionInputBuffer;
44
* Content decoder that cuts off after a defined number of bytes. This class
45
* is used to receive content of HTTP messages where the end of the content
46
* entity is determined by the value of the <code>Content-Length header</code>.
47
* Entities transferred using this stream can be maximum {@link Long#MAX_VALUE}
50
* This decoder is optimized to transfer data directly from the underlying
51
* I/O session's channel to a {@link FileChannel}, whenever
52
* possible avoiding intermediate buffering in the session buffer.
55
* @version $Revision: 744538 $
59
public class LengthDelimitedDecoder extends AbstractContentDecoder
60
implements FileContentDecoder {
62
private final long contentLength;
66
public LengthDelimitedDecoder(
67
final ReadableByteChannel channel,
68
final SessionInputBuffer buffer,
69
final HttpTransportMetricsImpl metrics,
71
super(channel, buffer, metrics);
72
if (contentLength < 0) {
73
throw new IllegalArgumentException("Content length may not be negative");
75
this.contentLength = contentLength;
78
public int read(final ByteBuffer dst) throws IOException {
80
throw new IllegalArgumentException("Byte buffer may not be null");
85
int lenRemaining = (int) (this.contentLength - this.len);
88
if (this.buffer.hasData()) {
89
int maxLen = Math.min(lenRemaining, this.buffer.length());
90
bytesRead = this.buffer.read(dst, maxLen);
92
if (dst.remaining() > lenRemaining) {
93
int oldLimit = dst.limit();
94
int newLimit = oldLimit - (dst.remaining() - lenRemaining);
96
bytesRead = this.channel.read(dst);
99
bytesRead = this.channel.read(dst);
102
this.metrics.incrementBytesTransferred(bytesRead);
105
if (bytesRead == -1) {
106
this.completed = true;
109
this.len += bytesRead;
110
if (this.len >= this.contentLength) {
111
this.completed = true;
116
public long transfer(
117
final FileChannel dst,
119
long count) throws IOException {
124
if (this.completed) {
128
int lenRemaining = (int) (this.contentLength - this.len);
131
if (this.buffer.hasData()) {
132
int maxLen = Math.min(lenRemaining, this.buffer.length());
133
dst.position(position);
134
bytesRead = this.buffer.read(dst, maxLen);
136
if (count > lenRemaining) {
137
count = lenRemaining;
139
if (this.channel.isOpen()) {
140
if(dst.size() < position)
141
throw new IOException("FileChannel.size() [" + dst.size() +
142
"] < position [" + position +
143
"]. Please grow the file before writing.");
145
bytesRead = dst.transferFrom(this.channel, position, count);
150
this.metrics.incrementBytesTransferred(bytesRead);
153
if (bytesRead == -1) {
154
this.completed = true;
157
this.len += bytesRead;
158
if (this.len >= this.contentLength) {
159
this.completed = true;
165
public String toString() {
166
StringBuffer buffer = new StringBuffer();
167
buffer.append("[content length: ");
168
buffer.append(this.contentLength);
169
buffer.append("; pos: ");
170
buffer.append(this.len);
171
buffer.append("; completed: ");
172
buffer.append(this.completed);
174
return buffer.toString();