chromium/components/cronet/android/test/mock_url_request_job_factory.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "components/cronet/android/test/cronet_test_util.h"
#include "components/cronet/android/test/url_request_intercepting_job_factory.h"
#include "net/test/url_request/ssl_certificate_error_job.h"
#include "net/test/url_request/url_request_failed_job.h"
#include "net/test/url_request/url_request_hanging_read_job.h"
#include "net/test/url_request/url_request_mock_data_job.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_filter.h"
#include "url/gurl.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/cronet/android/cronet_test_apk_jni/MockUrlRequestJobFactory_jni.h"

using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;

namespace cronet {

// Intercept URLRequestJob creation using URLRequestFilter from
// libcronet_tests.so
class UrlInterceptorJobFactoryHandle {
 public:
  // |jcontext_adapter| points to a URLRequestContextAdapater.
  UrlInterceptorJobFactoryHandle(jlong jcontext_adapter)
      : jcontext_adapter_(jcontext_adapter) {
    TestUtil::RunAfterContextInit(
        jcontext_adapter,
        base::BindOnce(&UrlInterceptorJobFactoryHandle::InitOnNetworkThread,
                       base::Unretained(this)));
  }
  // Should only be called on network thread; other threads should use
  // ShutDown().
  ~UrlInterceptorJobFactoryHandle() {
    DCHECK(
        TestUtil::GetTaskRunner(jcontext_adapter_)->BelongsToCurrentThread());
    TestUtil::GetURLRequestContext(jcontext_adapter_)
        ->SetJobFactoryForTesting(old_job_factory_);  // IN-TEST
  }

  void ShutDown() {
    TestUtil::RunAfterContextInit(
        jcontext_adapter_,
        base::BindOnce(&UrlInterceptorJobFactoryHandle::ShutdownOnNetworkThread,
                       base::Unretained(this)));
  }

 private:
  void InitOnNetworkThread() {
    net::URLRequestContext* request_context =
        TestUtil::GetURLRequestContext(jcontext_adapter_);
    old_job_factory_ = request_context->job_factory();
    new_job_factory_.reset(new URLRequestInterceptingJobFactory(
        const_cast<net::URLRequestJobFactory*>(old_job_factory_.get()),
        net::URLRequestFilter::GetInstance()));
    request_context->SetJobFactoryForTesting(  // IN-TEST
        new_job_factory_.get());
  }

  void ShutdownOnNetworkThread() { delete this; }

  // The URLRequestContextAdapater this object intercepts from.
  const jlong jcontext_adapter_;
  // URLRequestJobFactory previously used in URLRequestContext.
  raw_ptr<const net::URLRequestJobFactory> old_job_factory_;
  // URLRequestJobFactory inserted during tests to intercept URLRequests with
  // libcronet's URLRequestFilter.
  std::unique_ptr<URLRequestInterceptingJobFactory> new_job_factory_;
};

// URL interceptors are registered with the URLRequestFilter in
// libcronet_tests.so.  However tests are run on libcronet.so.  Use the
// URLRequestFilter in libcronet_tests.so with the URLRequestContext in
// libcronet.so by installing a URLRequestInterceptingJobFactory
// that calls into libcronet_tests.so's URLRequestFilter.
jlong JNI_MockUrlRequestJobFactory_AddUrlInterceptors(
    JNIEnv* env,
    jlong jcontext_adapter) {
  net::URLRequestMockDataJob::AddUrlHandler();
  net::URLRequestFailedJob::AddUrlHandler();
  net::URLRequestHangingReadJob::AddUrlHandler();
  net::SSLCertificateErrorJob::AddUrlHandler();
  return reinterpret_cast<jlong>(
      new UrlInterceptorJobFactoryHandle(jcontext_adapter));
}

// Put back the old URLRequestJobFactory into the URLRequestContext.
void JNI_MockUrlRequestJobFactory_RemoveUrlInterceptorJobFactory(
    JNIEnv* env,
    jlong jinterceptor_handle) {
  reinterpret_cast<UrlInterceptorJobFactoryHandle*>(jinterceptor_handle)
      ->ShutDown();
}

ScopedJavaLocalRef<jstring> JNI_MockUrlRequestJobFactory_GetMockUrlWithFailure(
    JNIEnv* jenv,
    jint jphase,
    jint jnet_error) {
  GURL url(net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
      static_cast<net::URLRequestFailedJob::FailurePhase>(jphase),
      static_cast<int>(jnet_error)));
  return base::android::ConvertUTF8ToJavaString(jenv, url.spec());
}

ScopedJavaLocalRef<jstring> JNI_MockUrlRequestJobFactory_GetMockUrlForData(
    JNIEnv* jenv,
    const JavaParamRef<jstring>& jdata,
    jint jdata_repeat_count) {
  std::string data(base::android::ConvertJavaStringToUTF8(jenv, jdata));
  GURL url(net::URLRequestMockDataJob::GetMockHttpUrl(data,
                                                      jdata_repeat_count));
  return base::android::ConvertUTF8ToJavaString(jenv, url.spec());
}

ScopedJavaLocalRef<jstring>
JNI_MockUrlRequestJobFactory_GetMockUrlForSSLCertificateError(JNIEnv* jenv) {
  GURL url(net::SSLCertificateErrorJob::GetMockUrl());
  return base::android::ConvertUTF8ToJavaString(jenv, url.spec());
}

ScopedJavaLocalRef<jstring>
JNI_MockUrlRequestJobFactory_GetMockUrlForClientCertificateRequest(
    JNIEnv* jenv) {
  GURL url(net::URLRequestMockDataJob::GetMockUrlForClientCertificateRequest());
  return base::android::ConvertUTF8ToJavaString(jenv, url.spec());
}

ScopedJavaLocalRef<jstring>
JNI_MockUrlRequestJobFactory_GetMockUrlForHangingRead(JNIEnv* jenv) {
  GURL url(net::URLRequestHangingReadJob::GetMockHttpUrl());
  return base::android::ConvertUTF8ToJavaString(jenv, url.spec());
}

}  // namespace cronet