741 |
10 Oct 06 |
olle |
1 |
/* |
1652 |
22 May 07 |
gregory |
$Id$ |
741 |
10 Oct 06 |
olle |
3 |
|
1916 |
31 Aug 07 |
jari |
Copyright (C) 2006 Olle Mansson |
1916 |
31 Aug 07 |
jari |
Copyright (C) 2007 Gregory Vincic |
741 |
10 Oct 06 |
olle |
6 |
|
1652 |
22 May 07 |
gregory |
This file is part of Proteios. |
1652 |
22 May 07 |
gregory |
Available at http://www.proteios.org/ |
741 |
10 Oct 06 |
olle |
9 |
|
1652 |
22 May 07 |
gregory |
Proteios is free software; you can redistribute it and/or modify it |
1652 |
22 May 07 |
gregory |
under the terms of the GNU General Public License as published by |
1652 |
22 May 07 |
gregory |
the Free Software Foundation; either version 2 of the License, or |
1652 |
22 May 07 |
gregory |
(at your option) any later version. |
741 |
10 Oct 06 |
olle |
14 |
|
1652 |
22 May 07 |
gregory |
Proteios is distributed in the hope that it will be useful, but |
1652 |
22 May 07 |
gregory |
WITHOUT ANY WARRANTY; without even the implied warranty of |
1652 |
22 May 07 |
gregory |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1652 |
22 May 07 |
gregory |
General Public License for more details. |
741 |
10 Oct 06 |
olle |
19 |
|
1652 |
22 May 07 |
gregory |
You should have received a copy of the GNU General Public License |
1652 |
22 May 07 |
gregory |
along with this program; if not, write to the Free Software |
1652 |
22 May 07 |
gregory |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
1652 |
22 May 07 |
gregory |
02111-1307, USA. |
1652 |
22 May 07 |
gregory |
24 |
*/ |
741 |
10 Oct 06 |
olle |
25 |
|
741 |
10 Oct 06 |
olle |
// Xerver Free Web Server |
741 |
10 Oct 06 |
olle |
// Copyright (C) 2002-2005 Omid Rouhani |
741 |
10 Oct 06 |
olle |
28 |
// |
741 |
10 Oct 06 |
olle |
29 |
// |
741 |
10 Oct 06 |
olle |
// This program is free software; you can redistribute it and/or |
741 |
10 Oct 06 |
olle |
// modify it under the terms of the GNU General Public License |
741 |
10 Oct 06 |
olle |
// as published by the Free Software Foundation; either version 2 |
741 |
10 Oct 06 |
olle |
// of the License, or (at your option) any later version. |
741 |
10 Oct 06 |
olle |
34 |
// |
741 |
10 Oct 06 |
olle |
// This program is distributed in the hope that it will be useful, |
741 |
10 Oct 06 |
olle |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
741 |
10 Oct 06 |
olle |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
741 |
10 Oct 06 |
olle |
// GNU General Public License for more details. |
741 |
10 Oct 06 |
olle |
39 |
// |
741 |
10 Oct 06 |
olle |
// You should have received a copy of the GNU General Public License |
741 |
10 Oct 06 |
olle |
// along with this program; if not, write to the Free Software |
741 |
10 Oct 06 |
olle |
// 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 |
// ## YOU CAN CONTACT THE AUTHOR (OMID ROUHANI) AT: ## |
741 |
10 Oct 06 |
olle |
// ## HTTP://WWW.JAVASCRIPT.NU/XERVER/ ## |
741 |
10 Oct 06 |
olle |
48 |
// ## ## |
741 |
10 Oct 06 |
olle |
// ## IF YOUR SOFTWARE IS NOT RELEASED UNDER THE ## |
741 |
10 Oct 06 |
olle |
// ## GNU GENERAL PUBLIC LICENSE (GPL), ## |
741 |
10 Oct 06 |
olle |
// ## PLEASE DO NOT COPY ANYTHING FROM THIS SOURCE CODE!!! ## |
741 |
10 Oct 06 |
olle |
52 |
// ## ## |
741 |
10 Oct 06 |
olle |
// ## 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 |
* <B>About this class:</B> <BR> |
741 |
10 Oct 06 |
olle |
* <CODE>ChunkedDataOutputStream</CODE> is similar to a <CODE>DataOutputStream</CODE>, |
1652 |
22 May 07 |
gregory |
* but a new "writeBytes(String str, boolean bufferData)" method has been |
1652 |
22 May 07 |
gregory |
* created. <BR> |
1652 |
22 May 07 |
gregory |
* <CODE>ChunkedDataOutputStream</CODE> has an internal buffer and it waits |
1652 |
22 May 07 |
gregory |
* until the buffer is large enough (how large is defined in <CODE>i_maxBufferSize</CODE>) |
1652 |
22 May 07 |
gregory |
* before it sends the data. Note that this sends the data "chunked", as it is |
1652 |
22 May 07 |
gregory |
* defined in HTTP/1.1, which means that it won't send only the data given as |
1652 |
22 May 07 |
gregory |
* argument <CODE>str</CODE>, but also send some "\r\n" and the buffer size. |
1652 |
22 May 07 |
gregory |
* This is useful when we don't have the Content-Length of the data we want to |
1652 |
22 May 07 |
gregory |
* send, for example during a directory listing. <BR> |
1652 |
22 May 07 |
gregory |
* Note: If the constructor gets <CODE>argUseChunkedFeatures==false</CODE>, |
1652 |
22 May 07 |
gregory |
* <CODE>ChunkedDataOutputStream</CODE> will work exactly like <CODE>DataOutputStream</CODE>. |
741 |
10 Oct 06 |
olle |
* <BR> |
1652 |
22 May 07 |
gregory |
* finalizeDataTransfer() MUST be called when the last piece of data has been |
1652 |
22 May 07 |
gregory |
* sent. |
1652 |
22 May 07 |
gregory |
80 |
* |
741 |
10 Oct 06 |
olle |
* @author <a href="http://www.JavaScript.nu/xerver/" TARGET="_top">Omid Rouhani</a> |
741 |
10 Oct 06 |
olle |
* @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 |
// ChunkedDataOutputStream will work |
1652 |
22 May 07 |
gregory |
// exactly as a DataOutputStream, |
1652 |
22 May 07 |
gregory |
// otherwise ChunkedDataOutputStream |
1652 |
22 May 07 |
gregory |
// will be used to buffer data and |
1652 |
22 May 07 |
gregory |
// send it "chunked", as it is |
1652 |
22 May 07 |
gregory |
// defined in HTTP/1.1. (This is |
1652 |
22 May 07 |
gregory |
// useful when we don't have the |
1652 |
22 May 07 |
gregory |
// Content-Length of the data we |
1652 |
22 May 07 |
gregory |
// want to send, for example during |
1652 |
22 May 07 |
gregory |
// 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 |
* If argUseChunkedFeatures==false ChunkedDataOutputStream is equivalent to |
1652 |
22 May 07 |
gregory |
* DataOutputStream. If argUseChunkedFeatures==false you can use this class |
1652 |
22 May 07 |
gregory |
* 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 |
* When you send the HTTP-headers use bufferData==false, which will make |
1652 |
22 May 07 |
gregory |
* this method to work exactly as writeBytes(str) defined in |
1652 |
22 May 07 |
gregory |
* DataOutputStream. When bufferData==false then writeBytes(str) defined in |
1652 |
22 May 07 |
gregory |
* DataOutputStream will be used, no matter if there already exists a |
1652 |
22 May 07 |
gregory |
* buffer. You can use this if you want to send some piece of data before |
1652 |
22 May 07 |
gregory |
* the current buffer is sent. In all other cases bufferData must be true to |
1652 |
22 May 07 |
gregory |
* 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 |
* This can be called at any time and will send what is left in the buffer. |
1652 |
22 May 07 |
gregory |
* Note that it's recommended to call finalizeDataTransfer() when you are |
1652 |
22 May 07 |
gregory |
* 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 |
// 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 |
* This method sends the data chunked. <CODE>Flush()</CODE> and <CODE>writeBytes()</CODE> |
1652 |
22 May 07 |
gregory |
* 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 |
// 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 |
// write |
1652 |
22 May 07 |
gregory |
// length of |
1652 |
22 May 07 |
gregory |
// buffer in |
1652 |
22 May 07 |
gregory |
// hexadecimal |
1652 |
22 May 07 |
gregory |
// 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 |
* This should be called ONCE per each HTTP-respond. After this has been |
1652 |
22 May 07 |
gregory |
* called, don't call "writeBytes" any more. (or the data won't be sent |
1652 |
22 May 07 |
gregory |
* according to a correct HTTP/1.1 standard) This Method calls on flush(), |
1652 |
22 May 07 |
gregory |
* so you don't need to call flush() after you called this method. There |
1652 |
22 May 07 |
gregory |
* will however be no problems if you can flush() after this, but it's |
1652 |
22 May 07 |
gregory |
* 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 |
// 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 |
// "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 |
// sent... |
741 |
10 Oct 06 |
olle |
195 |
} |
741 |
10 Oct 06 |
olle |
196 |
} |