Skip to content

Commit

Permalink
expose /api/startUpMeasurement
Browse files Browse the repository at this point in the history
Remove compiled version of start-up-visualizer from source code in favour of externally hosted (for now - https://ij-perf.develar.org)
In general, nothing stops us to continue providing because still it is small text only js file, but not clear does it worth it or not.

Migrate from parcel to webpack because:

1. SRI support — https://github.com/waysact/webpack-subresource-integrity (parcel issue: parcel-bundler/parcel#2003)
2. Full typescript support (including type checking) — https://github.com/TypeStrong/ts-loader & https://github.com/Realytics/fork-ts-checker-webpack-plugin (parcel issue: parcel-bundler/parcel#1378)
3. Externals support — https://webpack.js.org/configuration/externals/ (parcel issue: parcel-bundler/parcel#144) There is workaround, but still because of lack type checking for typescript parcel is no-go.

So, parcel is good for very small projects during experimenting but not suitable for any production usage. Yeach, a lot of things in webpack can be simplified without sacrificing user-friendly (so funny bug that documented flag `optimize-minimize` doesn't work if `mode` also specified - and so on), but as no webpack alternatives at the moment, it is ok to write monstrous webpack.config.js
  • Loading branch information
develar committed Feb 25, 2019
1 parent 4eb0150 commit e37dbba
Show file tree
Hide file tree
Showing 22 changed files with 1,980 additions and 3,619 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.builtInWebServer

import com.google.common.cache.CacheBuilder
Expand Down Expand Up @@ -65,35 +65,26 @@ class BuiltInWebServer : HttpRequestHandler() {
override fun isSupported(request: FullHttpRequest): Boolean = super.isSupported(request) || request.method() == HttpMethod.POST

override fun process(urlDecoder: QueryStringDecoder, request: FullHttpRequest, context: ChannelHandlerContext): Boolean {
var host = request.host
if (host.isNullOrEmpty()) {
return false
}

val portIndex = host!!.indexOf(':')
if (portIndex > 0) {
host = host.substring(0, portIndex)
}

var hostName = request.hostName ?: return false
val projectName: String?
val isIpv6 = host[0] == '[' && host.length > 2 && host[host.length - 1] == ']'
val isIpv6 = hostName[0] == '[' && hostName.length > 2 && hostName[hostName.length - 1] == ']'
if (isIpv6) {
host = host.substring(1, host.length - 1)
hostName = hostName.substring(1, hostName.length - 1)
}

if (isIpv6 || InetAddresses.isInetAddress(host) || isOwnHostName(host) || host.endsWith(".ngrok.io")) {
if (isIpv6 || InetAddresses.isInetAddress(hostName) || isOwnHostName(hostName) || hostName.endsWith(".ngrok.io")) {
if (urlDecoder.path().length < 2) {
return false
}

projectName = null
}
else {
if (host.endsWith(".localhost")) {
projectName = host.substring(0, host.lastIndexOf('.'))
if (hostName.endsWith(".localhost")) {
projectName = hostName.substring(0, hostName.lastIndexOf('.'))
}
else {
projectName = host
projectName = hostName
}
}
return doProcess(urlDecoder, request, context, projectName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,19 @@

import com.google.gson.stream.JsonWriter;
import com.intellij.ide.IdeAboutInfoUtil;
import com.intellij.ide.StartUpPerformanceReporter;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.vfs.CharsetToolkit;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.InvocationTargetException;

/**
* @api {get} /about The application info
Expand Down Expand Up @@ -54,11 +48,6 @@ protected String getServiceName() {
return "about";
}

@Override
protected boolean isMethodSupported(@NotNull HttpMethod method) {
return method == HttpMethod.GET;
}

@Nullable
@Override
public String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) throws IOException {
Expand All @@ -68,15 +57,8 @@ public String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpR
return null;
}

@Override
protected boolean isHostTrusted(@NotNull FullHttpRequest request, @NotNull QueryStringDecoder urlDecoder) throws InterruptedException, InvocationTargetException {
return !getBooleanParameter("more", urlDecoder) || super.isHostTrusted(request, urlDecoder);
}

public static void getAbout(@NotNull OutputStream out, @Nullable QueryStringDecoder urlDecoder) throws IOException {
final OutputStreamWriter streamWriter = new OutputStreamWriter(out, CharsetToolkit.UTF8_CHARSET);
JsonWriter writer = new JsonWriter(streamWriter);
writer.setIndent(" ");
JsonWriter writer = createJsonWriter(out);
writer.beginObject();

IdeAboutInfoUtil.writeAboutJson(writer);
Expand Down Expand Up @@ -107,18 +89,7 @@ public static void getAbout(@NotNull OutputStream out, @Nullable QueryStringDeco
writer.name("homePath").value(PathManager.getHomePath());
}

if (urlDecoder != null && getBooleanParameter("startUpMeasurement", urlDecoder)) {
String report = StartupActivity.POST_STARTUP_ACTIVITY.findExtensionOrFail(StartUpPerformanceReporter.class).getLastReport();
if (report != null) {
streamWriter.write(", \"startUpMeasurement\": ");
streamWriter.write(report);
}
streamWriter.write("\n}");
streamWriter.close();
}
else {
writer.endObject();
writer.close();
}
writer.endObject();
writer.close();
}
}
14 changes: 10 additions & 4 deletions platform/built-in-server/src/org/jetbrains/ide/RestService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.ui.AppIcon;
Expand Down Expand Up @@ -51,6 +50,7 @@
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -125,7 +125,9 @@ protected boolean isPrefixlessAllowed() {
@NotNull
protected abstract String getServiceName();

protected abstract boolean isMethodSupported(@NotNull HttpMethod method);
protected boolean isMethodSupported(@NotNull HttpMethod method) {
return method == HttpMethod.GET;
}

@Override
public final boolean process(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) {
Expand Down Expand Up @@ -231,14 +233,14 @@ protected static void activateLastFocusedFrame() {

@NotNull
protected static JsonReader createJsonReader(@NotNull FullHttpRequest request) {
JsonReader reader = new JsonReader(new InputStreamReader(new ByteBufInputStream(request.content()), CharsetToolkit.UTF8_CHARSET));
JsonReader reader = new JsonReader(new InputStreamReader(new ByteBufInputStream(request.content()), StandardCharsets.UTF_8));
reader.setLenient(true);
return reader;
}

@NotNull
protected static JsonWriter createJsonWriter(@NotNull OutputStream out) {
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, CharsetToolkit.UTF8_CHARSET));
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
writer.setIndent(" ");
return writer;
}
Expand Down Expand Up @@ -272,6 +274,10 @@ protected static void sendStatus(@NotNull HttpResponseStatus status, boolean kee

protected static void send(@NotNull BufferExposingByteArrayOutputStream byteOut, @NotNull HttpRequest request, @NotNull ChannelHandlerContext context) {
HttpResponse response = Responses.response("application/json", Unpooled.wrappedBuffer(byteOut.getInternalBuffer(), 0, byteOut.size()));
sendResponse(request, context, response);
}

protected static void sendResponse(@NotNull HttpRequest request, @NotNull ChannelHandlerContext context, @NotNull HttpResponse response) {
Responses.addNoCache(response);
response.headers().set("X-Frame-Options", "Deny");
Responses.send(response, context.channel(), request);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.ide

import com.intellij.ide.StartUpPerformanceReporter
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ex.ApplicationInfoEx
import com.intellij.openapi.startup.StartupActivity
import com.intellij.util.io.hostName
import com.intellij.util.net.NetUtils
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.http.FullHttpRequest
import io.netty.handler.codec.http.HttpRequest
import io.netty.handler.codec.http.QueryStringDecoder
import org.jetbrains.io.response

internal class StartUpMeasurementService : RestService() {
override fun getServiceName() = "startUpMeasurement"

override fun isAccessible(request: HttpRequest): Boolean {
if (super.isAccessible(request)) {
return true
}

// expose externally to use visualizer front-end
// personal data is not exposed (but someone can say that 3rd plugin class names should be not exposed),
// so, limit to dev builds only (EAP builds are not allowed too) or app in an internal mode (and still only for known hosts)
return isTrustedHostName(request) && ApplicationInfoEx.getInstanceEx().build.isSnapshot || ApplicationManager.getApplication().isInternal
}

override fun isHostTrusted(request: FullHttpRequest, urlDecoder: QueryStringDecoder): Boolean {
return isTrustedHostName(request) || super.isHostTrusted(request, urlDecoder)
}

override fun execute(urlDecoder: QueryStringDecoder, request: FullHttpRequest, context: ChannelHandlerContext): String? {
val lastReport = StartupActivity.POST_STARTUP_ACTIVITY.findExtensionOrFail(StartUpPerformanceReporter::class.java).lastReport!!
val response = response("application/json", Unpooled.wrappedBuffer(lastReport))
sendResponse(request, context, response)
return null
}
}

private fun isTrustedHostName(request: HttpRequest): Boolean {
val hostName = request.hostName ?: return false
return hostName == "ij-perf.develar.org" || NetUtils.isLocalhost(hostName)
}
1 change: 0 additions & 1 deletion platform/built-in-server/start-up-visualizer/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
node_modules/
.cache/
dist/
49 changes: 0 additions & 49 deletions platform/built-in-server/start-up-visualizer/amd.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@

<!-- for security reasons official source of scripts is not used - versioned URL must be used -->
<!-- jsdelivr cannot handle amcharts package (>50MB), so, use https://www.srihash.org/ to compute integrity -->
<script src="https://cdn.jsdelivr.net/gh/amcharts/[email protected]/dist/script/core.js" integrity="sha384-PlKsP/oQhuEJevVS1tTQ/cYJBNgqwZqOXgKuPFqvBNkv23cnGg2AFhcuWqiGlYSX" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/amcharts/[email protected]/dist/script/charts.js" integrity="sha384-aly+R8ukAs/wzeo5YvKZznHxXi48TS3WCHBE8YnuVUKGO1ta/+yzwUV5QphoyPxY" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/amcharts/[email protected]/dist/script/themes/animated.js" integrity="sha384-2WR4/PAikFSwy8DTue1g8Cb6Bht0j1T3VoB1WthzSBLIf98n5BHhNHtOmfcPsqvk" crossorigin="anonymous"></script>

<script defer src="amd.js"></script>
<script defer src="out/index.js"></script>
<script src="https://cdn.jsdelivr.net/gh/amcharts/[email protected]/dist/script/core.js" integrity="sha384-PsQiHaSv7tAeZR6KSjTw51TF0NcswEHzG6mqFYN6ncdtAY50NWHwuyjWQK2q7LA/" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/amcharts/[email protected]/dist/script/charts.js" integrity="sha384-bPDXFb1ACdfO04ncNlNWC3q0orsZZ0Sok39fO9ztr/3kt7OuKZyEGnIlb6f3Nr4w" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/amcharts/[email protected]/dist/script/themes/animated.js" integrity="sha384-2WR4/PAikFSwy8DTue1g8Cb6Bht0j1T3VoB1WthzSBLIf98n5BHhNHtOmfcPsqvk" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
Expand Down
40 changes: 0 additions & 40 deletions platform/built-in-server/start-up-visualizer/main.html

This file was deleted.

Loading

0 comments on commit e37dbba

Please sign in to comment.