client/ftpd/src/se/lu/thep/coreftpd/webserver/ChunkedDataOutputStream.java

Code
Comments
Other
Rev Date Author Line
741 10 Oct 06 olle 1 /*
1652 22 May 07 gregory 2  $Id$
741 10 Oct 06 olle 3
1916 31 Aug 07 jari 4  Copyright (C) 2006 Olle Mansson
1916 31 Aug 07 jari 5  Copyright (C) 2007 Gregory Vincic
741 10 Oct 06 olle 6
1652 22 May 07 gregory 7  This file is part of Proteios.
1652 22 May 07 gregory 8  Available at http://www.proteios.org/
741 10 Oct 06 olle 9
1652 22 May 07 gregory 10  Proteios is free software; you can redistribute it and/or modify it
1652 22 May 07 gregory 11  under the terms of the GNU General Public License as published by
1652 22 May 07 gregory 12  the Free Software Foundation; either version 2 of the License, or
1652 22 May 07 gregory 13  (at your option) any later version.
741 10 Oct 06 olle 14
1652 22 May 07 gregory 15  Proteios is distributed in the hope that it will be useful, but
1652 22 May 07 gregory 16  WITHOUT ANY WARRANTY; without even the implied warranty of
1652 22 May 07 gregory 17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1652 22 May 07 gregory 18  General Public License for more details.
741 10 Oct 06 olle 19
1652 22 May 07 gregory 20  You should have received a copy of the GNU General Public License
1652 22 May 07 gregory 21  along with this program; if not, write to the Free Software
1652 22 May 07 gregory 22  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1652 22 May 07 gregory 23  02111-1307, USA.
1652 22 May 07 gregory 24  */
741 10 Oct 06 olle 25
741 10 Oct 06 olle 26 //  Xerver Free Web Server
741 10 Oct 06 olle 27 //  Copyright (C) 2002-2005 Omid Rouhani
741 10 Oct 06 olle 28 //
741 10 Oct 06 olle 29 //
741 10 Oct 06 olle 30 //  This program is free software; you can redistribute it and/or
741 10 Oct 06 olle 31 //  modify it under the terms of the GNU General Public License
741 10 Oct 06 olle 32 //  as published by the Free Software Foundation; either version 2
741 10 Oct 06 olle 33 //  of the License, or (at your option) any later version.
741 10 Oct 06 olle 34 //
741 10 Oct 06 olle 35 //  This program is distributed in the hope that it will be useful,
741 10 Oct 06 olle 36 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
741 10 Oct 06 olle 37 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
741 10 Oct 06 olle 38 //  GNU General Public License for more details.
741 10 Oct 06 olle 39 //
741 10 Oct 06 olle 40 //  You should have received a copy of the GNU General Public License
741 10 Oct 06 olle 41 //  along with this program; if not, write to the Free Software
741 10 Oct 06 olle 42 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
741 10 Oct 06 olle 43 //
741 10 Oct 06 olle 44 //
741 10 Oct 06 olle 45 //  #############################################################
741 10 Oct 06 olle 46 //  ##  YOU CAN CONTACT THE AUTHOR (OMID ROUHANI) AT:          ##
741 10 Oct 06 olle 47 //  ##  HTTP://WWW.JAVASCRIPT.NU/XERVER/                       ##
741 10 Oct 06 olle 48 //  ##                                                         ##
741 10 Oct 06 olle 49 //  ##  IF YOUR SOFTWARE IS NOT RELEASED UNDER THE             ##
741 10 Oct 06 olle 50 //  ##  GNU GENERAL PUBLIC LICENSE (GPL),                      ##
741 10 Oct 06 olle 51 //  ##  PLEASE DO NOT COPY ANYTHING FROM THIS SOURCE CODE!!!   ##
741 10 Oct 06 olle 52 //  ##                                                         ##
741 10 Oct 06 olle 53 //  ##  FOR FULL LICENSE, PLEASE READ "XERVER LICENSE".        ##
741 10 Oct 06 olle 54 //  #############################################################
741 10 Oct 06 olle 55
1652 22 May 07 gregory 56 package se.lu.thep.coreftpd.webserver;
741 10 Oct 06 olle 57
741 10 Oct 06 olle 58 import java.io.DataOutputStream;
741 10 Oct 06 olle 59 import java.io.IOException;
741 10 Oct 06 olle 60 import java.io.OutputStream;
741 10 Oct 06 olle 61
741 10 Oct 06 olle 62 /**
1652 22 May 07 gregory 63  * 
1652 22 May 07 gregory 64  * <B>About this class:</B> <BR>
741 10 Oct 06 olle 65  * <CODE>ChunkedDataOutputStream</CODE> is similar to a <CODE>DataOutputStream</CODE>,
1652 22 May 07 gregory 66  * but a new "writeBytes(String str, boolean bufferData)" method has been
1652 22 May 07 gregory 67  * created. <BR>
1652 22 May 07 gregory 68  * <CODE>ChunkedDataOutputStream</CODE> has an internal buffer and it waits
1652 22 May 07 gregory 69  * until the buffer is large enough (how large is defined in <CODE>i_maxBufferSize</CODE>)
1652 22 May 07 gregory 70  * before it sends the data. Note that this sends the data "chunked", as it is
1652 22 May 07 gregory 71  * defined in HTTP/1.1, which means that it won't send only the data given as
1652 22 May 07 gregory 72  * argument <CODE>str</CODE>, but also send some "\r\n" and the buffer size.
1652 22 May 07 gregory 73  * This is useful when we don't have the Content-Length of the data we want to
1652 22 May 07 gregory 74  * send, for example during a directory listing. <BR>
1652 22 May 07 gregory 75  * Note: If the constructor gets <CODE>argUseChunkedFeatures==false</CODE>,
1652 22 May 07 gregory 76  * <CODE>ChunkedDataOutputStream</CODE> will work exactly like <CODE>DataOutputStream</CODE>.
741 10 Oct 06 olle 77  * <BR>
1652 22 May 07 gregory 78  * finalizeDataTransfer() MUST be called when the last piece of data has been
1652 22 May 07 gregory 79  * sent.
1652 22 May 07 gregory 80  * 
741 10 Oct 06 olle 81  * @author <a href="http://www.JavaScript.nu/xerver/" TARGET="_top">Omid Rouhani</a>
741 10 Oct 06 olle 82  * @version 1.0
741 10 Oct 06 olle 83  */
741 10 Oct 06 olle 84
1652 22 May 07 gregory 85 final public class ChunkedDataOutputStream extends DataOutputStream {
1652 22 May 07 gregory 86   private StringBuffer bufString;
741 10 Oct 06 olle 87
1652 22 May 07 gregory 88   private final static int i_maxBufferSize = 5000;
1652 22 May 07 gregory 89
1652 22 May 07 gregory 90   private boolean b_useChunkedFeatures; // Iff this is false
1652 22 May 07 gregory 91                       // ChunkedDataOutputStream will work
1652 22 May 07 gregory 92                       // exactly as a DataOutputStream,
1652 22 May 07 gregory 93                       // otherwise ChunkedDataOutputStream
1652 22 May 07 gregory 94                       // will be used to buffer data and
1652 22 May 07 gregory 95                       // send it "chunked", as it is
1652 22 May 07 gregory 96                       // defined in HTTP/1.1. (This is
1652 22 May 07 gregory 97                       // useful when we don't have the
1652 22 May 07 gregory 98                       // Content-Length of the data we
1652 22 May 07 gregory 99                       // want to send, for example during
1652 22 May 07 gregory 100                       // a directory listing)
1652 22 May 07 gregory 101
741 10 Oct 06 olle 102   private boolean b_logThisHit;
1652 22 May 07 gregory 103
1652 22 May 07 gregory 104   /**
1652 22 May 07 gregory 105    * If argUseChunkedFeatures==false ChunkedDataOutputStream is equivalent to
1652 22 May 07 gregory 106    * DataOutputStream. If argUseChunkedFeatures==false you can use this class
1652 22 May 07 gregory 107    * to send "chunked" data, as it is defined in HTTP/1.1.
1652 22 May 07 gregory 108    */
1652 22 May 07 gregory 109   ChunkedDataOutputStream(OutputStream out, boolean argUseChunkedFeatures,
1652 22 May 07 gregory 110       boolean argLogThisHit) {
741 10 Oct 06 olle 111     super(out);
1652 22 May 07 gregory 112     bufString = new StringBuffer(i_maxBufferSize);
1652 22 May 07 gregory 113     b_useChunkedFeatures = argUseChunkedFeatures;
1652 22 May 07 gregory 114     b_logThisHit = argLogThisHit;
741 10 Oct 06 olle 115   }
741 10 Oct 06 olle 116
1652 22 May 07 gregory 117   /**
1652 22 May 07 gregory 118    * When you send the HTTP-headers use bufferData==false, which will make
1652 22 May 07 gregory 119    * this method to work exactly as writeBytes(str) defined in
1652 22 May 07 gregory 120    * DataOutputStream. When bufferData==false then writeBytes(str) defined in
1652 22 May 07 gregory 121    * DataOutputStream will be used, no matter if there already exists a
1652 22 May 07 gregory 122    * buffer. You can use this if you want to send some piece of data before
1652 22 May 07 gregory 123    * the current buffer is sent. In all other cases bufferData must be true to
1652 22 May 07 gregory 124    * use the buffer which this class is using.
1652 22 May 07 gregory 125    */
1652 22 May 07 gregory 126   public synchronized void writeBytes(String str, boolean bufferData)
1652 22 May 07 gregory 127       throws IOException {
1652 22 May 07 gregory 128     if (bufferData && b_useChunkedFeatures) {
741 10 Oct 06 olle 129       bufString.append(str);
741 10 Oct 06 olle 130
1652 22 May 07 gregory 131       if (bufString.length() > i_maxBufferSize) {
741 10 Oct 06 olle 132         sendChunkedData();
741 10 Oct 06 olle 133       }
1652 22 May 07 gregory 134     } else {
1652 22 May 07 gregory 135       super.writeBytes(str); // writeUTF?
741 10 Oct 06 olle 136     }
741 10 Oct 06 olle 137   }
741 10 Oct 06 olle 138
1652 22 May 07 gregory 139   /**
1652 22 May 07 gregory 140    * This can be called at any time and will send what is left in the buffer.
1652 22 May 07 gregory 141    * Note that it's recommended to call finalizeDataTransfer() when you are
1652 22 May 07 gregory 142    * done sending data. finalizeDataTransfer() will call on flush.
1652 22 May 07 gregory 143    */
2386 14 Nov 07 gregory 144   @Override
1652 22 May 07 gregory 145   public synchronized void flush() throws IOException {
1652 22 May 07 gregory 146     // The format of "Transfer-Encoding: chunked\r\n" is:
1652 22 May 07 gregory 147     if (bufString.length() > 0 && b_useChunkedFeatures) {
741 10 Oct 06 olle 148       sendChunkedData();
741 10 Oct 06 olle 149     }
741 10 Oct 06 olle 150     super.flush();
741 10 Oct 06 olle 151   }
741 10 Oct 06 olle 152
1652 22 May 07 gregory 153   /**
1652 22 May 07 gregory 154    * This method sends the data chunked. <CODE>Flush()</CODE> and <CODE>writeBytes()</CODE>
1652 22 May 07 gregory 155    * will call this method when necessary.
1652 22 May 07 gregory 156    */
1652 22 May 07 gregory 157   private void sendChunkedData() throws IOException {
1652 22 May 07 gregory 158     int i_sizeOfDataToSend = bufString.length();
1652 22 May 07 gregory 159     // The format of "Transfer-Encoding: chunked\r\n" is:
1652 22 May 07 gregory 160     super.writeBytes(Integer.toHexString(i_sizeOfDataToSend)); // First
1652 22 May 07 gregory 161                                   // write
1652 22 May 07 gregory 162                                   // length of
1652 22 May 07 gregory 163                                   // buffer in
1652 22 May 07 gregory 164                                   // hexadecimal
1652 22 May 07 gregory 165                                   // chars
1652 22 May 07 gregory 166     super.writeBytes("\r\n"); // Then write \r\n
1652 22 May 07 gregory 167     super.writeBytes(bufString.toString()); // Then write the buffer
1652 22 May 07 gregory 168     super.writeBytes("\r\n"); // Then write \r\n
1652 22 May 07 gregory 169     bufString = new StringBuffer(i_maxBufferSize);
741 10 Oct 06 olle 170
741 10 Oct 06 olle 171     if (b_logThisHit)
1652 22 May 07 gregory 172       NewConnection.totalNumberOfBytesDownloaded += i_sizeOfDataToSend;
741 10 Oct 06 olle 173   }
741 10 Oct 06 olle 174
1652 22 May 07 gregory 175   /**
1652 22 May 07 gregory 176    * This should be called ONCE per each HTTP-respond. After this has been
1652 22 May 07 gregory 177    * called, don't call "writeBytes" any more. (or the data won't be sent
1652 22 May 07 gregory 178    * according to a correct HTTP/1.1 standard) This Method calls on flush(),
1652 22 May 07 gregory 179    * so you don't need to call flush() after you called this method. There
1652 22 May 07 gregory 180    * will however be no problems if you can flush() after this, but it's
1652 22 May 07 gregory 181    * unnecessary.
1652 22 May 07 gregory 182    */
1652 22 May 07 gregory 183   public synchronized void finalizeDataTransfer() throws IOException {
1652 22 May 07 gregory 184     if (b_useChunkedFeatures) {
1652 22 May 07 gregory 185       flush();// Send what is left in the buffer...
1652 22 May 07 gregory 186       super.writeBytes("0\r\n\r\n");// Then send a "zero-sized" chunk
1652 22 May 07 gregory 187                       // ending this transfer...
741 10 Oct 06 olle 188
741 10 Oct 06 olle 189       if (b_logThisHit)
1652 22 May 07 gregory 190         NewConnection.totalNumberOfBytesDownloaded += 5; // Size of
1652 22 May 07 gregory 191                                   // "0\r\n\r\n"
741 10 Oct 06 olle 192     }
1652 22 May 07 gregory 193     super.flush();// Now flush to make sure the "0\r\n" above has been
1652 22 May 07 gregory 194             // sent...
741 10 Oct 06 olle 195   }
741 10 Oct 06 olle 196 }