summaryrefslogtreecommitdiff
path: root/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java
diff options
context:
space:
mode:
Diffstat (limited to 'xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java')
-rw-r--r--xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java108
1 files changed, 108 insertions, 0 deletions
diff --git a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java
new file mode 100644
index 000000000000..d24078221b30
--- /dev/null
+++ b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java
@@ -0,0 +1,108 @@
+package org.jetbrains.io.fastCgi;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.util.text.StringUtilRt;
+import com.intellij.util.containers.ConcurrentIntObjectMap;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.*;
+import org.jetbrains.io.Responses;
+import org.jetbrains.io.SimpleChannelInboundHandlerAdapter;
+
+import static org.jetbrains.io.fastCgi.FastCgiService.LOG;
+
+@ChannelHandler.Sharable
+public class FastCgiChannelHandler extends SimpleChannelInboundHandlerAdapter<FastCgiResponse> {
+ private final ConcurrentIntObjectMap<Channel> requestToChannel;
+
+ public FastCgiChannelHandler(ConcurrentIntObjectMap<Channel> channel) {
+ requestToChannel = channel;
+ }
+
+ @Override
+ protected void messageReceived(ChannelHandlerContext context, FastCgiResponse response) throws Exception {
+ ByteBuf buffer = response.getData();
+ Channel channel = requestToChannel.remove(response.getId());
+ if (channel == null || !channel.isActive()) {
+ if (buffer != null) {
+ buffer.release();
+ }
+ return;
+ }
+
+ if (buffer == null) {
+ Responses.sendStatus(HttpResponseStatus.BAD_GATEWAY, channel);
+ return;
+ }
+
+ HttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buffer);
+ try {
+ parseHeaders(httpResponse, buffer);
+ Responses.addServer(httpResponse);
+ if (!HttpHeaders.isContentLengthSet(httpResponse)) {
+ HttpHeaders.setContentLength(httpResponse, buffer.readableBytes());
+ }
+ }
+ catch (Throwable e) {
+ buffer.release();
+ Responses.sendStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR, channel);
+ LOG.error(e);
+ }
+ channel.writeAndFlush(httpResponse);
+ }
+
+ private static void parseHeaders(HttpResponse response, ByteBuf buffer) {
+ StringBuilder builder = new StringBuilder();
+ while (buffer.isReadable()) {
+ builder.setLength(0);
+
+ String key = null;
+ boolean valueExpected = true;
+ while (true) {
+ int b = buffer.readByte();
+ if (b < 0 || b == '\n') {
+ break;
+ }
+
+ if (b != '\r') {
+ if (valueExpected && b == ':') {
+ valueExpected = false;
+
+ key = builder.toString();
+ builder.setLength(0);
+ skipWhitespace(buffer);
+ }
+ else {
+ builder.append((char)b);
+ }
+ }
+ }
+
+ if (builder.length() == 0) {
+ // end of headers
+ return;
+ }
+
+ // skip standard headers
+ if (StringUtil.isEmpty(key) || StringUtilRt.startsWithIgnoreCase(key, "http") || StringUtilRt.startsWithIgnoreCase(key, "X-Accel-")) {
+ continue;
+ }
+
+ String value = builder.toString();
+ if (key.equalsIgnoreCase("status")) {
+ response.setStatus(HttpResponseStatus.valueOf(Integer.parseInt(value.substring(0, value.indexOf(' ')))));
+ }
+ else if (!(key.startsWith("http") || key.startsWith("HTTP"))) {
+ response.headers().add(key, value);
+ }
+ }
+ }
+
+ private static void skipWhitespace(ByteBuf buffer) {
+ while (buffer.isReadable() && buffer.getByte(buffer.readerIndex()) == ' ') {
+ buffer.skipBytes(1);
+ }
+ }
+} \ No newline at end of file