Home | History | Annotate | Download | only in com.example.android.permissionrequest
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.permissionrequest;
     18 
     19 import android.content.res.AssetManager;
     20 import android.text.TextUtils;
     21 import android.util.Log;
     22 
     23 import java.io.BufferedReader;
     24 import java.io.ByteArrayOutputStream;
     25 import java.io.FileNotFoundException;
     26 import java.io.IOException;
     27 import java.io.InputStream;
     28 import java.io.InputStreamReader;
     29 import java.io.PrintStream;
     30 import java.net.ServerSocket;
     31 import java.net.Socket;
     32 import java.net.SocketException;
     33 
     34 /**
     35  * Implementation of a very basic HTTP server. The contents are loaded from the assets folder. This
     36  * server handles one request at a time. It only supports GET method.
     37  */
     38 public class SimpleWebServer implements Runnable {
     39 
     40     private static final String TAG = "SimpleWebServer";
     41 
     42     /**
     43      * The port number we listen to
     44      */
     45     private final int mPort;
     46 
     47     /**
     48      * {@link android.content.res.AssetManager} for loading files to serve.
     49      */
     50     private final AssetManager mAssets;
     51 
     52     /**
     53      * True if the server is running.
     54      */
     55     private boolean mIsRunning;
     56 
     57     /**
     58      * The {@link java.net.ServerSocket} that we listen to.
     59      */
     60     private ServerSocket mServerSocket;
     61 
     62     /**
     63      * WebServer constructor.
     64      */
     65     public SimpleWebServer(int port, AssetManager assets) {
     66         mPort = port;
     67         mAssets = assets;
     68     }
     69 
     70     /**
     71      * This method starts the web server listening to the specified port.
     72      */
     73     public void start() {
     74         mIsRunning = true;
     75         new Thread(this).start();
     76     }
     77 
     78     /**
     79      * This method stops the web server
     80      */
     81     public void stop() {
     82         try {
     83             mIsRunning = false;
     84             if (null != mServerSocket) {
     85                 mServerSocket.close();
     86                 mServerSocket = null;
     87             }
     88         } catch (IOException e) {
     89             Log.e(TAG, "Error closing the server socket.", e);
     90         }
     91     }
     92 
     93     public int getPort() {
     94         return mPort;
     95     }
     96 
     97     @Override
     98     public void run() {
     99         try {
    100             mServerSocket = new ServerSocket(mPort);
    101             while (mIsRunning) {
    102                 Socket socket = mServerSocket.accept();
    103                 handle(socket);
    104                 socket.close();
    105             }
    106         } catch (SocketException e) {
    107             // The server was stopped; ignore.
    108         } catch (IOException e) {
    109             Log.e(TAG, "Web server error.", e);
    110         }
    111     }
    112 
    113     /**
    114      * Respond to a request from a client.
    115      *
    116      * @param socket The client socket.
    117      * @throws IOException
    118      */
    119     private void handle(Socket socket) throws IOException {
    120         BufferedReader reader = null;
    121         PrintStream output = null;
    122         try {
    123             String route = null;
    124 
    125             // Read HTTP headers and parse out the route.
    126             reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    127             String line;
    128             while (!TextUtils.isEmpty(line = reader.readLine())) {
    129                 if (line.startsWith("GET /")) {
    130                     int start = line.indexOf('/') + 1;
    131                     int end = line.indexOf(' ', start);
    132                     route = line.substring(start, end);
    133                     break;
    134                 }
    135             }
    136 
    137             // Output stream that we send the response to
    138             output = new PrintStream(socket.getOutputStream());
    139 
    140             // Prepare the content to send.
    141             if (null == route) {
    142                 writeServerError(output);
    143                 return;
    144             }
    145             byte[] bytes = loadContent(route);
    146             if (null == bytes) {
    147                 writeServerError(output);
    148                 return;
    149             }
    150 
    151             // Send out the content.
    152             output.println("HTTP/1.0 200 OK");
    153             output.println("Content-Type: " + detectMimeType(route));
    154             output.println("Content-Length: " + bytes.length);
    155             output.println();
    156             output.write(bytes);
    157             output.flush();
    158         } finally {
    159             if (null != output) {
    160                 output.close();
    161             }
    162             if (null != reader) {
    163                 reader.close();
    164             }
    165         }
    166     }
    167 
    168     /**
    169      * Writes a server error response (HTTP/1.0 500) to the given output stream.
    170      *
    171      * @param output The output stream.
    172      */
    173     private void writeServerError(PrintStream output) {
    174         output.println("HTTP/1.0 500 Internal Server Error");
    175         output.flush();
    176     }
    177 
    178     /**
    179      * Loads all the content of {@code fileName}.
    180      *
    181      * @param fileName The name of the file.
    182      * @return The content of the file.
    183      * @throws IOException
    184      */
    185     private byte[] loadContent(String fileName) throws IOException {
    186         InputStream input = null;
    187         try {
    188             ByteArrayOutputStream output = new ByteArrayOutputStream();
    189             input = mAssets.open(fileName);
    190             byte[] buffer = new byte[1024];
    191             int size;
    192             while (-1 != (size = input.read(buffer))) {
    193                 output.write(buffer, 0, size);
    194             }
    195             output.flush();
    196             return output.toByteArray();
    197         } catch (FileNotFoundException e) {
    198             return null;
    199         } finally {
    200             if (null != input) {
    201                 input.close();
    202             }
    203         }
    204     }
    205 
    206     /**
    207      * Detects the MIME type from the {@code fileName}.
    208      *
    209      * @param fileName The name of the file.
    210      * @return A MIME type.
    211      */
    212     private String detectMimeType(String fileName) {
    213         if (TextUtils.isEmpty(fileName)) {
    214             return null;
    215         } else if (fileName.endsWith(".html")) {
    216             return "text/html";
    217         } else if (fileName.endsWith(".js")) {
    218             return "application/javascript";
    219         } else if (fileName.endsWith(".css")) {
    220             return "text/css";
    221         } else {
    222             return "application/octet-stream";
    223         }
    224     }
    225 
    226 }
    227