Skip to content

Commit 7964f1b

Browse files
authored
Merge pull request #507 from orudge/master
Add support for retrieving remote address in HTTP listener
2 parents 1b7294c + 4824434 commit 7964f1b

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

Release/include/cpprest/http_msg.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena
715715

716716
_ASYNCRTIMP void set_request_uri(const uri&);
717717

718+
const utility::string_t& remote_address() const { return m_remote_address; }
719+
718720
const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; }
719721

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

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

760+
void _set_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; }
761+
758762
private:
759763

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

780784
pplx::task_completion_event<http_response> m_response;
785+
786+
utility::string_t m_remote_address;
781787
};
782788

783789

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

878+
/// <summary>
879+
/// Returns a string representation of the remote IP address.
880+
/// </summary>
881+
/// <returns>The remote IP address.</returns>
882+
const utility::string_t& get_remote_address() const { return _m_impl->remote_address(); }
883+
872884
/// <summary>
873885
/// Extract the body of the request message as a string value, checking that the content type is a MIME text type.
874886
/// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.

Release/src/http/listener/http_server_asio.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,9 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys
654654
m_close = true;
655655
}
656656

657+
// Get the remote IP address
658+
m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(m_socket->remote_endpoint().address().to_string()));
659+
657660
return handle_headers();
658661
}
659662
}

Release/src/http/listener/http_server_httpsys.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,22 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD
555555
m_msg.set_method(parse_request_method(m_request));
556556
parse_http_headers(m_request->Headers, m_msg.headers());
557557

558+
// Retrieve the remote IP address
559+
std::vector<wchar_t> remoteAddressBuffer(50);
560+
PVOID inAddr;
561+
562+
if (m_request->Address.pRemoteAddress->sa_family == AF_INET6)
563+
{
564+
inAddr = &reinterpret_cast<SOCKADDR_IN6 *>(m_request->Address.pRemoteAddress)->sin6_addr;
565+
}
566+
else
567+
{
568+
inAddr = &reinterpret_cast<SOCKADDR_IN *>(m_request->Address.pRemoteAddress)->sin_addr;
569+
}
570+
571+
InetNtopW(m_request->Address.pRemoteAddress->sa_family, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size());
572+
m_msg._get_impl()->_set_remote_address(std::wstring(&remoteAddressBuffer[0]));
573+
558574
// Start reading in body from the network.
559575
m_msg._get_impl()->_prepare_to_receive_data();
560576
read_request_body_chunk();

Release/tests/functional/http/listener/request_handler_tests.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,41 @@ TEST_FIXTURE(uri_address, test_leaks)
448448
listener.close().wait();
449449
}
450450

451+
TEST_FIXTURE(uri_address, remote_address)
452+
{
453+
http_listener listener(U("http://localhost:45678/path1"));
454+
listener.open().wait();
455+
456+
test_http_client::scoped_client client(U("http://localhost:45678"));
457+
test_http_client * p_client = client.client();
458+
459+
volatile unsigned long requestCount = 0;
460+
461+
listener.support(methods::GET, [&requestCount](http_request request)
462+
{
463+
const string_t& remoteAddr = request.get_remote_address();
464+
const string_t& localhost4 = string_t(U("127.0.0.1"));
465+
const string_t& localhost6 = string_t(U("::1"));
466+
467+
// We can't guarantee that the host has both IPv4 and IPv6 available, so check for either IP
468+
VERIFY_IS_TRUE((remoteAddr == localhost4) || (remoteAddr == localhost6));
469+
470+
os_utilities::interlocked_increment(&requestCount);
471+
request.reply(status_codes::NoContent);
472+
});
473+
474+
// Send a request to the listener
475+
VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1")));
476+
477+
p_client->next_response().then([](test_response *p_response)
478+
{
479+
http_asserts::assert_test_response_equals(p_response, status_codes::NoContent);
480+
}).wait();
481+
482+
VERIFY_IS_TRUE(requestCount >= 1);
483+
listener.close().wait();
484+
}
485+
451486
}
452487

453488
}}}}

0 commit comments

Comments
 (0)