📄 protocol.java
字号:
* the proxy server and the requested URL will include the full http URL. * <P> * On output the Content-Length header is included in the request based * on the size of the buffered output array. * <P> * This routine inserts the Host header needed for HTTP 1.1 virtual host * addressing. * <P> * This routine also receives the reply response and parses the headers * for easier access. After the headers are parsed the application has * access to the raw data from the socket stream connection. * * @param next_state transition to this state when finished * @exception IOException is thrown if the connection cannot be opened */ protected void sendRequest(int next_state) throws IOException { if (state == CONNECT_STATE) { return; } if (state > OPEN_STATE) { /* * if moved to CHUNK state all we need to do is write payload */ if (next_state == CHUNK_STATE) { sendRequestWritePayload(next_state); } /* * if current state is CHUNK and next state is CLOSE * or READ STATE's - time to end */ if ((state == CHUNK_STATE) && ((next_state == CLOSE_STATE) || (next_state == READ_STATE))) { if (byteArrayOutput.size() > 0) sendRequestWritePayload(state); sendRequestEndSession(next_state); } else { setState(next_state); } } else { /* * before (creating) and getting a connection set the state OPEN. */ setState(OPEN_STATE); streamConnection = connect(); streamOutput = streamConnection.openDataOutputStream(); streamInput = streamConnection.openDataInputStream(); sendRequestGeneric(next_state); /* * write the payload to the output stream */ sendRequestWritePayload(next_state); /* * if next state not CHUNK write - time to end. */ if (next_state != CHUNK_STATE) { sendRequestEndSession(next_state); } else { setState(next_state); } } /* * If the connection is a proxy connection and the proxy * server returns an error, raise an exception. */ if (http_proxy != null) { if (responseCode >= HTTP_INTERNAL_ERROR) { throw new IOException("server error ["+responseCode+"]"); } } return; } /** * Simplifies the sendRequest() method functionality into one method * this is extremely helpful for persistent connection support and * retries. * * @param next_state the next state to transition to * @exception IOException is thrown if the connection cannot be opened */ protected void sendRequestGeneric(int next_state) throws IOException { int numberOfKeys; if (reconnects > MAX_NUMBER_OF_RECONNECTS) { throw new IOException("ERROR: too many reconnections"); } reconnects++; // HTTP 1.0 requests must contain content length for proxies if (getRequestProperty("Content-Length") == null) { setRequestProperty("Content-Length", "" + (out == null ? 0 : byteArrayOutput.size())); } /* * if in OPEN state - then begin to format http request headers. */ if (state != OPEN_STATE) { return; } String reqLine; /* * HTTP RFC and bug#4402149, * if there is no ("/") slash in the path then add one. */ String filename = url.path; if (filename == null) { filename = "/"; } /* * Note: the "ref" or fragment, is not sent to the server. */ if (http_proxy == null) { reqLine = method + " " + filename + (url.query == null ? "" : "?" + url.query) + " " + HTTP_VERSION + "\r\n"; } else { reqLine = method + " " + protocol + "://" + hostAndPort + filename + (url.query == null ? "" : "?" + url.query) + " " + HTTP_VERSION + "\r\n"; } /* * Persistent connections: * lets try and write to the output stream - if it fails * then the connection is dead - re-connect and come * back through this method again (until max amount of times). */ try { streamOutput.write((reqLine).getBytes()); } catch (IOException ioe) { if (chunkedOut) { throw (ioe); } reconnectServer(); sendRequestGeneric(next_state); return; } /* * HTTP 1/1 requests require the Host header to distinguish * virtual host locations. */ setRequestProperty("Host", hostAndPort); /* * 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); String reqPropLine = key + ": " + reqProperties.getValueAt(i) + "\r\n"; if (key.equals("Content-Length")) { /* * If its CHUNK state - no content-length: size required. */ if ((next_state == CHUNK_STATE) || (chunkedOut)) { continue; } else { /* * Check that the output stream has been opened. */ if (byteArrayOutput == null) { reqPropLine = "Content-Length: 0" + "\r\n"; } else { reqPropLine = "Content-Length: "+ byteArrayOutput.size() + "\r\n"; } } } /* * Persistent connections: * lets try and write to the output stream - if it fails * then the connection is dead - re-connect and come * back through this method again (until max amount of times) */ try { streamOutput.write((reqPropLine).getBytes()); } catch (IOException ioe) { if (chunkedOut) throw (ioe); reconnectServer(); sendRequestGeneric(next_state); return; } } /* * Persistent connections: * lets try and write to the output stream - if it fails * then the connection is dead - re-connect and come * back through this method again (until max amount of times). */ try { streamOutput.write("\r\n".getBytes()); } catch (IOException ioe) { if (chunkedOut) throw (ioe); reconnectServer(); sendRequestGeneric(next_state); return; } return; } /** * Ends the http session output stream. * * @param next_state the next state to transition to - not done here * @exception IOException is thrown, if an I/O error occurs for final stream * output or on reading the response message line */ protected void sendRequestEndSession(int next_state) throws IOException { /* * if this is a CHUNKed session write out the last set of CRLF */ if ((state == CHUNK_STATE) || (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(); } else { 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); } setState(CONNECT_STATE); return; } /** * Write the http message payload bytes to the output stream. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @exception IOException */ protected void sendRequestWritePayloadDirect(byte b[], int off, int len) throws IOException { String temp = Integer.toHexString(len); streamOutput.write(temp.getBytes()); streamOutput.write("\r\n".getBytes()); streamOutput.write(b, off, len); streamOutput.write("\r\n".getBytes()); } /** * Write the http message payload bytes to the output stream. * * @param next_state the next state to transition to - not done here * @exception IOException */ protected void sendRequestWritePayload(int next_state) throws IOException { if ((byteArrayOutput == null) || (byteArrayOutput.size() == 0)) { return; } /* * Persistent connections: * lets try and write to the output stream - if it fails * then the connection is dead - re-connect and come * back through this method again (until max amount of times). */ try { /* * 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 ((next_state == CHUNK_STATE) || (chunkedOut)) { /* * For CHUNKed write out the chunk size with CRLF. */ String temp = Integer.toHexString(byteArrayOutput.size()); streamOutput.write(temp.getBytes()); streamOutput.write("\r\n".getBytes()); } streamOutput.write(byteArrayOutput.toByteArray()); byteArrayOutput.reset(); /* * If a CHUNKed session then write out another CRLF and flush(). */ if ((next_state == CHUNK_STATE) || (chunkedOut)) { streamOutput.write("\r\n".getBytes()); } } catch (IOException ioe) { if (chunkedOut) throw (ioe); reconnectServer(); sendRequestGeneric(next_state); return; } } /** * Disconnect/Reconnect to server - somehow the connection was lost. * * @exception IOException is thrown if the connection cannot be opened */ protected void reconnectServer() throws IOException { boolean old_ConnectionCloseFlag = ConnectionCloseFlag; String old_httpVer = httpVer; ConnectionCloseFlag = true; // need to force disconnect!! httpVer = "HTTP/1.0"; // need to force disconnect!! disconnect(); streamConnection = connect(); ConnectionCloseFlag = old_ConnectionCloseFlag; httpVer = old_httpVer; return; } /** * Connect to the underlying socket transport. * If an http_proxy was specified the socket connection will be made to * the proxy server. * * @return TCP/IP stream connection * @exception IOException is thrown if the connection cannot be opened */ protected StreamConnection connect() throws IOException { StreamConnection conn; /* * Get the proxy here instead of the connector, * so when this method subclassed by HTTPS http_proxy will be null * and the proxy will not be added into the request. */ http_proxy = Configuration.getProperty("com.sun.midp.io.http.proxy"); /* * if first time intialize the connection pool and create
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -