9
9
* It is a required component in Drupal 8, and strongly recommended by other
10
10
* frameworks, including Symfony 2 and 3.
11
11
*
12
- * Our approach for Guzzle 6 is to register middleware on every client that
12
+ * Our approach for Guzzle 6-7 is to register middleware on every client that
13
13
* adds our headers to the request object, handles responses, and creates
14
14
* metrics and trace nodes using the internal RequestHandler class declared
15
15
* below.
16
16
*
17
17
* There is one issue with this approach, which is that the middleware is
18
18
* called when the request is created, rather than when the request is sent. As
19
- * Guzzle 6 removed the event system that allowed us to know exactly when the
19
+ * Guzzle 6-7 removed the event system that allowed us to know exactly when the
20
20
* request was sent, we are unable to get the time of the request being sent
21
21
* without instrumenting much more deeply into Guzzle's handlers. We consider
22
22
* this to be an obscure enough edge case that we are not doing this work at
65
65
*/
66
66
#if ZEND_MODULE_API_NO >= ZEND_5_5_X_API_NO
67
67
68
- /* {{{ newrelic\Guzzle6\RequestHandler class definition and methods */
69
-
70
68
/*
71
69
* True global for the RequestHandler class entry.
72
70
*/
73
71
zend_class_entry * nr_guzzle6_requesthandler_ce ;
72
+ zval * config ;
73
+ zend_class_entry * guzzle_client_ce ;
74
+ zval * handler_stack ;
75
+ zval * middleware = NULL ;
76
+ zval * retval ;
74
77
75
78
/*
76
79
* Arginfo for the RequestHandler methods.
@@ -107,7 +110,7 @@ static void nr_guzzle6_requesthandler_handle_response(zval* handler,
107
110
zval * response
108
111
TSRMLS_DC ) {
109
112
nr_segment_t * segment = NULL ;
110
- nr_segment_external_params_t external_params = {.library = "Guzzle 6" };
113
+ nr_segment_external_params_t external_params = {.library = "Guzzle 6-7 " };
111
114
zval * request ;
112
115
zval * method ;
113
116
zval * status ;
@@ -140,7 +143,7 @@ static void nr_guzzle6_requesthandler_handle_response(zval* handler,
140
143
141
144
if (NRPRG (txn ) && NRTXN (special_flags .debug_cat )) {
142
145
nrl_verbosedebug (
143
- NRL_CAT , "CAT: outbound response: transport='Guzzle 6' %s=" NRP_FMT ,
146
+ NRL_CAT , "CAT: outbound response: transport='Guzzle 6-7 ' %s=" NRP_FMT ,
144
147
X_NEWRELIC_APP_DATA , NRP_CAT (external_params .encoded_response_header ));
145
148
}
146
149
@@ -206,14 +209,14 @@ static PHP_NAMED_FUNCTION(nr_guzzle6_requesthandler_construct) {
206
209
zend_update_property (Z_OBJCE_P (this_obj ), ZVAL_OR_ZEND_OBJECT (this_obj ),
207
210
NR_PSTR ("request" ), request TSRMLS_CC );
208
211
209
- nr_guzzle_obj_add (this_obj , "Guzzle 6" TSRMLS_CC );
212
+ nr_guzzle_obj_add (this_obj , "Guzzle 6-7 " TSRMLS_CC );
210
213
}
211
214
212
215
/*
213
216
* Proto : void RequestHandler::onFulfilled(Psr\Http\Message\ResponseInterface
214
217
* $response)
215
218
*
216
- * Purpose : Called when a Guzzle 6 request promise is fulfilled.
219
+ * Purpose : Called when a Guzzle 6-7 request promise is fulfilled.
217
220
*
218
221
* Params : 1. The response object.
219
222
*/
@@ -257,7 +260,7 @@ static PHP_NAMED_FUNCTION(nr_guzzle6_requesthandler_onfulfilled) {
257
260
* Proto : void
258
261
* RequestHandler::onRejected(GuzzleHttp\Exception\TransferException $e)
259
262
*
260
- * Purpose : Called when a Guzzle 6 request promise failed.
263
+ * Purpose : Called when a Guzzle 6-7 request promise failed.
261
264
*
262
265
* Params : 1. The exception object.
263
266
*/
@@ -340,40 +343,33 @@ const zend_function_entry nr_guzzle6_requesthandler_functions[]
340
343
nr_guzzle6_requesthandler_onrejected_arginfo ,
341
344
ZEND_ACC_PUBLIC ) PHP_FE_END };
342
345
343
- /* }}} */
346
+ /*
347
+ * Guzzle 7 requires PHP 7.2.0 or later, which is why we will not build Guzzle 7
348
+ * support on older versions and will instead provide simple stubs for the two
349
+ * exported functions to avoid linking errors.
350
+ */
351
+ #if ZEND_MODULE_API_NO >= ZEND_7_2_X_API_NO
344
352
345
- NR_PHP_WRAPPER_START (nr_guzzle6_client_construct ) {
346
- zval * config ;
347
- zend_class_entry * guzzle_client_ce ;
348
- zval * handler_stack ;
349
- zval * middleware = NULL ;
350
- zval * retval ;
353
+ NR_PHP_WRAPPER_START (nr_guzzle7_client_construct ){
351
354
zval * this_var = nr_php_scope_get (NR_EXECUTE_ORIG_ARGS TSRMLS_CC );
352
355
353
356
(void )wraprec ;
354
357
NR_UNUSED_SPECIALFN ;
355
-
356
- /* This is how we distinguish Guzzle 4/5. */
357
- if (nr_guzzle_does_zval_implement_has_emitter (this_var TSRMLS_CC )) {
358
- NR_PHP_WRAPPER_CALL ;
359
- goto end ;
360
- }
361
-
362
358
NR_PHP_WRAPPER_CALL ;
363
359
364
360
/*
365
361
* Get our middleware callable (which is just a string), and make sure it's
366
362
* actually callable before we invoke push(). (See also PHP-1184.)
367
363
*/
368
364
middleware = nr_php_zval_alloc ();
369
- nr_php_zval_str (middleware , "newrelic\\Guzzle6 \\middleware" );
365
+ nr_php_zval_str (middleware , "newrelic\\Guzzle7 \\middleware" );
370
366
if (!nr_php_is_zval_valid_callable (middleware TSRMLS_CC )) {
371
367
nrl_verbosedebug (NRL_FRAMEWORK ,
372
368
"%s: middleware string is not considered callable" ,
373
369
__func__ );
374
370
375
371
nrm_force_add (NRTXN (unscoped_metrics ),
376
- "Supportability/library/Guzzle 6 /MiddlewareNotCallable" , 0 );
372
+ "Supportability/library/Guzzle 7 /MiddlewareNotCallable" , 0 );
377
373
378
374
goto end ;
379
375
}
@@ -408,8 +404,8 @@ NR_PHP_WRAPPER_START(nr_guzzle6_client_construct) {
408
404
}
409
405
NR_PHP_WRAPPER_END
410
406
411
- void nr_guzzle6_enable (TSRMLS_D ) {
412
- int retval ;
407
+ void nr_guzzle7_enable (TSRMLS_D ) {
408
+ int _retval ;
413
409
414
410
if (0 == NRINI (guzzle_enabled )) {
415
411
return ;
@@ -429,20 +425,20 @@ void nr_guzzle6_enable(TSRMLS_D) {
429
425
* as a standalone file, so we can use a normal namespace declaration to
430
426
* avoid possible clashes.
431
427
*/
432
- retval = zend_eval_string (
433
- "namespace newrelic\\Guzzle6 ;"
428
+ _retval = zend_eval_string (
429
+ "namespace newrelic\\Guzzle7 ;"
434
430
435
431
"use Psr\\Http\\Message\\RequestInterface;"
436
432
437
- "if (!function_exists('newrelic\\Guzzle6 \\middleware')) {"
433
+ "if (!function_exists('newrelic\\Guzzle7 \\middleware')) {"
438
434
" function middleware(callable $handler) {"
439
435
" return function (RequestInterface $request, array $options) use "
440
436
"($handler) {"
441
437
442
438
/*
443
439
* Start by adding the outbound CAT/DT/Synthetics headers to the request.
444
440
*/
445
- " foreach (newrelic_get_request_metadata('Guzzle 6 ') as $k => $v) {"
441
+ " foreach (newrelic_get_request_metadata('Guzzle 7 ') as $k => $v) {"
446
442
" $request = $request->withHeader($k, $v);"
447
443
" }"
448
444
@@ -455,13 +451,142 @@ void nr_guzzle6_enable(TSRMLS_D) {
455
451
" $promise = $handler($request, $options);"
456
452
" $promise->then([$rh, 'onFulfilled'], [$rh, 'onRejected']);"
457
453
454
+ " return $promise;"
455
+ " };"
456
+ " }"
457
+ "}" ,
458
+ NULL , "newrelic/Guzzle7" TSRMLS_CC );
459
+
460
+ if (SUCCESS == _retval ) {
461
+ nr_php_wrap_user_function (NR_PSTR ("GuzzleHttp\\Client::__construct" ),
462
+ nr_guzzle_client_construct TSRMLS_CC );
463
+ } else {
464
+ nrl_warning (NRL_FRAMEWORK ,
465
+ "%s: error evaluating PHP code; not installing handler" ,
466
+ __func__ );
467
+ }
468
+ }
469
+
470
+ void nr_guzzle7_minit (TSRMLS_D ) {
471
+ zend_class_entry ce ;
472
+
473
+ if (0 == NRINI (guzzle_enabled )) {
474
+ return ;
475
+ }
476
+
477
+ INIT_CLASS_ENTRY (ce , "newrelic\\Guzzle7\\RequestHandler" ,
478
+ nr_guzzle6_requesthandler_functions );
479
+ nr_guzzle6_requesthandler_ce
480
+ = nr_php_zend_register_internal_class_ex (& ce , NULL TSRMLS_CC );
481
+
482
+ zend_declare_property_null (nr_guzzle6_requesthandler_ce , NR_PSTR ("request" ),
483
+ ZEND_ACC_PRIVATE TSRMLS_CC );
484
+ }
485
+
486
+
487
+ #else /* PHP < 7.2 */
488
+
489
+ NR_PHP_WRAPPER_START (nr_guzzle7_client_construct ) {
490
+ (void )wraprec ;
491
+ NR_UNUSED_SPECIALFN ;
492
+ NR_UNUSED_TSRMLS ;
493
+ }
494
+ NR_PHP_WRAPPER_END
495
+
496
+ void nr_guzzle7_enable (TSRMLS_D ) {
497
+ NR_UNUSED_TSRMLS
498
+ }
499
+
500
+ void nr_guzzle7_minit (TSRMLS_D ) {
501
+ NR_UNUSED_TSRMLS ;
502
+ }
503
+
504
+ #endif /* 7.2.x */
505
+
506
+ NR_PHP_WRAPPER_START (nr_guzzle6_client_construct ) {
507
+ zval * this_var = nr_php_scope_get (NR_EXECUTE_ORIG_ARGS TSRMLS_CC );
508
+
509
+ (void )wraprec ;
510
+ NR_UNUSED_SPECIALFN ;
511
+
512
+ NR_PHP_WRAPPER_CALL ;
513
+ middleware = nr_php_zval_alloc ();
514
+ nr_php_zval_str (middleware , "newrelic\\Guzzle6\\middleware" );
515
+ if (!nr_php_is_zval_valid_callable (middleware TSRMLS_CC )) {
516
+ nrl_verbosedebug (NRL_FRAMEWORK ,
517
+ "%s: middleware string is not considered callable" ,
518
+ __func__ );
519
+
520
+ nrm_force_add (NRTXN (unscoped_metrics ),
521
+ "Supportability/library/Guzzle 6/MiddlewareNotCallable" , 0 );
522
+
523
+ goto end ;
524
+ }
525
+
526
+ guzzle_client_ce = nr_php_find_class ("guzzlehttp\\client" TSRMLS_CC );
527
+ if (NULL == guzzle_client_ce ) {
528
+ nrl_verbosedebug (NRL_FRAMEWORK ,
529
+ "%s: unable to get class entry for GuzzleHttp\\Client" ,
530
+ __func__ );
531
+ goto end ;
532
+ }
533
+
534
+ config = nr_php_get_zval_object_property_with_class (
535
+ this_var , guzzle_client_ce , "config" TSRMLS_CC );
536
+ if (!nr_php_is_zval_valid_array (config )) {
537
+ goto end ;
538
+ }
539
+
540
+ handler_stack = nr_php_zend_hash_find (Z_ARRVAL_P (config ), "handler" );
541
+ if (!nr_php_object_instanceof_class (handler_stack ,
542
+ "GuzzleHttp\\HandlerStack" TSRMLS_CC )) {
543
+ goto end ;
544
+ }
545
+
546
+ retval = nr_php_call (handler_stack , "push" , middleware );
547
+
548
+ nr_php_zval_free (& retval );
549
+
550
+ end :
551
+ nr_php_zval_free (& middleware );
552
+ nr_php_scope_release (& this_var );
553
+ }
554
+ NR_PHP_WRAPPER_END
555
+
556
+
557
+ void nr_guzzle6_enable (TSRMLS_D ) {
558
+ int _retval ;
559
+
560
+ if (0 == NRINI (guzzle_enabled )) {
561
+ return ;
562
+ }
563
+
564
+ _retval = zend_eval_string (
565
+ "namespace newrelic\\Guzzle6;"
566
+
567
+ "use Psr\\Http\\Message\\RequestInterface;"
568
+
569
+ "if (!function_exists('newrelic\\Guzzle6\\middleware')) {"
570
+ " function middleware(callable $handler) {"
571
+ " return function (RequestInterface $request, array $options) use "
572
+ "($handler) {"
573
+
574
+ " foreach (newrelic_get_request_metadata('Guzzle 6') as $k => $v) {"
575
+ " $request = $request->withHeader($k, $v);"
576
+ " }"
577
+
578
+
579
+ " $rh = new RequestHandler($request);"
580
+ " $promise = $handler($request, $options);"
581
+ " $promise->then([$rh, 'onFulfilled'], [$rh, 'onRejected']);"
582
+
458
583
" return $promise;"
459
584
" };"
460
585
" }"
461
586
"}" ,
462
587
NULL , "newrelic/Guzzle6" TSRMLS_CC );
463
588
464
- if (SUCCESS == retval ) {
589
+ if (SUCCESS == _retval ) {
465
590
nr_php_wrap_user_function (NR_PSTR ("GuzzleHttp\\Client::__construct" ),
466
591
nr_guzzle_client_construct TSRMLS_CC );
467
592
} else {
@@ -504,4 +629,4 @@ void nr_guzzle6_minit(TSRMLS_D) {
504
629
NR_UNUSED_TSRMLS ;
505
630
}
506
631
507
- #endif /* 5.5.x */
632
+ #endif /* 5.5.x */
0 commit comments