View Javadoc
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.Contract;
36  import org.apache.http.annotation.ThreadingBehavior;
37  import org.apache.http.util.Args;
38  import org.apache.http.util.CharArrayBuffer;
39  
40  /**
41   * Interface for formatting elements of the HEAD section of an HTTP message.
42   * This is the complement to {@link LineParser}.
43   * There are individual methods for formatting a request line, a
44   * status line, or a header line. The formatting does <i>not</i> include the
45   * trailing line break sequence CR-LF.
46   * The formatted lines are returned in memory, the formatter does not depend
47   * on any specific IO mechanism.
48   * Instances of this interface are expected to be stateless and thread-safe.
49   *
50   * @since 4.0
51   */
52  @Contract(threading = ThreadingBehavior.IMMUTABLE)
53  public class BasicLineFormatter implements LineFormatter {
54  
55      /**
56       * A default instance of this class, for use as default or fallback.
57       * Note that {@link BasicLineFormatter} is not a singleton, there can
58       * be many instances of the class itself and of derived classes.
59       * The instance here provides non-customized, default behavior.
60       *
61       * @deprecated (4.3) use {@link #INSTANCE}
62       */
63      @Deprecated
64      public final static BasicLineFormatterr.html#BasicLineFormatter">BasicLineFormatter DEFAULT = new BasicLineFormatter();
65  
66      public final static BasicLineFormatter.html#BasicLineFormatter">BasicLineFormatter INSTANCE = new BasicLineFormatter();
67  
68      public BasicLineFormatter() {
69          super();
70      }
71  
72      /**
73       * Obtains a buffer for formatting.
74       *
75       * @param charBuffer a buffer already available, or {@code null}
76       *
77       * @return  the cleared argument buffer if there is one, or
78       *          a new empty buffer that can be used for formatting
79       */
80      protected CharArrayBuffer#CharArrayBuffer">CharArrayBuffer initBuffer(final CharArrayBuffer charBuffer) {
81          CharArrayBuffer buffer = charBuffer;
82          if (buffer != null) {
83              buffer.clear();
84          } else {
85              buffer = new CharArrayBuffer(64);
86          }
87          return buffer;
88      }
89  
90  
91      /**
92       * Formats a protocol version.
93       *
94       * @param version           the protocol version to format
95       * @param formatter         the formatter to use, or
96       *                          {@code null} for the
97       *                          {@link #INSTANCE default}
98       *
99       * @return  the formatted protocol version
100      */
101     public static
102         String formatProtocolVersion(final ProtocolVersion version,
103                                      final LineFormatter formatter) {
104         return (formatter != null ? formatter : BasicLineFormatter.INSTANCE)
105                 .appendProtocolVersion(null, version).toString();
106     }
107 
108 
109     // non-javadoc, see interface LineFormatter
110     @Override
111     public CharArrayBufferuffer">CharArrayBuffer appendProtocolVersion(final CharArrayBuffer buffer,
112                                                  final ProtocolVersion version) {
113         Args.notNull(version, "Protocol version");
114         // can't use initBuffer, that would clear the argument!
115         CharArrayBuffer result = buffer;
116         final int len = estimateProtocolVersionLen(version);
117         if (result == null) {
118             result = new CharArrayBuffer(len);
119         } else {
120             result.ensureCapacity(len);
121         }
122 
123         result.append(version.getProtocol());
124         result.append('/');
125         result.append(Integer.toString(version.getMajor()));
126         result.append('.');
127         result.append(Integer.toString(version.getMinor()));
128 
129         return result;
130     }
131 
132 
133     /**
134      * Guesses the length of a formatted protocol version.
135      * Needed to guess the length of a formatted request or status line.
136      *
137      * @param version   the protocol version to format, or {@code null}
138      *
139      * @return  the estimated length of the formatted protocol version,
140      *          in characters
141      */
142     protected int estimateProtocolVersionLen(final ProtocolVersion version) {
143         return version.getProtocol().length() + 4; // room for "HTTP/1.1"
144     }
145 
146 
147     /**
148      * Formats a request line.
149      *
150      * @param reqline           the request line to format
151      * @param formatter         the formatter to use, or
152      *                          {@code null} for the
153      *                          {@link #INSTANCE default}
154      *
155      * @return  the formatted request line
156      */
157     public static String formatRequestLine(final RequestLine reqline,
158                                            final LineFormatter formatter) {
159         return (formatter != null ? formatter : BasicLineFormatter.INSTANCE)
160                 .formatRequestLine(null, reqline).toString();
161     }
162 
163 
164     // non-javadoc, see interface LineFormatter
165     @Override
166     public CharArrayBufferrayBuffer">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}
182      * @param reqline   the request line to format, never {@code null}
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} for the
209      *                          {@link #INSTANCE default}
210      *
211      * @return  the formatted status line
212      */
213     public static String formatStatusLine(final StatusLine statline,
214                                           final LineFormatter formatter) {
215         return (formatter != null ? formatter : BasicLineFormatter.INSTANCE)
216                 .formatStatusLine(null, statline).toString();
217     }
218 
219 
220     // non-javadoc, see interface LineFormatter
221     @Override
222     public CharArrayBufferrrayBuffer">CharArrayBuffer formatStatusLine(final CharArrayBuffer buffer,
223                                             final StatusLine statline) {
224         Args.notNull(statline, "Status line");
225         final CharArrayBuffer result = initBuffer(buffer);
226         doFormatStatusLine(result, statline);
227 
228         return result;
229     }
230 
231 
232     /**
233      * Actually formats a status line.
234      * Called from {@link #formatStatusLine}.
235      *
236      * @param buffer    the empty buffer into which to format,
237      *                  never {@code null}
238      * @param statline  the status line to format, never {@code null}
239      */
240     protected void doFormatStatusLine(final CharArrayBuffer buffer,
241                                       final StatusLine statline) {
242 
243         int len = estimateProtocolVersionLen(statline.getProtocolVersion())
244             + 1 + 3 + 1; // room for "HTTP/1.1 200 "
245         final String reason = statline.getReasonPhrase();
246         if (reason != null) {
247             len += reason.length();
248         }
249         buffer.ensureCapacity(len);
250 
251         appendProtocolVersion(buffer, statline.getProtocolVersion());
252         buffer.append(' ');
253         buffer.append(Integer.toString(statline.getStatusCode()));
254         buffer.append(' '); // keep whitespace even if reason phrase is empty
255         if (reason != null) {
256             buffer.append(reason);
257         }
258     }
259 
260 
261     /**
262      * Formats a header.
263      *
264      * @param header            the header to format
265      * @param formatter         the formatter to use, or
266      *                          {@code null} for the
267      *                          {@link #INSTANCE default}
268      *
269      * @return  the formatted header
270      */
271     public static String formatHeader(final Header header,
272                                       final LineFormatter formatter) {
273         return (formatter != null ? formatter : BasicLineFormatter.INSTANCE)
274                 .formatHeader(null, header).toString();
275     }
276 
277 
278     // non-javadoc, see interface LineFormatter
279     @Override
280     public CharArrayBufferharArrayBuffer">CharArrayBuffer formatHeader(final CharArrayBuffer buffer,
281                                         final Header header) {
282         Args.notNull(header, "Header");
283         final CharArrayBuffer result;
284 
285         if (header instanceof FormattedHeader) {
286             // If the header is backed by a buffer, re-use the buffer
287             result = ((FormattedHeader)header).getBuffer();
288         } else {
289             result = initBuffer(buffer);
290             doFormatHeader(result, header);
291         }
292         return result;
293 
294     } // formatHeader
295 
296 
297     /**
298      * Actually formats a header.
299      * Called from {@link #formatHeader}.
300      *
301      * @param buffer    the empty buffer into which to format,
302      *                  never {@code null}
303      * @param header    the header to format, never {@code null}
304      */
305     protected void doFormatHeader(final CharArrayBuffer buffer,
306                                   final Header header) {
307         final String name = header.getName();
308         final String value = header.getValue();
309 
310         int len = name.length() + 2;
311         if (value != null) {
312             len += value.length();
313         }
314         buffer.ensureCapacity(len);
315 
316         buffer.append(name);
317         buffer.append(": ");
318         if (value != null) {
319             buffer.ensureCapacity(buffer.length() + value.length());
320             for (int valueIndex = 0; valueIndex < value.length(); valueIndex++) {
321                 char valueChar = value.charAt(valueIndex);
322                 if (valueChar == '\r'
323                         || valueChar == '\n'
324                         || valueChar == '\f'
325                         || valueChar == 0x0b) {
326                     valueChar = ' ';
327                 }
328                 buffer.append(valueChar);
329             }
330         }
331     }
332 
333 
334 } // class BasicLineFormatter