Skip to content

Commit 4d9b423

Browse files
authored
[darwin-framework-tool] Use NSURLSession instead of the NetworkFramework for reading DCL content (#37964)
1 parent c0e580c commit 4d9b423

File tree

1 file changed

+54
-177
lines changed

1 file changed

+54
-177
lines changed

examples/darwin-framework-tool/commands/dcl/HTTPSRequest.mm

+54-177
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include <system/SystemError.h>
2727

2828
#include <CommonCrypto/CommonDigest.h>
29-
#include <Network/Network.h>
29+
#include <Foundation/Foundation.h>
3030

3131
#include <unistd.h>
3232

@@ -41,186 +41,69 @@
4141
constexpr const char * kErrorSizeMismatch = "The response size does not match the expected size: ";
4242
} // namespace
4343

44+
@interface NSURLSessionDelegateAllowAll : NSObject <NSURLSessionDelegate>
45+
@end
46+
47+
@implementation NSURLSessionDelegateAllowAll
48+
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * credential))completionHandler
49+
{
50+
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
51+
}
52+
@end
53+
4454
namespace chip {
4555
namespace tool {
4656
namespace https {
4757
namespace {
48-
constexpr uint16_t kResponseBufferSize = 4096;
49-
constexpr uint64_t kConnectionTimeoutSeconds = 10;
5058
constexpr uint64_t kSendTimeoutSeconds = 10;
51-
constexpr uint64_t kReceiveTimeoutSeconds = 10;
52-
constexpr const char * kDispatchQueueName = "com.chip.httpsrequest";
53-
constexpr const char * kContentContextName = "httpsrequest";
54-
constexpr const char * kErrorSendHTTPRequest = "Failed to send HTTP request";
55-
constexpr const char * kErrorSendHTTPRequestTimeout = "Failed to send HTTP request: timeout";
56-
constexpr const char * kErrorReceiveHTTPResponse = "Failed to read HTTP response";
57-
constexpr const char * kErrorReceiveHTTPResponseTimeout = "Failed to read HTTP response: timeout";
58-
constexpr const char * kErrorConnection = "Failed to connect to: ";
59-
constexpr const char * kErrorConnectionTimeout = "Timeout connecting to: ";
60-
constexpr const char * kErrorConnectionUnknowState = "Unknown connection state";
59+
constexpr const char * kErrorReceiveHTTPResponse = "Failed to read HTTP response: ";
60+
constexpr const char * kErrorReceiveHTTPResponseTimeout = "Failed to read HTTP response (timeout): ";
6161
constexpr const char * kErrorDigestMismatch = "The response digest does not match the expected digest";
6262

63-
constexpr sec_protocol_verify_t NULL_VERIFIER = ^(sec_protocol_metadata_t metadata,
64-
sec_trust_t trust_ref,
65-
sec_protocol_verify_complete_t complete) {
66-
complete(true);
67-
};
68-
69-
class HTTPSSessionHolder {
70-
public:
71-
HTTPSSessionHolder() {};
72-
73-
~HTTPSSessionHolder()
74-
{
75-
VerifyOrReturn(nullptr != mConnection);
76-
nw_connection_cancel(mConnection);
77-
mConnection = nullptr;
78-
}
79-
80-
CHIP_ERROR Init(std::string & hostname, uint16_t port, HttpsSecurityMode securityMode)
81-
{
82-
__auto_type semaphore = dispatch_semaphore_create(0);
83-
__block CHIP_ERROR result = CHIP_NO_ERROR;
84-
__auto_type queue = dispatch_queue_create(kDispatchQueueName, DISPATCH_QUEUE_SERIAL);
85-
86-
__auto_type endpoint = nw_endpoint_create_host(hostname.c_str(), std::to_string(port).c_str());
87-
88-
nw_parameters_configure_protocol_block_t tls_options;
89-
switch (securityMode) {
90-
case HttpsSecurityMode::kDefault: {
91-
tls_options = NW_PARAMETERS_DEFAULT_CONFIGURATION;
92-
break;
93-
}
94-
case HttpsSecurityMode::kDisableValidation: {
95-
tls_options = ^(nw_protocol_options_t options) {
96-
sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(options);
97-
sec_protocol_options_set_verify_block(sec_options, NULL_VERIFIER, queue);
98-
};
99-
break;
100-
}
101-
case HttpsSecurityMode::kDisableHttps: {
102-
tls_options = NW_PARAMETERS_DISABLE_PROTOCOL;
103-
break;
104-
}
105-
}
106-
107-
// NW_PARAMETERS_DISABLE_PROTOCOL
108-
nw_parameters_t parameters = nw_parameters_create_secure_tcp(tls_options, NW_PARAMETERS_DEFAULT_CONFIGURATION);
109-
110-
mConnection = nw_connection_create(endpoint, parameters);
111-
VerifyOrReturnError(nullptr != mConnection, CHIP_ERROR_INTERNAL);
112-
113-
nw_connection_set_state_changed_handler(mConnection, ^(nw_connection_state_t state, nw_error_t error) {
114-
switch (state) {
115-
case nw_connection_state_waiting:
116-
case nw_connection_state_preparing:
117-
break;
118-
case nw_connection_state_ready:
119-
result = CHIP_NO_ERROR;
120-
dispatch_semaphore_signal(semaphore);
121-
break;
122-
case nw_connection_state_failed:
123-
case nw_connection_state_cancelled:
124-
ChipLogError(chipTool, "%s%s", kErrorConnection, hostname.c_str());
125-
result = CHIP_ERROR_NOT_CONNECTED;
126-
dispatch_semaphore_signal(semaphore);
127-
default:
128-
ChipLogError(chipTool, "%s", kErrorConnectionUnknowState);
129-
break;
130-
}
131-
});
132-
133-
nw_connection_set_queue(mConnection, queue);
134-
nw_connection_start(mConnection);
135-
136-
if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kConnectionTimeoutSeconds * NSEC_PER_SEC)) != 0) {
137-
ChipLogError(chipTool, "%s%s", kErrorConnectionTimeout, hostname.c_str());
138-
return CHIP_ERROR_TIMEOUT;
139-
}
140-
141-
nw_connection_set_state_changed_handler(mConnection, nullptr);
142-
return result;
143-
}
144-
145-
CHIP_ERROR SendRequest(std::string & request)
146-
{
147-
__auto_type semaphore = dispatch_semaphore_create(0);
148-
__block CHIP_ERROR result = CHIP_NO_ERROR;
149-
150-
__auto_type context = nw_content_context_create(kContentContextName);
151-
__auto_type data = dispatch_data_create(request.c_str(), request.size(), dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
152-
nw_connection_send(mConnection, data, context, true, ^(nw_error_t error) {
153-
if (nullptr != error) {
154-
ChipLogError(chipTool, "%s", kErrorSendHTTPRequest);
155-
result = CHIP_ERROR_BAD_REQUEST;
156-
}
157-
dispatch_semaphore_signal(semaphore);
158-
});
159-
160-
if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kSendTimeoutSeconds * NSEC_PER_SEC)) != 0) {
161-
ChipLogError(chipTool, "%s", kErrorSendHTTPRequestTimeout);
162-
return CHIP_ERROR_TIMEOUT;
163-
}
164-
165-
return result;
63+
CHIP_ERROR SendRequest(const std::string & hostname, uint16_t port, const std::string & path, HttpsSecurityMode securityMode, std::string & response)
64+
{
65+
std::string urlString = (securityMode == HttpsSecurityMode::kDisableHttps ? "http://" : "https://") + hostname + ":" + std::to_string(port) + path;
66+
__auto_type * requestURL = [NSURL URLWithString:[NSString stringWithUTF8String:urlString.c_str()]];
67+
__auto_type * urlRequest = [NSMutableURLRequest requestWithURL:requestURL];
68+
[urlRequest setHTTPMethod:@"GET"];
69+
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];
70+
[urlRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
71+
72+
__auto_type * config = [NSURLSessionConfiguration defaultSessionConfiguration];
73+
74+
NSURLSession * session;
75+
if (securityMode == HttpsSecurityMode::kDisableValidation) {
76+
session = [NSURLSession sessionWithConfiguration:config
77+
delegate:(id<NSURLSessionDelegate>) [[NSURLSessionDelegateAllowAll alloc] init]
78+
delegateQueue:nil];
79+
} else {
80+
session = [NSURLSession sessionWithConfiguration:config];
16681
}
16782

168-
CHIP_ERROR ReceiveResponse(std::string & response)
169-
{
170-
__auto_type semaphore = dispatch_semaphore_create(0);
171-
__block CHIP_ERROR result = CHIP_NO_ERROR;
172-
__block std::string receivedData;
173-
174-
nw_connection_receive(mConnection, 1, kResponseBufferSize, ^(dispatch_data_t content, nw_content_context_t context, bool isComplete, nw_error_t error) {
175-
if (nullptr != error) {
176-
ChipLogError(chipTool, "%s", kErrorReceiveHTTPResponse);
177-
result = CHIP_ERROR_INTERNAL;
178-
} else if (nullptr != content) {
179-
size_t total_size = dispatch_data_get_size(content);
180-
receivedData.reserve(total_size);
181-
182-
dispatch_data_apply(content, ^(dispatch_data_t region, size_t offset, const void * buffer, size_t size) {
183-
receivedData.append(static_cast<const char *>(buffer), size);
184-
return true;
185-
});
186-
187-
result = CHIP_NO_ERROR;
188-
}
189-
190-
dispatch_semaphore_signal(semaphore);
191-
});
192-
193-
if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kReceiveTimeoutSeconds * NSEC_PER_SEC)) != 0) {
194-
ChipLogError(chipTool, "%s", kErrorReceiveHTTPResponseTimeout);
195-
return CHIP_ERROR_TIMEOUT;
196-
}
197-
198-
response = receivedData;
199-
return result;
83+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
84+
__block CHIP_ERROR rv = CHIP_NO_ERROR;
85+
__block std::string receivedData;
86+
NSURLSessionDataTask * task = [session dataTaskWithRequest:urlRequest
87+
completionHandler:^(NSData * data, NSURLResponse * resp, NSError * error) {
88+
if (error) {
89+
ChipLogError(chipTool, "%s%s", kErrorReceiveHTTPResponse, [[error localizedDescription] UTF8String]);
90+
rv = CHIP_ERROR_BAD_REQUEST;
91+
} else {
92+
receivedData.assign((const char *) [data bytes], [data length]);
93+
rv = CHIP_NO_ERROR;
94+
}
95+
dispatch_semaphore_signal(semaphore);
96+
}];
97+
98+
[task resume];
99+
100+
if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kSendTimeoutSeconds * NSEC_PER_SEC)) != 0) {
101+
ChipLogError(chipTool, "%s%s", kErrorReceiveHTTPResponseTimeout, hostname.c_str());
102+
return CHIP_ERROR_TIMEOUT;
200103
}
201104

202-
private:
203-
nw_connection_t mConnection = nullptr;
204-
};
205-
206-
std::string BuildRequest(std::string & hostname, std::string & path)
207-
{
208-
return "GET " + path + " HTTP/1.1\r\n" + //
209-
"Host: " + hostname + "\r\n" + //
210-
"Accept: application/json\r\n" + //
211-
"Connection: close\r\n\r\n"; //
212-
}
213-
214-
CHIP_ERROR RemoveHeader(std::string & response)
215-
{
216-
// TODO: Parse the response status. Why are we doing HTTP by hand?
217-
size_t headerEnd = response.find("\r\n\r\n");
218-
VerifyOrReturnError(std::string::npos != headerEnd, CHIP_ERROR_INVALID_ARGUMENT);
219-
220-
auto body = response.substr(headerEnd + 4);
221-
response = body;
222-
223-
return CHIP_NO_ERROR;
105+
response = receivedData;
106+
return rv;
224107
}
225108

226109
CHIP_ERROR MaybeCheckResponseSize(const std::string & response, const chip::Optional<uint32_t> & optionalExpectedSize)
@@ -348,14 +231,8 @@ CHIP_ERROR Request(std::string hostname, uint16_t port, std::string path, Json::
348231
}
349232
ChipLogDetail(chipTool, "%s request to %s:%u%s", protocol, hostname.c_str(), port, path.c_str());
350233

351-
std::string request = BuildRequest(hostname, path);
352234
std::string response;
353-
354-
HTTPSSessionHolder session;
355-
ReturnErrorOnFailure(session.Init(hostname, port, securityMode));
356-
ReturnErrorOnFailure(session.SendRequest(request));
357-
ReturnErrorOnFailure(session.ReceiveResponse(response));
358-
ReturnErrorOnFailure(RemoveHeader(response));
235+
ReturnErrorOnFailure(SendRequest(hostname, port, path, securityMode, response));
359236
ReturnErrorOnFailure(MaybeCheckResponseSize(response, optionalExpectedSize));
360237
ReturnErrorOnFailure(MaybeCheckResponseDigest(response, optionalExpectedDigest));
361238
ReturnErrorOnFailure(ConvertResponseToJSON(response, jsonResponse));

0 commit comments

Comments
 (0)