close
The Wayback Machine - https://web.archive.org/web/20160417074107/https://developer.android.com/samples/PermissionRequest/src/com.example.android.permissionrequest/SimpleWebServer.html
Show navigation Hide navigation
PermissionRequest / src / com.example.android.permissionrequest /

SimpleWebServer.java

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
    @Override
94
    public void run() {
95
        try {
96
            mServerSocket = new ServerSocket(mPort);
97
            while (mIsRunning) {
98
                Socket socket = mServerSocket.accept();
99
                handle(socket);
100
                socket.close();
101
            }
102
        } catch (SocketException e) {
103
            // The server was stopped; ignore.
104
        } catch (IOException e) {
105
            Log.e(TAG, "Web server error.", e);
106
        }
107
    }
108
 
109
    /**
110
     * Respond to a request from a client.
111
     *
112
     * @param socket The client socket.
113
     * @throws IOException
114
     */
115
    private void handle(Socket socket) throws IOException {
116
        BufferedReader reader = null;
117
        PrintStream output = null;
118
        try {
119
            String route = null;
120
 
121
            // Read HTTP headers and parse out the route.
122
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
123
            String line;
124
            while (!TextUtils.isEmpty(line = reader.readLine())) {
125
                if (line.startsWith("GET /")) {
126
                    int start = line.indexOf('/') + 1;
127
                    int end = line.indexOf(' ', start);
128
                    route = line.substring(start, end);
129
                    break;
130
                }
131
            }
132
 
133
            // Output stream that we send the response to
134
            output = new PrintStream(socket.getOutputStream());
135
 
136
            // Prepare the content to send.
137
            if (null == route) {
138
                writeServerError(output);
139
                return;
140
            }
141
            byte[] bytes = loadContent(route);
142
            if (null == bytes) {
143
                writeServerError(output);
144
                return;
145
            }
146
 
147
            // Send out the content.
148
            output.println("HTTP/1.0 200 OK");
149
            output.println("Content-Type: " + detectMimeType(route));
150
            output.println("Content-Length: " + bytes.length);
151
            output.println();
152
            output.write(bytes);
153
            output.flush();
154
        } finally {
155
            if (null != output) {
156
                output.close();
157
            }
158
            if (null != reader) {
159
                reader.close();
160
            }
161
        }
162
    }
163
 
164
    /**
165
     * Writes a server error response (HTTP/1.0 500) to the given output stream.
166
     *
167
     * @param output The output stream.
168
     */
169
    private void writeServerError(PrintStream output) {
170
        output.println("HTTP/1.0 500 Internal Server Error");
171
        output.flush();
172
    }
173
 
174
    /**
175
     * Loads all the content of {@code fileName}.
176
     *
177
     * @param fileName The name of the file.
178
     * @return The content of the file.
179
     * @throws IOException
180
     */
181
    private byte[] loadContent(String fileName) throws IOException {
182
        InputStream input = null;
183
        try {
184
            ByteArrayOutputStream output = new ByteArrayOutputStream();
185
            input = mAssets.open(fileName);
186
            byte[] buffer = new byte[1024];
187
            int size;
188
            while (-1 != (size = input.read(buffer))) {
189
                output.write(buffer, 0, size);
190
            }
191
            output.flush();
192
            return output.toByteArray();
193
        } catch (FileNotFoundException e) {
194
            return null;
195
        } finally {
196
            if (null != input) {
197
                input.close();
198
            }
199
        }
200
    }
201
 
202
    /**
203
     * Detects the MIME type from the {@code fileName}.
204
     *
205
     * @param fileName The name of the file.
206
     * @return A MIME type.
207
     */
208
    private String detectMimeType(String fileName) {
209
        if (TextUtils.isEmpty(fileName)) {
210
            return null;
211
        } else if (fileName.endsWith(".html")) {
212
            return "text/html";
213
        } else if (fileName.endsWith(".js")) {
214
            return "application/javascript";
215
        } else if (fileName.endsWith(".css")) {
216
            return "text/css";
217
        } else {
218
            return "application/octet-stream";
219
        }
220
    }
221
 
222
}