📄 protocol.java
字号:
* a connection (you could create more) */ if (connectionPool == null) { connectionPool = new StreamConnectionPool( maxNumberOfPersistentConnections); } /* * Each subsequent time call into the connection pool * and either grab an available one or create a new one */ if (http_proxy == null) { conn = connectionPool.getConnection(saved_url, url.host, url.port, hostAndPort); streamOutput = conn.openDataOutputStream(); streamInput = conn.openDataInputStream(); } else { conn = connectionPool.getConnection(saved_url, url.host, url.port, http_proxy); streamOutput = conn.openDataOutputStream(); streamInput = conn.openDataInputStream(); try { doTunnelHandshake(streamOutput, streamInput); } catch (IOException ioe) { connectionElement = (StreamConnectionElement)conn; boolean rc = connectionPool.remove(connectionElement); streamOutput.close(); streamInput.close(); String response = ioe.getMessage(); if (response.indexOf(" 500 ") > -1) { throw new ConnectionNotFoundException(ioe.getMessage()); } else { throw ioe; } } } connectionElement = (StreamConnectionElement)conn; return conn; } /** * Connects to the SSL tunnel and completes the intialization of the * tunnel (handshake). The handshake based on the Internet-Draft * "A. Luotonen, Tunneling TCP based protocols through Web proxy servers, * February 1999". * @param os output stream for secure handshake * @param is input stream for secure handshake * @exception IOException is thrown if an error occurs in the SSL handshake */ protected void doTunnelHandshake(OutputStream os, InputStream is) throws IOException { String required; String optional; String endOfLine = "\r\n"; String emptyLine = endOfLine; int numberOfKeys; StringBuffer temp; boolean newline; String response; /* * request = required *optional emptyLine * required = "CONNECT" SP HOST ":" PORT SP HTTP_VERSION endOfLine * optional = HTTP_HEADER endOfLine ; proxy dependent: most likely * ; used for authorization. * emptyLine = endOfLine * endOfLine = *1CR LF * * example: * CONNECT home.acme.com:443 HTTP/1.0 * Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== * */ required = "CONNECT " + hostAndPort + " " + HTTP_VERSION + endOfLine; os.write(required.getBytes()); numberOfKeys = proxyHeaders.size(); for (int i = 0; i < numberOfKeys; i++) { optional = proxyHeaders.getKeyAt(i) + ": " + proxyHeaders.getValueAt(i) + endOfLine; os.write(optional.getBytes()); } os.write(emptyLine.getBytes()); os.flush(); /* * response = status *optional emptyLine * status = HTTP_VERSION SP STATUSCODE STATUS_MESSAGE *1CR LF * optional = HTTP_HEADER *1CR LF * emptyLine = *1CR LF * * example: * HTTP/1.0 200 Connection established * */ // Read in response until an empty line is found (1*CR LF 1*CR LF) temp = new StringBuffer(); newline = false; while (true) { int c = is.read(); if (c == -1) { break; } else if (c == '\n') { if (newline) { break; } newline = true; } else if (c != '\r') { newline = false; } temp.append((char)c); } if (temp.length() == 0) { temp.append("none"); } response = temp.toString(); if (response.indexOf(" 200 ") == -1) { throw new IOException("Error initializing HTTP tunnel connection: \n" + response); } } /** * Check the initial response message looking for the * appropriate HTTP version string. Parse the response * code for easy application branching on condition codes. * * @param in input stream where the response headers are read * @exception IOException is thrown if the header response can * not be parsed */ private void readResponseMessage(InputStream in) throws IOException { String line = null; responseCode = -1; responseMsg = null; try { line = readLine(in); } catch (IOException ioe) { /* throw new IOException(ioe.getMessage()); */ } /* * 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 inputstreams and for performance reasons we * do not attempt to clean up the previous connections input * stream. the first thing we do here is read the stream and * discard it. */ if (line != null && line.length() == 0) { try { line = readLine(in); } catch (IOException ioe) { /* throw new IOException(ioe.getMessage()); */ } } int httpEnd, codeEnd; responseCode = -1; responseMsg = null; malformed: { if (line == null) break malformed; httpEnd = line.indexOf(' '); if (httpEnd < 0) break malformed; httpVer = line.substring(0, httpEnd); if (!httpVer.startsWith("HTTP")) break malformed; if (line.length() <= httpEnd) break malformed; codeEnd = line.substring(httpEnd + 1).indexOf(' '); if (codeEnd < 0) break malformed; codeEnd += (httpEnd + 1); if (line.length() <= codeEnd) break malformed; try { responseCode = Integer.parseInt(line.substring(httpEnd+1, codeEnd)); } catch (NumberFormatException nfe) { break malformed; } responseMsg = line.substring(codeEnd + 1); return; } throw new IOException("malformed response message"); } /** * Read the response message headers. * Parse the response headers name value pairs for easy application use. * * @param in input stream where the response headers are read * @exception IOException is thrown if the response headers cannot * be parsed */ private void readHeaders(InputStream in) throws IOException { String line, key, value; int index; for (;;) { try { line = readLine(in); } catch (IOException ioe) { throw new IOException(ioe.getMessage()); } if (line == null || line.equals("")) return; index = line.indexOf(':'); if (index < 0) { throw new IOException("malformed header field"); } key = line.substring(0, index); if (key.length() == 0) { throw new IOException("malformed header field"); } if (line.length() <= index + 1) value = ""; else value = line.substring(index + 1).trim(); /** * Check the response header to see if the server would like * to close the connection. * BUG#4492849 */ if ((key.equals("Connection")) && (value.equals("close"))) { ConnectionCloseFlag = true; } headerFields.addProperty(toLowerCase(key), value); } } /** * Uses the shared stringbuffer to read a line terminated by CRLF * and return it as string. * * @param in InputStream to read the data * @return one line of input header * @exception IOException if EOF encountered while reading headers */ private String readLine(InputStream in) throws IOException { int c; stringbuffer.setLength(0); for (;;) { try { c = in.read(); if (c < 0) { /* throw new IOException("EOF"); */ return null; } if (c == '\r') { continue; } } catch (IOException ioe) { /* throw new IOException(ioe.getMessage()); */ return null; } if (c == '\n') { break; } stringbuffer.append((char)c); } return stringbuffer.toString(); } /** * Disconnect from the underlying socket transport. * Closes the low level socket connection and the input and * output streams used by the socket. * <P> * Resets the flags associated with the last transaction and the * connectedness of the current HTTP connection. * * @exception IOException is thrown if the connection or * associated streams cannot be closed */ protected void disconnect() throws IOException { disconnect(streamConnection, streamInput, streamOutput); } /** * Disconnect the current low level socket connection. If the connection * is an HTTP1.1 connection that connection will be put back in the pool * for another session to use to connect. * * @param connection connection return from {@link #connect()} * @param inputStream input stream opened from <code>connection</code> * @param outputStream output stream opened from <code>connection</code> * @exception IOException if an I/O error occurs while * the connection is terminated. */ protected void disconnect(StreamConnection connection, InputStream inputStream, OutputStream outputStream) throws IOException { /** * if the current state is CHUNK then close the outputstream */ if ((state == CHUNK_STATE) || (state == WRITE_STATE)) { sendRequest(CLOSE_STATE); } if ((streamConnection != null) && (httpVer != null)) { streamOutput.flush(); /* * if this is NOT HTTP1.1 or the application specifically * wants to close the stream - do this close everything down. */ if ((httpVer.equals("HTTP/1.0")) || (ConnectionCloseFlag)) { boolean rc = connectionPool.remove(connectionElement); streamOutput.close(); streamInput.close(); streamConnection.close(); streamConnection = null; } else { /* * if this is a HTTP1.1 connection we need to check for an * abort condition (if bytesleft != 0 or more chunks) we * need to close and throw this connection away. */ if ((bytesleft > 0) || (eof != true)) { boolean rc = connectionPool.remove(connectionElement); streamOutput.close(); streamInput.close(); streamConnection.close(); streamConnection = null; } } } else { if (ConnectionCloseFlag) { if (connectionPool != null) { boolean rc = connectionPool.remove(connectionElement); } if (streamOutput != null) { streamOutput.close(); } if (streamInput != null) { streamInput.close(); } if (streamConnection != null) { streamConnection.close(); } streamConnection = null; return; } } /* * return the connection to the connection pool */ if (streamConnection != null) { try { connectionPool.returnConnection(streamConnection); } catch (Exception e) { throw new IOException(e.getMessage()); } } responseCode = -1; reconnects = 0; responseMsg = null; } /** * Convert a string to lowercase. Used to make uniform * name for header fields in the response message for * simple comparisons.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -