mobile/android/thirdparty/com/codebutler/android_websockets/WebSocketClient.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 // This file was copied from:
     2 // https://github.com/koush/android-websockets/blob/master/src/com/codebutler/android_websockets/WebSocketClient.java
     4 package com.codebutler.android_websockets;
     6 import android.os.Handler;
     7 import android.os.HandlerThread;
     8 import android.text.TextUtils;
     9 import android.util.Base64;
    10 import android.util.Log;
    11 import org.apache.http.*;
    12 import org.apache.http.client.HttpResponseException;
    13 import org.apache.http.message.BasicLineParser;
    14 import org.apache.http.message.BasicNameValuePair;
    16 import javax.net.SocketFactory;
    17 import javax.net.ssl.SSLContext;
    18 import javax.net.ssl.SSLException;
    19 import javax.net.ssl.SSLSocketFactory;
    20 import javax.net.ssl.TrustManager;
    21 import java.io.EOFException;
    22 import java.io.IOException;
    23 import java.io.OutputStream;
    24 import java.io.PrintWriter;
    25 import java.net.Socket;
    26 import java.net.URI;
    27 import java.security.KeyManagementException;
    28 import java.security.NoSuchAlgorithmException;
    29 import java.util.List;
    31 public class WebSocketClient {
    32     private static final String TAG = "WebSocketClient";
    34     private URI                      mURI;
    35     private Listener                 mListener;
    36     private Socket                   mSocket;
    37     private Thread                   mThread;
    38     private HandlerThread            mHandlerThread;
    39     private Handler                  mHandler;
    40     private List<BasicNameValuePair> mExtraHeaders;
    41     private HybiParser               mParser;
    42     private boolean                  mConnected;
    44     private final Object mSendLock = new Object();
    46     private static TrustManager[] sTrustManagers;
    48     public static void setTrustManagers(TrustManager[] tm) {
    49         sTrustManagers = tm;
    50     }
    52     public WebSocketClient(URI uri, Listener listener, List<BasicNameValuePair> extraHeaders) {
    53         mURI          = uri;
    54         mListener     = listener;
    55         mExtraHeaders = extraHeaders;
    56         mConnected    = false;
    57         mParser       = new HybiParser(this);
    59         mHandlerThread = new HandlerThread("websocket-thread");
    60         mHandlerThread.start();
    61         mHandler = new Handler(mHandlerThread.getLooper());
    62     }
    64     public Listener getListener() {
    65         return mListener;
    66     }
    68     public void connect() {
    69         if (mThread != null && mThread.isAlive()) {
    70             return;
    71         }
    73         mThread = new Thread(new Runnable() {
    74             @Override
    75             public void run() {
    76                 try {
    77                     int port = (mURI.getPort() != -1) ? mURI.getPort() : ((mURI.getScheme().equals("wss") || mURI.getScheme().equals("https")) ? 443 : 80);
    79                     String path = TextUtils.isEmpty(mURI.getPath()) ? "/" : mURI.getPath();
    80                     if (!TextUtils.isEmpty(mURI.getQuery())) {
    81                         path += "?" + mURI.getQuery();
    82                     }
    84                     String originScheme = mURI.getScheme().equals("wss") ? "https" : "http";
    85                     URI origin = new URI(originScheme, "//" + mURI.getHost(), null);
    87                     SocketFactory factory = (mURI.getScheme().equals("wss") || mURI.getScheme().equals("https")) ? getSSLSocketFactory() : SocketFactory.getDefault();
    88                     mSocket = factory.createSocket(mURI.getHost(), port);
    90                     PrintWriter out = new PrintWriter(mSocket.getOutputStream());
    91                     out.print("GET " + path + " HTTP/1.1\r\n");
    92                     out.print("Upgrade: websocket\r\n");
    93                     out.print("Connection: Upgrade\r\n");
    94                     out.print("Host: " + mURI.getHost() + "\r\n");
    95                     out.print("Origin: " + origin.toString() + "\r\n");
    96                     out.print("Sec-WebSocket-Key: " + createSecret() + "\r\n");
    97                     out.print("Sec-WebSocket-Version: 13\r\n");
    98                     if (mExtraHeaders != null) {
    99                         for (NameValuePair pair : mExtraHeaders) {
   100                             out.print(String.format("%s: %s\r\n", pair.getName(), pair.getValue()));
   101                         }
   102                     }
   103                     out.print("\r\n");
   104                     out.flush();
   106                     HybiParser.HappyDataInputStream stream = new HybiParser.HappyDataInputStream(mSocket.getInputStream());
   108                     // Read HTTP response status line.
   109                     StatusLine statusLine = parseStatusLine(readLine(stream));
   110                     if (statusLine == null) {
   111                         throw new HttpException("Received no reply from server.");
   112                     } else if (statusLine.getStatusCode() != HttpStatus.SC_SWITCHING_PROTOCOLS) {
   113                         throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
   114                     }
   116                     // Read HTTP response headers.
   117                     String line;
   118                     while (!TextUtils.isEmpty(line = readLine(stream))) {
   119                         Header header = parseHeader(line);
   120                         if (header.getName().equals("Sec-WebSocket-Accept")) {
   121                             // FIXME: Verify the response...
   122                         }
   123                     }
   125                     mListener.onConnect();
   127                     mConnected = true;
   129                     // Now decode websocket frames.
   130                     mParser.start(stream);
   132                 } catch (EOFException ex) {
   133                     Log.d(TAG, "WebSocket EOF!", ex);
   134                     mListener.onDisconnect(0, "EOF");
   135                     mConnected = false;
   137                 } catch (SSLException ex) {
   138                     // Connection reset by peer
   139                     Log.d(TAG, "Websocket SSL error!", ex);
   140                     mListener.onDisconnect(0, "SSL");
   141                     mConnected = false;
   143                 } catch (Exception ex) {
   144                     mListener.onError(ex);
   145                 }
   146             }
   147         });
   148         mThread.start();
   149     }
   151     public void disconnect() {
   152         if (mSocket != null) {
   153             mHandler.post(new Runnable() {
   154                 @Override
   155                 public void run() {
   156                     if (mSocket != null) {
   157                         try {
   158                             mSocket.close();
   159                         } catch (IOException ex) {
   160                             Log.d(TAG, "Error while disconnecting", ex);
   161                             mListener.onError(ex);
   162                         }
   163                         mSocket = null;
   164                     }
   165                     mConnected = false;
   166                 }
   167             });
   168         }
   169     }
   171     public void send(String data) {
   172         sendFrame(mParser.frame(data));
   173     }
   175     public void send(byte[] data) {
   176         sendFrame(mParser.frame(data));
   177     }
   179     public boolean isConnected() {
   180         return mConnected;
   181     }
   183     private StatusLine parseStatusLine(String line) {
   184         if (TextUtils.isEmpty(line)) {
   185             return null;
   186         }
   187         return BasicLineParser.parseStatusLine(line, new BasicLineParser());
   188     }
   190     private Header parseHeader(String line) {
   191         return BasicLineParser.parseHeader(line, new BasicLineParser());
   192     }
   194     // Can't use BufferedReader because it buffers past the HTTP data.
   195     private String readLine(HybiParser.HappyDataInputStream reader) throws IOException {
   196         int readChar = reader.read();
   197         if (readChar == -1) {
   198             return null;
   199         }
   200         StringBuilder string = new StringBuilder("");
   201         while (readChar != '\n') {
   202             if (readChar != '\r') {
   203                 string.append((char) readChar);
   204             }
   206             readChar = reader.read();
   207             if (readChar == -1) {
   208                 return null;
   209             }
   210         }
   211         return string.toString();
   212     }
   214     private String createSecret() {
   215         byte[] nonce = new byte[16];
   216         for (int i = 0; i < 16; i++) {
   217             nonce[i] = (byte) (Math.random() * 256);
   218         }
   219         return Base64.encodeToString(nonce, Base64.DEFAULT).trim();
   220     }
   222     void sendFrame(final byte[] frame) {
   223         mHandler.post(new Runnable() {
   224             @Override
   225             public void run() {
   226                 try {
   227                     synchronized (mSendLock) {
   228                         OutputStream outputStream = mSocket.getOutputStream();
   229                         outputStream.write(frame);
   230                         outputStream.flush();
   231                     }
   232                 } catch (IOException e) {
   233                     mListener.onError(e);
   234                 }
   235             }
   236         });
   237     }
   239     public interface Listener {
   240         public void onConnect();
   241         public void onMessage(String message);
   242         public void onMessage(byte[] data);
   243         public void onDisconnect(int code, String reason);
   244         public void onError(Exception error);
   245     }
   247     private SSLSocketFactory getSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException {
   248         SSLContext context = SSLContext.getInstance("TLS");
   249         context.init(null, sTrustManagers, null);
   250         return context.getSocketFactory();
   251     }
   252 }

mercurial