basic_response<Tag> send_request(string_type const & method, basic_request<Tag> request_, bool get_body) { basic_response<Tag> response_; do { pimpl->init_socket(request_.host(), lexical_cast<string_type>(request_.port())); pimpl->send_request_impl(method, request_); response_ = basic_response<Tag>(); response_ << network::source(request_.host()); boost::asio::streambuf response_buffer; pimpl->read_status(response_, response_buffer); pimpl->read_headers(response_, response_buffer); if (get_body) pimpl->read_body(response_, response_buffer); if (follow_redirect_) { boost::uint16_t status = response_.status(); if (status >= 300 && status <= 307) { typename headers_range<http::basic_response<Tag> >::type location_range = headers(response_)["Location"]; typename range_iterator<typename headers_range<http::basic_request<Tag> >::type>::type location_header = boost::begin(location_range); if (location_header != boost::end(location_range)) { request_.uri(location_header->second); } else throw std::runtime_error("Location header not defined in redirect response."); } else break; } else break; } while(true); return response_; }
response_type const request_skeleton( basic_request<Tag> const & request, string_type const & method, bool get_body, body_callback_function_type callback, body_generator_function_type generator ) { auto && app = webmock::api::app(); webmock::core::request webmock_request; webmock_request.method = method; webmock_request.url.set_encoded(request.uri().string()); for (auto && header: http::headers(request)) { webmock_request.headers.insert(header); } webmock_request.body = http::body(request); if (auto && webmock_response = app.registry.access(webmock_request)) { basic_response<Tag> response; response << http::status(webmock_response->status) << network::body(webmock_response->body); for (auto && header: webmock_response->headers) { response << network::header(header.first, header.second); } return response; } if (app.config.stub_not_found.is_connecting_to_net) { return this->connect_net( request, method, get_body, callback, generator ); } if (app.config.stub_not_found.callback) { app.config.stub_not_found.callback(webmock_request); } throw (std::ostringstream() << "A stub satisfying the request not found!\n" << webmock_request ).str(); }
basic_response<Tag> send_request(string_type /*unused*/ const& method, basic_request<Tag> request_, bool get_body, body_callback_function_type callback, body_generator_function_type generator) { // TODO(dberris): review parameter necessity. (void)callback; basic_response<Tag> response_; do { pimpl->init_socket(request_.host(), std::to_string(request_.port())); pimpl->send_request_impl(method, request_, generator); response_ = basic_response<Tag>(); response_ << network::source(request_.host()); ::asio::streambuf response_buffer; pimpl->read_status(response_, response_buffer); pimpl->read_headers(response_, response_buffer); if (get_body) pimpl->read_body(response_, response_buffer); if (follow_redirect_) { std::uint16_t status = response_.status(); if (status >= 300 && status <= 307) { typename headers_range<http::basic_response<Tag> >::type location_range = headers(response_)["Location"]; typename range_iterator< typename headers_range<http::basic_response<Tag> >::type>::type location_header = std::begin(location_range); if (location_header != std::end(location_range)) { request_.uri(location_header->second); } else throw std::runtime_error( "Location header not defined in redirect response."); } else { break; } } else { break; } } while (true); return response_; }
basic_response<Tag> send_request_impl(string_type const & method, basic_request<Tag> request_, bool get_body) { boost::uint8_t count = 0; bool retry = false; do { if (count >= BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT) boost::throw_exception(std::runtime_error("Redirection exceeds maximum redirect count.")); basic_response<Tag> response_; // check if the socket is open first if (!pimpl->is_open()) { pimpl->init_socket(request_.host(), lexical_cast<string_type>(request_.port())); } response_ = basic_response<Tag>(); response_ << ::boost::network::source(request_.host()); pimpl->send_request_impl(method, request_); boost::asio::streambuf response_buffer; try { pimpl->read_status(response_, response_buffer); } catch (boost::system::system_error & e) { if (!retry && e.code() == boost::asio::error::eof) { retry = true; pimpl->init_socket(request_.host(), lexical_cast<string_type>(request_.port())); continue; } throw; // it's a retry, and there's something wrong. } pimpl->read_headers(response_, response_buffer); if ( get_body && response_.status() != 304 && (response_.status() != 204) && !(response_.status() >= 100 && response_.status() <= 199) ) { pimpl->read_body(response_, response_buffer); } typename headers_range<basic_response<Tag> >::type connection_range = headers(response_)["Connection"]; if (version_major == 1 && version_minor == 1 && !empty(connection_range) && boost::begin(connection_range)->second == string_type("close")) { pimpl->close_socket(); } else if (version_major == 1 && version_minor == 0) { pimpl->close_socket(); } if (connection_follow_redirect_) { boost::uint16_t status = response_.status(); if (status >= 300 && status <= 307) { typename headers_range<basic_response<Tag> >::type location_range = headers(response_)["Location"]; typename range_iterator<typename headers_range<basic_request<Tag> >::type>::type location_header = boost::begin(location_range); if (location_header != boost::end(location_range)) { request_.uri(location_header->second); connection_ptr connection_; connection_ = get_connection_(resolver_, request_, certificate_filename_, verify_path_); ++count; continue; } else boost::throw_exception(std::runtime_error("Location header not defined in redirect response.")); } } return response_; } while(true); }
response_type const connect_net( basic_request<Tag> const & request, string_type const & method, bool get_body, body_callback_function_type callback, body_generator_function_type generator ) { using original_tag = typename webmock::adapter::cpp_netlib::tags::rmap<Tag>::type; using original_string_type = typename string<original_tag>::type; using original_client_type = basic_client< original_tag, version_major, version_minor >; typename original_client_type::request original_request(request.uri()); for (auto && header: http::headers(request)) { original_request << network::header(header.first, header.second); } std::string body = http::body(request); original_request << network::body(body); client_options<original_tag> original_option; original_option .cache_resolved(this->cache_resolved) .follow_redirects(this->follow_redirect) .io_service(this->service) .timeout(this->timeout) ; if (this->certificate_filename) { original_option.openssl_certificate( lexical_cast<original_string_type>(*this->certificate_filename) ); } if (this->verify_path) { original_option.openssl_verify_path( lexical_cast<original_string_type>(*this->verify_path) ); } if (this->certificate_file) { original_option.openssl_certificate_file( lexical_cast<original_string_type>(*this->certificate_file) ); } if (this->private_key_file) { original_option.openssl_private_key_file( lexical_cast<original_string_type>(*this->private_key_file) ); } original_client_type original_client(original_option); typename original_client_type::response original_response; if (method == "HEAD") { original_response = original_client.head( original_request ); } else if (method == "GET") { original_response = original_client.get( original_request, callback ); } else if (method == "POST") { original_response = original_client.post( original_request, body, callback, generator ); } else if (method == "PUT") { original_response = original_client.put( original_request, body, callback, generator ); } else if (method == "DELETE") { original_response = original_client.delete_( original_request, callback ); } basic_response<Tag> response; response << http::status(static_cast<int>(http::status(original_response))) << network::body(static_cast<std::string>(http::body(original_response))); for (auto && header: http::headers(original_response)) { response << network::header(header.first, header.second); } return response; }