# 機能設計書 25-セッション開始ミドルウェア

## 概要

本ドキュメントは、Laravel Frameworkのセッション開始ミドルウェア（StartSession）の設計仕様を記載する。StartSessionはHTTPリクエスト処理のライフサイクルにおいて、セッションの開始・管理・保存を担当するミドルウェアである。

### 本機能の処理概要

StartSessionミドルウェアは、HTTPリクエストごとにセッションを開始し、レスポンス送信前にセッションを保存するライフサイクル管理を行う。キャッシュベースのセッションブロッキングにも対応。

**業務上の目的・背景**：Webアプリケーションでは、リクエストごとにセッションデータの読み込みと保存が必要となる。StartSessionミドルウェアはこの処理を透過的に行い、アプリケーションコードではセッションを意識せずに利用できるようにする。また、同一セッションへの同時リクエスト（Ajax等）でのデータ競合を防ぐブロッキング機能も提供する。

**機能の利用シーン**：すべてのWebリクエスト処理において自動的に実行される。ログイン状態の維持、フラッシュメッセージの伝達、CSRFトークンの検証準備、前回URLの記録など、セッションを必要とするあらゆる処理の基盤となる。

**主要な処理内容**：
1. リクエストCookieからセッションIDを取得
2. セッションストアの開始とデータ読み込み
3. ブロッキングセッション時のロック取得
4. アプリケーション処理の実行
5. 現在URLの保存（GETリクエスト時）
6. セッションCookieのレスポンスへの追加
7. セッションデータの保存
8. ガベージコレクションの実行（確率的）

**関連システム・外部連携**：SessionManager、キャッシュドライバ（ブロッキング用）、ルーターとの連携。

**権限による制御**：本機能自体には権限制御はない。ミドルウェアパイプラインの一部として動作。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 全画面 | 主画面 | リクエストごとのセッション管理 |

## 機能種別

ミドルウェア / セッション管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| request | Request | Yes | HTTPリクエストオブジェクト | - |
| next | Closure | Yes | 次のミドルウェア/コントローラ | - |

### 入力データソース

- HTTPリクエストCookie（セッションID）
- 設定ファイル（config/session.php）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| response | Response | HTTPレスポンスオブジェクト |
| session_cookie | Cookie | セッションIDを含むCookie |

### 出力先

- セッションストレージ（セッションデータ）
- HTTPレスポンスヘッダー（セッションCookie）

## 処理フロー

### 処理シーケンス

```
1. handle()でリクエストを受け取る
   └─ sessionConfigured()でセッション設定確認

2. getSession()でセッションストアを取得
   └─ CookieからセッションIDを設定

3. ブロッキング判定
   └─ shouldBlock()またはroute->locksFor()でブロッキング判定
   └─ ブロッキング時はロックを取得

4. handleStatefulRequest()でステートフル処理
   └─ startSession()でセッション開始
   └─ collectGarbage()でGC実行（確率的）
   └─ 次のミドルウェア/コントローラを実行
   └─ storeCurrentUrl()で現在URLを保存
   └─ addCookieToResponse()でCookieを追加
   └─ saveSession()でセッションを保存

5. レスポンスを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{セッション設定あり?}
    B -->|No| C[次の処理へ]
    B -->|Yes| D[getSession]
    D --> E[CookieからセッションID取得]
    E --> F{ブロッキング必要?}
    F -->|Yes| G[ロック取得]
    G --> H[handleStatefulRequest]
    F -->|No| H
    H --> I[startSession]
    I --> J[collectGarbage]
    J --> K[アプリケーション処理]
    K --> L{GETリクエスト?}
    L -->|Yes| M[現在URL保存]
    L -->|No| N[Cookieをレスポンスに追加]
    M --> N
    N --> O{Precognitive?}
    O -->|No| P[セッション保存]
    O -->|Yes| Q[保存スキップ]
    P --> R[レスポンス返却]
    Q --> R
    R --> S[終了]
    C --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | セッションCookie | 永続セッションではexpiresを設定、セッションでは0 | expire_on_close設定 |
| BR-02 | 現在URL保存 | GETリクエストかつ非Ajax/非Prefetch時のみ保存 | GETリクエスト時 |
| BR-03 | Precognitive | Precognitiveリクエスト時はセッション保存をスキップ | isPrecognitive()時 |
| BR-04 | GC確率 | lottery設定に基づき確率的にGCを実行 | セッション開始時 |
| BR-05 | ブロッキングロック | 同一セッションへの同時アクセスを排他制御 | shouldBlock()時 |

### 計算ロジック

- セッション有効期限: lifetime * 60 秒
- Cookie有効期限: expire_on_close ? 0 : now + lifetime秒
- GC確率: random_int(1, lottery[1]) <= lottery[0]

## データベース操作仕様

本ミドルウェア自体はデータベースを直接操作しない。セッションハンドラを通じて間接的に操作される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| LockTimeoutException | ロックエラー | ブロッキングセッションでロック取得失敗 | リトライまたはエラー表示 |
| Exception | 一般エラー | セッション読み込み/保存失敗 | ログ出力、エラーハンドリング |

### リトライ仕様

ブロッキングセッションでのロック取得時、block_wait_seconds設定に基づきリトライを行う。デフォルト10秒。

## トランザクション仕様

本機能はトランザクションを使用しない。セッション操作はアプリケーショントランザクションとは独立。

## パフォーマンス要件

- ロック取得タイムアウト: block_wait_seconds（デフォルト10秒）
- ロック保持時間: block_lock_seconds（デフォルト10秒）
- GC処理: 確率的実行によりリクエストごとの負荷を分散

## セキュリティ考慮事項

- **Cookie属性**: HttpOnly、Secure、SameSiteを設定
- **Partitioned Cookie**: partitioned設定でCHIPS対応
- **セッションID漏洩防止**: CookieのみでセッションIDを伝達
- **セッション固定攻撃対策**: 認証処理でregenerateを使用

## 備考

- webミドルウェアグループに含まれる
- api ルートでは通常使用しない（ステートレスAPI）
- Precognitiveリクエストではセッション保存をスキップ

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: ミドルウェアの基本構造を理解する

まず、StartSessionミドルウェアの全体構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | StartSession.php | `src/Illuminate/Session/Middleware/StartSession.php` | メインのミドルウェア実装 |

**読解のコツ**: handle()メソッドがエントリーポイント。ブロッキング/非ブロッキングの分岐を確認。

#### Step 2: メイン処理フローを理解する

handle()メソッドの処理フローを詳細に確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StartSession.php | `src/Illuminate/Session/Middleware/StartSession.php` | 各処理メソッドの詳細 |

**主要処理フロー**:
- **50-64行目**: handle()でリクエストを処理、ブロッキング判定
- **74-99行目**: handleRequestWhileBlocking()でロック取得とリリース
- **109-132行目**: handleStatefulRequest()でメイン処理
- **141-148行目**: startSession()でセッション開始
- **156-161行目**: getSession()でセッションストアを取得
- **169-179行目**: collectGarbage()でGC実行
- **199-212行目**: storeCurrentUrl()で現在URL保存
- **221-237行目**: addCookieToResponse()でCookie追加
- **245-250行目**: saveSession()でセッション保存

#### Step 3: ブロッキングセッションを理解する

同時アクセス制御の仕組みを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StartSession.php | `src/Illuminate/Session/Middleware/StartSession.php` | handleRequestWhileBlocking |
| 3-2 | SessionManager.php | `src/Illuminate/Session/SessionManager.php` | shouldBlock, blockDriver設定 |

**主要処理フロー**:
- **74-99行目**: ロック取得、処理実行、ロックリリース
- **84-86行目**: キャッシュベースのロックを取得
- **88-93行目**: block()でロック取得を待機

### プログラム呼び出し階層図

```
StartSession::handle()
    │
    ├─ sessionConfigured()
    │      └─ config('session.driver')
    │
    ├─ getSession()
    │      ├─ SessionManager::driver()
    │      └─ setId(Cookie)
    │
    └─ handleStatefulRequest() / handleRequestWhileBlocking()
           │
           ├─ startSession()
           │      ├─ setRequestOnHandler()
           │      └─ Store::start()
           │
           ├─ collectGarbage()
           │      └─ SessionHandler::gc()
           │
           ├─ $next($request) ─── アプリケーション処理
           │
           ├─ storeCurrentUrl()
           │      └─ Store::setPreviousUrl()
           │
           ├─ addCookieToResponse()
           │      └─ Response::headers::setCookie()
           │
           └─ saveSession()
                  └─ Store::save()
```

### データフロー図

```
[入力]               [処理]                    [出力]

HTTP Request
    │
    ├─ Cookie: session_id
    │
    ▼
StartSession::handle()
    │
    ├─ getSession()
    │      └─ SessionManager::driver()
    │
    ├─ startSession()
    │      └─ Store::start()
    │             └─ ストレージからデータ読み込み
    │
    ├─ collectGarbage() [確率的]
    │
    ├─ $next($request)
    │      └─ アプリケーション処理
    │             └─ セッション読み書き
    │
    ├─ storeCurrentUrl() [GETのみ]
    │
    ├─ addCookieToResponse()
    │
    └─ saveSession()
           └─ Store::save()
                  └─ ストレージにデータ保存
                         │
                         ▼
                  HTTP Response
                  + Set-Cookie: session_id
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StartSession.php | `src/Illuminate/Session/Middleware/StartSession.php` | ソース | メインミドルウェア |
| SessionManager.php | `src/Illuminate/Session/SessionManager.php` | ソース | セッション管理 |
| Store.php | `src/Illuminate/Session/Store.php` | ソース | セッションストア |
| AuthenticateSession.php | `src/Illuminate/Session/Middleware/AuthenticateSession.php` | ソース | 認証セッション |
| SessionServiceProvider.php | `src/Illuminate/Session/SessionServiceProvider.php` | ソース | サービス登録 |
