I have been trying to set up a HTTP Client which uses the Apple Network Framework for it's connection and TLS needs. Using Objective-C calls in a C++ project. I have been playing around with the Implementation at Implementing netcat with Network Framework . After a successful TLS handshake, I send a request to the server using the following code snippet:
dispatch_data_t content = dispatch_data_create(headers.c_str(), strlen(headers.c_str()), dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
nw_connection_send(m_connectionObject, content, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^ (nw_error_t nwError) {
if (nwError != NULL)
{
auto errNumber = nw_error_get_error_code(nwError);
logger->Error("Error sending data to [%s]:%d : Error Number :%d", request.Host(), request.Port(), errNumber);
}
else
{
logger->Debug("Sent %u byte(s) of HTTP headers", headersLen);
}
});
where std::string headers is a stream of HTTPS request headers.
The sending operation is successful but when it comes to receiving block which starts after the above snippet, the Network framework directly produces the content offered by the destination. I need to access the server's HTTP response headers first. Is there a way to do that?
Also I need to continue using this framework and can not more to NSURLSessions stuff.
The receive block:
nw_connection_receive(m_connectionObject, 1, UINT32_MAX, ^ (dispatch_data_t content, nw_content_context_t context, bool isComplete, nw_error_t receiveError) {
nw_retain(context);
dispatch_block_t schedule_next_receive = ^ {
// If the context is marked as complete, and is the final context,
// we're read-closed.
if (isComplete && (context == NULL || nw_content_context_get_is_final(context)))
{
logger->Info(
"HTTP Client was remotely disconnected from destination.");
nw_connection_cancel(m_connectionObject);
}
// If there was no error in receiving, request more data
if (receiveError == NULL)
{
ReceiveResponse(request, response, bodyParser);
}
nw_release(context);
};
if (content != NULL)
{
schedule_next_receive = Block_copy(schedule_next_receive);
//Convert dispatch_data_t to std::string
std::string message = CreateStringWithDispatchData(content);
//Parse the response message, false means unsuccessful parsing
if(ProcessResponse(message))
{
schedule_next_receive();
}
else
{
nw_connection_cancel(m_connectionObject);
}
}
else
{
// Content was NULL, so directly schedule the next receive
schedule_next_receive();
}
});