| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| WOMessage |
|
| 1.625;1.625 |
| 1 | /* |
|
| 2 | Wotonomy: OpenStep design patterns for pure Java applications. |
|
| 3 | Copyright (C) 2000 Blacksmith, Inc. |
|
| 4 | ||
| 5 | This library is free software; you can redistribute it and/or |
|
| 6 | modify it under the terms of the GNU Lesser General Public |
|
| 7 | License as published by the Free Software Foundation; either |
|
| 8 | version 2.1 of the License, or (at your option) any later version. |
|
| 9 | ||
| 10 | This library is distributed in the hope that it will be useful, |
|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 13 | Lesser General Public License for more details. |
|
| 14 | ||
| 15 | You should have received a copy of the GNU Lesser General Public |
|
| 16 | License along with this library; if not, see http://www.gnu.org |
|
| 17 | */ |
|
| 18 | package net.wotonomy.web; |
|
| 19 | ||
| 20 | import net.wotonomy.foundation.NSArray; |
|
| 21 | import net.wotonomy.foundation.NSData; |
|
| 22 | import net.wotonomy.foundation.NSDictionary; |
|
| 23 | import net.wotonomy.foundation.NSMutableData; |
|
| 24 | import net.wotonomy.foundation.NSMutableDictionary; |
|
| 25 | ||
| 26 | /** |
|
| 27 | * A pure java implementation of WOResponse. |
|
| 28 | * |
|
| 29 | * @author ezamudio@nasoft.com |
|
| 30 | * @author $Author: cgruber $ |
|
| 31 | * @version $Revision: 905 $ |
|
| 32 | */ |
|
| 33 | public class WOMessage { |
|
| 34 | ||
| 35 | 0 | protected String _contentEncoding = "ISO8859_1"; |
| 36 | 0 | protected NSMutableDictionary _headers = new NSMutableDictionary(); |
| 37 | 0 | protected NSMutableDictionary _cookies = new NSMutableDictionary(); |
| 38 | 0 | private NSMutableDictionary _userInfo = new NSMutableDictionary(); |
| 39 | 0 | protected NSMutableData _contentData = new NSMutableData(); |
| 40 | ||
| 41 | public WOMessage() { |
|
| 42 | 0 | super(); |
| 43 | 0 | } |
| 44 | ||
| 45 | /** |
|
| 46 | * Sets the content encoding for the response. |
|
| 47 | */ |
|
| 48 | public void setContentEncoding (String encoding) |
|
| 49 | { |
|
| 50 | 0 | _contentEncoding = encoding; |
| 51 | 0 | } |
| 52 | ||
| 53 | /** |
|
| 54 | * Gets the current content encoding for the response. |
|
| 55 | */ |
|
| 56 | public String contentEncoding () { |
|
| 57 | 0 | return _contentEncoding; |
| 58 | } |
|
| 59 | ||
| 60 | /** |
|
| 61 | * Sets the specified array of values as headers under |
|
| 62 | * the specified key. |
|
| 63 | */ |
|
| 64 | public void setHeaders (NSArray headerArray, String aKey) { |
|
| 65 | 0 | _headers.setObjectForKey( headerArray, aKey ); |
| 66 | 0 | } |
| 67 | ||
| 68 | /** |
|
| 69 | * Sets the specified header value for the specified key. |
|
| 70 | */ |
|
| 71 | public void setHeader (String aValue, String aKey) { |
|
| 72 | 0 | _headers.setObjectForKey( new NSArray( aValue ), aKey ); |
| 73 | 0 | } |
| 74 | ||
| 75 | /** |
|
| 76 | * Returns an array of all the header keys that have been |
|
| 77 | * set in the response. |
|
| 78 | */ |
|
| 79 | public NSArray headerKeys () { |
|
| 80 | 0 | return _headers.allKeys(); |
| 81 | } |
|
| 82 | ||
| 83 | /** |
|
| 84 | * Returns an array of all the header values for the specified key, |
|
| 85 | * or null if the key does not exist. |
|
| 86 | */ |
|
| 87 | public NSArray headersForKey (String aKey) { |
|
| 88 | 0 | return (NSArray)_headers.objectForKey( aKey ); |
| 89 | } |
|
| 90 | ||
| 91 | /** |
|
| 92 | * Returns one header value for the specified key. |
|
| 93 | * Provided as a convenience, since most header keys |
|
| 94 | * will have a single value. |
|
| 95 | */ |
|
| 96 | public String headerForKey (String aKey) { |
|
| 97 | 0 | NSArray values = (NSArray)_headers.objectForKey( aKey ); |
| 98 | 0 | if ( values != null && values.count() > 0 ) { |
| 99 | 0 | return values.objectAtIndex( 0 ).toString(); |
| 100 | } |
|
| 101 | 0 | return null; |
| 102 | } |
|
| 103 | ||
| 104 | /** |
|
| 105 | * Sets the content of the response to the bytes represented |
|
| 106 | * by the specified data object. |
|
| 107 | */ |
|
| 108 | public void setContent(NSData aData) { |
|
| 109 | 0 | _contentData.setData( aData ); |
| 110 | 0 | setHeader(Integer.toString(aData.length()), "content-length"); |
| 111 | 0 | } |
| 112 | ||
| 113 | /** |
|
| 114 | * Retrieves the current content of the response. |
|
| 115 | */ |
|
| 116 | public NSData content() { |
|
| 117 | 0 | return _contentData; |
| 118 | } |
|
| 119 | ||
| 120 | /** |
|
| 121 | * Sets the current user info dictionary. These values |
|
| 122 | * are for application-specific uses and are available to |
|
| 123 | * other actions and components in the request-response cycle. |
|
| 124 | */ |
|
| 125 | public void setUserInfo (NSDictionary aDict) { |
|
| 126 | 0 | _userInfo = new NSMutableDictionary( aDict ); |
| 127 | 0 | } |
| 128 | ||
| 129 | /** |
|
| 130 | * Gets the current user info dictionary. These values |
|
| 131 | * are for application-specific uses are are available to |
|
| 132 | * other actions and components in the request-response cycle. |
|
| 133 | */ |
|
| 134 | public NSDictionary userInfo () { |
|
| 135 | 0 | return new NSDictionary(_userInfo); |
| 136 | } |
|
| 137 | ||
| 138 | /** |
|
| 139 | * Appends the bytes in the specified data object to the response. |
|
| 140 | */ |
|
| 141 | public void appendContentData (NSData aData) |
|
| 142 | { |
|
| 143 | 0 | _contentData.appendData( aData ); |
| 144 | 0 | setHeader(Integer.toString(_contentData.length()), "content-length"); |
| 145 | 0 | } |
| 146 | ||
| 147 | /** |
|
| 148 | * Appends the specified byte to the response. |
|
| 149 | */ |
|
| 150 | public void appendContentCharacter (char character) { |
|
| 151 | 0 | _contentData.appendByte((byte)character); |
| 152 | 0 | setHeader(Integer.toString(_contentData.length()), "content-length"); |
| 153 | 0 | } |
| 154 | ||
| 155 | /** |
|
| 156 | * Appends the specified string to the response. |
|
| 157 | * Any special characters will not be escaped. |
|
| 158 | * The string will be encoded in the current content encoding. |
|
| 159 | */ |
|
| 160 | public void appendContentString (String aString) |
|
| 161 | { |
|
| 162 | 0 | _contentData.appendData( new NSData( aString.getBytes() ) ); |
| 163 | 0 | setHeader(Integer.toString(_contentData.length()), "content-length"); |
| 164 | 0 | } |
| 165 | ||
| 166 | /** |
|
| 167 | * Appends the specified string containing HTML to the response. |
|
| 168 | * Any special characters will be escaped appropriately. |
|
| 169 | * The string will be encoded in the current content encoding. |
|
| 170 | */ |
|
| 171 | public void appendContentHTMLString (String aString) |
|
| 172 | { |
|
| 173 | 0 | _contentData.appendData( |
| 174 | 0 | new NSData( stringByEscapingHTMLString( |
| 175 | 0 | aString ).getBytes() ) ); |
| 176 | 0 | setHeader(Integer.toString(_contentData.length()), "content-length"); |
| 177 | 0 | } |
| 178 | ||
| 179 | /** |
|
| 180 | * Appends the specified string containing HTML to the response. |
|
| 181 | * Any special characters will be escaped appropriately. |
|
| 182 | * This method escapes tabs and new-line characters as well. |
|
| 183 | * The string will be encoded in the current content encoding. |
|
| 184 | */ |
|
| 185 | public void appendContentHTMLAttributeValue (String aString) |
|
| 186 | { |
|
| 187 | 0 | _contentData.appendData ( |
| 188 | 0 | new NSData( stringByEscapingHTMLAttributeValue( |
| 189 | 0 | aString ).getBytes() ) ); |
| 190 | 0 | setHeader(Integer.toString(_contentData.length()), "content-length"); |
| 191 | 0 | } |
| 192 | ||
| 193 | /** |
|
| 194 | * Adds the specified cookie to the response. |
|
| 195 | */ |
|
| 196 | public void addCookie (WOCookie aCookie) |
|
| 197 | { |
|
| 198 | 0 | _cookies.setObjectForKey( aCookie, aCookie.name() ); |
| 199 | 0 | } |
| 200 | ||
| 201 | /** |
|
| 202 | * Removes the specified cookie from the response. |
|
| 203 | */ |
|
| 204 | public void removeCookie (WOCookie aCookie) |
|
| 205 | { |
|
| 206 | 0 | _cookies.removeObjectForKey( aCookie.name() ); |
| 207 | 0 | } |
| 208 | ||
| 209 | /** |
|
| 210 | * Returns an array of cookies currently being sent with the response. |
|
| 211 | * Contains whatever cookies have previously been set in this response. |
|
| 212 | */ |
|
| 213 | public NSArray cookies () |
|
| 214 | { |
|
| 215 | 0 | return _cookies.allValues(); |
| 216 | } |
|
| 217 | ||
| 218 | /** |
|
| 219 | * Sets the HTTP version header in the response. |
|
| 220 | */ |
|
| 221 | public void setHTTPVersion (String aString) |
|
| 222 | { |
|
| 223 | 0 | setHeader( aString, "Protocol"); |
| 224 | 0 | } |
| 225 | ||
| 226 | /** |
|
| 227 | * Gets the current HTTP version header for the response. |
|
| 228 | * Because servlet responses do not allow read access |
|
| 229 | * to headers, this method returns null if setHTTPVersion |
|
| 230 | * has not been called. |
|
| 231 | */ |
|
| 232 | public String httpVersion () |
|
| 233 | { |
|
| 234 | 0 | return headerForKey( "Protocol" ); |
| 235 | } |
|
| 236 | ||
| 237 | /** |
|
| 238 | * Returns a sting containing the contents of the specified |
|
| 239 | * string after escaping all special HTML characters. |
|
| 240 | */ |
|
| 241 | public static String stringByEscapingHTMLString |
|
| 242 | (String aString) |
|
| 243 | { |
|
| 244 | 0 | int len = aString.length(); |
| 245 | 0 | StringBuffer result = new StringBuffer(); |
| 246 | 0 | char[] buf = new char[ len ]; |
| 247 | 0 | aString.getChars( 0, len, buf, 0 ); |
| 248 | 0 | for ( int i = 0; i < len; i++ ) |
| 249 | { |
|
| 250 | 0 | if ( buf[i] == '&' ) |
| 251 | { |
|
| 252 | 0 | result.append( "&" ); |
| 253 | 0 | } |
| 254 | else |
|
| 255 | 0 | if ( buf[i] == '\\' ) |
| 256 | { |
|
| 257 | 0 | result.append( """ ); |
| 258 | 0 | } |
| 259 | else |
|
| 260 | 0 | if ( buf[i] == '<' ) |
| 261 | { |
|
| 262 | 0 | result.append( "<" ); |
| 263 | 0 | } |
| 264 | else |
|
| 265 | 0 | if ( buf[i] == '>' ) |
| 266 | { |
|
| 267 | 0 | result.append( ">" ); |
| 268 | 0 | } |
| 269 | else |
|
| 270 | { |
|
| 271 | 0 | result.append( buf[i] ); |
| 272 | } |
|
| 273 | } |
|
| 274 | 0 | return result.toString(); |
| 275 | } |
|
| 276 | ||
| 277 | /** |
|
| 278 | * Returns a sting containing the contents of the specified |
|
| 279 | * string after escaping all special HTML characters. |
|
| 280 | * This method escapes tabs and new-line characters as well. |
|
| 281 | */ |
|
| 282 | public static String stringByEscapingHTMLAttributeValue |
|
| 283 | (String aString) |
|
| 284 | { |
|
| 285 | 0 | int len = aString.length(); |
| 286 | 0 | StringBuffer result = new StringBuffer(); |
| 287 | 0 | char[] buf = new char[ len ]; |
| 288 | 0 | aString.getChars( 0, len, buf, 0 ); |
| 289 | 0 | for ( int i = 0; i < len; i++ ) |
| 290 | { |
|
| 291 | 0 | if ( buf[i] == '&' ) |
| 292 | { |
|
| 293 | 0 | result.append( "&" ); |
| 294 | 0 | } |
| 295 | else |
|
| 296 | 0 | if ( buf[i] == '\\' ) |
| 297 | { |
|
| 298 | 0 | result.append( """ ); |
| 299 | 0 | } |
| 300 | else |
|
| 301 | 0 | if ( buf[i] == '<' ) |
| 302 | { |
|
| 303 | 0 | result.append( "<" ); |
| 304 | 0 | } |
| 305 | else |
|
| 306 | 0 | if ( buf[i] == '>' ) |
| 307 | { |
|
| 308 | 0 | result.append( ">" ); |
| 309 | 0 | } |
| 310 | else |
|
| 311 | 0 | if ( buf[i] == '\t' ) |
| 312 | { |
|
| 313 | 0 | result.append( "	" ); |
| 314 | 0 | } |
| 315 | else |
|
| 316 | 0 | if ( buf[i] == '\n' ) |
| 317 | { |
|
| 318 | 0 | result.append( " " ); |
| 319 | 0 | } |
| 320 | else |
|
| 321 | 0 | if ( buf[i] == '\r' ) |
| 322 | { |
|
| 323 | 0 | result.append( " " ); |
| 324 | 0 | } |
| 325 | else |
|
| 326 | { |
|
| 327 | 0 | result.append( buf[i] ); |
| 328 | } |
|
| 329 | } |
|
| 330 | 0 | return result.toString(); |
| 331 | } |
|
| 332 | ||
| 333 | } |