package io.myweb; import android.net.LocalSocket; import android.util.Log; import io.myweb.http.*; import java.io.*; import java.net.URI; import java.util.List; public class RequestTask implements Runnable { private static final String TAG = RequestTask.class.getName(); private final LocalSocket socket; private final RequestProcessor processor; public RequestTask(LocalSocket socket, RequestProcessor processor) { this.socket = socket; this.processor = processor; } private static final int BUFFER_SIZE = 512; private void writeErrorResponse(String requestId, HttpException ex) { try { ResponseWriter rw = new ResponseWriter(socket.getOutputStream()); rw.write(Response.error(ex).withId(requestId).withBody(preformatted(Log.getStackTraceString(ex)))); rw.close(); } catch (IOException err) { Log.e(TAG, "Error while writing error response " + err, err); } } private static String preformatted(String text) { return "<pre>"+text+"</pre>"; } @Override public void run() { String requestId = null; boolean keepAlive = true; try { PushbackInputStream inputStream; try { inputStream = new PushbackInputStream(socket.getInputStream(), BUFFER_SIZE); } catch (IOException e) { throw new HttpBadRequestException(e.getMessage(), e); } while (keepAlive) { Request request; try { request = readRequest(inputStream); } catch (IOException e) { throw new HttpBadRequestException(e.getMessage(), e); } if (request != null) { requestId = request.getId(); writeResponse(processor.processRequest(request.withBody(inputStream))); keepAlive = request.isKeptAlive(); // make sure request body has been read if (keepAlive) request.readBody(); } else keepAlive = false; } } catch (HttpException e) { Log.e(TAG, "Error " + e, e); writeErrorResponse(requestId, e); } catch (IOException e) { writeErrorResponse(requestId, new HttpInternalErrorException(e.getMessage(), e)); } finally { closeConnection(); } } private void writeResponse(Response response) throws IOException { ResponseWriter rw = new ResponseWriter(socket.getOutputStream()); try { rw.write(response); } finally { rw.close(response); } } private Request readRequest(PushbackInputStream is) throws IOException, HttpBadRequestException { int length; byte[] buffer = new byte[BUFFER_SIZE]; StringBuilder sb = new StringBuilder(); while ((length = is.read(buffer)) != -1) { // find double EOLs String result = new String(buffer, 0, length); int idx = result.indexOf("\r\n\r\n"); if (idx >= 0) { sb.append(result.substring(0, idx)); idx += 4; int len = length - idx; if (len>0) is.unread(buffer, idx, len); break; } else { sb.append(result); } } return Request.parse(sb.toString()); } private void closeConnection() { if (socket != null) { try { socket.getOutputStream().close(); } catch (IOException e) { // ignore any errors when closing output stream } try { socket.close(); } catch (IOException e) { Log.e(TAG, "Error occurred while closing connection " + e); } } } }