private void setupTraceLog(HttpContext httpContext, String queue, AccessLog accessLog) throws IOException { String clientIp = httpContext.getClientIp(); // DBへのアクセスログ採取有無 if (!isLogging(clientIp, "accessDb." + queue)) { return; } // DBに記録する accessLog.insert(); // リクエストStreamのpeek処理 if (isLogging(clientIp, "accessTrace.request." + queue)) { PeekStream requestPeeker = accessLog.setupPeekRequest(); httpContext.peekRequest(requestPeeker); context.enque(requestPeeker, Config.QUEUE_PEEK); // 既に受け取っているヘッダ部分をPeekStreamに流し込む HttpParser requestParser = httpContext.getRequestParser(); OutputStream os = requestPeeker.getPeekOutputStream(); requestParser.writeSeriarizeHeader(os); } // レスポンスStreamのpeek処理 if (isLogging(clientIp, "accessTrace.response." + queue)) { PeekStream responsePeeker = accessLog.setupPeekResponse(); httpContext.peekResponse(responsePeeker); context.enque(responsePeeker, Config.QUEUE_PEEK); } }
public void doReadLoop() { HttpContext context = new BasicHttpContext(); context.setAttribute(CX_SOCKET, rawSocket); while (!Thread.interrupted() && this.htConn.isOpen() && HttpServer.this.shouldRun) { // Clear the context from any auth settings; since this is done // anew on each connection.. context.removeAttribute(CX_AUTH); try { HttpServer.this.httpService.handleRequest(htConn, context); } catch (ConnectionClosedException ex_closed) { break; } catch (IOException ex) { if (!closeRequested) { ex.printStackTrace(); } break; } catch (HttpException ex) { ex.printStackTrace(); break; } catch (ResponseHandledException ex) { break; } } bail(); }
// URIと設定から呼び出し先QUEUEを決める。 private MappingEntry mappingQueue(HttpContext httpContext) { String uri = httpContext.getRequestUri(); if (MappingEntry.controllerEntry.matches(uri)) { // controllerへのリクエストか? httpContext.setAttribute(HttpContext.ATTRIBUTE_MAPPING_ENTRY, MappingEntry.controllerEntry); return MappingEntry.controllerEntry; } String clientIp = httpContext.getClientIp(); // リクエストがReplay対象か? if (config.isReplay(clientIp, uri)) { return MappingEntry.replayEntry; } if (httpContext.isProxyRequest()) { // TODO 強制的にWebサーバとして動作するモード要, // requestLineがhttp://から始まってもクライアントが間違って送ってきたと判断する return MappingEntry.proxyEntry; } MappingEntry mappingEntry = config.mapping(uri); if (mappingEntry == null) { return null; } // マッピング先がReplay対象か? if (config.isReplay(clientIp, mappingEntry.getDestination())) { return MappingEntry.replayEntry; } httpContext.setAttribute(HttpContext.ATTRIBUTE_MAPPING_ENTRY, mappingEntry); return mappingEntry; }
private MappingEntry responseWebAuthenticationForm(HttpContext httpContext, String orgPath) { // 認証画面をVelocityPageから出力する if (orgPath == null) { orgPath = httpContext.getRequestUri(); } httpContext.setAttribute("orgPath", orgPath); httpContext.setAttribute(HttpContext.ATTRIBUTE_VELOCITY_PAGE, webAuthenticateForm); return MappingEntry.velopageEntry; }
// WWW-Authenticate: Basic realm="FIND2",Basicはreverseの事を考えると使えない // Authorization: Basic XXXbase64XXX // "Proxy-Authenticate", "Basic Realm=\"myProxy\"",proxyの場合こちらを使う // Proxy-Authorization: Basic XXXbase64XXX // Response Queueに依頼する前にレスポンスを返却したい場合 private void responseDirect(HttpContext httpContext, String statusCode, String text) { httpContext.registerResponse(statusCode, text); httpContext.startResponse(); try { httpContext.responseDirect(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } context.enque(httpContext, Config.QUEUE_CLOSE); }
private void addCtx(String path, HttpHandler h) { HttpContext ctx = server.createContext(path, h); if (configuration.isWebAuthenticate()) { ctx.setAuthenticator( new BasicAuthenticator("") { @Override public boolean checkCredentials(String user, String pwd) { LOGGER.debug("authenticate " + user); return pwd.equals(users.get(user)); // return true; } }); } }
protected void write(HttpServletResponse response, HttpContext httpContext) throws IOException { response.setStatus(httpContext.getStatus().getCode()); for (String name : httpContext.getResponseHeaders()) { response.setHeader(name, httpContext.getResponseHeaders().getString(name)); } String content = httpContext.getResponseContent(); if (content != null && !content.isEmpty()) { response.getWriter().write(httpContext.getResponseContent()); response.getWriter().flush(); response.getWriter().close(); } }
/** * Initialize this JolokiaServer with the given HttpServer. The calle is responsible for managing * (starting/stopping) the HttpServer. * * @param pServer server to use * @param pConfig configuration * @param pLazy whether the initialization should be done lazy or not */ protected final void init(HttpServer pServer, JolokiaServerConfig pConfig, boolean pLazy) { config = pConfig; lazy = pLazy; // Create proper context along with handler final String contextPath = pConfig.getContextPath(); jolokiaHttpHandler = new JolokiaHttpHandler(pConfig.getJolokiaConfig()); HttpContext context = pServer.createContext(contextPath, jolokiaHttpHandler); // Add authentication if configured final Authenticator authenticator = pConfig.getAuthenticator(); if (authenticator != null) { context.setAuthenticator(authenticator); } url = detectAgentUrl(pServer, pConfig, contextPath); }
private MappingEntry proxyAuthentication(HttpContext httpContext, MappingEntry entry) { String paHeader = httpContext.getRequestHeader(HttpContext.PROXY_AUTHORIZATION_HEADER); httpContext.removeRequestHeader(HttpContext.PROXY_AUTHORIZATION_HEADER); if (proxyAuthenticate == null) { // 認証なしモード return entry; } if (paHeader != null) { String[] paParts = paHeader.split(" "); if (paParts.length >= 2 && "Basic".equalsIgnoreCase(paParts[0]) && proxyAuthenticate.equalsIgnoreCase(paParts[1])) { return entry; // 認証成功 } } // 認証失敗 httpContext.addResponseHeader("Proxy-Authenticate", "Basic Realm=\"myProxy\""); httpContext.registerResponse("407", "myProxy Proxy-Authenticate"); httpContext.startResponse(); return null; // 自分でコンテンツを作ったのでentryなし }
private static HttpServer createHttpServer(ExecutorService execs) throws Exception { InetSocketAddress inetAddress = new InetSocketAddress(0); HttpServer testServer = HttpServer.create(inetAddress, 5); testServer.setExecutor(execs); HttpContext context = testServer.createContext("/test"); context.setHandler( new HttpHandler() { public void handle(HttpExchange msg) { try { synchronized (lock) { ++s_received; if ((s_received % 1000) == 0) { System.out.println("Received=" + s_received); } } String method = msg.getRequestMethod(); if (method.equals("POST")) { InputStream is = msg.getRequestBody(); byte[] buf = readFully(is); is.close(); writePostReply(msg, buf); } else { System.out.println("****** METHOD not handled ***** " + method); System.out.println("Received=" + s_received); } synchronized (lock) { ++sent; if ((sent % 1000) == 0) { System.out.println("sent=" + sent); } } } catch (Exception e) { e.printStackTrace(); } finally { msg.close(); } } }); return testServer; }
// Cookie: FujitsuWebsite_common_01=k7.fujitsu.co.jp.63941208497096656; NIN=1; RIYOU=4; // OUSU=UgxIaMwUtKwIN3hwh8OiYYcrBNVyVpK3HlrKr15VacKsBFa_bDTDO3x40ronDNDJrMuu1v/uYVZ4n5eAg1in7tJJQhicQHsdDZzU3FB0gWDMyVd0cyW7pQ==; POTO=0 // Set-Cookie: // JSESSIONID=54KAU74VEVVUM8AVE7NJKNIIJ08114SFEH6VTFT3IH12CJU17R7RMRDEIKDG20001G000000.Naru001_001 private String getCookieAuthAndFilter(HttpContext httpContext) { String cookieHeader = httpContext.getRequestHeader(HttpContext.COOKIE_HEADER); if (cookieHeader == null) { return null; } Matcher matcher; synchronized (webAuthenticatePattern) { matcher = webAuthenticatePattern.matcher(cookieHeader); } if (matcher.find() == false) { return null; } String cookieAuth = matcher.group(1); // webAuthenticateCookieKeyがあったなら、抜いたものを設定する。 httpContext.removeRequestHeader(HttpContext.COOKIE_HEADER); String updateCookie = matcher.replaceAll(""); if (!"".equals(updateCookie)) { // webAuthenticateCookieKeyを抜いた結果何か残れば httpContext.setRequestHeader(HttpContext.COOKIE_HEADER, updateCookie); } // "や'で括られている場合は、削除する return stripQuote(cookieAuth); }
private MappingEntry webAuthentication(HttpContext httpContext, MappingEntry entry) { if (webAuthenticate == null) { return entry; // 認証なしモード } String cookieAuth = getCookieAuthAndFilter(httpContext); String uri = httpContext.getRequestUri(); String orgPath = null; if (uri.indexOf(webAuthenticateForm) >= 0) { // 認証画面からのリクエスト String user; String pass; try { user = httpContext.getParameter("user"); pass = httpContext.getParameter("pass"); orgPath = httpContext.getParameter("orgPath"); } catch (IOException e) { // 認証失敗と判断 logger.warn("webAuthenticate fail to getParameter.", e); return responseWebAuthenticationForm(httpContext, orgPath); } String inputAuth = encodeBase64(user + ":" + pass); if (webAuthenticate.equals(inputAuth)) { // 認証成功 httpContext.addResponseHeader( "Set-Cookie", webAuthenticateCookieKey + "=" + webAuthenticate + "; path=/"); String location = "http://" + httpContext.getRequestServer() + orgPath; httpContext.addResponseHeader(HttpContext.LOCATION_HEADER, location); httpContext.registerResponse("302", "success webAuthenticate"); httpContext.startResponse(); return null; // 自分でコンテンツを作ったのでentryなし } } if (cookieAuth != null && webAuthenticate.equals(cookieAuth)) { return entry; // 認可成功 } // 認可、認証失敗、認証Formをレスポンスする。webAuthenticateFormからのリクエストでない限りorgPathは,null return responseWebAuthenticationForm(httpContext, orgPath); }
/* (non-Javadoc) * @see naru.queuelet.Queuelet#service(java.lang.Object) */ public boolean service(Object req) { HttpContext httpContext = null; if (req instanceof Socket) { Socket socket = (Socket) req; // 指定IPからのリクエストかどうかをチェック if (checkIp(socket) == false) { return false; } httpContext = (HttpContext) context.deque(Config.QUEUE_HTTPCONTEXT_POOL); httpContext.setSocket(socket); } else { // KeepAliveを実装する時はこちら httpContext = (HttpContext) req; } // 処理の起点がaccessLogの中に採られる AccessLog accessLog = (AccessLog) context.deque(Config.QUEUE_ACCESSLOG_POOL); httpContext.setupAccessLog(accessLog); boolean parseHeader = false; try { parseHeader = httpContext.parseRequestHeader(); } catch (IOException e) { // 不当リクエスト logger.error("fail to parse Request.", e); } catch (Throwable t) { // java.nio.channels.ClosedSelectorExceptionが発生したりする logger.error("fail to parse Request.!!", t); } if (!parseHeader) { context.enque(httpContext, Config.QUEUE_CLOSE); return false; } MappingEntry entry = mappingQueue(httpContext); if (entry == null) { logger.warn("fail to mapping.URL:" + httpContext.getRequestUri()); responseDirect(httpContext, "404", "failt to mapping." + httpContext.getRequestUri()); return false; } String queue = entry.getQueue(); // 一連streamの初期化 try { setupTraceLog(httpContext, queue, accessLog); } catch (IOException e) { // streamの初期化に失敗、レスポンスもできない logger.error("fail to setupAccessTrace", e); responseDirect(httpContext, "404", "failt to accesslog." + httpContext.getRequestUri()); return false; } // 以降普通にレスポンスできる // response予約 context.enque(httpContext, Config.QUEUE_RESPONSE); entry = authentication(httpContext, entry); if (entry == null) { return false; } accessLog.setMappingSource(entry.getSourcePath()); accessLog.setMappingDestination(entry.getDestination()); // response作成依頼(認証時にqueueが変更されている可能性がある) context.enque(httpContext, entry.getQueue()); return true; }
public Object removeAttribute(String s) { return context.removeAttribute(s); }
public void setAttribute(String s, Object obj) { context.setAttribute(s, obj); }
/** * Handles receives one HTTP request over the given connection within the given execution context * and sends a response back to the client. * * @param conn the active connection to the client * @param context the actual execution context. * @throws IOException in case of an I/O error. * @throws HttpException in case of HTTP protocol violation or a processing problem. */ public void handleRequest(final HttpServerConnection conn, final HttpContext context) throws IOException, HttpException { context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); HttpResponse response = null; try { HttpRequest request = conn.receiveRequestHeader(); request.setParams(new DefaultedHttpParams(request.getParams(), this.params)); ProtocolVersion ver = request.getRequestLine().getProtocolVersion(); if (!ver.lessEquals(HttpVersion.HTTP_1_1)) { // Downgrade protocol version if greater than HTTP/1.1 ver = HttpVersion.HTTP_1_1; } if (request instanceof HttpEntityEnclosingRequest) { if (((HttpEntityEnclosingRequest) request).expectContinue()) { response = this.responseFactory.newHttpResponse(ver, HttpStatus.SC_CONTINUE, context); response.setParams(new DefaultedHttpParams(response.getParams(), this.params)); if (this.expectationVerifier != null) { try { this.expectationVerifier.verify(request, response, context); } catch (HttpException ex) { response = this.responseFactory.newHttpResponse( HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR, context); response.setParams(new DefaultedHttpParams(response.getParams(), this.params)); handleException(ex, response); } } if (response.getStatusLine().getStatusCode() < 200) { // Send 1xx response indicating the server expections // have been met conn.sendResponseHeader(response); conn.flush(); response = null; conn.receiveRequestEntity((HttpEntityEnclosingRequest) request); } } else { conn.receiveRequestEntity((HttpEntityEnclosingRequest) request); } } if (response == null) { response = this.responseFactory.newHttpResponse(ver, HttpStatus.SC_OK, context); response.setParams(new DefaultedHttpParams(response.getParams(), this.params)); context.setAttribute(ExecutionContext.HTTP_REQUEST, request); context.setAttribute(ExecutionContext.HTTP_RESPONSE, response); this.processor.process(request, context); doService(request, response, context); } // Make sure the request content is fully consumed if (request instanceof HttpEntityEnclosingRequest) { HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); if (entity != null) { entity.consumeContent(); } } } catch (HttpException ex) { response = this.responseFactory.newHttpResponse( HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR, context); response.setParams(new DefaultedHttpParams(response.getParams(), this.params)); handleException(ex, response); } this.processor.process(response, context); conn.sendResponseHeader(response); conn.sendResponseEntity(response); conn.flush(); if (!this.connStrategy.keepAlive(response, context)) { conn.close(); } }
/** * Handle next request off the connection. The service(request,response) method is called by * handle to service each request received on the connection. If the thread is a PoolThread, the * thread is set as inactive when waiting for a request. * * <p>If a HttpTunnel has been set on this connection, it's handle method is called and when that * completes, false is return from this method. * * <p>The Connection is set as a ThreadLocal of the calling thread and is available via the * getHttpConnection() method. * * @return true if the connection is still open and may provide more requests. */ public boolean handleNext() { // Handle a HTTP tunnel if (_tunnel != null) { if (log.isDebugEnabled()) log.debug("Tunnel: " + _tunnel); _outputStream.resetObservers(); _tunnel.handle(_inputStream.getInputStream(), _outputStream.getOutputStream()); return false; } // Normal handling. HttpContext context = null; boolean stats = false; try { // Assume the connection is not persistent, // unless told otherwise. _persistent = false; _close = false; _keepAlive = false; _firstWrite = false; _completing = false; _dotVersion = 0; // Read requests readRequest(); if (_listener == null || !_listener.isStarted()) { // dead connection _response.destroy(); _response = null; _persistent = false; return false; } _listener.customizeRequest(this, _request); if (_request.getState() != HttpMessage.__MSG_RECEIVED) throw new HttpException(HttpResponse.__400_Bad_Request); // We have a valid request! statsRequestStart(); stats = true; // Pick response version, we assume that _request.getVersion() == 1 _dotVersion = _request.getDotVersion(); if (_dotVersion > 1) { _dotVersion = 1; } // Common fields on the response _response.setVersion(HttpMessage.__HTTP_1_1); _response.setField(HttpFields.__Date, _request.getTimeStampStr()); if (!Version.isParanoid()) _response.setField(HttpFields.__Server, Version.getDetail()); // Handle Connection header field Enumeration connectionValues = _request.getFieldValues(HttpFields.__Connection, HttpFields.__separators); if (connectionValues != null) { while (connectionValues.hasMoreElements()) { String token = connectionValues.nextElement().toString(); // handle close token if (token.equalsIgnoreCase(HttpFields.__Close)) { _close = true; _response.setField(HttpFields.__Connection, HttpFields.__Close); } else if (token.equalsIgnoreCase(HttpFields.__KeepAlive) && _dotVersion == 0) _keepAlive = true; // Remove headers for HTTP/1.0 requests if (_dotVersion == 0) _request.forceRemoveField(token); } } // Handle version specifics if (_dotVersion == 1) verifyHTTP_1_1(); else if (_dotVersion == 0) verifyHTTP_1_0(); else if (_dotVersion != -1) throw new HttpException(HttpResponse.__505_HTTP_Version_Not_Supported); if (log.isDebugEnabled()) log.debug("REQUEST from " + _listener + ":\n" + _request); // handle HttpListener handlers if (!_request.isHandled() && _listener.getHttpHandler() != null) _listener.getHttpHandler().handle("", null, _request, _response); // service the request if (!_request.isHandled()) context = service(_request, _response); } catch (HttpException e) { exception(e); } catch (IOException e) { if (_request.getState() != HttpMessage.__MSG_RECEIVED) { if (log.isDebugEnabled()) { if (log.isTraceEnabled()) log.trace(LogSupport.EXCEPTION, e); else if (log.isDebugEnabled()) log.debug(e.toString()); } _response.destroy(); _response = null; } else exception(e); } catch (Exception e) { exception(e); } catch (Error e) { exception(e); } finally { int bytes_written = 0; int content_length = _response == null ? -1 : _response.getIntField(HttpFields.__ContentLength); // Complete the request if (_persistent) { boolean no_continue_sent = false; try { if (_inputStream.getExpectContinues() != null) { _inputStream.setExpectContinues(null); no_continue_sent = true; } else { int remaining = _inputStream.getContentLength(); if (remaining != 0) // Read remaining input while (_inputStream.skip(4096) > 0 || _inputStream.read() >= 0) ; } } catch (IOException e) { if (_inputStream.getContentLength() > 0) _inputStream.setContentLength(0); _persistent = false; LogSupport.ignore(log, e); exception(new HttpException(HttpResponse.__400_Bad_Request, "Missing Content")); } // Check for no more content if (!no_continue_sent && _inputStream.getContentLength() > 0) { _inputStream.setContentLength(0); _persistent = false; exception(new HttpException(HttpResponse.__400_Bad_Request, "Missing Content")); } // Commit the response try { _outputStream.close(); bytes_written = _outputStream.getBytesWritten(); _outputStream.resetStream(); _outputStream.addObserver(this); _inputStream.resetStream(); } catch (IOException e) { exception(e); } } else if (_response != null) // There was a request { // half hearted attempt to eat any remaining input try { if (_inputStream.getContentLength() > 0) while (_inputStream.skip(4096) > 0 || _inputStream.read() >= 0) ; _inputStream.resetStream(); } catch (IOException e) { LogSupport.ignore(log, e); } // commit non persistent try { _outputStream.flush(); _response.commit(); bytes_written = _outputStream.getBytesWritten(); _outputStream.close(); _outputStream.resetStream(); } catch (IOException e) { exception(e); } } // Check response length if (_response != null) { if (log.isDebugEnabled()) log.debug("RESPONSE:\n" + _response); if (_persistent && content_length >= 0 && bytes_written > 0 && content_length != bytes_written) { log.warn( "Invalid length: Content-Length=" + content_length + " written=" + bytes_written + " for " + _request.getRequestURL()); _persistent = false; try { _outputStream.close(); } catch (IOException e) { log.warn(LogSupport.EXCEPTION, e); } } } // stats & logging if (stats) statsRequestEnd(); if (context != null) context.log(_request, _response, bytes_written); } return (_tunnel != null) || _persistent; }
public Cookie resolveLocale(HttpContext context, UserContext usr, OperationContextBuilder ctxb) { if (this.locales.size() == 0) { // make sure we have at least 1 locale listed for the site String lvalue = this.getDefaultLocale(); // add the list of locales supported for this site this.locales.put(lvalue, this.getLocaleDefinition(lvalue)); } LocaleDefinition locale = null; // see if the path indicates a language CommonPath path = context.getRequest().getPath(); if (path.getNameCount() > 0) { String lvalue = path.getName(0); locale = this.locales.get(lvalue); // extract the language from the path if (locale != null) context.getRequest().setPath(path.subpath(1)); } // but respect the cookie if it matches something though Cookie langcookie = context.getRequest().getCookie("dcLang"); if (locale == null) { if (langcookie != null) { String lvalue = langcookie.value(); // if everything checks out set the op locale and done if (this.locales.containsKey(lvalue)) { ctxb.withOperatingLocale(lvalue); return null; } locale = this.getLocaleDefinition(lvalue); // use language if variant - still ok and done if (locale.hasVariant()) { if (this.locales.containsKey(locale.getLanguage())) { ctxb.withOperatingLocale( lvalue); // keep the variant part, it may be used in places on site - supporting a // lang implicitly allows all variants return null; } } // otherwise ignore the cookie, will replace it } } // see if the domain is set for a specific language if (locale == null) { String domain = context.getRequest().getHeader("Host"); if (domain.indexOf(':') > -1) domain = domain.substring(0, domain.indexOf(':')); locale = this.domainlocales.get(domain); } // see if the user has a preference if (locale == null) { String lvalue = usr.getLocale(); if (StringUtil.isNotEmpty(lvalue)) locale = this.locales.get(lvalue); } // if we find any locale at all then to see if it is the default // if not use it, else use the default if ((locale != null) && !locale.equals(this.getDefaultLocaleDefinition())) { ctxb.withOperatingLocale(locale.getName()); return new DefaultCookie("dcLang", locale.getName()); } // clear the cookie if we are to use default locale if (langcookie != null) return new DefaultCookie("dcLang", ""); // we are using default locale, nothing more to do return null; }
public Object getAttribute(String s) { return context.getAttribute(s); }
protected void configureHttpServer(HttpServer server) { // Favicon hack HttpContext faviconContext = new HttpContext(); faviconContext.setContextPath("/favicon.ico"); server.addContext(faviconContext); ResourceHandler faviconHandler = new ResourceHandler(); faviconContext.setResourceBase(SysConfig.getStaticDir().getRootPath()); faviconContext.addHandler(faviconHandler); faviconContext.addHandler(new NotFoundHandler()); // robots.txt hack HttpContext robotsContext = new HttpContext(); robotsContext.setContextPath("/robots.txt"); server.addContext(robotsContext); ResourceHandler robotsHandler = new ResourceHandler(); robotsContext.setResourceBase(SysConfig.getStaticDir().getRootPath()); robotsContext.addHandler(robotsHandler); robotsContext.addHandler(new NotFoundHandler()); // Dynamic content HttpContext servletContext = new HttpContext(); servletContext.setContextPath("/"); server.addContext(servletContext); ServletHandler servlets = new ServletHandler(); servletContext.addHandler(servlets); servlets.addServlet("/*", "org.wahlzeit.main.MainServlet"); servletContext.addHandler(new NotFoundHandler()); // Photos content HttpContext photosContext = new HttpContext(); photosContext.setContextPath(SysConfig.getPhotosDirAsString()); server.addContext(photosContext); ResourceHandler photosHandler = new ResourceHandler(); photosContext.setResourceBase(SysConfig.getPhotosDirAsString()); photosContext.addHandler(photosHandler); photosContext.addHandler(new NotFoundHandler()); // Static content HttpContext staticContext = new HttpContext(); staticContext.setContextPath(SysConfig.getStaticDir().getRootPath()); server.addContext(staticContext); ResourceHandler staticHandler = new ResourceHandler(); staticContext.setResourceBase(SysConfig.getStaticDir().getRootPath()); staticContext.addHandler(staticHandler); staticContext.addHandler(new NotFoundHandler()); }