Last active
August 29, 2015 14:13
-
-
Save Asmod4n/7e9dd6f562f21b0dfec6 to your computer and use it in GitHub Desktop.
picohttpparser for mruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "picohttpparser.h" | |
#include <mruby.h> | |
#include <mruby/data.h> | |
#include <mruby/variable.h> | |
#include <mruby/array.h> | |
#include <mruby/string.h> | |
#include <mruby/class.h> | |
#define PHR_MAX_HEADERS 255 | |
typedef struct phr_chunked_decoder phr_chunked_decoder_t; | |
static const struct mrb_data_type phr_chunked_decoder_type = { | |
"$i_phr_chunked_decoder", mrb_free, | |
}; | |
static mrb_value | |
phr_chunked_decoder_init(mrb_state *mrb, mrb_value self) | |
{ | |
phr_chunked_decoder_t *decoder; | |
decoder = (phr_chunked_decoder_t *) DATA_PTR(self); | |
if(decoder) | |
mrb_free(mrb, decoder); | |
mrb_data_init(self, NULL, &phr_chunked_decoder_type); | |
decoder = (phr_chunked_decoder_t *) mrb_calloc(mrb, 1, | |
sizeof(phr_chunked_decoder_t)); | |
mrb_data_init(self, decoder, &phr_chunked_decoder_type); | |
mrb_iv_set(mrb, self, | |
mrb_intern_lit(mrb, "size"), | |
mrb_fixnum_value(0)); | |
return self; | |
} | |
static mrb_value | |
mrb_phr_init(mrb_state *mrb, mrb_value self) | |
{ | |
mrb_iv_set(mrb, self, | |
mrb_intern_lit(mrb, "last_len"), | |
mrb_fixnum_value(0)); | |
mrb_iv_set(mrb, self, | |
mrb_intern_lit(mrb, "chunked_decoder"), | |
mrb_obj_new(mrb, mrb_class_get_under(mrb, | |
mrb_class_get(mrb, "Phr"), "ChunkedDecoder"), 0, NULL)); | |
return self; | |
} | |
static mrb_value | |
mrb_phr_method(mrb_state *mrb, mrb_value self) | |
{ | |
return mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "method")); | |
} | |
static mrb_value | |
mrb_phr_path(mrb_state *mrb, mrb_value self) | |
{ | |
return mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "path")); | |
} | |
static mrb_value | |
mrb_phr_minor_version(mrb_state *mrb, mrb_value self) | |
{ | |
return mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "minor_version")); | |
} | |
static mrb_value | |
mrb_phr_status(mrb_state *mrb, mrb_value self) | |
{ | |
return mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "status")); | |
} | |
static mrb_value | |
mrb_phr_msg(mrb_state *mrb, mrb_value self) | |
{ | |
return mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "msg")); | |
} | |
static mrb_value | |
mrb_phr_headers(mrb_state *mrb, mrb_value self) | |
{ | |
return mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "headers")); | |
} | |
static inline mrb_value | |
mrb_phr_headers_to_a(mrb_state *mrb, struct phr_header *headers, size_t num_headers) | |
{ | |
mrb_value headers_array = mrb_ary_new_capa(mrb, (mrb_int)num_headers); | |
mrb_int i; | |
for(i=0;i != num_headers;i++) { | |
mrb_value tmp = mrb_ary_new_capa(mrb, 2); | |
mrb_ary_set(mrb, tmp, 0, | |
mrb_str_new_static(mrb, headers[i].name, headers[i].name_len)); | |
mrb_ary_set(mrb, tmp, 1, | |
mrb_str_new_static(mrb, headers[i].value, headers[i].value_len)); | |
mrb_ary_set(mrb, headers_array, i, tmp); | |
} | |
return headers_array; | |
} | |
static mrb_value | |
mrb_phr_parse_request(mrb_state *mrb, mrb_value self) | |
{ | |
mrb_int i; | |
char *request; | |
mrb_int request_len; | |
int ret; | |
const char *method; | |
size_t method_len; | |
const char *path; | |
size_t path_len; | |
int minor_version; | |
size_t num_headers = PHR_MAX_HEADERS; | |
struct phr_header headers[num_headers]; | |
mrb_int last_len = mrb_int(mrb, mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "last_len"))); | |
i = mrb_get_args(mrb, "s", &request, &request_len); | |
ret = phr_parse_request(request, request_len, | |
&method, &method_len, &path, &path_len, &minor_version, headers, | |
&num_headers, last_len); | |
if (ret == -1) | |
return mrb_symbol_value(mrb_intern_lit(mrb, "parser_error")); | |
else | |
if (ret == -2) { | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "last_len"), | |
mrb_fixnum_value(request_len)); | |
return mrb_symbol_value(mrb_intern_lit(mrb, "incomplete")); | |
} else { | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "method"), | |
mrb_str_new_static(mrb, method, method_len)); | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "path"), | |
mrb_str_new_static(mrb, path, path_len)); | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "minor_version"), | |
mrb_fixnum_value(minor_version)); | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "headers"), | |
mrb_phr_headers_to_a(mrb, headers, num_headers)); | |
return mrb_fixnum_value(ret); | |
} | |
} | |
static mrb_value | |
mrb_phr_parse_response(mrb_state *mrb, mrb_value self) | |
{ | |
mrb_int i; | |
char *response; | |
mrb_int response_len; | |
int ret; | |
int minor_version; | |
int status; | |
const char *msg; | |
size_t msg_len; | |
size_t num_headers = PHR_MAX_HEADERS; | |
struct phr_header headers[num_headers]; | |
mrb_int last_len = mrb_int(mrb, mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "last_len"))); | |
i = mrb_get_args(mrb, "s", &response, &response_len); | |
ret = phr_parse_response(response, response_len, | |
&minor_version, &status, &msg, &msg_len, headers, | |
&num_headers, last_len); | |
if (ret == -1) | |
return mrb_symbol_value(mrb_intern_lit(mrb, "parser_error")); | |
else | |
if (ret == -2) { | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "last_len"), | |
mrb_fixnum_value(response_len)); | |
return mrb_symbol_value(mrb_intern_lit(mrb, "incomplete")); | |
} else { | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "minor_version"), | |
mrb_fixnum_value(minor_version)); | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "status"), | |
mrb_fixnum_value(status)); | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "msg"), | |
mrb_str_new_static(mrb, msg, msg_len)); | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "headers"), | |
mrb_phr_headers_to_a(mrb, headers, num_headers)); | |
return mrb_fixnum_value(ret); | |
} | |
} | |
static mrb_value | |
mrb_phr_parse_headers(mrb_state *mrb, mrb_value self) | |
{ | |
mrb_int i; | |
char *buf; | |
mrb_int buf_len, ret; | |
size_t num_headers = PHR_MAX_HEADERS; | |
struct phr_header headers[num_headers]; | |
mrb_int last_len = mrb_int(mrb, mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "last_len"))); | |
i = mrb_get_args(mrb, "s", &buf, &buf_len); | |
ret = phr_parse_headers(buf, buf_len, headers, &num_headers, last_len); | |
if (ret == -1) | |
return mrb_symbol_value(mrb_intern_lit(mrb, "parser_error")); | |
else | |
if (ret == -2) { | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "last_len"), | |
mrb_fixnum_value(buf_len)); | |
return mrb_symbol_value(mrb_intern_lit(mrb, "incomplete")); | |
} else { | |
mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "headers"), | |
mrb_phr_headers_to_a(mrb, headers, num_headers)); | |
return mrb_fixnum_value(ret); | |
} | |
} | |
static mrb_value | |
mrb_phr_decode_chunked(mrb_state *mrb, mrb_value self) | |
{ | |
mrb_int i; | |
mrb_value buf; | |
mrb_int rsize, ret; | |
mrb_value decoder_obj = mrb_iv_get(mrb, self, | |
mrb_intern_lit(mrb, "chunked_decoder")); | |
phr_chunked_decoder_t *decoder; | |
decoder = (phr_chunked_decoder_t *) DATA_PTR(decoder_obj); | |
mrb_int size = mrb_int(mrb, mrb_iv_get(mrb, decoder_obj, | |
mrb_intern_lit(mrb, "size"))); | |
i = mrb_get_args(mrb, "S", &buf); | |
rsize = RSTRING_LEN(buf) - size; | |
ret = phr_decode_chunked(decoder, RSTRING_PTR(buf) + size | |
(size_t *)&rsize); | |
size += rsize; | |
if(ret == -1) | |
return mrb_symbol_value(mrb_intern_lit(mrb, "parser_error")); | |
else | |
if (ret == -2) { | |
mrb_str_resize(mrb, buf, size); | |
mrb_iv_set(mrb, decoder_obj, | |
mrb_intern_lit(mrb, "size"), | |
mrb_fixnum_value(size)); | |
return mrb_symbol_value(mrb_intern_lit(mrb, "incomplete")); | |
} | |
else { | |
mrb_str_resize(mrb, buf, size + ret); | |
return mrb_fixnum_value(size); | |
} | |
} | |
static mrb_value | |
mrb_phr_reset(mrb_state *mrb, mrb_value self) | |
{ | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "last_len")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "method")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "path")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "minor_version")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "status")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "msg")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "headers")); | |
(void) mrb_iv_remove(mrb, self, | |
mrb_intern_lit(mrb, "chunked_decoder")); | |
(void) mrb_phr_init(mrb, self); | |
return self; | |
} | |
void | |
mrb_phr_gem_init(mrb_state* mrb) { | |
struct RClass *phr_class, *phr_chunked_decoder_class; | |
phr_class = mrb_define_class(mrb, "Phr", mrb->object_class); | |
mrb_define_method(mrb, phr_class, "initialize", mrb_phr_init, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "method", mrb_phr_method, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "path", mrb_phr_path, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "minor_version", mrb_phr_minor_version, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "status", mrb_phr_status, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "msg", mrb_phr_msg, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "headers", mrb_phr_headers, MRB_ARGS_NONE()); | |
mrb_define_method(mrb, phr_class, "parse_request", mrb_phr_parse_request, MRB_ARGS_REQ(1)); | |
mrb_define_method(mrb, phr_class, "parse_response", mrb_phr_parse_response, MRB_ARGS_REQ(1)); | |
mrb_define_method(mrb, phr_class, "parse_headers", mrb_phr_parse_headers, MRB_ARGS_REQ(1)); | |
mrb_define_method(mrb, phr_class, "decode_chunked", mrb_phr_decode_chunked, MRB_ARGS_REQ(2)); | |
mrb_define_method(mrb, phr_class, "reset", mrb_phr_reset, MRB_ARGS_NONE()); | |
phr_chunked_decoder_class = mrb_define_class_under(mrb, phr_class, "ChunkedDecoder", mrb->object_class); | |
MRB_SET_INSTANCE_TT(phr_chunked_decoder_class, MRB_TT_DATA); | |
mrb_define_method(mrb, phr_chunked_decoder_class, "initialize", phr_chunked_decoder_init, MRB_ARGS_NONE()); | |
} | |
void | |
mrb_phr_gem_final(mrb_state* mrb) { | |
/* finalizer */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment