json_call::json_call(http::context &c) { if(c.request().content_type()!="application/json") throw call_error("Invalid content type"); if(c.request().request_method()!="POST") throw call_error("Invalid request method"); std::pair<void *,size_t> post_data = c.request().raw_post_data(); std::istringstream ss(std::string(reinterpret_cast<char const *>(post_data.first),post_data.second)); json::value request; if(!request.load(ss,true)) throw call_error("Invalid JSON"); if( request.type("method")!=json::is_string || request.type("params")!=json::is_array || request.type("id")==json::is_undefined) { throw call_error("Invalid JSON-RPC"); } if(request.type("id")==json::is_null) { notification_ = true; } else { notification_ = false; id_.swap(request["id"]); params_.swap(request["params"].array()); method_ = request.get<std::string>("method"); } }
void timeout_callback(void *arg) { module_data_t *mod = arg; asc_timer_destroy(mod->timeout_timer); mod->timeout_timer = NULL; switch(mod->is_connected) { case 0: call_error(mod, "connection timeout"); break; case 1: call_error(mod, "connection failed"); break; case 2: call_error(mod, "response timeout"); break; default: call_error(mod, "unknown error"); break; } on_close(mod); }
R call_member_impl(lua_State* L, std::false_type /*void*/, meta::index_list<Indices...>, Args&&... args) { // don't count the function and self-reference // since those will be popped by pcall int top = lua_gettop(L) - 2; // pcall will pop the function and self reference // and all the parameters meta::expand_calls_hack(( specialized_converter_policy_n<Indices, PolicyList, typename unwrapped<Args>::type, cpp_to_lua>().to_lua(L, unwrapped<Args>::get(std::forward<Args>(args))), 0)... ); if (pcall(L, sizeof...(Args) +1, 1)) { assert(lua_gettop(L) == top + 1); call_error(L); } // pops the return values from the function stack_pop pop(L, lua_gettop(L) - top); specialized_converter_policy_n<0, PolicyList, R, lua_to_cpp> converter; if (converter.match(L, decorated_type<R>(), -1) < 0) { cast_error<R>(L); } return converter.to_cpp(L, decorated_type<R>(), -1); }
static void read_array(ParseInfo pi, const char *key) { if (pi->has_array_start) { call_no_value(pi->handler, oj_array_start_id, key); } pi->s++; next_non_white(pi); if (']' == *pi->s) { pi->s++; } else { while (1) { read_next(pi, 0); next_non_white(pi); if (',' == *pi->s) { pi->s++; } else if (']' == *pi->s) { pi->s++; break; } else { if (pi->has_error) { call_error("invalid format, expected , or ] while in an array", pi, __FILE__, __LINE__); } raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s); } } } if (pi->has_array_end) { call_no_value(pi->handler, oj_array_end_id, key); } }
static void read_hash(ParseInfo pi, const char *key) { const char *ks; if (pi->has_hash_start) { call_no_value(pi->handler, oj_hash_start_id, key); } pi->s++; next_non_white(pi); if ('}' == *pi->s) { pi->s++; } else { while (1) { next_non_white(pi); ks = read_quoted_value(pi); next_non_white(pi); if (':' == *pi->s) { pi->s++; } else { if (pi->has_error) { call_error("invalid format, expected :", pi, __FILE__, __LINE__); } raise_error("invalid format, expected :", pi->str, pi->s); } read_next(pi, ks); next_non_white(pi); if ('}' == *pi->s) { pi->s++; break; } else if (',' == *pi->s) { pi->s++; } else { if (pi->has_error) { call_error("invalid format, expected , or } while in an object", pi, __FILE__, __LINE__); } raise_error("invalid format, expected , or } while in an object", pi->str, pi->s); } } } if (pi->has_hash_end) { call_no_value(pi->handler, oj_hash_end_id, key); } }
static void read_nil(ParseInfo pi, const char *key) { pi->s++; if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) { if (pi->has_error) { call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__); } raise_error("invalid format, expected 'null'", pi->str, pi->s); } pi->s += 3; if (pi->has_add_value) { call_add_value(pi->handler, Qnil, key); } }
static void read_false(ParseInfo pi, const char *key) { pi->s++; if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) { if (pi->has_error) { call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__); } raise_error("invalid format, expected 'false'", pi->str, pi->s); } pi->s += 4; if (pi->has_add_value) { call_add_value(pi->handler, Qfalse, key); } }
static void skip_comment(ParseInfo pi) { pi->s++; /* skip first / */ if ('*' == *pi->s) { pi->s++; for (; '\0' != *pi->s; pi->s++) { if ('*' == *pi->s && '/' == *(pi->s + 1)) { pi->s++; return; } else if ('\0' == *pi->s) { if (pi->has_error) { call_error("comment not terminated", pi, __FILE__, __LINE__); } else { raise_error("comment not terminated", pi->str, pi->s); } } } } else if ('/' == *pi->s) { for (; 1; pi->s++) { switch (*pi->s) { case '\n': case '\r': case '\f': case '\0': return; default: break; } } } else { if (pi->has_error) { call_error("invalid comment", pi, __FILE__, __LINE__); } else { raise_error("invalid comment", pi->str, pi->s); } } }
static uint32_t read_hex(ParseInfo pi, char *h) { uint32_t b = 0; int i; /* TBD this can be made faster with a table */ for (i = 0; i < 4; i++, h++) { b = b << 4; if ('0' <= *h && *h <= '9') { b += *h - '0'; } else if ('A' <= *h && *h <= 'F') { b += *h - 'A' + 10; } else if ('a' <= *h && *h <= 'f') { b += *h - 'a' + 10; } else { pi->s = h; if (pi->has_error) { call_error("invalid hex character", pi, __FILE__, __LINE__); } raise_error("invalid hex character", pi->str, pi->s); } } return b; }
void json_call::check_not_notification() { if(notification()) throw call_error("Notification method should not return response"); }
static void on_read(void *arg) { module_data_t *mod = arg; asc_timer_destroy(mod->timeout_timer); mod->timeout_timer = NULL; char *buffer = mod->buffer; int skip = mod->ts_len_in_buf; int r = asc_socket_recv(mod->sock, buffer + skip, HTTP_BUFFER_SIZE - skip); if(r <= 0) { on_close(mod); return; } r += mod->ts_len_in_buf;// Imagine that we've received more (+ previous part) int response = 0; parse_match_t m[4]; // parse response if(mod->ready_state == 0) { if(!http_parse_response(buffer, m)) { call_error(mod, "invalid response"); on_close(mod); return; } lua_newtable(lua); response = lua_gettop(lua); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->__lua.oref); lua_pushvalue(lua, -2); // duplicate table lua_setfield(lua, -2, __response); lua_pop(lua, 1); // options lua_pushnumber(lua, atoi(&buffer[m[2].so])); lua_setfield(lua, response, __code); lua_pushlstring(lua, &buffer[m[3].so], m[3].eo - m[3].so); lua_setfield(lua, response, __message); skip = m[0].eo; mod->ready_state = 1; if(skip >= r) { lua_pop(lua, 1); // response return; } } // parse headers if(mod->ready_state == 1) { if(!response) { lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->__lua.oref); lua_getfield(lua, -1, __response); lua_remove(lua, -2); response = lua_gettop(lua); } int headers_count = 0; lua_getfield(lua, response, __headers); if(lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_newtable(lua); lua_pushvalue(lua, -1); lua_setfield(lua, response, __headers); } else { headers_count = luaL_len(lua, -1); } const int headers = lua_gettop(lua); while(skip < r && http_parse_header(&buffer[skip], m)) { const size_t so = m[1].so; const size_t length = m[1].eo - so; if(!length) { skip += m[0].eo; mod->ready_state = 2; break; } const char *header = &buffer[skip + so]; if(!strncasecmp(header, __transfer_encoding, sizeof(__transfer_encoding) - 1)) { const char *val = &header[sizeof(__transfer_encoding) - 1]; if(!strncasecmp(val, __chunked, sizeof(__chunked) - 1)) mod->is_chunked = 1; } else if(!strncasecmp(header, __connection, sizeof(__connection) - 1)) { const char *val = &header[sizeof(__connection) - 1]; if(!strncasecmp(val, __close, sizeof(__close) - 1)) mod->is_close = 1; else if(!strncasecmp(val, __keep_alive, sizeof(__keep_alive) - 1)) mod->is_keep_alive = 1; } else if(!strncasecmp(header, __content_length, sizeof(__content_length) - 1)) { const char *val = &header[sizeof(__content_length) - 1]; mod->is_content_length = 1; mod->chunk_left = strtoul(val, NULL, 10); } ++headers_count; lua_pushnumber(lua, headers_count); lua_pushlstring(lua, header, length); lua_settable(lua, headers); skip += m[0].eo; } lua_pop(lua, 1); // headers if(mod->ready_state == 2) { get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushvalue(lua, response); lua_call(lua, 2, 0); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->__lua.oref); lua_pushnil(lua); lua_setfield(lua, -2, __response); lua_pop(lua, 1); // options } lua_pop(lua, 1); // response if(skip >= r) return; } // content if(mod->ready_state == 2) { /* Push to stream */ if (mod->is_ts) { int pos = skip - mod->ts_len_in_buf;// buffer rewind while (r - pos >= TS_PACKET_SIZE) { module_stream_send(mod, (uint8_t*)&mod->buffer[pos]); pos += TS_PACKET_SIZE; } int left = r - pos; if (left > 0) {//there is something usefull in the end of buffer, move it to begin if (pos > 0) memmove(&mod->buffer[0], &mod->buffer[pos], left); mod->ts_len_in_buf = left; } else {//all data is processed mod->ts_len_in_buf = 0; } } // Transfer-Encoding: chunked else if(mod->is_chunked) { while(skip < r) { if(!mod->chunk_left) { if(!http_parse_chunk(&buffer[skip], m)) { call_error(mod, "invalid chunk"); on_close(mod); return; } char cs_str[] = "00000000"; const size_t cs_size = m[1].eo - m[1].so; const size_t cs_skip = 8 - cs_size; memcpy(&cs_str[cs_skip], &buffer[skip], cs_size); uint8_t cs_hex[4]; str_to_hex(cs_str, cs_hex, sizeof(cs_hex)); mod->chunk_left = (cs_hex[0] << 24) | (cs_hex[1] << 16) | (cs_hex[2] << 8) | (cs_hex[3] ); skip += m[0].eo; if(!mod->chunk_left) { if(mod->is_keep_alive) { // keep-alive connection get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushstring(lua, ""); lua_call(lua, 2, 0); } else { // close connection on_close(mod); } return; } } const size_t r_skip = r - skip; get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); if(mod->chunk_left < r_skip) { lua_pushlstring(lua, &buffer[skip], mod->chunk_left); lua_call(lua, 2, 0); skip += mod->chunk_left; mod->chunk_left = 0; if(buffer[skip] == '\r') ++skip; if(buffer[skip] == '\n') ++skip; else { call_error(mod, "invalid chunk"); on_close(mod); return; } } else { lua_pushlstring(lua, &buffer[skip], r_skip); lua_call(lua, 2, 0); mod->chunk_left -= r_skip; break; } } } // Content-Length else if(mod->is_content_length) { if(mod->chunk_left > 0) { const size_t r_skip = r - skip; get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); if(mod->chunk_left > r_skip) { lua_pushlstring(lua, &buffer[skip], r_skip); lua_call(lua, 2, 0); mod->chunk_left -= r_skip; } else { lua_pushlstring(lua, &buffer[skip], mod->chunk_left); lua_call(lua, 2, 0); mod->chunk_left = 0; if(mod->is_keep_alive) { // keep-alive connection get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushstring(lua, ""); lua_call(lua, 2, 0); } else { // close connection on_close(mod); } return; } } } // Stream else { get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushlstring(lua, &buffer[skip], r - skip); lua_call(lua, 2, 0); } } } /* on_read */
static void read_num(ParseInfo pi, const char *key) { char *start = pi->s; int64_t n = 0; long a = 0; long div = 1; long e = 0; int neg = 0; int eneg = 0; int big = 0; if ('-' == *pi->s) { pi->s++; neg = 1; } else if ('+' == *pi->s) { pi->s++; } if ('I' == *pi->s) { if (0 != strncmp("Infinity", pi->s, 8)) { if (pi->has_error) { call_error("number or other value", pi, __FILE__, __LINE__); } raise_error("number or other value", pi->str, pi->s); } pi->s += 8; if (neg) { if (pi->has_add_value) { call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key); } } else { if (pi->has_add_value) { call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key); } } return; } for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { if (big) { big++; } else { n = n * 10 + (*pi->s - '0'); if (NUM_MAX <= n) { big = 1; } } } if ('.' == *pi->s) { pi->s++; for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { a = a * 10 + (*pi->s - '0'); div *= 10; if (NUM_MAX <= div) { big = 1; } } } if ('e' == *pi->s || 'E' == *pi->s) { pi->s++; if ('-' == *pi->s) { pi->s++; eneg = 1; } else if ('+' == *pi->s) { pi->s++; } for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { e = e * 10 + (*pi->s - '0'); if (NUM_MAX <= e) { big = 1; } } } if (0 == e && 0 == a && 1 == div) { if (big) { char c = *pi->s; *pi->s = '\0'; if (pi->has_add_value) { call_add_value(pi->handler, rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(start)), key); } *pi->s = c; } else { if (neg) { n = -n; } if (pi->has_add_value) { call_add_value(pi->handler, LONG2NUM(n), key); } } return; } else { /* decimal */ if (big) { char c = *pi->s; *pi->s = '\0'; if (pi->has_add_value) { call_add_value(pi->handler, rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(start)), key); } *pi->s = c; } else { double d = (double)n + (double)a / (double)div; if (neg) { d = -d; } if (1 < big) { e += big - 1; } if (0 != e) { if (eneg) { e = -e; } d *= pow(10.0, e); } if (pi->has_add_value) { call_add_value(pi->handler, rb_float_new(d), key); } } } }