/** * 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); } if (DebugConn) System.err.println("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 (DebugConn && trailers.length > 0) { System.err.println("OutS: Sending trailers:"); for (int idx = 0; idx < trailers.length; idx++) System.err.println( " " + trailers[idx].getName() + ": " + trailers[idx].getValue()); } os.write(Codecs.chunkedEncode(null, 0, 0, trailers, true)); } os.flush(); if (DebugConn) System.err.println("OutS: All data sent"); } catch (IOException ioe) { req.getConnection().closeDemux(ioe, true); throw ioe; } finally { req.getConnection().outputFinished(); } } }