📄 relayconnection.java
字号:
line.append( ( char ) byteRead ); } } catch( IOException e ) { throw new APIException( "io-exception-reading-from-socket", e.getMessage() ); } if( line.length() != 0 ) throw new APIException( "improperly-formated-line", line ); return null; } /** * This method is used to retrieve the HTTP response code from the input stream * after a message has been written to it. * * @param inStream the input stream to read from. * @return the HTTP response code. * @exception APIException if there is no response from server or if the returned * response code is not a number. * */ private int getHTTPResponseCode( InputStream inStream ) throws APIException { String firstLine = getLine( inStream ); if( firstLine == null || firstLine.length() == 0 ) throw new APIException( ErrorCode.SERVER_ERROR, "no-response-from-server" ); String responseCode = null; int responseCodeStart = firstLine.indexOf( ' ' ); if( responseCodeStart != -1 ) { int responseCodeEnd = firstLine.indexOf( ' ', responseCodeStart + 1 ); responseCode = firstLine.substring( responseCodeStart + 1, responseCodeEnd ); try { return Integer.parseInt( responseCode ); } catch( NumberFormatException e ) { throw new APIException( ErrorCode.SERVER_ERROR, "http-response-code-not-number", responseCode ); } } else throw new APIException( ErrorCode.SERVER_ERROR, "http-response-code-not-found" ); } /** * Inner class to hold the values from the WWW-Authenticate HTTP header. */ class WWWAuthenticateHeader { public String authType; //basic/digest public String realm; public String algorithm; public String qop; public String nonce; } /** * This method is used to retrieve the WWW-Authenticate header from the input stream. * * @param inStr the input stream to read from. * @return the WWWAuthenticateHeader object. * @exception APIException if the authenticate header is not found or if it is not properly formatted. * */ private WWWAuthenticateHeader getWWWAuthHeader( InputStream inStr ) throws APIException { InternetHeaders headers = null; try { headers = new InternetHeaders( inStr ); } catch( MessagingException me ) { throw new APIException( "cannot-read-headers", me.getMessage() ); } String authHeaderValue[] = headers.getHeader( "www-authenticate" ); if( authHeaderValue == null || authHeaderValue[0] == null || authHeaderValue[0].length() == 0 ) throw new APIException( ErrorCode.SERVER_ERROR, "www-authenticate-header-not-found" ); WWWAuthenticateHeader header = new WWWAuthenticateHeader(); StringTokenizer parser = new StringTokenizer( authHeaderValue[0] ); if( parser.hasMoreTokens() ) { header.authType = parser.nextToken().toLowerCase(); } while( parser.hasMoreTokens() ) { String token = parser.nextToken( ", " ); int equalsIndex = token.indexOf( '=' ); if( equalsIndex == -1 ) throw new APIException( ErrorCode.SERVER_ERROR, "bad-www-authenticate-header" ); String key = token.substring( 0, equalsIndex ).toLowerCase(); String value = token.substring( equalsIndex + 2 , token.length() - 1 ); if( key.equals( "realm" ) ) { header.realm = value; } else if( key.equals( "nonce" ) ) { header.nonce = value; } else if( key.equals( "qop" ) ) { header.qop = value; } else if( key.equals( "algorithm" ) ) { header.algorithm = value; } } return header; } /** * This method is used to compute the HTTP Authorization header value. * * @param header the WWW-Athenticate header values encapsulated in a WWWAuthenticateHeader * object. * @exception APIException if authType from the header is not one of basic or digest. * */ private String computeAuthHeaderValue( WWWAuthenticateHeader header ) throws APIException { if( header.authType.equals( "basic" ) ) { return "Basic " + Base64.encodeString( userName + ":" + password ); } else if( header.authType.equals( "digest" ) ) { String nonceCount = "0000001"; String cNonce = "openwave"; MessageDigest digest = null; try { digest = MessageDigest.getInstance( "MD5" ); } catch( NoSuchAlgorithmException nsae ) { throw new APIException( "no-md5" ); } String ha1 = convertDigestToString( digest.digest( ( userName + ":" + header.realm + ":" + password ).getBytes() ) ); digest.reset(); String ha2 = convertDigestToString( digest.digest( ( "POST:" + url.getPath() ).getBytes() ) ); digest.reset(); String response = convertDigestToString( digest.digest( ( ha1 + ":" + header.nonce + ":" + nonceCount + ":" + cNonce + ":" + header.qop + ":" + ha2 ).getBytes() ) ); return "Digest " + "username=\"" + userName + "\"," + "realm=\"" + header.realm + "\"," + "response=\"" + response + "\"," + "nonce=\"" + header.nonce + "\"," + "cnonce=\"" + cNonce + "\"," + "nc=\"" + nonceCount + "\"," + "qop=\"" + header.qop + "\"," + "uri=\"" + url.getPath() + "\""; } else throw new APIException( ErrorCode.SERVER_ERROR, "unknown-authtype", header.authType ); } private String convertDigestToString( byte[] digest ) { StringBuffer buf = new StringBuffer( 32 ); for( int i = 0; i < 16; i++ ) { String hex = Integer.toHexString( digest[i] ); if( hex.length() > 2 ) hex = hex.substring( 6 ); if( hex.length() < 2 ) hex = "0" + hex; buf.append( hex ); } return buf.toString(); } private static void writeHeaders( OutputStream out ) throws IOException { out.write( "HTTP/1.0 200 OK\r\n".getBytes() ); out.write( "Content-Type: text/xml\r\n".getBytes() ); if( logger.isDebugEnabled() ) { logger.debug( "HTTP/1.0 200 OK\r\n" ); logger.debug( "Content-Type: text/xml\r\n" ); } } private void writeEmptyResponse( OutputStream out ) throws IOException { writeHeaders( out ); out.write( "Content-length: 0\r\n\r\n".getBytes() ); if( logger.isDebugEnabled() ) { logger.debug( "Content-length: 0\r\n\r\n" ); } } /** * This method is called at the beginning of every public method to enforce threading policy. * Only the thread that created the RelayConnection object is allowed to use it. * * @exception APIException if thread policy if not followed. * */ private void threadCheck() throws APIException { if( ! owningThread.equals( Thread.currentThread() ) ) throw new APIException( ErrorCode.THREADING_ERROR, "thread-policy" ); } static { try { // always there. shipped with the api String propFileName = "/resources/RelayConnection.properties"; InputStream propFile = RelayConnection.class.getResourceAsStream( propFileName ); Properties p = new Properties( System.getProperties() ); p.load( propFile ); // set the system properties System.setProperties( p ); } catch( IOException e ) { e.printStackTrace(); } } private static void writeResponse( Response res, OutputStream outputStream ) throws IOException, SOAPException { if( logger.isDebugEnabled() ) { logger.debug( "[Begin Outgoing Response To Relay]" ); } writeHeaders( outputStream ); res.writeTo( outputStream ); if( logger.isDebugEnabled() ) { logger.debug( "[End Outgoing Response To Relay]" ); } } private static void writeServletResponse( Response res, ServletResponse response ) throws IOException, SOAPException { if( logger.isDebugEnabled() ) { logger.debug( "[Begin Outgoing Response To Relay]" ); } response.setContentType( "text/xml" ); if( res != null ) res.writeTo( response ); if( logger.isDebugEnabled() ) { logger.debug( "[End Outgoing Response To Relay]" ); } } private static final Logger logger = Logger.getLogger( RelayConnection.class ); // connection modes private static final int RECEIVER_ONLY = 0; private static final int SENDER_ONLY = 1; private static final int SENDER_AND_RECEIVER = 2; private int mode; private int port; private URL url; private boolean weakCN = false; private String userName; private String password; private Server server; private OutputStream debugOutputStream; private OutputStream logOutputStream; private HashMap authenticators; private AuthenticationType authType = AuthenticationType.ANY; private MessageListener messageListener; private Thread owningThread;}/* important prop info.Only in 1.4?Proxy support:http.proxyHost (default: <none>)http.proxyPort (default: 80 if http.proxyHost specified)http.nonProxyHosts (default: <none>http.proxyHost and http.proxyPort indicate the proxy server and port that the http protocol handler will use. http.nonProxyHosts indicates the hosts which should be connected too directly and not through the proxy server. The value can be a list of hosts, each seperated by a |, and in addition a wildcard character (*) can be used for matching. For example: -Dhttp.nonProxyHosts="*.foo.com|localhost". Digest Auth support:http.auth.digest.validateServer (default: false)http.auth.digest.validateProxy (default: false)http.auth.digest.cnonceRepeat (default: 5) These system properties modify the behavior of the HTTP digest authentication mechanism. Digest authentication provides a limited ability for the server to authenticate itself to the client (ie. by proving that it knows the users password). Haever, not all servers support this capability and by default the check is switched off. The first two properties above can be set to true, to enforce this check, for either authentication with an origin, or a proxy server respectively. It is not normally necessary to set the third property (http.auth.digest.cnonceRepeat). This determines how many times a cnonce value is reused. This can be useful when the MD5-sess algorithm is being used. Increasing the value reduces the computational overhead on both the client and the server by reducing the amount of material that has to be hashed for each HTTP request. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -