public class BuiltInWebBrowserUrlProvider extends WebBrowserUrlProvider implements DumbAware {
@NotNull
public static List<Url> getUrls(@NotNull VirtualFile file, @NotNull Project project, @Nullable String currentAuthority) {
+ return getUrls(file, project, currentAuthority, true);
+ }
+
+ @NotNull
+ public static List<Url> getUrls(@NotNull VirtualFile file, @NotNull Project project, @Nullable String currentAuthority, boolean appendAccessToken) {
if (currentAuthority != null && !compareAuthority(currentAuthority)) {
return Collections.emptyList();
}
String path = info.getPath();
String authority = currentAuthority == null ? "localhost:" + effectiveBuiltInServerPort : currentAuthority;
- String query = "?" + BuiltInWebServerKt.TOKEN_PARAM_NAME + "=" + BuiltInWebServerKt.acquireToken();
+ String query = appendAccessToken ? "?" + BuiltInWebServerKt.TOKEN_PARAM_NAME + "=" + BuiltInWebServerKt.acquireToken() : "";
List<Url> urls = new SmartList<>(Urls.newHttpUrl(authority, '/' + project.getName() + '/' + path, query));
String path2 = info.getRootLessPathIfPossible();
return Urls.newFromVirtualFile(file);
}
else {
- return ContainerUtil.getFirstItem(getUrls(file, request.getProject(), null));
+ return ContainerUtil.getFirstItem(getUrls(file, request.getProject(), null, request.isAppendAccessToken()));
}
}
}
internal fun isActivatable() = Registry.`is`("ide.built.in.web.server.activatable", false)
internal const val TOKEN_PARAM_NAME = "_ijt"
+const val TOKEN_HEADER_NAME = "x-ijt"
private val STANDARD_COOKIE by lazy {
val productName = ApplicationNamesInfo.getInstance().lowercaseProductName
// expire after access because we reuse tokens
private val tokens = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.MINUTES).build<String, Boolean>()
-internal fun acquireToken(): String {
+fun acquireToken(): String {
var token = tokens.asMap().keys.firstOrNull()
if (token == null) {
token = TokenGenerator.generate()
val urlDecoder = QueryStringDecoder(request.uri())
// we must check referrer - if html cached, browser will send request without query
- val token = urlDecoder.parameters().get(TOKEN_PARAM_NAME)?.firstOrNull() ?: request.referrer?.let { QueryStringDecoder(it).parameters().get(TOKEN_PARAM_NAME)?.firstOrNull() }
+ val token = request.headers().get(TOKEN_HEADER_NAME)
+ ?: urlDecoder.parameters().get(TOKEN_PARAM_NAME)?.firstOrNull()
+ ?: request.referrer?.let { QueryStringDecoder(it).parameters().get(TOKEN_PARAM_NAME)?.firstOrNull() }
val url = "${channel.uriScheme}://${request.host!!}${urlDecoder.path()}"
if (token != null && tokens.getIfPresent(token) != null) {
tokens.invalidate(token)
internal abstract class DelegatingHttpRequestHandlerBase : SimpleChannelInboundHandlerAdapter<FullHttpRequest>() {
override fun messageReceived(context: ChannelHandlerContext, message: FullHttpRequest) {
- Logger.getInstance(BuiltInServer::class.java).debug { "IN HTTP: $message" }
+ Logger.getInstance(BuiltInServer::class.java).debug { "\n\nIN HTTP: $message\n\n" }
if (!process(context, message, QueryStringDecoder(message.uri()))) {
HttpResponseStatus.NOT_FOUND.send(context.channel(), message)
/*
- * Copyright 2000-2015 JetBrains s.r.o.
+ * Copyright 2000-2016 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.
public static Collection<Url> getDebuggableUrls(@Nullable PsiElement context) {
try {
OpenInBrowserRequest request = context == null ? null : OpenInBrowserRequest.create(context);
- return request == null || request.getFile().getViewProvider().getBaseLanguage() == XMLLanguage.INSTANCE ? Collections.<Url>emptyList() : getUrls(getProvider(request), request);
+ if (request == null || request.getFile().getViewProvider().getBaseLanguage() == XMLLanguage.INSTANCE) {
+ return Collections.<Url>emptyList();
+ }
+ else {
+ // it is client responsibility to set token
+ request.setAppendAccessToken(false);
+ return getUrls(getProvider(request), request);
+ }
}
catch (WebBrowserUrlProvider.BrowserException ignored) {
return Collections.emptyList();
+/*
+ * Copyright 2000-2016 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 com.intellij.ide.browsers;
import com.intellij.openapi.application.AccessToken;
public abstract class OpenInBrowserRequest {
private Collection<Url> result;
protected PsiFile file;
+
+ private boolean appendAccessToken = true;
public OpenInBrowserRequest(@NotNull PsiFile file) {
this.file = file;
public Collection<Url> getResult() {
return result;
}
+
+ public boolean isAppendAccessToken() {
+ return appendAccessToken;
+ }
+
+ public void setAppendAccessToken(boolean value) {
+ this.appendAccessToken = value;
+ }
}
\ No newline at end of file