001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.message; 029 030import org.apache.http.FormattedHeader; 031import org.apache.http.Header; 032import org.apache.http.ProtocolVersion; 033import org.apache.http.RequestLine; 034import org.apache.http.StatusLine; 035import org.apache.http.annotation.ThreadingBehavior; 036import org.apache.http.annotation.Contract; 037import org.apache.http.util.Args; 038import org.apache.http.util.CharArrayBuffer; 039 040/** 041 * Interface for formatting elements of the HEAD section of an HTTP message. 042 * This is the complement to {@link LineParser}. 043 * There are individual methods for formatting a request line, a 044 * status line, or a header line. The formatting does <i>not</i> include the 045 * trailing line break sequence CR-LF. 046 * The formatted lines are returned in memory, the formatter does not depend 047 * on any specific IO mechanism. 048 * Instances of this interface are expected to be stateless and thread-safe. 049 * 050 * @since 4.0 051 */ 052@Contract(threading = ThreadingBehavior.IMMUTABLE) 053public class BasicLineFormatter implements LineFormatter { 054 055 /** 056 * A default instance of this class, for use as default or fallback. 057 * Note that {@link BasicLineFormatter} is not a singleton, there can 058 * be many instances of the class itself and of derived classes. 059 * The instance here provides non-customized, default behavior. 060 * 061 * @deprecated (4.3) use {@link #INSTANCE} 062 */ 063 @Deprecated 064 public final static BasicLineFormatter DEFAULT = new BasicLineFormatter(); 065 066 public final static BasicLineFormatter INSTANCE = new BasicLineFormatter(); 067 068 public BasicLineFormatter() { 069 super(); 070 } 071 072 /** 073 * Obtains a buffer for formatting. 074 * 075 * @param charBuffer a buffer already available, or {@code null} 076 * 077 * @return the cleared argument buffer if there is one, or 078 * a new empty buffer that can be used for formatting 079 */ 080 protected CharArrayBuffer initBuffer(final CharArrayBuffer charBuffer) { 081 CharArrayBuffer buffer = charBuffer; 082 if (buffer != null) { 083 buffer.clear(); 084 } else { 085 buffer = new CharArrayBuffer(64); 086 } 087 return buffer; 088 } 089 090 091 /** 092 * Formats a protocol version. 093 * 094 * @param version the protocol version to format 095 * @param formatter the formatter to use, or 096 * {@code null} for the 097 * {@link #INSTANCE default} 098 * 099 * @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 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 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 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 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.append(value); 320 } 321 } 322 323 324} // class BasicLineFormatter