1 19 20 package org.netbeans.modules.httpserver; 21 22 import java.awt.Dialog ; 23 import java.beans.IntrospectionException ; 24 import java.util.Hashtable ; 25 import java.util.HashSet ; 26 import java.util.Set ; 27 import java.util.StringTokenizer ; 28 import java.util.Properties ; 29 import java.net.InetAddress ; 30 import java.net.UnknownHostException ; 31 import java.util.logging.Level ; 32 import java.util.logging.Logger ; 33 import java.util.prefs.Preferences ; 34 import javax.swing.event.EventListenerList ; 35 import org.openide.DialogDescriptor; 36 37 import org.openide.util.NbBundle; 38 import org.openide.util.HelpCtx; 39 import org.openide.util.Utilities; 40 import org.openide.NotifyDescriptor; 41 import org.openide.DialogDisplayer; 42 import org.openide.nodes.BeanNode; 43 import org.openide.util.NbPreferences; 44 45 49 public class HttpServerSettings { 50 private static HttpServerSettings INSTANCE = new HttpServerSettings(); 51 private static BeanNode view = null; 52 53 private static final int MAX_START_RETRIES = 20; 54 private static int currentRetries = 0; 55 56 protected static EventListenerList listenerList = new EventListenerList (); 57 58 61 static boolean inited = false; 62 63 64 private static Hashtable <InetAddress ,Thread > whoAsking = new Hashtable <InetAddress ,Thread >(); 65 66 public static final int SERVER_STARTUP_TIMEOUT = 3000; 67 68 69 public static final String LOCALHOST = "local"; 71 public static final String ANYHOST = "any"; 73 public static HostProperty hostProperty = null; 74 75 public static final String PROP_PORT = "port"; public static final String PROP_HOST_PROPERTY = "hostProperty"; static final String PROP_WRAPPER_BASEURL = "wrapperBaseURL"; public static final String PROP_RUNNING = "running"; 80 private static final String PROP_SHOW_GRANT_ACCESS = "showGrantAccess"; 82 83 private static final int DEFAULT_PORT = 8082; 84 85 86 private static String wrapperBaseURL = "/resource/"; 88 89 static boolean running = false; 90 91 private static boolean startStopMessages = true; 92 93 private static Properties mappedServlets = new Properties (); 94 95 98 public static HttpServerSettings OPTIONS = null; 99 100 101 private static Object httpLock; 102 103 private static Preferences getPreferences() { 104 return NbPreferences.forModule(HttpServerSettings.class); 105 } 106 107 110 static final Object httpLock () { 111 if (httpLock == null) { 112 httpLock = new Object (); 113 } 114 return httpLock; 115 } 116 117 private HttpServerSettings() { 118 } 119 120 public static HttpServerSettings getDefault() { 121 return INSTANCE; 122 } 123 124 125 public String displayName() { 126 return NbBundle.getMessage(HttpServerSettings.class, "CTL_HTTP_settings"); 127 } 128 129 130 public boolean isRunning() { 131 if (inited) { 132 return running; 133 } 134 else { 135 setRunning(false); 138 return running; 139 } 140 } 141 142 143 void runSuccess() { 144 synchronized (httpLock ()) { 145 currentRetries = 0; 146 running = true; 147 httpLock ().notifyAll(); 148 } 149 } 150 151 155 void runFailure(Throwable t) { 156 running = false; 157 if (t instanceof IncompatibleClassChangeError ) { 158 DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message( 160 NbBundle.getMessage (HttpServerSettings.class, "MSG_HTTP_SERVER_incompatbleClasses"), 161 NotifyDescriptor.Message.WARNING_MESSAGE)); 162 } 163 else if (t instanceof java.net.BindException ) { 164 currentRetries ++; 166 if (currentRetries <= MAX_START_RETRIES) { 167 setPort(getPort() + 1); 168 setRunning(true); 169 } 170 else { 171 currentRetries = 0; 172 DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message( 173 NbBundle.getMessage (HttpServerSettings.class, "MSG_HTTP_SERVER_START_FAIL"), 174 NotifyDescriptor.Message.WARNING_MESSAGE)); 175 int p = getPort (); 176 if (p < 1024 && inited && Utilities.isUnix()) { 177 DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message( 178 NbBundle.getMessage (HttpServerSettings.class, "MSG_onlyRootOnUnix"), 179 NotifyDescriptor.WARNING_MESSAGE)); 180 } 181 182 } 183 } 184 else { 185 DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message( 187 NbBundle.getMessage (HttpServerSettings.class, "MSG_HTTP_SERVER_START_FAIL_unknown"), 188 NotifyDescriptor.Message.WARNING_MESSAGE)); 189 } 190 } 191 192 195 private void restartIfNecessary(boolean printMessages) { 196 if (running) { 197 if (!printMessages) 198 setStartStopMessages(false); 199 HttpServerModule.stopHTTPServer(); 200 HttpServerModule.initHTTPServer(); 201 } 203 } 204 205 206 private String getCanonicalRelativeURL(String url) { 207 String newURL; 208 if (url.length() == 0) 209 newURL = "/"; else { 211 if (url.charAt(0) != '/') 212 newURL = "/" + url; else 214 newURL = url; 215 if (newURL.charAt(newURL.length() - 1) != '/') 216 newURL = newURL + "/"; } 218 return newURL; 219 } 220 221 222 public void setRunning(boolean running) { 223 inited = true; 224 if (this.running == running) 225 return; 226 227 synchronized (httpLock ()) { 228 if (running) { 229 HttpServerModule.initHTTPServer(); 231 } 232 else { 233 this.running = false; 234 HttpServerModule.stopHTTPServer(); 235 } 236 } 237 } 238 239 241 242 String getWrapperBaseURL() { 243 return wrapperBaseURL; 244 } 245 246 247 void setWrapperBaseURL(String wrapperBaseURL) { 248 String oldURL; 250 String newURL = getCanonicalRelativeURL(wrapperBaseURL); 251 252 if (this.wrapperBaseURL.equals(newURL)) 254 return; 255 256 synchronized (httpLock ()) { 258 oldURL = this.wrapperBaseURL; 259 this.wrapperBaseURL = newURL; 260 restartIfNecessary(false); 261 } 262 } 263 264 265 public void setPort(int p) { 266 if (p <= 0 || p >65535) { 267 NotifyDescriptor.Message msg = new NotifyDescriptor.Message( 268 NbBundle.getMessage(HttpServerSettings.class, "ERR_PortNumberOutOfRange", new Integer (p)), NotifyDescriptor.ERROR_MESSAGE); 269 270 DialogDisplayer.getDefault().notify(msg); 271 return; 272 } 273 274 synchronized (httpLock ()) { 275 getPreferences().putInt(PROP_PORT,p); 276 restartIfNecessary(true); 277 } 278 } 279 280 281 public int getPort() { 282 return getPreferences().getInt(PROP_PORT, DEFAULT_PORT); 283 } 284 285 public void setStartStopMessages(boolean ssm) { 286 startStopMessages = ssm; 287 } 288 289 public boolean isStartStopMessages() { 290 return startStopMessages; 291 } 292 293 public HelpCtx getHelpCtx () { 294 return new HelpCtx (HttpServerSettings.class); 295 } 296 297 298 private String getLocalHost() { 299 try { 300 return InetAddress.getLocalHost().getHostName(); 301 } 302 catch (UnknownHostException e) { 303 return "localhost"; } 305 } 306 307 public void addGrantAccessListener(GrantAccessListener l) { 308 listenerList.add(GrantAccessListener.class, l); 309 } 310 311 public void removeGrantAccessListener(GrantAccessListener l) { 312 listenerList.remove(GrantAccessListener.class, l); 313 } 314 315 316 protected boolean fireGrantAccessEvent(InetAddress clientAddress, String resource) { 317 Object [] listeners = listenerList.getListenerList(); 318 GrantAccessEvent grantAccessEvent = null; 319 for (int i = listeners.length-2; i>=0; i-=2) { 320 if (listeners[i]==GrantAccessListener.class) { 321 if (grantAccessEvent == null) 322 grantAccessEvent = new GrantAccessEvent(this, clientAddress, resource); 323 ((GrantAccessListener)listeners[i+1]).grantAccess(grantAccessEvent); 324 } 325 } 326 return (grantAccessEvent == null) ? false : grantAccessEvent.isGranted(); 327 } 328 329 331 boolean allowAccess(InetAddress addr, String requestPath) { 332 if (accessAllowedNow(addr, requestPath)) 333 return true; 334 335 Thread askThread = null; 336 synchronized (whoAsking) { 337 if (accessAllowedNow(addr, requestPath)) 339 return true; 340 341 askThread = (Thread )whoAsking.get(addr); 342 if (askThread == null) { 343 askThread = Thread.currentThread(); 344 whoAsking.put(addr, askThread); 345 } 346 } 347 348 synchronized (HttpServerSettings.class) { 350 if (askThread != Thread.currentThread()) { 351 return accessAllowedNow(addr, requestPath); 352 } 353 354 try { 355 if (!isShowGrantAccessDialog ()) 356 return false; 357 358 String msg = NbBundle.getMessage (HttpServerSettings.class, "MSG_AddAddress", addr.getHostAddress ()); 359 360 final GrantAccessPanel panel = new GrantAccessPanel (msg); 361 DialogDescriptor descriptor = new DialogDescriptor ( 362 panel, 363 NbBundle.getMessage (HttpServerSettings.class, "CTL_GrantAccessTitle"), 364 true, 365 NotifyDescriptor.YES_NO_OPTION, 366 NotifyDescriptor.NO_OPTION, 367 null 368 ); 369 descriptor.setMessageType (NotifyDescriptor.QUESTION_MESSAGE); 370 final Dialog d = DialogDisplayer.getDefault ().createDialog (descriptor); 372 d.setSize (580, 180); 373 d.setVisible(true); 374 375 setShowGrantAccessDialog (panel.getShowDialog ()); 376 if (NotifyDescriptor.YES_OPTION.equals(descriptor.getValue ())) { 377 appendAddressToGranted(addr.getHostAddress()); 378 return true; 379 } 380 else 381 return false; 382 } 383 finally { 384 whoAsking.remove(addr); 385 } 386 } } 388 389 390 private boolean accessAllowedNow(InetAddress addr, String resource) { 391 if (hostProperty.getHost().equals(HttpServerSettings.ANYHOST)) 392 return true; 393 394 Set hs = getGrantedAddressesSet(); 395 if (hs.contains(addr.getHostAddress())) 396 return true; 397 398 if (fireGrantAccessEvent(addr, resource)) 399 return true; 400 401 return false; 402 } 403 404 405 private void appendAddressToGranted(String addr) { 406 synchronized (httpLock ()) { 407 String granted = hostProperty.getGrantedAddresses().trim(); 408 if ((granted.length() > 0) && 409 (granted.charAt(granted.length() - 1) != ';') && 410 (granted.charAt(granted.length() - 1) != ',')) 411 granted += ','; 412 granted += addr; 413 hostProperty.setGrantedAddresses(granted); 414 } 415 } 416 417 419 Set <String > getGrantedAddressesSet() { 420 HashSet <String > addr = new HashSet <String >(); 421 try { 422 addr.add(InetAddress.getByName("localhost").getHostAddress()); addr.add(InetAddress.getLocalHost().getHostAddress()); 424 } 425 catch (UnknownHostException e) {} 426 StringTokenizer st = new StringTokenizer (hostProperty.getGrantedAddresses(), ",;"); while (st.hasMoreTokens()) { 428 String ipa = st.nextToken(); 429 ipa = ipa.trim(); 430 try { 431 addr.add(InetAddress.getByName(ipa).getHostAddress()); 432 } 433 catch (UnknownHostException e) {} 434 } 435 return addr; 436 } 437 438 Properties getMappedServlets() { 439 return mappedServlets; 440 } 441 442 445 static String mangle (String name) { 446 StringBuffer sb = new StringBuffer (); 447 for (int i = 0; i < name.length (); i++) { 448 if (Character.isLetterOrDigit (name.charAt (i)) || 449 name.charAt (i) == '.') { 450 sb.append (name.charAt (i)); 451 } 452 else { 453 String code = Integer.toHexString ((int)name.charAt (i)).toUpperCase (); 454 if (code.length ()<2) 455 code = (code.length () == 0)? "00": "0"+code; sb.append ("%"). append ((code.length () == 2)? code: code.substring (code.length ()-2)); 458 } 459 } 460 return sb.toString (); 461 } 462 463 466 static String demangle (String name) { 467 StringBuffer sb = new StringBuffer (); 468 try { 469 for (int i = 0; i < name.length (); i++) { 470 if (name.charAt (i) != '%') { 471 sb.append (name.charAt (i)); 472 } 473 else { 474 sb.append ((char)Integer.parseInt (name.substring (i+1, i+3), 16)); 475 i += 2; 476 } 477 } 478 } 479 catch (NumberFormatException ex) { 480 ex.printStackTrace (); 481 return ""; } 483 return sb.toString (); 484 } 485 486 489 public HttpServerSettings.HostProperty getHostProperty () { 490 if (hostProperty == null) { 491 hostProperty = new HostProperty(getPreferences().get("grantedAddresses",""), 492 getPreferences().get("host",LOCALHOST)); 493 } 494 return hostProperty; 495 } 496 497 500 public void setHostProperty (HttpServerSettings.HostProperty hostProperty) { 501 if (ANYHOST.equals(hostProperty.getHost ()) || LOCALHOST.equals(hostProperty.getHost ())) { 502 this.hostProperty.setHost(hostProperty.getHost()); 503 this.hostProperty.setGrantedAddresses(hostProperty.getGrantedAddresses()); 504 getPreferences().put("host", hostProperty.getHost()); getPreferences().put("grantedAddresses", hostProperty.getGrantedAddresses()); } 507 } 508 509 public boolean isShowGrantAccessDialog () { 510 return getPreferences().getBoolean(PROP_SHOW_GRANT_ACCESS, true); 511 } 512 513 public void setShowGrantAccessDialog (boolean show) { 514 getPreferences().putBoolean(PROP_SHOW_GRANT_ACCESS,show); 515 } 516 517 519 public static class HostProperty implements java.io.Serializable { 520 521 private String grantedAddresses; 522 523 private String host; 524 525 private static final long serialVersionUID = 1927848926692414249L; 526 527 HostProperty (String grantedAddresses, String host) { 528 this.grantedAddresses = grantedAddresses; 529 this.host = host; 530 } 531 532 535 public String getHost () { 536 return host; 537 } 538 539 542 public void setHost (String host) { 543 this.host = host; 544 } 545 546 549 public String getGrantedAddresses () { 550 return grantedAddresses; 551 } 552 553 556 public void setGrantedAddresses (String grantedAddresses) { 557 this.grantedAddresses = grantedAddresses; 558 } 559 560 } 561 static synchronized BeanNode createViewNode() { 562 if (view == null) { 563 try { 564 view = new BeanNode<HttpServerSettings>(HttpServerSettings.getDefault()); 565 } 566 catch (IntrospectionException ex) { 567 Logger.getLogger(HttpServerSettings.class.getName()).log(Level.INFO, null, ex); 568 } 569 } 570 return view; 571 } 572 } 573 | Popular Tags |