Skip to content

Commit

Permalink
Fix a few issues with the C generator (part 3) (#20269)
Browse files Browse the repository at this point in the history
* [C] Clear the response code from previous api calls

Before making an api call, reset apiClient->response_code to zero. That
will protect us from checking stale values if the curl request fails.

* [C] Check that string arguments are not null

Check early on that the arguments are not null, to prevent crashes on
strdup() calls.

* [C] Don't attempt to fill in a type with error info

Check if the api call returned an error before attempting to parse the
reply as the expected type.

* [C] Handle binary and integer return types

* [C] Update test schemas with binary and integer return types

* Update samples
  • Loading branch information
eafer authored and jorgeferdz committed Dec 10, 2024
1 parent 60147f0 commit 3c7688b
Show file tree
Hide file tree
Showing 16 changed files with 955 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ end:
// {{{.}}}
//
{{/notes}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{#isArray}}{{{.}}}_t*{{/isArray}}{{#isMap}}{{{.}}}{{/isMap}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#returnProperty}}{{^isEnum}}{{{returnType}}}_t*{{/isEnum}}{{#isEnum}}{{projectName}}_{{{returnType}}}_{{returnEnumName}}_e{{/isEnum}}{{/returnProperty}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}{{#returnProperty}}{{#isString}}*{{/isString}}{{/returnProperty}}{{/returnSimpleType}}{{^returnSimpleType}}{{#isArray}}{{{.}}}_t*{{/isArray}}{{#isMap}}{{{.}}}{{/isMap}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#returnProperty}}{{^isEnum}}{{{returnType}}}_t*{{/isEnum}}{{#isEnum}}{{projectName}}_{{{returnType}}}_{{returnEnumName}}_e{{/isEnum}}{{/returnProperty}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}}, {{#isPrimitiveType}}{{#isNumber}}{{{dataType}}} {{/isNumber}}{{#isLong}}{{{dataType}}} {{/isLong}}{{#isInteger}}{{{dataType}}} *{{/isInteger}}{{#isDouble}}{{{dataType}}} {{/isDouble}}{{#isFloat}}{{{dataType}}} {{/isFloat}}{{#isBoolean}}{{dataType}} *{{/isBoolean}}{{#isEnum}}{{#isString}}{{projectName}}_{{operationId}}_{{baseName}}_e {{/isString}}{{/isEnum}}{{^isEnum}}{{#isString}}{{{dataType}}} *{{/isString}}{{/isEnum}}{{#isByteArray}}{{{dataType}}} *{{/isByteArray}}{{#isDate}}{{{dataType}}} {{/isDate}}{{#isDateTime}}{{{dataType}}} {{/isDateTime}}{{#isFile}}{{{dataType}}} {{/isFile}}{{#isFreeFormObject}}{{dataType}}_t *{{/isFreeFormObject}}{{/isPrimitiveType}}{{^isArray}}{{^isPrimitiveType}}{{#isModel}}{{#isEnum}}{{datatypeWithEnum}}_e {{/isEnum}}{{^isEnum}}{{{dataType}}}_t *{{/isEnum}}{{/isModel}}{{^isModel}}{{#isEnum}}{{datatypeWithEnum}}_e {{/isEnum}}{{/isModel}}{{#isUuid}}{{dataType}} *{{/isUuid}}{{#isEmail}}{{dataType}} {{/isEmail}}{{/isPrimitiveType}}{{/isArray}}{{#isContainer}}{{#isArray}}{{dataType}}_t *{{/isArray}}{{#isMap}}{{dataType}} {{/isMap}}{{/isContainer}}{{{paramName}}}{{/allParams}})
{
list_t *localVarQueryParameters = {{#hasQueryParams}}list_createList();{{/hasQueryParams}}{{^hasQueryParams}}NULL;{{/hasQueryParams}}
Expand All @@ -108,11 +108,21 @@ end:
list_t *localVarContentType = {{#hasConsumes}}list_createList();{{/hasConsumes}}{{^hasConsumes}}NULL;{{/hasConsumes}}
char *localVarBodyParameters = NULL;

// clear the error code from the previous api call
apiClient->response_code = 0;

// create the path
long sizeOfPath = strlen("{{{path}}}")+1;
char *localVarPath = malloc(sizeOfPath);
snprintf(localVarPath, sizeOfPath, "{{{path}}}");

{{#pathParams}}
{{#isString}}
if(!{{paramName}})
goto end;
{{/isString}}
{{/pathParams}}

{{#pathParams}}

// Path Params
Expand Down Expand Up @@ -363,51 +373,80 @@ end:
{{#returnType}}
{{#returnTypeIsPrimitive}}
{{#returnSimpleType}}
//primitive return type simple
{{returnType}}* elementToReturn = strdup(({{returnType}}*)apiClient->dataReceived);
{{#returnProperty}}
{{#isBinary}}
//primitive return type simple binary
{{returnType}} elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300)
elementToReturn = instantiate_binary_t(apiClient->dataReceived, apiClient->dataReceivedLen);

{{/isBinary}}
{{#isString}}
//primitive return type simple string
{{returnType}}* elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300)
elementToReturn = strdup(({{returnType}}*)apiClient->dataReceived);

{{/isString}}
{{#isInteger}}
//primitive return type simple integer
{{returnType}} elementToReturn = 0;
if(apiClient->response_code >= 200 && apiClient->response_code < 300)
elementToReturn = atoi(apiClient->dataReceived);

{{/isInteger}}
{{/returnProperty}}
{{/returnSimpleType}}
{{^returnSimpleType}}
//primitive return type not simple
cJSON *{{paramName}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
cJSON *{{{paramName}}}VarJSON;
list_t *elementToReturn = list_createList();
cJSON_ArrayForEach({{{paramName}}}VarJSON, {{paramName}}localVarJSON){
keyValuePair_t *keyPair = keyValuePair_create(strdup({{{paramName}}}VarJSON->string), {{{cJSONPrint}}}({{{paramName}}}VarJSON));
list_addElement(elementToReturn, keyPair);
list_t *elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300) {
cJSON *{{paramName}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
cJSON *{{{paramName}}}VarJSON;
elementToReturn = list_createList();
cJSON_ArrayForEach({{{paramName}}}VarJSON, {{paramName}}localVarJSON){
keyValuePair_t *keyPair = keyValuePair_create(strdup({{{paramName}}}VarJSON->string), {{{cJSONPrint}}}({{{paramName}}}VarJSON));
list_addElement(elementToReturn, keyPair);
}
cJSON_Delete({{paramName}}localVarJSON);
}
cJSON_Delete({{paramName}}localVarJSON);

{{/returnSimpleType}}
{{/returnTypeIsPrimitive}}
{{^returnTypeIsPrimitive}}
{{#returnContainer}}
cJSON *{{classname}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
if(!cJSON_IsArray({{classname}}localVarJSON)) {
return 0;//nonprimitive container
}
list_t *elementToReturn = list_createList();
cJSON *{{{paramName}}}VarJSON;
cJSON_ArrayForEach({{{paramName}}}VarJSON, {{classname}}localVarJSON)
{
if(!cJSON_IsObject({{{paramName}}}VarJSON))
list_t *elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300) {
cJSON *{{classname}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
if(!cJSON_IsArray({{classname}}localVarJSON)) {
return 0;//nonprimitive container
}
elementToReturn = list_createList();
cJSON *{{{paramName}}}VarJSON;
cJSON_ArrayForEach({{{paramName}}}VarJSON, {{classname}}localVarJSON)
{
// return 0;
if(!cJSON_IsObject({{{paramName}}}VarJSON))
{
// return 0;
}
char *localVarJSONToChar = {{{cJSONPrint}}}({{{paramName}}}VarJSON);
list_addElement(elementToReturn , localVarJSONToChar);
}
char *localVarJSONToChar = {{{cJSONPrint}}}({{{paramName}}}VarJSON);
list_addElement(elementToReturn , localVarJSONToChar);
}

cJSON_Delete( {{classname}}localVarJSON);
cJSON_Delete( {{{paramName}}}VarJSON);
cJSON_Delete( {{classname}}localVarJSON);
cJSON_Delete( {{{paramName}}}VarJSON);
}
{{/returnContainer}}
{{^returnContainer}}
//nonprimitive not container
cJSON *{{classname}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
{{#returnProperty}}{{^isEnum}}{{{returnBaseType}}}_t *{{/isEnum}}{{#isEnum}}{{projectName}}_{{{returnType}}}_{{returnEnumName}}_e {{/isEnum}}{{/returnProperty}}elementToReturn = {{{returnBaseType}}}_parseFromJSON({{classname}}localVarJSON);
cJSON_Delete({{classname}}localVarJSON);
if(elementToReturn == {{#returnProperty}}{{^isEnum}}NULL{{/isEnum}}{{#isEnum}}0{{/isEnum}}{{/returnProperty}}) {
// return 0;
{{#returnProperty}}{{^isEnum}}{{{returnBaseType}}}_t *{{/isEnum}}{{#isEnum}}{{projectName}}_{{{returnType}}}_{{returnEnumName}}_e {{/isEnum}}{{/returnProperty}}elementToReturn = {{#returnProperty}}{{^isEnum}}NULL{{/isEnum}}{{#isEnum}}0{{/isEnum}}{{/returnProperty}};
if(apiClient->response_code >= 200 && apiClient->response_code < 300) {
cJSON *{{classname}}localVarJSON = cJSON_Parse(apiClient->dataReceived);
elementToReturn = {{{returnBaseType}}}_parseFromJSON({{classname}}localVarJSON);
cJSON_Delete({{classname}}localVarJSON);
if(elementToReturn == {{#returnProperty}}{{^isEnum}}NULL{{/isEnum}}{{#isEnum}}0{{/isEnum}}{{/returnProperty}}) {
// return 0;
}
}

{{/returnContainer}}
Expand Down Expand Up @@ -550,7 +589,7 @@ end:
return elementToReturn;
end:
free(localVarPath);
return {{#returnProperty}}{{^isEnum}}NULL{{/isEnum}}{{#isEnum}}0{{/isEnum}}{{/returnProperty}};
return {{#returnProperty}}{{#isInteger}}0{{/isInteger}}{{^isInteger}}{{^isEnum}}NULL{{/isEnum}}{{#isEnum}}0{{/isEnum}}{{/isInteger}}{{/returnProperty}};
{{/returnType}}
{{^returnType}}
//No return type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ typedef enum { {{projectName}}_{{operationId}}_{{enumName}}_NULL = 0{{#enumVars
// {{{.}}}
//
{{/notes}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}*{{/returnSimpleType}}{{^returnSimpleType}}{{#isArray}}{{{.}}}_t*{{/isArray}}{{#isMap}}{{{.}}}{{/isMap}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#returnProperty}}{{^isEnum}}{{{returnType}}}_t*{{/isEnum}}{{#isEnum}}{{projectName}}_{{{returnType}}}_{{returnEnumName}}_e{{/isEnum}}{{/returnProperty}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{#returnType}}{{#returnTypeIsPrimitive}}{{#returnSimpleType}}{{{.}}}{{#returnProperty}}{{#isString}}*{{/isString}}{{/returnProperty}}{{/returnSimpleType}}{{^returnSimpleType}}{{#isArray}}{{{.}}}_t*{{/isArray}}{{#isMap}}{{{.}}}{{/isMap}}{{/returnSimpleType}}{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#returnProperty}}{{^isEnum}}{{{returnType}}}_t*{{/isEnum}}{{#isEnum}}{{projectName}}_{{{returnType}}}_{{returnEnumName}}_e{{/isEnum}}{{/returnProperty}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void{{/returnType}}
{{{classname}}}_{{{operationId}}}(apiClient_t *apiClient{{#allParams}}, {{#isPrimitiveType}}{{#isNumber}}{{{dataType}}} {{/isNumber}}{{#isLong}}{{{dataType}}} {{/isLong}}{{#isInteger}}{{{dataType}}} *{{/isInteger}}{{#isDouble}}{{{dataType}}} {{/isDouble}}{{#isFloat}}{{{dataType}}} {{/isFloat}}{{#isBoolean}}{{dataType}} *{{/isBoolean}}{{#isEnum}}{{#isString}}{{projectName}}_{{operationId}}_{{baseName}}_e {{/isString}}{{/isEnum}}{{^isEnum}}{{#isString}}{{{dataType}}} *{{/isString}}{{/isEnum}}{{#isByteArray}}{{{dataType}}} *{{/isByteArray}}{{#isDate}}{{{dataType}}} {{/isDate}}{{#isDateTime}}{{{dataType}}} {{/isDateTime}}{{#isFile}}{{{dataType}}} {{/isFile}}{{#isFreeFormObject}}{{dataType}}_t *{{/isFreeFormObject}}{{/isPrimitiveType}}{{^isArray}}{{^isPrimitiveType}}{{#isModel}}{{#isEnum}}{{datatypeWithEnum}}_e {{/isEnum}}{{^isEnum}}{{{dataType}}}_t *{{/isEnum}}{{/isModel}}{{^isModel}}{{#isEnum}}{{datatypeWithEnum}}_e {{/isEnum}}{{/isModel}}{{#isUuid}}{{dataType}} *{{/isUuid}}{{#isEmail}}{{dataType}} {{/isEmail}}{{/isPrimitiveType}}{{/isArray}}{{#isContainer}}{{#isArray}}{{dataType}}_t *{{/isArray}}{{#isMap}}{{dataType}} {{/isMap}}{{/isContainer}}{{{paramName}}}{{/allParams}});


Expand Down
26 changes: 26 additions & 0 deletions modules/openapi-generator/src/test/resources/2_0/c/petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,19 @@ paths:
- 'write:pets'
- 'read:pets'
/pet/picture:
get:
tags:
- pet
summary: Get a random picture of someone else's pet
description: ''
operationId: getPicture
parameters: []
responses:
'200':
description: successful operation
schema:
type: string
format: binary
post:
tags:
- pet
Expand Down Expand Up @@ -335,6 +348,19 @@ paths:
- petstore_auth:
- 'write:pets'
- 'read:pets'
/store/daysWithoutIncident:
get:
tags:
- pet
summary: Number of days since the last time a pet maimed someone at the store
description: ''
operationId: getDaysWithoutIncident
parameters: []
responses:
'200':
description: successful operation
schema:
type: integer
/store/inventory:
get:
tags:
Expand Down
55 changes: 38 additions & 17 deletions samples/client/others/c/bearerAuth/api/DefaultAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ DefaultAPI_privateGet(apiClient_t *apiClient)
list_t *localVarContentType = NULL;
char *localVarBodyParameters = NULL;

// clear the error code from the previous api call
apiClient->response_code = 0;

// create the path
long sizeOfPath = strlen("/private")+1;
char *localVarPath = malloc(sizeOfPath);
snprintf(localVarPath, sizeOfPath, "/private");




list_addElement(localVarHeaderType,"application/json"); //produces
apiClient_invoke(apiClient,
localVarPath,
Expand All @@ -49,11 +53,14 @@ DefaultAPI_privateGet(apiClient_t *apiClient)
// printf("%s\n","A JSON object with private information");
//}
//nonprimitive not container
cJSON *DefaultAPIlocalVarJSON = cJSON_Parse(apiClient->dataReceived);
object_t *elementToReturn = object_parseFromJSON(DefaultAPIlocalVarJSON);
cJSON_Delete(DefaultAPIlocalVarJSON);
if(elementToReturn == NULL) {
// return 0;
object_t *elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300) {
cJSON *DefaultAPIlocalVarJSON = cJSON_Parse(apiClient->dataReceived);
elementToReturn = object_parseFromJSON(DefaultAPIlocalVarJSON);
cJSON_Delete(DefaultAPIlocalVarJSON);
if(elementToReturn == NULL) {
// return 0;
}
}

//return type
Expand Down Expand Up @@ -89,13 +96,17 @@ DefaultAPI_publicGet(apiClient_t *apiClient)
list_t *localVarContentType = NULL;
char *localVarBodyParameters = NULL;

// clear the error code from the previous api call
apiClient->response_code = 0;

// create the path
long sizeOfPath = strlen("/public")+1;
char *localVarPath = malloc(sizeOfPath);
snprintf(localVarPath, sizeOfPath, "/public");




list_addElement(localVarHeaderType,"application/json"); //produces
apiClient_invoke(apiClient,
localVarPath,
Expand All @@ -112,11 +123,14 @@ DefaultAPI_publicGet(apiClient_t *apiClient)
// printf("%s\n","A JSON object with public information");
//}
//nonprimitive not container
cJSON *DefaultAPIlocalVarJSON = cJSON_Parse(apiClient->dataReceived);
object_t *elementToReturn = object_parseFromJSON(DefaultAPIlocalVarJSON);
cJSON_Delete(DefaultAPIlocalVarJSON);
if(elementToReturn == NULL) {
// return 0;
object_t *elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300) {
cJSON *DefaultAPIlocalVarJSON = cJSON_Parse(apiClient->dataReceived);
elementToReturn = object_parseFromJSON(DefaultAPIlocalVarJSON);
cJSON_Delete(DefaultAPIlocalVarJSON);
if(elementToReturn == NULL) {
// return 0;
}
}

//return type
Expand Down Expand Up @@ -152,13 +166,17 @@ DefaultAPI_usersGet(apiClient_t *apiClient)
list_t *localVarContentType = NULL;
char *localVarBodyParameters = NULL;

// clear the error code from the previous api call
apiClient->response_code = 0;

// create the path
long sizeOfPath = strlen("/users")+1;
char *localVarPath = malloc(sizeOfPath);
snprintf(localVarPath, sizeOfPath, "/users");




list_addElement(localVarHeaderType,"application/json"); //produces
apiClient_invoke(apiClient,
localVarPath,
Expand All @@ -175,14 +193,17 @@ DefaultAPI_usersGet(apiClient_t *apiClient)
// printf("%s\n","A JSON array of user names");
//}
//primitive return type not simple
cJSON *localVarJSON = cJSON_Parse(apiClient->dataReceived);
cJSON *VarJSON;
list_t *elementToReturn = list_createList();
cJSON_ArrayForEach(VarJSON, localVarJSON){
keyValuePair_t *keyPair = keyValuePair_create(strdup(VarJSON->string), cJSON_Print(VarJSON));
list_addElement(elementToReturn, keyPair);
list_t *elementToReturn = NULL;
if(apiClient->response_code >= 200 && apiClient->response_code < 300) {
cJSON *localVarJSON = cJSON_Parse(apiClient->dataReceived);
cJSON *VarJSON;
elementToReturn = list_createList();
cJSON_ArrayForEach(VarJSON, localVarJSON){
keyValuePair_t *keyPair = keyValuePair_create(strdup(VarJSON->string), cJSON_Print(VarJSON));
list_addElement(elementToReturn, keyPair);
}
cJSON_Delete(localVarJSON);
}
cJSON_Delete(localVarJSON);

if (apiClient->dataReceived) {
free(apiClient->dataReceived);
Expand Down
2 changes: 2 additions & 0 deletions samples/client/petstore/c-useJsonUnformatted/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ Category | Method | HTTP request | Description
*PetAPI* | [**PetAPI_deletePet**](docs/PetAPI.md#PetAPI_deletePet) | **DELETE** /pet/{petId} | Deletes a pet
*PetAPI* | [**PetAPI_findPetsByStatus**](docs/PetAPI.md#PetAPI_findPetsByStatus) | **GET** /pet/findByStatus | Finds Pets by status
*PetAPI* | [**PetAPI_findPetsByTags**](docs/PetAPI.md#PetAPI_findPetsByTags) | **GET** /pet/findByTags | Finds Pets by tags
*PetAPI* | [**PetAPI_getDaysWithoutIncident**](docs/PetAPI.md#PetAPI_getDaysWithoutIncident) | **GET** /store/daysWithoutIncident | Number of days since the last time a pet maimed someone at the store
*PetAPI* | [**PetAPI_getPetById**](docs/PetAPI.md#PetAPI_getPetById) | **GET** /pet/{petId} | Find pet by ID
*PetAPI* | [**PetAPI_getPicture**](docs/PetAPI.md#PetAPI_getPicture) | **GET** /pet/picture | Get a random picture of someone else's pet
*PetAPI* | [**PetAPI_isPetAvailable**](docs/PetAPI.md#PetAPI_isPetAvailable) | **POST** /pet/{petId}/isAvailable | Is this pet still available?
*PetAPI* | [**PetAPI_sharePicture**](docs/PetAPI.md#PetAPI_sharePicture) | **POST** /pet/picture | Send a picture of your happy pet
*PetAPI* | [**PetAPI_specialtyPet**](docs/PetAPI.md#PetAPI_specialtyPet) | **GET** /pet/specialty | Specialty of the shop
Expand Down
Loading

0 comments on commit 3c7688b

Please sign in to comment.