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

Last change on this file since 3715 was 3715, checked in by Upliner, 13 years ago

Added imagery plugin to josm core. Imagery plugin is union of wmsplugin and slippymap plugins. It includes code by Tim Waters, Petr Dlouhý, Frederik Ramm and others. Also enables the remotecontol which was integrated in [3707].

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