import java.util.*; /** * CWE-407 unit test for nginx ngx_http_core_module.c defect. * * nginx-0001: src/http/ngx_http_core_module.c ngx_http_link_multi_headers() * Nested double-traversal of r->headers_in.headers to chain duplicate * header names: outer loop at position i, inner loop scans 0..i-1. * O(H²) where H = number of incoming request headers. * Fix: single O(H) pass using a hash map of name → first header pointer; * append to chain on first match, no backward scan needed. */ public class NginxTest { // Simulate defect: O(H²) double-traversal static Map> linkMultiHeaders_quadratic(String[] headers) { // Returns map of name -> list of positions (the "chain") Map> chains = new LinkedHashMap<>(); for (int i = 0; i < headers.length; i++) { boolean linked = false; for (int j = 0; j < i; j++) { // O(H²) total — defect if (headers[j].equalsIgnoreCase(headers[i])) { chains.get(headers[j].toLowerCase()).add(i); linked = true; break; } } if (!linked) { List chain = new ArrayList<>(); chain.add(i); chains.put(headers[i].toLowerCase(), chain); } } return chains; } // Simulate fix: O(H) single pass with hash map static Map> linkMultiHeaders_hash(String[] headers) { Map> chains = new LinkedHashMap<>(); for (int i = 0; i < headers.length; i++) { String lower = headers[i].toLowerCase(); chains.computeIfAbsent(lower, k -> new ArrayList<>()).add(i); // O(1) } return chains; } static void testNginx0001() throws Exception { // Simulate H headers with many duplicates (worst case for O(H²)) // nginx default: ~50 unique header names, many repeated → H=300 total int H = 300; int UNIQUE = 20; String[] headers = new String[H]; String[] names = new String[UNIQUE]; for (int i = 0; i < UNIQUE; i++) names[i] = "X-Header-" + i; for (int i = 0; i < H; i++) headers[i] = names[i % UNIQUE]; // correctness Map> r1 = linkMultiHeaders_quadratic(headers); Map> r2 = linkMultiHeaders_hash(headers); assert r1.keySet().equals(r2.keySet()) : "must produce same key set"; for (String k : r1.keySet()) { assert r1.get(k).equals(r2.get(k)) : "chain mismatch for " + k + ": " + r1.get(k) + " vs " + r2.get(k); } // performance int REPS = 10_000; long t0 = System.nanoTime(); for (int r = 0; r < REPS; r++) linkMultiHeaders_quadratic(headers); long tQuad = System.nanoTime() - t0; t0 = System.nanoTime(); for (int r = 0; r < REPS; r++) linkMultiHeaders_hash(headers); long tHash = System.nanoTime() - t0; double ratio = (double) tQuad / tHash; System.out.printf("nginx-0001: quadratic=%.3fs hash=%.3fs ratio=%.1f×%n", tQuad / 1e9, tHash / 1e9, ratio); assert ratio > 3 : "Expected >3× speedup, got " + ratio; System.out.println("PASS nginx-0001"); } public static void main(String[] args) throws Exception { testNginx0001(); System.out.println("ALL PASS"); } }