java-topology/defects/haproxy/unit/HaproxyCaptureHeadersAlgorithmTest.java
russell@unturf.com ba818693db nmap-0002 + haproxy-0004 + nginx-0004 + weechat-0003 + zeek-0002 + curl-0004: 6 new CWE-407 defects in network tools; count 693→699
nmap-0002:     nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range
haproxy-0004:  http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H)
nginx-0004:    ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1)
weechat-0003:  irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1)
zeek-0002:     Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A)
curl-0004:     mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
2026-03-29 22:22:11 -04:00

126 lines
4.4 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.*;
/**
* haproxy-0004 — CWE-407: http_capture_headers O(H×C) per request
*
* Models http_ana.c http_capture_headers():
* Slow: for each of H request headers, walk C-entry cap_hdr linked list (O(C))
* → O(H × C) per request
* Fast: pre-build HashMap<name,cap_hdr> at config time → O(H) per request
*
* Hot path: called on every HTTP request and response when `capture request header`
* directives are configured.
*/
public class HaproxyCaptureHeadersAlgorithmTest {
// Simulates a cap_hdr linked-list entry (from include/haproxy/capture-t.h)
static class CapHdr {
final String name;
final int index;
CapHdr next;
CapHdr(String name, int index) { this.name = name; this.index = index; }
}
// Simulates an HTTP header (name + value)
static class HttpHeader {
final String name;
final String value;
HttpHeader(String name, String value) { this.name = name; this.value = value; }
}
// --- SLOW: O(H × C) per request (defect) ---
// Models: for each htx header → for each cap_hdr → strncasecmp
static long captureHeadersSlow(List<HttpHeader> headers, CapHdr capHdrHead) {
long ops = 0;
String[] cap = new String[64];
for (HttpHeader hdr : headers) {
for (CapHdr h = capHdrHead; h != null; h = h.next) {
ops++; // strncasecmp call
if (h.name.equalsIgnoreCase(hdr.name)) {
if (cap[h.index] == null)
cap[h.index] = hdr.value;
}
}
}
return ops;
}
// --- FAST: O(H) per request (fix) ---
// Models: pre-built HashMap<lowercaseName, cap_hdr> at config time
static long captureHeadersFast(List<HttpHeader> headers,
Map<String, CapHdr> capHdrMap) {
long ops = 0;
String[] cap = new String[64];
for (HttpHeader hdr : headers) {
ops++; // O(1) hash lookup
CapHdr h = capHdrMap.get(hdr.name.toLowerCase());
if (h != null && cap[h.index] == null)
cap[h.index] = hdr.value;
}
return ops;
}
// Build cap_hdr linked list
static CapHdr buildCapHdrList(int count) {
CapHdr head = null;
for (int i = count - 1; i >= 0; i--) {
CapHdr h = new CapHdr("X-Custom-Header-" + i, i);
h.next = head;
head = h;
}
return head;
}
// Build pre-indexed cap_hdr map
static Map<String, CapHdr> buildCapHdrMap(CapHdr head) {
Map<String, CapHdr> map = new HashMap<>();
for (CapHdr h = head; h != null; h = h.next)
map.put(h.name.toLowerCase(), h);
return map;
}
// Build HTTP request headers list
static List<HttpHeader> buildHeaders(int count, int captureHits) {
List<HttpHeader> headers = new ArrayList<>();
for (int i = 0; i < count; i++) {
String name;
if (i < captureHits)
name = "X-Custom-Header-" + i; // will match cap_hdr
else
name = "Standard-Header-" + i; // won't match cap_hdr
headers.add(new HttpHeader(name, "value-" + i));
}
return headers;
}
public static void main(String[] args) {
System.out.println("haproxy-0004 CWE-407: http_capture_headers O(H*C) vs O(H)");
System.out.println("==========================================================");
// Parameters: H request headers, C capture headers configured
int[][] params = { {30, 10}, {50, 20}, {100, 50} };
for (int[] p : params) {
int H = p[0], C = p[1];
CapHdr capHdrHead = buildCapHdrList(C);
Map<String, CapHdr> capHdrMap = buildCapHdrMap(capHdrHead);
List<HttpHeader> headers = buildHeaders(H, C / 2);
long slowOps = captureHeadersSlow(headers, capHdrHead);
long fastOps = captureHeadersFast(headers, capHdrMap);
double ratio = (double) slowOps / fastOps;
System.out.printf(" H=%3d headers, C=%2d captures: slow=%,5d ops fast=%,3d ops speedup=%.0fx%n",
H, C, slowOps, fastOps, ratio);
assert ratio >= (double) C / 2 :
"Expected speedup >= " + (C/2) + "x but got " + ratio;
}
System.out.println("\nPASS");
}
}