package org.objectstyle.wolips.womodeler.server;
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.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import org.objectstyle.wolips.preferences.PreferencesPlugin;
import org.objectstyle.wolips.womodeler.preferences.PreferenceConstants;
public class Request implements Runnable {
public static final String METHOD_GET = "GET";
public static final String METHOD_POST = "POST";
public static final String CONTENT_LENGTH = "content-length";
private Webserver _server;
private Socket _socket;
private OutputStream _outputStream;
private String _method;
private String _pathAndQueryString;
private String _path;
private String _queryString;
private String _content;
private Map<String, String> _queryParameters;
private Map<String, String> _requestHeaders;
private Map<String, String> _responseHeaders;
private int _responseCode;
private ByteArrayOutputStream _responseStream;
public Request(Webserver server, Socket socket) {
_server = server;
_socket = socket;
_responseStream = new ByteArrayOutputStream();
_responseCode = 200;
}
public void run() {
//System.out.println("Request.run: request " + hashCode() + " begin");
try {
_responseHeaders = new HashMap<String, String>();
InputStream is = _socket.getInputStream();
_outputStream = _socket.getOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String request = br.readLine();
boolean inputDone = false;
while (!inputDone) {
String line = br.readLine();
if (line == null) {
inputDone = true;
}
else if ("".equals(line)) {
inputDone = true;
}
else {
int colonIndex = line.indexOf(':');
if (colonIndex != -1) {
if (_requestHeaders == null) {
_requestHeaders = new HashMap<String, String>();
}
String key = line.substring(0, colonIndex).trim().toLowerCase();
String value = line.substring(colonIndex + 1).trim().toLowerCase();
_requestHeaders.put(key, value);
}
}
}
String[] requestElements = request.split(" ");
_method = requestElements[0].toUpperCase();
if (Request.METHOD_GET.equalsIgnoreCase(_method)) {
_pathAndQueryString = (requestElements[1].startsWith("/") ? "" : "/") + requestElements[1];
parsePathAndQuery();
String womodelerPassword = PreferencesPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.WOMODELER_SERVER_PASSWORD);
if (_queryParameters != null && womodelerPassword != null && womodelerPassword.equals(_queryParameters.get("pw"))) {
IRequestHandler handler = _server.getHandler(this);
if (handler != null) {
handler.handle(this);
}
else {
_responseCode = 404;
}
}
else {
_responseCode = 401;
}
}
else if (Request.METHOD_POST.equalsIgnoreCase(_method)) {
StringBuffer contentBuffer = new StringBuffer();
String contentLengthStr = _requestHeaders.get(Request.CONTENT_LENGTH);
if (contentLengthStr == null) {
throw new IOException("Missing Content-Length header.");
}
int contentLength = Integer.parseInt(contentLengthStr);
if (contentLength > 1024 * 1024) {
throw new IOException("Illegal Content-Length: " + contentLength);
}
char[] buf = new char[2048];
while (contentLength > 0 && br.ready()) {
int charsRead = br.read(buf, 0, Math.min(contentLength, buf.length));
if (charsRead == -1) {
throw new IOException("Request stopped by client.");
}
else if (charsRead > 0) {
contentLength -= charsRead;
contentBuffer.append(buf, 0, charsRead);
}
}
_content = contentBuffer.toString();
_pathAndQueryString = (requestElements[1].startsWith("/") ? "" : "/") + requestElements[1];
parsePathAndQuery();
try {
IRequestHandler handler = _server.getHandler(this);
handler.handle(this);
}
catch (FileNotFoundException e) {
_responseStream.reset();
_responseCode = 404;
getWriter().println("File Not Found: " + e.getMessage());
}
}
PrintWriter pw = new PrintWriter(new OutputStreamWriter(_outputStream), true);
pw.print("HTTP/1.1 ");
pw.print(_responseCode);
pw.print(" ");
if (_responseCode == 200) {
pw.println("OK");
}
else if (_responseCode == 404) {
pw.println("Not Found");
}
else if (_responseCode == 401) {
pw.println("Authorization Required");
}
else {
pw.println("Unknown");
}
pw.println("Connection: close");
for (Map.Entry<String, String> responseHeader : _responseHeaders.entrySet()) {
pw.println(responseHeader.getKey() + ": " + responseHeader.getValue());
}
pw.println();
pw.flush();
_outputStream.write(_responseStream.toByteArray(), 0, _responseStream.size());
_outputStream.flush();
}
catch (Throwable t) {
t.printStackTrace();
}
finally {
try {
if (_outputStream != null) {
_outputStream.flush();
}
}
catch (Throwable t) {
t.printStackTrace();
}
try {
_socket.close();
}
catch (Throwable t) {
t.printStackTrace();
}
//System.out.println("Request.run: request " + hashCode() + " end -- " + getPath());
}
}
public String getMethod() {
return _method;
}
public String getPath() {
return _path;
}
public String getContent() {
return _content;
}
public void setResponseCode(int responseCode) {
_responseCode = responseCode;
}
public int getResponseCode() {
return _responseCode;
}
public String getQueryString() {
return _queryString;
}
public String getPathAndQueryString() {
return _pathAndQueryString;
}
public String getQueryParameter(String name) {
return (_queryParameters == null) ? null : _queryParameters.get(name);
}
public Map<String, String> getResponseHeaders() {
return _responseHeaders;
}
public Map<String, String> getQueryParameters() {
return _queryParameters;
}
public Map<String, String> getRequestHeaders() {
return _requestHeaders;
}
public String getRequestHeader(String name) {
return (_requestHeaders == null) ? null : _requestHeaders.get(name);
}
public OutputStream getOutputStream() {
return _responseStream;
}
public PrintWriter getWriter() {
return new PrintWriter(new OutputStreamWriter(_responseStream), true);
}
public Webserver getServer() {
return _server;
}
protected void parsePathAndQuery() throws UnsupportedEncodingException {
int queryStringIndex = _pathAndQueryString.indexOf("?");
if (queryStringIndex != -1) {
_queryParameters = new HashMap<String, String>();
_path = _pathAndQueryString.substring(0, queryStringIndex);
_queryString = _pathAndQueryString.substring(queryStringIndex + 1);
_queryString = _queryString.replace("&", "&");
String[] nvPairs = _queryString.split("&");
for (int i = 0; i < nvPairs.length; i++) {
int equalsIndex = nvPairs[i].indexOf('=');
if (equalsIndex == -1) {
_queryParameters.put(URLDecoder.decode(nvPairs[i], "UTF-8"), "");
}
else {
_queryParameters.put(URLDecoder.decode(nvPairs[i].substring(0, equalsIndex), "UTF-8"), URLDecoder.decode(nvPairs[i].substring(equalsIndex + 1), "UTF-8"));
}
}
}
else {
_path = _pathAndQueryString;
_queryString = null;
}
}
}