// HomeAutomation software to accompany the book // 'Practical Arduino + Android Projects for the Evil Genius' // Copyright (C) 2011. Simon Monk // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. package com.simonmonk.home; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; class WebServer extends Thread { final int PORT = 8080; private HomeActivity mActivity; public WebServer(HomeActivity activity) { super(); mActivity = activity; } public void run() { ResponseHelper helper = new ResponseHelper(mActivity); try { ServerSocket serversocket = new ServerSocket(PORT); setStatus("Started, Connect to: " + mActivity.URL + "home?"); while (true) { Socket connectionsocket = serversocket.accept(); BufferedReader input = new BufferedReader(new InputStreamReader(connectionsocket.getInputStream()), 8192); DataOutputStream output = new DataOutputStream(connectionsocket.getOutputStream()); handleRequest(input, output, helper); } } catch (Throwable e) { setStatus(e.getMessage()); } } private void setStatus(final String message) { mActivity.runOnUiThread(new Runnable() { public void run() { mActivity.setStatus(message); } }); } private void handleRequest(BufferedReader input, DataOutputStream output, ResponseHelper helper) throws Exception { // todo - make bullet proof !!!!!! String request = input.readLine(); // GET /page?arg1=fred&arg2=smith HTTP/1.1 int indexOfSlash = request.indexOf('/'); int indexOfQ = request.indexOf('?'); String page = null; String paramsString = null; String response = ""; if (indexOfSlash < 0 || indexOfQ <= indexOfSlash) { response = generateError("No page specified"); } else { int indexOfSpace = request.indexOf("HTTP")-1; if (indexOfSpace >= indexOfQ) { page = request.substring(indexOfSlash+1, indexOfQ); paramsString = request.substring(indexOfQ+1, indexOfSpace); response = helper.generateResponse(page, mActivity.URL, parseParams(paramsString)); } } output.writeBytes(constructHttpHeader()); output.writeBytes(response); output.close(); } private String constructHttpHeader() { String s = "HTTP/1.0 "; s = s + "200 OK"; s = s + "\r\n"; //other header fields, s = s + "Connection: close\r\n"; //we can't handle persistent connections s = s + "Server: Home Automation v0\r\n"; //server name s = s + "Content-Type: text/html\r\n"; s = s + "\r\n"; return s; } private HashMap<String, String> parseParams(String paramsString) { HashMap<String, String> map = new HashMap<String, String>(); //arg1=fred&arg2=smith if (paramsString == null) { return map; } final int READING_NAME = 0; final int READING_VALUE = 1; String name = ""; String value = ""; int state = READING_NAME; int i = 0; char ch; int n = paramsString.length(); while (i < n) { ch = paramsString.charAt(i); i++; if (state == READING_NAME) { if (ch == '=') { state = READING_VALUE; } else { name = name + ch; } continue; } if (state == READING_VALUE) { if (ch == '&' || i == n) { if (i == n) { value = value + ch; } map.put(name, value); name = ""; value = ""; state = READING_NAME; } else { value = value + ch; } } } return map; } private String generateError(String message) { String s = "<html><body>"; s = s + "<H1>Error</H1>"; s = s + "<p>" + message + "</p>"; s = s +"</body></html>"; return s; } }