1/*
2 * Copyright (C) 2011 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
17package libcore.net.spdy;
18
19import java.io.File;
20import java.io.FileInputStream;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.OutputStream;
24import java.net.ServerSocket;
25import java.net.Socket;
26import java.util.Arrays;
27import java.util.List;
28
29/**
30 * A basic SPDY server that serves the contents of a local directory. This
31 * server will service a single SPDY connection.
32 */
33public final class SpdyServer implements IncomingStreamHandler {
34    private final File baseDirectory;
35
36    public SpdyServer(File baseDirectory) {
37        this.baseDirectory = baseDirectory;
38    }
39
40    private void run() throws IOException {
41        ServerSocket serverSocket = new ServerSocket(8888);
42        serverSocket.setReuseAddress(true);
43
44        Socket socket = serverSocket.accept();
45        new SpdyConnection.Builder(false, socket)
46                .handler(this)
47                .build();
48    }
49
50    @Override public void receive(final SpdyStream stream) throws IOException {
51        List<String> requestHeaders = stream.getRequestHeaders();
52        String path = null;
53        for (int i = 0; i < requestHeaders.size(); i += 2) {
54            String s = requestHeaders.get(i);
55            if ("url".equals(s)) {
56                path = requestHeaders.get(i + 1);
57                break;
58            }
59        }
60
61        if (path == null) {
62            // TODO: send bad request error
63            throw new AssertionError();
64        }
65
66        File file = new File(baseDirectory + path);
67
68        if (file.exists() && !file.isDirectory()) {
69            serveFile(stream, file);
70        } else {
71            send404(stream, path);
72        }
73    }
74
75    private void send404(SpdyStream stream, String path) throws IOException {
76        List<String> responseHeaders = Arrays.asList(
77                "status", "404",
78                "version", "HTTP/1.1",
79                "content-type", "text/plain"
80        );
81        OutputStream out = stream.reply(responseHeaders);
82        String text = "Not found: " + path;
83        out.write(text.getBytes("UTF-8"));
84        out.close();
85    }
86
87    private void serveFile(SpdyStream stream, File file) throws IOException {
88        InputStream in = new FileInputStream(file);
89        byte[] buffer = new byte[8192];
90        OutputStream out = stream.reply(Arrays.asList(
91                "status", "200",
92                "version", "HTTP/1.1",
93                "content-type", contentType(file)
94        ));
95        int count;
96        while ((count = in.read(buffer)) != -1) {
97            out.write(buffer, 0, count);
98        }
99        out.close();
100    }
101
102    private String contentType(File file) {
103        return file.getName().endsWith(".html") ? "text/html" : "text/plain";
104    }
105
106    public static void main(String... args) throws IOException {
107        if (args.length != 1 || args[0].startsWith("-")) {
108            System.out.println("Usage: SpdyServer <base directory>");
109            return;
110        }
111
112        new SpdyServer(new File(args[0])).run();
113    }
114}
115