1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.client.util;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.InputStream;
23 import java.nio.ByteBuffer;
24 import java.nio.charset.Charset;
25 import java.nio.charset.StandardCharsets;
26 import java.util.Locale;
27
28 import org.eclipse.jetty.client.api.Response;
29 import org.eclipse.jetty.client.api.Response.Listener;
30 import org.eclipse.jetty.client.api.Result;
31 import org.eclipse.jetty.http.HttpFields;
32 import org.eclipse.jetty.http.HttpHeader;
33 import org.eclipse.jetty.util.BufferUtil;
34
35
36
37
38
39
40
41 public abstract class BufferingResponseListener extends Listener.Adapter
42 {
43 private final int maxLength;
44 private volatile ByteBuffer buffer;
45 private volatile String mediaType;
46 private volatile String encoding;
47
48
49
50
51 public BufferingResponseListener()
52 {
53 this(2 * 1024 * 1024);
54 }
55
56
57
58
59
60
61 public BufferingResponseListener(int maxLength)
62 {
63 this.maxLength = maxLength;
64 }
65
66 @Override
67 public void onHeaders(Response response)
68 {
69 super.onHeaders(response);
70
71 HttpFields headers = response.getHeaders();
72 long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
73 if (length > maxLength)
74 {
75 response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
76 return;
77 }
78
79 buffer = BufferUtil.allocate(length > 0 ? (int)length : 1024);
80
81 String contentType = headers.get(HttpHeader.CONTENT_TYPE);
82 if (contentType != null)
83 {
84 String media = contentType;
85
86 String charset = "charset=";
87 int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset);
88 if (index > 0)
89 {
90 media = contentType.substring(0, index);
91 String encoding = contentType.substring(index + charset.length());
92
93 int semicolon = encoding.indexOf(';');
94 if (semicolon > 0)
95 encoding = encoding.substring(0, semicolon).trim();
96 this.encoding = encoding;
97 }
98
99 int semicolon = media.indexOf(';');
100 if (semicolon > 0)
101 media = media.substring(0, semicolon).trim();
102 this.mediaType = media;
103 }
104 }
105
106 @Override
107 public void onContent(Response response, ByteBuffer content)
108 {
109 int length = content.remaining();
110 if (length > BufferUtil.space(buffer))
111 {
112 int requiredCapacity = buffer == null ? 0 : buffer.capacity() + length;
113 if (requiredCapacity > maxLength)
114 response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
115
116 int newCapacity = Math.min(Integer.highestOneBit(requiredCapacity) << 1, maxLength);
117 buffer = BufferUtil.ensureCapacity(buffer, newCapacity);
118 }
119 BufferUtil.append(buffer, content);
120 }
121
122 @Override
123 public abstract void onComplete(Result result);
124
125 public String getMediaType()
126 {
127 return mediaType;
128 }
129
130 public String getEncoding()
131 {
132 return encoding;
133 }
134
135
136
137
138
139 public byte[] getContent()
140 {
141 if (buffer == null)
142 return new byte[0];
143 return BufferUtil.toArray(buffer);
144 }
145
146
147
148
149
150
151 public String getContentAsString()
152 {
153 String encoding = this.encoding;
154 if (encoding == null)
155 return getContentAsString(StandardCharsets.UTF_8);
156 return getContentAsString(encoding);
157 }
158
159
160
161
162
163
164 public String getContentAsString(String encoding)
165 {
166 if (buffer == null)
167 return null;
168 return BufferUtil.toString(buffer, Charset.forName(encoding));
169 }
170
171
172
173
174
175
176 public String getContentAsString(Charset encoding)
177 {
178 if (buffer == null)
179 return null;
180 return BufferUtil.toString(buffer, encoding);
181 }
182
183
184
185
186 public InputStream getContentAsInputStream()
187 {
188 if (buffer == null)
189 return new ByteArrayInputStream(new byte[]{});
190 return new ByteArrayInputStream(buffer.array(), buffer.arrayOffset(), buffer.remaining());
191 }
192 }