@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String uri = getDecodedUri(request); try { Pattern p = Pattern.compile(".*/NodePersistentStorage.bin/([^/]+)/([^/]+)"); Matcher m = p.matcher(uri); boolean b = m.matches(); if (!b) { setResponseStatus(response, HttpServletResponse.SC_BAD_REQUEST); response.getWriter().write("Improperly formatted URI"); return; } String categoryName = m.group(1); String keyName = m.group(2); NodePersistentStorage nps = H2O.getNPS(); AtomicLong length = new AtomicLong(); InputStream is = nps.get(categoryName, keyName, length); if (length.get() > (long) Integer.MAX_VALUE) { throw new Exception("NPS value size exceeds Integer.MAX_VALUE"); } response.setContentType("application/octet-stream"); response.setContentLength((int) length.get()); response.addHeader("Content-Disposition", "attachment; filename=" + keyName + ".flow"); setResponseStatus(response, HttpServletResponse.SC_OK); OutputStream os = response.getOutputStream(); water.util.FileUtils.copyStream(is, os, 2048); } catch (Exception e) { sendErrorResponse(response, e, uri); } finally { logRequest("GET", request, response); } }
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String uri = getDecodedUri(request); try { Pattern p = Pattern.compile(".*NodePersistentStorage.bin/([^/]+)/([^/]+)"); Matcher m = p.matcher(uri); boolean b = m.matches(); if (!b) { setResponseStatus(response, HttpServletResponse.SC_BAD_REQUEST); response.getWriter().write("Improperly formatted URI"); return; } String categoryName = m.group(1); String keyName = m.group(2); InputStream is = extractPartInputStream(request, response); if (is == null) { return; } H2O.getNPS().put(categoryName, keyName, is); long length = H2O.getNPS().get_length(categoryName, keyName); String responsePayload = "{ " + "\"category\" : " + "\"" + categoryName + "\", " + "\"name\" : " + "\"" + keyName + "\", " + "\"total_bytes\" : " + length + " " + "}\n"; response.setContentType("application/json"); response.getWriter().write(responsePayload); } catch (Exception e) { sendErrorResponse(response, e, uri); } finally { logRequest("POST", request, response); } }
public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { H2O.getJetty().handle1(target, baseRequest, request, response); }
private static void sendErrorResponse(HttpServletResponse response, Exception e, String uri) { if (e instanceof H2OFailException) { H2OFailException ee = (H2OFailException) e; H2OError error = ee.toH2OError(uri); Log.fatal("Caught exception (fatal to the cluster): " + error.toString()); throw (H2O.fail(error.toString())); } else if (e instanceof H2OAbstractRuntimeException) { H2OAbstractRuntimeException ee = (H2OAbstractRuntimeException) e; H2OError error = ee.toH2OError(uri); Log.warn("Caught exception: " + error.toString()); setResponseStatus(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // Note: don't use Schema.schema(version, error) because we have to work at bootstrap: try { @SuppressWarnings("unchecked") String s = new H2OErrorV3().fillFromImpl(error).toJsonString(); response.getWriter().write(s); } catch (Exception ignore) { } } else { // make sure that no Exception is ever thrown out from the request H2OError error = new H2OError(e, uri); // some special cases for which we return 400 because it's likely a problem with the client // request: if (e instanceof IllegalArgumentException) error._http_status = HttpResponseStatus.BAD_REQUEST.getCode(); else if (e instanceof FileNotFoundException) error._http_status = HttpResponseStatus.BAD_REQUEST.getCode(); else if (e instanceof MalformedURLException) error._http_status = HttpResponseStatus.BAD_REQUEST.getCode(); setResponseStatus(response, error._http_status); Log.warn("Caught exception: " + error.toString()); // Note: don't use Schema.schema(version, error) because we have to work at bootstrap: try { @SuppressWarnings("unchecked") String s = new H2OErrorV3().fillFromImpl(error).toJsonString(); response.getWriter().write(s); } catch (Exception ignore) { } } }
public void doGeneric(String method, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try { startTransaction(request.getHeader("User-Agent")); // Marshal Jetty request parameters to Nano-style. // Note that getServletPath does an un-escape so that the %24 of job id's are turned into $ // characters. String uri = request.getServletPath(); Properties headers = new Properties(); Enumeration<String> en = request.getHeaderNames(); while (en.hasMoreElements()) { String key = en.nextElement(); String value = request.getHeader(key); headers.put(key, value); } Properties parms = new Properties(); Map<String, String[]> parameterMap; parameterMap = request.getParameterMap(); for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) { String key = entry.getKey(); String[] values = entry.getValue(); for (String value : values) { parms.put(key, value); } } // Make Nano call. NanoHTTPD.Response resp = water.api.RequestServer.SERVER.serve(uri, method, headers, parms); // Un-marshal Nano response back to Jetty. String choppedNanoStatus = resp.status.substring(0, 3); assert (choppedNanoStatus.length() == 3); int sc = Integer.parseInt(choppedNanoStatus); setResponseStatus(response, sc); response.setContentType(resp.mimeType); Properties header = resp.header; Enumeration<Object> en2 = header.keys(); while (en2.hasMoreElements()) { String key = (String) en2.nextElement(); String value = header.getProperty(key); response.setHeader(key, value); } OutputStream os = response.getOutputStream(); if (resp instanceof NanoHTTPD.StreamResponse) { NanoHTTPD.StreamResponse ssr = (NanoHTTPD.StreamResponse) resp; ssr.streamWriter.writeTo(os); } else { InputStream is = resp.data; FileUtils.copyStream(is, os, 1024); } } finally { logRequest(method, request, response); // Handle shutdown if it was requested. if (H2O.getShutdownRequested()) { (new Thread() { public void run() { boolean[] confirmations = new boolean[H2O.CLOUD.size()]; if (H2O.SELF.index() >= 0) { confirmations[H2O.SELF.index()] = true; } for (H2ONode n : H2O.CLOUD._memary) { if (n != H2O.SELF) new RPC(n, new ShutdownTsk(H2O.SELF, n.index(), 1000, confirmations)).call(); } try { Thread.sleep(2000); } catch (Exception ignore) { } int failedToShutdown = 0; // shutdown failed for (boolean b : confirmations) if (!b) failedToShutdown++; Log.info( "Orderly shutdown: " + (failedToShutdown > 0 ? failedToShutdown + " nodes failed to shut down! " : "") + " Shutting down now."); H2O.closeAll(); H2O.exit(failedToShutdown); } }) .start(); } endTransaction(); } }
protected void createServer(Connector connector) throws Exception { _server.setConnectors(new Connector[] {connector}); if (H2O.ARGS.hash_login || H2O.ARGS.ldap_login) { // REFER TO // http://www.eclipse.org/jetty/documentation/9.1.4.v20140401/embedded-examples.html#embedded-secured-hello-handler if (H2O.ARGS.login_conf == null) { Log.err("Must specify -login_conf argument"); H2O.exit(1); } LoginService loginService; if (H2O.ARGS.hash_login) { Log.info("Configuring HashLoginService"); loginService = new HashLoginService("H2O", H2O.ARGS.login_conf); } else if (H2O.ARGS.ldap_login) { Log.info("Configuring JAASLoginService (with LDAP)"); System.setProperty("java.security.auth.login.config", H2O.ARGS.login_conf); loginService = new JAASLoginService("ldaploginmodule"); } else { throw H2O.fail(); } IdentityService identityService = new DefaultIdentityService(); loginService.setIdentityService(identityService); _server.addBean(loginService); // Set a security handler as the first handler in the chain. ConstraintSecurityHandler security = new ConstraintSecurityHandler(); // Set up a constraint to authenticate all calls, and allow certain roles in. Constraint constraint = new Constraint(); constraint.setName("auth"); constraint.setAuthenticate(true); // Configure role stuff (to be disregarded). We are ignoring roles, and only going off the // user name. // // Jetty 8 and prior. // // Jetty 8 requires the security.setStrict(false) and ANY_ROLE. security.setStrict(false); constraint.setRoles(new String[] {Constraint.ANY_ROLE}); // Jetty 9 and later. // // Jetty 9 and later uses a different servlet spec, and ANY_AUTH gives the same behavior // for that API version as ANY_ROLE did previously. This required some low-level // debugging // to figure out, so I'm documenting it here. // Jetty 9 did not require security.setStrict(false). // // constraint.setRoles(new String[]{Constraint.ANY_AUTH}); ConstraintMapping mapping = new ConstraintMapping(); mapping.setPathSpec("/*"); // Lock down all API calls mapping.setConstraint(constraint); security.setConstraintMappings(Collections.singletonList(mapping)); // Authentication / Authorization security.setAuthenticator(new BasicAuthenticator()); security.setLoginService(loginService); // Pass-through to H2O if authenticated. registerHandlers(security); _server.setHandler(security); } else { registerHandlers(_server); } _server.start(); }