/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.permissionrequest; import android.content.res.AssetManager; import android.text.TextUtils; import android.util.Log; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; /** * Implementation of a very basic HTTP server. The contents are loaded from the assets folder. This * server handles one request at a time. It only supports GET method. */ public class SimpleWebServer implements Runnable { private static final String TAG = "SimpleWebServer"; /** * The port number we listen to */ private final int mPort; /** * {@link android.content.res.AssetManager} for loading files to serve. */ private final AssetManager mAssets; /** * True if the server is running. */ private boolean mIsRunning; /** * The {@link java.net.ServerSocket} that we listen to. */ private ServerSocket mServerSocket; /** * WebServer constructor. */ public SimpleWebServer(int port, AssetManager assets) { mPort = port; mAssets = assets; } /** * This method starts the web server listening to the specified port. */ public void start() { mIsRunning = true; new Thread(this).start(); } /** * This method stops the web server */ public void stop() { try { mIsRunning = false; if (null != mServerSocket) { mServerSocket.close(); mServerSocket = null; } } catch (IOException e) { Log.e(TAG, "Error closing the server socket.", e); } } @Override public void run() { try { mServerSocket = new ServerSocket(mPort); while (mIsRunning) { Socket socket = mServerSocket.accept(); handle(socket); socket.close(); } } catch (SocketException e) { // The server was stopped; ignore. } catch (IOException e) { Log.e(TAG, "Web server error.", e); } } /** * Respond to a request from a client. * * @param socket The client socket. * @throws IOException */ private void handle(Socket socket) throws IOException { BufferedReader reader = null; PrintStream output = null; try { String route = null; // Read HTTP headers and parse out the route. reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line; while (!TextUtils.isEmpty(line = reader.readLine())) { if (line.startsWith("GET /")) { int start = line.indexOf('/') + 1; int end = line.indexOf(' ', start); route = line.substring(start, end); break; } } // Output stream that we send the response to output = new PrintStream(socket.getOutputStream()); // Prepare the content to send. if (null == route) { writeServerError(output); return; } byte[] bytes = loadContent(route); if (null == bytes) { writeServerError(output); return; } // Send out the content. output.println("HTTP/1.0 200 OK"); output.println("Content-Type: " + detectMimeType(route)); output.println("Content-Length: " + bytes.length); output.println(); output.write(bytes); output.flush(); } finally { if (null != output) { output.close(); } if (null != reader) { reader.close(); } } } /** * Writes a server error response (HTTP/1.0 500) to the given output stream. * * @param output The output stream. */ private void writeServerError(PrintStream output) { output.println("HTTP/1.0 500 Internal Server Error"); output.flush(); } /** * Loads all the content of {@code fileName}. * * @param fileName The name of the file. * @return The content of the file. * @throws IOException */ private byte[] loadContent(String fileName) throws IOException { InputStream input = null; try { ByteArrayOutputStream output = new ByteArrayOutputStream(); input = mAssets.open(fileName); byte[] buffer = new byte[1024]; int size; while (-1 != (size = input.read(buffer))) { output.write(buffer, 0, size); } output.flush(); return output.toByteArray(); } catch (FileNotFoundException e) { return null; } finally { if (null != input) { input.close(); } } } /** * Detects the MIME type from the {@code fileName}. * * @param fileName The name of the file. * @return A MIME type. */ private String detectMimeType(String fileName) { if (TextUtils.isEmpty(fileName)) { return null; } else if (fileName.endsWith(".html")) { return "text/html"; } else if (fileName.endsWith(".js")) { return "application/javascript"; } else if (fileName.endsWith(".css")) { return "text/css"; } else { return "application/octet-stream"; } } }