# HTTP Probing

This page explains how `Monitor.Check()` decides whether a site is online: URL normalization, when it switches from HEAD to GET, timeouts, and the online criteria.

## URL Normalization

When the input URL does not start with `http`, `https://` is prepended (`internal/service/monitor.go:75`).

| Input | Actual request |
|-------|----------------|
| `example.com` | `https://example.com` |
| `https://example.com/health` | Unchanged |
| `http://example.com` | Unchanged (requested over HTTP) |

The normalized URL is written to `list[].url` in `.webMonitor.json`, and the watch list loads that value after a restart; see [Known Limitations](/known-limitations) for the impact.

## Request Flow

```mermaid
graph TB
    Start[Check url] --> Norm[Prepend https://]
    Norm --> Head[Send HEAD]
    Head -->|connection error or 404| Get[Send GET]
    Head -->|any other status| Judge
    Get --> Judge{Got a response?}
    Judge -->|Yes| SSL[CheckExpire reads certificate]
    SSL --> Code[Judge online by status code]
    Judge -->|No| Offline[Offline, Code = 0]
```

| Item | Value |
|------|-------|
| First request | `HEAD` |
| Switch to `GET` when | HEAD hits a connection error (including timeout) or returns `404` |
| Timeout | `http.Client.Timeout` of 10 seconds, counted separately for HEAD and GET |
| Redirects | Followed |
| Request headers | `User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36`, `Accept: */*`, `Connection: keep-alive` |

Only connection errors and `404` trigger GET. When a server rejects HEAD with `405` (Method Not Allowed) or any other 4xx / 5xx, the check does not retry with GET and marks the site offline.

## Online Criteria

| Result | `online` | `code` |
|--------|----------|--------|
| Status code 200–399 | `true` | Actual status code |
| Status code ≥ 400 | `false` | Actual status code |
| Connection failure, timeout, DNS error | `false` | `0` |

`duration` records the total time from start to response, including the GET retry after a failed HEAD, and the table shows it in milliseconds.

## When the SSL Check Runs

`util.CheckExpire()` reads the certificate only when the request got a response (any status code); on connection failure the SSL field is `0`. See [SSL Expiry](/ssl-expiry) for details.
