/* * Copyright 2000-2013 JetBrains s.r.o. * * 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.jetbrains.io; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; import com.intellij.openapi.util.text.StringUtil; import consulo.application.impl.FrameTitleUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; import org.jetbrains.annotations.Nullable; import java.nio.CharBuffer; import java.util.Calendar; import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; /** * from kotlin platform\platform-impl\src\org\jetbrains\io\Responses.kt */ public final class Responses { private static String SERVER_HEADER_VALUE; private static String getServerHeaderValue() { if (SERVER_HEADER_VALUE == null) { Application app = ApplicationManager.getApplication(); if (app != null && !app.isDisposed()) { SERVER_HEADER_VALUE = ApplicationInfoEx.getInstanceEx().getFullApplicationName(); } } return SERVER_HEADER_VALUE; } public static void setDate(HttpResponse response) { if (!response.headers().contains(HttpHeaderNames.DATE)) { response.headers().set(HttpHeaderNames.DATE, Calendar.getInstance().getTime()); } } public static void addServer(HttpResponse response) { if (SERVER_HEADER_VALUE == null) { Application app = ApplicationManager.getApplication(); if (app != null && !app.isDisposed()) { SERVER_HEADER_VALUE = FrameTitleUtil.buildTitle(); } } if (SERVER_HEADER_VALUE != null) { response.headers().set("Server", SERVER_HEADER_VALUE); } } public static void send(HttpResponseStatus status, Channel channel, HttpRequest request, String description) { send(status, channel, request, description, null); } public static void send(HttpResponseStatus status, Channel channel, String description) { send(status, channel, null, description, null); } public static void send(HttpResponseStatus status, Channel channel, HttpRequest request) { send(status, channel, request, null, null); } public static void send(HttpResponseStatus status, Channel channel, @Nullable HttpRequest request, @Nullable String description, @Nullable HttpHeaders extraHeaders) { HttpResponse response = createStatusResponse(status, request, description); send(response, channel, request, extraHeaders); } private static HttpResponse createStatusResponse(HttpResponseStatus responseStatus, HttpRequest request, String description) { if (request != null && request.method() == HttpMethod.HEAD) { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseStatus, Unpooled.EMPTY_BUFFER); } StringBuilder builder = new StringBuilder(); String message = responseStatus.toString(); builder.append("<!doctype html><title>").append(message).append("</title>").append("<h1 style=\"text-align: center\">").append(message).append("</h1>"); if (description != null) { builder.append("<p>").append(description).append("</p>"); } builder.append("<hr/><p style=\"text-align: center\">").append(StringUtil.notNullize(getServerHeaderValue())).append("</p>"); DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseStatus, ByteBufUtil .encodeString(ByteBufAllocator.DEFAULT, CharBuffer.wrap(builder), CharsetUtil.UTF_8)); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html"); return response; } public static void send(HttpResponse response, Channel channel, HttpRequest request) { send(response, channel, request, null); } public static void send(HttpResponse response, Channel channel, HttpRequest request, HttpHeaders extraHeaders) { if (response.status() != HttpResponseStatus.NOT_MODIFIED && !HttpUtil.isContentLengthSet(response)) { long toLong = (response instanceof FullHttpResponse) ? ((FullHttpResponse)response).content().readableBytes() : 0; HttpUtil.setContentLength(response, toLong); } addCommonHeaders(response); if (extraHeaders != null) { response.headers().add(extraHeaders); } send(response, channel, request != null && !addKeepAliveIfNeed(response, request)); } static void send(HttpResponse response, Channel channel, boolean close) { if (!channel.isActive()) { return; } ChannelFuture future = channel.write(response); if (!(response instanceof FullHttpResponse)) { channel.write(LastHttpContent.EMPTY_LAST_CONTENT); } channel.flush(); if (close) { future.addListener(ChannelFutureListener.CLOSE); } } private static boolean addKeepAliveIfNeed(HttpResponse response, HttpRequest request) { if (HttpUtil.isKeepAlive(request)) { HttpUtil.setKeepAlive(response, true); return true; } return false; } public static FullHttpResponse response(String contentType, ByteBuf content) { FullHttpResponse response = null; if (content == null) { response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); } else { response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); } if (contentType != null) { response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType); } return response; } public static HttpResponse addNoCache(HttpResponse response) { response.headers().add(HttpHeaderNames.CACHE_CONTROL, "no-cache, no-store, must-revalidate, max-age=0"); response.headers().add(HttpHeaderNames.PRAGMA, "no-cache"); return response; } public static FullHttpResponse create(String contentType) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK); response.headers().set(CONTENT_TYPE, contentType); return response; } private static void addCommonHeaders(HttpResponse response) { addServer(response); setDate(response); if (!response.headers().contains("X-Frame-Options")) { response.headers().set("X-Frame-Options", "SameOrigin"); } response.headers().set("x-xss-protection", "1; mode=block"); response.headers().set("X-Content-Type-Options", "nosniff"); } }