static Variant new_socket_connect(const HostURL &hosturl, double timeout, Variant &errnum, Variant &errstr) { int domain = AF_UNSPEC; int type = SOCK_STREAM; auto const& scheme = hosturl.getScheme(); SmartPtr<Socket> sock; SmartPtr<SSLSocket> sslsock; std::string sockerr; int error; if (scheme == "udp" || scheme == "udg") { type = SOCK_DGRAM; } else if (scheme == "unix") { domain = AF_UNIX; } int fd = -1; if (domain == AF_UNIX) { sockaddr_storage sa_storage; struct sockaddr *sa_ptr; size_t sa_size; fd = socket(domain, type, 0); sock = makeSmartPtr<Socket>( fd, domain, hosturl.getHost().c_str(), hosturl.getPort()); if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(), hosturl.getPort(), sa_ptr, sa_size)) { // set_sockaddr raises its own warning on failure return false; } if (connect_with_timeout(fd, sa_ptr, sa_size, timeout, hosturl, sockerr, error) != 0) { SOCKET_ERROR(sock, sockerr.c_str(), error); errnum = sock->getLastError(); errstr = HHVM_FN(socket_strerror)(sock->getLastError()); return false; } } else { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = domain; hints.ai_socktype = type; auto port = folly::to<std::string>(hosturl.getPort()); auto host = hosturl.getHost(); struct addrinfo *aiHead; int errcode = getaddrinfo(host.c_str(), port.c_str(), &hints, &aiHead); if (errcode != 0) { errstr = String(gai_strerror(errcode), CopyString); return false; } SCOPE_EXIT { freeaddrinfo(aiHead); }; for (struct addrinfo *ai = aiHead; ai != nullptr; ai = ai->ai_next) { domain = ai->ai_family; fd = socket(domain, ai->ai_socktype, ai->ai_protocol); if (fd == -1) { continue; } if (connect_with_timeout(fd, ai->ai_addr, ai->ai_addrlen, timeout, hosturl, sockerr, error) == 0) { break; } close(fd); fd = -1; } sslsock = SSLSocket::Create(fd, domain, hosturl, timeout); if (sslsock) { sock = sslsock; } else { sock = makeSmartPtr<Socket>(fd, domain, hosturl.getHost().c_str(), hosturl.getPort()); } } if (!sock->valid()) { SOCKET_ERROR(sock, sockerr.empty() ? "unable to create socket" : sockerr.c_str(), error); errnum = sock->getLastError(); errstr = HHVM_FN(socket_strerror)(sock->getLastError()); return false; } if (sslsock && !sslsock->onConnect()) { raise_warning("Failed to enable crypto"); return false; } return Variant(std::move(sock)); }
Variant appendOrPrependFilter(const Resource& stream, const String& filtername, const Variant& readwrite, const Variant& params, bool append) { const char* func_name = append ? "stream_filter_append()" : "stream_filter_prepend()"; if (!m_registeredFilters.exists(filtername)) { raise_warning("%s: unable to locate filter \"%s\"", func_name, filtername.data()); return false; } auto file = cast<File>(stream); int mode = readwrite.toInt32(); if (!mode) { auto str = file->getMode(); /* The documentation says a read filter is only created for 'r' and '+' * modes, but the implementation will always create one unless * STREAM_FILTER_WRITE is passed. * * This branch is only executed if no STREAM_FILTER* args were passed, * so we always create a READ filter. */ mode = k_STREAM_FILTER_READ; if (str.find('+') != -1 || str.find('w') != -1 || str.find('a') != -1) { mode |= k_STREAM_FILTER_WRITE; } } if (!(mode & k_STREAM_FILTER_ALL)) { return false; } // If it's ALL we create two resources, but only return one - this // matches Zend, and is the documented behavior. req::ptr<StreamFilter> ret; if (mode & k_STREAM_FILTER_READ) { auto resource = createInstance(func_name, file, filtername, params); if (!resource) { return false; } ret = resource; if (append) { file->appendReadFilter(resource); } else { file->prependReadFilter(resource); } } if (mode & k_STREAM_FILTER_WRITE) { auto resource = createInstance(func_name, file, filtername, params); if (!resource) { return false; } ret = resource; if (append) { file->appendWriteFilter(resource); } else { file->prependWriteFilter(resource); } } return Variant(std::move(ret)); }
static Variant warn_non_object() { raise_warning("Cannot access property on non-object"); return null; }
bool HttpProtocol::ProxyRequest(Transport *transport, bool force, const std::string &url, int &code, std::string &error, StringBuffer &response, HeaderMap *extraHeaders /* = NULL */) { ASSERT(transport); if (transport->headersSent()) { raise_warning("Cannot proxy request - headers already sent"); return false; } HeaderMap requestHeaders; transport->getHeaders(requestHeaders); if (extraHeaders) { for (HeaderMap::const_iterator iter = extraHeaders->begin(); iter != extraHeaders->end(); ++iter) { vector<string> &values = requestHeaders[iter->first]; values.insert(values.end(), iter->second.begin(), iter->second.end()); } } int size = 0; const char *data = NULL; if (transport->getMethod() == Transport::POST) { data = (const char *)transport->getPostData(size); } code = 0; // HTTP status of curl or 0 for "no server response code" vector<String> responseHeaders; HttpClient http; if (data && size) { code = http.post(url.c_str(), data, size, response, &requestHeaders, &responseHeaders); } else { code = http.get(url.c_str(), response, &requestHeaders, &responseHeaders); } if (code == 0) { if (!force) return false; // so we can retry Logger::Error("Unable to proxy %s: %s", url.c_str(), http.getLastError().c_str()); error = http.getLastError(); return true; } for (unsigned int i = 0; i < responseHeaders.size(); i++) { String &header = responseHeaders[i]; if (header.find(":") != String::npos && header.find("Content-Length: ") != 0 && header.find("Client-Transfer-Encoding: ") != 0 && header.find("Transfer-Encoding: ") != 0 && header.find("Connection: ") != 0) { transport->addHeader(header.data()); } } const char* respData = response.data(); if (!respData) { respData = ""; } Logger::Verbose("Response code was %d when proxying %s", code, url.c_str()); return true; }
static void HHVM_FUNCTION(gc_enable) { if (RuntimeOption::EnableHipHopSyntax) { raise_warning("HipHop currently does not support circular reference " "collection"); } }
bool SSLSocket::handleError(int64_t nr_bytes, bool is_init) { char esbuf[512]; std::string ebuf; unsigned long ecode; bool retry = true; int err = SSL_get_error(m_data->m_handle, nr_bytes); switch (err) { case SSL_ERROR_ZERO_RETURN: /* SSL terminated (but socket may still be active) */ retry = false; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* re-negotiation, or perhaps the SSL layer needs more * packets: retry in next iteration */ errno = EAGAIN; retry = (is_init || m_data->m_is_blocked); break; case SSL_ERROR_SYSCALL: if (ERR_peek_error() == 0) { if (nr_bytes == 0) { if (ERR_get_error()) { raise_warning("SSL: fatal protocol error"); } SSL_set_shutdown(m_data->m_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); setEof(true); retry = false; } else { raise_warning("SSL: %s", folly::errnoStr(errno).c_str()); retry = false; } break; } /* fall through */ default: /* some other error */ ecode = ERR_get_error(); switch (ERR_GET_REASON(ecode)) { case SSL_R_NO_SHARED_CIPHER: raise_warning("SSL_R_NO_SHARED_CIPHER: no suitable shared cipher " "could be used. This could be because the server is " "missing an SSL certificate (local_cert context " "option)"); retry = false; break; default: do { // NULL is automatically added ERR_error_string_n(ecode, esbuf, sizeof(esbuf)); if (!ebuf.empty()) { ebuf += '\n'; } ebuf += esbuf; } while ((ecode = ERR_get_error()) != 0); raise_warning("SSL operation failed with code %d. %s%s", err, !ebuf.empty() ? "OpenSSL Error messages:\n" : "", !ebuf.empty() ? ebuf.c_str() : ""); } retry = false; errno = 0; } return retry; }
bool SSLSocket::applyVerificationPolicy(X509 *peer) { /* verification is turned off */ if (!m_context[s_verify_peer].toBoolean()) { return true; } if (peer == nullptr) { raise_warning("Could not get peer certificate"); return false; } int err = SSL_get_verify_result(m_data->m_handle); switch (err) { case X509_V_OK: /* fine */ break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: if (m_context[s_allow_self_signed].toBoolean()) { /* allowed */ break; } /* not allowed, so fall through */ default: raise_warning("Could not verify peer: code:%d %s", err, X509_verify_cert_error_string(err)); return false; } /* if the cert passed the usual checks, apply our own local policies now */ /* Does the common name match ? (used primarily for https://) */ String cnmatch = m_context[s_CN_match].toString(); if (!cnmatch.empty()) { X509_NAME *name = X509_get_subject_name(peer); char buf[1024]; int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf)); if (name_len < 0) { raise_warning("Unable to locate peer certificate CN"); return false; } else if (name_len != (int)strlen(buf)) { raise_warning("Peer certificate CN=`%.*s' is malformed", name_len, buf); return false; } bool match = (strcmp(cnmatch.c_str(), buf) == 0); if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') { /* Try wildcard */ if (strchr(buf+2, '.')) { const char* cnmatch_str = cnmatch.c_str(); const char *tmp = strstr(cnmatch_str, buf+1); match = tmp && strcmp(tmp, buf+2) && tmp == strchr(cnmatch_str, '.'); } } if (!match) { /* didn't match */ raise_warning("Peer certificate CN=`%.*s' did not match expected CN=`%s'", name_len, buf, cnmatch.c_str()); return false; } } return true; }
void f_hphp_thread_set_warmup_enabled() { raise_warning("hphp_thread_set_warmup_enabled is deprecated, to enable " "the RequestInitFunction and RequestInitDocument features " "please set Server.EnableMemoryManager=true in your HipHop " "config"); }
static bool yaf_route_map_route(const Object& o, const Object& request) { auto ptr_uri = request->o_realProp(YAF_REQUEST_PROPERTY_NAME_URI, ObjectData::RealPropUnchecked, "Yaf_Request_Abstract"); auto ptr_base_uri = request->o_realProp(YAF_REQUEST_PROPERTY_NAME_BASE, ObjectData::RealPropUnchecked, "Yaf_Request_Abstract"); auto ptr_ctl_prefer = o->o_realProp(YAF_ROUTE_MAP_VAR_NAME_CTL_PREFER, ObjectData::RealPropUnchecked, "Yaf_Route_Map"); auto ptr_delim = o->o_realProp(YAF_ROUTE_MAP_VAR_NAME_DELIMETER, ObjectData::RealPropUnchecked, "Yaf_Route_Map"); if (ptr_uri == NULL) { raise_warning("invalid uri:%p", ptr_uri); return false; } std::string req_uri; if (ptr_uri && ptr_uri->isString() && ptr_base_uri && ptr_base_uri->isString()&& strncasecmp(ptr_uri->toString().c_str(), ptr_base_uri->toString().c_str(), ptr_base_uri->toString().length()) == 0) { req_uri = std::string(ptr_uri->toString().c_str() + ptr_base_uri->toString().length()); } else { req_uri = std::string(ptr_uri->toString().c_str()); } if (req_uri.length() == 0) { return false; } std::string str_query_str; if (ptr_delim->isString() && ptr_delim->toString().length()) { const char* str_delim = ptr_delim->toString().c_str(); char* tmp_req_uri = strdup(req_uri.c_str()); char* query_str = strstr(tmp_req_uri, str_delim); if (query_str && *(query_str - 1) == '/') { char* rest = query_str + strlen(str_delim); if (*rest == '\0') { req_uri = std::string(req_uri, query_str - tmp_req_uri); query_str = NULL; } else if(*rest == '/') { req_uri = std::string(req_uri, query_str - tmp_req_uri); str_query_str = std::string(rest); } else { query_str = NULL; } } free(tmp_req_uri); } std::string route_result; char* save_ptr = NULL; char* tmp = strdup(req_uri.c_str()); char* seg = strtok_r(tmp, YAF_ROUTER_URL_DELIMIETER, &save_ptr); while (seg) { int seg_len = strlen(seg); if (seg_len) { route_result += seg; } route_result += "_"; seg = strtok_r(NULL, YAF_ROUTER_URL_DELIMIETER, &save_ptr); } free(tmp); if (route_result.length()) { if (route_result[route_result.length() - 1] == '_') { route_result.pop_back(); } if (ptr_ctl_prefer->toBoolean()) { auto ptr_controller = request->o_realProp(YAF_REQUEST_PROPERTY_NAME_CONTROLLER, ObjectData::RealPropUnchecked, "Yaf_Request_Abstract"); *ptr_controller = String(route_result); } else { auto ptr_action = request->o_realProp(YAF_REQUEST_PROPERTY_NAME_ACTION, ObjectData::RealPropUnchecked, "Yaf_Request_Abstract"); *ptr_action = String(route_result); } } if (str_query_str.length()) { Array arr = yaf_router_parse_parameters(str_query_str.c_str()); yaf_request_set_params_multi(&request, arr); } return true; }
void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) { auto parser = getParserFromToken(userData); if (parser) { Variant retval; Array args = Array::Create(); if (parser->characterDataHandler.toBoolean()) { args.append(Variant(parser)); args.append(_xml_xmlchar_zval(s, len, parser->target_encoding)); xml_call_handler(parser, parser->characterDataHandler, args); } if (!parser->data.isNull()) { int i; int doprint = 0; String decoded_value; int decoded_len; decoded_value = xml_utf8_decode(s,len, parser->target_encoding); decoded_len = decoded_value.size(); for (i = 0; i < decoded_len; i++) { switch (decoded_value[i]) { case ' ': case '\t': case '\n': default: doprint = 1; break; } if (doprint) { break; } } if (doprint || (! parser->skipwhite)) { if (parser->lastwasopen) { String myval; // check if value exists, if yes append to that if (parser->ctag.toArrRef().exists(s_value)) { myval = tvCastToString(parser->ctag.toArray().rvalAt(s_value).tv()); myval += decoded_value; parser->ctag.toArrRef().set(s_value, myval); } else { parser->ctag.toArrRef().set( s_value, decoded_value ); } } else { Array tag; String myval; String mytype; auto curtag = parser->data.toArrRef().pop(); SCOPE_EXIT { try { parser->data.toArrRef().append(curtag); } catch (...) {} }; if (curtag.toArrRef().exists(s_type)) { mytype = tvCastToString(curtag.toArrRef().rvalAt(s_type).tv()); if (!strcmp(mytype.data(), "cdata") && curtag.toArrRef().exists(s_value)) { myval = tvCastToString(curtag.toArrRef().rvalAt(s_value).tv()); myval += decoded_value; curtag.toArrRef().set(s_value, myval); return; } } if (parser->level <= XML_MAXLEVEL && parser->level > 0) { tag = Array::Create(); _xml_add_to_info(parser, parser->ltags[parser->level-1] + parser->toffset); tag.set(s_tag, String(parser->ltags[parser->level-1] + parser->toffset, CopyString)); tag.set(s_value, decoded_value); tag.set(s_type, s_cdata); tag.set(s_level, parser->level); parser->data.toArrRef().append(tag); } else if (parser->level == (XML_MAXLEVEL + 1)) { raise_warning("Maximum depth exceeded - Results truncated"); } } } } }
void raiseWarning(const StringData* sd) { raise_warning("%s", sd->data()); }
void Variant::unserialize(VariableUnserializer *uns, Uns::Mode mode /* = Uns::Mode::Value */) { // NOTE: If you make changes to how serialization and unserialization work, // make sure to update the reserialize() method in "runtime/ext/ext_apc.cpp" // and to update test_apc_reserialize() in "test/ext/test_ext_apc.cpp". char type, sep; type = uns->readChar(); sep = uns->readChar(); if (type != 'R') { uns->add(this, mode); } if (type == 'N') { if (sep != ';') throw Exception("Expected ';' but got '%c'", sep); setNull(); // NULL *IS* the value, without we get undefined warnings return; } if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } switch (type) { case 'r': { int64_t id = uns->readInt(); Variant *v = uns->getByVal(id); if (v == nullptr) { throw Exception("Id %" PRId64 " out of range", id); } operator=(*v); } break; case 'R': { int64_t id = uns->readInt(); Variant *v = uns->getByRef(id); if (v == nullptr) { throw Exception("Id %" PRId64 " out of range", id); } assignRef(*v); } break; case 'b': { int64_t v = uns->readInt(); operator=((bool)v); } break; case 'i': { int64_t v = uns->readInt(); operator=(v); } break; case 'd': { double v; char ch = uns->peek(); bool negative = false; char buf[4]; if (ch == '-') { negative = true; ch = uns->readChar(); ch = uns->peek(); } if (ch == 'I') { uns->read(buf, 3); buf[3] = '\0'; if (strcmp(buf, "INF")) { throw Exception("Expected 'INF' but got '%s'", buf); } v = atof("inf"); } else if (ch == 'N') { uns->read(buf, 3); buf[3] = '\0'; if (strcmp(buf, "NAN")) { throw Exception("Expected 'NAN' but got '%s'", buf); } v = atof("nan"); } else { v = uns->readDouble(); } operator=(negative ? -v : v); } break; case 's': { String v; v.unserialize(uns); operator=(v); } break; case 'S': if (uns->getType() == VariableUnserializer::Type::APCSerialize) { union { char buf[8]; StringData *sd; } u; uns->read(u.buf, 8); operator=(u.sd); } else { throw Exception("Unknown type '%c'", type); } break; case 'a': { Array v = Array::Create(); v.unserialize(uns); operator=(v); return; // array has '}' terminating } break; case 'L': { int64_t id = uns->readInt(); sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } String rsrcName; rsrcName.unserialize(uns); sep = uns->readChar(); if (sep != '{') { throw Exception("Expected '{' but got '%c'", sep); } sep = uns->readChar(); if (sep != '}') { throw Exception("Expected '}' but got '%c'", sep); } DummyResource* rsrc = NEWOBJ(DummyResource); rsrc->o_setResourceId(id); rsrc->m_class_name = rsrcName; operator=(rsrc); return; // resource has '}' terminating } break; case 'O': case 'V': case 'K': { String clsName; clsName.unserialize(uns); sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } int64_t size = uns->readInt(); char sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } sep = uns->readChar(); if (sep != '{') { throw Exception("Expected '{' but got '%c'", sep); } const bool allowObjectFormatForCollections = true; Class* cls; // If we are potentially dealing with a collection, we need to try to // load the collection class under an alternate name so that we can // deserialize data that was serialized before the migration of // collections to the HH namespace. if (type != 'O') { // Collections are CPP builtins; don't attempt to autoload cls = Unit::getClass(clsName.get(), /* autoload */ false); if (!cls) { cls = tryAlternateCollectionClass(clsName.get()); } } else if (allowObjectFormatForCollections) { // In order to support the legacy {O|V}:{Set|Vector|Map} // serialization, we defer autoloading until we know that there's // no alternate (builtin) collection class. cls = Unit::getClass(clsName.get(), /* autoload */ false); if (!cls) { cls = tryAlternateCollectionClass(clsName.get()); } if (!cls) { cls = Unit::loadClass(clsName.get()); // with autoloading } } else { cls = Unit::loadClass(clsName.get()); // with autoloading } Object obj; if (RuntimeOption::UnserializationWhitelistCheck && (type == 'O') && !uns->isWhitelistedClass(clsName)) { const char* err_msg = "The object being unserialized with class name '%s' " "is not in the given whitelist. " "See http://fburl.com/SafeSerializable for more detail"; if (RuntimeOption::UnserializationWhitelistCheckWarningOnly) { raise_warning(err_msg, clsName.c_str()); } else { raise_error(err_msg, clsName.c_str()); } } if (cls) { // Only unserialize CPP extension types which can actually // support it. Otherwise, we risk creating a CPP object // without having it initialized completely. if (cls->instanceCtor() && !cls->isCppSerializable()) { obj = ObjectData::newInstance( SystemLib::s___PHP_Unserializable_ClassClass); obj->o_set(s_PHP_Unserializable_Class_Name, clsName); } else { obj = ObjectData::newInstance(cls); if (UNLIKELY(cls == c_Pair::classof() && size != 2)) { throw Exception("Pair objects must have exactly 2 elements"); } } } else { obj = ObjectData::newInstance( SystemLib::s___PHP_Incomplete_ClassClass); obj->o_set(s_PHP_Incomplete_Class_Name, clsName); } operator=(obj); if (size > 0) { if (type == 'O') { // Collections are not allowed if (obj->isCollection()) { if (size > 0) { throw Exception("%s does not support the 'O' serialization " "format", clsName.data()); } // Be lax and tolerate the 'O' serialization format for collection // classes if there are 0 properties. raise_warning("%s does not support the 'O' serialization " "format", clsName.data()); } /* Count backwards so that i is the number of properties remaining (to be used as an estimate for the total number of dynamic properties when we see the first dynamic prop). see getVariantPtr */ for (int64_t i = size; i--; ) { String key = uns->unserializeKey().toString(); int ksize = key.size(); const char *kdata = key.data(); int subLen = 0; if (kdata[0] == '\0') { if (UNLIKELY(!ksize)) { throw EmptyObjectPropertyException(); } // private or protected subLen = strlen(kdata + 1) + 2; if (UNLIKELY(subLen >= ksize)) { if (subLen == ksize) { throw EmptyObjectPropertyException(); } else { throw Exception("Mangled private object property"); } } String k(kdata + subLen, ksize - subLen, CopyString); Class* ctx = (Class*)-1; if (kdata[1] != '*') { ctx = Unit::lookupClass( String(kdata + 1, subLen - 2, CopyString).get()); } unserializeProp(uns, obj.get(), k, ctx, key, i + 1); } else { unserializeProp(uns, obj.get(), key, nullptr, key, i + 1); } } } else { assert(type == 'V' || type == 'K'); if (!obj->isCollection()) { throw Exception("%s is not a collection class", clsName.data()); } collectionUnserialize(obj.get(), uns, size, type); } } sep = uns->readChar(); if (sep != '}') { throw Exception("Expected '}' but got '%c'", sep); } obj->invokeWakeup(); return; // object has '}' terminating } break; case 'C': { String clsName; clsName.unserialize(uns); sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } String serialized; serialized.unserialize(uns, '{', '}'); Object obj; try { obj = create_object_only(clsName); } catch (ClassNotFoundException &e) { if (!uns->allowUnknownSerializableClass()) { throw; } obj = create_object_only(s_PHP_Incomplete_Class); obj->o_set(s_PHP_Incomplete_Class_Name, clsName); obj->o_set("serialized", serialized); } if (!obj->instanceof(SystemLib::s_SerializableClass)) { raise_warning("Class %s has no unserializer", obj->o_getClassName().data()); } else { obj->o_invoke_few_args(s_unserialize, 1, serialized); obj.get()->clearNoDestruct(); } operator=(obj); return; // object has '}' terminating } break; default: throw Exception("Unknown type '%c'", type); } sep = uns->readChar(); if (sep != ';') { throw Exception("Expected ';' but got '%c'", sep); } }
Variant HHVM_FUNCTION(socket_select, VRefParam read, VRefParam write, VRefParam except, const Variant& vtv_sec, int tv_usec /* = 0 */) { int count = 0; if (!read.isNull()) { count += read.toArray().size(); } if (!write.isNull()) { count += write.toArray().size(); } if (!except.isNull()) { count += except.toArray().size(); } if (!count) { return false; } struct pollfd *fds = (struct pollfd *)calloc(count, sizeof(struct pollfd)); count = 0; if (!read.isNull()) { sock_array_to_fd_set(read.toArray(), fds, count, POLLIN); } if (!write.isNull()) { sock_array_to_fd_set(write.toArray(), fds, count, POLLOUT); } if (!except.isNull()) { sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI); } if (!count) { raise_warning("no resource arrays were passed to select"); free(fds); return false; } IOStatusHelper io("socket_select"); int timeout_ms = -1; if (!vtv_sec.isNull()) { timeout_ms = vtv_sec.toInt32() * 1000 + tv_usec / 1000; } /* slight hack to support buffered data; if there is data sitting in the * read buffer of any of the streams in the read array, let's pretend * that we selected, but return only the readable sockets */ if (!read.isNull()) { auto hasData = Array::Create(); for (ArrayIter iter(read.toArray()); iter; ++iter) { auto file = cast<File>(iter.second()); if (file->bufferedLen() > 0) { hasData.append(iter.second()); } } if (hasData.size() > 0) { if (!write.isNull()) { write = empty_array(); } if (!except.isNull()) { except = empty_array(); } read = hasData; free(fds); return hasData.size(); } } int retval = poll(fds, count, timeout_ms); if (retval == -1) { raise_warning("unable to select [%d]: %s", errno, folly::errnoStr(errno).c_str()); free(fds); return false; } count = 0; int nfds = 0; if (!read.isNull()) { sock_array_from_fd_set(read, fds, nfds, count, POLLIN|POLLERR|POLLHUP); } if (!write.isNull()) { sock_array_from_fd_set(write, fds, nfds, count, POLLOUT|POLLERR); } if (!except.isNull()) { sock_array_from_fd_set(except, fds, nfds, count, POLLPRI|POLLERR); } free(fds); return count; }
bool HHVM_FUNCTION(socket_set_option, const Resource& socket, int level, int optname, const Variant& optval) { auto sock = cast<Socket>(socket); struct linger lv; struct timeval tv; int ov; int optlen; void *opt_ptr; switch (optname) { case SO_LINGER: { Array value = optval.toArray(); if (!value.exists(s_l_onoff)) { raise_warning("no key \"l_onoff\" passed in optval"); return false; } if (!value.exists(s_l_linger)) { raise_warning("no key \"l_linger\" passed in optval"); return false; } lv.l_onoff = (unsigned short)value[s_l_onoff].toInt32(); lv.l_linger = (unsigned short)value[s_l_linger].toInt32(); optlen = sizeof(lv); opt_ptr = &lv; } break; case SO_RCVTIMEO: case SO_SNDTIMEO: { Array value = optval.toArray(); if (!value.exists(s_sec)) { raise_warning("no key \"sec\" passed in optval"); return false; } if (!value.exists(s_usec)) { raise_warning("no key \"usec\" passed in optval"); return false; } tv.tv_sec = value[s_sec].toInt32(); tv.tv_usec = value[s_usec].toInt32(); if (tv.tv_usec >= 1000000) { tv.tv_sec += tv.tv_usec / 1000000; tv.tv_usec %= 1000000; } if (tv.tv_sec < 0) { tv.tv_sec = ThreadInfo::s_threadInfo.getNoCheck()-> m_reqInjectionData.getSocketDefaultTimeout(); } optlen = sizeof(tv); opt_ptr = &tv; sock->setTimeout(tv); } break; default: ov = optval.toInt32(); optlen = sizeof(ov); opt_ptr = &ov; break; } if (setsockopt(sock->fd(), level, optname, opt_ptr, optlen) != 0) { SOCKET_ERROR(sock, "unable to set socket option", errno); return false; } return true; }
static Variant php_mcrypt_do_crypt(CStrRef cipher, CStrRef key, CStrRef data, CStrRef mode, CStrRef iv, bool dencrypt) { MCRYPT td = mcrypt_module_open((char*)cipher.data(), (char*)MCG(algorithms_dir).data(), (char*)mode.data(), (char*)MCG(modes_dir).data()); if (td == MCRYPT_FAILED) { raise_warning(MCRYPT_OPEN_MODULE_FAILED); return false; } /* Checking for key-length */ int max_key_length = mcrypt_enc_get_key_size(td); if (key.size() > max_key_length) { raise_warning("Size of key is too large for this algorithm"); } int count; int *key_length_sizes = mcrypt_enc_get_supported_key_sizes(td, &count); int use_key_length; char *key_s = NULL; if (count == 0 && key_length_sizes == NULL) { // all lengths 1 - k_l_s = OK use_key_length = key.size(); key_s = (char*)malloc(use_key_length); memcpy(key_s, key.data(), use_key_length); } else if (count == 1) { /* only m_k_l = OK */ key_s = (char*)malloc(key_length_sizes[0]); memset(key_s, 0, key_length_sizes[0]); memcpy(key_s, key.data(), MIN(key.size(), key_length_sizes[0])); use_key_length = key_length_sizes[0]; } else { /* dertermine smallest supported key > length of requested key */ use_key_length = max_key_length; /* start with max key length */ for (int i = 0; i < count; i++) { if (key_length_sizes[i] >= key.size() && key_length_sizes[i] < use_key_length) { use_key_length = key_length_sizes[i]; } } key_s = (char*)malloc(use_key_length); memset(key_s, 0, use_key_length); memcpy(key_s, key.data(), MIN(key.size(), use_key_length)); } mcrypt_free(key_length_sizes); /* Check IV */ char *iv_s = NULL; int iv_size = mcrypt_enc_get_iv_size(td); /* IV is required */ if (mcrypt_enc_mode_has_iv(td) == 1) { if (!iv.empty()) { if (iv_size != iv.size()) { raise_warning("The IV parameter must be as long as the blocksize"); } else { iv_s = (char*)malloc(iv_size + 1); memcpy(iv_s, iv.data(), iv_size); } } else { raise_warning("Attempt to use an empty IV, which is NOT recommended"); iv_s = (char*)malloc(iv_size + 1); memset(iv_s, 0, iv_size + 1); } } int block_size; unsigned long int data_size; String s; char *data_s; /* Check blocksize */ if (mcrypt_enc_is_block_mode(td) == 1) { /* It's a block algorithm */ block_size = mcrypt_enc_get_block_size(td); data_size = (((data.size() - 1) / block_size) + 1) * block_size; s = String(data_size, ReserveString); data_s = (char*)s.mutableSlice().ptr; memset(data_s, 0, data_size); memcpy(data_s, data.data(), data.size()); } else { /* It's not a block algorithm */ data_size = data.size(); s = String(data_size, ReserveString); data_s = (char*)s.mutableSlice().ptr; memcpy(data_s, data.data(), data.size()); } if (mcrypt_generic_init(td, key_s, use_key_length, iv_s) < 0) { raise_warning("Mcrypt initialisation failed"); return false; } if (dencrypt) { mdecrypt_generic(td, data_s, data_size); } else { mcrypt_generic(td, data_s, data_size); } /* freeing vars */ mcrypt_generic_end(td); if (key_s != NULL) { free(key_s); } if (iv_s != NULL) { free(iv_s); } return s.setSize(data_size); }
void f_gc_disable() { raise_warning("HipHop currently does not support circular reference " "collection"); }
SSL *SSLSocket::createSSL(SSL_CTX *ctx) { ERR_clear_error(); /* look at options in the stream and set appropriate verification flags */ if (m_context[s_verify_peer].toBoolean()) { /* turn on verification callback */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verifyCallback); /* CA stuff */ String cafile = m_context[s_cafile].toString(); String capath = m_context[s_capath].toString(); if (!cafile.empty() || !capath.empty()) { if (!SSL_CTX_load_verify_locations(ctx, cafile.data(), capath.data())) { raise_warning("Unable to set verify locations `%s' `%s'", cafile.data(), capath.data()); return nullptr; } } int64_t depth = m_context[s_verify_depth].toInt64(); if (depth) { SSL_CTX_set_verify_depth(ctx, depth); } } else { SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr); } /* callback for the passphrase (for localcert) */ if (!m_context[s_passphrase].toString().empty()) { SSL_CTX_set_default_passwd_cb_userdata(ctx, this); SSL_CTX_set_default_passwd_cb(ctx, passwdCallback); } String cipherlist = m_context[s_ciphers].toString(); if (cipherlist.empty()) { cipherlist = "DEFAULT"; } SSL_CTX_set_cipher_list(ctx, cipherlist.data()); String certfile = m_context[s_local_cert].toString(); if (!certfile.empty()) { String resolved_path_buff = File::TranslatePath(certfile); if (!resolved_path_buff.empty()) { /* a certificate to use for authentication */ if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff.data()) != 1) { raise_warning("Unable to set local cert chain file `%s'; Check " "that your cafile/capath settings include details of " "your certificate and its issuer", certfile.data()); return nullptr; } if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff.data(), SSL_FILETYPE_PEM) != 1) { raise_warning("Unable to set private key file `%s'", resolved_path_buff.data()); return nullptr; } SSL *tmpssl = SSL_new(ctx); X509 *cert = SSL_get_certificate(tmpssl); if (cert) { EVP_PKEY *key = X509_get_pubkey(cert); EVP_PKEY_copy_parameters(key, SSL_get_privatekey(tmpssl)); EVP_PKEY_free(key); } SSL_free(tmpssl); if (!SSL_CTX_check_private_key(ctx)) { raise_warning("Private key does not match certificate!"); } } } SSL *ssl = SSL_new(ctx); if (ssl) { SSL_set_ex_data(ssl, GetSSLExDataIndex(), this); /* map SSL => stream */ } return ssl; }
int64_t f_gc_collect_cycles() { raise_warning("HipHop currently does not support circular reference " "collection"); return 0; }
bool SSLSocket::setupCrypto(SSLSocket *session /* = NULL */) { if (m_data->m_handle) { raise_warning("SSL/TLS already set-up for this stream"); return false; } /* need to do slightly different things, based on client/server method, * so lets remember which method was selected */ #if OPENSSL_VERSION_NUMBER < 0x00909000L SSL_METHOD *smethod; #else const SSL_METHOD *smethod; #endif switch (m_data->m_method) { case CryptoMethod::ClientSSLv23: m_data->m_client = true; smethod = SSLv23_client_method(); break; case CryptoMethod::ClientSSLv3: m_data->m_client = true; smethod = SSLv3_client_method(); break; case CryptoMethod::ClientTLS: m_data->m_client = true; smethod = TLSv1_client_method(); break; case CryptoMethod::ServerSSLv23: m_data->m_client = false; smethod = SSLv23_server_method(); break; case CryptoMethod::ServerSSLv3: m_data->m_client = false; smethod = SSLv3_server_method(); break; /* SSLv2 protocol might be disabled in the OpenSSL library */ #ifndef OPENSSL_NO_SSL2 case CryptoMethod::ClientSSLv2: m_data->m_client = true; smethod = SSLv2_client_method(); break; case CryptoMethod::ServerSSLv2: m_data->m_client = false; smethod = SSLv2_server_method(); break; #else case CryptoMethod::ClientSSLv2: case CryptoMethod::ServerSSLv2: raise_warning("OpenSSL library does not support SSL2 protocol"); return false; break; #endif case CryptoMethod::ServerTLS: m_data->m_client = false; smethod = TLSv1_server_method(); break; default: return false; } SSL_CTX *ctx = SSL_CTX_new(smethod); if (ctx == nullptr) { raise_warning("failed to create an SSL context"); return false; } SSL_CTX_set_options(ctx, SSL_OP_ALL); m_data->m_handle = createSSL(ctx); if (m_data->m_handle == nullptr) { raise_warning("failed to create an SSL handle"); SSL_CTX_free(ctx); return false; } if (!SSL_set_fd(m_data->m_handle, getFd())) { handleError(0, true); } if (session) { SSL_copy_session_id(m_data->m_handle, session->m_data->m_handle); } return true; }
Variant HHVM_FUNCTION(bzopen, const Variant& filename, const String& mode) { if (mode != s_r && mode != s_w) { raise_warning( "'%s' is not a valid mode for bzopen(). " "Only 'w' and 'r' are supported.", mode.data() ); return false; } BZ2File *bz; if (filename.isString()) { if (filename.asCStrRef().empty()) { raise_warning("filename cannot be empty"); return false; } bz = newres<BZ2File>(); bool ret = bz->open(File::TranslatePath(filename.toString()), mode); if (!ret) { raise_warning("%s", folly::errnoStr(errno).c_str()); return false; } } else { if (!filename.isResource()) { raise_warning("first parameter has to be string or file-resource"); return false; } PlainFile* f = filename.toResource().getTyped<PlainFile>(); if (!f) { return false; } std::string stream_mode = f->getMode(); int stream_mode_len = stream_mode.length(); if (stream_mode_len != 1 && !(stream_mode_len == 2 && stream_mode.find('b') != std::string::npos)) { raise_warning("cannot use stream opened in mode '%s'", stream_mode.c_str()); return false; } else if (stream_mode_len == 1 && stream_mode[0] != 'r' && stream_mode[0] != 'w' && stream_mode[0] != 'a' && stream_mode[0] != 'x') { raise_warning("cannot use stream opened in mode '%s'", stream_mode.c_str()); return false; } const char rw_mode = stream_mode[0]; if (mode == s_r && rw_mode != 'r') { raise_warning("cannot write to a stream opened in read only mode"); return false; } else if (mode == s_w && rw_mode != 'w' && rw_mode != 'a' && rw_mode != 'x') { raise_warning("cannot read from a stream opened in write only mode"); return false; } bz = newres<BZ2File>(f); } Resource handle(bz); return handle; }
bool SSLSocket::enableCrypto(bool activate /* = true */) { if (activate && !m_data->m_ssl_active) { double timeout = m_data->m_connect_timeout; bool blocked = m_data->m_is_blocked; if (!m_data->m_state_set) { if (m_data->m_client) { SSL_set_connect_state(m_data->m_handle); } else { SSL_set_accept_state(m_data->m_handle); } m_data->m_state_set = true; } if (m_data->m_client && setBlocking(false)) { m_data->m_is_blocked = false; } int n; bool retry = true; do { if (m_data->m_client) { struct timeval tvs, tve; struct timezone tz; gettimeofday(&tvs, &tz); n = SSL_connect(m_data->m_handle); gettimeofday(&tve, &tz); timeout -= (tve.tv_sec + (double) tve.tv_usec / 1000000) - (tvs.tv_sec + (double) tvs.tv_usec / 1000000); if (timeout < 0) { raise_warning("SSL: connection timeout"); return -1; } } else { n = SSL_accept(m_data->m_handle); } if (n <= 0) { retry = handleError(n, true); } else { break; } } while (retry); if (m_data->m_client && m_data->m_is_blocked != blocked && setBlocking(blocked)) { m_data->m_is_blocked = blocked; } if (n == 1) { X509 *peer_cert = SSL_get_peer_certificate(m_data->m_handle); if (!applyVerificationPolicy(peer_cert)) { SSL_shutdown(m_data->m_handle); } else { m_data->m_ssl_active = true; /* allow the script to capture the peer cert * and/or the certificate chain */ if (m_context[s_capture_peer_cert].toBoolean()) { m_context.set(s_peer_certificate, Variant(makeSmartPtr<Certificate>(peer_cert))); peer_cert = nullptr; } if (m_context[s_capture_peer_cert_chain].toBoolean()) { Array arr; STACK_OF(X509) *chain = SSL_get_peer_cert_chain(m_data->m_handle); if (chain) { for (int i = 0; i < sk_X509_num(chain); i++) { X509 *mycert = X509_dup(sk_X509_value(chain, i)); arr.append(Variant(makeSmartPtr<Certificate>(mycert))); } } m_context.set(s_peer_certificate_chain, arr); } } if (peer_cert) { X509_free(peer_cert); } } else { n = errno == EAGAIN ? 0 : -1; } return n >= 0; } else if (!activate && m_data->m_ssl_active) { /* deactivate - common for server/client */ SSL_shutdown(m_data->m_handle); m_data->m_ssl_active = false; } return true; }
bool Transport::setCookie(CStrRef name, CStrRef value, int64_t expire /* = 0 */, CStrRef path /* = "" */, CStrRef domain /* = "" */, bool secure /* = false */, bool httponly /* = false */, bool encode_url /* = true */) { if (!name.empty() && strpbrk(name.data(), "=,; \t\r\n\013\014")) { Logger::Warning("Cookie names can not contain any of the following " "'=,; \\t\\r\\n\\013\\014'"); return false; } if (!encode_url && !value.empty() && strpbrk(value.data(), ",; \t\r\n\013\014")) { Logger::Warning("Cookie values can not contain any of the following " "',; \\t\\r\\n\\013\\014'"); return false; } char *encoded_value = nullptr; int len = 0; if (!value.empty() && encode_url) { int encoded_value_len = value.size(); encoded_value = url_encode(value.data(), encoded_value_len); len += encoded_value_len; } else if (!value.empty()) { encoded_value = strdup(value.data()); len += value.size(); } len += path.size(); len += domain.size(); std::string cookie; cookie.reserve(len + 100); if (value.empty()) { /* * MSIE doesn't delete a cookie when you set it to a null value * so in order to force cookies to be deleted, even on MSIE, we * pick an expiry date in the past */ String sdt = DateTime(1, true).toString(DateTime::DateFormat::Cookie); cookie += name.data(); cookie += "=deleted; expires="; cookie += sdt.data(); } else { cookie += name.data(); cookie += "="; cookie += encoded_value ? encoded_value : ""; if (expire > 0) { if (expire > 253402300799LL) { raise_warning("Expiry date cannot have a year greater then 9999"); return false; } cookie += "; expires="; String sdt = DateTime(expire, true).toString(DateTime::DateFormat::Cookie); cookie += sdt.data(); } } if (encoded_value) { free(encoded_value); } if (!path.empty()) { cookie += "; path="; cookie += path.data(); } if (!domain.empty()) { cookie += "; domain="; cookie += domain.data(); } if (secure) { cookie += "; secure"; } if (httponly) { cookie += "; httponly"; } m_responseCookies[name.data()] = cookie; return true; }
req::ptr<File> HttpStreamWrapper::open(const String& filename, const String& mode, int options, const req::ptr<StreamContext>& context) { if (RuntimeOption::ServerHttpSafeMode && !is_cli_mode()) { return nullptr; } if (strncmp(filename.data(), "http://", sizeof("http://") - 1) && strncmp(filename.data(), "https://", sizeof("https://") - 1)) { return nullptr; } Array headers; String method = s_GET; String post_data = null_string; String proxy_host; String proxy_user; String proxy_pass; int proxy_port = -1; int max_redirs = 20; int timeout = -1; bool ignore_errors = false; if (context && !context->getOptions().isNull() && !context->getOptions()[s_http].isNull()) { Array opts = context->getOptions()[s_http].toArray(); if (opts.exists(s_method)) { method = opts[s_method].toString(); } if (opts.exists(s_header)) { Array lines; if (opts[s_header].isString()) { lines = StringUtil::Explode( opts[s_header].toString(), "\r\n").toArray(); } else if (opts[s_header].isArray()) { lines = opts[s_header]; } for (ArrayIter it(lines); it; ++it) { Array parts = StringUtil::Explode( it.second().toString(), ":", 2).toArray(); headers.set(parts.rvalAt(0), parts.rvalAt(1)); } } if (opts.exists(s_user_agent) && !headers.exists(s_User_Agent)) { headers.set(s_User_Agent, opts[s_user_agent]); } if (opts.exists(s_max_redirects)) { max_redirs = opts[s_max_redirects].toInt64(); } if (opts.exists(s_timeout)) { timeout = opts[s_timeout].toInt64(); } if (opts.exists(s_ignore_errors)) { ignore_errors = opts[s_ignore_errors].toBoolean(); } if (opts.exists(s_proxy)) { Variant host = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_HOST); Variant port = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_PORT); if (!same(host, false) && !same(port, false)) { proxy_host = host.toString(); proxy_port = port.toInt64(); Variant user = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_USER); Variant pass = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_PASS); if (!same(user, false) && !same(pass, false)) { proxy_user = user.toString(); proxy_pass = pass.toString(); } } } post_data = opts[s_content].toString(); } if (!headers.exists(s_User_Agent)) { auto default_user_agent = ThreadInfo::s_threadInfo.getNoCheck() ->m_reqInjectionData.getUserAgent(); if (!default_user_agent.empty()) { headers.set(s_User_Agent, default_user_agent); } } auto file = req::make<UrlFile>(method.data(), headers, post_data, max_redirs, timeout, ignore_errors); file->setStreamContext(context); file->setProxy(proxy_host, proxy_port, proxy_user, proxy_pass); bool ret = file->open(filename, mode); if (!ret) { raise_warning("Failed to open %s (%s)", filename.data(), file->getLastError().c_str()); return nullptr; } return file; }
void Transport::prepareHeaders(bool compressed, bool chunked, const String &response, const String& orig_response) { for (HeaderMap::const_iterator iter = m_responseHeaders.begin(); iter != m_responseHeaders.end(); ++iter) { const vector<string> &values = iter->second; for (unsigned int i = 0; i < values.size(); i++) { addHeaderImpl(iter->first.c_str(), values[i].c_str()); } } for (CookieMap::const_iterator iter = m_responseCookies.begin(); iter != m_responseCookies.end(); ++iter) { addHeaderImpl("Set-Cookie", iter->second.c_str()); } if (compressed) { addHeaderImpl("Content-Encoding", "gzip"); removeHeaderImpl("Content-Length"); // Remove the Content-MD5 header coming from PHP if we compressed the data, // as the checksum is going to be invalid. auto it = m_responseHeaders.find("Content-MD5"); if (it != m_responseHeaders.end()) { removeHeaderImpl("Content-MD5"); // Re-add it back unless this is a chunked response. We'd have to buffer // the response completely to compute the MD5, which defeats the purpose // of chunking. if (chunked) { raise_warning("Cannot use chunked HTTP response and Content-MD5 header " "at the same time. Dropping Content-MD5."); } else { string cur_md5 = it->second[0]; String expected_md5 = StringUtil::Base64Encode(StringUtil::MD5( orig_response, true)); // Can never trust these PHP people... if (expected_md5.c_str() != cur_md5) { raise_warning("Content-MD5 mismatch. Expected: %s, Got: %s", expected_md5.c_str(), cur_md5.c_str()); } addHeaderImpl("Content-MD5", StringUtil::Base64Encode(StringUtil::MD5( response, true)).c_str()); } } } if (m_responseHeaders.find("Content-Type") == m_responseHeaders.end() && m_responseCode != 304) { string contentType = "text/html; charset=" + RuntimeOption::DefaultCharsetName; addHeaderImpl("Content-Type", contentType.c_str()); } if (RuntimeOption::ExposeHPHP) { addHeaderImpl("X-Powered-By", "HPHP"); } if ((RuntimeOption::ExposeXFBServer || RuntimeOption::ExposeXFBDebug) && !RuntimeOption::XFBDebugSSLKey.empty() && m_responseHeaders.find("X-FB-Debug") == m_responseHeaders.end()) { String ip = RuntimeOption::ServerPrimaryIP; String key = RuntimeOption::XFBDebugSSLKey; String cipher("AES-256-CBC"); int iv_len = f_openssl_cipher_iv_length(cipher).toInt32(); String iv = f_openssl_random_pseudo_bytes(iv_len); String encrypted = f_openssl_encrypt(ip, cipher, key, k_OPENSSL_RAW_DATA, iv); String output = StringUtil::Base64Encode(iv + encrypted); if (debug) { String decrypted = f_openssl_decrypt(encrypted, cipher, key, k_OPENSSL_RAW_DATA, iv); assert(decrypted->same(ip.get())); } addHeaderImpl("X-FB-Debug", output.c_str()); } // shutting down servers, so need to terminate all Keep-Alive connections if (!RuntimeOption::EnableKeepAlive || isServerStopping()) { addHeaderImpl("Connection", "close"); removeHeaderImpl("Keep-Alive"); // so lower level transports can ignore incoming "Connection: keep-alive" removeRequestHeaderImpl("Connection"); } }
bool setOption(long option, CVarRef value) { if (m_cp == NULL) { return false; } m_error_no = CURLE_OK; switch (option) { case CURLOPT_INFILESIZE: case CURLOPT_VERBOSE: case CURLOPT_HEADER: case CURLOPT_NOPROGRESS: case CURLOPT_NOBODY: case CURLOPT_FAILONERROR: case CURLOPT_UPLOAD: case CURLOPT_POST: case CURLOPT_FTPLISTONLY: case CURLOPT_FTPAPPEND: case CURLOPT_NETRC: case CURLOPT_PUT: case CURLOPT_TIMEOUT: #if LIBCURL_VERSION_NUM >= 0x071002 case CURLOPT_TIMEOUT_MS: #endif case CURLOPT_FTP_USE_EPSV: case CURLOPT_LOW_SPEED_LIMIT: case CURLOPT_SSLVERSION: case CURLOPT_LOW_SPEED_TIME: case CURLOPT_RESUME_FROM: case CURLOPT_TIMEVALUE: case CURLOPT_TIMECONDITION: case CURLOPT_TRANSFERTEXT: case CURLOPT_HTTPPROXYTUNNEL: case CURLOPT_FILETIME: case CURLOPT_MAXREDIRS: case CURLOPT_MAXCONNECTS: case CURLOPT_CLOSEPOLICY: case CURLOPT_FRESH_CONNECT: case CURLOPT_FORBID_REUSE: case CURLOPT_CONNECTTIMEOUT: #if LIBCURL_VERSION_NUM >= 0x071002 case CURLOPT_CONNECTTIMEOUT_MS: #endif case CURLOPT_SSL_VERIFYHOST: case CURLOPT_SSL_VERIFYPEER: //case CURLOPT_DNS_USE_GLOBAL_CACHE: not thread-safe when set to true case CURLOPT_NOSIGNAL: case CURLOPT_PROXYTYPE: case CURLOPT_BUFFERSIZE: case CURLOPT_HTTPGET: case CURLOPT_HTTP_VERSION: case CURLOPT_CRLF: case CURLOPT_DNS_CACHE_TIMEOUT: case CURLOPT_PROXYPORT: case CURLOPT_FTP_USE_EPRT: case CURLOPT_HTTPAUTH: case CURLOPT_PROXYAUTH: case CURLOPT_FTP_CREATE_MISSING_DIRS: case CURLOPT_FTPSSLAUTH: case CURLOPT_FTP_SSL: case CURLOPT_UNRESTRICTED_AUTH: case CURLOPT_PORT: case CURLOPT_AUTOREFERER: case CURLOPT_COOKIESESSION: case CURLOPT_TCP_NODELAY: case CURLOPT_IPRESOLVE: case CURLOPT_FOLLOWLOCATION: m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, value.toInt64()); break; case CURLOPT_RETURNTRANSFER: m_write.method = value.toBoolean() ? PHP_CURL_RETURN : PHP_CURL_STDOUT; break; case CURLOPT_BINARYTRANSFER: m_write.type = value.toBoolean() ? PHP_CURL_BINARY : PHP_CURL_ASCII; break; case CURLOPT_PRIVATE: case CURLOPT_URL: case CURLOPT_PROXY: case CURLOPT_USERPWD: case CURLOPT_PROXYUSERPWD: case CURLOPT_RANGE: case CURLOPT_CUSTOMREQUEST: case CURLOPT_USERAGENT: case CURLOPT_FTPPORT: case CURLOPT_COOKIE: case CURLOPT_REFERER: case CURLOPT_INTERFACE: case CURLOPT_KRB4LEVEL: case CURLOPT_EGDSOCKET: case CURLOPT_CAINFO: case CURLOPT_CAPATH: case CURLOPT_SSL_CIPHER_LIST: case CURLOPT_SSLKEY: case CURLOPT_SSLKEYTYPE: case CURLOPT_SSLKEYPASSWD: case CURLOPT_SSLENGINE: case CURLOPT_SSLENGINE_DEFAULT: case CURLOPT_SSLCERTTYPE: case CURLOPT_ENCODING: case CURLOPT_COOKIEJAR: case CURLOPT_SSLCERT: case CURLOPT_RANDOM_FILE: case CURLOPT_COOKIEFILE: { String svalue = value.toString(); #if LIBCURL_VERSION_NUM >= 0x071100 /* Strings passed to libcurl as 'char *' arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */ m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, svalue.c_str()); #else char *copystr = strndup(svalue.data(), svalue.size()); m_to_free->str.push_back(copystr); m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, copystr); #endif if (option == CURLOPT_URL) m_url = value; } break; case CURLOPT_FILE: case CURLOPT_INFILE: case CURLOPT_WRITEHEADER: case CURLOPT_STDERR: { if (!value.is(KindOfObject)) { return false; } Object obj = value.toObject(); if (obj.isNull() || obj.getTyped<File>(true) == NULL) { return false; } switch (option) { case CURLOPT_FILE: m_write.fp = obj; m_write.method = PHP_CURL_FILE; break; case CURLOPT_WRITEHEADER: m_write_header.fp = obj; m_write_header.method = PHP_CURL_FILE; break; case CURLOPT_INFILE: m_read.fp = obj; m_emptyPost = false; break; default: { if (obj.getTyped<PlainFile>(true) == NULL) { return false; } FILE *fp = obj.getTyped<PlainFile>()->getStream(); if (!fp) { return false; } m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, fp); break; } } } break; case CURLOPT_WRITEFUNCTION: m_write.callback = value; m_write.method = PHP_CURL_USER; break; case CURLOPT_READFUNCTION: m_read.callback = value; m_read.method = PHP_CURL_USER; m_emptyPost = false; break; case CURLOPT_HEADERFUNCTION: m_write_header.callback = value; m_write_header.method = PHP_CURL_USER; break; case CURLOPT_POSTFIELDS: m_emptyPost = false; if (value.is(KindOfArray) || value.is(KindOfObject)) { Array arr = value.toArray(); curl_httppost *first = NULL; curl_httppost *last = NULL; for (ArrayIter iter(arr); iter; ++iter) { String key = iter.first().toString(); String val = iter.second().toString(); const char *postval = val.data(); /* The arguments after _NAMELENGTH and _CONTENTSLENGTH * must be explicitly cast to long in curl_formadd * use since curl needs a long not an int. */ if (*postval == '@') { ++postval; m_error_no = (CURLcode)curl_formadd (&first, &last, CURLFORM_COPYNAME, key.data(), CURLFORM_NAMELENGTH, (long)key.size(), CURLFORM_FILE, postval, CURLFORM_END); } else { m_error_no = (CURLcode)curl_formadd (&first, &last, CURLFORM_COPYNAME, key.data(), CURLFORM_NAMELENGTH, (long)key.size(), CURLFORM_COPYCONTENTS, postval, CURLFORM_CONTENTSLENGTH,(long)val.size(), CURLFORM_END); } } if (m_error_no != CURLE_OK) { return false; } m_to_free->post.push_back(first); m_error_no = curl_easy_setopt(m_cp, CURLOPT_HTTPPOST, first); } else { String svalue = value.toString(); #if LIBCURL_VERSION_NUM >= 0x071100 /* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */ m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDSIZE, svalue.size()); m_error_no = curl_easy_setopt(m_cp, CURLOPT_COPYPOSTFIELDS, svalue.c_str()); #else char *post = strndup(svalue.data(), svalue.size()); m_to_free->str.push_back(post); m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDS, post); m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDSIZE, svalue.size()); #endif } break; case CURLOPT_HTTPHEADER: case CURLOPT_QUOTE: case CURLOPT_HTTP200ALIASES: case CURLOPT_POSTQUOTE: if (value.is(KindOfArray) || value.is(KindOfObject)) { Array arr = value.toArray(); curl_slist *slist = NULL; for (ArrayIter iter(arr); iter; ++iter) { String key = iter.first().toString(); String val = iter.second().toString(); slist = curl_slist_append(slist, val.c_str()); if (!slist) { raise_warning("Could not build curl_slist"); return false; } } m_to_free->slist.push_back(slist); m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, slist); } else { raise_warning("You must pass either an object or an array with " "the CURLOPT_HTTPHEADER, CURLOPT_QUOTE, " "CURLOPT_HTTP200ALIASES and CURLOPT_POSTQUOTE " "arguments"); return false; } break; case CURLINFO_HEADER_OUT: if (value.toInt64() == 1) { curl_easy_setopt(m_cp, CURLOPT_DEBUGFUNCTION, curl_debug); curl_easy_setopt(m_cp, CURLOPT_DEBUGDATA, (void *)this); curl_easy_setopt(m_cp, CURLOPT_VERBOSE, 1); } else { curl_easy_setopt(m_cp, CURLOPT_DEBUGFUNCTION, NULL); curl_easy_setopt(m_cp, CURLOPT_DEBUGDATA, NULL); curl_easy_setopt(m_cp, CURLOPT_VERBOSE, 0); } break; default: m_error_no = CURLE_FAILED_INIT; throw_invalid_argument("option: %d", option); break; } m_opts.set(int64(option), value); return m_error_no == CURLE_OK; }
Variant HHVM_FUNCTION(dns_get_record, const String& hostname, int type /*= -1*/, VRefParam authnsRef /* = null */, VRefParam addtlRef /* = null */) { IOStatusHelper io("dns_get_record", hostname.data(), type); if (type < 0) type = PHP_DNS_ALL; if (type & ~PHP_DNS_ALL && type != PHP_DNS_ANY) { raise_warning("Type '%d' not supported", type); return false; } unsigned char *cp = NULL, *end = NULL; int qd, an, ns = 0, ar = 0; querybuf answer; /* - We emulate an or'ed type mask by querying type by type. * (Steps 0 - NUMTYPES-1 ) * If additional info is wanted we check again with DNS_T_ANY * (step NUMTYPES / NUMTYPES+1 ) * store_results is used to skip storing the results retrieved in step * NUMTYPES+1 when results were already fetched. * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. * (step NUMTYPES+1 ) */ Array ret; bool first_query = true; bool store_results = true; for (int t = (type == PHP_DNS_ANY ? (PHP_DNS_NUM_TYPES + 1) : 0); t < PHP_DNS_NUM_TYPES + 2 || first_query; t++) { first_query = false; int type_to_fetch; switch (t) { case 0: type_to_fetch = type & PHP_DNS_A ? DNS_T_A : 0; break; case 1: type_to_fetch = type & PHP_DNS_NS ? DNS_T_NS : 0; break; case 2: type_to_fetch = type & PHP_DNS_CNAME ? DNS_T_CNAME : 0; break; case 3: type_to_fetch = type & PHP_DNS_SOA ? DNS_T_SOA : 0; break; case 4: type_to_fetch = type & PHP_DNS_PTR ? DNS_T_PTR : 0; break; case 5: type_to_fetch = type & PHP_DNS_HINFO ? DNS_T_HINFO : 0; break; case 6: type_to_fetch = type & PHP_DNS_MX ? DNS_T_MX : 0; break; case 7: type_to_fetch = type & PHP_DNS_TXT ? DNS_T_TXT : 0; break; case 8: type_to_fetch = type & PHP_DNS_AAAA ? DNS_T_AAAA : 0; break; case 9: type_to_fetch = type & PHP_DNS_SRV ? DNS_T_SRV : 0; break; case 10: type_to_fetch = type & PHP_DNS_NAPTR ? DNS_T_NAPTR : 0; break; case 11: type_to_fetch = type & PHP_DNS_A6 ? DNS_T_A6 : 0; break; case PHP_DNS_NUM_TYPES: store_results = false; continue; default: case (PHP_DNS_NUM_TYPES + 1): type_to_fetch = DNS_T_ANY; break; } if (!type_to_fetch) continue; struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int n = res_nsearch(res, hostname.data(), C_IN, type_to_fetch, answer.qb2, sizeof answer); if (n < 0) { res_nclose(res); php_dns_free_res(res); continue; } HEADER *hp; cp = answer.qb2 + HFIXEDSZ; end = answer.qb2 + n; hp = (HEADER *)&answer; qd = ntohs(hp->qdcount); an = ntohs(hp->ancount); ns = ntohs(hp->nscount); ar = ntohs(hp->arcount); /* Skip QD entries, they're only used by dn_expand later on */ while (qd-- > 0) { n = dn_skipname(cp, end); if (n < 0) { raise_warning("Unable to parse DNS data received"); res_nclose(res); php_dns_free_res(res); return false; } cp += n + QFIXEDSZ; } /* YAY! Our real answers! */ while (an-- && cp && cp < end) { Array retval; cp = php_parserr(cp, end, &answer, type_to_fetch, store_results, retval); if (!retval.empty() && store_results) { ret.append(retval); } } res_nclose(res); php_dns_free_res(res); } Array authns; Array addtl; /* List of Authoritative Name Servers */ while (ns-- > 0 && cp && cp < end) { Array retval; cp = php_parserr(cp, end, &answer, DNS_T_ANY, true, retval); if (!retval.empty()) { authns.append(retval); } } /* Additional records associated with authoritative name servers */ while (ar-- > 0 && cp && cp < end) { Array retval; cp = php_parserr(cp, end, &answer, DNS_T_ANY, true, retval); if (!retval.empty()) { addtl.append(retval); } } authnsRef = authns; addtlRef = addtl; return ret; }
ArrayData* GlobalsArray::EscalateForSort(ArrayData* ad, SortFunction sf) { raise_warning("Sorting the $GLOBALS array is not supported"); return ad; }
void HHVM_FUNCTION(header, const String& str, bool replace /* = true */, int http_response_code /* = 0 */) { if (HHVM_FN(headers_sent)()) { raise_warning("Cannot modify header information - headers already sent"); } String header = HHVM_FN(rtrim)(str); // new line safety check // NOTE: PHP actually allows "\n " and "\n\t" to fall through. Is that bad // for security? if (header.find('\n') >= 0 || header.find('\r') >= 0) { raise_warning("Header may not contain more than a single header, " "new line detected"); return; } Transport *transport = g_context->getTransport(); if (transport && header.size()) { const char *header_line = header.data(); // handle single line of status code if ((header.size() >= 5 && strncasecmp(header_line, "HTTP/", 5) == 0) || (header.size() >= 7 && strncasecmp(header_line, "Status:", 7) == 0)) { int code = 200; const char *reason = nullptr; for (const char *ptr = header_line + 5; *ptr; ptr++) { if (*ptr == ' ' && *(ptr + 1) != ' ') { code = atoi(ptr + 1); for (ptr++; *ptr; ptr++) { if (*ptr == ' ' && *(ptr + 1) != ' ') { reason = ptr + 1; break; } } break; } } if (code) { transport->setResponse(code, reason); } return; } const char *colon_offset = strchr(header_line, ':'); String newHeader; if (colon_offset) { if (!strncasecmp(header_line, "Content-Type", colon_offset - header_line)) { const char *ptr = colon_offset+1, *mimetype = NULL; while (*ptr == ' ') ptr++; mimetype = ptr; if (strncmp(mimetype, "text/", 5) == 0 && strstr(mimetype, "charset=") == NULL) { newHeader = header + ";charset=utf-8"; } } } if (replace) { transport->replaceHeader(newHeader.empty() ? header : newHeader); } else { transport->addHeader(newHeader.empty() ? header : newHeader); } if (http_response_code) { transport->setResponse(http_response_code); } } }
void Object::setToDefaultObject() { raise_warning(Strings::CREATING_DEFAULT_OBJECT); operator=(SystemLib::AllocStdClassObject()); }
Variant HHVM_FUNCTION(getaddrinfo, const String& host, const String& port, int family /* = 0 */, int socktype /* = 0 */, int protocol /* = 0 */, int flags /* = 0 */) { const char *hptr = NULL, *pptr = NULL; if (!host.empty()) { hptr = host.c_str(); } if (!port.empty()) { pptr = port.c_str(); } struct addrinfo hints, *res; struct addrinfo *res0 = NULL; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = socktype; hints.ai_protocol = protocol; hints.ai_flags = flags; error = getaddrinfo(hptr, pptr, &hints, &res0); if (error) { raise_warning("%s", gai_strerror(error)); if (res0) { freeaddrinfo(res0); } return false; } Array ret = Array::Create(); for (res = res0; res; res = res->ai_next) { Array data = make_map_array( s_family, res->ai_family, s_socktype, res->ai_socktype, s_protocol, res->ai_protocol ); switch (res->ai_addr->sa_family) { case AF_INET: { struct sockaddr_in *a; String buffer = ipaddr_convert(res->ai_addr, sizeof(*a)); if (!buffer.empty()) { a = (struct sockaddr_in *)res->ai_addr; data.set( s_sockaddr, make_map_array( s_address, buffer, s_port, ntohs(a->sin_port) ) ); } break; } case AF_INET6: { struct sockaddr_in6 *a; String buffer = ipaddr_convert(res->ai_addr, sizeof(*a)); if (!buffer.empty()) { a = (struct sockaddr_in6 *)res->ai_addr; data.set( s_sockaddr, make_map_array( s_address, buffer, s_port, ntohs(a->sin6_port), s_flow_info, (int32_t)a->sin6_flowinfo, s_scope_id, (int32_t)a->sin6_scope_id ) ); } break; } default: data.set(s_sockaddr, empty_array()); break; } ret.append(data); } if (res0) { freeaddrinfo(res0); } return ret; }