diff --git a/platform/built-in-server-api/src/org/jetbrains/builtInWebServer/PathInfo.kt b/platform/built-in-server-api/src/org/jetbrains/builtInWebServer/PathInfo.kt index b5a96720afa9..f5aad5b6f632 100644 --- a/platform/built-in-server-api/src/org/jetbrains/builtInWebServer/PathInfo.kt +++ b/platform/built-in-server-api/src/org/jetbrains/builtInWebServer/PathInfo.kt @@ -6,8 +6,10 @@ import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile import java.io.File +import java.nio.file.Files +import java.nio.file.Path -class PathInfo(val ioFile: File?, val file: VirtualFile?, val root: VirtualFile, moduleName: String? = null, val isLibrary: Boolean = false, val isRootNameOptionalInPath: Boolean = false) { +class PathInfo(val ioFile: Path?, val file: VirtualFile?, val root: VirtualFile, moduleName: String? = null, val isLibrary: Boolean = false, val isRootNameOptionalInPath: Boolean = false) { var moduleName: String? = moduleName set @@ -34,7 +36,7 @@ class PathInfo(val ioFile: File?, val file: VirtualFile?, val root: VirtualFile, val relativeTo = if (useRootName) root else root.parent ?: root if (file == null) { - builder.append(FileUtilRt.getRelativePath(relativeTo.path, FileUtilRt.toSystemIndependentName(ioFile!!.path), '/')) + builder.append(FileUtilRt.getRelativePath(relativeTo.path, ioFile!!.toString().replace(File.separatorChar, '/'), '/')) } else { builder.append(VfsUtilCore.getRelativePath(file, relativeTo, '/')) @@ -45,17 +47,17 @@ class PathInfo(val ioFile: File?, val file: VirtualFile?, val root: VirtualFile, /** * System-dependent path to file. */ - val filePath: String by lazy { if (ioFile == null) FileUtilRt.toSystemDependentName(file!!.path) else ioFile.path } + val filePath: String by lazy { if (ioFile == null) FileUtilRt.toSystemDependentName(file!!.path) else ioFile.toString() } val isValid: Boolean - get() = if (ioFile == null) file!!.isValid else ioFile.exists() + get() = if (ioFile == null) file!!.isValid else Files.exists(ioFile) val name: String - get() = if (ioFile == null) file!!.name else ioFile.name + get() = if (ioFile == null) file!!.name else ioFile.fileName.toString() val fileType: FileType - get() = if (ioFile == null) file!!.fileType else FileTypeManager.getInstance().getFileTypeByFileName(ioFile.name) + get() = if (ioFile == null) file!!.fileType else FileTypeManager.getInstance().getFileTypeByFileName(ioFile.fileName.toString()) - fun isDirectory(): Boolean = if (ioFile == null) file!!.isDirectory else ioFile.isDirectory + fun isDirectory(): Boolean = if (ioFile == null) file!!.isDirectory else Files.isDirectory(ioFile) } \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt index 8e23e6069150..212c68468bc8 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInWebServer.kt @@ -25,7 +25,9 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.endsWithName import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.UriUtil +import com.intellij.util.directoryStreamIfExists import com.intellij.util.io.URLUtil +import com.intellij.util.isDirectory import com.intellij.util.net.NetUtils import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.FullHttpRequest @@ -33,9 +35,9 @@ import io.netty.handler.codec.http.HttpMethod import io.netty.handler.codec.http.QueryStringDecoder import org.jetbrains.ide.HttpRequestHandler import org.jetbrains.io.host -import java.io.File import java.net.InetAddress import java.net.UnknownHostException +import java.nio.file.Path internal val LOG = Logger.getInstance(BuiltInWebServer::class.java) @@ -177,18 +179,18 @@ fun findIndexFile(basedir: VirtualFile): VirtualFile? { return null } -fun findIndexFile(basedir: File): File? { - val children = basedir.listFiles { dir, name -> name.startsWith("index.") || name.startsWith("default.") } - if (children == null || children.isEmpty()) { - return null - } +fun findIndexFile(basedir: Path): Path? { + val children = basedir.directoryStreamIfExists({ + val name = it.fileName.toString() + name.startsWith("index.") || name.startsWith("default.") + }) { it.toList() } ?: return null for (indexNamePrefix in arrayOf("index.", "default.")) { - var index: File? = null + var index: Path? = null val preferredName = "${indexNamePrefix}html" for (child in children) { - if (!child.isDirectory) { - val name = child.name + if (!child.isDirectory()) { + val name = child.fileName.toString() if (name == preferredName) { return child } diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt index a5bd7c8e9784..377716b829f9 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt @@ -26,7 +26,7 @@ import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.FullHttpRequest import io.netty.handler.codec.http.HttpResponseStatus import org.jetbrains.io.Responses -import java.io.File +import java.nio.file.Path private class DefaultWebServerPathHandler : WebServerPathHandler() { override fun process(path: String, @@ -62,7 +62,7 @@ private class DefaultWebServerPathHandler : WebServerPathHandler() { } var indexVirtualFile: VirtualFile? = null - var indexFile: File? = null + var indexFile: Path? = null if (pathInfo.file == null) { indexFile = findIndexFile(pathInfo.ioFile!!) } diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/StaticFileHandler.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/StaticFileHandler.kt index a3c7eb1cd403..cbb6a01ac2a5 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/StaticFileHandler.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/StaticFileHandler.kt @@ -3,6 +3,7 @@ package org.jetbrains.builtInWebServer import com.intellij.openapi.project.Project import com.intellij.openapi.util.text.StringUtilRt import com.intellij.util.PathUtilRt +import com.intellij.util.isDirectory import io.netty.buffer.ByteBufUtf8Writer import io.netty.channel.Channel import io.netty.channel.ChannelFutureListener @@ -12,14 +13,16 @@ import org.jetbrains.builtInWebServer.ssi.SsiExternalResolver import org.jetbrains.builtInWebServer.ssi.SsiProcessor import org.jetbrains.io.FileResponses import org.jetbrains.io.Responses -import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths private class StaticFileHandler : WebServerFileHandler() { private var ssiProcessor: SsiProcessor? = null override fun process(pathInfo: PathInfo, canonicalPath: CharSequence, project: Project, request: FullHttpRequest, channel: Channel, projectNameIfNotCustomHost: String?): Boolean { if (pathInfo.ioFile != null || pathInfo.file!!.isInLocalFileSystem) { - val ioFile = pathInfo.ioFile ?: File(pathInfo.file!!.path) + val ioFile = pathInfo.ioFile ?: Paths.get(pathInfo.file!!.path) val nameSequence = pathInfo.name //noinspection SpellCheckingInspection @@ -32,7 +35,7 @@ private class StaticFileHandler : WebServerFileHandler() { } else { val file = pathInfo.file!! - val response = FileResponses.prepareSend(request, channel, file.timeStamp, file.path) ?: return true + val response = FileResponses.prepareSend(request, channel, file.timeStamp, file.name) ?: return true val keepAlive = Responses.addKeepAliveIfNeed(response, request) if (request.method() != HttpMethod.HEAD) { @@ -54,7 +57,7 @@ private class StaticFileHandler : WebServerFileHandler() { return true } - private fun processSsi(file: File, path: String, project: Project, request: FullHttpRequest, channel: Channel) { + private fun processSsi(file: Path, path: String, project: Project, request: FullHttpRequest, channel: Channel) { if (ssiProcessor == null) { ssiProcessor = SsiProcessor(false) } @@ -63,8 +66,8 @@ private class StaticFileHandler : WebServerFileHandler() { val keepAlive: Boolean var releaseBuffer = true try { - val lastModified = ssiProcessor!!.process(SsiExternalResolver(project, request, path, file.parentFile), file, ByteBufUtf8Writer(buffer)) - val response = FileResponses.prepareSend(request, channel, lastModified, file.path) ?: return + val lastModified = ssiProcessor!!.process(SsiExternalResolver(project, request, path, file.parent), file, ByteBufUtf8Writer(buffer)) + val response = FileResponses.prepareSend(request, channel, lastModified, file.fileName.toString()) ?: return keepAlive = Responses.addKeepAliveIfNeed(response, request) if (request.method() != HttpMethod.HEAD) { HttpUtil.setContentLength(response, buffer.readableBytes().toLong()) @@ -90,7 +93,7 @@ private class StaticFileHandler : WebServerFileHandler() { } } -fun sendIoFile(channel: Channel, ioFile: File, request: HttpRequest) { +fun sendIoFile(channel: Channel, ioFile: Path, request: HttpRequest) { if (hasAccess(ioFile)) { FileResponses.sendFile(request, channel, ioFile) } @@ -100,4 +103,4 @@ fun sendIoFile(channel: Channel, ioFile: File, request: HttpRequest) { } // deny access to .htaccess files -private fun hasAccess(result: File) = !result.isDirectory && result.canRead() && !(result.isHidden || result.name.startsWith(".ht")) \ No newline at end of file +private fun hasAccess(result: Path) = !result.isDirectory() && Files.isReadable(result) && !(Files.isHidden(result) || result.fileName.toString().startsWith(".ht")) \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathToFileManager.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathToFileManager.kt index 6635066d6682..338fe1a180da 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathToFileManager.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathToFileManager.kt @@ -14,7 +14,9 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent import com.intellij.openapi.vfs.newvfs.events.VFileEvent import com.intellij.util.containers.computeOrNull -import java.io.File +import com.intellij.util.exists +import com.intellij.util.systemIndependentPath +import java.nio.file.Paths import java.util.concurrent.TimeUnit /** @@ -63,7 +65,7 @@ class WebServerPathToFileManager(application: Application, private val project: @JvmOverloads fun findVirtualFile(path: String, cacheResult: Boolean = true): VirtualFile? { val pathInfo = getPathInfo(path, cacheResult) ?: return null - return pathInfo.file ?: LocalFileSystem.getInstance().findFileByIoFile(pathInfo.ioFile!!) + return pathInfo.file ?: LocalFileSystem.getInstance().findFileByPath(pathInfo.ioFile!!.systemIndependentPath) } @JvmOverloads fun getPathInfo(path: String, cacheResult: Boolean = true): PathInfo? { @@ -110,7 +112,7 @@ private val RELATIVE_PATH_RESOLVER = object : FileResolver { // WEB-17691 built-in server doesn't serve files it doesn't have in the project tree // temp:// reports isInLocalFileSystem == true, but it is not true if (root.isInLocalFileSystem && root.fileSystem == LocalFileSystem.getInstance()) { - val file = File(root.path, path) + val file = Paths.get(root.path, path) if (file.exists()) { return PathInfo(file, null, root, moduleName, isLibrary) } diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/ssi/SsiProcessor.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/ssi/SsiProcessor.kt index 717597292685..1175af6021a9 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/ssi/SsiProcessor.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/ssi/SsiProcessor.kt @@ -16,14 +16,12 @@ package org.jetbrains.builtInWebServer.ssi import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.util.io.FileUtilRt -import com.intellij.util.SmartList +import com.intellij.util.* import com.intellij.util.text.CharArrayUtil import gnu.trove.THashMap import io.netty.buffer.ByteBufUtf8Writer -import java.io.File -import java.io.FileInputStream import java.io.IOException +import java.nio.file.Path import java.util.* internal val LOG = Logger.getInstance(SsiProcessor::class.java) @@ -37,184 +35,168 @@ class SsiProcessor(allowExec: Boolean) { private val commands: MutableMap = THashMap() init { - commands.put("config", object : SsiCommand { - override fun process(state: SsiProcessingState, commandName: String, paramNames: List, paramValues: Array, writer: ByteBufUtf8Writer): Long { - for (i in paramNames.indices) { - val paramName = paramNames[i] - val paramValue = paramValues[i] - val substitutedValue = state.substituteVariables(paramValue) - if (paramName.equals("errmsg", ignoreCase = true)) { - state.configErrorMessage = substitutedValue - } - else if (paramName.equals("sizefmt", ignoreCase = true)) { - state.configSizeFmt = substitutedValue - } - else if (paramName.equals("timefmt", ignoreCase = true)) { - state.setConfigTimeFormat(substitutedValue, false) - } - else { - LOG.info("#config--Invalid attribute: " + paramName) - // We need to fetch this value each time, since it may change during the loop - writer.write(state.configErrorMessage) - } + commands.put("config", SsiCommand { state, commandName, paramNames, paramValues, writer -> + for (i in paramNames.indices) { + val paramName = paramNames[i] + val paramValue = paramValues[i] + val substitutedValue = state.substituteVariables(paramValue) + if (paramName.equals("errmsg", ignoreCase = true)) { + state.configErrorMessage = substitutedValue + } + else if (paramName.equals("sizefmt", ignoreCase = true)) { + state.configSizeFmt = substitutedValue + } + else if (paramName.equals("timefmt", ignoreCase = true)) { + state.setConfigTimeFormat(substitutedValue, false) + } + else { + LOG.info("#config--Invalid attribute: " + paramName) + // We need to fetch this value each time, since it may change during the loop + writer.write(state.configErrorMessage) } - return 0 } + 0 }) - commands.put("echo", object : SsiCommand { - override fun process(state: SsiProcessingState, commandName: String, paramNames: List, paramValues: Array, writer: ByteBufUtf8Writer): Long { - var encoding = "entity" - var originalValue: String? = null - val errorMessage = state.configErrorMessage - for (i in paramNames.indices) { - val paramName = paramNames[i] - val paramValue = paramValues[i] - if (paramName.equals("var", ignoreCase = true)) { - originalValue = paramValue - } - else if (paramName.equals("encoding", ignoreCase = true)) { - if (paramValue.equals("url", ignoreCase = true) || paramValue.equals("entity", ignoreCase = true) || paramValue.equals("none", ignoreCase = true)) { - encoding = paramValue - } - else { - LOG.info("#echo--Invalid encoding: " + paramValue) - writer.write(errorMessage) - } + commands.put("echo", SsiCommand { state, commandName, paramNames, paramValues, writer -> + var encoding = "entity" + var originalValue: String? = null + val errorMessage = state.configErrorMessage + for (i in paramNames.indices) { + val paramName = paramNames[i] + val paramValue = paramValues[i] + if (paramName.equals("var", ignoreCase = true)) { + originalValue = paramValue + } + else if (paramName.equals("encoding", ignoreCase = true)) { + if (paramValue.equals("url", ignoreCase = true) || paramValue.equals("entity", ignoreCase = true) || paramValue.equals("none", ignoreCase = true)) { + encoding = paramValue } else { - LOG.info("#echo--Invalid attribute: " + paramName) + LOG.info("#echo--Invalid encoding: " + paramValue) writer.write(errorMessage) } } - val variableValue = state.getVariableValue(originalValue!!, encoding) - writer.write(variableValue ?: "(none)") - return System.currentTimeMillis() + else { + LOG.info("#echo--Invalid attribute: " + paramName) + writer.write(errorMessage) + } } + val variableValue = state.getVariableValue(originalValue!!, encoding) + writer.write(variableValue ?: "(none)") + System.currentTimeMillis() }) //noinspection StatementWithEmptyBody if (allowExec) { // commands.put("exec", new SsiExec()); } - commands.put("include", object : SsiCommand { - override fun process(state: SsiProcessingState, commandName: String, paramNames: List, paramValues: Array, writer: ByteBufUtf8Writer): Long { - var lastModified: Long = 0 - val configErrorMessage = state.configErrorMessage - for (i in paramNames.indices) { - val paramName = paramNames[i] - if (paramName.equals("file", ignoreCase = true) || paramName.equals("virtual", ignoreCase = true)) { - val substitutedValue = state.substituteVariables(paramValues[i]) - try { - val virtual = paramName.equals("virtual", ignoreCase = true) - lastModified = state.ssiExternalResolver.getFileLastModified(substitutedValue, virtual) - val file = state.ssiExternalResolver.findFile(substitutedValue, virtual) - if (file == null) { - LOG.warn("#include-- Couldn't find file: " + substitutedValue) - return 0 - } - - val `in` = FileInputStream(file) - try { - writer.write(`in`, file.length().toInt()) - } - finally { - `in`.close() - } - } - catch (e: IOException) { - LOG.warn("#include--Couldn't include file: " + substitutedValue, e) - writer.write(configErrorMessage) - } - - } - else { - LOG.info("#include--Invalid attribute: " + paramName) - writer.write(configErrorMessage) - } - } - return lastModified - } - }) - commands.put("flastmod", object : SsiCommand { - override fun process(state: SsiProcessingState, commandName: String, paramNames: List, paramValues: Array, writer: ByteBufUtf8Writer): Long { - var lastModified: Long = 0 - val configErrMsg = state.configErrorMessage - for (i in paramNames.indices) { - val paramName = paramNames[i] - val paramValue = paramValues[i] - val substitutedValue = state.substituteVariables(paramValue) - if (paramName.equals("file", ignoreCase = true) || paramName.equals("virtual", ignoreCase = true)) { + commands.put("include", SsiCommand { state, commandName, paramNames, paramValues, writer -> + var lastModified: Long = 0 + val configErrorMessage = state.configErrorMessage + for (i in paramNames.indices) { + val paramName = paramNames[i] + if (paramName.equals("file", ignoreCase = true) || paramName.equals("virtual", ignoreCase = true)) { + val substitutedValue = state.substituteVariables(paramValues[i]) + try { val virtual = paramName.equals("virtual", ignoreCase = true) lastModified = state.ssiExternalResolver.getFileLastModified(substitutedValue, virtual) - val strftime = Strftime(state.configTimeFmt, Locale.US) - writer.write(strftime.format(Date(lastModified))) - } - else { - LOG.info("#flastmod--Invalid attribute: " + paramName) - writer.write(configErrMsg) - } - } - return lastModified - } - }) - commands.put("fsize", SsiFsize()) - commands.put("printenv", object : SsiCommand { - override fun process(state: SsiProcessingState, commandName: String, paramNames: List, paramValues: Array, writer: ByteBufUtf8Writer): Long { - var lastModified: Long = 0 - // any arguments should produce an error - if (paramNames.isEmpty()) { - val variableNames = LinkedHashSet() - //These built-in variables are supplied by the mediator ( if not over-written by the user ) and always exist - variableNames.add("DATE_GMT") - variableNames.add("DATE_LOCAL") - variableNames.add("LAST_MODIFIED") - state.ssiExternalResolver.addVariableNames(variableNames) - for (variableName in variableNames) { - var variableValue: String? = state.getVariableValue(variableName) - // This shouldn't happen, since all the variable names must have values - if (variableValue == null) { - variableValue = "(none)" + val file = state.ssiExternalResolver.findFile(substitutedValue, virtual) + if (file == null) { + LOG.warn("#include-- Couldn't find file: " + substitutedValue) + return@SsiCommand 0 + } + + file.inputStream().use { + writer.write(it, file.size().toInt()) } - writer.append(variableName).append('=').append(variableValue).append('\n') - lastModified = System.currentTimeMillis() } + catch (e: IOException) { + LOG.warn("#include--Couldn't include file: " + substitutedValue, e) + writer.write(configErrorMessage) + } + } else { - writer.write(state.configErrorMessage) + LOG.info("#include--Invalid attribute: " + paramName) + writer.write(configErrorMessage) } - return lastModified } + lastModified }) - commands.put("set", object : SsiCommand { - override fun process(state: SsiProcessingState, commandName: String, paramNames: List, paramValues: Array, writer: ByteBufUtf8Writer): Long { - var lastModified: Long = 0 - val errorMessage = state.configErrorMessage - var variableName: String? = null - for (i in paramNames.indices) { - val paramName = paramNames[i] - val paramValue = paramValues[i] - if (paramName.equals("var", ignoreCase = true)) { - variableName = paramValue + commands.put("flastmod", SsiCommand { state, commandName, paramNames, paramValues, writer -> + var lastModified: Long = 0 + val configErrMsg = state.configErrorMessage + for (i in paramNames.indices) { + val paramName = paramNames[i] + val paramValue = paramValues[i] + val substitutedValue = state.substituteVariables(paramValue) + if (paramName.equals("file", ignoreCase = true) || paramName.equals("virtual", ignoreCase = true)) { + val virtual = paramName.equals("virtual", ignoreCase = true) + lastModified = state.ssiExternalResolver.getFileLastModified(substitutedValue, virtual) + val strftime = Strftime(state.configTimeFmt, Locale.US) + writer.write(strftime.format(Date(lastModified))) + } + else { + LOG.info("#flastmod--Invalid attribute: " + paramName) + writer.write(configErrMsg) + } + } + lastModified + }) + commands.put("fsize", SsiFsize()) + commands.put("printenv", SsiCommand { state, commandName, paramNames, paramValues, writer -> + var lastModified: Long = 0 + // any arguments should produce an error + if (paramNames.isEmpty()) { + val variableNames = LinkedHashSet() + //These built-in variables are supplied by the mediator ( if not over-written by the user ) and always exist + variableNames.add("DATE_GMT") + variableNames.add("DATE_LOCAL") + variableNames.add("LAST_MODIFIED") + state.ssiExternalResolver.addVariableNames(variableNames) + for (variableName in variableNames) { + var variableValue: String? = state.getVariableValue(variableName) + // This shouldn't happen, since all the variable names must have values + if (variableValue == null) { + variableValue = "(none)" } - else if (paramName.equals("value", ignoreCase = true)) { - if (variableName != null) { - val substitutedValue = state.substituteVariables(paramValue) - state.ssiExternalResolver.setVariableValue(variableName, substitutedValue) - lastModified = System.currentTimeMillis() - } - else { - LOG.info("#set--no variable specified") - writer.write(errorMessage) - throw SsiStopProcessingException() - } + writer.append(variableName).append('=').append(variableValue).append('\n') + lastModified = System.currentTimeMillis() + } + } + else { + writer.write(state.configErrorMessage) + } + lastModified + }) + commands.put("set", SsiCommand { state, commandName, paramNames, paramValues, writer -> + var lastModified: Long = 0 + val errorMessage = state.configErrorMessage + var variableName: String? = null + for (i in paramNames.indices) { + val paramName = paramNames[i] + val paramValue = paramValues[i] + if (paramName.equals("var", ignoreCase = true)) { + variableName = paramValue + } + else if (paramName.equals("value", ignoreCase = true)) { + if (variableName != null) { + val substitutedValue = state.substituteVariables(paramValue) + state.ssiExternalResolver.setVariableValue(variableName, substitutedValue) + lastModified = System.currentTimeMillis() } else { - LOG.info("#set--Invalid attribute: " + paramName) + LOG.info("#set--no variable specified") writer.write(errorMessage) throw SsiStopProcessingException() } } - return lastModified + else { + LOG.info("#set--Invalid attribute: " + paramName) + writer.write(errorMessage) + throw SsiStopProcessingException() + } } + lastModified }) val ssiConditional = SsiConditional() @@ -227,16 +209,16 @@ class SsiProcessor(allowExec: Boolean) { /** * @return the most current modified date resulting from any SSI commands */ - fun process(ssiExternalResolver: SsiExternalResolver, file: File, writer: ByteBufUtf8Writer): Long { - val fileContents = FileUtilRt.loadFileText(file) - var lastModifiedDate = file.lastModified() + fun process(ssiExternalResolver: SsiExternalResolver, file: Path, writer: ByteBufUtf8Writer): Long { + val fileContents = file.readChars() + var lastModifiedDate = file.lastModified().toMillis() val ssiProcessingState = SsiProcessingState(ssiExternalResolver, lastModifiedDate) var index = 0 var inside = false val command = StringBuilder() - writer.ensureWritable(file.length().toInt()) + writer.ensureWritable(file.size().toInt()) try { - while (index < fileContents.size) { + while (index < fileContents.length) { val c = fileContents[index] if (inside) { if (c == COMMAND_END[0] && charCmp(fileContents, index, COMMAND_END)) { @@ -426,7 +408,7 @@ class SsiProcessor(allowExec: Boolean) { return if (firstLetter == -1) "" else instruction.substring(firstLetter, lastLetter + 1) } - protected fun charCmp(buf: CharArray, index: Int, command: String) = CharArrayUtil.regionMatches(buf, index, index + command.length, command) + protected fun charCmp(buf: CharSequence, index: Int, command: String) = CharArrayUtil.regionMatches(buf, index, index + command.length, command) protected fun isSpace(c: Char) = c == ' ' || c == '\n' || c == '\t' || c == '\r' diff --git a/platform/platform-impl/src/com/intellij/util/path.kt b/platform/platform-impl/src/com/intellij/util/path.kt index f7fae1b5816d..33d2a184a15e 100644 --- a/platform/platform-impl/src/com/intellij/util/path.kt +++ b/platform/platform-impl/src/com/intellij/util/path.kt @@ -18,6 +18,7 @@ package com.intellij.util import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VfsUtil +import org.jetbrains.io.readCharSequence import java.io.File import java.io.IOException import java.io.OutputStream @@ -82,6 +83,8 @@ fun Path.readBytes() = Files.readAllBytes(this) fun Path.readText() = readBytes().toString(Charsets.UTF_8) +fun Path.readChars() = inputStream().reader().readCharSequence(size().toInt()) + fun Path.writeChild(relativePath: String, data: ByteArray) = resolve(relativePath).write(data) fun Path.writeChild(relativePath: String, data: String) = writeChild(relativePath, data.toByteArray()) diff --git a/platform/platform-impl/src/org/jetbrains/io/FileResponses.java b/platform/platform-impl/src/org/jetbrains/io/FileResponses.java index 65b450b5cad6..28bf29cb5eda 100644 --- a/platform/platform-impl/src/org/jetbrains/io/FileResponses.java +++ b/platform/platform-impl/src/org/jetbrains/io/FileResponses.java @@ -1,5 +1,5 @@ /* - * 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. @@ -26,10 +26,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.activation.MimetypesFileTypeMap; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Date; import static org.jetbrains.io.Responses.*; @@ -51,21 +52,21 @@ public class FileResponses { } @Nullable - public static HttpResponse prepareSend(@NotNull HttpRequest request, @NotNull Channel channel, long lastModified, @NotNull String path) { + public static HttpResponse prepareSend(@NotNull HttpRequest request, @NotNull Channel channel, long lastModified, @NotNull String filename) { if (checkCache(request, channel, lastModified)) { return null; } HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); - response.headers().set(HttpHeaderNames.CONTENT_TYPE, getContentType(path)); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, getContentType(filename)); addCommonHeaders(response); response.headers().set(HttpHeaderNames.CACHE_CONTROL, "private, must-revalidate"); response.headers().set(HttpHeaderNames.LAST_MODIFIED, new Date(lastModified)); return response; } - public static void sendFile(@NotNull HttpRequest request, @NotNull Channel channel, @NotNull File file) throws IOException { - HttpResponse response = prepareSend(request, channel, file.lastModified(), file.getPath()); + public static void sendFile(@NotNull HttpRequest request, @NotNull Channel channel, @NotNull Path file) throws IOException { + HttpResponse response = prepareSend(request, channel, Files.getLastModifiedTime(file).toMillis(), file.getFileName().toString()); if (response == null) { return; } @@ -75,7 +76,7 @@ public class FileResponses { boolean fileWillBeClosed = false; RandomAccessFile raf; try { - raf = new RandomAccessFile(file, "r"); + raf = new RandomAccessFile(file.toFile(), "r"); } catch (FileNotFoundException ignored) { send(response(HttpResponseStatus.NOT_FOUND), channel, request);