⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpclient.cc

📁 本人收集整理的一份c/c++跨平台网络库
💻 CC
📖 第 1 页 / 共 2 页
字号:
    return HE_CACHE;  }  // Write all unknown and end-to-end headers to a cache file  for (HttpData::const_iterator it = response_.begin();       it != response_.end(); ++it) {    HttpHeader header;    if (FromString(header, it->first) && !HttpHeaderIsEndToEnd(header))      continue;    std::string formatted_header(it->first);    formatted_header.append(": ");    formatted_header.append(it->second);    formatted_header.append("\r\n");    StreamResult result = stream->WriteAll(formatted_header.data(),                                           formatted_header.length(),                                           NULL, NULL);    if (SR_SUCCESS != result) {      LOG_F(LS_ERROR) << "Couldn't write header cache";      return HE_CACHE;    }  }  return HE_NONE;}void HttpClient::CompleteCacheFile() {  // Restore previous response document  StreamTap* tap = static_cast<StreamTap*>(response_.document.release());  response_.document.reset(tap->Detach());  int error;  StreamResult result = tap->GetTapResult(&error);  // Delete the tap and cache stream (which completes cache unlock)  delete tap;  if (SR_SUCCESS != result) {    LOG(LS_ERROR) << "Cache file error: " << error;    cache_->DeleteResource(GetCacheID(server_, request_));  }}bool HttpClient::CheckCache() {  ASSERT(NULL != cache_);  ASSERT(CS_READY == cache_state_);  std::string id = GetCacheID(server_, request_);  if (!cache_->HasResource(id)) {    // No cache file available    return false;  }  HttpError error = ReadCacheHeaders(id, true);  if (HE_NONE == error) {    switch (HttpGetCacheState(request_, response_)) {    case HCS_FRESH:      // Cache content is good, read from cache      break;    case HCS_STALE:      // Cache content may be acceptable.  Issue a validation request.      if (PrepareValidate()) {        return false;      }      // Couldn't validate, fall through.    case HCS_NONE:      // Cache content is not useable.  Issue a regular request.      response_.clear(false);      return false;    }  }  if (HE_NONE == error) {    error = ReadCacheBody(id);    cache_state_ = CS_READY;  }  if (HE_CACHE == error) {    LOG_F(LS_WARNING) << "Cache failure, continuing with normal request";    response_.clear(false);    return false;  }  SignalHttpClientComplete(this, error);  return true;}HttpError HttpClient::ReadCacheHeaders(const std::string& id, bool override) {  scoped_ptr<StreamInterface> stream(cache_->ReadResource(id, kCacheHeader));  if (!stream.get()) {    return HE_CACHE;  }  HttpData::HeaderCombine combine =    override ? HttpData::HC_REPLACE : HttpData::HC_AUTO;  while (true) {    std::string formatted_header;    StreamResult result = stream->ReadLine(&formatted_header);    if (SR_EOS == result)      break;    if (SR_SUCCESS != result) {      LOG_F(LS_ERROR) << "ReadLine error in cache headers";      return HE_CACHE;    }    size_t end_of_name = formatted_header.find(':');    if (std::string::npos == end_of_name) {      LOG_F(LS_WARNING) << "Malformed cache header";      continue;    }    size_t start_of_value = end_of_name + 1;    size_t end_of_value = formatted_header.length();    while ((start_of_value < end_of_value)           && isspace(formatted_header[start_of_value]))      ++start_of_value;    while ((start_of_value < end_of_value)           && isspace(formatted_header[end_of_value-1]))     --end_of_value;    size_t value_length = end_of_value - start_of_value;    std::string name(formatted_header.substr(0, end_of_name));    std::string value(formatted_header.substr(start_of_value, value_length));    response_.changeHeader(name, value, combine);  }  response_.scode = HC_OK;  return HE_NONE;}HttpError HttpClient::ReadCacheBody(const std::string& id) {  cache_state_ = CS_READING;  HttpError error = HE_NONE;  size_t data_size;  scoped_ptr<StreamInterface> stream(cache_->ReadResource(id, kCacheBody));  if (!stream.get() || !stream->GetSize(&data_size)) {    LOG_F(LS_ERROR) << "Unavailable cache body";    error = HE_CACHE;  } else {    error = OnHeaderAvailable(false, false, data_size);  }  if ((HE_NONE == error)      && (HV_HEAD != request_.verb)      && (NULL != response_.document.get())) {    char buffer[1024 * 64];    StreamResult result = Flow(stream.get(), buffer, ARRAY_SIZE(buffer),                               response_.document.get());    if (SR_SUCCESS != result) {      error = HE_STREAM;    }  }  return error;}bool HttpClient::PrepareValidate() {  ASSERT(CS_READY == cache_state_);  // At this point, request_ contains the pending request, and response_  // contains the cached response headers.  Reformat the request to validate  // the cached content.  HttpValidatorStrength vs_required = HttpRequestValidatorLevel(request_);  HttpValidatorStrength vs_available = HttpResponseValidatorLevel(response_);  if (vs_available < vs_required) {    return false;  }  std::string value;  if (response_.hasHeader(HH_ETAG, &value)) {    request_.addHeader(HH_IF_NONE_MATCH, value);  }  if (response_.hasHeader(HH_LAST_MODIFIED, &value)) {    request_.addHeader(HH_IF_MODIFIED_SINCE, value);  }  response_.clear(false);  cache_state_ = CS_VALIDATING;  return true;}HttpError HttpClient::CompleteValidate() {  ASSERT(CS_VALIDATING == cache_state_);  std::string id = GetCacheID(server_, request_);  // Merge cached headers with new headers  HttpError error = ReadCacheHeaders(id, false);  if (HE_NONE != error) {    // Rewrite merged headers to cache    CacheLock lock(cache_, id);    error = WriteCacheHeaders(id);  }  if (HE_NONE != error) {    error = ReadCacheBody(id);  }  return error;}HttpError HttpClient::OnHeaderAvailable(bool ignore_data, bool chunked,                                        size_t data_size) {  if (!ignore_data && !chunked && response_.document.get()) {    // Attempt to pre-allocate space for the downloaded data.    if (!response_.document->ReserveSize(data_size)) {      return HE_OVERFLOW;    }  }  SignalHeaderAvailable(this, chunked, data_size);  return HE_NONE;}//// HttpBase Implementation//HttpError HttpClient::onHttpHeaderComplete(bool chunked, size_t& data_size) {  if (CS_VALIDATING == cache_state_) {    if (HC_NOT_MODIFIED == response_.scode) {      return CompleteValidate();    }    // Should we remove conditional headers from request?    cache_state_ = CS_READY;    cache_->DeleteResource(GetCacheID(server_, request_));    // Continue processing response as normal  }  ASSERT(!IsCacheActive());  if ((request_.verb == HV_HEAD) || !HttpCodeHasBody(response_.scode)) {    // HEAD requests and certain response codes contain no body    data_size = 0;  }  if ((HttpCodeIsRedirection(response_.scode) && !fail_redirect_)      || ((HC_PROXY_AUTHENTICATION_REQUIRED == response_.scode)          && (PROXY_HTTPS == proxy_.type))) {    // We're going to issue another request, so ignore the incoming data.    base_.set_ignore_data(true);  }  HttpError error = OnHeaderAvailable(base_.ignore_data(), chunked, data_size);  if (HE_NONE != error) {    return error;  }  if ((NULL != cache_)      && !base_.ignore_data()      && HttpShouldCache(request_, response_)) {    if (BeginCacheFile()) {      cache_state_ = CS_WRITING;    }  }  return HE_NONE;}void HttpClient::onHttpComplete(HttpMode mode, HttpError err) {  if (err != HE_NONE) {    // fall through  } else if (mode == HM_CONNECT) {    base_.send(&request_);    return;  } else if ((mode == HM_SEND) || HttpCodeIsInformational(response_.scode)) {    // If you're interested in informational headers, catch    // SignalHeaderAvailable.    base_.recv(&response_);    return;  } else {    if (!HttpShouldKeepAlive(response_)) {      LOG(INFO) << "HttpClient: closing socket";      base_.stream()->Close();    }    if (HttpCodeIsRedirection(response_.scode) && !fail_redirect_) {      std::string value;      if (!response_.hasHeader(HH_LOCATION, &value)) {        err = HE_PROTOCOL;      } else {        Url<char> purl(value);        set_server(SocketAddress(purl.server(), purl.port(), false));        request_.path = purl.full_path();        if (response_.scode == HC_SEE_OTHER) {          request_.verb = HV_GET;          request_.clearHeader(HH_CONTENT_TYPE);          request_.clearHeader(HH_CONTENT_LENGTH);          request_.document.reset();        } else if (request_.document.get() && !request_.document->Rewind()) {          // Unable to replay the request document.          err = HE_STREAM;        }      }      if (err == HE_NONE) {        context_.reset();        response_.clear(false);        release();        start();        return;      }    } else if ((HC_PROXY_AUTHENTICATION_REQUIRED == response_.scode)               && (PROXY_HTTPS == proxy_.type)) {      std::string response, auth_method;      HttpData::const_iterator begin = response_.begin(HH_PROXY_AUTHENTICATE);      HttpData::const_iterator end = response_.end(HH_PROXY_AUTHENTICATE);      for (HttpData::const_iterator it = begin; it != end; ++it) {        HttpAuthResult res = HttpAuthenticate(          it->second.data(), it->second.size(),          proxy_.address,          ToString(request_.verb), request_.path,          proxy_.username, proxy_.password,          *context_.use(), response, auth_method);        if (res == HAR_RESPONSE) {          request_.setHeader(HH_PROXY_AUTHORIZATION, response);          if (request_.document.get() && !request_.document->Rewind()) {            err = HE_STREAM;          } else {            // Explicitly do not reset the HttpAuthContext            response_.clear(false);            // TODO: Reuse socket when authenticating?            release();            start();            return;          }        } else if (res == HAR_IGNORE) {          LOG(INFO) << "Ignoring Proxy-Authenticate: " << auth_method;          continue;        } else {          break;        }      }    }  }  if (CS_WRITING == cache_state_) {    CompleteCacheFile();    cache_state_ = CS_READY;  } else if (CS_READING == cache_state_) {    cache_state_ = CS_READY;  }  release();  SignalHttpClientComplete(this, err);}void HttpClient::onHttpClosed(HttpError err) {  SignalHttpClientClosed(this, err);}//////////////////////////////////////////////////////////////////////} // namespace talk_base

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -