Skip to content

Add support for retrieving remote address in HTTP listener #507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Release/include/cpprest/http_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena

_ASYNCRTIMP void set_request_uri(const uri&);

const utility::string_t& remote_address() const { return m_remote_address; }

const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; }

void set_cancellation_token(const pplx::cancellation_token &token)
Expand Down Expand Up @@ -755,6 +757,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena

void _set_base_uri(const http::uri &base_uri) { m_base_uri = base_uri; }

void _set_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; }

private:

// Actual initiates sending the response, without checking if a response has already been sent.
Expand All @@ -778,6 +782,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena
std::shared_ptr<progress_handler> m_progress_handler;

pplx::task_completion_event<http_response> m_response;

utility::string_t m_remote_address;
};


Expand Down Expand Up @@ -869,6 +875,12 @@ class http_request
/// </remarks>
const http_headers &headers() const { return _m_impl->headers(); }

/// <summary>
/// Returns a string representation of the remote IP address.
/// </summary>
/// <returns>The remote IP address.</returns>
const utility::string_t& get_remote_address() const { return _m_impl->remote_address(); }

/// <summary>
/// Extract the body of the request message as a string value, checking that the content type is a MIME text type.
/// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.
Expand Down
3 changes: 3 additions & 0 deletions Release/src/http/listener/http_server_asio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,9 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys
m_close = true;
}

// Get the remote IP address
m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(m_socket->remote_endpoint().address().to_string()));

return handle_headers();
}
}
Expand Down
16 changes: 16 additions & 0 deletions Release/src/http/listener/http_server_httpsys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,22 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD
m_msg.set_method(parse_request_method(m_request));
parse_http_headers(m_request->Headers, m_msg.headers());

// Retrieve the remote IP address
std::vector<wchar_t> remoteAddressBuffer(50);
PVOID inAddr;

if (m_request->Address.pRemoteAddress->sa_family == AF_INET6)
{
inAddr = &reinterpret_cast<SOCKADDR_IN6 *>(m_request->Address.pRemoteAddress)->sin6_addr;
}
else
{
inAddr = &reinterpret_cast<SOCKADDR_IN *>(m_request->Address.pRemoteAddress)->sin_addr;
}

InetNtopW(m_request->Address.pRemoteAddress->sa_family, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size());
m_msg._get_impl()->_set_remote_address(std::wstring(&remoteAddressBuffer[0]));

// Start reading in body from the network.
m_msg._get_impl()->_prepare_to_receive_data();
read_request_body_chunk();
Expand Down
35 changes: 35 additions & 0 deletions Release/tests/functional/http/listener/request_handler_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,41 @@ TEST_FIXTURE(uri_address, test_leaks)
listener.close().wait();
}

TEST_FIXTURE(uri_address, remote_address)
{
http_listener listener(U("http://localhost:45678/path1"));
listener.open().wait();

test_http_client::scoped_client client(U("http://localhost:45678"));
test_http_client * p_client = client.client();

volatile unsigned long requestCount = 0;

listener.support(methods::GET, [&requestCount](http_request request)
{
const string_t& remoteAddr = request.get_remote_address();
const string_t& localhost4 = string_t(U("127.0.0.1"));
const string_t& localhost6 = string_t(U("::1"));

// We can't guarantee that the host has both IPv4 and IPv6 available, so check for either IP
VERIFY_IS_TRUE((remoteAddr == localhost4) || (remoteAddr == localhost6));

os_utilities::interlocked_increment(&requestCount);
request.reply(status_codes::NoContent);
});

// Send a request to the listener
VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1")));

p_client->next_response().then([](test_response *p_response)
{
http_asserts::assert_test_response_equals(p_response, status_codes::NoContent);
}).wait();

VERIFY_IS_TRUE(requestCount >= 1);
listener.close().wait();
}

}

}}}}