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