Arquivos
hhvm/hphp/runtime/ext/ext_url.cpp
T
Drew Paroski 84b9d9a3a2 Separate resources from objects, part 1
In HHVM (and HPHPc before it) we've been piggybacking resources on the
KindOfObject machinery. At the language level, resource is considered to
be a different type than object, and there are a number of differences
in behavior between objects and resources (ex. resources don't allow for
dynamic properties, resources don't work with the clone operator, the
"(object)" cast behaves differently for resources vs. objects, etc).

Piggybacking resources on the KindOfObject machinery has some downsides.
Code that deals with KindOfObject values often needs to check if the value
is a resource and go down a different code path. This makes things harder
to maintain and harder to keep parity with Zend. Also, these extra branches
hurt performance a little, and they make it harder for the JIT to do a good
job in some cases when its generating machine code that operates on objects.

This diff prepares the code base for a new KindOfResource type by adding a
new "Resource" smart pointer type (currently a typedef for the Object smart
pointer type) and it updates the C++ code and the idl files appropriately.
This diff is essentially a cosmetic change and should not impact run time
behavior. In the next diff (part 2) we'll actually add a new KindOfResource
type, detach ResourceData from the ObjectData inheritence hierarchy, and
provide a real implementation for the Resource smart pointer type (instead
of just aliasing the Object smart pointer type).
2013-07-10 11:16:33 -07:00

292 linhas
8.9 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/ext/ext_url.h"
#include "hphp/runtime/base/string_util.h"
#include "hphp/runtime/base/zend/zend_url.h"
#include "hphp/runtime/base/util/string_buffer.h"
#include "hphp/runtime/ext/ext_curl.h"
#include "hphp/runtime/ext/ext_string.h"
#include "hphp/runtime/ext/ext_file.h"
#include "hphp/runtime/ext/ext_preg.h"
#include "hphp/runtime/ext/ext_options.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
Variant f_base64_decode(CStrRef data, bool strict /* = false */) {
String decoded = StringUtil::Base64Decode(data, strict);
if (decoded.isNull()) {
return false;
}
return decoded;
}
String f_base64_encode(CStrRef data) {
String encoded = StringUtil::Base64Encode(data);
if (encoded.isNull()) {
return false;
}
return encoded;
}
Variant f_get_headers(CStrRef url, int format /* = 0 */) {
Variant c = f_curl_init();
f_curl_setopt(c.toResource(), k_CURLOPT_URL, url);
f_curl_setopt(c.toResource(), k_CURLOPT_RETURNTRANSFER, true);
f_curl_setopt(c.toResource(), k_CURLOPT_HEADER, 1);
Variant res = f_curl_exec(c.toResource());
if (same(res, false)) {
return false;
}
String response = res.toString();
int pos = response.find("\r\n\r\n");
if (pos != String::npos) {
response = response.substr(0, pos);
}
Array ret = f_explode("\r\n", response).toArray();
if (!format) {
return ret;
}
Array assoc;
for (ArrayIter iter(ret); iter; ++iter) {
Array tokens = f_explode(": ", iter.second(), 2).toArray();
if (tokens.size() == 2) {
assoc.set(tokens[0], tokens[1]);
} else {
assoc.append(iter.second());
}
}
return assoc;
}
static String normalize_variable_name(CStrRef name) {
StringBuffer sb;
for (int i = 0; i < name.size(); i++) {
char ch = name.charAt(i);
if ((i > 0 && ch >= '0' && ch <= '9') ||
(ch >= 'a' && ch <= 'z') ||
(ch == '_')) {
sb.append(ch);
} else if (ch >= 'A' && ch <= 'Z') {
sb.append((char)(ch + 'a' - 'A'));
} else {
sb.append('_');
}
}
return sb.detach();
}
Array f_get_meta_tags(CStrRef filename, bool use_include_path /* = false */) {
String f = f_file_get_contents(filename);
Variant matches;
f_preg_match_all("/<meta\\s+name=\"(.*?)\"\\s+content=\"(.*?)\".*?>/s",
f, ref(matches), k_PREG_SET_ORDER);
Array ret = Array::Create();
for (ArrayIter iter(matches.toArray()); iter; ++iter) {
Array pair = iter.second().toArray();
ret.set(normalize_variable_name(pair[1].toString()), pair[2]);
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
static void url_encode_array(StringBuffer &ret, CVarRef varr,
std::set<void*> &seen_arrs,
CStrRef num_prefix, CStrRef key_prefix,
CStrRef key_suffix, CStrRef arg_sep) {
void *id = varr.is(KindOfArray) ?
(void*)varr.getArrayData() : (void*)varr.getObjectData();
if (!seen_arrs.insert(id).second) {
return; // recursive
}
Array arr = varr.toArray();
for (ArrayIter iter(arr); iter; ++iter) {
Variant data = iter.second();
if (data.isNull() || data.isResource()) continue;
String key = iter.first();
bool numeric = key.isNumeric();
if (data.is(KindOfArray) || data.is(KindOfObject)) {
String encoded;
if (numeric) {
encoded = key;
} else {
encoded = StringUtil::UrlEncode(key);
}
StringBuffer new_prefix(key_prefix.size() + num_prefix.size() +
encoded.size() + key_suffix.size() + 4);
new_prefix += key_prefix;
if (numeric) new_prefix += num_prefix;
new_prefix += encoded;
new_prefix += key_suffix;
new_prefix += "%5B";
url_encode_array(ret, data, seen_arrs, String(),
new_prefix.detach(), String("%5D", AttachLiteral),
arg_sep);
} else {
if (!ret.empty()) {
ret += arg_sep;
}
ret += key_prefix;
if (numeric) {
ret += num_prefix;
ret += key;
} else {
ret += StringUtil::UrlEncode(key);
}
ret += key_suffix;
ret += "=";
if (data.isInteger() || data.is(KindOfBoolean)) {
ret += String(data.toInt64());
} else if (data.is(KindOfDouble)) {
ret += String(data.toDouble());
} else {
ret += StringUtil::UrlEncode(data.toString());
}
}
}
}
static const StaticString s_arg_separator_output("arg_separator.output");
Variant f_http_build_query(CVarRef formdata,
CStrRef numeric_prefix /* = null_string */,
CStrRef arg_separator /* = null_string */) {
if (!formdata.is(KindOfArray) && !formdata.is(KindOfObject)) {
throw_invalid_argument("formdata: (need Array or Object)");
return false;
}
String arg_sep;
if (arg_separator.isNull()) {
arg_sep = f_ini_get(s_arg_separator_output);
} else {
arg_sep = arg_separator;
}
StringBuffer ret(1024);
std::set<void*> seen_arrs;
url_encode_array(ret, formdata, seen_arrs,
numeric_prefix, String(), String(), arg_sep);
return ret.detach();
}
///////////////////////////////////////////////////////////////////////////////
static const StaticString
s_scheme("scheme"),
s_host("host"),
s_user("user"),
s_pass("pass"),
s_path("path"),
s_query("query"),
s_fragment("fragment"),
s_port("port");
#define RETURN_COMPONENT(name) \
if (resource.name != NULL) { \
String ret(resource.name, AttachString); \
resource.name = NULL; \
return ret; \
} \
#define SET_COMPONENT(name) \
if (resource.name != NULL) { \
ret.set(s_ ## name, String(resource.name, AttachString)); \
resource.name = NULL; \
} \
#define PHP_URL_SCHEME 0
#define PHP_URL_HOST 1
#define PHP_URL_PORT 2
#define PHP_URL_USER 3
#define PHP_URL_PASS 4
#define PHP_URL_PATH 5
#define PHP_URL_QUERY 6
#define PHP_URL_FRAGMENT 7
Variant f_parse_url(CStrRef url, int component /* = -1 */) {
Url resource;
if (!url_parse(resource, url.data(), url.size())) {
raise_notice("invalid url: %s", url.data());
return false;
}
if (component > -1) {
switch (component) {
case PHP_URL_SCHEME: RETURN_COMPONENT(scheme); break;
case PHP_URL_HOST: RETURN_COMPONENT(host); break;
case PHP_URL_USER: RETURN_COMPONENT(user); break;
case PHP_URL_PASS: RETURN_COMPONENT(pass); break;
case PHP_URL_PATH: RETURN_COMPONENT(path); break;
case PHP_URL_QUERY: RETURN_COMPONENT(query); break;
case PHP_URL_FRAGMENT: RETURN_COMPONENT(fragment); break;
case PHP_URL_PORT:
if (resource.port) {
return resource.port;
}
break;
default:
throw_invalid_argument("component: %d", component);
return false;
}
return uninit_null();
}
ArrayInit ret(8);
SET_COMPONENT(scheme);
SET_COMPONENT(host);
SET_COMPONENT(user);
SET_COMPONENT(pass);
SET_COMPONENT(path);
SET_COMPONENT(query);
SET_COMPONENT(fragment);
if (resource.port) {
ret.set(s_port, (int64_t)resource.port);
}
return ret.create();
}
String f_rawurldecode(CStrRef str) {
return StringUtil::UrlDecode(str, false);
}
String f_rawurlencode(CStrRef str) {
return StringUtil::UrlEncode(str, false);
}
String f_urldecode(CStrRef str) {
return StringUtil::UrlDecode(str, true);
}
String f_urlencode(CStrRef str) {
return StringUtil::UrlEncode(str, true);
}
///////////////////////////////////////////////////////////////////////////////
}