X-Git-Url: https://juplo.de/gitweb/?p=percentcodec;a=blobdiff_plain;f=accelerator%2Fsrc%2Ftest%2Fjava%2Fcom%2Fmeterware%2Fservletunit%2FServletUnitHttpResponse.java;fp=accelerator%2Fsrc%2Ftest%2Fjava%2Fcom%2Fmeterware%2Fservletunit%2FServletUnitHttpResponse.java;h=285d17377fe2ddbb3815654c8e0561ead0ea0375;hp=0000000000000000000000000000000000000000;hb=a6e0e65cce68acb20abc6ca935471611a740c342;hpb=1d395c6002486d485bde0d5dc713886d70bd3f8a diff --git a/accelerator/src/test/java/com/meterware/servletunit/ServletUnitHttpResponse.java b/accelerator/src/test/java/com/meterware/servletunit/ServletUnitHttpResponse.java new file mode 100644 index 00000000..285d1737 --- /dev/null +++ b/accelerator/src/test/java/com/meterware/servletunit/ServletUnitHttpResponse.java @@ -0,0 +1,621 @@ +package com.meterware.servletunit; +/******************************************************************************************************************** +* $Id: ServletUnitHttpResponse.java 751 2006-03-24 19:59:12Z russgold $ +* +* Copyright (c) 2000-2004,2006, Russell Gold +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +* documentation files (the "Software"), to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +* to permit persons to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or substantial portions +* of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*******************************************************************************************************************/ +import com.meterware.httpunit.HttpUnitUtils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; + +import java.util.*; +import java.text.SimpleDateFormat; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + + +class ServletUnitHttpResponse implements HttpServletResponse { + + // rfc1123-date is "Sun, 06 Nov 1994 08:49:37 GMT" + private static final String RFC1123_DATE_SPEC = "EEE, dd MMM yyyy HH:mm:ss z"; + private boolean _committed; + private Locale _locale = Locale.getDefault(); + + private static final Hashtable ENCODING_MAP = new Hashtable(); + + /** + * @deprecated Use encodeURL(String url) + */ + public String encodeUrl( String url ) { + return encodeURL( url ); + } + + + /** + * Adds the specified cookie to the response. It can be called + * multiple times to set more than one cookie. + */ + public void addCookie( Cookie cookie ) { + _cookies.addElement( cookie ); + } + + + /** + * Checks whether the response message header has a field with + * the specified name. + */ + public boolean containsHeader( String name ) { + return _headers.containsKey( name.toUpperCase() ); + } + + + /** + * @deprecated Use encodeRedirectURL(String url) + **/ + public String encodeRedirectUrl( String url ) { + return encodeRedirectURL( url ); + } + + + /** + * Encodes the specified URL by including the session ID in it, + * or, if encoding is not needed, returns the URL unchanged. + * The implementation of this method should include the logic to + * determine whether the session ID needs to be encoded in the URL. + * For example, if the browser supports cookies, or session + * tracking is turned off, URL encoding is unnecessary. + **/ + public String encodeURL( String url ) { + return url; + } + + + /** + * Encodes the specified URL for use in the + * sendRedirect method or, if encoding is not needed, + * returns the URL unchanged. The implementation of this method + * should include the logic to determine whether the session ID + * needs to be encoded in the URL. Because the rules for making + * this determination differ from those used to decide whether to + * encode a normal link, this method is seperate from the + * encodeUrl method. + **/ + public String encodeRedirectURL( String url ) { + return url; + } + + + /** + * Sends a temporary redirect response to the client using the + * specified redirect location URL. The URL must be absolute (for + * example, https://hostname/path/file.html). + * Relative URLs are not permitted here. + */ + public void sendRedirect( String location ) throws IOException { + setStatus( HttpServletResponse.SC_MOVED_TEMPORARILY ); + setHeader( "Location", location ); + } + + + /** + * Sends an error response to the client using the specified status + * code and descriptive message. If setStatus has previously been + * called, it is reset to the error status code. The message is + * sent as the body of an HTML page, which is returned to the user + * to describe the problem. The page is sent with a default HTML + * header; the message is enclosed in simple body tags + * (<body></body>). + **/ + public void sendError( int sc ) throws IOException { + sendError( sc, "" ); + } + + + /** + * Sends an error response to the client using the specified status + * code and descriptive message. If setStatus has previously been + * called, it is reset to the error status code. The message is + * sent as the body of an HTML page, which is returned to the user + * to describe the problem. The page is sent with a default HTML + * header; the message is enclosed in simple body tags + * (<body></body>). + **/ + public void sendError(int sc, String msg) throws IOException { + setStatus( sc ); + _statusMessage = msg; + + _writer = null; + _servletStream = null; + + setContentType( "text/html" ); + getWriter().println( "" + msg + "" + msg + "" ); + } + + + /** + * Sets the status code for this response. This method is used to + * set the return status code when there is no error (for example, + * for the status codes SC_OK or SC_MOVED_TEMPORARILY). If there + * is an error, the sendError method should be used + * instead. + **/ + public void setStatus( int sc ) { + _status = sc; + } + + + /** + * @deprecated As of version 2.1, due to ambiguous meaning of the message parameter. + * To set a status code use setStatus(int), to send an error with a description + * use sendError(int, String). Sets the status code and message for this response. + **/ + public void setStatus( int sc, String msg ) { + setStatus( sc ); + } + + + /** + * Adds a field to the response header with the given name and value. + * If the field had already been set, the new value overwrites the + * previous one. The containsHeader method can be + * used to test for the presence of a header before setting its + * value. + **/ + public void setHeader( String name, String value ) { + ArrayList values = new ArrayList(); + values.add( value ); + synchronized (_headers) { + _headers.put( name.toUpperCase(), values ); + } + } + + + /** + * Adds a field to the response header with the given name and + * integer value. If the field had already been set, the new value + * overwrites the previous one. The containsHeader + * method can be used to test for the presence of a header before + * setting its value. + **/ + public void setIntHeader( String name, int value ) { + setHeader( name, asHeaderValue( value ) ); + } + + + private String asHeaderValue( int value ) { + return Integer.toString( value ); + } + + + /** + * Adds a field to the response header with the given name and + * date-valued field. The date is specified in terms of + * milliseconds since the epoch. If the date field had already + * been set, the new value overwrites the previous one. The + * containsHeader method can be used to test for the + * presence of a header before setting its value. + **/ + public void setDateHeader( String name, long date ) { + setHeader( name, asDateHeaderValue( date ) ); + } + + + private String asDateHeaderValue( long date ) { + Date value = new Date( date ); + SimpleDateFormat formatter = new SimpleDateFormat( RFC1123_DATE_SPEC, Locale.US ); + formatter.setTimeZone( TimeZone.getTimeZone( "Greenwich Mean Time" ) ); + return formatter.format( value ); + } + + + /** + * Returns the name of the character set encoding used for + * the MIME body sent by this response. + **/ + public String getCharacterEncoding() { + return _encoding == null ? HttpUnitUtils.DEFAULT_CHARACTER_SET : _encoding; + } + + + /** + * Sets the content type of the response the server sends to + * the client. The content type may include the type of character + * encoding used, for example, text/html; charset=ISO-8859-4. + * + *

You can only use this method once, and you should call it + * before you obtain a PrintWriter or + * {@link ServletOutputStream} object to return a response. + **/ + public void setContentType( String type ) { + String[] typeAndEncoding = HttpUnitUtils.parseContentTypeHeader( type ); + + _contentType = typeAndEncoding[0]; + if (typeAndEncoding[1] != null) _encoding = typeAndEncoding[1]; + } + + + /** + * Returns a {@link ServletOutputStream} suitable for writing binary + * data in the response. The servlet engine does not encode the + * binary data. + * + * @exception IllegalStateException if you have already called the getWriter method + **/ + public ServletOutputStream getOutputStream() throws IOException { + if (_writer != null) throw new IllegalStateException( "Tried to create output stream; writer already exists" ); + if (_servletStream == null) { + _outputStream = new ByteArrayOutputStream(); + _servletStream = new ServletUnitOutputStream( _outputStream ); + } + return _servletStream; + } + + + /** + * Returns a PrintWriter object that you + * can use to send character text to the client. + * The character encoding used is the one specified + * in the charset= property of the + * {@link #setContentType} method, which you must call + * before you call this method. + * + *

If necessary, the MIME type of the response is + * modified to reflect the character encoding used. + * + *

You cannot use this method if you have already + * called {@link #getOutputStream} for this + * ServletResponse object. + * + * @exception UnsupportedEncodingException if the character encoding specified in + * setContentType cannot be + * used + * + * @exception IllegalStateException if the getOutputStream + * method has already been called for this + * response object; in that case, you can't + * use this method + * + **/ + public PrintWriter getWriter() throws UnsupportedEncodingException { + if (_servletStream != null) throw new IllegalStateException( "Tried to create writer; output stream already exists" ); + if (_writer == null) { + _outputStream = new ByteArrayOutputStream(); + _writer = new PrintWriter( new OutputStreamWriter( _outputStream, getCharacterEncoding() ) ); + } + return _writer; + } + + + /** + * Sets the length of the content the server returns + * to the client. In HTTP servlets, this method sets the + * HTTP Content-Length header. + **/ + public void setContentLength( int len ) { + setIntHeader( "Content-Length", len ); + } + + +//------------------------------- the following methods are new in JSDK 2.2 ---------------------- + + + /** + * Adds a response header with the given name and value. This method allows response headers to have multiple values. + **/ + public void addHeader( String name, String value ) { + synchronized (_headers) { + String key = name.toUpperCase(); + ArrayList values = (ArrayList) _headers.get( key ); + if (values == null) { + values = new ArrayList(); + _headers.put( key, values ); + } + values.add( value ); + } + } + + + /** + * Adds a response header with the given name and value. This method allows response headers to have multiple values. + **/ + public void addIntHeader( String name, int value ) { + addHeader( name, asHeaderValue( value ) ); + } + + + /** + * Adds a response header with the given name and value. This method allows response headers to have multiple values. + **/ + public void addDateHeader( String name, long value ) { + addHeader( name, asDateHeaderValue( value ) ); + } + + + /** + * Sets the preferred buffer size for the body of the response. The servlet container + * will use a buffer at least as large as the size requested. The actual buffer size + * used can be found using getBufferSize. + **/ + public void setBufferSize( int size ) { + if (getContents().length != 0) throw new IllegalStateException( "May not set buffer size after data is written" ); + } + + + /** + * Returns the actual buffer size used for the response. If no buffering is used, this method returns 0. + **/ + public int getBufferSize() { + return 0; + } + + + /** + * Returns a boolean indicating if the response has been committed. A committed response has + * already had its status code and headers written. + **/ + public boolean isCommitted() { + return _committed; + } + + + /** + * Forces any content in the buffer to be written to the client. A call to this method automatically + * commits the response, meaning the status code and headers will be written. + **/ + public void flushBuffer() throws IOException { + _committed = true; + } + + + /** + * Clears any data that exists in the buffer as well as the status code and headers. + * If the response has been committed, this method throws an IllegalStateException. + **/ + public void reset() { + resetBuffer(); + _headers.clear(); + _headersComplete = false; + _status = SC_OK; + } + + + /** + * Sets the locale of the response, setting the headers (including the Content-Type's charset) + * as appropriate. This method should be called before a call to getWriter(). + * By default, the response locale is the default locale for the server. + **/ + public void setLocale( Locale locale ) { + _locale = locale; + if (_encoding == null) { + for (Iterator it = ENCODING_MAP.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + String locales = (String) entry.getValue(); + if (locales.indexOf( locale.getLanguage() ) >= 0 || locales.indexOf( locale.toString() ) >= 0) { + _encoding = (String) entry.getKey(); + return; + } + } + } + } + + + /** + * Returns the locale assigned to the response. + **/ + public Locale getLocale() { + return _locale; + } + + +//----------------------------- methods added to ServletResponse in JSDK 2.3 -------------------------------------- + + + /** + * Clears the content of the underlying buffer in the response without clearing headers or status code. + * If the response has been committed, this method throws an IllegalStateException. + * + * @since 1.3 + */ + public void resetBuffer() { + if (_committed) throw new IllegalStateException( "May not resetBuffer after response is committed" ); + _outputStream = null; + _servletStream = null; + _writer = null; + } + + +//---------------------------------------------- package methods -------------------------------------------------- + + /** + * Returns the contents of this response. + **/ + byte[] getContents() { + if (_outputStream == null) { + return new byte[0]; + } else { + if (_writer != null) _writer.flush(); + return _outputStream.toByteArray(); + } + } + + + /** + * Returns the status of this response. + **/ + int getStatus() { + return _status; + } + + + /** + * Returns the message associated with this response's status. + **/ + String getMessage() { + return _statusMessage; + } + + + public String[] getHeaderFieldNames() { + if (!_headersComplete) completeHeaders(); + Vector names = new Vector(); + for (Enumeration e = _headers.keys(); e.hasMoreElements();) { + names.addElement( e.nextElement() ); + } + String[] result = new String[ names.size() ]; + names.copyInto( result ); + return result; + } + + + /** + * Returns the headers defined for this response. + **/ + String getHeaderField( String name ) { + if (!_headersComplete) completeHeaders(); + + ArrayList values; + synchronized (_headers) { + values = (ArrayList) _headers.get( name.toUpperCase() ); + } + + return values == null ? null : (String) values.get( 0 ); + } + + + /** + * Return an array of all the header values associated with the + * specified header name, or an zero-length array if there are no such + * header values. + * + * @param name Header name to look up + */ + public String[] getHeaderFields(String name) { + if (!_headersComplete) completeHeaders(); + ArrayList values; + synchronized (_headers) { + values = (ArrayList) _headers.get(name.toUpperCase()); + } + if (values == null) + return (new String[0]); + String results[] = new String[values.size()]; + return ((String[]) values.toArray(results)); + + } + +//--------------------------------------- methods added to ServletRequest in Servlet API 2.4 ---------------------------- + + public void setCharacterEncoding(String string) { + _encoding = string; + } + + /** + * Returns the content type defined for this response. + **/ + public String getContentType() { + return _contentType; + } + + +//------------------------------------------- private members ------------------------------------ + + + private String _contentType = "text/plain"; + + private String _encoding; + + private PrintWriter _writer; + + private ServletOutputStream _servletStream; + + private ByteArrayOutputStream _outputStream; + + private int _status = SC_OK; + + private String _statusMessage = "OK"; + + private final Hashtable _headers = new Hashtable(); + + private boolean _headersComplete; + + private Vector _cookies = new Vector(); + + + private void completeHeaders() { + if (_headersComplete) return; + addCookieHeader(); + setHeader( "Content-Type", _contentType + "; charset=" + getCharacterEncoding() ); + _headersComplete = true; + } + + + private void addCookieHeader() { + if (_cookies.isEmpty()) return; + + StringBuffer sb = new StringBuffer(); + for (Enumeration e = _cookies.elements(); e.hasMoreElements();) { + Cookie cookie = (Cookie) e.nextElement(); + sb.append( cookie.getName() ).append( '=' ).append( cookie.getValue() ); + if (cookie.getPath() != null) sb.append( ";path=" ).append( cookie.getPath() ); + if (cookie.getDomain() != null) sb.append( ";domain=" ).append( cookie.getDomain() ); + if (e.hasMoreElements()) sb.append( ',' ); + } + setHeader( "Set-Cookie", sb.toString() ); + } + + + + static { + ENCODING_MAP.put( "iso-8859-1", "ca da de en es fi fr is it nl no pt sv " ); + ENCODING_MAP.put( "iso-8859-2", "cs hr hu pl ro sh sk sl sq " ); + ENCODING_MAP.put( "iso-8859-4", "et lt lv "); + ENCODING_MAP.put( "iso-8859-5", "be bg mk ru sr uk " ); + ENCODING_MAP.put( "iso-8859-6", "ar " ); + ENCODING_MAP.put( "iso-8859-7", "el " ); + ENCODING_MAP.put( "iso-8859-8", "iw he " ); + ENCODING_MAP.put( "iso-8859-9", "tr " ); + + ENCODING_MAP.put("Shift_JIS", "ja "); + ENCODING_MAP.put("EUC-KR", "ko "); + ENCODING_MAP.put("TIS-620", "th "); + ENCODING_MAP.put("GB2312", "zh " ); + ENCODING_MAP.put("Big5", "zh_TW zh_HK " ); + } + +} + + + +class ServletUnitOutputStream extends ServletOutputStream { + + ServletUnitOutputStream( ByteArrayOutputStream stream ) { + _stream = stream; + } + + + public void write( int aByte ) throws IOException { + _stream.write( aByte ); + } + + private ByteArrayOutputStream _stream; +}