bool MemFile::open(const String& filename, const String& mode) { assert(m_len == -1); // mem files are read-only const char* mode_str = mode.c_str(); if (strchr(mode_str, '+') || strchr(mode_str, 'a') || strchr(mode_str, 'w')) { return false; } int len = INT_MIN; bool compressed = false; const char *data = StaticContentCache::TheFileCache->read(filename.c_str(), len, compressed); assert(len >= 0); if (compressed) { assert(RuntimeOption::EnableOnDemandUncompress); data = gzdecode(data, len); if (data == nullptr) { throw FatalErrorException("cannot unzip compressed data"); } m_data = data; m_malloced = true; m_len = len; return true; } m_name = (std::string) filename; m_data = data; m_len = len; return true; }
Variant f_gzdecode(CStrRef data) { int len = data.size(); char *ret = gzdecode(data.data(), len); if (ret == NULL) { return false; } return String(ret, len, AttachString); }
void StringUtil::InitLiteralStrings(StaticString literalStrings[], int nliteralStrings, const char *literalStringBuf, int literalStringBufSize, const char *literalStringLen, int literalStringLenSize) { int bufSize = literalStringBufSize; int lenSize = literalStringLenSize; static char *uncompressedBuf; // permanently allocated char *uncompressedLen; if (uncompressedBuf) { throw Exception("StringUtil::InitLiteralStrings called twice"); } uncompressedBuf = gzdecode(literalStringBuf, bufSize); if (uncompressedBuf == NULL) { throw Exception("Bad literalStringBuf %p", literalStringBuf); } uncompressedLen = gzdecode(literalStringLen, lenSize); if (uncompressedLen == NULL) { throw Exception("Bad literalStringLen %p", literalStringLen); } const char *pb = uncompressedBuf; const char *pl = uncompressedLen; const char *endBuf = pb + bufSize; const char *endLen = pl + lenSize; for (int i = 0; i < nliteralStrings; i++) { int size; memcpy(&size, pl, sizeof(size)); literalStrings[i].init(pb, size); pb += size; ASSERT(*pb == '\0'); pb++; pl += sizeof(size); } if (pb != endBuf) { throw Exception("Bad literalStringBuf %p", literalStringBuf); } if (pl != endLen) { throw Exception("Bad literalStringLen %p", literalStringLen); } free(uncompressedLen); }
void MemFile::unzip() { ASSERT(m_len != -1); ASSERT(!m_malloced); ASSERT(m_cursor == 0); int len = m_len; char *data = gzdecode(m_data, len); if (data == NULL) { throw FatalErrorException((string("cannot unzip mem stream: ") + m_name).c_str()); } m_data = data; m_malloced = true; m_len = len; }
void MemFile::unzip() { assertx(m_len != -1); assertx(!m_malloced); assertx(m_cursor == 0); int len = m_len; char *data = gzdecode(m_data, len); if (data == nullptr) { raise_fatal_error((std::string("cannot unzip mem stream: ") + getName()).c_str()); } m_data = data; m_malloced = true; m_len = len; }
void ArrayUtil::InitScalarArrays(Array arrs[], int nArrs, const char *scalarArrayData, int scalarArrayDataSize) { int len = scalarArrayDataSize; char *uncompressed = gzdecode(scalarArrayData, len); if (uncompressed == nullptr) { throw Exception("Bad scalarArrayData %p", scalarArrayData); } Variant v(unserialize_from_buffer(uncompressed, len)); assert(v.isArray()); Array scalarArrays = v; assert(scalarArrays.size() == nArrs); for (int i = 0; i < nArrs; i++) { arrs[i] = scalarArrays[i]; arrs[i].setEvalScalar(); } }
void ArrayUtil::InitScalarArrays(Array arrs[], int nArrs, const char *scalarArrayData, int scalarArrayDataSize) { int len = scalarArrayDataSize; char *uncompressed = gzdecode(scalarArrayData, len); if (uncompressed == NULL) { throw Exception("Bad scalarArrayData %p", scalarArrayData); } String s = String(uncompressed, len, AttachString); Variant v = f_unserialize(s); ASSERT(v.isArray()); Array scalarArrays = v; ASSERT(scalarArrays.size() == nArrs); for (int i = 0; i < nArrs; i++) { arrs[i] = scalarArrays[i]; arrs[i].setStatic(); } }
void LibEventHttpClient::onRequestCompleted(evhttp_request* request) { if (!request) { // eek -- this is just a clean-up notification because the connection's // been closed, but we already dealt with it in onConnectionClosed return; } // response code line m_code = request->response_code; if (request->response_code_line) { m_codeLine = request->response_code_line; } bool gzip = false; // response headers for (evkeyval *p = ((evkeyvalq_*)request->input_headers)->tqh_first; p; p = p->next.tqe_next) { if (p->key && p->value) { if (strcasecmp(p->key, "Content-Encoding") == 0 && strncmp(p->value, "gzip", 4) == 0 && (!p->value[4] || isspace(p->value[4]))) { // in the (illegal) case of multiple Content-Encoding headers, any one // with the value 'gzip' means we treat it as gzip. gzip = true; } m_responseHeaders.push_back(std::string(p->key) + ": " + p->value); } } // response body m_len = EVBUFFER_LENGTH(request->input_buffer); if (gzip) { m_response = gzdecode((const char*)EVBUFFER_DATA(request->input_buffer), m_len); } else { m_response = (char*)malloc(m_len + 1); strncpy(m_response, (char*)EVBUFFER_DATA(request->input_buffer), m_len); m_response[m_len] = '\0'; } ++m_requests; event_base_loopbreak(m_eventBase); }
void LibEventHttpClient::onRequestCompleted() { ASSERT(m_request); ASSERT(m_request->input_buffer); // response code line m_code = m_request->response_code; if (m_request->response_code_line) { m_codeLine = m_request->response_code_line; } bool gzip = false; // response headers for (evkeyval *p = ((evkeyvalq_*)m_request->input_headers)->tqh_first; p; p = p->next.tqe_next) { if (p->key && p->value) { if (strcasecmp(p->key, "Content-Encoding") == 0 && strncmp(p->value, "gzip", 4) == 0 && (!p->value[4] || isspace(p->value[4]))) { // in the (illegal) case of multiple Content-Encoding headers, any one // with the value 'gzip' means we treat it as gzip. gzip = true; } m_responseHeaders.push_back(string(p->key) + ": " + p->value); } } // response body m_len = EVBUFFER_LENGTH(m_request->input_buffer); if (gzip) { m_response = gzdecode((const char*)EVBUFFER_DATA(m_request->input_buffer), m_len); } else { m_response = (char*)malloc(m_len + 1); strncpy(m_response, (char*)EVBUFFER_DATA(m_request->input_buffer), m_len); m_response[m_len] = '\0'; } // libevent will call evhttp_request_free(m_request) automatically m_request = NULL; event_base_loopbreak(m_eventBase); }
int64_t FileCache::fileSize(const char *name, bool isRelative) const { if (!name || !*name) return -1; if (isRelative) { FileMap::const_iterator iter = m_files.find(name); if (iter != m_files.end()) { const Buffer &buf = iter->second; if (buf.len >= 0) return buf.len; if (buf.cdata) { int new_len = buf.clen; char *uncompressed = gzdecode(buf.cdata, new_len); if (uncompressed == nullptr) { throw Exception("Bad compressed data in archive %s", name); } else { free(uncompressed); } return new_len; } } return -1; } return fileSize(GetRelativePath(name).c_str(), true); }
bool MemFile::open(const String& filename, const String& mode) { assertx(m_len == -1); // mem files are read-only const char* mode_str = mode.c_str(); if (strchr(mode_str, '+') || strchr(mode_str, 'a') || strchr(mode_str, 'w')) { return false; } int len = INT_MIN; bool compressed = false; char *data = StaticContentCache::TheFileCache->read(filename.c_str(), len, compressed); // -1: PHP file; -2: directory if (len != INT_MIN && len != -1 && len != -2) { assertx(len >= 0); if (compressed) { assertx(RuntimeOption::EnableOnDemandUncompress); data = gzdecode(data, len); if (data == nullptr) { raise_fatal_error("cannot unzip compressed data"); } m_data = data; m_malloced = true; m_len = len; return true; } setName(filename.toCppString()); m_data = data; m_len = len; return true; } if (len != INT_MIN) { Logger::Error("Cannot open a PHP file or a directory as MemFile: %s", filename.c_str()); } return false; }
void HttpRequestHandler::handleRequest(Transport *transport) { ExecutionProfiler ep(ThreadInfo::RuntimeFunctions); Logger::OnNewRequest(); GetAccessLog().onNewRequest(); transport->enableCompression(); ServerStatsHelper ssh("all", ServerStatsHelper::TRACK_MEMORY); Logger::Verbose("receiving %s", transport->getCommand().c_str()); // will clear all extra logging when this function goes out of scope StackTraceNoHeap::ExtraLoggingClearer clearer; StackTraceNoHeap::AddExtraLogging("URL", transport->getUrl()); // resolve virtual host const VirtualHost *vhost = HttpProtocol::GetVirtualHost(transport); assert(vhost); if (vhost->disabled() || vhost->isBlocking(transport->getCommand(), transport->getRemoteHost())) { transport->sendString("Not Found", 404); return; } // don't serve the request if it's been sitting in queue for longer than our // allowed request timeout. int requestTimeoutSeconds = vhost->getRequestTimeoutSeconds(getDefaultTimeout()); if (requestTimeoutSeconds > 0) { timespec now; Timer::GetMonotonicTime(now); const timespec& queueTime = transport->getQueueTime(); if (gettime_diff_us(queueTime, now) > requestTimeoutSeconds * 1000000) { transport->sendString("Service Unavailable", 503); m_requestTimedOutOnQueue->addValue(1); return; } } ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); // resolve source root string host = transport->getHeader("Host"); SourceRootInfo sourceRootInfo(host.c_str()); if (sourceRootInfo.error()) { sourceRootInfo.handleError(transport); return; } // request URI string pathTranslation = m_pathTranslation ? vhost->getPathTranslation().c_str() : ""; RequestURI reqURI(vhost, transport, sourceRootInfo.path(), pathTranslation); if (reqURI.done()) { return; // already handled with redirection or 404 } string path = reqURI.path().data(); string absPath = reqURI.absolutePath().data(); // determine whether we should compress response bool compressed = transport->decideCompression(); const char *data; int len; const char *ext = reqURI.ext(); if (reqURI.forbidden()) { transport->sendString("Forbidden", 403); return; } bool cachableDynamicContent = (!RuntimeOption::StaticFileGenerators.empty() && RuntimeOption::StaticFileGenerators.find(path) != RuntimeOption::StaticFileGenerators.end()); // If this is not a php file, check the static and dynamic content caches if (ext && strcasecmp(ext, "php") != 0) { if (RuntimeOption::EnableStaticContentCache) { bool original = compressed; // check against static content cache if (StaticContentCache::TheCache.find(path, data, len, compressed)) { Util::ScopedMem decompressed_data; // (qigao) not calling stat at this point because the timestamp of // local cache file is not valuable, maybe misleading. This way // the Last-Modified header will not show in response. // stat(RuntimeOption::FileCache.c_str(), &st); if (!original && compressed) { data = gzdecode(data, len); if (data == nullptr) { throw FatalErrorException("cannot unzip compressed data"); } decompressed_data = const_cast<char*>(data); compressed = false; } sendStaticContent(transport, data, len, 0, compressed, path, ext); StaticContentCache::TheFileCache->adviseOutMemory(); ServerStats::LogPage(path, 200); GetAccessLog().log(transport, vhost); return; } } if (RuntimeOption::EnableStaticContentFromDisk) { String translated = File::TranslatePath(String(absPath)); if (!translated.empty()) { CstrBuffer sb(translated.data()); if (sb.valid()) { struct stat st; st.st_mtime = 0; stat(translated.data(), &st); sendStaticContent(transport, sb.data(), sb.size(), st.st_mtime, false, path, ext); ServerStats::LogPage(path, 200); GetAccessLog().log(transport, vhost); return; } } } // check static contents that were generated by dynamic pages if (cachableDynamicContent) { // check against dynamic content cache assert(transport->getUrl()); string key = path + transport->getUrl(); if (DynamicContentCache::TheCache.find(key, data, len, compressed)) { sendStaticContent(transport, data, len, 0, compressed, path, ext); ServerStats::LogPage(path, 200); GetAccessLog().log(transport, vhost); return; } } } // proxy any URLs that not specified in ServeURLs if (!RuntimeOption::ProxyOrigin.empty() && ((RuntimeOption::UseServeURLs && RuntimeOption::ServeURLs.find(path) == RuntimeOption::ServeURLs.end()) || (RuntimeOption::UseProxyURLs && (RuntimeOption::ProxyURLs.find(path) != RuntimeOption::ProxyURLs.end() || MatchAnyPattern(path, RuntimeOption::ProxyPatterns) || (abs(rand()) % 100) < RuntimeOption::ProxyPercentage)))) { for (int i = 0; i < RuntimeOption::ProxyRetry; i++) { bool force = (i == RuntimeOption::ProxyRetry - 1); // last one if (handleProxyRequest(transport, force)) break; } return; } // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); // main body hphp_session_init(); ThreadInfo::s_threadInfo->m_reqInjectionData. setTimeout(requestTimeoutSeconds); bool ret = false; try { ret = executePHPRequest(transport, reqURI, sourceRootInfo, cachableDynamicContent); } catch (const Eval::DebuggerException &e) { transport->sendString(e.what(), 200); transport->onSendEnd(); hphp_context_exit(g_context.getNoCheck(), true, true, transport->getUrl()); } catch (...) { Logger::Error("Unhandled exception in HPHP server engine."); } GetAccessLog().log(transport, vhost); /* * HPHP logs may need to access data in ServerStats, so we have to * clear the hashtable after writing the log entry. */ ServerStats::Reset(); hphp_session_exit(); HttpProtocol::ClearRecord(ret, tmpfile); }
EXTERNALLY_VISIBLE void apc_load_impl_compressed (struct cache_info *info, int *int_lens, const char *int_keys, long long *int_values, int *char_lens, const char *char_keys, char *char_values, int *string_lens, const char *strings, int *object_lens, const char *objects, int *thrift_lens, const char *thrifts, int *other_lens, const char *others) { if (!apcExtension::ForceConstLoadToAPC) { if (apcExtension::EnableConstLoad && info && info->use_const) return; } auto& s = s_apc_store[0]; { int count = int_lens[0]; int len = int_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *keys = gzdecode(int_keys, len); if (keys == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(keys); const char *k = keys; long long* v = int_values; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = k; item.len = int_lens[i + 2]; s.constructPrime(*v++, item); k += int_lens[i + 2] + 1; // skip \0 } s.prime(vars); assert((k - keys) == len); } } { int count = char_lens[0]; int len = char_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *keys = gzdecode(char_keys, len); if (keys == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(keys); const char *k = keys; char *v = char_values; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = k; item.len = char_lens[i + 2]; switch (*v++) { case 0: s.constructPrime(false, item); break; case 1: s.constructPrime(true , item); break; case 2: s.constructPrime(uninit_null() , item); break; default: throw Exception("bad apc archive, unknown char type"); } k += char_lens[i + 2] + 1; // skip \0 } s.prime(vars); assert((k - keys) == len); } } { int count = string_lens[0] / 2; int len = string_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(strings, len); if (decoded == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = string_lens[i + i + 2]; p += string_lens[i + i + 2] + 1; // skip \0 // Strings would be copied into APC anyway. String value(p, string_lens[i + i + 3], CopyString); // todo: t2539893: check if value is already a static string s.constructPrime(value, item, false); p += string_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } { int count = object_lens[0] / 2; int len = object_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(objects, len); if (decoded == NULL) throw Exception("bad compressed APC archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = object_lens[i + i + 2]; p += object_lens[i + i + 2] + 1; // skip \0 String value(p, object_lens[i + i + 3], CopyString); s.constructPrime(value, item, true); p += object_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } { int count = thrift_lens[0] / 2; int len = thrift_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(thrifts, len); if (decoded == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = thrift_lens[i + i + 2]; p += thrift_lens[i + i + 2] + 1; // skip \0 String value(p, thrift_lens[i + i + 3], CopyString); Variant success; Variant v = f_fb_unserialize(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, f_fb_unserialize failed"); } s.constructPrime(v, item); p += thrift_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } { int count = other_lens[0] / 2; int len = other_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(others, len); if (decoded == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = other_lens[i + i + 2]; p += other_lens[i + i + 2] + 1; // skip \0 String value(p, other_lens[i + i + 3], CopyString); Variant v = unserialize_from_string(value); if (same(v, false)) { // we can't possibly get here if it was a boolean "false" that's // supposed to be serialized as a char throw Exception("bad apc archive, unserialize_from_string failed"); } s.constructPrime(v, item); p += other_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } }
EXTERNALLY_VISIBLE void const_load_impl_compressed (struct cache_info *info, int *int_lens, const char *int_keys, long long *int_values, int *char_lens, const char *char_keys, char *char_values, int *string_lens, const char *strings, int *object_lens, const char *objects, int *thrift_lens, const char *thrifts, int *other_lens, const char *others) { if (!apcExtension::EnableConstLoad || !info || !info->use_const) return; { int count = int_lens[0]; int len = int_lens[1]; if (count) { char *keys = gzdecode(int_keys, len); if (keys == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(keys); const char *k = keys; long long* v = int_values; for (int i = 0; i < count; i++) { String key(k, int_lens[i + 2], CopyString); int64_t value = *v++; const_load_set(key, value); k += int_lens[i + 2] + 1; } assert((k - keys) == len); } } { int count = char_lens[0]; int len = char_lens[1]; if (count) { char *keys = gzdecode(char_keys, len); if (keys == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(keys); const char *k = keys; char *v = char_values; for (int i = 0; i < count; i++) { String key(k, char_lens[i + 2], CopyString); Variant value; switch (*v++) { case 0: value = false; break; case 1: value = true; break; case 2: value = uninit_null(); break; default: throw Exception("bad const archive, unknown char type"); } const_load_set(key, value); k += char_lens[i + 2] + 1; } assert((k - keys) == len); } } { int count = string_lens[0] / 2; int len = string_lens[1]; if (count) { char *decoded = gzdecode(strings, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, string_lens[i + i + 2], CopyString); p += string_lens[i + i + 2] + 1; String value(p, string_lens[i + i + 3], CopyString); const_load_set(key, value); p += string_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } // unserialize_from_string object is extremely slow here; // currently turned off: no objects in haste_maps. if (false) { int count = object_lens[0] / 2; int len = object_lens[1]; if (count) { char *decoded = gzdecode(objects, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, object_lens[i + i + 2], CopyString); p += object_lens[i + i + 2] + 1; String value(p, object_lens[i + i + 3], CopyString); const_load_set(key, unserialize_from_string(value)); p += object_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } { int count = thrift_lens[0] / 2; int len = thrift_lens[1]; if (count) { char *decoded = gzdecode(thrifts, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, thrift_lens[i + i + 2], CopyString); p += thrift_lens[i + i + 2] + 1; String value(p, thrift_lens[i + i + 3], CopyString); Variant success; Variant v = f_fb_unserialize(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, f_fb_unserialize failed"); } const_load_set(key, v); p += thrift_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } {//Would we use others[]? int count = other_lens[0] / 2; int len = other_lens[1]; if (count) { char *decoded = gzdecode(others, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, other_lens[i + i + 2], CopyString); p += other_lens[i + i + 2] + 1; String value(p, other_lens[i + i + 3], CopyString); Variant v = unserialize_from_string(value); if (same(v, false)) { throw Exception("bad apc archive, unserialize_from_string failed"); } const_load_set(key, v); p += other_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } }
void HttpRequestHandler::handleRequest(Transport *transport) { ExecutionProfiler ep(ThreadInfo::RuntimeFunctions); Logger::OnNewRequest(); GetAccessLog().onNewRequest(); transport->enableCompression(); ServerStatsHelper ssh("all", true); Logger::Verbose("receiving %s", transport->getCommand().c_str()); // will clear all extra logging when this function goes out of scope StackTraceNoHeap::ExtraLoggingClearer clearer; StackTraceNoHeap::AddExtraLogging("URL", transport->getUrl()); // resolve virtual host const VirtualHost *vhost = HttpProtocol::GetVirtualHost(transport); ASSERT(vhost); if (vhost->disabled() || vhost->isBlocking(transport->getCommand(), transport->getRemoteHost())) { transport->sendString("Not Found", 404); return; } ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); // resolve source root string host = transport->getHeader("Host"); SourceRootInfo sourceRootInfo(host.c_str()); if (sourceRootInfo.error()) { sourceRootInfo.handleError(transport); return; } // request URI string pathTranslation = m_pathTranslation ? vhost->getPathTranslation().c_str() : ""; RequestURI reqURI(vhost, transport, sourceRootInfo.path(), pathTranslation); if (reqURI.done()) { return; // already handled with redirection or 404 } string path = reqURI.path().data(); string absPath = reqURI.absolutePath().data(); // determine whether we should compress response bool compressed = transport->decideCompression(); const char *data; int len; size_t pos = path.rfind('.'); const char *ext = (pos != string::npos) && path.find('/', pos) == string::npos // no extention in ./foo or ../bar ? (path.c_str() + pos + 1) : NULL; bool cachableDynamicContent = (!RuntimeOption::StaticFileGenerators.empty() && RuntimeOption::StaticFileGenerators.find(path) != RuntimeOption::StaticFileGenerators.end()); // If this is not a php file, check the static and dynamic content caches if (ext && strcasecmp(ext, "php") != 0) { if (RuntimeOption::EnableStaticContentCache) { bool original = compressed; // check against static content cache if (StaticContentCache::TheCache.find(path, data, len, compressed)) { struct stat st; st.st_mtime = 0; String str; // (qigao) not calling stat at this point because the timestamp of // local cache file is not valuable, maybe misleading. This way // the Last-Modified header will not show in response. // stat(RuntimeOption::FileCache.c_str(), &st); if (!original && compressed) { data = gzdecode(data, len); if (data == NULL) { throw FatalErrorException("cannot unzip compressed data"); } compressed = false; str = NEW(StringData)(data, len, AttachString); } sendStaticContent(transport, data, len, st.st_mtime, compressed, path); StaticContentCache::TheFileCache->adviseOutMemory(); ServerStats::LogPage(path, 200); return; } } if (RuntimeOption::EnableStaticContentFromDisk) { String translated = File::TranslatePath(String(absPath)); if (!translated.empty()) { StringBuffer sb(translated.data()); if (sb.valid()) { struct stat st; st.st_mtime = 0; stat(translated.data(), &st); sendStaticContent(transport, sb.data(), sb.size(), st.st_mtime, false, path); ServerStats::LogPage(path, 200); return; } } } // check static contents that were generated by dynamic pages if (cachableDynamicContent) { // check against dynamic content cache ASSERT(transport->getUrl()); string key = path + transport->getUrl(); if (DynamicContentCache::TheCache.find(key, data, len, compressed)) { sendStaticContent(transport, data, len, 0, compressed, path); ServerStats::LogPage(path, 200); return; } } } // proxy any URLs that not specified in ServeURLs if (!RuntimeOption::ProxyOrigin.empty() && ((RuntimeOption::UseServeURLs && RuntimeOption::ServeURLs.find(path) == RuntimeOption::ServeURLs.end()) || (RuntimeOption::UseProxyURLs && (RuntimeOption::ProxyURLs.find(path) != RuntimeOption::ProxyURLs.end() || MatchAnyPattern(path, RuntimeOption::ProxyPatterns) || (abs(rand()) % 100) < RuntimeOption::ProxyPercentage)))) { for (int i = 0; i < RuntimeOption::ProxyRetry; i++) { bool force = (i == RuntimeOption::ProxyRetry - 1); // last one if (handleProxyRequest(transport, force)) break; } return; } // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); // main body hphp_session_init(); vhost->setRequestTimeoutSeconds(); bool ret = false; try { ret = executePHPRequest(transport, reqURI, sourceRootInfo, cachableDynamicContent); } catch (const Eval::DebuggerException &e) { transport->sendString(e.what(), 200); transport->onSendEnd(); hphp_context_exit(g_context.getNoCheck(), true, true, transport->getUrl()); } catch (...) { Logger::Error("Unhandled exception in HPHP server engine."); } GetAccessLog().log(transport, vhost); hphp_session_exit(); HttpProtocol::ClearRecord(ret, tmpfile); }
void FileCache::load(const char *filename, bool onDemandUncompress, short version) { assert(filename && *filename); FILE *f = fopen(filename, "r"); if (f == nullptr) { throw Exception("Unable to open %s: %s", filename, Util::safe_strerror(errno).c_str()); } if (version > 0) { // skip the leading -1 and the version id short tmp = -1; read_bytes(f, (char*)&tmp, sizeof(tmp)); read_bytes(f, (char*)&tmp, sizeof(tmp)); } while (true) { short name_len; if (!read_bytes(f, (char*)&name_len, sizeof(short)) || name_len <= 0) { if (feof(f)) break; throw Exception("Bad file name length in archive %s", filename); } char *name = (char *)malloc(name_len + 1); if (!read_bytes(f, name, name_len)) { free(name); throw Exception("Bad file name in archive %s", filename); } name[name_len] = '\0'; string file(name, name_len); free(name); if (exists(file.c_str())) { throw Exception("Same file %s appeared twice in %s", file.c_str(), filename); } char c; int len; if (!read_bytes(f, (char*)&c, 1) || !read_bytes(f, (char*)&len, sizeof(int))) { throw Exception("Bad data length in archive %s", filename); } Buffer &buffer = m_files[file]; buffer.len = len; buffer.data = nullptr; buffer.clen = -1; buffer.cdata = nullptr; if (len > 0) { buffer.data = (char *)malloc(len + 1); if (version > 0) { if (!read_bytes(f, buffer.data, len + 1)) { throw Exception("Bad data in archive %s", filename); } always_assert(buffer.data[len] == '\0'); } else { if (!read_bytes(f, buffer.data, len)) { throw Exception("Bad data in archive %s", filename); } buffer.data[len] = '\0'; } if (c) { if (onDemandUncompress) { buffer.clen = buffer.len; buffer.cdata = buffer.data; buffer.len = -1; buffer.data = nullptr; } else { int new_len = buffer.len; char *uncompressed = gzdecode(buffer.data, new_len); if (uncompressed == nullptr) { throw Exception("Bad compressed data in archive %s", filename); } buffer.clen = buffer.len; buffer.cdata = buffer.data; buffer.len = new_len; buffer.data = uncompressed; } } } } fclose(f); }
folly::Optional<std::string> hackcExtractPath() { if (!RuntimeOption::EvalHackCompilerUseEmbedded) return folly::none; auto check = [] (const std::string& s) { return !s.empty() && access(s.data(), X_OK) == 0; }; if (!tl_extractPath.isNull() && check(*tl_extractPath)) { return *tl_extractPath; } std::unique_lock<std::mutex> lock{s_extractLock}; if (check(s_extractPath)) { *tl_extractPath.getCheck() = s_extractPath; return *tl_extractPath; } auto set = [&] (const std::string& s) { s_extractPath = s; *tl_extractPath.getCheck() = s; return s; }; auto const trust = RuntimeOption::EvalHackCompilerTrustExtract; auto const location = RuntimeOption::EvalHackCompilerExtractPath; // As an optimization we can just choose to trust the extracted version // without reading it. if (trust && check(location)) return set(location); embedded_data desc; if (!get_embedded_data("hackc_binary", &desc)) { Logger::Error("Embedded hackc binary is missing"); return folly::none; } auto const gz_binary = read_embedded_data(desc); int len = safe_cast<int>(gz_binary.size()); auto const bin_str = gzdecode(gz_binary.data(), len); SCOPE_EXIT { free(bin_str); }; if (!bin_str || !len) { Logger::Error("Embedded hackc binary could not be decompressed"); return folly::none; } auto const binary = std::string(bin_str, len); if (createHackc(location, binary)) return set(location); int fd = -1; SCOPE_EXIT { if (fd != -1) close(fd); }; auto fallback = RuntimeOption::EvalHackCompilerFallbackPath; if ((fd = mkstemp(&fallback[0])) == -1) { Logger::FError( "Unable to create temp file for hackc binary: {}", folly::errnoStr(errno) ); return folly::none; } if (folly::writeFull(fd, binary.data(), binary.size()) == -1) { Logger::FError( "Failed to write extern hackc binary: {}", folly::errnoStr(errno) ); return folly::none; } if (chmod(fallback.data(), 0755) != 0) { Logger::Error("Unable to mark hackc binary as writable"); return folly::none; } return set(fallback); }