Skip to content

Instantly share code, notes, and snippets.

@Asmod4n
Last active August 29, 2015 14:13
Show Gist options
  • Save Asmod4n/7e9dd6f562f21b0dfec6 to your computer and use it in GitHub Desktop.
Save Asmod4n/7e9dd6f562f21b0dfec6 to your computer and use it in GitHub Desktop.
picohttpparser for mruby
#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