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

#import "ios/chrome/browser/https_upgrades/model/https_upgrade_test_helper.h"

#import <map>
#import <string>

#import "base/functional/bind.h"
#import "base/strings/escape.h"
#import "base/strings/string_util.h"
#import "base/strings/stringprintf.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "base/test/metrics/histogram_tester.h"
#import "ios/chrome/browser/https_upgrades/model/https_upgrade_app_interface.h"
#import "ios/chrome/browser/metrics/model/metrics_app_interface.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "ios/testing/embedded_test_server_handlers.h"
#import "ios/web/common/features.h"
#import "net/test/embedded_test_server/default_handlers.h"
#import "net/test/embedded_test_server/http_request.h"
#import "net/test/embedded_test_server/http_response.h"
#import "net/test/embedded_test_server/request_handler_util.h"
#import "ui/base/l10n/l10n_util.h"

namespace {

const long kVeryLongTimeout = 100 * 3600 * 1000;

// net::EmbeddedTestServer handler that responds with simple text.
std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
    int* counter,
    const net::test_server::HttpRequest& request) {
  // Ignore favicon requests.
  if (request.relative_url == "/favicon.ico") {
    return nullptr;
  }
  std::unique_ptr<net::test_server::BasicHttpResponse> response(
      new net::test_server::BasicHttpResponse);
  response->set_content_type("text/html");
  response->set_content("HTTP_RESPONSE");
  if (counter) {
    (*counter)++;
  }
  return std::move(response);
}

std::unique_ptr<net::test_server::HttpResponse> FakeHTTPSResponse(
    const net::test_server::HttpRequest& request) {
  std::unique_ptr<net::test_server::BasicHttpResponse> response(
      new net::test_server::BasicHttpResponse);

  const GURL request_url = request.GetURL();
  const std::string destValue =
      base::UnescapeBinaryURLComponent(request_url.query());
  // If the URL is in the form http://example.com/?redirect=url,
  // redirect the response to `url`.
  if (base::StartsWith(destValue, "redirect=")) {
    const std::string dest = destValue.substr(strlen("redirect="));
    response->set_code(net::HttpStatusCode::HTTP_MOVED_PERMANENTLY);
    response->AddCustomHeader("Location", dest);
    response->AddCustomHeader("Access-Control-Allow-Origin", "*");
    response->set_content_type("text/html");
    response->set_content(base::StringPrintf(
        "<html><head></head><body>Redirecting to %s</body></html>",
        dest.c_str()));
    return response;
  }

  response->set_content_type("text/html");
  response->set_content("HTTPS_RESPONSE");
  return std::move(response);
}

std::unique_ptr<net::test_server::HttpResponse> FakeHungResponse(
    const net::test_server::HttpRequest& request) {
  return std::make_unique<net::test_server::HungResponse>();
}

}  // namespace

@implementation HttpsUpgradeTestCaseBase

- (net::EmbeddedTestServer*)goodHTTPSServer {
  if (!_goodHTTPSServer) {
    _goodHTTPSServer = std::make_unique<net::EmbeddedTestServer>(
        net::test_server::EmbeddedTestServer::TYPE_HTTP);
    _goodHTTPSServer->RegisterRequestHandler(
        base::BindRepeating(&FakeHTTPSResponse));
  }
  return _goodHTTPSServer.get();
}

- (net::EmbeddedTestServer*)badHTTPSServer {
  if (!_badHTTPSServer) {
    _badHTTPSServer = std::make_unique<net::EmbeddedTestServer>(
        net::test_server::EmbeddedTestServer::TYPE_HTTPS);
    _badHTTPSServer->RegisterRequestHandler(
        base::BindRepeating(&StandardResponse, nullptr));
  }
  return _badHTTPSServer.get();
}

- (net::EmbeddedTestServer*)slowServer {
  if (!_slowServer) {
    _slowServer = std::make_unique<net::EmbeddedTestServer>(
        net::test_server::EmbeddedTestServer::TYPE_HTTP);
    _slowServer->RegisterRequestHandler(base::BindRepeating(&FakeHungResponse));
  }
  return _slowServer.get();
}

- (void)setUp {
  [super setUp];
  // Start test servers.
  _HTTPResponseCounter = 0;
  self.testServer->RegisterRequestHandler(base::BindRepeating(
      base::BindRepeating(&StandardResponse, &_HTTPResponseCounter)));

  GREYAssertTrue(self.testServer->Start(), @"Test HTTP server failed to start");
  GREYAssertTrue(self.goodHTTPSServer->Start(),
                 @"Test good faux-HTTPS server failed to start.");
  GREYAssertTrue(self.badHTTPSServer->Start(),
                 @"Test bad HTTPS server failed to start.");
  GREYAssertTrue(self.slowServer->Start(),
                 @"Test slow server failed to start.");

  chrome_test_util::GREYAssertErrorNil(
      [MetricsAppInterface setupHistogramTester]);

  [HttpsUpgradeAppInterface setHTTPSPortForTesting:self.goodHTTPSServer->port()
                                      useFakeHTTPS:false];
  [HttpsUpgradeAppInterface setFallbackDelayForTesting:kVeryLongTimeout];
}

- (void)tearDown {
  // Release the histogram tester.
  chrome_test_util::GREYAssertErrorNil(
      [MetricsAppInterface releaseHistogramTester]);

  [super tearDown];
}

@end
