org.prx.prp.StreamProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.prx.prp.StreamProxy.java

Source

//  Copyright (c) 2010 Mahesh Sharma,Matt MacDonald
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.

package org.prx.prp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.StringTokenizer;

import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseFactory;
import org.apache.http.ParseException;
import org.apache.http.ProtocolVersion;
import org.apache.http.RequestLine;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.OperatedClientConnection;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.DefaultClientConnection;
import org.apache.http.impl.conn.DefaultClientConnectionOperator;
import org.apache.http.impl.conn.DefaultResponseParser;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.io.HttpMessageParser;
import org.apache.http.io.SessionInputBuffer;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicLineParser;
import org.apache.http.message.ParserCursor;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.CharArrayBuffer;

import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.util.Log;

public class StreamProxy implements Runnable {
    private int port = 0;
    MediaPlayer m;
    Context mContext;

    public int getPort() {
        return port;
    }

    private boolean isRunning = true;
    private ServerSocket socket;
    private Thread thread;

    public void init(MediaPlayer m, Context mContext) {
        try {
            this.m = m;
            this.mContext = mContext;
            socket = new ServerSocket(port, 0, InetAddress.getLocalHost());
            socket.setSoTimeout(5000);
            port = socket.getLocalPort();
            Log.d(getClass().getName(), "port " + port + " obtained");
        } catch (UnknownHostException e) {
            Log.e(getClass().getName(), "Error initializing server", e);
        } catch (IOException e) {
            Log.e(getClass().getName(), "Error initializing server", e);
        }
    }

    public void start() {
        thread = new Thread(this);
        thread.start();
    }

    public void stop() {
        isRunning = false;
        thread.interrupt();
        try {
            thread.join(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        Log.d(getClass().getName(), "running");
        while (isRunning) {
            try {
                Socket client = socket.accept();
                if (client == null) {
                    continue;
                }
                Log.d(getClass().getName(), "client connected");
                HttpRequest request = readRequest(client);
                processRequest(request, client);
            } catch (java.net.UnknownHostException e1) {
                Log.d("PRPAND", "asdasd");
            } catch (SocketTimeoutException e) {
                // Do nothing
            } catch (IOException e) {
                Log.e(getClass().getName(), "Error connecting to client", e);
            }
        }
        Log.d(getClass().getName(), "Proxy interrupted. Shutting down.");
    }

    private HttpRequest readRequest(Socket client) {
        HttpRequest request = null;
        InputStream is;
        String firstLine;
        try {
            is = client.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            firstLine = reader.readLine();
        } catch (IOException e) {
            Log.e(getClass().getName(), "Error parsing request", e);
            return request;
        }

        StringTokenizer st = new StringTokenizer(firstLine);
        String method = st.nextToken();
        String uri = st.nextToken();
        Log.d(getClass().getName(), uri);
        String realUri = uri.substring(1);
        Log.d(getClass().getName(), realUri);
        request = new BasicHttpRequest(method, realUri);
        return request;
    }

    private HttpResponse download(String url) {
        DefaultHttpClient seed = new DefaultHttpClient();
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        SingleClientConnManager mgr = new MyClientConnManager(seed.getParams(), registry);
        DefaultHttpClient http = new DefaultHttpClient(mgr, seed.getParams());
        HttpGet method = new HttpGet(url);
        HttpResponse response = null;
        try {
            Log.d(getClass().getName(), "starting download");
            response = http.execute(method);
            Log.d(getClass().getName(), "downloaded");

        } catch (java.net.UnknownHostException e) {
            Intent i = new Intent("org.prx.errorInStream");
            mContext.sendBroadcast(i);
        } catch (ClientProtocolException e) {
            Log.e(getClass().getName(), "Error downloading", e);
        } catch (IOException e) {
            Log.e(getClass().getName(), "Error downloading", e);
        }
        return response;
    }

    private void processRequest(HttpRequest request, Socket client) throws IllegalStateException, IOException {
        if (request == null) {
            return;
        }
        Log.d(getClass().getName(), "processing");
        String url = request.getRequestLine().getUri();
        HttpResponse realResponse = download(url);
        if (realResponse == null) {
            return;
        }

        Log.d(getClass().getName(), "downloading...");

        InputStream data = realResponse.getEntity().getContent();
        StatusLine line = realResponse.getStatusLine();
        HttpResponse response = new BasicHttpResponse(line);
        response.setHeaders(realResponse.getAllHeaders());

        Log.d(getClass().getName(), "reading headers");
        StringBuilder httpString = new StringBuilder();
        httpString.append(response.getStatusLine().toString());

        httpString.append("\n");
        for (Header h : response.getAllHeaders()) {
            httpString.append(h.getName()).append(": ").append(h.getValue()).append("\n");
        }
        httpString.append("\n");
        Log.d(getClass().getName(), "headers done");
        //Log.d("PRPAND","Response "+httpString);
        try {
            byte[] buffer = httpString.toString().getBytes();
            int readBytes = -1;
            Log.d(getClass().getName(), "writing to client");
            client.getOutputStream().write(buffer, 0, buffer.length);

            // Start streaming content.
            byte[] buff = new byte[1024 * 50];
            while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) {
                client.getOutputStream().write(buff, 0, readBytes);
            }
        } catch (Exception e) {
            Log.e("", e.getMessage(), e);
        } finally {
            if (data != null) {
                data.close();
            }
            client.close();

        }
    }

    private class IcyLineParser extends BasicLineParser {
        private static final String ICY_PROTOCOL_NAME = "ICY";

        private IcyLineParser() {
            super();
        }

        @Override
        public boolean hasProtocolVersion(CharArrayBuffer buffer, ParserCursor cursor) {
            boolean superFound = super.hasProtocolVersion(buffer, cursor);
            if (superFound) {
                return true;
            }
            int index = cursor.getPos();

            final int protolength = ICY_PROTOCOL_NAME.length();

            if (buffer.length() < protolength)
                return false; // not long enough for "HTTP/1.1"

            if (index < 0) {
                // end of line, no tolerance for trailing whitespace
                // this works only for single-digit major and minor version
                index = buffer.length() - protolength;
            } else if (index == 0) {
                // beginning of line, tolerate leading whitespace
                while ((index < buffer.length()) && HTTP.isWhitespace(buffer.charAt(index))) {
                    index++;
                }
            } // else within line, don't tolerate whitespace

            if (index + protolength > buffer.length())
                return false;

            return buffer.substring(index, index + protolength).equals(ICY_PROTOCOL_NAME);
        }

        @Override
        public Header parseHeader(CharArrayBuffer buffer) throws ParseException {
            return super.parseHeader(buffer);
        }

        @Override
        public ProtocolVersion parseProtocolVersion(CharArrayBuffer buffer, ParserCursor cursor)
                throws ParseException {

            if (buffer == null) {
                throw new IllegalArgumentException("Char array buffer may not be null");
            }
            if (cursor == null) {
                throw new IllegalArgumentException("Parser cursor may not be null");
            }

            final int protolength = ICY_PROTOCOL_NAME.length();

            int indexFrom = cursor.getPos();
            int indexTo = cursor.getUpperBound();

            skipWhitespace(buffer, cursor);

            int i = cursor.getPos();

            // long enough for "HTTP/1.1"?
            if (i + protolength + 4 > indexTo) {
                throw new ParseException("Not a valid protocol version: " + buffer.substring(indexFrom, indexTo));
            }

            if (!buffer.substring(i, i + protolength).equals(ICY_PROTOCOL_NAME)) {
                return super.parseProtocolVersion(buffer, cursor);
            }

            cursor.updatePos(i + protolength);

            return createProtocolVersion(1, 0);
        }

        @Override
        public RequestLine parseRequestLine(CharArrayBuffer buffer, ParserCursor cursor) throws ParseException {
            return super.parseRequestLine(buffer, cursor);
        }

        @Override
        public StatusLine parseStatusLine(CharArrayBuffer buffer, ParserCursor cursor) throws ParseException {
            StatusLine superLine = super.parseStatusLine(buffer, cursor);
            return superLine;
        }
    }

    class MyClientConnection extends DefaultClientConnection {
        @Override
        protected HttpMessageParser createResponseParser(final SessionInputBuffer buffer,
                final HttpResponseFactory responseFactory, final HttpParams params) {
            return new DefaultResponseParser(buffer, new IcyLineParser(), responseFactory, params);
        }
    }

    class MyClientConnectionOperator extends DefaultClientConnectionOperator {
        public MyClientConnectionOperator(final SchemeRegistry sr) {
            super(sr);
        }

        @Override
        public OperatedClientConnection createConnection() {
            return new MyClientConnection();
        }
    }

    class MyClientConnManager extends SingleClientConnManager {
        private MyClientConnManager(HttpParams params, SchemeRegistry schreg) {
            super(params, schreg);
        }

        @Override
        protected ClientConnectionOperator createConnectionOperator(final SchemeRegistry sr) {
            return new MyClientConnectionOperator(sr);
        }
    }

}