game engines/web frameworks: 27 CWE-407 defects + 3 CLEAN; 194 sites, 78 ecosystems
This commit is contained in:
parent
547a9f5738
commit
4d3fcc8e73
76 changed files with 6216 additions and 17 deletions
153
defects/sinatra/unit/SinatraTest.java
Normal file
153
defects/sinatra/unit/SinatraTest.java
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
/**
|
||||
* SinatraTest — CWE-407 benchmarks for Sinatra base.rb defects.
|
||||
*
|
||||
* sinatra-0001: content_type calls add_charset.all? {|p| !(p === mime_type)} on every response.
|
||||
* Slow: Array#all? iterates all entries (Strings + Regexps) — O(k) per content_type call.
|
||||
* Fast: Set#include? for string entries (O(1)), Regexp only on miss.
|
||||
*
|
||||
* sinatra-0002: provides condition block calls types.include?(response_content_type) per request.
|
||||
* Slow: Array#include? — O(n) where n = number of types in the provides() call.
|
||||
* Fast: Set#include? built once at route-definition time — O(1) per request.
|
||||
*
|
||||
* Ruby Array#include? and Java List#contains are both O(n) linear scans.
|
||||
* Ruby Set#include? and Java HashSet#contains are both O(1) hash lookups.
|
||||
* The Java model faithfully represents the algorithmic complexity.
|
||||
*/
|
||||
public class SinatraTest {
|
||||
|
||||
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
|
||||
// warmup
|
||||
slow.run();
|
||||
fast.run();
|
||||
long t0 = System.nanoTime();
|
||||
slow.run();
|
||||
long sMs = (System.nanoTime() - t0) / 1_000_000;
|
||||
long t1 = System.nanoTime();
|
||||
fast.run();
|
||||
long fMs = (System.nanoTime() - t1) / 1_000_000;
|
||||
double r = fMs > 0 ? (double) sMs / fMs : 0;
|
||||
System.out.printf(" %-52s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.1fx%n",
|
||||
label, sMs, sOps, fMs, fOps, r);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// sinatra-0001: content_type add_charset scan
|
||||
// Simulates: settings.add_charset.all? { |p| !(p === mime_type) }
|
||||
// add_charset contains both String exact-match entries and Regexp patterns.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Models Ruby's === for mixed String/Regexp array
|
||||
static boolean addCharsetMatchSlow(List<Object> addCharset, String mimeType) {
|
||||
for (Object p : addCharset) {
|
||||
if (p instanceof String && ((String) p).equals(mimeType)) return true;
|
||||
if (p instanceof Pattern && ((Pattern) p).matcher(mimeType).find()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fast: check Set<String> first (O(1)), then Regexp array only on miss
|
||||
static boolean addCharsetMatchFast(Set<String> strings, List<Pattern> patterns, String mimeType) {
|
||||
if (strings.contains(mimeType)) return true;
|
||||
for (Pattern p : patterns) {
|
||||
if (p.matcher(mimeType).find()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// sinatra-0002: provides condition — types.include? per request
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
static boolean providesCheckSlow(List<String> types, String responseContentType) {
|
||||
// Ruby: types.include?(response_content_type) || types.include?(base_ct)
|
||||
if (types.contains(responseContentType)) return true;
|
||||
int semi = responseContentType.indexOf(';');
|
||||
String base = semi >= 0 ? responseContentType.substring(0, semi) : responseContentType;
|
||||
return types.contains(base);
|
||||
}
|
||||
|
||||
static boolean providesCheckFast(Set<String> typesSet, String responseContentType) {
|
||||
// Built once at route-definition time
|
||||
if (typesSet.contains(responseContentType)) return true;
|
||||
int semi = responseContentType.indexOf(';');
|
||||
String base = semi >= 0 ? responseContentType.substring(0, semi) : responseContentType;
|
||||
return typesSet.contains(base);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Sinatra CWE-407 Benchmarks");
|
||||
System.out.println("==========================");
|
||||
System.out.println();
|
||||
|
||||
// --- sinatra-0001: add_charset scan ---
|
||||
// Default Sinatra add_charset: ["application/javascript", "application/xml",
|
||||
// "application/xhtml+xml", "application/json"] + /^text\//
|
||||
// We extend it to demonstrate scaling with larger add_charset arrays.
|
||||
|
||||
// Default (k=5)
|
||||
List<Object> addCharsetDefault = Arrays.asList(
|
||||
"application/javascript", "application/xml",
|
||||
"application/xhtml+xml", "application/json",
|
||||
Pattern.compile("^text/")
|
||||
);
|
||||
Set<String> defaultStrings = new HashSet<>(Arrays.asList(
|
||||
"application/javascript", "application/xml",
|
||||
"application/xhtml+xml", "application/json"
|
||||
));
|
||||
List<Pattern> defaultPatterns = List.of(Pattern.compile("^text/"));
|
||||
|
||||
int REQUESTS_0001 = 500_000;
|
||||
String testMime = "text/html; charset=utf-8";
|
||||
|
||||
System.out.println("sinatra-0001: content_type add_charset check (" + REQUESTS_0001 + " requests)");
|
||||
bench(
|
||||
"k=5 (default): Array.all? vs Set+Regexp split",
|
||||
() -> { for (int i = 0; i < REQUESTS_0001; i++) addCharsetMatchSlow(addCharsetDefault, testMime); },
|
||||
() -> { for (int i = 0; i < REQUESTS_0001; i++) addCharsetMatchFast(defaultStrings, defaultPatterns, testMime); },
|
||||
REQUESTS_0001, REQUESTS_0001
|
||||
);
|
||||
|
||||
// Extended add_charset (k=50) — user-extended array
|
||||
List<Object> addCharsetLarge = new ArrayList<>(addCharsetDefault);
|
||||
Set<String> largeStrings = new HashSet<>(defaultStrings);
|
||||
for (int i = 0; i < 45; i++) {
|
||||
String s = "application/custom-type-" + i;
|
||||
addCharsetLarge.add(s);
|
||||
largeStrings.add(s);
|
||||
}
|
||||
bench(
|
||||
"k=50 (extended): Array.all? vs Set+Regexp split",
|
||||
() -> { for (int i = 0; i < REQUESTS_0001; i++) addCharsetMatchSlow(addCharsetLarge, testMime); },
|
||||
() -> { for (int i = 0; i < REQUESTS_0001; i++) addCharsetMatchFast(largeStrings, defaultPatterns, testMime); },
|
||||
REQUESTS_0001, REQUESTS_0001
|
||||
);
|
||||
|
||||
// --- sinatra-0002: provides condition ---
|
||||
System.out.println();
|
||||
System.out.println("sinatra-0002: provides() condition types membership check (" + REQUESTS_0001 + " requests)");
|
||||
|
||||
// Vary number of types in provides(...)
|
||||
int[] typeCounts = {2, 5, 10, 20, 50};
|
||||
for (int T : typeCounts) {
|
||||
List<String> types = new ArrayList<>();
|
||||
for (int i = 0; i < T; i++) types.add("application/type-" + i);
|
||||
Set<String> typesSet = new HashSet<>(types);
|
||||
// Worst case: content-type matches the last entry
|
||||
String ct = "application/type-" + (T - 1);
|
||||
bench(
|
||||
String.format("T=%2d types: Array#include? vs Set#include?", T),
|
||||
() -> { for (int i = 0; i < REQUESTS_0001; i++) providesCheckSlow(types, ct); },
|
||||
() -> { for (int i = 0; i < REQUESTS_0001; i++) providesCheckFast(typesSet, ct); },
|
||||
REQUESTS_0001, REQUESTS_0001
|
||||
);
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println("Done.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue