int main() { auto pool = std::make_shared<thread_pool>(4); auto a = std::make_shared<sample::sample_actor>(std::move(pool)); auto t1 = std::thread([a]() { for (int i = 0; i < 1000; i++) { std::stringstream ss; ss << "thread 1: " << i; auto fut = a->send_message<sample::message, sample::result>(std::move(sample::message{ss.str()})); fut.wait(); auto res = fut.get(); if (res.is_nothing()) { std::cout << "result is nothing, continue..." << std::endl; continue; } std::cout << res.get()->str << std::endl; } }); auto t2 = std::thread([a]() { for (int i = 0; i < 1000; i++) { std::stringstream ss; ss << "thread 2: " << i; auto fut = a->send_message<sample::message, sample::result>(std::move(sample::message{ss.str()})); fut.wait(); auto res = fut.get(); if (res.is_nothing()) { std::cout << "result is nothing, continue..." << std::endl; continue; } std::cout << res.get()->str << std::endl; } }); t1.join(); t2.join(); t1.detach(); t2.detach(); return 0; }
void load(sf2::JsonDeserializer& s, Entity& e) { static_assert(sf2::details::has_load<format::Json_reader,details::Component_base>::value, "missing load"); s.read_lambda([&](const auto& key){ auto mb_comp = e.manager().find_comp_info(key); if(mb_comp.is_nothing()) { DEBUG("Skipped unknown component "<<key); s.skip_obj(); return true; } auto& comp = mb_comp.get_or_throw(); auto& ecs_deserializer = static_cast<EcsDeserializer&>(s); if(ecs_deserializer.filter && !ecs_deserializer.filter(comp.type)) { DEBUG("Skipped filtered component "<<key); s.skip_obj(); return true; } auto comp_ptr = comp.get(e); if(!comp_ptr) { comp.add(e); comp_ptr = comp.get(e); } s.read_value(*comp_ptr); return true; }); }
// Returns true if the given signature could possibly match an invocation where // the given tag maps to the given value. static bool can_match_eq(value_t signature, value_t tag, value_t value) { int64_t paramc = get_signature_parameter_count(signature); // First look for a matching parameter in the signature. value_t match = nothing(); for (int64_t i = 0; i < paramc; i++) { value_t param = get_signature_parameter_at(signature, i); value_t tags = get_parameter_tags(param); if (in_array(tags, tag)) { match = param; break; } } if (is_nothing(match)) { // There was no matching parameter so this can only match if the signature // permits it as an extra argument. return get_signature_allow_extra(signature); } else { value_t guard = get_parameter_guard(match); if (get_guard_type(guard) == gtEq) { value_t eq_value = get_guard_value(guard); return value_identity_compare(value, eq_value); } else { return true; } } }
Music::Music(asset::istream stream) throw(Music_loading_failed) : _handle(nullptr, Mix_FreeMusic), _stream(std::make_unique<asset::istream>(std::move(stream))){ auto id = _stream->aid(); #ifndef EMSCRIPTEN SDL_RWops *rwops = SDL_AllocRW(); INVARIANT(rwops, "SDL_AllocRW failed"); rwops->seek = istream_seek; rwops->read = istream_read; rwops->write = NULL; rwops->close = istream_close; rwops->hidden.unknown.data1 = _stream.get(); _handle.reset(Mix_LoadMUS_RW(rwops, 1)); #else auto location = _stream->physical_location(); _stream.reset(); if(location.is_nothing()) return; _handle.reset(Mix_LoadMUS(location.get_or_throw().c_str())); #endif if(!_handle){ WARN("Mix_LoadMUS_RW ("<<id.str()<<") failed: " << Mix_GetError()); } }
// Gets the code from a method object, compiling the method if necessary. static value_t ensure_method_code(runtime_t *runtime, value_t method) { value_t code = get_method_code(method); if (is_nothing(code)) { TRY_SET(code, compile_method(runtime, method)); set_method_code(method, code); } return code; }
void Maybe_f_fmap(OPObject* _self, OPObject* _next, f_fmap_callback cb) { Maybe* self = (Maybe*) _self; Maybe* next = (Maybe*) _next; if (is_nothing(self) && self != next) { nothing(next); } cb(self->data, &next->data); }
int64 getMicroSecZeroInt64(const AbstractQoreNode* a) { if (is_nothing(a)) return 0; if (a->getType() == NT_DATE) return (reinterpret_cast<const DateTimeNode*>(a)->getRelativeMicroseconds()); return a->getAsBigInt(); }
void Maybe_m_bind(OPObject* _self, m_bind_callback cb, OPObject* _next) { Maybe* self = (Maybe*) _self; Maybe* next = (Maybe*) _next; if (is_nothing(self) && self != next) { nothing(next); } cb(self->data, _next); }
int64 getMsMinusOneBigInt(const AbstractQoreNode* a) { if (is_nothing(a)) return -1; if (a->getType() == NT_DATE) return reinterpret_cast<const DateTimeNode*>(a)->getRelativeMilliseconds(); return a->getAsBigInt(); }
// for getting relative time values or integer values int getSecMinusOneInt(const AbstractQoreNode* a) { if (is_nothing(a)) return -1; if (a->getType() == NT_DATE) return (int)(reinterpret_cast<const DateTimeNode*>(a)->getRelativeSeconds()); return a->getAsInt(); }
int getMsZeroInt(const AbstractQoreNode* a) { if (is_nothing(a)) return 0; if (a->getType() == NT_DATE) return (int)(reinterpret_cast<const DateTimeNode*>(a)->getRelativeMilliseconds()); return a->getAsInt(); }
value_t stack_validate(value_t self) { VALIDATE_FAMILY(ofStack, self); VALIDATE_FAMILY(ofStackPiece, get_stack_top_piece(self)); value_t current = get_stack_top_piece(self); while (!is_nothing(current)) { value_t stack = get_stack_piece_stack(current); VALIDATE(is_same_value(stack, self)); current = get_stack_piece_previous(current); } return success(); }
maybe<TOut> first_match_by(F f, const ContainerIn1& xs, const ContainerIn2& ys) { const auto maybe_idx = first_match_idx_by(f, xs, ys); if (is_nothing(maybe_idx)) { return nothing<TOut>(); } else { const auto idx = maybe_idx.unsafe_get_just(); return just(std::make_pair( elem_at_idx(idx, xs), elem_at_idx(idx, ys))); } }
value_t get_or_create_methodspace_selector_slice(runtime_t *runtime, value_t self, value_t selector) { value_t cache_ptr = get_methodspace_cache_ptr(self); value_t cache = get_freeze_cheat_value(cache_ptr); // Create the cache if it doesn't exist. if (is_nothing(cache)) { TRY_SET(cache, new_heap_id_hash_map(runtime, 128)); set_freeze_cheat_value(cache_ptr, cache); } // Create the selector-specific cache if it doesn't exits. value_t slice = get_id_hash_map_at(cache, selector); if (in_condition_cause(ccNotFound, slice)) { TRY_SET(slice, create_methodspace_selector_slice(runtime, self, selector)); TRY(set_id_hash_map_at(runtime, cache, selector, slice)); } return slice; }
// Binds an individual module fragment. static value_t bind_module_fragment(binding_context_t *context, value_t entry, value_t bound_fragment) { CHECK_FAMILY(ofModuleFragment, bound_fragment); value_t unbound_fragment = get_fragment_entry_fragment(entry); value_t imports = get_fragment_entry_imports(entry); if (!is_nothing(unbound_fragment)) { // This is a real fragment so we have to apply the entries. CHECK_FAMILY(ofUnboundModuleFragment, unbound_fragment); CHECK_EQ("fragment already bound", feUnbound, get_module_fragment_epoch(bound_fragment)); set_module_fragment_epoch(bound_fragment, feBinding); TRY(bind_module_fragment_imports(context, imports, bound_fragment)); TRY(apply_module_fragment_elements(context, unbound_fragment, bound_fragment)); } set_module_fragment_epoch(bound_fragment, feComplete); return success(); }
static value_t create_methodspace_selector_slice(runtime_t *runtime, value_t self, value_t selector) { TRY_DEF(result, new_heap_signature_map(runtime)); value_t current = self; while (!is_nothing(current)) { value_t methods = get_methodspace_methods(current); value_t entries = get_signature_map_entries(methods); for (int64_t i = 0; i < get_pair_array_buffer_length(entries); i++) { value_t signature = get_pair_array_buffer_first_at(entries, i); if (can_match_eq(signature, ROOT(runtime, selector_key), selector)) { value_t method = get_pair_array_buffer_second_at(entries, i); TRY(add_to_signature_map(runtime, result, signature, method)); } } current = get_methodspace_parent(current); } return result; }
java::lang::Object *toJava(const AbstractQoreNode *n, ExceptionSink *xsink) { if (is_nothing(n)) return 0; switch (n->getType()) { case NT_STRING: return toJava(*(reinterpret_cast<const QoreStringNode *>(n)), xsink); case NT_INT: { int64 v = reinterpret_cast<const QoreBigIntNode *>(n)->val; if ((v & 0xff) == v) return toJava((jbyte)v); if ((v & 0xffff) == v) return toJava((jshort)v); if ((v & 0xffffffff) == v) return toJava((jint)v); return toJava((jlong)v); } case NT_BOOLEAN: return toJava((jboolean)reinterpret_cast<const QoreBoolNode *>(n)->getValue()); case NT_FLOAT: return toJava((jdouble)reinterpret_cast<const QoreFloatNode *>(n)->f); case NT_OBJECT: { const QoreObject *o = reinterpret_cast<const QoreObject *>(n); // get java object PrivateDataRefHolder<QoreJavaPrivateData> jo(o, CID_OBJECT, xsink); if (!jo) { if (!*xsink) xsink->raiseException("JAVA-UNSUPPORTED-TYPE", "cannot convert from Qore class '%s' to a Java value; '%s' does not inherit java::lang::Object", o->getClassName(), o->getClassName()); return 0; } return jo->getObject(); } } xsink->raiseException("JAVA-UNSUPPORTED-TYPE", "cannot convert from Qore '%s' to a Java value", get_type_name(n)); return 0; }
// Add synthetic fragment entries corresponding to imported fragments where // there is no real fragment to import the fragment into. static value_t build_synthetic_fragment_entries(binding_context_t *context) { // Keep adding synthetic modules as long as changes are being made to the // map. We'll scan through the fragments currently in the map, then scan // through their imports, and for each check that the fragment that should // receive the import exists. If it doesn't it is created. loop: do { id_hash_map_iter_t module_iter; id_hash_map_iter_init(&module_iter, context->fragment_entry_map); while (id_hash_map_iter_advance(&module_iter)) { value_t module_path; value_t module_fragments; // Scan through the fragments. id_hash_map_iter_get_current(&module_iter, &module_path, &module_fragments); id_hash_map_iter_t fragment_iter; id_hash_map_iter_init(&fragment_iter, module_fragments); while (id_hash_map_iter_advance(&fragment_iter)) { value_t stage; value_t entry; id_hash_map_iter_get_current(&fragment_iter, &stage, &entry); value_t unbound_fragment = get_fragment_entry_fragment(entry); // If there is no fragment associated with this entry it is synthetic // and hence we're done. if (is_nothing(unbound_fragment)) continue; // Scan through the fragment's imports and ensure that their import // targets have been created. value_t imports = get_fragment_entry_imports(entry); for (size_t i = 0; i < get_array_buffer_length(imports); i++) { value_t import = get_array_buffer_at(imports, i); value_t import_fragment_stage = get_identifier_stage(import); if (!value_identity_compare(import_fragment_stage, present_stage())) // We'll record past imports but ignore them for the purposes of // closing the import map since they're redundant. continue; value_t import_module_path = get_identifier_path(import); value_t import_module = get_id_hash_map_at(context->fragment_entry_map, import_module_path); // Scan through the fragments of the imported module. id_hash_map_iter_t imported_fragment_iter; id_hash_map_iter_init(&imported_fragment_iter, import_module); bool has_changed_anything = false; while (id_hash_map_iter_advance(&imported_fragment_iter)) { value_t import_stage; value_t import_entry; id_hash_map_iter_get_current(&imported_fragment_iter, &import_stage, &import_entry); value_t target_stage = add_stage_offsets(import_stage, stage); // Ensure that there is a target entry to add the import to. If it // already exists this is a no-op, if it doesn't a synthetic entry // is created. TRY_DEF(target_entry, binding_context_ensure_fragment_entry( context, target_stage, module_path, nothing(), &has_changed_anything)); value_t target_imports = get_fragment_entry_imports(target_entry); value_t import_ident = get_fragment_entry_identifier(import_entry); if (!in_array_buffer(target_imports, import_ident)) { has_changed_anything = true; TRY(add_to_array_buffer(get_ambience_runtime(context->ambience), target_imports, import_ident)); } } // If any changes were made we have to start over. if (has_changed_anything) goto loop; } } } } while (false); return success(); }
// FIXME: use ct_setparam to avoid copying data void command::set_params(sybase_query &query, const QoreListNode *args, ExceptionSink *xsink) { unsigned nparams = query.param_list.size(); for (unsigned i = 0; i < nparams; ++i) { if (query.param_list[i] == 'd') continue; const AbstractQoreNode *val = args ? args->retrieve_entry(i) : NULL; CS_DATAFMT datafmt; memset(&datafmt, 0, sizeof(datafmt)); datafmt.status = CS_INPUTVALUE; datafmt.namelen = CS_NULLTERM; sprintf(datafmt.name, "@par%d", int(i + 1)); datafmt.maxlength = CS_UNUSED; datafmt.count = 1; CS_RETCODE err = CS_FAIL; if (!val || is_null(val) || is_nothing(val)) { #ifdef FREETDS // it seems to be necessary to specify a type like // this to get a null value to be bound with freetds datafmt.datatype = CS_CHAR_TYPE; datafmt.format = CS_FMT_NULLTERM; datafmt.maxlength = 1; #endif // SQL NULL value err = ct_param(m_cmd, &datafmt, 0, CS_UNUSED, -1); if (err != CS_SUCCEED) { m_conn.do_exception(xsink, "DBI:SYBASE:EXEC-ERROR", "ct_param() for 'null' failed for parameter %u with error %d", i, (int)err); return; } continue; } qore_type_t ntype = val ? val->getType() : 0; switch (ntype) { case NT_STRING: { const QoreStringNode *str = reinterpret_cast<const QoreStringNode *>(val); // ensure we bind with the proper encoding for the connection TempEncodingHelper s(str, m_conn.getEncoding(), xsink); if (!s) throw ss::Error("DBI:SYBASE:EXEC-ERROR", "encoding"); int slen = s->strlen(); datafmt.datatype = CS_CHAR_TYPE; datafmt.format = CS_FMT_NULLTERM; // NOTE: setting large sizes here like 2GB works for sybase ctlib, // not for freetds datafmt.maxlength = slen + 1; err = ct_param(m_cmd, &datafmt, (CS_VOID*)s->getBuffer(), slen, 0); break; } case NT_NUMBER: { QoreStringValueHelper vh(val); int slen = vh->strlen(); datafmt.datatype = CS_CHAR_TYPE; datafmt.format = CS_FMT_NULLTERM; datafmt.maxlength = slen + 1; err = ct_param(m_cmd, &datafmt, (CS_VOID *)vh->getBuffer(), slen, 0); break; } case NT_DATE: { const DateTimeNode *date = reinterpret_cast<const DateTimeNode *>(val); CS_DATETIME dt; ss::Conversions conv; if (conv.DateTime_to_DATETIME(date, dt, xsink)) throw ss::Error("DBI:SYBASE:EXEC-ERROR", "can't convert date"); datafmt.datatype = CS_DATETIME_TYPE; err = ct_param(m_cmd, &datafmt, &dt, sizeof(dt), 0); break; } case NT_INT: { #ifdef CS_BIGINT_TYPE datafmt.datatype = CS_BIGINT_TYPE; err = ct_param(m_cmd, &datafmt, &(const_cast<QoreBigIntNode *>(reinterpret_cast<const QoreBigIntNode *>(val))->val), sizeof(int64), 0); #else int64 ival = reinterpret_cast<const QoreBigIntNode *>(val)->val; // if it's a 32-bit integer, bind as integer if (ival <= 2147483647 && ival >= -2147483647) { datafmt.datatype = CS_INT_TYPE; CS_INT vint = ival; err = ct_param(m_cmd, &datafmt, &vint, sizeof(CS_INT), 0); } else { // bind as float CS_FLOAT fval = ival; datafmt.datatype = CS_FLOAT_TYPE; err = ct_param(m_cmd, &datafmt, &fval, sizeof(CS_FLOAT), 0); } #endif break; } case NT_BOOLEAN: { // Seems mssql doesn't like CS_BIT_TYPE for some reason. // Replacing by CS_INT_TYPE helps // // The "BIT" code is supposed to be like this: // datafmt.datatype = CS_BIT_TYPE; // err = ct_param(m_cmd, &datafmt, &bval, sizeof(bval), 0); // ... but it doesn't work CS_BIT bval = reinterpret_cast<const QoreBoolNode *>(val)->getValue(); datafmt.datatype = CS_INT_TYPE; int64 ival = bval ? 1 : 0; err = ct_param(m_cmd, &datafmt, &ival, sizeof(ival), 0); break; } case NT_FLOAT: { CS_FLOAT fval = reinterpret_cast<const QoreFloatNode *>(val)->f; datafmt.datatype = CS_FLOAT_TYPE; err = ct_param(m_cmd, &datafmt, &fval, sizeof(CS_FLOAT), 0); break; } case NT_BINARY: { const BinaryNode *b = reinterpret_cast<const BinaryNode *>(val); datafmt.datatype = CS_BINARY_TYPE; datafmt.maxlength = b->size(); datafmt.count = 1; err = ct_param(m_cmd, &datafmt, (void *)b->getPtr(), b->size(), 0); break; } default: m_conn.do_exception(xsink, "DBI:SYBASE:BIND-ERROR", "do not know how to bind values of type '%s'", val->getTypeName()); return; } // switch(ntype) if (err != CS_SUCCEED) { m_conn.do_exception(xsink, "DBI:SYBASE:EXEC-ERROR", "ct_param() for binary parameter %u failed with error", i, (int)err); } } }
bool QoreValue::isNullOrNothing() const { return type == QV_Node && (is_nothing(v.n) || is_null(v.n)); }
QoreHashNode* qore_httpclient_priv::send_internal(ExceptionSink* xsink, const char* mname, const char* meth, const char* mpath, const QoreHashNode* headers, const void* data, unsigned size, const ResolvedCallReferenceNode* send_callback, bool getbody, QoreHashNode* info, int timeout_ms, const ResolvedCallReferenceNode* recv_callback, QoreObject* obj) { assert(!(data && send_callback)); // check if method is valid method_map_t::const_iterator i = method_map.find(meth); if (i == method_map.end()) { i = additional_methods_map.find(meth); if (i == additional_methods_map.end()) { xsink->raiseException("HTTP-CLIENT-METHOD-ERROR", "HTTP method (%s) not recognized.", meth); return 0; } } // make sure the capitalized version is used meth = i->first.c_str(); bool bodyp = i->second; // use the default timeout value if a zero value is given in the call if (!timeout_ms) timeout_ms = timeout; SafeLocker sl(msock->m); Queue* cb_queue = msock->socket->getQueue(); ReferenceHolder<QoreHashNode> nh(new QoreHashNode, xsink); bool keep_alive = true; bool transfer_encoding = false; if (headers) { ConstHashIterator hi(headers); while (hi.next()) { // if one of the mandatory headers is found, then ignore it strcase_set_t::iterator si = header_ignore.find(hi.getKey()); if (si != header_ignore.end()) continue; // otherwise set the value in the hash const AbstractQoreNode* n = hi.getValue(); if (!is_nothing(n)) { if (!strcasecmp(hi.getKey(), "transfer-encoding")) transfer_encoding = true; nh->setKeyValue(hi.getKey(), n->refSelf(), xsink); if (!strcasecmp(hi.getKey(), "connection") || (proxy_connection.has_url() && !strcasecmp(hi.getKey(), "proxy-connection"))) { const char* conn = get_string_header(xsink, **nh, hi.getKey(), true); if (*xsink) { disconnect_unlocked(); return 0; } if (conn && !strcasecmp(conn, "close")) keep_alive = false; } } } } // add default headers if they weren't overridden for (header_map_t::const_iterator hdri = default_headers.begin(), e = default_headers.end(); hdri != e; ++hdri) { // look in original headers to see if the key was already given if (headers) { bool skip = false; ConstHashIterator hi(headers); while (hi.next()) { if (!strcasecmp(hi.getKey(), hdri->first.c_str())) { skip = true; break; } } if (skip) continue; } // if there is no message body then do not send the "content-type" header if (!data && !send_callback && !strcmp(hdri->first.c_str(), "Content-Type")) continue; nh->setKeyValue(hdri->first.c_str(), new QoreStringNode(hdri->second.c_str()), xsink); } // set Transfer-Encoding: chunked if used with a send callback if (send_callback && !transfer_encoding) nh->setKeyValue("Transfer-Encoding", new QoreStringNode("chunked"), xsink); if (!connection.username.empty()) { // check for "Authorization" header bool auth_found = false; if (headers) { ConstHashIterator hi(headers); while (hi.next()) { if (!strcasecmp(hi.getKey(), "Authorization")) { auth_found = true; break; } } } if (!auth_found) { QoreString tmp; tmp.sprintf("%s:%s", connection.username.c_str(), connection.password.c_str()); QoreStringNode* auth_str = new QoreStringNode("Basic "); auth_str->concatBase64(&tmp); nh->setKeyValue("Authorization", auth_str, xsink); } } // save original HTTP method in case we have to issue a CONNECT request to a proxy for an HTTPS connection const char* meth_orig = meth; bool use_proxy_connect = false; const char* proxy_path = 0; ReferenceHolder<QoreHashNode> proxy_headers(xsink); QoreString hostport; if (!proxy_connected && proxy_connection.has_url()) { // use CONNECT if we need to make an HTTPS connection from the proxy if (!proxy_connection.ssl && connection.ssl) { meth = "CONNECT"; use_proxy_connect = true; hostport.concat(connection.host); if (connection.port) hostport.sprintf(":%d", connection.port); proxy_path = hostport.getBuffer(); proxy_headers = new QoreHashNode; proxy_headers->setKeyValue("Host", new QoreStringNode(hostport), xsink); addProxyAuthorization(headers, **proxy_headers, xsink); } else addProxyAuthorization(headers, **nh, xsink); } bool host_override = headers ? (bool)headers->getKeyValue("Host") : false; int code; ReferenceHolder<QoreHashNode> ans(xsink); int redirect_count = 0; const char* location = 0; // flag for aborted chunked sends bool send_aborted = false; while (true) { // set host field automatically if not overridden if (!host_override) nh->setKeyValue("Host", getHostHeaderValue(), xsink); if (info) { info->setKeyValue("headers", nh->copy(), xsink); if (*xsink) return 0; } //printd(5, "qore_httpclient_priv::send_internal() meth=%s proxy_path=%s mpath=%s upc=%d\n", meth, proxy_path ? proxy_path : "n/a", mpath, use_proxy_connect); // send HTTP message and get response header if (use_proxy_connect) ans = sendMessageAndGetResponse(meth, proxy_path, *(*proxy_headers), 0, 0, 0, info, true, timeout_ms, code, send_aborted, xsink); else ans = sendMessageAndGetResponse(meth, mpath, *(*nh), data, size, send_callback, info, false, timeout_ms, code, send_aborted, xsink); if (!ans) return 0; if (info) { info->setKeyValue("response-headers", ans->refSelf(), xsink); if (*xsink) return 0; } if (code >= 300 && code < 400) { disconnect_unlocked(); host_override = false; const QoreStringNode* mess = reinterpret_cast<QoreStringNode*>(ans->getKeyValue("status_message")); const QoreStringNode* loc = get_string_header_node(xsink, **ans, "location"); if (*xsink) return 0; const char* location = loc && !loc->empty() ? loc->getBuffer() : 0; if (!location) { sl.unlock(); const char* msg = mess ? mess->getBuffer() : "<no message>"; xsink->raiseException("HTTP-CLIENT-REDIRECT-ERROR", "no redirect location given for status code %d: message: '%s'", code, msg); return 0; } if (cb_queue) do_redirect_event(cb_queue, msock->socket->getObjectIDForEvents(), loc, mess); if (++redirect_count > max_redirects) break; if (set_url_unlocked(location, xsink)) { sl.unlock(); const char* msg = mess ? mess->getBuffer() : "<no message>"; xsink->raiseException("HTTP-CLIENT-REDIRECT-ERROR", "exception occurred while setting URL for new location '%s' (code %d: message: '%s')", location, code, msg); return 0; } // set redirect info in info hash if present if (info) { QoreString tmp; tmp.sprintf("redirect-%d", redirect_count); info->setKeyValue(tmp.getBuffer(), loc->refSelf(), xsink); if (*xsink) return 0; tmp.clear(); tmp.sprintf("redirect-message-%d", redirect_count); info->setKeyValue(tmp.getBuffer(), mess ? mess->refSelf() : 0, xsink); } // FIXME: reset send callback and send_aborted here // set mpath to NULL so that the new path will be taken mpath = 0; continue; } else if (use_proxy_connect) { meth = meth_orig; use_proxy_connect = false; proxy_path = 0; if (msock->socket->upgradeClientToSSL(0, 0, xsink)) { disconnect_unlocked(); return 0; } proxy_connected = true; // remove "Proxy-Authorization" header nh->removeKey("Proxy-Authorization", xsink); if (*xsink) return 0; // try again as if we are talking directly to the client continue; } break; } if (code >= 300 && code < 400) { sl.unlock(); const char* mess = get_string_header(xsink, **ans, "status_message"); if (!mess) mess = "<no message>"; if (!location) location = "<no location>"; xsink->raiseException("HTTP-CLIENT-MAXIMUM-REDIRECTS-EXCEEDED", "maximum redirections (%d) exceeded; redirect code %d to '%s' ignored (message: '%s')", max_redirects, code, location, mess); return 0; } // process content-type const QoreStringNode* v = get_string_header_node(xsink, **ans, "content-type"); if (*xsink) { disconnect_unlocked(); return 0; } //ans->getKeyValue("content-type"); // see if there is a character set specification in the content-type header if (v) { // save original content-type header before processing ans->setKeyValue("_qore_orig_content_type", v->refSelf(), xsink); const char* str = v->getBuffer(); const char* p = strstr(str, "charset="); if (p && (p == str || *(p - 1) == ';' || *(p - 1) == ' ')) { // move p to start of encoding const char* c = p + 8; char quote = '\0'; if (*c == '\'' || *c == '"') { quote = *c; ++c; } QoreString enc; while (*c && *c != ';' && *c != ' ' && *c != quote) enc.concat(*(c++)); if (quote && *c == quote) ++c; printd(5, "QoreHttpClientObject::send_intern() setting encoding to '%s' from content-type header: '%s' (cs=%p c=%p %d)\n", enc.getBuffer(), str, p + 8, c); // set new encoding msock->socket->setEncoding(QEM.findCreate(&enc)); // strip from content-type QoreStringNode* nc = new QoreStringNode(); // skip any spaces before the charset= while (p != str && (*(p - 1) == ' ' || *(p - 1) == ';')) p--; if (p != str) nc->concat(str, p - str); if (*c) nc->concat(c); ans->setKeyValue("content-type", nc, xsink); str = nc->getBuffer(); } // split into a list if ";" characters are present p = strchr(str, ';'); if (p) { bool multipart = false; QoreListNode* l = new QoreListNode(); do { // skip whitespace while (*str == ' ') str++; if (str != p) { int len = p - str; check_headers(str, len, multipart, *(*ans), msock->socket->getEncoding(), xsink); l->push(new QoreStringNode(str, len, msock->socket->getEncoding())); } str = p + 1; } while ((p = strchr(str, ';'))); // skip whitespace while (*str == ' ') str++; // add last field if (*str) { check_headers(str, strlen(str), multipart, *(*ans), msock->socket->getEncoding(), xsink); l->push(new QoreStringNode(str, msock->socket->getEncoding())); } ans->setKeyValue("content-type", l, xsink); } } // send headers to recv_callback if (recv_callback && msock->socket->priv->runHeaderCallback(xsink, mname, *recv_callback, &msock->m, *ans, send_aborted, obj)) return 0; AbstractQoreNode* body = 0; const char* content_encoding = 0; // do not read any message body for messages that cannot have one // rfc 2616 4.4 p1 (http://tools.ietf.org/html/rfc2616#section-4.4) /* 1.Any response message which "MUST NOT" include a message-body (such as the 1xx, 204, and 304 responses and any response to a HEAD request) is always terminated by the first empty line after the header fields, regardless of the entity-header fields present in the message. */ //printd(5, "qore_httpclient_priv::send_internal() this: %p bodyp: %d code: %d\n", this, bodyp, code); qore_uncompress_to_string_t dec = 0; // code >= 300 && < 400 is already handled above if (bodyp && (code < 100 || code >= 200) && code != 204) { // see if we should do a binary or string read content_encoding = get_string_header(xsink, **ans, "content-encoding"); if (*xsink) { disconnect_unlocked(); return 0; } if (content_encoding) { // check for misuse (? not sure: check RFCs again) of this field by including a character encoding value if (!strncasecmp(content_encoding, "iso", 3) || !strncasecmp(content_encoding, "utf-", 4)) { msock->socket->setEncoding(QEM.findCreate(content_encoding)); content_encoding = 0; } else if (!recv_callback) { // only decode message bodies automatically if there is no receive callback if (!strcasecmp(content_encoding, "deflate") || !strcasecmp(content_encoding, "x-deflate")) dec = qore_inflate_to_string; else if (!strcasecmp(content_encoding, "gzip") || !strcasecmp(content_encoding, "x-gzip")) dec = qore_gunzip_to_string; else if (!strcasecmp(content_encoding, "bzip2") || !strcasecmp(content_encoding, "x-bzip2")) dec = qore_bunzip2_to_string; } } const char* te = get_string_header(xsink, **ans, "transfer-encoding"); if (*xsink) { disconnect_unlocked(); return 0; } // get response body, if any const char* cl = get_string_header(xsink, **ans, "content-length"); if (*xsink) { disconnect_unlocked(); return 0; } int len = cl ? atoi(cl) : 0; if (cl && cb_queue) do_content_length_event(cb_queue, msock->socket->getObjectIDForEvents(), len); if (te && !strcasecmp(te, "chunked")) { // check for chunked response body if (cb_queue) do_event(cb_queue, msock->socket->getObjectIDForEvents(), QORE_EVENT_HTTP_CHUNKED_START); ReferenceHolder<QoreHashNode> nah(xsink); if (recv_callback) { if (content_encoding) msock->socket->priv->readHttpChunkedBodyBinary(timeout_ms, xsink, QORE_SOURCE_HTTPCLIENT, recv_callback, &msock->m, obj); else msock->socket->priv->readHttpChunkedBody(timeout_ms, xsink, QORE_SOURCE_HTTPCLIENT, recv_callback, &msock->m, obj); } else { if (content_encoding) nah = msock->socket->priv->readHttpChunkedBodyBinary(timeout_ms, xsink, QORE_SOURCE_HTTPCLIENT); else nah = msock->socket->priv->readHttpChunkedBody(timeout_ms, xsink, QORE_SOURCE_HTTPCLIENT); } if (cb_queue) do_event(cb_queue, msock->socket->getObjectIDForEvents(), QORE_EVENT_HTTP_CHUNKED_END); if (!nah && !recv_callback) { if (!msock->socket->isOpen()) disconnect_unlocked(); return 0; } if (info) { info->setKeyValue("chunked", &True, xsink); if (*xsink) return 0; } if (!recv_callback) { body = nah->takeKeyValue("body"); ans->merge(*nah, xsink); } } else if (getbody || len) { if (content_encoding) { SimpleRefHolder<BinaryNode> bobj(msock->socket->recvBinary(len, timeout_ms, xsink)); if (!(*xsink) && bobj) body = bobj.release(); } else { QoreStringNodeHolder bstr(msock->socket->recv(len, timeout_ms, xsink)); if (!(*xsink) && bstr) body = bstr.release(); } if (*xsink && !msock->socket->isOpen()) disconnect_unlocked(); //printf("body=%p\n", body); } } // check for connection: close header if (!keep_alive) disconnect_unlocked(); else { const char* conn = get_string_header(xsink, **ans, "connection", true); if (*xsink) { disconnect_unlocked(); return 0; } if (conn && !strcasecmp(conn, "close")) disconnect_unlocked(); } sl.unlock(); // for content-encoding processing we can run unlocked // add body to result hash and process content encoding if necessary if (body) { if (content_encoding) { if (!dec) { if (!recv_callback) { xsink->raiseException("HTTP-CLIENT-RECEIVE-ERROR", "don't know how to handle content-encoding '%s'", content_encoding); ans = 0; } } else { BinaryNode* bobj = reinterpret_cast<BinaryNode*>(body); QoreStringNode* str = dec(bobj, msock->socket->getEncoding(), xsink); bobj->deref(); body = str; } } if (body) { // send data to recv_callback (already unlocked) if (recv_callback) { ReferenceHolder<> bh(body, xsink); if (msock->socket->priv->runDataCallback(xsink, mname, *recv_callback, 0, body, false) || msock->socket->priv->runHeaderCallback(xsink, mname, *recv_callback, 0, 0, send_aborted, obj)) return 0; } else ans->setKeyValue("body", body, xsink); } } // do not throw an exception if a receive callback is used if (!recv_callback && !*xsink && (code < 100 || code >= 300)) { const char* mess = get_string_header(xsink, **ans, "status_message"); if (!mess) mess = "<no message>"; assert(!*xsink); xsink->raiseExceptionArg("HTTP-CLIENT-RECEIVE-ERROR", ans.release(), "HTTP status code %d received: message: %s", code, mess); return 0; } return *xsink || recv_callback ? 0 : ans.release(); }
// Validates that the stack looks correct after execution completes normally. static void validate_stack_on_normal_exit(frame_t *frame) { value_t stack = get_stack_piece_stack(frame->stack_piece); CHECK_TRUE("leftover barriers", is_nothing(get_stack_top_barrier(stack))); }
int ForEachStatement::execRef(QoreValue& return_value, ExceptionSink* xsink) { int rc = 0; // instantiate local variables LVListInstantiator lvi(lvars, xsink); ParseReferenceNode* r = reinterpret_cast<ParseReferenceNode*>(list); // here we get the runtime reference ReferenceHolder<ReferenceNode> vr(r->evalToRef(xsink), xsink); if (*xsink) return 0; // get the current value of the lvalue expression ReferenceHolder<AbstractQoreNode> tlist(vr->eval(xsink), xsink); if (!code || *xsink || is_nothing(*tlist)) return 0; QoreListNode* l_tlist = tlist->getType() == NT_LIST ? reinterpret_cast<QoreListNode*>(*tlist) : 0; if (l_tlist && l_tlist->empty()) return 0; // execute "foreach" body ReferenceHolder<AbstractQoreNode> ln(0, xsink); unsigned i = 0; if (l_tlist) ln = new QoreListNode; while (true) { { LValueHelper n(var, xsink); if (!n) return 0; // assign variable to current value in list if (n.assign(l_tlist ? l_tlist->get_referenced_entry(i) : tlist.release())) return 0; } // set offset in thread-local data for "$#" ImplicitElementHelper eh(l_tlist ? (int)i : 0); // execute "for" body rc = code->execImpl(return_value, xsink); if (*xsink) return 0; // get value of foreach variable AbstractQoreNode* nv = var->eval(xsink); if (*xsink) return 0; // assign new value to temporary variable for later assignment to referenced lvalue if (l_tlist) reinterpret_cast<QoreListNode*>(*ln)->push(nv); else ln = nv; if (rc == RC_BREAK) { // assign remaining values to list unchanged if (l_tlist) while (++i < l_tlist->size()) reinterpret_cast<QoreListNode*>(*ln)->push(l_tlist->get_referenced_entry(i)); rc = 0; break; } if (rc == RC_RETURN) break; else if (rc == RC_CONTINUE) rc = 0; i++; // break out of loop if appropriate if (!l_tlist || i == l_tlist->size()) break; } // write the value back to the lvalue LValueHelper val(**vr, xsink); if (!val) return 0; if (val.assign(ln.release())) return 0; return rc; }
int ForEachStatement::execImpl(QoreValue& return_value, ExceptionSink* xsink) { if (is_ref) return execRef(return_value, xsink); if (is_keys) return execKeys(return_value, xsink); // instantiate local variables LVListInstantiator lvi(lvars, xsink); // get list evaluation (although may be a single node) ReferenceHolder<AbstractQoreNode> tlist(list->eval(xsink), xsink); if (!code || *xsink || is_nothing(*tlist)) return 0; qore_type_t t = tlist->getType(); QoreListNode* l_tlist = t == NT_LIST ? reinterpret_cast<QoreListNode*>(*tlist) : 0; if (l_tlist) { if (l_tlist->empty()) return 0; } else if (t == NT_OBJECT) { // check for an object derived from AbstractIterator AbstractIteratorHelper aih(xsink, "map operator", reinterpret_cast<QoreObject*>(*tlist)); if (*xsink) return 0; if (aih) return execIterator(aih, return_value, xsink); } // execute "foreach" body unsigned i = 0; int rc = 0; while (true) { { LValueHelper n(var, xsink); if (!n) break; // assign variable to current value in list if (n.assign(l_tlist ? l_tlist->get_referenced_entry(i) : tlist.release())) break; } // set offset in thread-local data for "$#" ImplicitElementHelper eh(l_tlist ? (int)i : 0); // execute "foreach" body if (((rc = code->execImpl(return_value, xsink)) == RC_BREAK) || *xsink) { rc = 0; break; } if (rc == RC_RETURN) break; else if (rc == RC_CONTINUE) rc = 0; i++; // if the argument is not a list or list iteration is done, then break if (!l_tlist || i == l_tlist->size()) break; } return rc; }
bool QoreValue::isNothing() const { return type == QV_Node && is_nothing(v.n); }
TEST(tagged, nothing) { value_t not = nothing(); ASSERT_EQ(ENCODED_NOTHING, not.encoded); ASSERT_TRUE(is_nothing(not)); }