WEB-21991 New Node.js debug protocol incompatibilities
[idea/community.git] / platform / platform-impl / src / org / jetbrains / io / DelegatingHttpRequestHandler.kt
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.io
17
18 import com.intellij.openapi.application.ex.ApplicationInfoEx
19 import com.intellij.openapi.diagnostic.Logger
20 import com.intellij.openapi.util.IconLoader
21 import com.intellij.util.ui.UIUtil
22 import io.netty.buffer.Unpooled
23 import io.netty.channel.ChannelHandler
24 import io.netty.channel.ChannelHandlerContext
25 import io.netty.handler.codec.http.FullHttpRequest
26 import io.netty.handler.codec.http.QueryStringDecoder
27 import io.netty.util.AttributeKey
28 import org.apache.sanselan.ImageFormat
29 import org.apache.sanselan.Sanselan
30 import org.jetbrains.ide.HttpRequestHandler
31 import java.awt.image.BufferedImage
32
33 private val PREV_HANDLER = AttributeKey.valueOf<HttpRequestHandler>("DelegatingHttpRequestHandler.handler")
34
35 @ChannelHandler.Sharable
36 internal class DelegatingHttpRequestHandler : DelegatingHttpRequestHandlerBase() {
37   override fun process(context: ChannelHandlerContext,
38                        request: FullHttpRequest,
39                        urlDecoder: QueryStringDecoder): Boolean {
40     fun HttpRequestHandler.checkAndProcess(): Boolean {
41       return isSupported(request) && !request.isWriteFromBrowserWithoutOrigin() && isAccessible(request) && process(urlDecoder, request, context)
42     }
43
44     val prevHandlerAttribute = context.channel().attr(PREV_HANDLER)
45     val connectedHandler = prevHandlerAttribute.get()
46     if (connectedHandler != null) {
47       if (connectedHandler.checkAndProcess()) {
48         return true
49       }
50       // prev cached connectedHandler is not suitable for this request, so, let's find it again
51       prevHandlerAttribute.set(null)
52     }
53
54     for (handler in HttpRequestHandler.EP_NAME.extensions) {
55       try {
56         if (handler.checkAndProcess()) {
57           prevHandlerAttribute.set(handler)
58           return true
59         }
60       }
61       catch (e: Throwable) {
62         Logger.getInstance(BuiltInServer::class.java).error(e)
63       }
64     }
65
66     if (urlDecoder.path() == "/favicon.ico") {
67       val icon = IconLoader.findIcon(ApplicationInfoEx.getInstanceEx().smallIconUrl)
68       if (icon != null) {
69         val image = UIUtil.createImage(icon.iconWidth, icon.iconHeight, BufferedImage.TYPE_INT_ARGB)
70         icon.paintIcon(null, image.graphics, 0, 0)
71         val icoBytes = Sanselan.writeImageToBytes(image, ImageFormat.IMAGE_FORMAT_ICO, null)
72         response(FileResponses.getContentType(urlDecoder.path()), Unpooled.wrappedBuffer(icoBytes))
73           .addNoCache()
74           .send(context.channel(), request)
75         return true
76       }
77     }
78
79     return false
80   }
81
82   @Suppress("OverridingDeprecatedMember")
83   override fun exceptionCaught(context: ChannelHandlerContext, cause: Throwable) {
84     try {
85       context.channel().attr(PREV_HANDLER).remove()
86     }
87     finally {
88       @Suppress("DEPRECATION")
89       super.exceptionCaught(context, cause)
90     }
91   }
92 }