Exemple #1
0
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;
}
Exemple #2
0
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);
}
Exemple #3
0
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);
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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();
  }
}
Exemple #7
0
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);
}
Exemple #11
0
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);
}
Exemple #13
0
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);
    }
  }
}
Exemple #14
0
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);
}
Exemple #17
0
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);
}