source: josm/trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java@ 5008

Last change on this file since 5008 was 5008, checked in by bastiK, 12 years ago

remotecontrol: tolerate '?' in query part of url (see #7434)

  • Property svn:eol-style set to native
File size: 7.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.remotecontrol.handler;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.HashMap;
7import java.util.LinkedList;
8import java.util.List;
9import java.util.StringTokenizer;
10
11import javax.swing.JOptionPane;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
15import org.openstreetmap.josm.tools.Utils;
16
17/**
18 * This is the parent of all classes that handle a specific remote control command
19 *
20 * @author Bodo Meissner
21 */
22public abstract class RequestHandler {
23
24 public static final String globalConfirmationKey = "remotecontrol.always-confirm";
25 public static final boolean globalConfirmationDefault = false;
26 public static final String loadInNewLayerKey = "remotecontrol.new-layer";
27 public static final boolean loadInNewLayerDefault = false;
28
29 /** The GET request arguments */
30 protected HashMap<String,String> args;
31
32 /** The request URL without "GET". */
33 protected String request;
34
35 /** default response */
36 protected String content = "OK\r\n";
37 /** default content type */
38 protected String contentType = "text/plain";
39
40 /** will be filled with the command assigned to the subclass */
41 protected String myCommand;
42
43 /**
44 * Check permission and parameters and handle request.
45 *
46 * @throws RequestHandlerForbiddenException
47 * @throws RequestHandlerBadRequestException
48 * @throws RequestHandlerErrorException
49 */
50 public final void handle() throws RequestHandlerForbiddenException, RequestHandlerBadRequestException, RequestHandlerErrorException
51 {
52 checkPermission();
53 checkMandatoryParams();
54 handleRequest();
55 }
56
57 /**
58 * Handle a specific command sent as remote control.
59 *
60 * This method of the subclass will do the real work.
61 *
62 * @throws RequestHandlerErrorException
63 * @throws RequestHandlerBadRequestException
64 */
65 protected abstract void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException;
66
67 /**
68 * Get a specific message to ask the user for permission for the operation
69 * requested via remote control.
70 *
71 * This message will be displayed to the user if the preference
72 * remotecontrol.always-confirm is true.
73 *
74 * @return the message
75 */
76 abstract public String getPermissionMessage();
77
78 /**
79 * Get a PermissionPref object containing the name of a special permission
80 * preference to individually allow the requested operation and an error
81 * message to be displayed when a disabled operation is requested.
82 *
83 * Default is not to check any special preference. Override this in a
84 * subclass to define permission preference and error message.
85 *
86 * @return the preference name and error message or null
87 */
88 public PermissionPrefWithDefault getPermissionPref()
89 {
90 /* Example:
91 return new PermissionPrefWithDefault("fooobar.remotecontrol",
92 true
93 "RemoteControl: foobar forbidden by preferences");
94 */
95 return null;
96 }
97
98 public String[] getMandatoryParams() {
99 return null;
100 }
101
102 /**
103 * Check permissions in preferences and display error message
104 * or ask for permission.
105 *
106 * @throws RequestHandlerForbiddenException
107 */
108 final public void checkPermission() throws RequestHandlerForbiddenException
109 {
110 /*
111 * If the subclass defines a specific preference and if this is set
112 * to false, abort with an error message.
113 *
114 * Note: we use the deprecated class here for compatibility with
115 * older versions of WMSPlugin.
116 */
117 PermissionPrefWithDefault permissionPref = getPermissionPref();
118 if((permissionPref != null) && (permissionPref.pref != null))
119 {
120 if (!Main.pref.getBoolean(permissionPref.pref, permissionPref.defaultVal)) {
121 System.out.println(permissionPref.message);
122 throw new RequestHandlerForbiddenException();
123 }
124 }
125
126 /* Does the user want to confirm everything?
127 * If yes, display specific confirmation message.
128 */
129 if (Main.pref.getBoolean(globalConfirmationKey, globalConfirmationDefault)) {
130 if (JOptionPane.showConfirmDialog(Main.parent,
131 "<html>" + getPermissionMessage() +
132 "<br>" + tr("Do you want to allow this?"),
133 tr("Confirm Remote Control action"),
134 JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
135 throw new RequestHandlerForbiddenException();
136 }
137 }
138 }
139
140 /**
141 * Set request URL and parse args.
142 *
143 * @param url The request URL.
144 */
145 public void setUrl(String url) {
146 this.request = url;
147 parseArgs();
148 }
149
150 /**
151 * Parse the request parameters as key=value pairs.
152 * The result will be stored in this.args.
153 *
154 * Can be overridden by subclass.
155 */
156 protected void parseArgs() {
157 HashMap<String, String> args = new HashMap<String, String>();
158 if (this.request.indexOf('?') != -1) {
159 String query = this.request.substring(this.request.indexOf('?') + 1);
160 if (query.indexOf('#') != -1) {
161 query = query.substring(0, query.indexOf('#'));
162 }
163 String[] params = query.split("&", -1);
164 for (String param : params) {
165 int eq = param.indexOf('=');
166 if (eq != -1) {
167 args.put(param.substring(0, eq), param.substring(eq + 1));
168 }
169 }
170 }
171 this.args = args;
172 }
173
174 void checkMandatoryParams() throws RequestHandlerBadRequestException {
175 String[] mandatory = getMandatoryParams();
176 if(mandatory == null) return;
177
178 List<String> missingKeys = new LinkedList<String>();
179 boolean error = false;
180 for (int i = 0; i < mandatory.length; ++i) {
181 String key = mandatory[i];
182 String value = args.get(key);
183 if ((value == null) || (value.length() == 0)) {
184 error = true;
185 System.out.println("'" + myCommand + "' remote control request must have '" + key + "' parameter");
186 missingKeys.add(key);
187 }
188 }
189 if (error) {
190 throw new RequestHandlerBadRequestException(
191 "The following keys are mandatory, but have not been provided: "
192 + Utils.join(", ", missingKeys));
193 }
194 }
195
196 /**
197 * Save command associated with this handler.
198 *
199 * @param command The command.
200 */
201 public void setCommand(String command)
202 {
203 if (command.charAt(0) == '/') {
204 command = command.substring(1);
205 }
206 myCommand = command;
207 }
208
209 public String getContent() {
210 return content;
211 }
212
213 public String getContentType() {
214 return contentType;
215 }
216
217 protected boolean isLoadInNewLayer() {
218 return args.get("new_layer") != null && !args.get("new_layer").isEmpty()
219 ? Boolean.parseBoolean(args.get("new_layer"))
220 : Main.pref.getBoolean(loadInNewLayerKey, loadInNewLayerDefault);
221 }
222
223 public static class RequestHandlerException extends Exception {
224
225 public RequestHandlerException(String message) {
226 super(message);
227 }
228
229 public RequestHandlerException() {
230 }
231 }
232
233 public static class RequestHandlerErrorException extends RequestHandlerException {
234 }
235
236 public static class RequestHandlerBadRequestException extends RequestHandlerException {
237
238 public RequestHandlerBadRequestException(String message) {
239 super(message);
240 }
241 }
242
243 public static class RequestHandlerForbiddenException extends RequestHandlerException {
244 private static final long serialVersionUID = 2263904699747115423L;
245 }
246}
Note: See TracBrowser for help on using the repository browser.