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
}