about summary refs log tree commit homepage
path: root/ext/unicorn_http/common_field_optimization.h
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-08-02 13:39:21 -0700
committerEric Wong <normalperson@yhbt.net>2009-08-09 01:24:30 -0700
commitca3fd8acb4bc3f5125a9f0f281951fb8f03778e5 (patch)
tree42752ea26cf989d9a8d02d750a87aff0d15dc1d8 /ext/unicorn_http/common_field_optimization.h
parente1d67bef994587ba77e1a3575773755b2b5e1558 (diff)
downloadunicorn-ca3fd8acb4bc3f5125a9f0f281951fb8f03778e5.tar.gz
More tightly integrate the C/Ruby portions with C/Ragel to avoid
the confusing the flow.  Split out some files into hopefully
logical areas so it's easier to focus on more
interesting/volatile code.
Diffstat (limited to 'ext/unicorn_http/common_field_optimization.h')
-rw-r--r--ext/unicorn_http/common_field_optimization.h96
1 files changed, 96 insertions, 0 deletions
diff --git a/ext/unicorn_http/common_field_optimization.h b/ext/unicorn_http/common_field_optimization.h
new file mode 100644
index 0000000..978f0d7
--- /dev/null
+++ b/ext/unicorn_http/common_field_optimization.h
@@ -0,0 +1,96 @@
+#ifndef common_field_optimization
+#define common_field_optimization
+#include "ruby.h"
+
+struct common_field {
+  const signed long len;
+  const char *name;
+  VALUE value;
+};
+
+/*
+ * A list of common HTTP headers we expect to receive.
+ * This allows us to avoid repeatedly creating identical string
+ * objects to be used with rb_hash_aset().
+ */
+static struct common_field common_http_fields[] = {
+# define f(N) { (sizeof(N) - 1), N, Qnil }
+  f("ACCEPT"),
+  f("ACCEPT_CHARSET"),
+  f("ACCEPT_ENCODING"),
+  f("ACCEPT_LANGUAGE"),
+  f("ALLOW"),
+  f("AUTHORIZATION"),
+  f("CACHE_CONTROL"),
+  f("CONNECTION"),
+  f("CONTENT_ENCODING"),
+  f("CONTENT_LENGTH"),
+  f("CONTENT_TYPE"),
+  f("COOKIE"),
+  f("DATE"),
+  f("EXPECT"),
+  f("FROM"),
+  f("HOST"),
+  f("IF_MATCH"),
+  f("IF_MODIFIED_SINCE"),
+  f("IF_NONE_MATCH"),
+  f("IF_RANGE"),
+  f("IF_UNMODIFIED_SINCE"),
+  f("KEEP_ALIVE"), /* Firefox sends this */
+  f("MAX_FORWARDS"),
+  f("PRAGMA"),
+  f("PROXY_AUTHORIZATION"),
+  f("RANGE"),
+  f("REFERER"),
+  f("TE"),
+  f("TRAILER"),
+  f("TRANSFER_ENCODING"),
+  f("UPGRADE"),
+  f("USER_AGENT"),
+  f("VIA"),
+  f("X_FORWARDED_FOR"), /* common for proxies */
+  f("X_FORWARDED_PROTO"), /* common for proxies */
+  f("X_REAL_IP"), /* common for proxies */
+  f("WARNING")
+# undef f
+};
+
+#define HTTP_PREFIX "HTTP_"
+#define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
+
+/* this function is not performance-critical, called only at load time */
+static void init_common_fields(void)
+{
+  int i;
+  struct common_field *cf = common_http_fields;
+  char tmp[64];
+  memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
+
+  for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
+    /* Rack doesn't like certain headers prefixed with "HTTP_" */
+    if (!strcmp("CONTENT_LENGTH", cf->name) ||
+        !strcmp("CONTENT_TYPE", cf->name)) {
+      cf->value = rb_str_new(cf->name, cf->len);
+    } else {
+      memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
+      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
+    }
+    cf->value = rb_obj_freeze(cf->value);
+    rb_global_variable(&cf->value);
+  }
+}
+
+/* this function is called for every header set */
+static VALUE find_common_field_value(const char *field, size_t flen)
+{
+  int i;
+  struct common_field *cf = common_http_fields;
+
+  for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
+    if (cf->len == flen && !memcmp(cf->name, field, flen))
+      return cf->value;
+  }
+  return Qnil;
+}
+
+#endif /* common_field_optimization_h */