/*
* Copyright 2011 Future Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.krakenapps.httpd.impl;
import java.security.SecureRandom;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.ssl.SslHandler;
import org.jboss.netty.handler.stream.ChunkedWriteHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
import org.krakenapps.api.KeyStoreManager;
import org.krakenapps.httpd.HttpConfiguration;
import org.krakenapps.httpd.HttpConfigurationListener;
import org.krakenapps.httpd.HttpContextRegistry;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpPipelineFactory implements ChannelPipelineFactory, HttpConfigurationListener {
private final Logger logger = LoggerFactory.getLogger(HttpPipelineFactory.class.getName());
private BundleContext bc;
private HttpConfiguration config;
private HttpContextRegistry contextRegistry;
private KeyStoreManager keyStoreManager;
private Timer timer;
private IdleStateHandler idleStateHandler;
public HttpPipelineFactory(BundleContext bc, HttpConfiguration config, HttpContextRegistry contextRegistry,
KeyStoreManager keyStoreManager) {
this.bc = bc;
this.config = config;
this.contextRegistry = contextRegistry;
this.keyStoreManager = keyStoreManager;
this.timer = new HashedWheelTimer();
this.idleStateHandler = new IdleStateHandler(timer, 0, 0, config.getIdleTimeout());
config.getListeners().add(this);
}
@Override
public void onSet(String fieldName, Object value) {
if (fieldName.equals("idleTimeout")) {
logger.debug("kraken httpd: http config field [{}] changed to [{}]", fieldName, value);
this.idleStateHandler = new IdleStateHandler(timer, 0, 0, config.getIdleTimeout());
}
}
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline(idleStateHandler);
SSLContext sslContext = newSslContext(config.getKeyAlias(), config.getTrustAlias());
if (config.isSsl()) {
SSLEngine engine = sslContext.createSSLEngine();
engine.setUseClientMode(false);
pipeline.addLast("ssl", new SslHandler(engine));
}
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(config.getMaxContentLength()));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
pipeline.addLast("handler", new HttpServerHandler(bc, config, contextRegistry));
return pipeline;
}
private SSLContext newSslContext(String keyAlias, String trustAlias) {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManager[] trustManagers = null;
KeyManager[] keyManagers = null;
TrustManagerFactory tmf = keyStoreManager.getTrustManagerFactory(trustAlias, "SunX509");
KeyManagerFactory kmf = keyStoreManager.getKeyManagerFactory(keyAlias, "SunX509");
if (tmf != null)
trustManagers = tmf.getTrustManagers();
if (kmf != null)
keyManagers = kmf.getKeyManagers();
sslContext.init(keyManagers, trustManagers, new SecureRandom());
return sslContext;
} catch (Exception e) {
throw new RuntimeException("cannot create ssl context", e);
}
}
}