text: /***
  * ==++==
  *
  * Copyright (c) Microsoft Corporation.  All rights reserved.
  *
  * ==--==
  * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  *
  * requests_tests.cpp
  *
  * Tests cases for covering sending various requests to http_listener.
  *
  * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  ****/
  
  #include "stdafx.h"
  #include <cpprest/http_client.h>
  
  using namespace web::http;
  using namespace web::http::experimental::listener;
  
  using namespace tests::functional::http::utilities;
  
  namespace tests { namespace functional { namespace http { namespace listener {
  
  SUITE(requests_tests)
  {
  
  TEST_FIXTURE(uri_address, http_methods)
  {
      http_listener listener(m_uri);
  
      listener.open().wait();
      test_http_client::scoped_client client(m_uri);
      test_http_client * p_client = client.client();
  
      // Don't include 'CONNECT' it has a special meaning.
      utility::string_t send_methods[] = 
      {
          methods::GET,
          U("GET"),
          methods::DEL,
          methods::HEAD,
          U("HeAd"),
          methods::POST,
          methods::PUT,
          U("CUstomMETHOD")
      };
      utility::string_t recv_methods[] = 
      {
          U("GET"),
          U("GET"),
          U("DELETE"),
          U("HEAD"),
          U("HEAD"),
          U("POST"),
          U("PUT"),
          U("CUstomMETHOD")
      };
      const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]);
  
      utility::string_t actual_method;
      listener.support([&](http_request request)
      {
          actual_method = request.method();
          request.reply(status_codes::OK).wait();
      });
  
      for(int i = 0; i < num_methods; ++i)
      {
          pplx::extensibility::event_t ev;
          VERIFY_ARE_EQUAL(0, p_client->request(send_methods[i], U("")));
          p_client->next_response().then([&ev](test_response *p_response)
          {
              http_asserts::assert_test_response_equals(p_response, status_codes::OK);
              ev.set();
          }).wait();
          VERIFY_ARE_EQUAL(recv_methods[i], actual_method);
          ev.wait();
      }
  
      listener.close().wait();
  }
  
  TEST_FIXTURE(uri_address, http_body_and_body_size)
  {
      http_listener listener(m_uri);
      listener.open().wait();
      test_http_client::scoped_client client(m_uri);
      test_http_client * p_client = client.client();
  
      // request with no body
      listener.support([](http_request request)
      {
          http_asserts::assert_request_equals(request, U("GET"), U("/"));
          VERIFY_ARE_EQUAL(0, request.body().streambuf().in_avail());
          request.reply(status_codes::OK);
      });
      VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("")));
      p_client->next_response().then([](test_response *p_response)
      {
          http_asserts::assert_test_response_equals(p_response, status_codes::OK);
      }).wait();
  
      // request with body size explicitly 0
      listener.support([](http_request request)
      {
          http_asserts::assert_request_equals(request, U("GET"), U("/"));
          VERIFY_ARE_EQUAL(0, request.body().streambuf().in_avail());
          request.reply(status_codes::OK);
      });
      VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), ""));
      p_client->next_response().then([](test_response *p_response)
      {
          http_asserts::assert_test_response_equals(p_response, status_codes::OK);
      }).wait();
  
      // request with body data
      std::string data("HEHE");
      listener.support([&](http_request request)
      {
          http_asserts::assert_request_equals(request, U("GET"), U("/"));
  
          auto stream = request.body();
          VERIFY_IS_TRUE(stream.is_valid());
          auto buf = stream.streambuf();
          VERIFY_IS_TRUE(buf);
  
          request.content_ready().wait();
          
          VERIFY_ARE_EQUAL(data.size(), buf.in_avail());
          VERIFY_ARE_EQUAL('H', (char)buf.sbumpc());
          VERIFY_ARE_EQUAL('E', (char)buf.sbumpc());
          VERIFY_ARE_EQUAL('H', (char)buf.sbumpc());
          VERIFY_ARE_EQUAL('E', (char)buf.sbumpc());
          request.reply(status_codes::OK);
  
      });
      VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), data));
      p_client->next_response().then([](test_response *p_response)
      {
          http_asserts::assert_test_response_equals(p_response, status_codes::OK);
      }).wait();
  
      listener.close().wait();
  }
  
  TEST_FIXTURE(uri_address, large_body)
  {
      http_listener listener(m_uri);
      listener.open().wait();
      test_http_client::scoped_client client(m_uri);
      test_http_client * p_client = client.client();
  
      std::string data_piece("abcdefghijklmnopqrstuvwxyz");
      std::string send_data;
      // 26 * 160 is greater than 4k which is the chunk size.
      for(int i = 0; i < 160; ++i)
      {
          send_data.append(data_piece);
      }
      listener.support([&](http_request request)
      {
          std::string recv_data = utility::conversions::to_utf8string(request.extract_string().get());
          VERIFY_ARE_EQUAL(send_data, recv_data);
          request.reply(status_codes::OK);
      });
      VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), U("text/plain"), send_data));
      p_client->next_response().then([](test_response *p_response)
      {
          http_asserts::assert_test_response_equals(p_response, status_codes::OK);
      }).wait();
  
      listener.close().wait();
  }
  
  TEST_FIXTURE(uri_address, response_order)
  {
      http_listener listener(m_uri);
      listener.open().wait();
  
      client::http_client_config config;
      // our product client would be able to pipe multiple requests on one connection
      client::http_client client(m_uri, config);
  
      const int num_requests = 50;
  
      listener.support([](http_request request)
      {
          auto str = request.extract_string().get();
          // intentionally break order
          if (str == U("0"))
              tests::common::utilities::os_utilities::sleep(500);
          request.reply(status_codes::OK, str);
      });
  
      std::vector<pplx::task<web::http::http_response>> responses;
  
      for (int i = 0; i < num_requests; ++i)
      {
          utility::ostringstream_t ss;
          ss << i;
          responses.push_back(client.request(web::http::methods::PUT, U(""), ss.str()));
      }
  
      // wait for requests.
      for(size_t i = 0; i < num_requests; ++i)
      {
          utility::ostringstream_t ss;
          ss << i;
          auto response = responses[i].get();
  
          // verify the requests and responses are still match
          VERIFY_ARE_EQUAL(response.status_code(), status_codes::OK);
          VERIFY_ARE_EQUAL(response.extract_string().get(), ss.str());
      }
  
      listener.close().wait();
  }
  
  TEST_FIXTURE(uri_address, uri_encoding, "Ignore", "Codeplex 201")
  {
      http_listener listener(m_uri);
      listener.open().wait();
      client::http_client client(m_uri);
      utility::string_t encoded_uri;
  
      listener.support([&](http_request request)
      {
          VERIFY_ARE_EQUAL(encoded_uri, request.relative_uri().to_string());
          request.reply(status_codes::OK);
      });
  
      // Wrap in try catch to print out more information to help with a sporadic failure.
      try
      {
          encoded_uri = uri::encode_uri(U("/path 1/path 2")); // Path component contains encoded characters
          client.request(methods::GET, encoded_uri).wait();
          encoded_uri = uri::encode_uri(U("/test?Text=J'ai besoin de trouver un personnage")); // Query string contains encoded characters
          client.request(methods::GET, encoded_uri).wait();
          encoded_uri = uri::encode_uri(U("/path 1/path 2#fragment1")); // URI has path and fragment components
          client.request(methods::GET, encoded_uri).wait();
          encoded_uri = uri::encode_uri(U("/path 1/path 2?key1=val1 val2#fragment1")); // URI has path, query and fragment components
          client.request(methods::GET, encoded_uri).wait();
      }
      catch (const http_exception &e)
      {
          std::cout << "http_exception caught" << std::endl <<
              "what():" << e.what() << std::endl <<
              "error_code msg:" << e.error_code().message() << std::endl <<
              "error_code value:" << e.error_code().value() << std::endl;
          VERIFY_IS_TRUE(false);
      }
  
      listener.close().wait();
  }
  
  TEST_FIXTURE(uri_address, https_listener, "Ignore", "Manual")
  {
      // Requires a certificate for execution. 
      // Here are instructions for creating a self signed cert. Full instructions can be located here:
      // http://blogs.msdn.com/b/haoxu/archive/2009/04/30/one-time-set-up-for-wwsapi-security-examples.aspx
      // From an elevated admin prompt:
      // 1. MakeCert.exe -ss Root -sr LocalMachine -n "CN=Fake-Test-CA" -cy authority -r -sk "CAKeyContainer"
      // 2. MakeCert.exe -ss My -sr LocalMachine -n "CN=localhost" -sky exchange -is Root -ir LocalMachine -in Fake-Test-CA -sk "ServerKeyContainer"
      // 3. Find corresponding SHA-1 hash with CertUtil.exe -store My localhost
      // 4. Netsh.exe http add sslcert ipport=0.0.0.0:8443 appid={00112233-4455-6677-8899-AABBCCDDEEFF} certhash=<40CharacterThumbprintWithNoSpaces>
  
      http_listener listener(m_secure_uri);
      listener.open().wait();
      client::http_client client(m_secure_uri);
  
      listener.support([&](http_request request)
      {
          request.reply(status_codes::OK);
      });
  
      http_asserts::assert_response_equals(client.request(methods::GET, U("")).get(), status_codes::OK);
  
      listener.close().wait();
  }
  }
  
  }}}}
  