Edit D:\app\Administrator\product\11.2.0\dbhome_1\owb\lib\int\HTTPClient\HttpOutputStream.java
/* * @(#)HttpOutputStream.java 0.3-3 06/05/2001 * * This file is part of the HTTPClient package * Copyright (C) 1996-2001 Ronald Tschal? * * 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 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, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA * * For questions, suggestions, bug-reports, enhancement-requests etc. * I may be contacted at: * * ronald@innovation.ch * * The HTTPClient's home page is located at: * * http://www.innovation.ch/java/HTTPClient/ * */ package HTTPClient; import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; /** * This class provides an output stream for requests. The stream must first * be associated with a request before it may be used; this is done by * passing it to one of the request methods in HTTPConnection. Example: * <PRE> * OutputStream out = new HttpOutputStream(12345); * rsp = con.Post("/cgi-bin/my_cgi", out); * out.write(...); * out.close(); * if (rsp.getStatusCode() >= 300) * ... * </PRE> * * <P>There are two constructors for this class, one taking a length parameter, * and one without any parameters. If the stream is created with a length * then the request will be sent with the corresponding Content-length header * and anything written to the stream will be written on the socket immediately. * This is the preferred way. If the stream is created without a length then * one of two things will happen: if, at the time of the request, the server * is known to understand HTTP/1.1 then each write() will send the data * immediately using the chunked encoding. If, however, either the server * version is unknown (because this is first request to that server) or the * server only understands HTTP/1.0 then all data will be written to a buffer * first, and only when the stream is closed will the request be sent. * * <P>Another reason that using the <var>HttpOutputStream(length)</var> * constructor is recommended over the <var>HttpOutputStream()</var> one is * that some HTTP/1.1 servers do not allow the chunked transfer encoding to * be used when POSTing to a cgi script. This is because the way the cgi API * is defined the cgi script expects a Content-length environment variable. * If the data is sent using the chunked transfer encoding however, then the * server would have to buffer all the data before invoking the cgi so that * this variable could be set correctly. Not all servers are willing to do * this. * * <P>If you cannot use the <var>HttpOutputStream(length)</var> constructor and * are having problems sending requests (usually a 411 response) then you can * try setting the system property <var>HTTPClient.dontChunkRequests</var> to * <var>true</var> (this needs to be done either on the command line or * somewhere in the code before the HTTPConnection is first accessed). This * will prevent the client from using the chunked encoding in this case and * will cause the HttpOutputStream to buffer all the data instead, sending it * only when close() is invoked. * * <P>The behaviour of a request sent with an output stream may differ from * that of a request sent with a data parameter. The reason for this is that * the various modules cannot resend a request which used an output stream. * Therefore such things as authorization and retrying of requests won't be * done by the HTTPClient for such requests. But see {@link * HTTPResponse#retryRequest() HTTPResponse.retryRequest} for a partial * solution. * * @version 0.3-3 06/05/2001 * @author Ronald Tschal? * @since V0.3 */ public class HttpOutputStream extends OutputStream { /** null trailers */ private static final NVPair[] empty = new NVPair[0]; /** the length of the data to be sent */ private int length; /** the length of the data received so far */ private int rcvd = 0; /** the request this stream is associated with */ private Request req = null; /** the response from sendRequest if we stalled the request */ private Response resp = null; /** the socket output stream */ private OutputStream os = null; /** the buffer to be used if needed */ private ByteArrayOutputStream bos = null; /** the trailers to send if using chunked encoding. */ private NVPair[] trailers = empty; /** the timeout to pass to SendRequest() */ private int con_to = 0; /** just ignore all the data if told to do so */ private boolean ignore = false; // Constructors /** * Creates an output stream of unspecified length. Note that it is * <strong>highly</strong> recommended that this constructor be avoided * where possible and <code>HttpOutputStream(int)</code> used instead. * * @see HttpOutputStream#HttpOutputStream(int) */ public HttpOutputStream() { length = -1; } /** * This creates an output stream which will take <var>length</var> bytes * of data. * * @param length the number of bytes which will be sent over this stream */ public HttpOutputStream(int length) { if (length < 0) throw new IllegalArgumentException("Length must be greater equal 0"); this.length = length; } // Methods /** * Associates this stream with a request and the actual output stream. * No other methods in this class may be invoked until this method has * been invoked by the HTTPConnection. * * @param req the request this stream is to be associated with * @param os the underlying output stream to write our data to, or null * if we should write to a ByteArrayOutputStream instead. * @param con_to connection timeout to use in sendRequest() */ void goAhead(Request req, OutputStream os, int con_to) { this.req = req; this.os = os; this.con_to = con_to; if (os == null) bos = new ByteArrayOutputStream(); Log.write(Log.CONN, "OutS: Stream ready for writing"); if (bos != null) Log.write(Log.CONN, "OutS: Buffering all data before sending " + "request"); } /** * Setup this stream to dump the data to the great bit-bucket in the sky. * This is needed for when a module handles the request directly. * * @param req the request this stream is to be associated with */ void ignoreData(Request req) { this.req = req; ignore = true; } /** * Return the response we got from sendRequest(). This waits until * the request has actually been sent. * * @return the response returned by sendRequest() */ synchronized Response getResponse() { while (resp == null) try { wait(); } catch (InterruptedException ie) { } return resp; } /** * Returns the number of bytes this stream is willing to accept, or -1 * if it is unbounded. * * @return the number of bytes */ public int getLength() { return length; } /** * Gets the trailers which were set with <code>setTrailers()</code>. * * @return an array of header fields * @see #setTrailers(HTTPClient.NVPair[]) */ public NVPair[] getTrailers() { return trailers; } /** * Sets the trailers to be sent if the output is sent with the * chunked transfer encoding. These must be set before the output * stream is closed for them to be sent. * * <P>Any trailers set here <strong>should</strong> be mentioned * in a <var>Trailer</var> header in the request (see section 14.40 * of draft-ietf-http-v11-spec-rev-06.txt). * * <P>This method (and its related <code>getTrailers()</code>)) are * in this class and not in <var>Request</var> because setting * trailers is something an application may want to do, not only * modules. * * @param trailers an array of header fields */ public void setTrailers(NVPair[] trailers) { if (trailers != null) this.trailers = trailers; else this.trailers = empty; } /** * Reset this output stream, so it may be reused in a retried request. * This method may only be invoked by modules, and <strong>must</strong> * never be invoked by an application. */ public void reset() { rcvd = 0; req = null; resp = null; os = null; bos = null; con_to = 0; ignore = false; } /** * Writes a single byte on the stream. It is subject to the same rules * as <code>write(byte[], int, int)</code>. * * @param b the byte to write * @exception IOException if any exception is thrown by the socket * @see #write(byte[], int, int) */ public void write(int b) throws IOException, IllegalAccessError { byte[] tmp = { (byte) b }; write(tmp, 0, 1); } /** * Writes an array of bytes on the stream. This method may not be used * until this stream has been passed to one of the methods in * HTTPConnection (i.e. until it has been associated with a request). * * @param buf an array containing the data to write * @param off the offset of the data whithin the buffer * @param len the number bytes (starting at <var>off</var>) to write * @exception IOException if any exception is thrown by the socket, or * if writing <var>len</var> bytes would cause more bytes to * be written than this stream is willing to accept. * @exception IllegalAccessError if this stream has not been associated * with a request yet */ public synchronized void write(byte[] buf, int off, int len) throws IOException, IllegalAccessError { if (req == null) throw new IllegalAccessError("Stream not associated with a request"); if (ignore) return; if (length != -1 && rcvd+len > length) { IOException ioe = new IOException("Tried to write too many bytes (" + (rcvd+len) + " > " + length + ")"); req.getConnection().closeDemux(ioe, false); req.getConnection().outputFinished(); throw ioe; } try { if (bos != null) bos.write(buf, off, len); else if (length != -1) os.write(buf, off, len); else os.write(Codecs.chunkedEncode(buf, off, len, null, false)); } catch (IOException ioe) { req.getConnection().closeDemux(ioe, true); req.getConnection().outputFinished(); throw ioe; } rcvd += len; } /** * Closes the stream and causes the data to be sent if it has not already * been done so. This method <strong>must</strong> be invoked when all * data has been written. * * @exception IOException if any exception is thrown by the underlying * socket, or if too few bytes were written. * @exception IllegalAccessError if this stream has not been associated * with a request yet. */ public synchronized void close() throws IOException, IllegalAccessError { if (req == null) throw new IllegalAccessError("Stream not associated with a request"); if (ignore) return; if (bos != null) { req.setData(bos.toByteArray()); req.setStream(null); if (trailers.length > 0) { NVPair[] hdrs = req.getHeaders(); // remove any Trailer header field int len = hdrs.length; for (int idx=0; idx<len; idx++) { if (hdrs[idx].getName().equalsIgnoreCase("Trailer")) { System.arraycopy(hdrs, idx+1, hdrs, idx, len-idx-1); len--; } } // add the trailers to the headers hdrs = Util.resizeArray(hdrs, len+trailers.length); System.arraycopy(trailers, 0, hdrs, len, trailers.length); req.setHeaders(hdrs); } Log.write(Log.CONN, "OutS: Sending request"); try { resp = req.getConnection().sendRequest(req, con_to); } catch (ModuleException me) { throw new IOException(me.toString()); } notify(); } else { if (rcvd < length) { IOException ioe = new IOException("Premature close: only " + rcvd + " bytes written instead of the " + "expected " + length); req.getConnection().closeDemux(ioe, false); req.getConnection().outputFinished(); throw ioe; } try { if (length == -1) { if (Log.isEnabled(Log.CONN) && trailers.length > 0) { Log.write(Log.CONN, "OutS: Sending trailers:"); for (int idx=0; idx<trailers.length; idx++) Log.write(Log.CONN, " " + trailers[idx].getName() + ": " + trailers[idx].getValue()); } os.write(Codecs.chunkedEncode(null, 0, 0, trailers, true)); } os.flush(); Log.write(Log.CONN, "OutS: All data sent"); } catch (IOException ioe) { req.getConnection().closeDemux(ioe, true); throw ioe; } finally { req.getConnection().outputFinished(); } } } /** * produces a string describing this stream. * * @return a string containing the name and the length */ public String toString() { return getClass().getName() + "[length=" + length + "]"; } }
Ms-Dos/Windows
Unix
Write backup
jsp File Browser version 1.2 by
www.vonloesch.de