📄 multipartstream.java
字号:
* application. * * <p><strong>TODO</strong> allow limiting maximum header size to * protect against abuse. * * @return The <code>header-part</code> of the current encapsulation. * * @throws MalformedStreamException if the stream ends unexpecetedly. */ public String readHeaders() throws MalformedStreamException { int i = 0; byte[] b = new byte[1]; // to support multi-byte characters ByteArrayOutputStream baos = new ByteArrayOutputStream(); int sizeMax = HEADER_PART_SIZE_MAX; int size = 0; while (i < HEADER_SEPARATOR.length) { try { b[0] = readByte(); } catch (IOException e) { throw new MalformedStreamException("Stream ended unexpectedly"); } size++; if (b[0] == HEADER_SEPARATOR[i]) { i++; } else { i = 0; } if (size <= sizeMax) { baos.write(b[0]); } } String headers = null; if (headerEncoding != null) { try { headers = baos.toString(headerEncoding); } catch (UnsupportedEncodingException e) { // Fall back to platform default if specified encoding is not // supported. headers = baos.toString(); } } else { headers = baos.toString(); } return headers; } /** * <p>Reads <code>body-data</code> from the current * <code>encapsulation</code> and writes its contents into the * output <code>Stream</code>. * * <p>Arbitrary large amounts of data can be processed by this * method using a constant size buffer. (see {@link * #MultipartStream(InputStream,byte[],int) constructor}). * * @param output The <code>Stream</code> to write data into. * * @return the amount of data written. * * @throws MalformedStreamException if the stream ends unexpectedly. * @throws IOException if an i/o error occurs. */ public int readBodyData(OutputStream output) throws MalformedStreamException, IOException { boolean done = false; int pad; int pos; int bytesRead; int total = 0; while (!done) { // Is boundary token present somewere in the buffer? pos = findSeparator(); if (pos != -1) { // Write the rest of the data before the boundary. output.write(buffer, head, pos - head); total += pos - head; head = pos; done = true; } else { // Determine how much data should be kept in the // buffer. if (tail - head > keepRegion) { pad = keepRegion; } else { pad = tail - head; } // Write out the data belonging to the body-data. output.write(buffer, head, tail - head - pad); // Move the data to the beginning of the buffer. total += tail - head - pad; System.arraycopy(buffer, tail - pad, buffer, 0, pad); // Refill buffer with new data. head = 0; bytesRead = input.read(buffer, pad, bufSize - pad); // [pprrrrrrr] if (bytesRead != -1) { tail = pad + bytesRead; } else { // The last pad amount is left in the buffer. // Boundary can't be in there so write out the // data you have and signal an error condition. output.write(buffer, 0, pad); output.flush(); total += pad; throw new MalformedStreamException( "Stream ended unexpectedly"); } } } output.flush(); return total; } /** * <p> Reads <code>body-data</code> from the current * <code>encapsulation</code> and discards it. * * <p>Use this method to skip encapsulations you don't need or don't * understand. * * @return The amount of data discarded. * * @throws MalformedStreamException if the stream ends unexpectedly. * @throws IOException if an i/o error occurs. */ public int discardBodyData() throws MalformedStreamException, IOException { boolean done = false; int pad; int pos; int bytesRead; int total = 0; while (!done) { // Is boundary token present somewere in the buffer? pos = findSeparator(); if (pos != -1) { // Write the rest of the data before the boundary. total += pos - head; head = pos; done = true; } else { // Determine how much data should be kept in the // buffer. if (tail - head > keepRegion) { pad = keepRegion; } else { pad = tail - head; } total += tail - head - pad; // Move the data to the beginning of the buffer. System.arraycopy(buffer, tail - pad, buffer, 0, pad); // Refill buffer with new data. head = 0; bytesRead = input.read(buffer, pad, bufSize - pad); // [pprrrrrrr] if (bytesRead != -1) { tail = pad + bytesRead; } else { // The last pad amount is left in the buffer. // Boundary can't be in there so signal an error // condition. total += pad; throw new MalformedStreamException( "Stream ended unexpectedly"); } } } return total; } /** * Finds the beginning of the first <code>encapsulation</code>. * * @return <code>true</code> if an <code>encapsulation</code> was found in * the stream. * * @throws IOException if an i/o error occurs. */ public boolean skipPreamble() throws IOException { // First delimiter may be not preceeded with a CRLF. System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); boundaryLength = boundary.length - 2; try { // Discard all data up to the delimiter. discardBodyData(); // Read boundary - if succeded, the stream contains an // encapsulation. return readBoundary(); } catch (MalformedStreamException e) { return false; } finally { // Restore delimiter. System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2); boundaryLength = boundary.length; boundary[0] = CR; boundary[1] = LF; } } /** * Compares <code>count</code> first bytes in the arrays * <code>a</code> and <code>b</code>. * * @param a The first array to compare. * @param b The second array to compare. * @param count How many bytes should be compared. * * @return <code>true</code> if <code>count</code> first bytes in arrays * <code>a</code> and <code>b</code> are equal. */ public static boolean arrayequals(byte[] a, byte[] b, int count) { for (int i = 0; i < count; i++) { if (a[i] != b[i]) { return false; } } return true; } /** * Searches for a byte of specified value in the <code>buffer</code>, * starting at the specified <code>position</code>. * * @param value The value to find. * @param pos The starting position for searching. * * @return The position of byte found, counting from beginning of the * <code>buffer</code>, or <code>-1</code> if not found. */ protected int findByte(byte value, int pos) { for (int i = pos; i < tail; i++) { if (buffer[i] == value) { return i; } } return -1; } /** * Searches for the <code>boundary</code> in the <code>buffer</code> * region delimited by <code>head</code> and <code>tail</code>. * * @return The position of the boundary found, counting from the * beginning of the <code>buffer</code>, or <code>-1</code> if * not found. */ protected int findSeparator() { int first; int match = 0; int maxpos = tail - boundaryLength; for (first = head; (first <= maxpos) && (match != boundaryLength); first++) { first = findByte(boundary[0], first); if (first == -1 || (first > maxpos)) { return -1; } for (match = 1; match < boundaryLength; match++) { if (buffer[first + match] != boundary[match]) { break; } } } if (match == boundaryLength) { return first - 1; } return -1; } /** * Returns a string representation of this object. * * @return The string representation of this object. */ public String toString() { StringBuffer sbTemp = new StringBuffer(); sbTemp.append("boundary='"); sbTemp.append(String.valueOf(boundary)); sbTemp.append("'\nbufSize="); sbTemp.append(bufSize); return sbTemp.toString(); } /** * Thrown to indicate that the input stream fails to follow the * required syntax. */ public static class MalformedStreamException extends IOException { /** * Constructs a <code>MalformedStreamException</code> with no * detail message. */ public MalformedStreamException() { super(); } /** * Constructs an <code>MalformedStreamException</code> with * the specified detail message. * * @param message The detail message. */ public MalformedStreamException(String message) { super(message); } } /** * Thrown upon attempt of setting an invalid boundary token. */ public static class IllegalBoundaryException extends IOException { /** * Constructs an <code>IllegalBoundaryException</code> with no * detail message. */ public IllegalBoundaryException() { super(); } /** * Constructs an <code>IllegalBoundaryException</code> with * the specified detail message. * * @param message The detail message. */ public IllegalBoundaryException(String message) { super(message); } } // ------------------------------------------------------ Debugging methods // These are the methods that were used to debug this stuff. /* // Dump data. protected void dump() { System.out.println("01234567890"); byte[] temp = new byte[buffer.length]; for(int i=0; i<buffer.length; i++) { if (buffer[i] == 0x0D || buffer[i] == 0x0A) { temp[i] = 0x21; } else { temp[i] = buffer[i]; } } System.out.println(new String(temp)); int i; for (i=0; i<head; i++) System.out.print(" "); System.out.println("h"); for (i=0; i<tail; i++) System.out.print(" "); System.out.println("t"); System.out.flush(); } // Main routine, for testing purposes only. // // @param args A String[] with the command line arguments. // @throws Exception, a generic exception. public static void main( String[] args ) throws Exception { File boundaryFile = new File("boundary.dat"); int boundarySize = (int)boundaryFile.length(); byte[] boundary = new byte[boundarySize]; FileInputStream input = new FileInputStream(boundaryFile); input.read(boundary,0,boundarySize); input = new FileInputStream("multipart.dat"); MultipartStream chunks = new MultipartStream(input, boundary); int i = 0; String header; OutputStream output; boolean nextChunk = chunks.skipPreamble(); while (nextChunk) { header = chunks.readHeaders(); System.out.println("!"+header+"!"); System.out.println("wrote part"+i+".dat"); output = new FileOutputStream("part"+(i++)+".dat"); chunks.readBodyData(output); nextChunk = chunks.readBoundary(); } } */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -