Пример #1
0
static mrb_value
mrb_http_object_initialize(mrb_state *mrb, mrb_value self)
{
  OBJECT_SET(mrb, self, "headers", mrb_hash_new(mrb));
  OBJECT_SET(mrb, self, "body", mrb_nil_value());
  OBJECT_SET(mrb, self, "method", mrb_str_new_cstr(mrb, "GET"));
  return self;
}
Пример #2
0
Value ffi_pointer_read(VMState *state, Object *type, void *ptr) {
  ValueCache *vcache = &state->shared->vcache;
  Object *string_base = vcache->string_base;
  FFIObject *ffi = (FFIObject*) vcache->ffi_obj;
  if (type == ffi->float_obj) {
    float f = *(float*) ptr;
    return FLOAT2VAL(f);
  } else if (type == ffi->int_obj) {
    int i = *(int*) ptr;
    return INT2VAL(i);
  } else if (type == ffi->uint_obj) {
    unsigned int i = *(unsigned int*) ptr;
    return INT2VAL(i);
  } else {
    bool has_pointer = false;
    OBJECT_LOOKUP_P(type, pointer, &has_pointer);
    if (!has_pointer) {
      Object *c_type_obj = OBJ_OR_NULL(OBJECT_LOOKUP(type, c_type));
      StringObject *c_type = (StringObject*) obj_instance_of(c_type_obj, string_base);
      VM_ASSERT(c_type, "internal type error") VNULL;
      VM_ASSERT(false, "unhandled pointer read type: %s", c_type->value) VNULL;
    }
    Value res = make_object(state, type, false);
    char *error = OBJECT_SET(state, AS_OBJ(res), pointer, make_ffi_pointer(state, ptr));
    VM_ASSERT(!error, error) VNULL;
    return res;
  }
}
Пример #3
0
static mrb_value
mrb_http_object_body_set(mrb_state *mrb, mrb_value self)
{
  mrb_value arg;
  mrb_get_args(mrb, "S", &arg);
  OBJECT_SET(mrb, self, "body", arg);
  return mrb_nil_value();
}
Пример #4
0
static int
parser_settings_on_message_complete(http_parser* parser)
{
    mrb_http_parser_context *context = (mrb_http_parser_context*) parser->data;
    mrb_state* mrb = context->mrb;
    mrb_value c = context->instance;

    if (context->handle.field_set & (1<<UF_SCHEMA)) {
        OBJECT_SET(mrb, c, "schema", mrb_str_substr(mrb, OBJECT_GET(mrb, c, "buf"), context->handle.field_data[UF_SCHEMA].off, context->handle.field_data[UF_SCHEMA].len));
    }
    if (context->handle.field_set & (1<<UF_HOST)) {
        OBJECT_SET(mrb, c, "host", mrb_str_substr(mrb, OBJECT_GET(mrb, c, "buf"), context->handle.field_data[UF_HOST].off, context->handle.field_data[UF_HOST].len));
    }
    if (context->handle.field_set & (1<<UF_HOST)) {
        OBJECT_SET(mrb, c, "host", mrb_str_substr(mrb, OBJECT_GET(mrb, c, "buf"), context->handle.field_data[UF_HOST].off, context->handle.field_data[UF_HOST].len));
    }
    if (context->handle.field_set & (1<<UF_PORT)) {
        OBJECT_SET(mrb, c, "port", mrb_fixnum_value(context->handle.port));
    } else {
        if (context->handle.field_set & (1<<UF_SCHEMA)) {
            mrb_value schema = mrb_str_substr(mrb, OBJECT_GET(mrb, c, "buf"), context->handle.field_data[UF_SCHEMA].off, context->handle.field_data[UF_SCHEMA].len);
            if (!mrb_nil_p(schema) && !strcmp("https", (char*) RSTRING_PTR(schema))) {
                OBJECT_SET(mrb, c, "port", mrb_fixnum_value(443));
            }
        }
    }
    if (context->handle.field_set & (1<<UF_PATH)) {
        OBJECT_SET(mrb, c, "path", mrb_str_substr(mrb, OBJECT_GET(mrb, c, "buf"), context->handle.field_data[UF_PATH].off, context->handle.field_data[UF_PATH].len));
    }
    if (context->handle.field_set & (1<<UF_QUERY)) {
        OBJECT_SET(mrb, c, "query", mrb_str_substr(mrb, OBJECT_GET(mrb, c, "buf"), context->handle.field_data[UF_QUERY].off, context->handle.field_data[UF_QUERY].len));
    }
    if (context->parser.method)
        OBJECT_SET(mrb, c, "method", mrb_str_new_cstr(mrb, http_method_str(context->parser.method)));
    if (context->parser.status_code)
        OBJECT_SET(mrb, c, "status_code", mrb_fixnum_value(context->parser.status_code));
    if (context->parser.content_length)
        OBJECT_SET(mrb, c, "content_length", mrb_fixnum_value(context->parser.content_length));
    OBJECT_REMOVE(mrb, c, "last_header_field");
    OBJECT_REMOVE(mrb, c, "last_header_value");
    OBJECT_REMOVE(mrb, c, "buf");

    return 0;
}
Пример #5
0
static int
parser_settings_on_header_field(http_parser* parser, const char* at, size_t len)
{
  mrb_http_parser_context *context = (mrb_http_parser_context*) parser->data;
  mrb_state* mrb = context->mrb;

  int ai = mrb_gc_arena_save(mrb);
  if (context->was_header_value) {
    if (!mrb_nil_p(OBJECT_GET(mrb, context->instance, "last_header_field"))) {
      mrb_str_concat(mrb, OBJECT_GET(mrb, context->instance, "last_header_field"), OBJECT_GET(mrb, context->instance, "last_header_value"));
      OBJECT_SET(mrb, context->instance, "last_header_value", mrb_nil_value());
    }
    OBJECT_SET(mrb, context->instance, "last_header_field", mrb_str_new(mrb, at, len));
    context->was_header_value = FALSE;
  } else {
    mrb_str_concat(mrb, OBJECT_GET(mrb, context->instance, "last_header_field"), mrb_str_new(mrb, at, len));
  }
  mrb_gc_arena_restore(mrb, ai);
  return 0;
}
Пример #6
0
static int
parser_settings_on_body(http_parser *parser, const char *p, size_t len)
{
  mrb_http_parser_context *context = (mrb_http_parser_context*) parser->data;
  mrb_state* mrb = context->mrb;

  int ai = mrb_gc_arena_save(mrb);
  OBJECT_SET(mrb, context->instance, "body", mrb_str_new(mrb, p, len));
  mrb_gc_arena_restore(mrb, ai);
  return 0;
}
Пример #7
0
static mrb_value
mrb_http_parser_parse_url(mrb_state *mrb, mrb_value self)
{
    mrb_value c;
    mrb_value arg_data;
    struct http_parser_url handle = {0};
    struct RClass* _class_http, *_class_http_url;

    mrb_get_args(mrb, "S", &arg_data);

    if (http_parser_parse_url(RSTRING_PTR(arg_data), RSTRING_LEN(arg_data), FALSE, &handle)) {
        mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid URL");
    }

    _class_http = mrb_module_get(mrb, "HTTP");
    _class_http_url = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern_cstr(mrb, "URL")));

    c = mrb_obj_new(mrb, _class_http_url, 0, NULL);

    if (handle.field_set & (1<<UF_SCHEMA)) {
        OBJECT_SET(mrb, c, "schema", mrb_str_substr(mrb, arg_data, handle.field_data[UF_SCHEMA].off, handle.field_data[UF_SCHEMA].len));
    }
    if (handle.field_set & (1<<UF_HOST)) {
        OBJECT_SET(mrb, c, "host", mrb_str_substr(mrb, arg_data, handle.field_data[UF_HOST].off, handle.field_data[UF_HOST].len));
    }
    if (handle.field_set & (1<<UF_HOST)) {
        OBJECT_SET(mrb, c, "host", mrb_str_substr(mrb, arg_data, handle.field_data[UF_HOST].off, handle.field_data[UF_HOST].len));
    }
    if (handle.field_set & (1<<UF_PORT)) {
        OBJECT_SET(mrb, c, "port", mrb_fixnum_value(handle.port));
    } else {
        if (handle.field_set & (1<<UF_SCHEMA)) {
            mrb_value schema = mrb_str_substr(mrb, arg_data, handle.field_data[UF_SCHEMA].off, handle.field_data[UF_SCHEMA].len);
            if (!mrb_nil_p(schema) && !strcmp("https", (char*) RSTRING_PTR(schema))) {
                OBJECT_SET(mrb, c, "port", mrb_fixnum_value(443));
            }
        }
    }
    if (handle.field_set & (1<<UF_PATH)) {
        OBJECT_SET(mrb, c, "path", mrb_str_substr(mrb, arg_data, handle.field_data[UF_PATH].off, handle.field_data[UF_PATH].len));
    }
    if (handle.field_set & (1<<UF_QUERY)) {
        OBJECT_SET(mrb, c, "query", mrb_str_substr(mrb, arg_data, handle.field_data[UF_QUERY].off, handle.field_data[UF_QUERY].len));
    }
    if (handle.field_set & (1<<UF_FRAGMENT)) {
        OBJECT_SET(mrb, c, "fragment", mrb_str_substr(mrb, arg_data, handle.field_data[UF_FRAGMENT].off, handle.field_data[UF_FRAGMENT].len));
    }

    return c;
}
Пример #8
0
static void ffi_open_fn(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 1, "wrong arity: expected 1, got %i", info->args_len);
  Object *root = state->root;
  Object *string_base = state->shared->vcache.string_base;
  Object *array_base = state->shared->vcache.array_base;
  Object *ffi = AS_OBJ(OBJECT_LOOKUP(root, ffi));
  Object *handle_base = AS_OBJ(OBJECT_LOOKUP(ffi, handle));

  StringObject *sarg = (StringObject*) obj_instance_of(OBJ_OR_NULL(load_arg(state->frame, INFO_ARGS_PTR(info)[0])), string_base);
  VM_ASSERT(sarg, "argument to ffi.open must be string!");

  Object *libmap = AS_OBJ(OBJECT_LOOKUP(ffi, library_map));

  char *file = sarg->value;

  bool file_found = false;
  FastKey file_key = prepare_key(file, strlen(file));
  Value mapping = object_lookup_p(libmap, &file_key, &file_found);
  const char **file_list_ptr = NULL;
  int file_list_len = 0;
  if (file_found) {
    ArrayObject *aobj = (ArrayObject*) obj_instance_of(OBJ_OR_NULL(mapping), array_base);
    StringObject *sobj = (StringObject*) obj_instance_of(OBJ_OR_NULL(mapping), string_base);
    if (aobj) {
      file_list_len = aobj->length;
      file_list_ptr = malloc(sizeof(char*) * file_list_len);
      for (int i = 0; i < file_list_len; i++) {
        StringObject *file = (StringObject*) obj_instance_of(OBJ_OR_NULL(aobj->ptr[i]), string_base);
        VM_ASSERT(file, "library_map sub-entries must be string");
        file_list_ptr[i] = my_asprintf("%s", file->value); // outside gc, make copy
      }
    } else if (sobj) {
      file_list_len = 1;
      file_list_ptr = malloc(sizeof(char*) * 1);
      file_list_ptr[0] = my_asprintf("%s", sobj->value);
    } else VM_ASSERT(false, "library_map entries must be string or array");
  } else {
    file_list_len = 1;
    file_list_ptr = malloc(sizeof(char*) * 1);
    file_list_ptr[0] = file;
  }

  void *dlptr = my_dlopen(file_list_len, file_list_ptr);

  Object *handle_obj = AS_OBJ(make_object(state, handle_base, false));
  handle_obj->flags |= OBJ_FROZEN;
  OBJECT_SET(state, handle_obj, pointer, make_ptr(state, dlptr));
  vm_return(state, info, OBJ2VAL(handle_obj));
}
Пример #9
0
static mrb_value
_http_parser_parse(mrb_state *mrb, mrb_value self, int type)
{
  mrb_value arg_data = mrb_nil_value();
  mrb_value value_context;
  mrb_http_parser_context* context;
  mrb_value b = mrb_nil_value();
  struct RClass* _class_http;
  struct RClass* clazz;
  char* data;
  size_t len;
  char* eol;
  size_t done;

  value_context = mrb_iv_get(mrb, self, mrb_intern(mrb, "context"));
  Data_Get_Struct(mrb, value_context, &http_parser_context_type, context);
  if (!context) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument");
  }

  mrb_get_args(mrb, "|&o", &b, &arg_data);
  if (mrb_nil_p(arg_data)) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument");
  }
  context->parser.data = context;

  _class_http = mrb_class_get(mrb, "HTTP");
  if (type == HTTP_REQUEST) {
    clazz = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern(mrb, "Request")));
    context->instance = mrb_class_new_instance(mrb, 0, NULL, clazz);
  } else {
    clazz = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern(mrb, "Response")));
    context->instance = mrb_class_new_instance(mrb, 0, NULL, clazz);
  }
  context->was_header_value = TRUE;

  http_parser_init(&context->parser, type);

  context->type = type;
  context->settings.on_url = parser_settings_on_url;
  context->settings.on_header_field = parser_settings_on_header_field;
  context->settings.on_header_value = parser_settings_on_header_value;
  context->settings.on_headers_complete = parser_settings_on_headers_complete;
  context->settings.on_body = parser_settings_on_body;
  context->settings.on_message_complete = parser_settings_on_message_complete;

  data = RSTRING_PTR(arg_data);
  len = RSTRING_LEN(arg_data);

  eol = strpbrk(data, "\r\n");
  if (eol) {
  }

RETRY:
  if (len > 10 && (!strncmp(data+9, "200 Connection established\r\n", 28) ||
      !strncmp(data+9, "100 Continue\r\n", 14) || *(data+9) == '3')) {
    char* next = strstr(data, "\r\n\r\n");
    if (next) {
      len -= (next + 4 - data);
      data = next + 4;
      goto RETRY;
    }
  }

  done = http_parser_execute(&context->parser, &context->settings, data, len);
  if (done < len) {
    OBJECT_SET(mrb, context->instance, "body", mrb_str_new(mrb, data + done, len - done));
  }

  if (!mrb_nil_p(b)) {
    mrb_value args[1];
    args[0] = context->instance;
    mrb_yield_argv(mrb, b, 1, args);
    return mrb_nil_value();
  }
  return context->instance;
}