I ran a hotspot scan on curl/curl this week, and every one of the top five functions sits in the ‘fire’ quadrant — structurally complex code that is also being actively edited right now, not backlog debt waiting for someone to get around to it. The top result, http_connect in tests/server/sws.c, carries an activity-weighted risk score of 20.26, with 106 cyclomatic paths, 8 levels of nesting, and a change 4 days ago. Across the full codebase I scanned 6,031 functions, 1,506 of them landing in the critical band — so this is a targeted look at where the highest-priority review effort belongs this week, not a verdict on the whole project.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
http_connect | tests/server/sws.c | 20.3 | 106 | 8 | 22 |
rtspd_ProcessRequest | tests/server/rtspd.c | 20.2 | 81 | 14 | 24 |
test_rtspd | tests/server/rtspd.c | 20.2 | 57 | 11 | 26 |
curltest_tweak_handler | tests/http/testenv/mod_curltest/mod_curltest.c | 20.2 | 54 | 15 | 28 |
sws_ProcessRequest | tests/server/sws.c | 20.0 | 104 | 8 | 17 |
Large Repo Analysis
curl is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 5 or more commits in the touch window (365 days by default); other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.
6,031 functions analyzed
The quadrant split is worth sitting with for a second: 3,299 functions are actively changing while structurally complex, and zero landed in the ‘debt’ quadrant among the functions surfaced here. That means the risk picture for curl right now is entirely about live churn colliding with complexity, not stale code nobody looks at anymore.
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.Deeply Nested×5Deeply Nested
Control structures nested 4+ levels deep, making it hard to reason about the full execution state at inner branches.Exit Heavy×5Exit Heavy
Multiple return or throw paths dispersed through the body — each exit needs separate test coverage.God Function×5God Function
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Long Function×5Long Function
Function body is too long to review in a single pass; likely contains multiple distinct responsibilities.
Every single one of the top five functions triggered all five tracked antipatterns: complex branching, deep nesting, heavy use of early exits, long function bodies, and the ‘god function’ signal for broad responsibility. That match rate tells me these aren’t borderline cases — they’re candidates for extract-method work. All five also live in test infrastructure (tests/server/ and tests/http/testenv/), not in libcurl’s production transfer engine, which changes how I’d prioritize the work but not whether it’s worth doing.
http_connect — tests/server/sws.c
This is the top-ranked function in the scan, and the source confirms what the metrics imply: it’s a socket tunnel handler juggling two client sockets, two server sockets, and independent read/write poll state for a primary and secondary tunnel (used for passive FTP-style data connections layered under an HTTP CONNECT). The 106-path cyclomatic complexity comes from tracking four socket file descriptors through a single select()-style event loop, with nested conditionals guarding every combination of readable/writable state. An 8-level nesting depth means a reviewer has to hold eight layers of conditional context in their head to verify any single branch. Two touches in the last year, both on this same function, and a bug-fix rate of 50% on the surrounding file gives this a mild historical quality signal — not proof of a live defect, but reason enough to review the diffs closely. My recommendation: extract the per-tunnel-index socket monitoring block (the loop over clientfd[i]/serverfd[i]) into its own helper — that’s the densest branching cluster and the most testable unit in isolation.
rtspd_ProcessRequest — tests/server/rtspd.c
A 14-level nesting depth is the standout number here — the deepest of any function in this list. The excerpt shows why: it parses an HTTP/RTSP request line with sscanf, then walks into nested checks for protocol type, document path parsing, slash-finding, and numeric test-number extraction, each wrapped in another conditional layer. Twenty-four distinct function calls (fan-out) means this single request parser reaches into a wide swath of the test server’s helper functions, so a change to how it validates or logs a request has a broad blast radius across that file. One touch in the last year, 6 days ago, and no bug-fix history recorded — this reads as complexity that accumulated over time rather than a function under repeated defect pressure. I’d start by pulling the protocol-detection block (HTTP vs RTSP string comparison and version parsing) into a small dedicated function; that alone should cut a meaningful slice of the nesting.
test_rtspd — tests/server/rtspd.c
This is the RTSP test server’s entry point, and the excerpt shows a long, flat-looking else if chain parsing command-line flags (--version, --pidfile, --portfile, --logfile, --logdir, --ipv4, --ipv6, --port, --srcdir, and presumably more past the excerpt). That’s a classic long-function pattern — each flag adds one more branch, and cyclomatic complexity climbs linearly with every option added over the years. Fan-out of 26 is the highest fan-out in this top five, meaning this function is a hub that touches nearly every subsystem of the test server (socket setup, logging, PID/port file writing). The practical fix here is a lookup table or argument-parsing struct that maps flag strings to handlers, replacing the else if ladder — a well-understood refactor for CLI parsers that would drop the cyclomatic count sharply without touching behavior.
curltest_tweak_handler — tests/http/testenv/mod_curltest/mod_curltest.c
The deepest nesting in the entire top five (15 levels) and the highest fan-out (28) both land on this function, an Apache module handler that parses query-string arguments (status, chunks, chunk_size, id, error, error_bucket, body_error, delay, and more) to synthesize configurable test HTTP responses. Each argument is handled by its own strcmp branch with inline validation and error handling, which is exactly how you accumulate both deep nesting and high branching in the same function. This one is doing exactly what it looks like it’s built to do — deliberately produce tunable, edge-case HTTP responses for test scenarios — but that flexibility is also why it’s the most structurally loaded function on the list. I’d split argument parsing from response construction: a first pass builds a validated options struct, a second pass acts on it. That alone would separate two concerns that are currently interleaved branch-by-branch.
sws_ProcessRequest — tests/server/sws.c
The second function from sws.c, and at 104 cyclomatic paths it’s nearly tied with http_connect for the most branching in the set. The excerpt shows it parsing an incoming HTTP request line, extracting the method, path, and protocol version, then walking backward through the path string to find embedded test numbers — logic that has to handle malformed input, oversized requests, and special-case paths like /verifiedserver all inline. Like http_connect in the same file, it was touched twice in the last year with a recorded bug-fix rate of 50% on the file, and the file has had two authors in the last 90 days — worth noting sws.c as a whole is under active shared ownership, so a review of one function in it should probably include a look at the other. Given the 8-level nesting is identical to http_connect’s, the same extract-method treatment applies: isolate the path/test-number extraction logic (the backward slash-scan) into its own function with clear input/output.
Worth stepping back on: none of these five functions live in libcurl’s production transfer code — they’re all test-server or test-harness infrastructure. That doesn’t make the complexity free (a flaky or hard-to-debug test server slows down every contributor who runs the test suite), but it does mean the urgency here is about developer velocity on the test bed, not runtime correctness of libcurl itself. That’s the profile I’d want to see everywhere: active development on simple code.
Codebase Risk Distribution
All five top hotspots share the same structural patterns (complex_branching, deeply_nested, exit_heavy, god_function, long_function), which is typical of the highest-risk functions in any large codebase — they accumulate every structural signal on the way to the top. More useful context is how the risk is distributed across all 6,031 analyzed functions:
| Band | Functions |
|---|---|
| Critical | 1,506 |
| High | 1,793 |
| Moderate | 1,844 |
| Low | 888 |
Hotspot patterns belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
See more analyses with these patterns: complex_branching, deeply_nested, exit_heavy, god_function, long_function.
Reproduce This Analysis
git clone https://github.com/curl/curl
cd curl
git checkout 484e4e9f3ea1481f471549690e189fc08184f753
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
I use Hotspots to highlight structural and activity risk — not “bad code.” I treat these findings as a prioritization aid, not a bug predictor. Editorial policy →