1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27
28 package org.apache.http.message;
29
30 import org.apache.http.FormattedHeader;
31 import org.apache.http.Header;
32 import org.apache.http.ProtocolVersion;
33 import org.apache.http.RequestLine;
34 import org.apache.http.StatusLine;
35 import org.apache.http.annotation.Immutable;
36 import org.apache.http.util.Args;
37 import org.apache.http.util.CharArrayBuffer;
38
39 /**
40 * Interface for formatting elements of the HEAD section of an HTTP message.
41 * This is the complement to {@link LineParser}.
42 * There are individual methods for formatting a request line, a
43 * status line, or a header line. The formatting does <i>not</i> include the
44 * trailing line break sequence CR-LF.
45 * The formatted lines are returned in memory, the formatter does not depend
46 * on any specific IO mechanism.
47 * Instances of this interface are expected to be stateless and thread-safe.
48 *
49 * @since 4.0
50 */
51 @Immutable
52 public class BasicLineFormatter implements LineFormatter {
53
54 /**
55 * A default instance of this class, for use as default or fallback.
56 * Note that {@link BasicLineFormatter} is not a singleton, there can
57 * be many instances of the class itself and of derived classes.
58 * The instance here provides non-customized, default behavior.
59 *
60 * @deprecated (4.3) use {@link #INSTANCE}
61 */
62 @Deprecated
63 public final static BasicLineFormatter DEFAULT = new BasicLineFormatter();
64
65 public final static BasicLineFormatter INSTANCE = new BasicLineFormatter();
66
67 public BasicLineFormatter() {
68 super();
69 }
70
71 /**
72 * Obtains a buffer for formatting.
73 *
74 * @param buffer a buffer already available, or <code>null</code>
75 *
76 * @return the cleared argument buffer if there is one, or
77 * a new empty buffer that can be used for formatting
78 */
79 protected CharArrayBuffer initBuffer(CharArrayBuffer buffer) {
80 if (buffer != null) {
81 buffer.clear();
82 } else {
83 buffer = new CharArrayBuffer(64);
84 }
85 return buffer;
86 }
87
88
89 /**
90 * Formats a protocol version.
91 *
92 * @param version the protocol version to format
93 * @param formatter the formatter to use, or
94 * <code>null</code> for the
95 * {@link #INSTANCE default}
96 *
97 * @return the formatted protocol version
98 */
99 public final static
100 String formatProtocolVersion(final ProtocolVersion version,
101 LineFormatter formatter) {
102 if (formatter == null) {
103 formatter = BasicLineFormatter.INSTANCE;
104 }
105 return formatter.appendProtocolVersion(null, version).toString();
106 }
107
108
109 // non-javadoc, see interface LineFormatter
110 public CharArrayBuffer appendProtocolVersion(final CharArrayBuffer buffer,
111 final ProtocolVersion version) {
112 Args.notNull(version, "Protocol version");
113 // can't use initBuffer, that would clear the argument!
114 CharArrayBuffer result = buffer;
115 final int len = estimateProtocolVersionLen(version);
116 if (result == null) {
117 result = new CharArrayBuffer(len);
118 } else {
119 result.ensureCapacity(len);
120 }
121
122 result.append(version.getProtocol());
123 result.append('/');
124 result.append(Integer.toString(version.getMajor()));
125 result.append('.');
126 result.append(Integer.toString(version.getMinor()));
127
128 return result;
129 }
130
131
132 /**
133 * Guesses the length of a formatted protocol version.
134 * Needed to guess the length of a formatted request or status line.
135 *
136 * @param version the protocol version to format, or <code>null</code>
137 *
138 * @return the estimated length of the formatted protocol version,
139 * in characters
140 */
141 protected int estimateProtocolVersionLen(final ProtocolVersion version) {
142 return version.getProtocol().length() + 4; // room for "HTTP/1.1"
143 }
144
145
146 /**
147 * Formats a request line.
148 *
149 * @param reqline the request line to format
150 * @param formatter the formatter to use, or
151 * <code>null</code> for the
152 * {@link #INSTANCE default}
153 *
154 * @return the formatted request line
155 */
156 public final static String formatRequestLine(final RequestLine reqline,
157 LineFormatter formatter) {
158 if (formatter == null) {
159 formatter = BasicLineFormatter.INSTANCE;
160 }
161 return formatter.formatRequestLine(null, reqline).toString();
162 }
163
164
165 // non-javadoc, see interface LineFormatter
166 public CharArrayBuffer formatRequestLine(final CharArrayBuffer buffer,
167 final RequestLine reqline) {
168 Args.notNull(reqline, "Request line");
169 final CharArrayBuffer result = initBuffer(buffer);
170 doFormatRequestLine(result, reqline);
171
172 return result;
173 }
174
175
176 /**
177 * Actually formats a request line.
178 * Called from {@link #formatRequestLine}.
179 *
180 * @param buffer the empty buffer into which to format,
181 * never <code>null</code>
182 * @param reqline the request line to format, never <code>null</code>
183 */
184 protected void doFormatRequestLine(final CharArrayBuffer buffer,
185 final RequestLine reqline) {
186 final String method = reqline.getMethod();
187 final String uri = reqline.getUri();
188
189 // room for "GET /index.html HTTP/1.1"
190 final int len = method.length() + 1 + uri.length() + 1 +
191 estimateProtocolVersionLen(reqline.getProtocolVersion());
192 buffer.ensureCapacity(len);
193
194 buffer.append(method);
195 buffer.append(' ');
196 buffer.append(uri);
197 buffer.append(' ');
198 appendProtocolVersion(buffer, reqline.getProtocolVersion());
199 }
200
201
202
203 /**
204 * Formats a status line.
205 *
206 * @param statline the status line to format
207 * @param formatter the formatter to use, or
208 * <code>null</code> for the
209 * {@link #INSTANCE default}
210 *
211 * @return the formatted status line
212 */
213 public final static String formatStatusLine(final StatusLine statline,
214 LineFormatter formatter) {
215 if (formatter == null) {
216 formatter = BasicLineFormatter.INSTANCE;
217 }
218 return formatter.formatStatusLine(null, statline).toString();
219 }
220
221
222 // non-javadoc, see interface LineFormatter
223 public CharArrayBuffer formatStatusLine(final CharArrayBuffer buffer,
224 final StatusLine statline) {
225 Args.notNull(statline, "Status line");
226 final CharArrayBuffer result = initBuffer(buffer);
227 doFormatStatusLine(result, statline);
228
229 return result;
230 }
231
232
233 /**
234 * Actually formats a status line.
235 * Called from {@link #formatStatusLine}.
236 *
237 * @param buffer the empty buffer into which to format,
238 * never <code>null</code>
239 * @param statline the status line to format, never <code>null</code>
240 */
241 protected void doFormatStatusLine(final CharArrayBuffer buffer,
242 final StatusLine statline) {
243
244 int len = estimateProtocolVersionLen(statline.getProtocolVersion())
245 + 1 + 3 + 1; // room for "HTTP/1.1 200 "
246 final String reason = statline.getReasonPhrase();
247 if (reason != null) {
248 len += reason.length();
249 }
250 buffer.ensureCapacity(len);
251
252 appendProtocolVersion(buffer, statline.getProtocolVersion());
253 buffer.append(' ');
254 buffer.append(Integer.toString(statline.getStatusCode()));
255 buffer.append(' '); // keep whitespace even if reason phrase is empty
256 if (reason != null) {
257 buffer.append(reason);
258 }
259 }
260
261
262 /**
263 * Formats a header.
264 *
265 * @param header the header to format
266 * @param formatter the formatter to use, or
267 * <code>null</code> for the
268 * {@link #INSTANCE default}
269 *
270 * @return the formatted header
271 */
272 public final static String formatHeader(final Header header,
273 LineFormatter formatter) {
274 if (formatter == null) {
275 formatter = BasicLineFormatter.INSTANCE;
276 }
277 return formatter.formatHeader(null, header).toString();
278 }
279
280
281 // non-javadoc, see interface LineFormatter
282 public CharArrayBuffer formatHeader(final CharArrayBuffer buffer,
283 final Header header) {
284 Args.notNull(header, "Header");
285 CharArrayBuffer result = null;
286
287 if (header instanceof FormattedHeader) {
288 // If the header is backed by a buffer, re-use the buffer
289 result = ((FormattedHeader)header).getBuffer();
290 } else {
291 result = initBuffer(buffer);
292 doFormatHeader(result, header);
293 }
294 return result;
295
296 } // formatHeader
297
298
299 /**
300 * Actually formats a header.
301 * Called from {@link #formatHeader}.
302 *
303 * @param buffer the empty buffer into which to format,
304 * never <code>null</code>
305 * @param header the header to format, never <code>null</code>
306 */
307 protected void doFormatHeader(final CharArrayBuffer buffer,
308 final Header header) {
309 final String name = header.getName();
310 final String value = header.getValue();
311
312 int len = name.length() + 2;
313 if (value != null) {
314 len += value.length();
315 }
316 buffer.ensureCapacity(len);
317
318 buffer.append(name);
319 buffer.append(": ");
320 if (value != null) {
321 buffer.append(value);
322 }
323 }
324
325
326 } // class BasicLineFormatter