public static void renderDirectoryListing(HttpServerExchange exchange, Resource resource) { String requestPath = exchange.getRequestPath(); if (! requestPath.endsWith("/")) { exchange.setStatusCode(StatusCodes.FOUND); exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true)); exchange.endExchange(); return; } StringBuilder builder = renderDirectoryListing(requestPath, resource); try { ByteBuffer output = ByteBuffer.wrap(builder.toString().getBytes(StandardCharsets.UTF_8)); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html; charset=UTF-8"); exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, String.valueOf(output.limit())); exchange.getResponseHeaders().put(Headers.LAST_MODIFIED, DateUtils.toDateString(new Date())); exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "must-revalidate"); Channels.writeBlocking(exchange.getResponseChannel(), output); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); } exchange.endExchange(); }
@Override public void handleRequest(HttpServerExchange exchange) throws Exception { if (isConfidential(exchange) || !confidentialityRequired(exchange)) { next.handleRequest(exchange); } else { try { URI redirectUri = getRedirectURI(exchange); UndertowLogger.SECURITY_LOGGER.debugf("Redirecting request %s to %s to meet confidentiality requirements", exchange, redirectUri); exchange.setStatusCode(StatusCodes.FOUND); exchange.getResponseHeaders().put(Headers.LOCATION, redirectUri.toString()); } catch (Exception e) { UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(e); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); } exchange.endExchange(); } }
public static void executeRootHandler(final HttpHandler handler, final HttpServerExchange exchange) { try { exchange.setInCall(true); handler.handleRequest(exchange); exchange.setInCall(false); boolean resumed = exchange.isResumed(); if (exchange.isDispatched()) { if (resumed) { UndertowLogger.REQUEST_LOGGER.resumedAndDispatched(); exchange.setStatusCode(500); exchange.endExchange(); exchange.unDispatch(); if (dispatchTask != null) { executor = executor == null ? exchange.getConnection().getWorker() : executor; try { executor.execute(dispatchTask); } catch (RejectedExecutionException e) { UndertowLogger.REQUEST_LOGGER.debug("Failed to dispatch to worker", e); exchange.setStatusCode(StatusCodes.SERVICE_UNAVAILABLE); exchange.endExchange(); UndertowLogger.REQUEST_IO_LOGGER.ioException((IOException) t); } else { UndertowLogger.REQUEST_LOGGER.undertowRequestFailed(t, exchange); exchange.endExchange();
@Override public void handleEvent(StreamSourceChannel channel) { try { doHttp2PriRead(connection, buffer, serverConnection, extraData); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); IoUtils.safeClose(connection); } catch (Throwable t) { UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t); IoUtils.safeClose(connection); } } });
private void flushChannelIgnoreFailure(StreamSinkChannel stream) { try { flushChannel(stream); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); } catch (Throwable t) { UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t); } }
@Override public void handleException(Channel channel, IOException exception) { IoUtils.safeClose(channel); IoUtils.safeClose(clientConnection); if (exchange.isResponseStarted()) { UndertowLogger.REQUEST_IO_LOGGER.debug("Exception reading from target server", exception); if (!exchange.isResponseStarted()) { exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } else { IoUtils.safeClose(exchange.getConnection()); } } else { UndertowLogger.REQUEST_IO_LOGGER.ioException(exception); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } } }
private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); if (qop == null || !supportedQops.contains(qop)) { REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.MESSAGE_QOP.getName(), parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP)); REQUEST_LOGGER.missingAuthorizationToken(currentToken.getName()); REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.REALM.getName(), parsedHeader.get(DigestAuthorizationToken.REALM)); REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.OPAQUE.getName(), parsedHeader.get(DigestAuthorizationToken.OPAQUE)); return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; if (algorithm == null || !supportedAlgorithms.contains(algorithm)) { REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.ALGORITHM.getName(), parsedHeader.get(DigestAuthorizationToken.ALGORITHM)); REQUEST_LOGGER.exceptionProcessingRequest(e); return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), mechanismName); return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
res = channel.read(buffer); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); safeClose(connection); return; try { channel.shutdownReads(); final StreamSinkChannel responseChannel = connection.getChannel().getSinkChannel(); responseChannel.shutdownWrites(); safeClose(connection); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge(connection.getPeerAddress(), maxRequestSize); UndertowLogger.REQUEST_LOGGER.debug("Received CPING, sending CPONG"); handleCPing(); } else if (state.prefix == AjpRequestParser.CPONG) { UndertowLogger.REQUEST_LOGGER.debug("Received CPONG, starting next request"); state = new AjpRequestParseState(); channel.getReadSetter().set(this); channel.resumeReads(); } else { UndertowLogger.REQUEST_LOGGER.ignoringAjpRequestWithPrefixCode(state.prefix); UndertowLogger.REQUEST_IO_LOGGER.debugf("Invalid AJP request from %s, request contained invalid headers", connection.getPeerAddress()); UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(t);
/** * Upgrade the channel to a raw socket. This method set the response code to 101, and then marks both the * request and response as terminated, which means that once the current request is completed the raw channel * can be obtained from {@link io.undertow.server.protocol.http.HttpServerConnection#getChannel()} * * @throws IllegalStateException if a response or upgrade was already sent, or if the request body is already being * read */ public HttpServerExchange upgradeChannel(final HttpUpgradeListener listener) { if (!connection.isUpgradeSupported()) { throw UndertowMessages.MESSAGES.upgradeNotSupported(); } if(!getRequestHeaders().contains(Headers.UPGRADE)) { throw UndertowMessages.MESSAGES.notAnUpgradeRequest(); } UndertowLogger.REQUEST_LOGGER.debugf("Upgrading request %s", this); connection.setUpgradeListener(listener); setStatusCode(StatusCodes.SWITCHING_PROTOCOLS); getResponseHeaders().put(Headers.CONNECTION, Headers.UPGRADE_STRING); return this; }
private void closeAndFlushResponse() { if(!connection.isOpen()) { invokeExchangeCompleteListeners(); return; if (isResponseChannelAvailable()) { if(!getRequestMethod().equals(Methods.CONNECT) && !(getRequestMethod().equals(Methods.HEAD) && getResponseHeaders().contains(Headers.CONTENT_LENGTH)) && Connectors.isEntityBodyAllowed(this)) { getResponseHeaders().put(Headers.CONTENT_LENGTH, "0"); getResponseChannel(); UndertowLogger.ROOT_LOGGER.responseWasNotTerminated(connection, this); IoUtils.safeClose(connection); UndertowLogger.REQUEST_IO_LOGGER.ioException((IOException) t); } else { UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t); invokeExchangeCompleteListeners(); IoUtils.safeClose(connection);
@Override public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) { if(silent) { //if this is silent we only send a challenge if the request contained auth headers //otherwise we assume another method will send the challenge String authHeader = exchange.getRequestHeaders().getFirst(AUTHORIZATION); if(authHeader == null) { return ChallengeResult.NOT_SENT; } } exchange.getResponseHeaders().add(WWW_AUTHENTICATE, challenge); UndertowLogger.SECURITY_LOGGER.debugf("Sending basic auth challenge %s for %s", challenge, exchange); return new ChallengeResult(true, UNAUTHORIZED); }
sb.append(" contentLength=" + exchange.getResponseContentLength() + "\n"); sb.append(" contentType=" + exchange.getResponseHeaders().getFirst(Headers.CONTENT_TYPE) + "\n"); Map<String, Cookie> cookies = exchange.getResponseCookies(); if (cookies != null) { for (Cookie cookie : cookies.values()) { UndertowLogger.REQUEST_DUMPER_LOGGER.info(sb.toString());
@Override public void run() { try { final FormData existing = exchange.getAttachment(FORM_DATA); if (existing != null) { exchange.dispatch(SameThreadExecutor.INSTANCE, handler); return; PooledByteBuffer pooled = exchange.getConnection().getByteBufferPool().allocate(); try { while (true) { exchange.dispatch(SameThreadExecutor.INSTANCE, handler); } else { UndertowLogger.REQUEST_IO_LOGGER.ioException(UndertowMessages.MESSAGES.connectionTerminatedReadingMultiPartData()); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); UndertowLogger.REQUEST_IO_LOGGER.ioException(e); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); UndertowLogger.REQUEST_IO_LOGGER.debug("Exception parsing data", e); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange();
/** * Upgrade the channel to a raw socket. This method set the response code to 101, and then marks both the * request and response as terminated, which means that once the current request is completed the raw channel * can be obtained from {@link io.undertow.server.protocol.http.HttpServerConnection#getChannel()} * * @param productName the product name to report to the client * @throws IllegalStateException if a response or upgrade was already sent, or if the request body is already being * read */ public HttpServerExchange upgradeChannel(String productName, final HttpUpgradeListener listener) { if (!connection.isUpgradeSupported()) { throw UndertowMessages.MESSAGES.upgradeNotSupported(); } UndertowLogger.REQUEST_LOGGER.debugf("Upgrading request %s", this); connection.setUpgradeListener(listener); setStatusCode(StatusCodes.SWITCHING_PROTOCOLS); final HeaderMap headers = getResponseHeaders(); headers.put(Headers.UPGRADE, productName); headers.put(Headers.CONNECTION, Headers.UPGRADE_STRING); return this; }
public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) { NegotiationContext negContext = exchange.getAttachment(NegotiationContext.ATTACHMENT_KEY); String header = NEGOTIATION_PLAIN; if (negContext != null) { byte[] responseChallenge = negContext.useResponseToken(); exchange.putAttachment(NegotiationContext.ATTACHMENT_KEY, null); if (responseChallenge != null) { header = NEGOTIATE_PREFIX + FlexBase64.encodeString(responseChallenge, false); } } else { Subject server = null; try { server = subjectFactory.getSubjectForHost(getHostName(exchange)); } catch (GeneralSecurityException e) { // Deliberately ignore - no Subject so don't offer GSSAPI is our main concern here. } if (server == null) { return ChallengeResult.NOT_SENT; } } exchange.getResponseHeaders().add(WWW_AUTHENTICATE, header); UndertowLogger.SECURITY_LOGGER.debugf("Sending GSSAPI challenge for %s", exchange); return new ChallengeResult(true, UNAUTHORIZED); }
public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) { List<String> authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION); if (authHeaders != null) { for (String current : authHeaders) { if (current.startsWith(DIGEST_PREFIX)) { String digestChallenge = current.substring(PREFIX_LENGTH); try { DigestContext context = new DigestContext(); Map<DigestAuthorizationToken, String> parsedHeader = parseHeader(digestChallenge); context.setMethod(exchange.getRequestMethod().toString()); context.setParsedHeader(parsedHeader); // Some form of Digest authentication is going to occur so get the DigestContext set on the exchange. exchange.putAttachment(DigestContext.ATTACHMENT_KEY, context); UndertowLogger.SECURITY_LOGGER.debugf("Found digest header %s in %s", current, exchange); return handleDigestHeader(exchange, securityContext); } catch (Exception e) { e.printStackTrace(); } } // By this point we had a header we should have been able to verify but for some reason // it was not correctly structured. return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; } } // No suitable header has been found in this request, return AuthenticationMechanismOutcome.NOT_ATTEMPTED; }
buffer.clear(); try { res = channel.read(buffer); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.debug("Error reading request", e); IoUtils.safeClose(connection); return; httpServerExchange = new HttpServerExchange(connection, maxEntitySize); read = total; if (read > maxRequestSize) { UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge(connection.getPeerAddress(), maxRequestSize); sendBadRequestAndClose(connection.getChannel(), null); return; UndertowLogger.REQUEST_IO_LOGGER.debugf("Closing connection from %s due to unknown protocol %s", connection.getChannel().getPeerAddress(), protocol); sendBadRequestAndClose(connection.getChannel(), new IOException()); return; channel.suspendReads(); sendBadRequestAndClose(connection.getChannel(), UndertowMessages.MESSAGES.noHostInHttp11Request()); return; sendBadRequestAndClose(connection.getChannel(), UndertowMessages.MESSAGES.invalidHeaders()); return;
@Override public FormDataParser create(final HttpServerExchange exchange) { String mimeType = exchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE); if (mimeType != null && mimeType.startsWith(MULTIPART_FORM_DATA)) { String boundary = Headers.extractQuotedValueFromHeader(mimeType, "boundary"); if (boundary == null) { UndertowLogger.REQUEST_LOGGER.debugf("Could not find boundary in multipart request with ContentType: %s, multipart data will not be available", mimeType); return null; } final MultiPartUploadHandler parser = new MultiPartUploadHandler(exchange, boundary, maxIndividualFileSize, fileSizeThreshold, defaultEncoding); exchange.addExchangeCompleteListener(new ExchangeCompletionListener() { @Override public void exchangeEvent(final HttpServerExchange exchange, final NextListener nextListener) { IoUtils.safeClose(parser); nextListener.proceed(); } }); Long sizeLimit = exchange.getConnection().getUndertowOptions().get(UndertowOptions.MULTIPART_MAX_ENTITY_SIZE); if(sizeLimit != null) { exchange.setMaxEntitySize(sizeLimit); } UndertowLogger.REQUEST_LOGGER.tracef("Created multipart parser for %s", exchange); return parser; } return null; }
@Override public void handleRequest(HttpServerExchange exchange) throws Exception { HeaderMap requestHeaders = exchange.getRequestHeaders(); final String sessionId = requestHeaders.getFirst(SSL_SESSION_ID); final String cipher = requestHeaders.getFirst(SSL_CIPHER); String clientCert = requestHeaders.getFirst(SSL_CLIENT_CERT); //the proxy client replaces \n with ' ' if (clientCert != null && clientCert.length() > 28) { StringBuilder sb = new StringBuilder(clientCert.length() + 1); sb.append(Certificates.BEGIN_CERT); sb.append('\n'); sb.append(clientCert.replace(' ', '\n').substring(28, clientCert.length() - 26));//core certificate data sb.append('\n'); sb.append(Certificates.END_CERT); clientCert = sb.toString(); } if (clientCert != null || sessionId != null || cipher != null) { try { SSLSessionInfo info = new BasicSSLSessionInfo(sessionId, cipher, clientCert); exchange.setRequestScheme(HTTPS); exchange.getConnection().setSslSessionInfo(info); exchange.addExchangeCompleteListener(CLEAR_SSL_LISTENER); } catch (java.security.cert.CertificateException | CertificateException e) { UndertowLogger.REQUEST_LOGGER.debugf(e, "Could not create certificate from header %s", clientCert); } } next.handleRequest(exchange); }
@Override public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) { ServerConnection connection = exchange.getConnection(); NegotiationContext negContext = connection.getAttachment(NegotiationContext.ATTACHMENT_KEY); if (negContext != null) { UndertowLogger.SECURITY_LOGGER.debugf("Existing negotiation context found for %s", exchange); exchange.putAttachment(NegotiationContext.ATTACHMENT_KEY, negContext); if (negContext.isEstablished()) { IdentityManager identityManager = getIdentityManager(securityContext); if (account != null) { securityContext.authenticationComplete(account, name, false); UndertowLogger.SECURITY_LOGGER.debugf("Authenticated as user %s with existing GSSAPI negotiation context for %s", account.getPrincipal().getName(), exchange); return AuthenticationMechanismOutcome.AUTHENTICATED; } else { UndertowLogger.SECURITY_LOGGER.debugf("Failed to authenticate with existing GSSAPI negotiation context for %s", exchange); return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; List<String> authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION); if (authHeaders != null) { for (String current : authHeaders) {