/*** * ==++== * * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ==--== * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * http_asserts.cpp - Utility class to help verify assertions about http requests and responses. * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" #include "cpprest/details/http_helpers.h" using namespace web; using namespace utility; using namespace utility::conversions; namespace tests { namespace functional { namespace http { namespace utilities { utility::string_t percent_encode_pound(utility::string_t str) { size_t index; while((index = str.find_first_of(U("#"))) != str.npos) { str.insert(index, U("%23")); str.erase(index + 3, 1); } return str; } // Helper function to verify all given headers are present. template static void verify_headers(const T1 &expected, const T2 &actual) { for(auto iter = expected.begin(); iter != expected.end(); ++iter) { VERIFY_ARE_EQUAL(iter->second, actual.find(iter->first)->second); } } void http_asserts::assert_request_equals( ::http::http_request request, const ::http::method &mtd, const utility::string_t & relative_path) { VERIFY_ARE_EQUAL(mtd, request.method()); if(relative_path == U("")) { VERIFY_ARE_EQUAL(U("/"), request.relative_uri().to_string()); } else { VERIFY_ARE_EQUAL(relative_path, request.relative_uri().to_string()); } } void http_asserts::assert_request_equals( ::http::http_request request, const ::http::method &mtd, const utility::string_t & relative_uri, const std::map &headers) { assert_request_equals(request, mtd, relative_uri); verify_headers(headers, request.headers()); } void http_asserts::assert_request_equals( ::http::http_request request, const ::http::method &mtd, const utility::string_t & relative_path, const utility::string_t & body) { assert_request_equals(request, mtd, relative_path); auto request_data = request.extract_string().get(); VERIFY_ARE_EQUAL(body, request_data); } void http_asserts::assert_response_equals( ::http::http_response response, const ::http::status_code &code) { VERIFY_ARE_EQUAL(response.status_code(), code); } void http_asserts::assert_response_equals( ::http::http_response response, const ::http::status_code &code, const utility::string_t &reason) { VERIFY_ARE_EQUAL(code, response.status_code()); VERIFY_ARE_EQUAL(reason, response.reason_phrase()); } void http_asserts::assert_response_equals( ::http::http_response response, const ::http::status_code &code, const std::map &headers) { VERIFY_ARE_EQUAL(code, response.status_code()); verify_headers(headers, response.headers()); } void http_asserts::assert_http_headers_equals( const ::http::http_headers &actual, const ::http::http_headers &expected) { verify_headers(actual, expected); } void http_asserts::assert_test_request_equals( const test_request *const p_request, const ::http::method &mtd, const utility::string_t &path) { VERIFY_ARE_EQUAL(mtd, p_request->m_method); VERIFY_ARE_EQUAL(path, p_request->m_path); } void http_asserts::assert_test_request_equals( const test_request *const p_request, const ::http::method &mtd, const utility::string_t &path, const utility::string_t &content_type) { VERIFY_ARE_EQUAL(mtd, p_request->m_method); VERIFY_ARE_EQUAL(path, p_request->m_path); // verify that content-type key exists in the header and the value matches the one provided auto iter = p_request->m_headers.find(U("Content-Type")); if(content_type.empty()) { VERIFY_ARE_EQUAL(iter, p_request->m_headers.end()); } else { VERIFY_IS_TRUE(iter != p_request->m_headers.end()); VERIFY_ARE_EQUAL(iter->second.find(content_type), 0); } } void http_asserts::assert_test_request_contains_headers( const test_request *const p_request, const ::http::http_headers &headers) { verify_headers(headers, p_request->m_headers); } void http_asserts::assert_test_request_contains_headers( const test_request *const p_request, const std::map &headers) { verify_headers(headers, p_request->m_headers); } // Helper function to parse HTTP headers from a stringstream. static std::map parse_headers(utility::istringstream_t &ss) { // Keep parsing until CRLF is encountered. std::map headers; utility::string_t header_line; while(getline(ss, header_line).good()) { const size_t colon_index = header_line.find(U(":")); const utility::string_t header_name = header_line.substr(0, colon_index); utility::string_t header_value = header_line.substr(colon_index + 1); web::http::details::trim_whitespace(header_value); headers[header_name] = header_value; char c1 = (char)ss.get(), c2 = (char)ss.get(); if(c1 == '\r' && c2 == '\n') { break; } ss.unget(); ss.unget(); } return headers; } void http_asserts::assert_request_string_equals( const utility::string_t &request, const ::http::method &mtd, const utility::string_t &path, const utility::string_t &version, const std::map &headers, const utility::string_t &body) { utility::istringstream_t ss(request); // Parse request line. utility::string_t actual_method, actual_path, actual_version; ss >> actual_method >> actual_path >> actual_version; // Parse headers. utility::string_t temp; getline(ss, temp); std::map actual_headers = parse_headers(ss); // Parse in any message body utility::string_t actual_body = ss.str().substr((size_t)ss.tellg()); VERIFY_ARE_EQUAL(mtd, actual_method); VERIFY_ARE_EQUAL(path, actual_path); VERIFY_ARE_EQUAL(version, actual_version); verify_headers(headers, actual_headers); VERIFY_ARE_EQUAL(body, actual_body); } void http_asserts::assert_response_string_equals( const utility::string_t &response, const utility::string_t &version, const ::http::status_code &code, const utility::string_t &phrase, const std::map &headers, const utility::string_t &body) { utility::istringstream_t ss(response); // Parse response line. utility::string_t actual_version, actual_phrase; ::http::status_code actual_code; ss >> actual_version >> actual_code >> actual_phrase; // Parse headers. utility::string_t temp; getline(ss, temp); std::map actual_headers = parse_headers(ss); // Prase in any message body. utility::string_t actual_body = ss.str().substr((size_t)ss.tellg()); VERIFY_ARE_EQUAL(version, actual_version); VERIFY_ARE_EQUAL(code, actual_code); VERIFY_ARE_EQUAL(phrase, actual_phrase); verify_headers(headers, actual_headers); VERIFY_ARE_EQUAL(body, actual_body); } void http_asserts::assert_test_request_equals( const test_request *const p_request, const ::http::method &mtd, const utility::string_t &path, const utility::string_t &content_type, const utility::string_t &body) { assert_test_request_equals(p_request, mtd, path, content_type); // Textual response is always sent as UTF-8, hence the converison to string_t std::string s((char*)&p_request->m_body[0], p_request->m_body.size()); utility::string_t extracted_body = to_string_t(s); VERIFY_ARE_EQUAL(body, extracted_body); } void http_asserts::assert_test_response_equals( const test_response * const p_response, const ::http::status_code &code) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); } void http_asserts::assert_test_response_equals( const test_response * const p_response, const ::http::status_code &code, const std::map &headers) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); verify_headers(headers, p_response->m_headers); } void http_asserts::assert_test_response_equals( const test_response * const p_response, const ::http::status_code &code, const ::http::http_headers &headers) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); verify_headers(headers, p_response->m_headers); } void http_asserts::assert_test_response_equals( test_response * p_response, const ::http::status_code &code, const utility::string_t &content_type) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); utility::string_t found_content; p_response->match_header(U("Content-Type"), found_content); VERIFY_ARE_EQUAL(content_type, found_content); } void http_asserts::assert_test_response_equals( test_response * p_response, const ::http::status_code &code, const utility::string_t &content_type, const utility::string_t data) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); utility::string_t found_content; p_response->match_header(U("Content-Type"), found_content); VERIFY_ARE_EQUAL(found_content.find(content_type), 0); // Beware: what kind of string this is? <-- stringhack until we tighten up wide/narrow string business utility::string_t extracted_body; if(p_response->m_data.size() == 0) { extracted_body = U(""); } else { auto actualRawData = (char*)&p_response->m_data[0]; if(p_response->m_data.size() > 1 && *(actualRawData+1) == '\0' ) { // We have more than one byte of data, but it's null-terminated at byte 1. // Therefore, this is a wide string extracted_body.assign((utility::char_t*)actualRawData, p_response->m_data.size()/sizeof(utility::char_t)); } else{ std::string s(actualRawData, p_response->m_data.size()); extracted_body = to_string_t(s); } } VERIFY_ARE_EQUAL(data, extracted_body); } }}}}