source: josm/trunk/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java@ 4798

Last change on this file since 4798 was 4798, checked in by simon04, 12 years ago

see #6425 - follow naming convention

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.remotecontrol;
3
4import java.io.BufferedInputStream;
5import java.io.BufferedOutputStream;
6import java.io.IOException;
7import java.io.InputStreamReader;
8import java.io.OutputStream;
9import java.io.OutputStreamWriter;
10import java.io.Reader;
11import java.io.Writer;
12import java.net.Socket;
13import java.util.Date;
14import java.util.HashMap;
15import java.util.StringTokenizer;
16
17import org.openstreetmap.josm.io.remotecontrol.handler.AddNodeHandler;
18import org.openstreetmap.josm.io.remotecontrol.handler.ImageryHandler;
19import org.openstreetmap.josm.io.remotecontrol.handler.ImportHandler;
20import org.openstreetmap.josm.io.remotecontrol.handler.LoadAndZoomHandler;
21import org.openstreetmap.josm.io.remotecontrol.handler.LoadObjectHandler;
22import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler;
23import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
24import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerErrorException;
25import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerForbiddenException;
26import org.openstreetmap.josm.io.remotecontrol.handler.VersionHandler;
27
28/**
29 * Processes HTTP "remote control" requests.
30 */
31public class RequestProcessor extends Thread {
32 /**
33 * RemoteControl protocol version. Change minor number for compatible
34 * interface extensions. Change major number in case of incompatible
35 * changes.
36 */
37 public static final String PROTOCOLVERSION = "{\"protocolversion\": {\"major\": " +
38 RemoteControl.protocolMajorVersion + ", \"minor\": " +
39 RemoteControl.protocolMinorVersion +
40 "}, \"application\": \"JOSM RemoteControl\"}";
41
42 /** The socket this processor listens on */
43 private Socket request;
44
45 /**
46 * Collection of request handlers.
47 * Will be initialized with default handlers here. Other plug-ins
48 * can extend this list by using @see addRequestHandler
49 */
50 private static HashMap<String, Class<? extends RequestHandler>> handlers = new HashMap<String, Class<? extends RequestHandler>>();
51
52 /**
53 * Constructor
54 *
55 * @param request A socket to read the request.
56 */
57 public RequestProcessor(Socket request) {
58 super("RemoteControl request processor");
59 this.setDaemon(true);
60 this.request = request;
61 }
62
63 /**
64 * Spawns a new thread for the request
65 */
66 public static void processRequest(Socket request) {
67 RequestProcessor processor = new RequestProcessor(request);
68 processor.start();
69 }
70
71 /**
72 * Add external request handler. Can be used by other plug-ins that
73 * want to use remote control.
74 *
75 * @param command The command to handle.
76 * @param handler The additional request handler.
77 */
78 static void addRequestHandlerClass(String command,
79 Class<? extends RequestHandler> handler) {
80 addRequestHandlerClass(command, handler, false);
81 }
82
83 /**
84 * Add external request handler. Message can be suppressed.
85 * (for internal use)
86 *
87 * @param command The command to handle.
88 * @param handler The additional request handler.
89 * @param silent Don't show message if true.
90 */
91 private static void addRequestHandlerClass(String command,
92 Class<? extends RequestHandler> handler, boolean silent) {
93 if(command.charAt(0) == '/')
94 {
95 command = command.substring(1);
96 }
97 String commandWithSlash = "/" + command;
98 if (handlers.get(commandWithSlash) != null) {
99 System.out.println("RemoteControl: ignoring duplicate command " + command
100 + " with handler " + handler.getName());
101 } else {
102 if (!silent) {
103 System.out.println("RemoteControl: adding command \"" +
104 command + "\" (handled by " + handler.getSimpleName() + ")");
105 }
106 handlers.put(commandWithSlash, handler);
107 }
108 }
109
110 /** Add default request handlers */
111 static {
112 addRequestHandlerClass(LoadAndZoomHandler.command,
113 LoadAndZoomHandler.class, true);
114 addRequestHandlerClass(LoadAndZoomHandler.command2,
115 LoadAndZoomHandler.class, true);
116 addRequestHandlerClass(ImageryHandler.command, ImageryHandler.class, true);
117 addRequestHandlerClass(AddNodeHandler.command, AddNodeHandler.class, true);
118 addRequestHandlerClass(ImportHandler.command, ImportHandler.class, true);
119 addRequestHandlerClass(VersionHandler.command, VersionHandler.class, true);
120 addRequestHandlerClass(LoadObjectHandler.command, LoadObjectHandler.class, true);
121 }
122
123 /**
124 * The work is done here.
125 */
126 public void run() {
127 Writer out = null;
128 try {
129 OutputStream raw = new BufferedOutputStream(
130 request.getOutputStream());
131 out = new OutputStreamWriter(raw);
132 Reader in = new InputStreamReader(new BufferedInputStream(
133 request.getInputStream()), "ASCII");
134
135 StringBuffer requestLine = new StringBuffer();
136 while (requestLine.length() < 1024) {
137 int c = in.read();
138 if (c == '\r' || c == '\n')
139 break;
140 requestLine.append((char) c);
141 }
142
143 System.out.println("RemoteControl received: " + requestLine);
144 String get = requestLine.toString();
145 StringTokenizer st = new StringTokenizer(get);
146 if (!st.hasMoreTokens()) {
147 sendError(out);
148 return;
149 }
150 String method = st.nextToken();
151 if (!st.hasMoreTokens()) {
152 sendError(out);
153 return;
154 }
155 String url = st.nextToken();
156
157 if (!method.equals("GET")) {
158 sendNotImplemented(out);
159 return;
160 }
161
162 String command = null;
163 int questionPos = url.indexOf('?');
164 if(questionPos < 0)
165 {
166 command = url;
167 }
168 else
169 {
170 command = url.substring(0, questionPos);
171 }
172
173 // find a handler for this command
174 Class<? extends RequestHandler> handlerClass = handlers
175 .get(command);
176 if (handlerClass == null) {
177 // no handler found
178 sendBadRequest(out);
179 } else {
180 // create handler object
181 RequestHandler handler = handlerClass.newInstance();
182 try {
183 handler.setCommand(command);
184 handler.setUrl(url);
185 handler.checkPermission();
186 handler.handle();
187 sendHeader(out, "200 OK", handler.getContentType(), false);
188 out.write("Content-length: " + handler.getContent().length()
189 + "\r\n");
190 out.write("\r\n");
191 out.write(handler.getContent());
192 out.flush();
193 } catch (RequestHandlerErrorException ex) {
194 sendError(out);
195 } catch (RequestHandlerBadRequestException ex) {
196 sendBadRequest(out);
197 } catch (RequestHandlerForbiddenException ex) {
198 sendForbidden(out);
199 }
200 }
201
202 } catch (IOException ioe) {
203 } catch (Exception e) {
204 e.printStackTrace();
205 try {
206 sendError(out);
207 } catch (IOException e1) {
208 }
209 } finally {
210 try {
211 request.close();
212 } catch (IOException e) {
213 }
214 }
215 }
216
217 /**
218 * Sends a 500 error: server error
219 *
220 * @param out
221 * The writer where the error is written
222 * @throws IOException
223 * If the error can not be written
224 */
225 private void sendError(Writer out) throws IOException {
226 sendHeader(out, "500 Internal Server Error", "text/html", true);
227 out.write("<HTML>\r\n");
228 out.write("<HEAD><TITLE>Internal Error</TITLE>\r\n");
229 out.write("</HEAD>\r\n");
230 out.write("<BODY>");
231 out.write("<H1>HTTP Error 500: Internal Server Error</h2>\r\n");
232 out.write("</BODY></HTML>\r\n");
233 out.flush();
234 }
235
236 /**
237 * Sends a 501 error: not implemented
238 *
239 * @param out
240 * The writer where the error is written
241 * @throws IOException
242 * If the error can not be written
243 */
244 private void sendNotImplemented(Writer out) throws IOException {
245 sendHeader(out, "501 Not Implemented", "text/html", true);
246 out.write("<HTML>\r\n");
247 out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
248 out.write("</HEAD>\r\n");
249 out.write("<BODY>");
250 out.write("<H1>HTTP Error 501: Not Implemented</h2>\r\n");
251 out.write("</BODY></HTML>\r\n");
252 out.flush();
253 }
254
255 /**
256 * Sends a 403 error: forbidden
257 *
258 * @param out
259 * The writer where the error is written
260 * @throws IOException
261 * If the error can not be written
262 */
263 private void sendForbidden(Writer out) throws IOException {
264 sendHeader(out, "403 Forbidden", "text/html", true);
265 out.write("<HTML>\r\n");
266 out.write("<HEAD><TITLE>Forbidden</TITLE>\r\n");
267 out.write("</HEAD>\r\n");
268 out.write("<BODY>");
269 out.write("<H1>HTTP Error 403: Forbidden</h2>\r\n");
270 out.write("</BODY></HTML>\r\n");
271 out.flush();
272 }
273
274 /**
275 * Sends a 403 error: forbidden
276 *
277 * @param out
278 * The writer where the error is written
279 * @throws IOException
280 * If the error can not be written
281 */
282 private void sendBadRequest(Writer out) throws IOException {
283 sendHeader(out, "400 Bad Request", "text/html", true);
284 out.write("<HTML>\r\n");
285 out.write("<HEAD><TITLE>Bad Request</TITLE>\r\n");
286 out.write("</HEAD>\r\n");
287 out.write("<BODY>");
288 out.write("<H1>HTTP Error 400: Bad Request</h2>\r\n");
289 out.write("</BODY></HTML>\r\n");
290 out.flush();
291 }
292
293 /**
294 * Send common HTTP headers to the client.
295 *
296 * @param out
297 * The Writer
298 * @param status
299 * The status string ("200 OK", "500", etc)
300 * @param contentType
301 * The content type of the data sent
302 * @param endHeaders
303 * If true, adds a new line, ending the headers.
304 * @throws IOException
305 * When error
306 */
307 private void sendHeader(Writer out, String status, String contentType,
308 boolean endHeaders) throws IOException {
309 out.write("HTTP/1.1 " + status + "\r\n");
310 Date now = new Date();
311 out.write("Date: " + now + "\r\n");
312 out.write("Server: JOSM RemoteControl\r\n");
313 out.write("Content-type: " + contentType + "\r\n");
314 out.write("Access-Control-Allow-Origin: *\r\n");
315 if (endHeaders)
316 out.write("\r\n");
317 }
318}
Note: See TracBrowser for help on using the repository browser.