ext/puma_http11/puma_http11.c in piesync-puma-3.12.6.1 vs ext/puma_http11/puma_http11.c in piesync-puma-5.4.0.1

- old
+ new

@@ -8,10 +8,11 @@ #include "ruby.h" #include "ext_help.h" #include <assert.h> #include <string.h> +#include <ctype.h> #include "http11_parser.h" #ifndef MANAGED_STRINGS #ifndef RSTRING_PTR @@ -37,26 +38,32 @@ static VALUE global_query_string; static VALUE global_http_version; static VALUE global_request_path; /** Defines common length and error messages for input length validation. */ -#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " # length " allowed length (was %d)" +#define QUOTE(s) #s +#define EXPLAIN_MAX_LENGTH_VALUE(s) QUOTE(s) +#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " EXPLAIN_MAX_LENGTH_VALUE(length) " allowed length (was %d)" /** Validates the max length of given input and throws an HttpParserError exception if over. */ #define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); } /** Defines global strings in the init method. */ #define DEF_GLOBAL(N, val) global_##N = rb_str_new2(val); rb_global_variable(&global_##N) /* Defines the maximum allowed lengths for various input elements.*/ +#ifndef PUMA_QUERY_STRING_MAX_LENGTH +#define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10) +#endif + DEF_MAX_LENGTH(FIELD_NAME, 256); DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024); DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12); DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */ -DEF_MAX_LENGTH(REQUEST_PATH, 2048); -DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10)); +DEF_MAX_LENGTH(REQUEST_PATH, 8192); +DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH); DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32))); struct common_field { const size_t len; const char *name; @@ -109,25 +116,10 @@ f("X_REAL_IP"), /* common for proxies */ f("WARNING") # undef f }; -/* - * qsort(3) and bsearch(3) improve average performance slightly, but may - * not be worth it for lack of portability to certain platforms... - */ -#if defined(HAVE_QSORT_BSEARCH) -/* sort by length, then by name if there's a tie */ -static int common_field_cmp(const void *a, const void *b) -{ - struct common_field *cfa = (struct common_field *)a; - struct common_field *cfb = (struct common_field *)b; - signed long diff = cfa->len - cfb->len; - return diff ? diff : memcmp(cfa->name, cfb->name, cfa->len); -} -#endif /* HAVE_QSORT_BSEARCH */ - static void init_common_fields(void) { unsigned i; struct common_field *cf = common_http_fields; char tmp[256]; /* MAX_FIELD_NAME_LENGTH */ @@ -140,40 +132,21 @@ memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1); cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len); } rb_global_variable(&cf->value); } - -#if defined(HAVE_QSORT_BSEARCH) - qsort(common_http_fields, - ARRAY_SIZE(common_http_fields), - sizeof(struct common_field), - common_field_cmp); -#endif /* HAVE_QSORT_BSEARCH */ } static VALUE find_common_field_value(const char *field, size_t flen) { -#if defined(HAVE_QSORT_BSEARCH) - struct common_field key; - struct common_field *found; - key.name = field; - key.len = (signed long)flen; - found = (struct common_field *)bsearch(&key, common_http_fields, - ARRAY_SIZE(common_http_fields), - sizeof(struct common_field), - common_field_cmp); - return found ? found->value : Qnil; -#else /* !HAVE_QSORT_BSEARCH */ unsigned 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 /* !HAVE_QSORT_BSEARCH */ } void http_field(puma_parser* hp, const char *field, size_t flen, const char *value, size_t vlen) { @@ -198,10 +171,12 @@ memcpy(hp->buf + HTTP_PREFIX_LEN, field, flen); f = rb_str_new(hp->buf, new_size); } + while (vlen > 0 && isspace(value[vlen - 1])) vlen--; + /* check for duplicate header */ v = rb_hash_aref(hp->request, f); if (v == Qnil) { v = rb_str_new(value, vlen); @@ -282,15 +257,22 @@ if(data) { xfree(data); } } -void HttpParser_mark(puma_parser* hp) { +void HttpParser_mark(void *ptr) { + puma_parser *hp = ptr; if(hp->request) rb_gc_mark(hp->request); if(hp->body) rb_gc_mark(hp->body); } +const rb_data_type_t HttpParser_data_type = { + "HttpParser", + { HttpParser_mark, HttpParser_free, 0 }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + VALUE HttpParser_alloc(VALUE klass) { puma_parser *hp = ALLOC_N(puma_parser, 1); TRACE(); hp->http_field = http_field; @@ -303,11 +285,11 @@ hp->header_done = header_done; hp->request = Qnil; puma_parser_init(hp); - return Data_Wrap_Struct(klass, HttpParser_mark, HttpParser_free, hp); + return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp); } /** * call-seq: * parser.new -> parser @@ -315,11 +297,11 @@ * Creates a new parser. */ VALUE HttpParser_init(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); puma_parser_init(http); return self; } @@ -332,11 +314,11 @@ * rather than making new ones. */ VALUE HttpParser_reset(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); puma_parser_init(http); return Qnil; } @@ -349,11 +331,11 @@ * You should call reset after finish it or bad things will happen. */ VALUE HttpParser_finish(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); puma_parser_finish(http); return puma_parser_is_finished(http) ? Qtrue : Qfalse; } @@ -380,11 +362,11 @@ puma_parser *http = NULL; int from = 0; char *dptr = NULL; long dlen = 0; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); from = FIX2INT(start); dptr = rb_extract_chars(data, &dlen); if(from >= dlen) { @@ -396,11 +378,11 @@ rb_free_chars(dptr); VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER); if(puma_parser_has_error(http)) { - rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails."); + rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?"); } else { return INT2FIX(puma_parser_nread(http)); } } } @@ -414,11 +396,11 @@ * Tells you whether the parser is in an error state. */ VALUE HttpParser_has_error(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); return puma_parser_has_error(http) ? Qtrue : Qfalse; } @@ -429,11 +411,11 @@ * Tells you whether the parser is finished or not and in a good state. */ VALUE HttpParser_is_finished(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); return puma_parser_is_finished(http) ? Qtrue : Qfalse; } @@ -445,11 +427,11 @@ * set to 0 on initialize or reset calls and is incremented each time execute is called. */ VALUE HttpParser_nread(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); return INT2FIX(http->nread); } /** @@ -458,17 +440,18 @@ * * If the request included a body, returns it. */ VALUE HttpParser_body(VALUE self) { puma_parser *http = NULL; - DATA_GET(self, puma_parser, http); + DATA_GET(self, puma_parser, &HttpParser_data_type, http); return http->body; } -void Init_io_buffer(VALUE puma); +#ifdef HAVE_OPENSSL_BIO_H void Init_mini_ssl(VALUE mod); +#endif void Init_puma_http11() { VALUE mPuma = rb_define_module("Puma"); @@ -493,8 +476,9 @@ rb_define_method(cHttpParser, "finished?", HttpParser_is_finished, 0); rb_define_method(cHttpParser, "nread", HttpParser_nread, 0); rb_define_method(cHttpParser, "body", HttpParser_body, 0); init_common_fields(); - Init_io_buffer(mPuma); +#ifdef HAVE_OPENSSL_BIO_H Init_mini_ssl(mPuma); +#endif }