1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.nio.codecs;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.FileChannel;
33 import java.nio.channels.WritableByteChannel;
34
35 import org.apache.http.annotation.NotThreadSafe;
36 import org.apache.http.impl.io.HttpTransportMetricsImpl;
37 import org.apache.http.nio.FileContentEncoder;
38 import org.apache.http.nio.reactor.SessionOutputBuffer;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 @NotThreadSafe
54 public class LengthDelimitedEncoder extends AbstractContentEncoder
55 implements FileContentEncoder {
56
57 private final long contentLength;
58
59 private long len;
60
61 public LengthDelimitedEncoder(
62 final WritableByteChannel channel,
63 final SessionOutputBuffer buffer,
64 final HttpTransportMetricsImpl metrics,
65 long contentLength) {
66 super(channel, buffer, metrics);
67 if (contentLength < 0) {
68 throw new IllegalArgumentException("Content length may not be negative");
69 }
70 this.contentLength = contentLength;
71 this.len = 0;
72 }
73
74 public int write(final ByteBuffer src) throws IOException {
75 if (src == null) {
76 return 0;
77 }
78 assertNotCompleted();
79 int chunk = (int) Math.min((this.contentLength - this.len), Integer.MAX_VALUE);
80
81 int bytesWritten;
82 if (src.remaining() > chunk) {
83 int oldLimit = src.limit();
84 int newLimit = oldLimit - (src.remaining() - chunk);
85 src.limit(newLimit);
86 bytesWritten = this.channel.write(src);
87 src.limit(oldLimit);
88 } else {
89 bytesWritten = this.channel.write(src);
90 }
91 if (bytesWritten > 0) {
92 this.metrics.incrementBytesTransferred(bytesWritten);
93 }
94 this.len += bytesWritten;
95 if (this.len >= this.contentLength) {
96 this.completed = true;
97 }
98 return bytesWritten;
99 }
100
101 public long transfer(
102 final FileChannel src,
103 long position,
104 long count) throws IOException {
105
106 if (src == null) {
107 return 0;
108 }
109 assertNotCompleted();
110 long chunk = Math.min((this.contentLength - this.len), count);
111 long bytesWritten = src.transferTo(position, chunk, this.channel);
112 if (bytesWritten > 0) {
113 this.metrics.incrementBytesTransferred(bytesWritten);
114 }
115 this.len += bytesWritten;
116 if (this.len >= this.contentLength) {
117 this.completed = true;
118 }
119 return bytesWritten;
120 }
121
122 @Override
123 public String toString() {
124 StringBuilder buffer = new StringBuilder();
125 buffer.append("[content length: ");
126 buffer.append(this.contentLength);
127 buffer.append("; pos: ");
128 buffer.append(this.len);
129 buffer.append("; completed: ");
130 buffer.append(this.completed);
131 buffer.append("]");
132 return buffer.toString();
133 }
134
135 }