Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / url-file.cpp
blob6046e54cb8186bcfadafffee584c8dc07fb0f971
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/url-file.h"
18 #include <vector>
19 #include "hphp/runtime/base/runtime-error.h"
20 #include "hphp/runtime/ext/pcre/ext_pcre.h"
21 #include "hphp/runtime/ext/stream/ext_stream.h"
22 #include "hphp/runtime/ext/url/ext_url.h"
23 #include "hphp/runtime/base/php-globals.h"
24 #include "hphp/runtime/vm/runtime.h"
25 #include "hphp/runtime/vm/jit/translator-inline.h"
27 namespace HPHP {
29 ///////////////////////////////////////////////////////////////////////////////
31 const StaticString s_http_response_header("http_response_header");
32 const StaticString s_http("http");
33 const StaticString s_tcp_socket("tcp_socket");
35 ///////////////////////////////////////////////////////////////////////////////
37 UrlFile::UrlFile(const char *method /* = "GET" */,
38 const Array& headers /* = null_array */,
39 const String& postData /* = null_string */,
40 int maxRedirect /* = 20 */,
41 int timeout /* = -1 */,
42 bool ignoreErrors /* = false */)
43 : MemFile(s_http, s_tcp_socket) {
44 m_get = (method == nullptr || strcasecmp(method, "GET") == 0);
45 m_method = method;
46 m_headers = headers;
47 m_postData = postData;
48 m_maxRedirect = maxRedirect;
49 m_timeout = timeout;
50 m_ignoreErrors = ignoreErrors;
51 setIsLocal(false);
54 void UrlFile::sweep() {
55 using std::string;
56 m_error.~string();
57 MemFile::sweep();
60 const StaticString
61 s_remove_user_pass_pattern("#://[^@]+@#"),
62 s_remove_user_pass_replace("://");
64 void UrlFile::setProxy(const String& proxy_host, int proxy_port,
65 const String& proxy_user, const String& proxy_pass) {
66 m_proxyHost = proxy_host.c_str();
67 m_proxyPort = proxy_port;
68 m_proxyUsername = proxy_user.c_str();
69 m_proxyPassword = proxy_pass.c_str();
72 bool UrlFile::open(const String& input_url, const String& mode) {
73 String url = input_url;
74 const char* modestr = mode.c_str();
75 if (strchr(modestr, '+') || strchr(modestr, 'a') || strchr(modestr, 'w')) {
76 std::string msg = "cannot open a url stream for write/append operation: ";
77 msg += url.c_str();
78 m_error = msg;
79 return false;
81 HttpClient http(m_timeout, m_maxRedirect);
82 auto ctx = this->getStreamContext();
83 if (ctx) {
84 http.setStreamContextOptions(ctx->getOptions());
86 m_response.clear();
88 if (!m_proxyHost.empty()) {
89 http.proxy(m_proxyHost, m_proxyPort, m_proxyUsername, m_proxyPassword);
92 HeaderMap *pHeaders = nullptr;
93 HeaderMap requestHeaders;
94 if (!m_headers.empty()) {
95 pHeaders = &requestHeaders;
96 for (ArrayIter iter(m_headers); iter; ++iter) {
97 requestHeaders[std::string(iter.first().toString().data())].
98 push_back(iter.second().toString().data());
102 Variant user = f_parse_url(url, k_PHP_URL_USER);
103 if (user.isString()) {
104 Variant pass = f_parse_url(url, k_PHP_URL_PASS);
105 http.auth(user.toString().c_str(), pass.toString().c_str());
106 url = HHVM_FN(preg_replace)(
107 s_remove_user_pass_pattern,
108 s_remove_user_pass_replace,
109 url,
111 ).toString();
114 int code;
115 req::vector<String> responseHeaders;
116 if (m_get) {
117 code = http.get(url.c_str(), m_response, pHeaders, &responseHeaders);
118 } else {
119 code = http.request(m_method,
120 url.c_str(), m_postData.data(), m_postData.size(),
121 m_response, pHeaders, &responseHeaders);
124 m_responseHeaders.reset();
125 for (unsigned int i = 0; i < responseHeaders.size(); i++) {
126 m_responseHeaders.append(responseHeaders[i]);
128 VMRegAnchor vra;
129 ActRec* fp = vmfp();
130 if (fp->skipFrame()) fp = g_context->getPrevVMStateSkipFrame(fp);
131 auto id = fp->func()->lookupVarId(s_http_response_header.get());
132 if (id != kInvalidId) {
133 auto tvTo = frame_local(fp, id);
134 Variant varFrom(m_responseHeaders);
135 const auto tvFrom(varFrom.asTypedValue());
136 if (tvTo->m_type == KindOfRef) {
137 tvTo = tvTo->m_data.pref->tv();
139 tvDup(*tvFrom, *tvTo);
140 } else if ((fp->func()->attrs() & AttrMayUseVV) && fp->hasVarEnv()) {
141 fp->getVarEnv()->set(s_http_response_header.get(),
142 Variant(m_responseHeaders).asTypedValue());
146 * If code == 0, Curl failed to connect; per PHP5, ignore_errors just means
147 * to not worry if we get an http resonse code that isn't between 200 and 400,
148 * but we shouldn't ignore other errors.
149 * all status codes in the 2xx range are defined by the specification as
150 * successful;
151 * all status codes in the 3xx range are for redirection, and so also should
152 * never fail.
154 if ((code >= 200 && code < 400) || (m_ignoreErrors && code != 0)) {
155 setName(url.toCppString());
156 m_data = const_cast<char*>(m_response.data());
157 m_len = m_response.size();
158 return true;
159 } else {
160 m_error = http.getLastError().c_str();
161 return false;
165 int64_t UrlFile::writeImpl(const char* /*buffer*/, int64_t /*length*/) {
166 assert(m_len != -1);
167 raise_fatal_error((std::string("cannot write a url stream: ") +
168 getName()).c_str());
171 bool UrlFile::flush() {
172 assert(m_len != -1);
173 raise_fatal_error((std::string("cannot flush a url stream: ") +
174 getName()).c_str());
177 String UrlFile::getLastError() {
178 return m_error;
181 ///////////////////////////////////////////////////////////////////////////////