📄 protocol.java
字号:
reqLine.append(HTTP_VERSION); reqLine.append("\r\n"); /* * HTTP 1/1 requests require the Host header to distinguish * virtual host locations. */ setRequestField("Host", url.authority); if (chunkedOut) { /* * Signal the server that the body is chunked * by setting the Transfer-Encoding property to "chunked". */ setRequestField("Transfer-Encoding", "chunked"); } /* * Setup the various http header field/values defined and/or * required. */ numberOfKeys = reqProperties.size(); for (int i = 0; i < numberOfKeys; i++) { String key = (String)reqProperties.getKeyAt(i); if (key.equals("Content-Length")) { /* * If its CHUNK data - no content-length: size required. */ if (chunkedOut) { continue; } else { /* * Check that the output stream has been opened. */ if (writebuf == null) { reqLine.append("Content-Length: 0"); } else { reqLine.append("Content-Length: "); reqLine.append(bytesToWrite); } reqLine.append("\r\n"); } } else { reqLine.append(key); reqLine.append(": "); reqLine.append(reqProperties.getValueAt(i)); reqLine.append("\r\n"); } } reqLine.append("\r\n"); streamOutput.write(reqLine.toString().getBytes()); } /** * Write the http request body bytes to the output stream. * * @exception IOException */ protected void sendRequestBody() throws IOException { int start; int endOfData; int length; if ((writebuf == null) || (bytesToWrite == 0)) { return; } start = HTTP_OUTPUT_DATA_OFFSET; endOfData = HTTP_OUTPUT_DATA_OFFSET + bytesToWrite; length = bytesToWrite; /* * If a CHUNKed session then write out the chunk size first * with a trailing CRLF. * * reference: RFC2616 - section 3 protocol parameters * 3.6 transfer coding: * 3.6.1 chunked transfer coding: * chunk-body = chunk / last chunk / trailer / CRLF * * chunk = chunk-size / chunk-data / CRLF * last_chunk = "0" / CRLF * trailer = " " / CRLF * *indicates its done here. */ if (chunkedOut) { /* * For CHUNKed write out the chunk size with CRLF. * Put this before the data in write buffer. */ String temp = Integer.toHexString(bytesToWrite); int tempLen = temp.length(); writebuf[--start] = (byte)'\n'; writebuf[--start] = (byte)'\r'; for (int i = tempLen - 1; i >= 0; i--) { writebuf[--start] = (byte)temp.charAt(i); } length += tempLen + 2; /* * If a CHUNKed session then write out another CRLF and flush(). * Put this after the data in the write bufffer. */ writebuf[endOfData++] = (byte)'\r'; writebuf[endOfData++] = (byte)'\n'; length += 2; } streamOutput.write(writebuf, start, length); bytesToWrite = 0; } /** * Finish the http request and reads the response headers. * * @exception IOException is thrown, if an I/O error occurs for final * stream output or on reading the response message line */ protected void finishRequestGetResponseHeader() throws IOException { // Even if we get an exception this request is finished requestFinished = true; /* * if this is a CHUNKed session write out the last set of CRLF */ if (chunkedOut) { /* * reference: RFC2616 - section 3 protocol parameters * 3.6 transfer coding: * 3.6.1 chunked transfer coding: * chunk-body = chunk / last chunk / trailer / CRLF * chunk = chunk-size / chunk-data / CRLF * * last_chunk = "0" / CRLF * * trailer = " " / CRLF * * indicates its done here. */ /* * write the last chunk (size=0 / CRLF) and the dummy trailer */ streamOutput.write("0\r\n\r\n".getBytes()); } streamOutput.flush(); readResponseMessage(streamInput); readHeaders(streamInput); /* * Ignore a continuation header and read the true headers again. * (Bug# 4382226 discovered with Jetty HTTP 1.1 web server. */ if (responseCode == 100) { readResponseMessage(streamInput); readHeaders(streamInput); } } /** * Connect to the underlying network TCP transport. * If the proxy is configured, connect to it as tunnel first. * <p> * Warning: A subclass that implements this method, should not call this * method and should implement the disconnect method. * * @return network stream connection * @exception IOException is thrown if the connection cannot be opened */ protected StreamConnection connect() throws IOException { com.sun.midp.io.j2me.socket.Protocol conn; verifyPermissionCheck(); conn = new com.sun.midp.io.j2me.socket.Protocol(); if (http_proxy == null) { conn.openPrim(classSecurityToken, "//" + hostAndPort); // Do not delay request since this delays the response. conn.setSocketOption(SocketConnection.DELAY, 0); return conn; } conn.openPrim(classSecurityToken, "//" + http_proxy); // Do not delay request since this delays the response. conn.setSocketOption(SocketConnection.DELAY, 0); // openData*Stream cannot be call twice, so save them for later streamOutput = conn.openDataOutputStream(); streamInput = conn.openDataInputStream(); try { doTunnelHandshake(streamOutput, streamInput); } catch (IOException ioe) { String response = ioe.getMessage(); try { disconnect(conn, streamInput, streamOutput); } catch (Exception e) { // do not over throw the handshake exception } streamOutput = null; streamInput = null; if ((response != null) && (response.indexOf(" 500 ") > -1)) { throw new ConnectionNotFoundException(response); } else { throw ioe; } } 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; line = readLine(in); /* * 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) { line = readLine(in); } int httpEnd, codeEnd; responseCode = -1; responseMsg = null; if (line == null) { throw new IOException("response empty"); } httpEnd = line.indexOf(' '); if (httpEnd < 0) { if (line.length() > 10) { // only put the first 10 chars in the exception line = line.substring(0, 10); } throw new IOException("cannot find status code in response: " + line); } String temp = line.substring(0, httpEnd); if (!temp.startsWith("HTTP")) { if (httpEnd > 10) { // only put the first 10 chars in the exception temp = temp.substring(0, 10); } throw new IOException("response does not start with HTTP " + "it starts with: " + temp); } httpVer = temp; if (line.length() <= httpEnd) { throw new IOException("status line ends after HTTP version"); } codeEnd = line.substring(httpEnd + 1).indexOf(' '); if (codeEnd < 0) { throw new IOException("cannot find reason phrase in response"); } codeEnd += (httpEnd + 1); if (line.length() <= codeEnd) { throw new IOException("status line end after status code"); } try { responseCode = Integer.parseInt(line.substring(httpEnd+1, codeEnd)); } catch (NumberFormatException nfe) { throw new IOException("status code in response is not a number"); } responseMsg = line.substring(codeEnd + 1); } /** * 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 throw
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -