Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@
## 2025-01-24 - 단일 readAttributes 호출로 파일 속성 조회 최적화
**학습:** `isDirectory`, `!it.isDirectory()`, `isSymbolicLink` 3개의 개별적인 파일 시스템 I/O 호출을 수행하면 성능 저하가 큽니다. 이를 단일 `Files.readAttributes` 호출로 변경하여 메타데이터를 한 번에 조회함으로써 I/O 오버헤드를 대폭 줄일 수 있음을 확인했습니다.
**조치:** 디렉토리 순회 시 파일의 여러 속성을 확인할 때는 개별적인 stat 호출보다 `Files.readAttributes`를 사용하여 필요한 모든 속성을 한 번에 가져오는 방식을 우선적으로 고려해야 합니다.
## 2024-05-27 - 디렉토리 처리 루프의 정적 리소스 최적화
**Learning:** 디렉토리를 순회하며 처리하는 루프(process_dir) 내에서 크기가 큰 정적 문자열(CSS)을 할당하거나 결정론적 계산(SHA-256 해시)을 반복하면 각 순회마다 중복 할당 및 불필요한 CPU 오버헤드가 발생한다는 것을 확인했습니다.
**Action:** 앞으로는 루프 내에서 변하지 않는 큰 상수 문자열이나 계산 결과는 `private object`를 활용하여 루프 외부로 추출하고, Kotlin 컴파일러의 암시적 getter로 인한 테스트 커버리지 하락을 방지하기 위해 `const val` 및 `@JvmField`를 함께 적용하겠습니다.
38 changes: 21 additions & 17 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,8 @@ fun write_index_file(curr_dir: File, content: String) {
}
}

fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array<File>? = null){

val exclude: Set<String> = excludeSet ?: process_ignore_file(curr_dir)

val cssContent = """
private object Constants {
const val cssContent = """
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.5;
Expand Down Expand Up @@ -310,25 +307,39 @@ fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array
}
"""

@JvmField
val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8)))

val css = """
const val css = """
<style>
${cssContent} </style>
"""
Comment on lines +313 to 316

const val index_bottom="""
</ul>
</nav>
</main>
</body>
</html>
"""
}

fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array<File>? = null){

val exclude: Set<String> = excludeSet ?: process_ignore_file(curr_dir)

val index_top = """<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<!-- 보안 향상: 인라인 스크립트 실행 방지 -->
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src '${styleHash}'; base-uri 'none'; form-action 'none';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src '${Constants.styleHash}'; base-uri 'none'; form-action 'none';">
<!-- 보안 향상: 리퍼러를 통한 디렉토리 경로 노출 방지 -->
<meta name="referrer" content="no-referrer">
<title>${curr_dir.getName().escapeHtml()}</title>
${css}
${Constants.css}
</head>
<body>
<main>
Expand Down Expand Up @@ -377,16 +388,9 @@ ${cssContent} </style>
return l.toString();
}

val index_bottom="""
</ul>
</nav>
</main>
</body>
</html>
"""

try {
write_index_file(curr_dir, index_top+index_middle()+index_bottom)
// ⚡ Bolt Performance Optimization: Use cached index_bottom from Constants
write_index_file(curr_dir, index_top+index_middle()+Constants.index_bottom)
} catch (e: Exception) {
// 보안 향상: 디렉토리에 쓰기 권한이 없거나 파일 시스템 오류가 발생했을 때
// 전체 크롤링(프로세스)이 중단되는 DoS를 방지합니다. (Fail Securely)
Expand Down
Loading