1 #ifndef common_field_optimization
2 #define common_field_optimization
13 * A list of common HTTP headers we expect to receive.
14 * This allows us to avoid repeatedly creating identical string
15 * objects to be used with rb_hash_aset().
17 static struct common_field common_http_fields
[] = {
18 # define f(N) { (sizeof(N) - 1), N, Qnil }
27 f("CONTENT_ENCODING"),
36 f("IF_MODIFIED_SINCE"),
39 f("IF_UNMODIFIED_SINCE"),
40 f("KEEP_ALIVE"), /* Firefox sends this */
43 f("PROXY_AUTHORIZATION"),
48 f("TRANSFER_ENCODING"),
52 f("X_FORWARDED_FOR"), /* common for proxies */
53 f("X_FORWARDED_PROTO"), /* common for proxies */
54 f("X_REAL_IP"), /* common for proxies */
59 #define HTTP_PREFIX "HTTP_"
60 #define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
63 /* this dedupes under Ruby 2.5+ (December 2017) */
64 static VALUE
str_dd_freeze(VALUE str
)
66 if (STR_UMINUS_DEDUPE
)
67 return rb_funcall(str
, id_uminus
, 0);
69 /* freeze,since it speeds up older MRI slightly */
74 static VALUE
str_new_dd_freeze(const char *ptr
, long len
)
76 return str_dd_freeze(rb_str_new(ptr
, len
));
79 /* this function is not performance-critical, called only at load time */
80 static void init_common_fields(void)
83 struct common_field
*cf
= common_http_fields
;
86 memcpy(tmp
, HTTP_PREFIX
, HTTP_PREFIX_LEN
);
88 for(i
= ARRAY_SIZE(common_http_fields
); --i
>= 0; cf
++) {
89 /* Rack doesn't like certain headers prefixed with "HTTP_" */
90 if (!strcmp("CONTENT_LENGTH", cf
->name
) ||
91 !strcmp("CONTENT_TYPE", cf
->name
)) {
92 cf
->value
= str_new_dd_freeze(cf
->name
, cf
->len
);
94 memcpy(tmp
+ HTTP_PREFIX_LEN
, cf
->name
, cf
->len
+ 1);
95 cf
->value
= str_new_dd_freeze(tmp
, HTTP_PREFIX_LEN
+ cf
->len
);
97 rb_gc_register_mark_object(cf
->value
);
101 /* this function is called for every header set */
102 static VALUE
find_common_field(const char *field
, size_t flen
)
105 struct common_field
*cf
= common_http_fields
;
107 for(i
= ARRAY_SIZE(common_http_fields
); --i
>= 0; cf
++) {
108 if (cf
->len
== (long)flen
&& !memcmp(cf
->name
, field
, flen
))
115 * We got a strange header that we don't have a memoized value for.
116 * Fallback to creating a new string to use as a hash key.
118 static VALUE
uncommon_field(const char *field
, size_t flen
)
120 VALUE f
= rb_str_new(NULL
, HTTP_PREFIX_LEN
+ flen
);
121 memcpy(RSTRING_PTR(f
), HTTP_PREFIX
, HTTP_PREFIX_LEN
);
122 memcpy(RSTRING_PTR(f
) + HTTP_PREFIX_LEN
, field
, flen
);
123 assert(*(RSTRING_PTR(f
) + RSTRING_LEN(f
)) == '\0' &&
124 "string didn't end with \\0"); /* paranoia */
125 return HASH_ASET_DEDUPE
? f
: str_dd_freeze(f
);
128 #endif /* common_field_optimization_h */