TianoCore EDK2 master
Loading...
Searching...
No Matches
payload.c
Go to the documentation of this file.
1
18#include <redfishPayload.h>
19
20static redfishPayload *
21getOpResult (
22 redfishPayload *payload,
23 const char *propName,
24 const char *op,
25 const char *value,
26 EFI_HTTP_STATUS_CODE **StatusCode
27 );
28
29static redfishPayload *
30collectionEvalOp (
31 redfishPayload *payload,
32 const char *propName,
33 const char *op,
34 const char *value,
35 EFI_HTTP_STATUS_CODE **StatusCode
36 );
37
38static redfishPayload *
39arrayEvalOp (
40 redfishPayload *payload,
41 const char *propName,
42 const char *op,
43 const char *value,
44 EFI_HTTP_STATUS_CODE **StatusCode
45 );
46
47static redfishPayload *
48createCollection (
49 redfishService *service,
50 size_t count,
51 redfishPayload **payloads
52 );
53
54static json_t *
55json_object_get_by_index (
56 json_t *json,
57 size_t index
58 );
59
60bool
61isPayloadCollection (
62 redfishPayload *payload
63 )
64{
65 json_t *members;
66 json_t *count;
67
68 if (!payload || !json_is_object (payload->json)) {
69 return false;
70 }
71
72 members = json_object_get (payload->json, "Members");
73 count = json_object_get (payload->json, "Members@odata.count");
74 return ((members != NULL) && (count != NULL));
75}
76
77size_t
78getCollectionSize (
79 redfishPayload *payload
80 )
81{
82 json_t *members;
83 json_t *count;
84
85 if (!payload || !json_is_object (payload->json)) {
86 return 0;
87 }
88
89 members = json_object_get (payload->json, "Members");
90 count = json_object_get (payload->json, "Members@odata.count");
91 if (!members || !count) {
92 return 0;
93 }
94
95 return (size_t)json_integer_value (count);
96}
97
98bool
99isPayloadArray (
100 redfishPayload *payload
101 )
102{
103 if (!payload || !json_is_array (payload->json)) {
104 return false;
105 }
106
107 return true;
108}
109
110char *
111payloadToString (
112 redfishPayload *payload,
113 bool prettyPrint
114 )
115{
116 size_t flags = 0;
117
118 if (!payload) {
119 return NULL;
120 }
121
122 if (prettyPrint) {
123 flags = JSON_INDENT (2);
124 }
125
126 return json_dumps (payload->json, flags);
127}
128
130createRedfishPayload (
131 json_t *value,
132 redfishService *service
133 )
134{
135 redfishPayload *payload;
136
137 payload = (redfishPayload *)malloc (sizeof (redfishPayload));
138 if (payload != NULL) {
139 payload->json = value;
140 payload->service = service;
141 }
142
143 return payload;
144}
145
147getPayloadByNodeName (
148 redfishPayload *payload,
149 const char *nodeName,
150 EFI_HTTP_STATUS_CODE **StatusCode
151 )
152{
153 json_t *value;
154 json_t *odataId;
155 const char *uri;
156
157 if (!payload || !nodeName || (StatusCode == NULL)) {
158 return NULL;
159 }
160
161 *StatusCode = NULL;
162
163 value = json_object_get (payload->json, nodeName);
164 if (value == NULL) {
165 return NULL;
166 }
167
168 json_incref (value);
169 if (json_object_size (value) == 1) {
170 odataId = json_object_get (value, "@odata.id");
171 if (odataId != NULL) {
172 json_incref (odataId);
173 uri = json_string_value (odataId);
174 json_decref (value);
175 value = getUriFromService (payload->service, uri, StatusCode);
176 json_decref (odataId);
177 if ((value == NULL) || (*StatusCode == NULL)) {
178 return NULL;
179 }
180 }
181 }
182
183 if ((*StatusCode == NULL) || ((**StatusCode >= HTTP_STATUS_200_OK) && (**StatusCode <= HTTP_STATUS_206_PARTIAL_CONTENT))) {
184 if (json_is_string (value)) {
185 odataId = json_object ();
186 json_object_set (odataId, nodeName, value);
187 json_decref (value);
188 value = odataId;
189 }
190 }
191
192 return createRedfishPayload (value, payload->service);
193}
194
196getPayloadByIndex (
197 redfishPayload *payload,
198 size_t index,
199 EFI_HTTP_STATUS_CODE **StatusCode
200 )
201{
202 json_t *value = NULL;
203 json_t *odataId;
204 const char *uri;
205 BOOLEAN FromServerFlag = FALSE;
206
207 if (!payload || (StatusCode == NULL)) {
208 return NULL;
209 }
210
211 *StatusCode = NULL;
212
213 if (isPayloadCollection (payload)) {
214 redfishPayload *members = getPayloadByNodeName (payload, "Members", StatusCode);
215 if (((*StatusCode == NULL) && (members == NULL)) ||
216 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
217 {
218 return members;
219 }
220
221 if (*StatusCode != NULL) {
222 //
223 // The Payload (members) are retrived from server.
224 //
225 FreePool (*StatusCode);
226 *StatusCode = NULL;
227 FromServerFlag = TRUE;
228 }
229
230 redfishPayload *ret = getPayloadByIndex (members, index, StatusCode);
231 if ((*StatusCode == NULL) && (ret != NULL) && FromServerFlag) {
232 //
233 // In such a case, the Redfish resource is parsed from the input payload (members) directly.
234 // Since the members are retrived from server, we still return HTTP_STATUS_200_OK.
235 //
236 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
237 if (*StatusCode == NULL) {
238 ret = NULL;
239 } else {
240 **StatusCode = HTTP_STATUS_200_OK;
241 }
242 }
243
244 cleanupPayload (members);
245 return ret;
246 }
247
248 if (json_is_array (payload->json)) {
249 //
250 // The valid range for index is from 0 to the return value of json_array_size() minus 1
251 //
252 value = json_array_get (payload->json, index);
253 } else if (json_is_object (payload->json)) {
254 value = json_object_get_by_index (payload->json, index);
255 }
256
257 if (value == NULL) {
258 return NULL;
259 }
260
261 json_incref (value);
262 if (json_object_size (value) == 1) {
263 odataId = json_object_get (value, "@odata.id");
264 if (odataId != NULL) {
265 uri = json_string_value (odataId);
266 json_decref (value);
267 value = getUriFromService (payload->service, uri, StatusCode);
268 if (value == NULL) {
269 return NULL;
270 }
271 }
272 }
273
274 return createRedfishPayload (value, payload->service);
275}
276
278getPayloadForPath (
279 redfishPayload *payload,
280 redPathNode *redpath,
281 EFI_HTTP_STATUS_CODE **StatusCode
282 )
283{
284 redfishPayload *ret = NULL;
285 redfishPayload *tmp;
286
287 if (!payload || !redpath || (StatusCode == NULL)) {
288 return NULL;
289 }
290
291 *StatusCode = NULL;
292 BOOLEAN FromServerFlag = FALSE;
293
294 if (redpath->nodeName) {
295 ret = getPayloadByNodeName (payload, redpath->nodeName, StatusCode);
296 if (((*StatusCode == NULL) && (ret == NULL)) ||
297 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
298 {
299 //
300 // Any error happen, return directly.
301 //
302 return ret;
303 }
304 } else if (redpath->isIndex) {
305 ASSERT (redpath->index >= 1);
306 ret = getPayloadByIndex (payload, redpath->index - 1, StatusCode);
307 if (((*StatusCode == NULL) && (ret == NULL)) ||
308 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
309 {
310 //
311 // Any error happen, return directly.
312 //
313 return ret;
314 }
315 } else if (redpath->op) {
316 ret = getOpResult (payload, redpath->propName, redpath->op, redpath->value, StatusCode);
317 if (((*StatusCode == NULL) && (ret == NULL)) ||
318 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
319 {
320 //
321 // Any error happen, return directly.
322 //
323 return ret;
324 }
325 } else {
326 return NULL;
327 }
328
329 if ((redpath->next == NULL) || (ret == NULL)) {
330 return ret;
331 } else {
332 if (*StatusCode != NULL) {
333 FreePool (*StatusCode);
334 *StatusCode = NULL;
335 FromServerFlag = TRUE;
336 }
337
338 tmp = getPayloadForPath (ret, redpath->next, StatusCode);
339 if ((*StatusCode == NULL) && (tmp != NULL) && FromServerFlag) {
340 //
341 // In such a case, the Redfish resource is parsed from the input payload (ret) directly.
342 // Since the ret are retrived from server, we still return HTTP_STATUS_200_OK.
343 //
344 *StatusCode = AllocateZeroPool (sizeof (EFI_HTTP_STATUS_CODE));
345 if (*StatusCode == NULL) {
346 tmp = NULL;
347 } else {
348 **StatusCode = HTTP_STATUS_200_OK;
349 }
350 }
351
352 cleanupPayload (ret);
353 return tmp;
354 }
355}
356
358getPayloadForPathString (
359 redfishPayload *payload,
360 const char *string,
361 EFI_HTTP_STATUS_CODE **StatusCode
362 )
363{
364 redPathNode *redpath;
365 redfishPayload *ret;
366
367 if (!string || (StatusCode == NULL)) {
368 return NULL;
369 }
370
371 *StatusCode = NULL;
372
373 redpath = parseRedPath (string);
374 if (redpath == NULL) {
375 return NULL;
376 }
377
378 ret = getPayloadForPath (payload, redpath, StatusCode);
379 cleanupRedPath (redpath);
380 return ret;
381}
382
384patchPayload (
385 redfishPayload *target,
386 redfishPayload *payload,
387 EFI_HTTP_STATUS_CODE **StatusCode
388 )
389{
390 json_t *json;
391 char *content;
392 char *uri;
393
394 if (!target || !payload || (StatusCode == NULL)) {
395 return NULL;
396 }
397
398 *StatusCode = NULL;
399
400 json = json_object_get (target->json, "@odata.id");
401 if (json == NULL) {
402 return NULL;
403 }
404
405 uri = strdup (json_string_value (json));
406
407 content = json_dumps (payload->json, 0);
408 json_decref (json);
409
410 json = patchUriFromService (target->service, uri, content, StatusCode);
411 free (uri);
412 free (content);
413 if (json == NULL) {
414 return NULL;
415 }
416
417 return createRedfishPayload (json, target->service);
418}
419
421postContentToPayload (
422 redfishPayload *target,
423 const char *data,
424 size_t dataSize,
425 const char *contentType,
426 EFI_HTTP_STATUS_CODE **StatusCode
427 )
428{
429 json_t *json;
430 char *uri;
431
432 if (!target || !data || (StatusCode == NULL)) {
433 return NULL;
434 }
435
436 *StatusCode = NULL;
437
438 json = json_object_get (target->json, "@odata.id");
439 if (json == NULL) {
440 json = json_object_get (target->json, "target");
441 if (json == NULL) {
442 return NULL;
443 }
444 }
445
446 uri = strdup (json_string_value (json));
447 json = postUriFromService (target->service, uri, data, dataSize, contentType, StatusCode);
448 free (uri);
449 if (json == NULL) {
450 return NULL;
451 }
452
453 return createRedfishPayload (json, target->service);
454}
455
457postPayload (
458 redfishPayload *target,
459 redfishPayload *payload,
460 EFI_HTTP_STATUS_CODE **StatusCode
461 )
462{
463 char *content;
464 redfishPayload *ret;
465
466 if (!target || !payload || (StatusCode == NULL)) {
467 return NULL;
468 }
469
470 *StatusCode = NULL;
471
472 if (!json_is_object (payload->json)) {
473 return NULL;
474 }
475
476 content = payloadToString (payload, false);
477 ret = postContentToPayload (target, content, strlen (content), NULL, StatusCode);
478 free (content);
479 return ret;
480}
481
482void
483cleanupPayload (
484 redfishPayload *payload
485 )
486{
487 if (!payload) {
488 return;
489 }
490
491 json_decref (payload->json);
492 // Don't free payload->service, let the caller handle cleaning up the service
493 free (payload);
494}
495
496static redfishPayload *
497getOpResult (
498 redfishPayload *payload,
499 const char *propName,
500 const char *op,
501 const char *value,
502 EFI_HTTP_STATUS_CODE **StatusCode
503 )
504{
505 const char *propStr;
506 json_t *stringProp;
507 bool ret = false;
508 redfishPayload *prop;
509 long long intVal, intPropVal;
510 json_type jsonType;
511
512 if (isPayloadCollection (payload)) {
513 return collectionEvalOp (payload, propName, op, value, StatusCode);
514 }
515
516 if (isPayloadArray (payload)) {
517 return arrayEvalOp (payload, propName, op, value, StatusCode);
518 }
519
520 prop = getPayloadByNodeName (payload, propName, StatusCode);
521 if (((*StatusCode == NULL) && (prop == NULL)) ||
522 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
523 {
524 return prop;
525 }
526
527 stringProp = prop->json;
528 jsonType = JsonGetType (prop->json);
529 switch (jsonType) {
530 case JSON_OBJECT:
531 stringProp = json_object_get (prop->json, propName);
532 case JSON_STRING:
533 if (strcmp (op, "=") == 0) {
534 propStr = json_string_value (stringProp);
535 if (propStr == NULL) {
536 cleanupPayload (prop);
537 return NULL;
538 }
539
540 ret = (strcmp (propStr, value) == 0);
541 } else if (strcmp (op, "~") == 0) {
542 propStr = json_string_value (stringProp);
543 if (propStr == NULL) {
544 cleanupPayload (prop);
545 return NULL;
546 }
547
548 ret = (strcasecmp (propStr, value) == 0);
549 }
550
551 break;
552 case JSON_TRUE:
553 if (strcmp (op, "=") == 0) {
554 ret = (strcmp (value, "true") == 0);
555 }
556
557 break;
558 case JSON_FALSE:
559 if (strcmp (op, "=") == 0) {
560 ret = (strcmp (value, "false") == 0);
561 }
562
563 break;
564 case JSON_INTEGER:
565 intPropVal = json_integer_value (prop->json);
566 intVal = strtoll (value, NULL, 0);
567 if (strcmp (op, "=") == 0) {
568 ret = (intPropVal == intVal);
569 } else if (strcmp (op, "<") == 0) {
570 ret = (intPropVal < intVal);
571 } else if (strcmp (op, ">") == 0) {
572 ret = (intPropVal > intVal);
573 } else if (strcmp (op, "<=") == 0) {
574 ret = (intPropVal <= intVal);
575 } else if (strcmp (op, ">=") == 0) {
576 ret = (intPropVal >= intVal);
577 }
578
579 break;
580 default:
581 break;
582 }
583
584 cleanupPayload (prop);
585 if (ret) {
586 return payload;
587 } else {
588 return NULL;
589 }
590}
591
592static redfishPayload *
593collectionEvalOp (
594 redfishPayload *payload,
595 const char *propName,
596 const char *op,
597 const char *value,
598 EFI_HTTP_STATUS_CODE **StatusCode
599 )
600{
601 redfishPayload *ret;
602 redfishPayload *tmp;
603 redfishPayload *members;
604 redfishPayload **valid;
605 size_t validMax;
606 size_t validCount = 0;
607 size_t i;
608
609 validMax = getCollectionSize (payload);
610 if (validMax == 0) {
611 return NULL;
612 }
613
614 valid = (redfishPayload **)calloc (validMax, sizeof (redfishPayload *));
615 if (valid == NULL) {
616 return NULL;
617 }
618
619 /*Technically getPayloadByIndex would do this, but this optimizes things*/
620 members = getPayloadByNodeName (payload, "Members", StatusCode);
621 if (((*StatusCode == NULL) && (members == NULL)) ||
622 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
623 {
624 free (valid);
625 return members;
626 }
627
628 for (i = 0; i < validMax; i++) {
629 if (*StatusCode != NULL) {
630 FreePool (*StatusCode);
631 *StatusCode = NULL;
632 }
633
634 tmp = getPayloadByIndex (members, i, StatusCode);
635 if (((*StatusCode == NULL) && (tmp == NULL)) ||
636 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
637 {
638 free (valid);
639 return tmp;
640 }
641
642 if (*StatusCode != NULL) {
643 FreePool (*StatusCode);
644 *StatusCode = NULL;
645 }
646
647 valid[validCount] = getOpResult (tmp, propName, op, value, StatusCode);
648
649 /*
650 if ((*StatusCode == NULL && valid[validCount] == NULL) ||
651 (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {
652 return valid[validCount];
653 }
654 */
655 if (valid[validCount] != NULL) {
656 validCount++;
657 } else {
658 cleanupPayload (tmp);
659 }
660 }
661
662 cleanupPayload (members);
663 if (validCount == 0) {
664 ret = NULL;
665 } else if (validCount == 1) {
666 ret = valid[0];
667 } else {
668 ret = createCollection (payload->service, validCount, valid);
669 }
670
671 free (valid);
672 return ret;
673}
674
675static redfishPayload *
676arrayEvalOp (
677 redfishPayload *payload,
678 const char *propName,
679 const char *op,
680 const char *value,
681 EFI_HTTP_STATUS_CODE **StatusCode
682 )
683{
684 redfishPayload *ret;
685 redfishPayload *tmp;
686 redfishPayload **valid;
687 size_t validMax;
688 size_t validCount = 0;
689 size_t i;
690
691 validMax = json_array_size (payload->json);
692 if (validMax == 0) {
693 return NULL;
694 }
695
696 valid = (redfishPayload **)calloc (validMax, sizeof (redfishPayload *));
697 if (valid == NULL) {
698 return NULL;
699 }
700
701 for (i = 0; i < validMax; i++) {
702 if (*StatusCode != NULL) {
703 FreePool (*StatusCode);
704 *StatusCode = NULL;
705 }
706
707 tmp = getPayloadByIndex (payload, i, StatusCode);
708 if (((*StatusCode == NULL) && (tmp == NULL)) ||
709 ((*StatusCode != NULL) && ((**StatusCode < HTTP_STATUS_200_OK) || (**StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))))
710 {
711 return tmp;
712 }
713
714 if (*StatusCode != NULL) {
715 FreePool (*StatusCode);
716 *StatusCode = NULL;
717 }
718
719 valid[validCount] = getOpResult (tmp, propName, op, value, StatusCode);
720
721 /*
722 if ((*StatusCode == NULL && valid[validCount] == NULL) ||
723 (*StatusCode != NULL && (**StatusCode < HTTP_STATUS_200_OK || **StatusCode > HTTP_STATUS_206_PARTIAL_CONTENT))) {
724 return valid[validCount];
725 }
726 */
727
728 if (valid[validCount] != NULL) {
729 validCount++;
730 } else {
731 cleanupPayload (tmp);
732 }
733 }
734
735 if (validCount == 0) {
736 free (valid);
737 return NULL;
738 }
739
740 if (validCount == 1) {
741 ret = valid[0];
742 free (valid);
743 return ret;
744 } else {
745 ret = createCollection (payload->service, validCount, valid);
746 free (valid);
747 return ret;
748 }
749}
750
751static redfishPayload *
752createCollection (
753 redfishService *service,
754 size_t count,
755 redfishPayload **payloads
756 )
757{
758 redfishPayload *ret;
759 json_t *collectionJson = json_object ();
760 json_t *jcount = json_integer ((json_int_t)count);
761 json_t *members = json_array ();
762 size_t i;
763
764 if (!collectionJson) {
765 return NULL;
766 }
767
768 if (!members) {
769 json_decref (collectionJson);
770 return NULL;
771 }
772
773 json_object_set (collectionJson, "Members@odata.count", jcount);
774 json_decref (jcount);
775 for (i = 0; i < count; i++) {
776 json_array_append (members, payloads[i]->json);
777 cleanupPayload (payloads[i]);
778 }
779
780 json_object_set (collectionJson, "Members", members);
781 json_decref (members);
782
783 ret = createRedfishPayload (collectionJson, service);
784 return ret;
785}
786
787static json_t *
788json_object_get_by_index (
789 json_t *json,
790 size_t index
791 )
792{
793 void *iter;
794 size_t i;
795
796 iter = json_object_iter (json);
797 for (i = 0; i < index; i++) {
798 iter = json_object_iter_next (json, iter);
799 if (iter == NULL) {
800 break;
801 }
802 }
803
804 if (iter == NULL) {
805 return NULL;
806 }
807
808 return json_object_iter_value (iter);
809}
810
811/* vim: set tabstop=4 shiftwidth=4 expandtab: */
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EDKII_JSON_TYPE EFIAPI JsonGetType(IN EDKII_JSON_VALUE JsonValue)
Definition: JsonLib.c:1161
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
EFI_HTTP_STATUS_CODE
Definition: Http.h:59
char * strdup(const char *str)
long long strtoll(const char *nptr, char **endptr, int base)