use of org.jboss.netty.handler.codec.http.DefaultHttpResponse in project hadoop by apache.
the class TestShuffleHandler method testKeepAlive.
@Test(timeout = 10000)
public void testKeepAlive() throws Exception {
final ArrayList<Throwable> failures = new ArrayList<Throwable>(1);
Configuration conf = new Configuration();
conf.setInt(ShuffleHandler.SHUFFLE_PORT_CONFIG_KEY, 0);
conf.setBoolean(ShuffleHandler.SHUFFLE_CONNECTION_KEEP_ALIVE_ENABLED, true);
// try setting to -ve keep alive timeout.
conf.setInt(ShuffleHandler.SHUFFLE_CONNECTION_KEEP_ALIVE_TIME_OUT, -100);
ShuffleHandler shuffleHandler = new ShuffleHandler() {
@Override
protected Shuffle getShuffle(final Configuration conf) {
// replace the shuffle handler with one stubbed for testing
return new Shuffle(conf) {
@Override
protected MapOutputInfo getMapOutputInfo(String mapId, int reduce, String jobId, String user) throws IOException {
return null;
}
@Override
protected void verifyRequest(String appid, ChannelHandlerContext ctx, HttpRequest request, HttpResponse response, URL requestUri) throws IOException {
}
@Override
protected void populateHeaders(List<String> mapIds, String jobId, String user, int reduce, HttpRequest request, HttpResponse response, boolean keepAliveParam, Map<String, MapOutputInfo> infoMap) throws IOException {
// Send some dummy data (populate content length details)
ShuffleHeader header = new ShuffleHeader("attempt_12345_1_m_1_0", 5678, 5678, 1);
DataOutputBuffer dob = new DataOutputBuffer();
header.write(dob);
dob = new DataOutputBuffer();
for (int i = 0; i < 100000; ++i) {
header.write(dob);
}
long contentLength = dob.getLength();
// disable connectinKeepAliveEnabled if keepAliveParam is available
if (keepAliveParam) {
connectionKeepAliveEnabled = false;
}
super.setResponseHeaders(response, keepAliveParam, contentLength);
}
@Override
protected ChannelFuture sendMapOutput(ChannelHandlerContext ctx, Channel ch, String user, String mapId, int reduce, MapOutputInfo info) throws IOException {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
// send a shuffle header and a lot of data down the channel
// to trigger a broken pipe
ShuffleHeader header = new ShuffleHeader("attempt_12345_1_m_1_0", 5678, 5678, 1);
DataOutputBuffer dob = new DataOutputBuffer();
header.write(dob);
ch.write(wrappedBuffer(dob.getData(), 0, dob.getLength()));
dob = new DataOutputBuffer();
for (int i = 0; i < 100000; ++i) {
header.write(dob);
}
return ch.write(wrappedBuffer(dob.getData(), 0, dob.getLength()));
}
@Override
protected void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
if (failures.size() == 0) {
failures.add(new Error());
ctx.getChannel().close();
}
}
@Override
protected void sendError(ChannelHandlerContext ctx, String message, HttpResponseStatus status) {
if (failures.size() == 0) {
failures.add(new Error());
ctx.getChannel().close();
}
}
};
}
};
shuffleHandler.init(conf);
shuffleHandler.start();
String shuffleBaseURL = "http://127.0.0.1:" + shuffleHandler.getConfig().get(ShuffleHandler.SHUFFLE_PORT_CONFIG_KEY);
URL url = new URL(shuffleBaseURL + "/mapOutput?job=job_12345_1&reduce=1&" + "map=attempt_12345_1_m_1_0");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty(ShuffleHeader.HTTP_HEADER_NAME, ShuffleHeader.DEFAULT_HTTP_HEADER_NAME);
conn.setRequestProperty(ShuffleHeader.HTTP_HEADER_VERSION, ShuffleHeader.DEFAULT_HTTP_HEADER_VERSION);
conn.connect();
DataInputStream input = new DataInputStream(conn.getInputStream());
Assert.assertEquals(HttpHeader.KEEP_ALIVE.asString(), conn.getHeaderField(HttpHeader.CONNECTION.asString()));
Assert.assertEquals("timeout=1", conn.getHeaderField(HttpHeader.KEEP_ALIVE.asString()));
Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
ShuffleHeader header = new ShuffleHeader();
header.readFields(input);
input.close();
// For keepAlive via URL
url = new URL(shuffleBaseURL + "/mapOutput?job=job_12345_1&reduce=1&" + "map=attempt_12345_1_m_1_0&keepAlive=true");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty(ShuffleHeader.HTTP_HEADER_NAME, ShuffleHeader.DEFAULT_HTTP_HEADER_NAME);
conn.setRequestProperty(ShuffleHeader.HTTP_HEADER_VERSION, ShuffleHeader.DEFAULT_HTTP_HEADER_VERSION);
conn.connect();
input = new DataInputStream(conn.getInputStream());
Assert.assertEquals(HttpHeader.KEEP_ALIVE.asString(), conn.getHeaderField(HttpHeader.CONNECTION.asString()));
Assert.assertEquals("timeout=1", conn.getHeaderField(HttpHeader.KEEP_ALIVE.asString()));
Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
header = new ShuffleHeader();
header.readFields(input);
input.close();
}
use of org.jboss.netty.handler.codec.http.DefaultHttpResponse in project camel by apache.
the class HttpServerChannelHandler method messageReceived.
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception {
HttpRequest request = (HttpRequest) messageEvent.getMessage();
LOG.debug("Message received: {}", request);
if (consumer.isSuspended()) {
// are we suspended?
LOG.debug("Consumer suspended, cannot service request {}", request);
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, SERVICE_UNAVAILABLE);
response.setChunked(false);
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
response.setContent(ChannelBuffers.copiedBuffer(new byte[] {}));
messageEvent.getChannel().write(response).syncUninterruptibly();
messageEvent.getChannel().close();
return;
}
// if its an OPTIONS request then return which methods is allowed
boolean isRestrictedToOptions = consumer.getEndpoint().getHttpMethodRestrict() != null && consumer.getEndpoint().getHttpMethodRestrict().contains("OPTIONS");
if ("OPTIONS".equals(request.getMethod().getName()) && !isRestrictedToOptions) {
String s;
if (consumer.getEndpoint().getHttpMethodRestrict() != null) {
s = "OPTIONS," + consumer.getEndpoint().getHttpMethodRestrict();
} else {
// allow them all
s = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATCH";
}
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
response.setChunked(false);
response.headers().set("Allow", s);
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
messageEvent.getChannel().write(response).syncUninterruptibly();
messageEvent.getChannel().close();
return;
}
if (consumer.getEndpoint().getHttpMethodRestrict() != null && !consumer.getEndpoint().getHttpMethodRestrict().contains(request.getMethod().getName())) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, METHOD_NOT_ALLOWED);
response.setChunked(false);
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
response.setContent(ChannelBuffers.copiedBuffer(new byte[] {}));
messageEvent.getChannel().write(response).syncUninterruptibly();
messageEvent.getChannel().close();
return;
}
if ("TRACE".equals(request.getMethod().getName()) && !consumer.getEndpoint().isTraceEnabled()) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, METHOD_NOT_ALLOWED);
response.setChunked(false);
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
response.setContent(ChannelBuffers.copiedBuffer(new byte[] {}));
messageEvent.getChannel().write(response).syncUninterruptibly();
messageEvent.getChannel().close();
return;
}
// must include HOST header as required by HTTP 1.1
if (!request.headers().contains(HttpHeaders.Names.HOST)) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST);
response.setChunked(false);
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
response.setContent(ChannelBuffers.copiedBuffer(new byte[] {}));
messageEvent.getChannel().write(response).syncUninterruptibly();
messageEvent.getChannel().close();
return;
}
// is basic auth configured
NettyHttpSecurityConfiguration security = consumer.getEndpoint().getSecurityConfiguration();
if (security != null && security.isAuthenticate() && "Basic".equalsIgnoreCase(security.getConstraint())) {
String url = request.getUri();
// drop parameters from url
if (url.contains("?")) {
url = ObjectHelper.before(url, "?");
}
// we need the relative path without the hostname and port
URI uri = new URI(request.getUri());
String target = uri.getPath();
// strip the starting endpoint path so the target is relative to the endpoint uri
String path = consumer.getConfiguration().getPath();
if (path != null) {
// need to match by lower case as we want to ignore case on context-path
path = path.toLowerCase(Locale.US);
String match = target.toLowerCase(Locale.US);
if (match.startsWith(path)) {
target = target.substring(path.length());
}
}
// is it a restricted resource?
String roles;
if (security.getSecurityConstraint() != null) {
// if restricted returns null, then the resource is not restricted and we should not authenticate the user
roles = security.getSecurityConstraint().restricted(target);
} else {
// assume any roles is valid if no security constraint has been configured
roles = "*";
}
if (roles != null) {
// basic auth subject
HttpPrincipal principal = extractBasicAuthSubject(request);
// authenticate principal and check if the user is in role
Subject subject = null;
boolean inRole = true;
if (principal != null) {
subject = authenticate(security.getSecurityAuthenticator(), security.getLoginDeniedLoggingLevel(), principal);
if (subject != null) {
String userRoles = security.getSecurityAuthenticator().getUserRoles(subject);
inRole = matchesRoles(roles, userRoles);
}
}
if (principal == null || subject == null || !inRole) {
if (principal == null) {
LOG.debug("Http Basic Auth required for resource: {}", url);
} else if (subject == null) {
LOG.debug("Http Basic Auth not authorized for username: {}", principal.getUsername());
} else {
LOG.debug("Http Basic Auth not in role for username: {}", principal.getUsername());
}
// restricted resource, so send back 401 to require valid username/password
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, UNAUTHORIZED);
response.headers().set("WWW-Authenticate", "Basic realm=\"" + security.getRealm() + "\"");
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
response.setContent(ChannelBuffers.copiedBuffer(new byte[] {}));
messageEvent.getChannel().write(response).syncUninterruptibly();
messageEvent.getChannel().close();
return;
} else {
LOG.debug("Http Basic Auth authorized for username: {}", principal.getUsername());
}
}
}
// let Camel process this message
// It did the way as camel-netty component does
super.messageReceived(ctx, messageEvent);
}
use of org.jboss.netty.handler.codec.http.DefaultHttpResponse in project camel by apache.
the class HttpServerMultiplexChannelHandler method exceptionCaught.
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
HttpServerChannelHandler handler = (HttpServerChannelHandler) ctx.getAttachment();
if (handler != null) {
handler.exceptionCaught(ctx, e);
} else {
if (e.getCause() instanceof ClosedChannelException) {
// The channel is closed so we do nothing here
LOG.debug("Channel already closed. Ignoring this exception.");
return;
} else {
if ("Broken pipe".equals(e.getCause().getMessage())) {
// Can't recover channel at this point. Only valid thing to do is close. A TCP RST is a possible cause for this.
// Note that trying to write to channel in this state will cause infinite recursion in netty 3.x
LOG.debug("Channel pipe is broken. Closing channel now.", e);
ctx.getChannel().close();
} else {
// we cannot throw the exception here
LOG.warn("HttpServerChannelHandler is not found as attachment to handle exception, send 404 back to the client.", e.getCause());
// Now we just send 404 back to the client
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
response.headers().set(Exchange.CONTENT_LENGTH, 0);
// Here we don't want to expose the exception detail to the client
response.setContent(ChannelBuffers.copiedBuffer(new byte[] {}));
ctx.getChannel().write(response).syncUninterruptibly();
// close the channel after send error message
ctx.getChannel().close();
}
}
}
}
use of org.jboss.netty.handler.codec.http.DefaultHttpResponse in project camel by apache.
the class DefaultNettyHttpBinding method toNettyResponse.
@Override
public HttpResponse toNettyResponse(Message message, NettyHttpConfiguration configuration) throws Exception {
LOG.trace("toNettyResponse: {}", message);
// the message body may already be a Netty HTTP response
if (message.getBody() instanceof HttpResponse) {
return (HttpResponse) message.getBody();
}
// the response code is 200 for OK and 500 for failed
boolean failed = message.getExchange().isFailed();
int defaultCode = failed ? 500 : 200;
int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, defaultCode, int.class);
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(code));
LOG.trace("HTTP Status Code: {}", code);
TypeConverter tc = message.getExchange().getContext().getTypeConverter();
// must use entrySet to ensure case of keys is preserved
for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// use an iterator as there can be multiple values. (must not use a delimiter)
final Iterator<?> it = ObjectHelper.createIterator(value, null);
while (it.hasNext()) {
String headerValue = tc.convertTo(String.class, it.next());
if (headerValue != null && headerFilterStrategy != null && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, message.getExchange())) {
LOG.trace("HTTP-Header: {}={}", key, headerValue);
response.headers().add(key, headerValue);
}
}
}
Object body = message.getBody();
Exception cause = message.getExchange().getException();
// support bodies as native Netty
ChannelBuffer buffer;
// if there was an exception then use that as body
if (cause != null) {
if (configuration.isTransferException()) {
// we failed due an exception, and transfer it as java serialized object
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(cause);
oos.flush();
IOHelper.close(oos, bos);
// the body should be the serialized java object of the exception
body = ChannelBuffers.copiedBuffer(bos.toByteArray());
// force content type to be serialized java object
message.setHeader(Exchange.CONTENT_TYPE, NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT);
} else {
// we failed due an exception so print it as plain text
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
cause.printStackTrace(pw);
// the body should then be the stacktrace
body = ChannelBuffers.copiedBuffer(sw.toString().getBytes());
// force content type to be text/plain as that is what the stacktrace is
message.setHeader(Exchange.CONTENT_TYPE, "text/plain");
}
// and mark the exception as failure handled, as we handled it by returning it as the response
ExchangeHelper.setFailureHandled(message.getExchange());
}
if (body instanceof ChannelBuffer) {
buffer = (ChannelBuffer) body;
} else {
// try to convert to buffer first
buffer = message.getBody(ChannelBuffer.class);
if (buffer == null) {
// fallback to byte array as last resort
byte[] data = message.getBody(byte[].class);
if (data != null) {
buffer = ChannelBuffers.copiedBuffer(data);
} else {
// and if byte array fails then try String
String str;
if (body != null) {
str = message.getMandatoryBody(String.class);
} else {
str = "";
}
buffer = ChannelBuffers.copiedBuffer(str.getBytes());
}
}
}
if (buffer != null) {
response.setContent(buffer);
// We just need to reset the readerIndex this time
if (buffer.readerIndex() == buffer.writerIndex()) {
buffer.setIndex(0, buffer.writerIndex());
}
// TODO How to enable the chunk transport
int len = buffer.readableBytes();
// set content-length
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, len);
LOG.trace("Content-Length: {}", len);
}
// set the content type in the response.
String contentType = MessageHelper.getContentType(message);
if (contentType != null) {
// set content-type
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, contentType);
LOG.trace("Content-Type: {}", contentType);
}
// configure connection to accordingly to keep alive configuration
// favor using the header from the message
String connection = message.getHeader(HttpHeaders.Names.CONNECTION, String.class);
// Read the connection header from the exchange property
if (connection == null) {
connection = message.getExchange().getProperty(HttpHeaders.Names.CONNECTION, String.class);
}
if (connection == null) {
// fallback and use the keep alive from the configuration
if (configuration.isKeepAlive()) {
connection = HttpHeaders.Values.KEEP_ALIVE;
} else {
connection = HttpHeaders.Values.CLOSE;
}
}
response.headers().set(HttpHeaders.Names.CONNECTION, connection);
// Just make sure we close the channel when the connection value is close
if (connection.equalsIgnoreCase(HttpHeaders.Values.CLOSE)) {
message.setHeader(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, true);
}
LOG.trace("Connection: {}", connection);
return response;
}
use of org.jboss.netty.handler.codec.http.DefaultHttpResponse in project cdap by caskdata.
the class SecurityAuthenticationHttpHandler method validateSecuredInterception.
/**
* Intercepts the HttpMessage for getting the access token in authorization header
*
* @param ctx channel handler context delegated from MessageReceived callback
* @param msg intercepted HTTP message
* @param inboundChannel
* @return {@code true} if the HTTP message has valid Access token
* @throws Exception
*/
private boolean validateSecuredInterception(ChannelHandlerContext ctx, HttpRequest msg, Channel inboundChannel, AuditLogEntry logEntry) throws Exception {
String auth = msg.getHeader(HttpHeaders.Names.AUTHORIZATION);
String accessToken = null;
/*
* Parse the access token from authorization header. The header will be in the form:
* Authorization: Bearer ACCESSTOKEN
*
* where ACCESSTOKEN is the base64 encoded serialized AccessToken instance.
*/
if (auth != null) {
int spIndex = auth.trim().indexOf(' ');
if (spIndex != -1) {
accessToken = auth.substring(spIndex + 1).trim();
}
}
HttpMethod httpMethod = msg.getMethod();
String uri = msg.getUri();
logEntry.setClientIP(((InetSocketAddress) ctx.getChannel().getRemoteAddress()).getAddress());
logEntry.setRequestLine(httpMethod, uri, msg.getProtocolVersion());
TokenState tokenState = tokenValidator.validate(accessToken);
if (!tokenState.isValid()) {
HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED);
logEntry.setResponseCode(HttpResponseStatus.UNAUTHORIZED.getCode());
JsonObject jsonObject = new JsonObject();
if (tokenState == TokenState.MISSING) {
httpResponse.addHeader(HttpHeaders.Names.WWW_AUTHENTICATE, String.format("Bearer realm=\"%s\"", realm));
LOG.debug("Authentication failed due to missing token");
} else {
httpResponse.addHeader(HttpHeaders.Names.WWW_AUTHENTICATE, String.format("Bearer realm=\"%s\" error=\"invalid_token\"" + " error_description=\"%s\"", realm, tokenState.getMsg()));
jsonObject.addProperty("error", "invalid_token");
jsonObject.addProperty("error_description", tokenState.getMsg());
LOG.debug("Authentication failed due to invalid token, reason={};", tokenState);
}
JsonArray externalAuthenticationURIs = new JsonArray();
// Waiting for service to get discovered
stopWatchWait(externalAuthenticationURIs);
jsonObject.add("auth_uri", externalAuthenticationURIs);
ChannelBuffer content = ChannelBuffers.wrappedBuffer(jsonObject.toString().getBytes(Charsets.UTF_8));
httpResponse.setContent(content);
int contentLength = content.readableBytes();
httpResponse.setHeader(HttpHeaders.Names.CONTENT_LENGTH, contentLength);
httpResponse.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/json;charset=UTF-8");
logEntry.setResponseContentLength(new Long(contentLength));
ChannelFuture writeFuture = Channels.future(inboundChannel);
Channels.write(ctx, writeFuture, httpResponse);
writeFuture.addListener(ChannelFutureListener.CLOSE);
return false;
} else {
AccessTokenTransformer.AccessTokenIdentifierPair accessTokenIdentifierPair = accessTokenTransformer.transform(accessToken);
AuditLogContent auditLogContent = AUDIT_LOG_LOOKUP_METHOD.contains(httpMethod) ? AUDIT_LOOK_UP.getAuditLogContent(msg.getUri(), httpMethod) : null;
if (auditLogContent != null) {
List<String> headerNames = auditLogContent.getHeaderNames();
if (!headerNames.isEmpty()) {
Map<String, String> headers = new HashMap<>();
for (String headerName : headerNames) {
headers.put(headerName, msg.getHeader(headerName));
}
logEntry.setHeaders(headers);
}
if (auditLogContent.isLogRequestBody()) {
ChannelBuffer body = msg.getContent();
if (body.readable()) {
logEntry.setRequestBody(body.toString(Charsets.UTF_8));
}
}
logEntry.setLogResponseBody(auditLogContent.isLogResponsebody());
}
logEntry.setUserName(accessTokenIdentifierPair.getAccessTokenIdentifierObj().getUsername());
msg.setHeader(HttpHeaders.Names.AUTHORIZATION, "CDAP-verified " + accessTokenIdentifierPair.getAccessTokenIdentifierStr());
msg.setHeader(Constants.Security.Headers.USER_ID, accessTokenIdentifierPair.getAccessTokenIdentifierObj().getUsername());
msg.setHeader(Constants.Security.Headers.USER_IP, ((InetSocketAddress) ctx.getChannel().getRemoteAddress()).getAddress().getHostAddress());
return true;
}
}
Aggregations