use of org.jboss.netty.handler.codec.http.HttpMethod 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;
}
}
use of org.jboss.netty.handler.codec.http.HttpMethod in project voldemort by voldemort.
the class AbstractRestRequestHandler method messageReceived.
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception {
RestRequestValidator requestValidator;
if (!readingChunks) {
// Construct the Request from messageEvent
HttpRequest request = this.request = (HttpRequest) messageEvent.getMessage();
String requestURI = this.request.getUri();
if (logger.isDebugEnabled()) {
logger.debug("Request URI: " + requestURI);
}
if (request.isChunked()) {
readingChunks = true;
} else {
// Instantiate the appropriate error handler
HttpMethod httpMethod = request.getMethod();
if (httpMethod.equals(HttpMethod.GET)) {
if (logger.isDebugEnabled()) {
logger.debug("Received a Http GET request at " + System.currentTimeMillis() + " ms");
}
requestValidator = new RestGetRequestValidator(request, messageEvent);
} else if (httpMethod.equals(HttpMethod.POST)) {
if (logger.isDebugEnabled()) {
logger.debug("Received a Http POST request at " + System.currentTimeMillis() + " ms");
}
requestValidator = new RestPutRequestValidator(request, messageEvent, this.isVectorClockOptional);
} else if (httpMethod.equals(HttpMethod.DELETE)) {
if (logger.isDebugEnabled()) {
logger.debug("Received a Http DELETE request at " + System.currentTimeMillis() + " ms");
}
requestValidator = new RestDeleteRequestValidator(request, messageEvent, this.isVectorClockOptional);
} else {
String errorMessage = "Illegal Http request received at " + System.currentTimeMillis() + " ms";
logger.error(errorMessage);
RestErrorHandler.writeErrorResponse(messageEvent, BAD_REQUEST, errorMessage);
return;
}
registerRequest(requestValidator, ctx, messageEvent);
}
} else {
HttpChunk chunk = (HttpChunk) messageEvent.getMessage();
if (chunk.isLast()) {
readingChunks = false;
}
}
}
use of org.jboss.netty.handler.codec.http.HttpMethod in project druid by druid-io.
the class NettyHttpClient method go.
@Override
public <Intermediate, Final> ListenableFuture<Final> go(final Request request, final HttpResponseHandler<Intermediate, Final> handler, final Duration requestReadTimeout) {
final HttpMethod method = request.getMethod();
final URL url = request.getUrl();
final Multimap<String, String> headers = request.getHeaders();
final String requestDesc = method + " " + url;
if (log.isDebugEnabled()) {
log.debug("[%s] starting", requestDesc);
}
// Block while acquiring a channel from the pool, then complete the request asynchronously.
final Channel channel;
final String hostKey = getPoolKey(url);
final ResourceContainer<ChannelFuture> channelResourceContainer = pool.take(hostKey);
final ChannelFuture channelFuture = channelResourceContainer.get().awaitUninterruptibly();
if (!channelFuture.isSuccess()) {
// Some other poor sap will have to deal with it...
channelResourceContainer.returnResource();
return Futures.immediateFailedFuture(new ChannelException("Faulty channel in resource pool", channelFuture.getCause()));
} else {
channel = channelFuture.getChannel();
// In case we get a channel that never had its readability turned back on.
channel.setReadable(true);
}
final String urlFile = StringUtils.nullToEmptyNonDruidDataString(url.getFile());
final HttpRequest httpRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, method, urlFile.isEmpty() ? "/" : urlFile);
if (!headers.containsKey(HttpHeaders.Names.HOST)) {
httpRequest.headers().add(HttpHeaders.Names.HOST, getHost(url));
}
// If Accept-Encoding is set in the Request, use that. Otherwise use the default from "compressionCodec".
if (!headers.containsKey(HttpHeaders.Names.ACCEPT_ENCODING)) {
httpRequest.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, compressionCodec.getEncodingString());
}
for (Map.Entry<String, Collection<String>> entry : headers.asMap().entrySet()) {
String key = entry.getKey();
for (String obj : entry.getValue()) {
httpRequest.headers().add(key, obj);
}
}
if (request.hasContent()) {
httpRequest.setContent(request.getContent());
}
final long readTimeout = getReadTimeout(requestReadTimeout);
final SettableFuture<Final> retVal = SettableFuture.create();
if (readTimeout > 0) {
channel.getPipeline().addLast(READ_TIMEOUT_HANDLER_NAME, new ReadTimeoutHandler(timer, readTimeout, TimeUnit.MILLISECONDS));
}
channel.getPipeline().addLast(LAST_HANDLER_NAME, new SimpleChannelUpstreamHandler() {
private volatile ClientResponse<Intermediate> response = null;
// Chunk number most recently assigned.
private long currentChunkNum = 0;
// Suspend and resume watermarks (respectively: last chunk number that triggered a suspend, and that was
// provided to the TrafficCop's resume method). Synchronized access since they are not always accessed
// from an I/O thread. (TrafficCops can be called from any thread.)
private final Object watermarkLock = new Object();
private long suspendWatermark = -1;
private long resumeWatermark = -1;
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
if (log.isDebugEnabled()) {
log.debug("[%s] messageReceived: %s", requestDesc, e.getMessage());
}
try {
Object msg = e.getMessage();
if (msg instanceof HttpResponse) {
HttpResponse httpResponse = (HttpResponse) msg;
if (log.isDebugEnabled()) {
log.debug("[%s] Got response: %s", requestDesc, httpResponse.getStatus());
}
HttpResponseHandler.TrafficCop trafficCop = resumeChunkNum -> {
synchronized (watermarkLock) {
resumeWatermark = Math.max(resumeWatermark, resumeChunkNum);
if (suspendWatermark >= 0 && resumeWatermark >= suspendWatermark) {
suspendWatermark = -1;
channel.setReadable(true);
long backPressureDuration = System.nanoTime() - backPressureStartTimeNs;
log.debug("[%s] Resumed reads from channel (chunkNum = %,d).", requestDesc, resumeChunkNum);
return backPressureDuration;
}
}
// If we didn't resume, don't know if backpressure was happening
return 0;
};
response = handler.handleResponse(httpResponse, trafficCop);
if (response.isFinished()) {
retVal.set((Final) response.getObj());
}
assert currentChunkNum == 0;
possiblySuspendReads(response);
if (!httpResponse.isChunked()) {
finishRequest();
}
} else if (msg instanceof HttpChunk) {
HttpChunk httpChunk = (HttpChunk) msg;
if (log.isDebugEnabled()) {
log.debug("[%s] Got chunk: %sB, last=%s", requestDesc, httpChunk.getContent().readableBytes(), httpChunk.isLast());
}
if (httpChunk.isLast()) {
finishRequest();
} else {
response = handler.handleChunk(response, httpChunk, ++currentChunkNum);
if (response.isFinished() && !retVal.isDone()) {
retVal.set((Final) response.getObj());
}
possiblySuspendReads(response);
}
} else {
throw new ISE("Unknown message type[%s]", msg.getClass());
}
} catch (Exception ex) {
log.warn(ex, "[%s] Exception thrown while processing message, closing channel.", requestDesc);
if (!retVal.isDone()) {
retVal.set(null);
}
channel.close();
channelResourceContainer.returnResource();
throw ex;
}
}
private void possiblySuspendReads(ClientResponse<?> response) {
if (!response.isContinueReading()) {
synchronized (watermarkLock) {
suspendWatermark = Math.max(suspendWatermark, currentChunkNum);
if (suspendWatermark > resumeWatermark) {
channel.setReadable(false);
backPressureStartTimeNs = System.nanoTime();
log.debug("[%s] Suspended reads from channel (chunkNum = %,d).", requestDesc, currentChunkNum);
}
}
}
}
private void finishRequest() {
ClientResponse<Final> finalResponse = handler.done(response);
if (!finalResponse.isFinished() || !finalResponse.isContinueReading()) {
throw new ISE("[%s] Didn't get a completed ClientResponse Object from [%s] (finished = %s, continueReading = %s)", requestDesc, handler.getClass(), finalResponse.isFinished(), finalResponse.isContinueReading());
}
if (!retVal.isDone()) {
retVal.set(finalResponse.getObj());
}
removeHandlers();
channel.setReadable(true);
channelResourceContainer.returnResource();
}
@Override
public void exceptionCaught(ChannelHandlerContext context, ExceptionEvent event) {
if (log.isDebugEnabled()) {
final Throwable cause = event.getCause();
if (cause == null) {
log.debug("[%s] Caught exception", requestDesc);
} else {
log.debug(cause, "[%s] Caught exception", requestDesc);
}
}
retVal.setException(event.getCause());
// response is non-null if we received initial chunk and then exception occurs
if (response != null) {
handler.exceptionCaught(response, event.getCause());
}
try {
if (channel.isOpen()) {
channel.close();
}
} catch (Exception e) {
log.warn(e, "Error while closing channel");
} finally {
channelResourceContainer.returnResource();
}
}
@Override
public void channelDisconnected(ChannelHandlerContext context, ChannelStateEvent event) {
if (log.isDebugEnabled()) {
log.debug("[%s] Channel disconnected", requestDesc);
}
// response is non-null if we received initial chunk and then exception occurs
if (response != null) {
handler.exceptionCaught(response, new ChannelException("Channel disconnected"));
}
channel.close();
channelResourceContainer.returnResource();
if (!retVal.isDone()) {
log.warn("[%s] Channel disconnected before response complete", requestDesc);
retVal.setException(new ChannelException("Channel disconnected"));
}
}
private void removeHandlers() {
if (readTimeout > 0) {
channel.getPipeline().remove(READ_TIMEOUT_HANDLER_NAME);
}
channel.getPipeline().remove(LAST_HANDLER_NAME);
}
});
channel.write(httpRequest).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
channel.close();
channelResourceContainer.returnResource();
if (!retVal.isDone()) {
retVal.setException(new ChannelException(StringUtils.format("[%s] Failed to write request to channel", requestDesc), future.getCause()));
}
}
}
});
return retVal;
}
use of org.jboss.netty.handler.codec.http.HttpMethod in project camel by apache.
the class DefaultNettyHttpBinding method toNettyRequest.
@Override
public HttpRequest toNettyRequest(Message message, String uri, NettyHttpConfiguration configuration) throws Exception {
LOG.trace("toNettyRequest: {}", message);
// the message body may already be a Netty HTTP response
if (message.getBody() instanceof HttpRequest) {
return (HttpRequest) message.getBody();
}
String uriForRequest = uri;
if (configuration.isUseRelativePath()) {
int indexOfPath = uri.indexOf((new URI(uri)).getPath());
if (indexOfPath > 0) {
uriForRequest = uri.substring(indexOfPath);
}
}
// just assume GET for now, we will later change that to the actual method to use
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriForRequest);
TypeConverter tc = message.getExchange().getContext().getTypeConverter();
// if we bridge endpoint then we need to skip matching headers with the HTTP_QUERY to avoid sending
// duplicated headers to the receiver, so use this skipRequestHeaders as the list of headers to skip
Map<String, Object> skipRequestHeaders = null;
if (configuration.isBridgeEndpoint()) {
String queryString = message.getHeader(Exchange.HTTP_QUERY, String.class);
if (queryString != null) {
skipRequestHeaders = URISupport.parseQuery(queryString, false, true);
}
// Need to remove the Host key as it should be not used
message.getHeaders().remove("host");
}
// 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();
// as then we would duplicate headers on both the endpoint uri, and in HTTP headers as well
if (skipRequestHeaders != null && skipRequestHeaders.containsKey(key)) {
continue;
}
// use an iterator as there can be multiple values. (must not use a delimiter)
final Iterator<?> it = ObjectHelper.createIterator(value, null, true);
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);
request.headers().add(key, headerValue);
}
}
}
Object body = message.getBody();
if (body != null) {
// support bodies as native Netty
ChannelBuffer buffer;
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.getMandatoryBody(byte[].class);
buffer = ChannelBuffers.copiedBuffer(data);
}
}
if (buffer != null) {
request.setContent(buffer);
int len = buffer.readableBytes();
// set content-length
request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, len);
LOG.trace("Content-Length: {}", len);
} else {
// we do not support this kind of body
throw new NoTypeConversionAvailableException(body, ChannelBuffer.class);
}
}
// update HTTP method accordingly as we know if we have a body or not
HttpMethod method = NettyHttpHelper.createMethod(message, body != null);
request.setMethod(method);
// set the content type in the response.
String contentType = MessageHelper.getContentType(message);
if (contentType != null) {
// set content-type
request.headers().set(HttpHeaders.Names.CONTENT_TYPE, contentType);
LOG.trace("Content-Type: {}", contentType);
}
// must include HOST header as required by HTTP 1.1
// use URI as its faster than URL (no DNS lookup)
URI u = new URI(uri);
String hostHeader = u.getHost() + (u.getPort() == 80 ? "" : ":" + u.getPort());
request.headers().set(HttpHeaders.Names.HOST, hostHeader);
LOG.trace("Host: {}", hostHeader);
// configure connection to accordingly to keep alive configuration
// favor using the header from the message
String connection = message.getHeader(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;
}
}
request.headers().set(HttpHeaders.Names.CONNECTION, connection);
LOG.trace("Connection: {}", connection);
return request;
}
use of org.jboss.netty.handler.codec.http.HttpMethod in project camel by apache.
the class NettyHttpHelper method createMethod.
/**
* Creates the {@link HttpMethod} to use to call the remote server, often either its GET or POST.
*
* @param message the Camel message
* @return the created method
*/
public static HttpMethod createMethod(Message message, boolean hasPayload) {
// use header first
HttpMethod m = message.getHeader(Exchange.HTTP_METHOD, HttpMethod.class);
if (m != null) {
return m;
}
String name = message.getHeader(Exchange.HTTP_METHOD, String.class);
if (name != null) {
return HttpMethod.valueOf(name);
}
if (hasPayload) {
// use POST if we have payload
return HttpMethod.POST;
} else {
// fallback to GET
return HttpMethod.GET;
}
}
Aggregations