cleanup, use java nio Path

This commit is contained in:
Vladimir Krivosheev
2016-04-07 14:39:45 +02:00
parent d32d5f6189
commit 464652d85d
8 changed files with 188 additions and 193 deletions
@@ -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)
}
@@ -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
}
@@ -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!!)
}
@@ -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"))
private fun hasAccess(result: Path) = !result.isDirectory() && Files.isReadable(result) && !(Files.isHidden(result) || result.fileName.toString().startsWith(".ht"))
@@ -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)
}
@@ -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<String, SsiCommand> = THashMap()
init {
commands.put("config", object : SsiCommand {
override fun process(state: SsiProcessingState, commandName: String, paramNames: List<String>, paramValues: Array<String>, 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<String>, paramValues: Array<String>, 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<String>, paramValues: Array<String>, 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<String>, paramValues: Array<String>, 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<String>, paramValues: Array<String>, writer: ByteBufUtf8Writer): Long {
var lastModified: Long = 0
// any arguments should produce an error
if (paramNames.isEmpty()) {
val variableNames = LinkedHashSet<String>()
//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<String>, paramValues: Array<String>, 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<String>()
//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'
@@ -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())
@@ -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);