1010#include < sstream>
1111#include < vector>
1212
13+ namespace
14+ {
15+ class LocalFrame
16+ {
17+ public:
18+ explicit LocalFrame (JNIEnv* env) :
19+ m_env(env), m_pushed(env->PushLocalFrame (16 ) == JNI_OK)
20+ {
21+ }
22+
23+ ~LocalFrame ()
24+ {
25+ if (m_pushed)
26+ {
27+ m_env->PopLocalFrame (nullptr );
28+ }
29+ }
30+
31+ bool IsValid () const
32+ {
33+ return m_pushed;
34+ }
35+
36+ private:
37+ JNIEnv* m_env;
38+ bool m_pushed;
39+ };
40+ }
41+
1342namespace MAT_NS_BEGIN
1443{
1544 HttpClient_Android::HttpRequest::~HttpRequest () noexcept
@@ -22,7 +51,16 @@ namespace MAT_NS_BEGIN
2251 {
2352 return ;
2453 }
54+ ReleaseJavaRequest (env);
55+ }
56+ }
57+
58+ void HttpClient_Android::HttpRequest::ReleaseJavaRequest (JNIEnv* env)
59+ {
60+ if (m_java_request)
61+ {
2562 env->DeleteGlobalRef (m_java_request);
63+ m_java_request = nullptr ;
2664 }
2765 }
2866
@@ -88,7 +126,7 @@ namespace MAT_NS_BEGIN
88126 IHttpResponseCallback* callback)
89127 {
90128 JNIEnv* env = nullptr ;
91- std::string const & target_id (request->GetId ());
129+ std::string const target_id (request->GetId ());
92130
93131 if (s_java_vm->AttachCurrentThread (&env, nullptr ) != JNI_OK )
94132 {
@@ -134,14 +172,22 @@ namespace MAT_NS_BEGIN
134172 total_size += u.first .length () + u.second .length ();
135173 }
136174
137- static constexpr int FrameSize = 16 ; // at most 16 local refs in the frame
138- auto pushed = env->PushLocalFrame (FrameSize);
139- if (CheckException (env, r))
175+ LocalFrame frame (env);
176+ if (CheckException (env, target_id))
140177 {
141178 return ;
142179 }
180+ if (!frame.IsValid ())
181+ {
182+ auto failed = GetAndRemoveRequest (target_id);
183+ if (failed)
184+ {
185+ CallbackForCancel (env, failed);
186+ }
187+ return ;
188+ }
143189 auto header_buffer = env->NewByteArray (static_cast <jsize>(total_size));
144- if (CheckException (env, r ))
190+ if (CheckException (env, target_id ))
145191 {
146192 return ;
147193 }
@@ -156,7 +202,7 @@ namespace MAT_NS_BEGIN
156202 {
157203 env->SetByteArrayRegion (header_buffer, offset, key_len,
158204 reinterpret_cast <jbyte const *>(u.first .data ()));
159- if (CheckException (env, r ))
205+ if (CheckException (env, target_id ))
160206 {
161207 return ;
162208 }
@@ -168,47 +214,47 @@ namespace MAT_NS_BEGIN
168214 {
169215 env->SetByteArrayRegion (header_buffer, offset, value_len,
170216 reinterpret_cast <jbyte const *>(u.second .data ()));
171- if (CheckException (env, r ))
217+ if (CheckException (env, target_id ))
172218 {
173219 return ;
174220 }
175221 }
176222 offset += value_len;
177223 }
178224 auto header_lengths = env->NewIntArray (static_cast <jsize>(index_buffer.size ()));
179- if (CheckException (env, r ))
225+ if (CheckException (env, target_id ))
180226 {
181227 return ;
182228 }
183229 env->SetIntArrayRegion (header_lengths, 0 , index_buffer.size (), index_buffer.data ());
184- if (CheckException (env, r ))
230+ if (CheckException (env, target_id ))
185231 {
186232 return ;
187233 }
188234
189235 auto body = env->NewByteArray (r->m_body .size ());
190- if (CheckException (env, r ))
236+ if (CheckException (env, target_id ))
191237 {
192238 return ;
193239 }
194240 env->SetByteArrayRegion (body, 0 , r->m_body .size (),
195241 reinterpret_cast <const jbyte*>(r->m_body .data ()));
196- if (CheckException (env, r ))
242+ if (CheckException (env, target_id ))
197243 {
198244 return ;
199245 }
200246 auto java_id = env->NewStringUTF (request->GetId ().c_str ());
201- if (CheckException (env, r ))
247+ if (CheckException (env, target_id ))
202248 {
203249 return ;
204250 }
205251 auto url_id = env->NewStringUTF (r->m_url .c_str ());
206- if (CheckException (env, r ))
252+ if (CheckException (env, target_id ))
207253 {
208254 return ;
209255 }
210256 auto method_id = env->NewStringUTF (r->m_method .c_str ());
211- if (CheckException (env, r ))
257+ if (CheckException (env, target_id ))
212258 {
213259 return ;
214260 }
@@ -231,10 +277,9 @@ namespace MAT_NS_BEGIN
231277 header_lengths,
232278 header_buffer);
233279 }
234- if (pushed == JNI_OK )
280+ if (CheckException (env, target_id) )
235281 {
236- // pass the return value "result" through the local frame pop
237- result = env->PopLocalFrame (result);
282+ return ;
238283 }
239284
240285 HttpRequest* cancel_me = nullptr ;
@@ -263,13 +308,18 @@ namespace MAT_NS_BEGIN
263308 }
264309 }
265310 }
311+ if (CheckException (env, target_id))
312+ {
313+ return ;
314+ }
266315 if (cancel_me)
267316 {
268317 CallbackForCancel (env, cancel_me);
269318 }
270319 else
271320 {
272321 env->CallVoidMethod (m_client, m_execute_id, result);
322+ CheckException (env, target_id);
273323 }
274324 }
275325
@@ -278,8 +328,18 @@ namespace MAT_NS_BEGIN
278328 if (request->m_java_request && env)
279329 {
280330 auto request_class = env->GetObjectClass (request->m_java_request );
281- auto cancel_method = env->GetMethodID (request_class, " cancel" , " (Z)Z" );
282- env->CallBooleanMethod (request->m_java_request , cancel_method, static_cast <jboolean>(JNI_TRUE ));
331+ auto cancel_method = request_class ? env->GetMethodID (request_class, " cancel" , " (Z)Z" ) : nullptr ;
332+ if (cancel_method)
333+ {
334+ env->CallBooleanMethod (request->m_java_request , cancel_method, static_cast <jboolean>(JNI_TRUE ));
335+ }
336+ env->DeleteLocalRef (request_class);
337+ request->ReleaseJavaRequest (env);
338+ if (env->ExceptionCheck ())
339+ {
340+ env->ExceptionDescribe ();
341+ env->ExceptionClear ();
342+ }
283343 }
284344 if (request->m_callback )
285345 {
@@ -379,11 +439,12 @@ namespace MAT_NS_BEGIN
379439 env->DeleteGlobalRef (m_client);
380440 }
381441 m_client = env->NewGlobalRef (client_);
382- m_client_class = env->GetObjectClass (m_client);
383- m_create_id = env->GetMethodID (m_client_class , " createTask" ,
442+ auto client_class = env->GetObjectClass (m_client);
443+ m_create_id = env->GetMethodID (client_class , " createTask" ,
384444 " (Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;[I[B)Ljava/util/concurrent/FutureTask;" );
385- m_execute_id = env->GetMethodID (m_client_class , " executeTask" ,
445+ m_execute_id = env->GetMethodID (client_class , " executeTask" ,
386446 " (Ljava/util/concurrent/FutureTask;)V" );
447+ env->DeleteLocalRef (client_class);
387448
388449 env->GetJavaVM (&s_java_vm);
389450 }
@@ -485,15 +546,19 @@ namespace MAT_NS_BEGIN
485546 return s_client;
486547 }
487548
488- bool HttpClient_Android::CheckException (JNIEnv* env, HttpRequest* request )
549+ bool HttpClient_Android::CheckException (JNIEnv* env, std::string const & id )
489550 {
490551 if (env->ExceptionCheck () == JNI_FALSE )
491552 {
492553 return false ;
493554 }
494555 env->ExceptionDescribe ();
495556 env->ExceptionClear ();
496- CallbackForCancel (env, request);
557+ auto request = GetAndRemoveRequest (id);
558+ if (request)
559+ {
560+ CallbackForCancel (env, request);
561+ }
497562 return true ;
498563 }
499564
@@ -559,6 +624,7 @@ extern "C" JNIEXPORT void
559624 {
560625 return ;
561626 }
627+ request->ReleaseJavaRequest (env);
562628 auto callback = request->GetCallback ();
563629 auto response = new Microsoft::Applications::Events::HttpClient_Android::HttpResponse (request->GetId ());
564630 response->SetResponse (statusCode);
0 commit comments