@@ -36,6 +36,57 @@ NOTE_C_STATIC bool _crcError(char *json, uint16_t shouldBeSeqno);
36
36
NOTE_C_STATIC bool notecardFirmwareSupportsCrc = false;
37
37
#endif // !NOTE_C_LOW_MEM
38
38
39
+ /*!
40
+ @internal
41
+
42
+ @brief Create a JSON object containing an error message.
43
+
44
+ Create a dynamically allocated `J` object containing a single string field
45
+ "err" whose value is the passed in error message.
46
+
47
+ @param id The "id" from the original request that resulted in an error
48
+ @param errmsg The error message.
49
+
50
+ @returns A `J` object with the "err" field populated.
51
+ */
52
+ NOTE_C_STATIC J * _errDoc (uint32_t id , const char * errmsg )
53
+ {
54
+ J * rspdoc = JCreateObject ();
55
+ if (rspdoc != NULL ) {
56
+ JAddStringToObject (rspdoc , c_err , errmsg );
57
+ JAddStringToObject (rspdoc , "src" , "note-c" );
58
+ if (id ) {
59
+ JAddIntToObject (rspdoc , "id" , id );
60
+ }
61
+ if (suppressShowTransactions == 0 ) {
62
+ _DebugWithLevel (NOTE_C_LOG_LEVEL_ERROR , "[ERROR] " );
63
+ _DebugWithLevel (NOTE_C_LOG_LEVEL_ERROR , "{\"err\":\"" );
64
+ _DebugWithLevel (NOTE_C_LOG_LEVEL_ERROR , errmsg );
65
+ _DebugWithLevelLn (NOTE_C_LOG_LEVEL_ERROR , "\",\"src\":\"note-c\"}" );
66
+ }
67
+ } else {
68
+ NOTE_C_LOG_ERROR ("Failed to allocate error document!" );
69
+ }
70
+
71
+ return rspdoc ;
72
+ }
73
+
74
+ /*!
75
+ @brief Resume showing transaction details.
76
+ */
77
+ void _noteResumeTransactionDebug (void )
78
+ {
79
+ suppressShowTransactions -- ;
80
+ }
81
+
82
+ /*!
83
+ @brief Suppress showing transaction details.
84
+ */
85
+ void _noteSuspendTransactionDebug (void )
86
+ {
87
+ suppressShowTransactions ++ ;
88
+ }
89
+
39
90
/*!
40
91
@internal
41
92
@@ -92,55 +143,6 @@ NOTE_C_STATIC bool notecardFirmwareSupportsCrc = false;
92
143
return result ;
93
144
}
94
145
95
- /*!
96
- @internal
97
-
98
- @brief Create a JSON object containing an error message.
99
-
100
- Create a dynamically allocated `J` object containing a single string field
101
- "err" whose value is the passed in error message.
102
-
103
- @param id The "id" from the original request that resulted in an error
104
- @param errmsg The error message.
105
-
106
- @returns A `J` object with the "err" field populated.
107
- */
108
- NOTE_C_STATIC J * errDoc (uint32_t id , const char * errmsg )
109
- {
110
- J * rspdoc = JCreateObject ();
111
- if (rspdoc != NULL ) {
112
- JAddStringToObject (rspdoc , c_err , errmsg );
113
- JAddStringToObject (rspdoc , "src" , "note-c" );
114
- if (id ) {
115
- JAddIntToObject (rspdoc , "id" , id );
116
- }
117
- if (suppressShowTransactions == 0 ) {
118
- _DebugWithLevel (NOTE_C_LOG_LEVEL_ERROR , "[ERROR] " );
119
- _DebugWithLevel (NOTE_C_LOG_LEVEL_ERROR , "{\"err\":\"" );
120
- _DebugWithLevel (NOTE_C_LOG_LEVEL_ERROR , errmsg );
121
- _DebugWithLevelLn (NOTE_C_LOG_LEVEL_ERROR , "\",\"src\":\"note-c\"}" );
122
- }
123
- }
124
-
125
- return rspdoc ;
126
- }
127
-
128
- /*!
129
- @brief Suppress showing transaction details.
130
- */
131
- void _noteSuspendTransactionDebug (void )
132
- {
133
- suppressShowTransactions ++ ;
134
- }
135
-
136
- /*!
137
- @brief Resume showing transaction details.
138
- */
139
- void _noteResumeTransactionDebug (void )
140
- {
141
- suppressShowTransactions -- ;
142
- }
143
-
144
146
/*!
145
147
@brief Suppress showing transaction details.
146
148
*/
@@ -367,11 +369,18 @@ J *NoteRequestResponseWithRetry(J *req, uint32_t timeoutSeconds)
367
369
if there was no response or if there was an error.
368
370
369
371
@note When a "cmd" is sent, it is not possible to determine if an error occurred.
372
+
373
+ @note Unlike the `NoteRequest*` functions, this function does not automatically
374
+ free the request JSON string. It is not possible to know if the parameter
375
+ is a string literal. As such, it is the caller's responsibility to manage
376
+ the memory associated with the request string.
370
377
*/
371
378
char * NoteRequestResponseJSON (const char * reqJSON )
372
379
{
373
380
const uint32_t transactionTimeoutMs = (CARD_INTER_TRANSACTION_TIMEOUT_SEC * 1000 );
374
381
char * rspJSON = NULL ;
382
+ char * allocatedJSON = NULL ; // required to free the string if it is not newline-terminated
383
+ bool isCmdPipeline = false;
375
384
376
385
if (reqJSON == NULL ) {
377
386
return NULL ;
@@ -396,25 +405,26 @@ char * NoteRequestResponseJSON(const char *reqJSON)
396
405
// All JSON strings should be newline-terminated to meet the
397
406
// specification, however this is required to ensure backward
398
407
// compatibility with the previous implementation.
399
- const size_t tempLen = strlen (reqJSON );
400
- if (0 == tempLen ) {
408
+ const size_t allocLen = strlen (reqJSON );
409
+ if (0 == allocLen ) {
401
410
NOTE_C_LOG_ERROR (ERRSTR ("request: jsonbuf zero length" , c_bad ));
402
411
break ;
403
412
}
404
413
405
414
NOTE_C_LOG_WARN (ERRSTR ("Memory allocation due to malformed request (not newline-terminated)" , c_bad ));
406
- char * const temp = _Malloc (tempLen + 2 ); // +2 for newline and null-terminator
407
- if (temp == NULL ) {
415
+ allocatedJSON = _Malloc (allocLen + 2 ); // +2 for newline and null-terminator
416
+ if (allocatedJSON == NULL ) {
408
417
NOTE_C_LOG_ERROR (ERRSTR ("request: jsonbuf malloc failed" , c_mem ));
409
418
break ;
410
419
}
411
420
412
- memcpy (temp , reqJSON , tempLen );
413
- temp [ tempLen ] = '\n' ;
414
- temp [ tempLen + 1 ] = '\0' ;
415
- reqJSON = temp ;
416
- endPtr = & temp [ tempLen ];
421
+ memcpy (allocatedJSON , reqJSON , allocLen );
422
+ allocatedJSON [ allocLen ] = '\n' ;
423
+ allocatedJSON [ allocLen + 1 ] = '\0' ;
424
+ reqJSON = allocatedJSON ;
425
+ endPtr = & allocatedJSON [ allocLen ];
417
426
} else {
427
+ isCmdPipeline = !(strlen (newlinePtr ) == 1 );
418
428
endPtr = newlinePtr ;
419
429
}
420
430
const size_t reqLen = ((endPtr - reqJSON ) + 1 );
@@ -439,15 +449,17 @@ char * NoteRequestResponseJSON(const char *reqJSON)
439
449
const char * errstr = _Transaction (reqJSON , reqLen , & rspJSON , transactionTimeoutMs );
440
450
if (errstr != NULL ) {
441
451
NOTE_C_LOG_ERROR (errstr );
452
+
453
+ // Extract ID from the request JSON, if present
442
454
uint32_t id = 0 ;
443
- if (reqJSON != NULL ) {
444
- J * req = JParse (reqJSON );
445
- if (req != NULL ) {
446
- id = JGetInt (req , "id" );
447
- JDelete (req );
448
- }
455
+ J * req = JParse (reqJSON );
456
+ if (req != NULL ) {
457
+ id = JGetInt (req , "id" );
458
+ JDelete (req );
449
459
}
450
- J * errdoc = errDoc (id , errstr );
460
+
461
+ // Use _errDoc() to create a well-formed JSON error string
462
+ J * errdoc = _errDoc (id , errstr );
451
463
if (errdoc != NULL ) {
452
464
char * errdocJSON = JPrintUnformatted (errdoc );
453
465
JDelete (errdoc );
@@ -463,25 +475,31 @@ char * NoteRequestResponseJSON(const char *reqJSON)
463
475
}
464
476
}
465
477
}
466
- if (NULL == newlinePtr ) {
467
- _Free ((void * )reqJSON );
478
+ if (allocatedJSON ) {
479
+ _Free ((void * )allocatedJSON );
480
+ allocatedJSON = NULL ;
468
481
}
469
482
break ;
470
483
} else {
471
484
// If it's a command, the Notecard will not respond, so we pass
472
485
// NULL for the response parameter.
473
486
const char * errstr = _Transaction (reqJSON , reqLen , NULL , transactionTimeoutMs );
474
- reqJSON = (endPtr + 1 );
487
+ reqJSON = (endPtr + 1 ); // Move to the next command in the pipeline
475
488
if (errstr != NULL ) {
476
489
NOTE_C_LOG_ERROR (errstr );
477
490
}
478
491
}
479
492
480
493
// Clean up if we allocated a new string
481
- if (NULL == newlinePtr ) {
482
- _Free ((void * )reqJSON );
494
+ (void )isCmdPipeline ;
495
+ if (allocatedJSON ) {
496
+ _Free ((void * )allocatedJSON );
497
+ break ;
483
498
}
484
- }
499
+ if (!isCmdPipeline ) {
500
+ break ;
501
+ }
502
+ } // for(;;)
485
503
486
504
_UnlockNote ();
487
505
_TransactionStop ();
@@ -567,7 +585,7 @@ J *_noteTransactionShouldLock(J *req, bool lockNotecard)
567
585
NOTE_C_LOG_ERROR (errStr );
568
586
return NULL ;
569
587
}
570
- return errDoc (id , errStr );
588
+ return _errDoc (id , errStr );
571
589
}
572
590
573
591
// Inject the user agent object only when we're doing a `hub.set` and
@@ -596,7 +614,7 @@ J *_noteTransactionShouldLock(J *req, bool lockNotecard)
596
614
NOTE_C_LOG_ERROR (errStr );
597
615
return NULL ;
598
616
}
599
- return errDoc (id , errStr );
617
+ return _errDoc (id , errStr );
600
618
}
601
619
}
602
620
@@ -788,7 +806,7 @@ J *_noteTransactionShouldLock(J *req, bool lockNotecard)
788
806
rsp = NULL ;
789
807
}
790
808
NoteResetRequired (); // queue up a reset
791
- J * errRsp = errDoc (id , errStr );
809
+ J * errRsp = _errDoc (id , errStr );
792
810
if (lockNotecard ) {
793
811
_UnlockNote ();
794
812
}
0 commit comments