📄 protocol.java
字号:
int rc; /* * Be consistent about returning EOF once encountered. */ if (eof) { return (-1); } /* * If the http connection is chunked call the readBytesChunked method */ if (chunkedIn) { /* * "smooth" out (minmize the calls to this method) the chunks at * this level when a caller gives a large buffer. This is a minor * optimation, since readBytesChucked optimizes the the number of * native TCP socket calls. This also allow reuse of * readBytesChunked for unchucked data with a known content length. */ int total = 0; do { rc = readBytesChunked(b, off, len); if (rc == -1) { if (total == 0) { total = -1; } break; } total += rc; off += rc; len -= rc; } while (len > 0); return total; } else if (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 >= HTTP_BUFFER_SIZE) { /* * No need to buffer, if the caller has given a big buffer. */ rc = streamInput.read(b, off, len); } else { rc = streamInput.read(readbuf, 0, HTTP_BUFFER_SIZE); 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); /* * Move to READ state - if there is a problem - raise an exception. */ if (state != CONNECT_STATE) { setState(READ_STATE); } return rc; } /** * 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; } /** * 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; } readCRLF(); 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 >= HTTP_BUFFER_SIZE) { /* * No need to buffer, if the caller has given a big buffer. */ rc = streamInput.read(b, off, len); } else { if (HTTP_BUFFER_SIZE >= bytesToRead) { rc = streamInput.read(readbuf, 0, bytesToRead); } else { rc = streamInput.read(readbuf, 0, HTTP_BUFFER_SIZE); } 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 { chunk = readLine(streamInput); } catch (IOException ioe) { /* throw new IOException(ioe.getMessage()); */ } if (chunk == null) { throw new IOException("No Chunk Size"); } int i; for (i = 0; i < chunk.length(); i++) { char ch = chunk.charAt(i); if (Character.digit(ch, 16) == -1) break; } /* look at extensions?.... */ size = Integer.parseInt(chunk.substring(0, i), 16); } catch (NumberFormatException e) { throw new IOException("invalid chunk size number format"); } return size; } /** * Read CRLF from the InputStream. * * @exception IOException is thrown if either CR or LF * is missing. */ private void readCRLF() throws IOException { int ch; ch = streamInput.read(); if (ch != '\r') throw new IOException("missing CRLF"); ch = streamInput.read(); if (ch != '\n') throw new IOException("missing CRLF"); } /** * Writes <code>len</code> bytes from the specified byte array * starting at offset <code>off</code> to this output stream. * <p> * Polling the native code is done here to allow for simple * asynchronous native code to be written. Not all implementations * work this way (they block in the native code) but the same * Java code works for both. * <p> * This method can only be called after an OutputStream setup has be * done. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @return int number of bytes written to stream * @exception IOException if an I/O error occurs. In particular, * an <code>IOException</code> is thrown if the output * stream is closed. */ protected int writeBytes(byte b[], int off, int len) throws IOException { /* * Here's the only time the state can transition backwards -because * of the unusual way http connection sends a request to the server * (please reference the class description for more details). */ if (state < OPEN_STATE) { setState(WRITE_STATE); } /* * If the length of the paramter buffer area is larger than the * internal buffer area (HTTP_OUTPUT_BUFFER_SIZE) - then write * the param buffer area directly to the output stream. */ if (len > HTTP_OUTPUT_BUFFER_SIZE) { /* * once the output buffer size exceeds the HTTP_OUTPUT_BUFFER_SIZE * the session becomes a HTTP1.1 type session */ chunkedOut = true; /* * Set the Transfer-Encoding property to "chunked". */ setRequestProperty("Transfer-Encoding", "chunked"); if (byteArrayOutput.size() > 0) { flush(); } byteArrayOutput.reset(); sendRequest(CHUNK_STATE); sendRequestWritePayloadDirect(b, off, len); return len; } if (byteArrayOutput.size()+len > (HTTP_OUTPUT_BUFFER_SIZE)) { /* * once the output buffer size exceeds the HTTP_OUTPUT_BUFFER_SIZE * the session becomes a HTTP1.1 type session */ chunkedOut = true; flush(); } byteArrayOutput.write(b, off, len); return len; } /** * Flush any output data to the output stream. * * @exception IOException if an I/O error occurs */ public void flush() throws IOException { chunkedOut = true; if (byteArrayOutput.size() > 0) { /* * set Transfer-Encoding to "chunked". */ setRequestProperty("Transfer-Encoding", "chunked"); /* * move to chunk state at the end of the sendRequest() */ sendRequest(CHUNK_STATE); } else { streamOutput.flush(); } } /** * Get the original URL used to open the HTTP connection. * * @return HTTP URL used in the the current connection */ public String getURL() { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -