/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Blacksmith, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.web; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSData; import net.wotonomy.foundation.NSDictionary; import net.wotonomy.foundation.NSMutableData; import net.wotonomy.foundation.NSMutableDictionary; /** * A pure java implementation of WOResponse. * * @author ezamudio@nasoft.com * @author $Author: cgruber $ * @version $Revision: 905 $ */ public class WOMessage { protected String _contentEncoding = "ISO8859_1"; protected NSMutableDictionary _headers = new NSMutableDictionary(); protected NSMutableDictionary _cookies = new NSMutableDictionary(); private NSMutableDictionary _userInfo = new NSMutableDictionary(); protected NSMutableData _contentData = new NSMutableData(); public WOMessage() { super(); } /** * Sets the content encoding for the response. */ public void setContentEncoding (String encoding) { _contentEncoding = encoding; } /** * Gets the current content encoding for the response. */ public String contentEncoding () { return _contentEncoding; } /** * Sets the specified array of values as headers under * the specified key. */ public void setHeaders (NSArray headerArray, String aKey) { _headers.setObjectForKey( headerArray, aKey ); } /** * Sets the specified header value for the specified key. */ public void setHeader (String aValue, String aKey) { _headers.setObjectForKey( new NSArray( aValue ), aKey ); } /** * Returns an array of all the header keys that have been * set in the response. */ public NSArray headerKeys () { return _headers.allKeys(); } /** * Returns an array of all the header values for the specified key, * or null if the key does not exist. */ public NSArray headersForKey (String aKey) { return (NSArray)_headers.objectForKey( aKey ); } /** * Returns one header value for the specified key. * Provided as a convenience, since most header keys * will have a single value. */ public String headerForKey (String aKey) { NSArray values = (NSArray)_headers.objectForKey( aKey ); if ( values != null && values.count() > 0 ) { return values.objectAtIndex( 0 ).toString(); } return null; } /** * Sets the content of the response to the bytes represented * by the specified data object. */ public void setContent(NSData aData) { _contentData.setData( aData ); setHeader(Integer.toString(aData.length()), "content-length"); } /** * Retrieves the current content of the response. */ public NSData content() { return _contentData; } /** * Sets the current user info dictionary. These values * are for application-specific uses and are available to * other actions and components in the request-response cycle. */ public void setUserInfo (NSDictionary aDict) { _userInfo = new NSMutableDictionary( aDict ); } /** * Gets the current user info dictionary. These values * are for application-specific uses are are available to * other actions and components in the request-response cycle. */ public NSDictionary userInfo () { return new NSDictionary(_userInfo); } /** * Appends the bytes in the specified data object to the response. */ public void appendContentData (NSData aData) { _contentData.appendData( aData ); setHeader(Integer.toString(_contentData.length()), "content-length"); } /** * Appends the specified byte to the response. */ public void appendContentCharacter (char character) { _contentData.appendByte((byte)character); setHeader(Integer.toString(_contentData.length()), "content-length"); } /** * Appends the specified string to the response. * Any special characters will not be escaped. * The string will be encoded in the current content encoding. */ public void appendContentString (String aString) { _contentData.appendData( new NSData( aString.getBytes() ) ); setHeader(Integer.toString(_contentData.length()), "content-length"); } /** * Appends the specified string containing HTML to the response. * Any special characters will be escaped appropriately. * The string will be encoded in the current content encoding. */ public void appendContentHTMLString (String aString) { _contentData.appendData( new NSData( stringByEscapingHTMLString( aString ).getBytes() ) ); setHeader(Integer.toString(_contentData.length()), "content-length"); } /** * Appends the specified string containing HTML to the response. * Any special characters will be escaped appropriately. * This method escapes tabs and new-line characters as well. * The string will be encoded in the current content encoding. */ public void appendContentHTMLAttributeValue (String aString) { _contentData.appendData ( new NSData( stringByEscapingHTMLAttributeValue( aString ).getBytes() ) ); setHeader(Integer.toString(_contentData.length()), "content-length"); } /** * Adds the specified cookie to the response. */ public void addCookie (WOCookie aCookie) { _cookies.setObjectForKey( aCookie, aCookie.name() ); } /** * Removes the specified cookie from the response. */ public void removeCookie (WOCookie aCookie) { _cookies.removeObjectForKey( aCookie.name() ); } /** * Returns an array of cookies currently being sent with the response. * Contains whatever cookies have previously been set in this response. */ public NSArray cookies () { return _cookies.allValues(); } /** * Sets the HTTP version header in the response. */ public void setHTTPVersion (String aString) { setHeader( aString, "Protocol"); } /** * Gets the current HTTP version header for the response. * Because servlet responses do not allow read access * to headers, this method returns null if setHTTPVersion * has not been called. */ public String httpVersion () { return headerForKey( "Protocol" ); } /** * Returns a sting containing the contents of the specified * string after escaping all special HTML characters. */ public static String stringByEscapingHTMLString (String aString) { int len = aString.length(); StringBuffer result = new StringBuffer(); char[] buf = new char[ len ]; aString.getChars( 0, len, buf, 0 ); for ( int i = 0; i < len; i++ ) { if ( buf[i] == '&' ) { result.append( "&" ); } else if ( buf[i] == '\\' ) { result.append( """ ); } else if ( buf[i] == '<' ) { result.append( "<" ); } else if ( buf[i] == '>' ) { result.append( ">" ); } else { result.append( buf[i] ); } } return result.toString(); } /** * Returns a sting containing the contents of the specified * string after escaping all special HTML characters. * This method escapes tabs and new-line characters as well. */ public static String stringByEscapingHTMLAttributeValue (String aString) { int len = aString.length(); StringBuffer result = new StringBuffer(); char[] buf = new char[ len ]; aString.getChars( 0, len, buf, 0 ); for ( int i = 0; i < len; i++ ) { if ( buf[i] == '&' ) { result.append( "&" ); } else if ( buf[i] == '\\' ) { result.append( """ ); } else if ( buf[i] == '<' ) { result.append( "<" ); } else if ( buf[i] == '>' ) { result.append( ">" ); } else if ( buf[i] == '\t' ) { result.append( " " ); } else if ( buf[i] == '\n' ) { result.append( " " ); } else if ( buf[i] == '\r' ) { result.append( " " ); } else { result.append( buf[i] ); } } return result.toString(); } }