📄 protocol.java
字号:
/** * Reads up to <code>len</code> bytes of data from the input stream into * an array of bytes. * This method reads NonChunked http connection input streams. * This method can only be called after the InputStream setup is complete. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ protected int readBytes(byte b[], int off, int len) throws IOException { int rc; /* * Be consistent about returning EOF once encountered. */ if (eof) { return (-1); } /* * The InputStream close behavior will be different if close is called * from another thread when reading. */ synchronized (streamInput) { readInProgress = true; } try { /* * If the http connection is chunked, call the readBytesChunked * method */ if (chunkedIn || chunksize > 0) { /* * Non-chunked data of known length is treated as one big chunk */ return readBytesChunked(b, off, len); } /* * Non-chunked unknown length */ if (bytesleft == 0) { /* * the internal input stream buffer is empty, read from the * stream */ if (len >= inputBufferSize) { /* * No need to buffer, if the caller has given a big buffer. */ rc = streamInput.read(b, off, len); } else { rc = streamInput.read(readbuf, 0, inputBufferSize); bytesleft = rc; bytesread = 0; } if (rc == -1) { /* * The next call to this method should not read. */ eof = true; return -1; } totalbytesread += rc; if (bytesleft == 0) { /* * The data was read directly into the caller's buffer. */ return rc; } } rc = readFromBuffer(b, off, len); return rc; } finally { synchronized (streamInput) { readInProgress = false; } } } /** * Reads up to <code>len</code> bytes of data from the internal buffer into * an array of bytes. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ private int readFromBuffer(byte b[], int off, int len) throws IOException { /* * copy http buffer data into user buffer, then * increment and decrement counters */ int rc; if (len > bytesleft) { rc = bytesleft; } else { rc = len; } System.arraycopy(readbuf, bytesread, b, off, rc); bytesleft -= rc; bytesread += rc; return rc; } /** * Returns the number of bytes that can be read (or skipped over) from * this input stream without blocking by the next caller of a method for * this input stream. The next caller might be the same thread or * another thread. * * @return the number of bytes that can be read from this input stream * without blocking. * @exception IOException if an I/O error occurs. */ public int available() throws IOException { int bytesAvailable; /* * Only after all the headers have been processed can * an accurate available count be provided. */ if (!requestFinished || eof) { return 0; } /* * Regardless of chunked or non-chunked transfers - * if data is already buffered return the amount * buffered. */ if (bytesleft > 0) { return bytesleft; } if (chunkedIn && totalbytesread == chunksize) { /* * Check if a new chunk size header is available. */ return readChunkSizeNonBlocking(); } /* * Otherwise rely on the lower level stream available * count for the nonchunked input stream. */ bytesAvailable = streamInput.available(); if (chunksize <= bytesAvailable) { return chunksize; } return bytesAvailable; } /** * Read a chunk size header into the readLine buffer * without blocking. The stringbuffer is populated * with characters one at a time. This routine is design * so that a partial chunk size header could be read * and then completed by a blocking read of the chunk * or a subsequent call to available. * * @return available data that can be read */ int readChunkSizeNonBlocking() throws IOException { /* * Check the underlying stream to see how many bytes are * available. Do not read beyond the available characters, * because that would block. */ int len = streamInput.available(); /* Reset the last character from the current readLine buffer. */ int sblen = stringbuffer.length(); char lastchar = '\0'; if (sblen > 0) { lastchar = stringbuffer.charAt(sblen - 1); } int size = -1; /* * Loop through the available characters until a full * chunk size header is in the readLine buffer. */ for (; len > 0; len--) { char c = (char) streamInput.read(); if (lastchar == '\r' && c == '\n') { // remove the '\r' from the buffer stringbuffer.setLength(stringbuffer.length() - 1); if (stringbuffer.length() > 0) { // this is a size, not the CRLF at the end of a chunk try { String temp = stringbuffer.toString(); int semi = temp.indexOf(';'); // skip extensions if (semi > 0) { temp = temp.substring(0, semi); } /* * Reset the string buffer length so readline() will * not parse this line. */ stringbuffer.setLength(0); size = Integer.parseInt(temp, 16); } catch (NumberFormatException nfe) { throw new IOException( "invalid chunk size number format"); } break; } } else { stringbuffer.append(c); lastchar = c; } } if (size < 0) { // did not get the size return 0; } /* * Update the chunksize and the total bytes that have been * read from the chunk. This will trigger the next call to * readBytes to refill the buffers as needed. */ chunksize = size; if (size == 0) { eof = true; return 0; } totalbytesread = 0; /* * If the full chunk is available, return chunksize, * otherwise return the remainder of the available * bytes (e.g. partial chunk). */ return (chunksize < len ? chunksize : len); } /** * Reads up to <code>len</code> bytes of data from the input stream into * an array of bytes. * This method reads Chunked and known length non-chunked http connection * input streams. For non-chunked set the field <code>chunkedIn</code> * should be false. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ protected int readBytesChunked(byte b[], int off, int len) throws IOException { int rc; if (bytesleft == 0) { /* * the internal input stream buffer is empty, read from the stream */ if (totalbytesread == chunksize) { /* * read the end of the chunk and get the size of the * the next if there is one */ if (!chunkedIn) { /* * non-chucked data is treated as one big chunk so there * is no more data so just return as if there are no * more chunks */ eof = true; return -1; } skipEndOfChunkCRLF(); chunksize = readChunkSize(); if (chunksize == 0) { eof = true; /* * REFERENCE: HTTP1.1 document * SECTION: 3.6.1 Chunked Transfer Coding * in some cases there may be an OPTIONAL trailer * containing entity-header fields. since we don't support * the available() method for TCP socket input streams and * for performance and reuse reasons we do not attempt to * clean up the current connections input stream. * check readResponseMessage() method in this class for * more details */ return -1; } /* * we have not read any bytes from this new chunk */ totalbytesread = 0; } int bytesToRead = chunksize - totalbytesread; if (len >= bytesToRead) { /* * No need to buffer, if the caller has given a big buffer. */ rc = streamInput.read(b, off, bytesToRead); } else if (len >= inputBufferSize) { /* * No need to buffer, if the caller has given a big buffer. */ rc = streamInput.read(b, off, len); } else { if (inputBufferSize >= bytesToRead) { rc = streamInput.read(readbuf, 0, bytesToRead); } else { rc = streamInput.read(readbuf, 0, inputBufferSize); } bytesleft = rc; bytesread = 0; } if (rc == -1) { /* * Network problem or the wrong length was sent by the server. */ eof = true; throw new IOException("unexpected end of stream"); } totalbytesread += rc; if (bytesleft == 0) { /* * The data was read directly into the caller's buffer. */ return rc; } } rc = readFromBuffer(b, off, len); return rc; } /** * Read the chunk size from the input. * It is a hex length followed by optional headers (ignored). * and terminated with CRLF. * * @return size of the buffered read */ private int readChunkSize() throws IOException { int size = -1; try { String chunk = null; try {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -