From 60b4397f51894d5e679a6eed73a8cde957f03c4a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 2 Aug 2009 16:16:28 -0700 Subject: http: generic C string vs VALUEs comparison function The macro version lets us painlessly compare Ruby strings against constant C strings. It wraps a C version of the function which is necessary to avoid double evaluation while preventing the user from having to type sizeof or strlen. --- ext/unicorn_http/ext_help.h | 8 ++++++++ ext/unicorn_http/unicorn_http.rl | 26 +++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ext/unicorn_http/ext_help.h b/ext/unicorn_http/ext_help.h index fec4f41..19f08c9 100644 --- a/ext/unicorn_http/ext_help.h +++ b/ext/unicorn_http/ext_help.h @@ -18,4 +18,12 @@ static void rb_18_str_set_len(VALUE str, long len) # define rb_str_set_len(str,len) rb_18_str_set_len(str,len) #endif +static inline int str_cstr_eq(VALUE val, const char *ptr, size_t len) +{ + return (RSTRING_LEN(val) == len && !memcmp(ptr, RSTRING_PTR(val), len)); +} + +#define STR_CSTR_EQ(val, const_str) \ + str_cstr_eq(val, const_str, sizeof(const_str) - 1) + #endif diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl index 5081605..76831bb 100644 --- a/ext/unicorn_http/unicorn_http.rl +++ b/ext/unicorn_http/unicorn_http.rl @@ -71,16 +71,18 @@ static void header_done(VALUE req, const char *at, size_t length); } action request_uri { size_t len = LEN(mark, fpc); + VALUE str; + VALIDATE_MAX_LENGTH(len, REQUEST_URI); - rb_hash_aset(req, g_request_uri, STR_NEW(mark, fpc)); + str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, fpc)); /* * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*' * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain */ - if (len == 1 && *PTR_TO(mark) == '*') { - VALUE val = rb_str_new(NULL, 0); - rb_hash_aset(req, g_request_path, val); - rb_hash_aset(req, g_path_info, val); + if (STR_CSTR_EQ(str, "*")) { + str = rb_str_new(NULL, 0); + rb_hash_aset(req, g_path_info, str); + rb_hash_aset(req, g_request_path, str); } } action fragment { @@ -100,11 +102,10 @@ static void header_done(VALUE req, const char *at, size_t length); size_t len = LEN(mark, fpc); VALIDATE_MAX_LENGTH(len, REQUEST_PATH); - val = STR_NEW(mark, fpc); + val = rb_hash_aset(req, g_request_path, STR_NEW(mark, fpc)); - rb_hash_aset(req, g_request_path, val); /* rack says PATH_INFO must start with "/" or be empty */ - if (!(len == 1 && *PTR_TO(mark) == '*')) + if (!STR_CSTR_EQ(val, "*")) rb_hash_aset(req, g_path_info, val); } action done { @@ -177,11 +178,6 @@ static void http_field(VALUE req, const char *field, size_t flen, VALUE val) rb_hash_aset(req, f, val); } -static int is_https(VALUE str) -{ - return RSTRING_LEN(str) == 5 && !memcmp("https", RSTRING_PTR(str), 5); -} - static void set_server_params(VALUE req) { VALUE temp = rb_hash_aref(req, g_rack_url_scheme); @@ -191,12 +187,12 @@ static void set_server_params(VALUE req) /* set rack.url_scheme to "https" or "http", no others are allowed by Rack */ if (temp == Qnil) { temp = rb_hash_aref(req, g_http_x_forwarded_proto); - if (temp != Qnil && is_https(temp)) + if (temp != Qnil && STR_CSTR_EQ(temp, "https")) server_port = g_port_443; else temp = g_http; rb_hash_aset(req, g_rack_url_scheme, temp); - } else if (is_https(temp)) { + } else if (STR_CSTR_EQ(temp, "https")) { server_port = g_port_443; } -- cgit v1.2.3-24-ge0c7