Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
user.c File Reference
#include "user.h"
#include <curl/curl.h>
#include <jansson.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Data Structures

struct  Buffer
 Buffer structure to hold incoming HTTP response data. More...
 

Functions

void buffer_init (Buffer *buf)
 Initialize a Buffer structure.
 
void buffer_cleanup (Buffer *buf)
 Free the memory held by a Buffer.
 
int buffer_ensure_capacity (Buffer *buf, size_t required_size)
 Ensure that a Buffer has enough capacity for new data.
 
static size_t write_callback (const void *contents, size_t size, size_t nmemb, void *userp)
 Callback for libcurl to write response data into a Buffer.
 
User fetch_github_user (const char *username)
 Fetch a GitHub user's information via the GitHub API.
 
void print_github_user (const User *user)
 Print a User's information to the console.
 

Function Documentation

◆ buffer_cleanup()

void buffer_cleanup ( Buffer * buf)

Free the memory held by a Buffer.

Parameters
bufPointer to Buffer to clean up.

Definition at line 36 of file user.c.

36 {
37 if (buf && buf->data) {
38 free(buf->data);
39 buf->data = NULL;
40 buf->size = 0;
41 buf->capacity = 0;
42 }
43}
#define free
Definition civetweb.c:1542
#define NULL
Definition gmacros.h:924
size_t size
Definition user.c:13
size_t capacity
Definition user.c:14
char * data
Definition user.c:12

References Buffer::capacity, Buffer::data, free, NULL, and Buffer::size.

Referenced by fetch_github_user().

◆ buffer_ensure_capacity()

int buffer_ensure_capacity ( Buffer * buf,
size_t required_size )

Ensure that a Buffer has enough capacity for new data.

Parameters
bufPointer to Buffer.
required_sizeSize needed.
Returns
1 if successful, 0 on failure.

Definition at line 52 of file user.c.

52 {
53 if (buf->capacity >= required_size) {
54 return 1; // Enough space
55 }
56
57 // Double the capacity to ensure enough room
58 size_t new_capacity = buf->capacity * 2;
59 while (new_capacity < required_size) {
60 new_capacity *= 2;
61
62 // Protect against integer overflow
63 if (new_capacity < buf->capacity) {
64 (void)fprintf(stderr, "Buffer capacity overflow\n");
65 return 0;
66 }
67 }
68
69 char *new_data = realloc(buf->data, new_capacity);
70 if (!new_data) {
71 (void)fprintf(stderr, "Memory allocation failed for buffer\n");
72 return 0;
73 }
74
75 buf->data = new_data;
76 buf->capacity = new_capacity;
77 return 1;
78}
#define realloc
Definition civetweb.c:1541

References Buffer::capacity, Buffer::data, and realloc.

Referenced by write_callback().

◆ buffer_init()

void buffer_init ( Buffer * buf)

Initialize a Buffer structure.

Parameters
bufPointer to Buffer to initialize.

Definition at line 22 of file user.c.

22 {
23 buf->data = malloc(1024); // Initial allocation
24 buf->size = 0;
25 buf->capacity = 1024;
26 if (!buf->data) {
27 (void)fprintf(stderr, "Memory allocation failed\n");
28 }
29}
#define malloc
Definition civetweb.c:1539

References Buffer::capacity, Buffer::data, malloc, and Buffer::size.

Referenced by fetch_github_user().

◆ fetch_github_user()

User fetch_github_user ( const char * username)

Fetch a GitHub user's information via the GitHub API.

Fetch GitHub user information for a given username.

Parameters
usernameGitHub username.
Returns
User structure containing fetched information.

The returned User must be freed using user_free().

Definition at line 130 of file user.c.

130 {
131 User user = {0};
132 Buffer buffer = {0};
133
134 // Check username for NULL or empty
135 if (!username || *username == '\0') {
136 (void)fprintf(stderr, "Invalid username\n");
137 return user;
138 }
139
140 buffer_init(&buffer); // Initialize buffer after username check to avoid leaks
141
142 // Dynamically allocate URL buffer with enough space for the URL
143 size_t username_len = strnlen(username, 100); // Limit username length
144 size_t url_size =
145 username_len + 50; // Account for the API URL length and username
146
147 char *url = malloc(url_size);
148 if (!url) {
149 (void)fprintf(stderr, "Memory allocation failed for URL\n");
150 buffer_cleanup(&buffer);
151 return user;
152 }
153
154 int ret =
155 snprintf(url, url_size, "https://api.github.com/users/%s", username);
156 if (ret < 0 || (size_t)ret >= url_size) {
157 (void)fprintf(stderr, "Error: URL was truncated or snprintf failed\n");
158 free(url);
159 buffer_cleanup(&buffer);
160 return user;
161 }
162
163 CURL *curl = curl_easy_init();
164 if (!curl) {
165 (void)fprintf(stderr, "curl init failed\n");
166 free(url);
167 buffer_cleanup(&buffer);
168 return user;
169 }
170
171 curl_easy_setopt(curl, CURLOPT_URL, url);
172 curl_easy_setopt(curl, CURLOPT_USERAGENT, "github_user_fetcher/1.0");
173 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
174 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
175
176 CURLcode res = curl_easy_perform(curl);
177 curl_easy_cleanup(curl);
178
179 free(url); // Free dynamically allocated URL buffer
180
181 if (res != CURLE_OK) {
182 (void)fprintf(stderr, "CURL error: %s\n", curl_easy_strerror(res));
183 buffer_cleanup(&buffer);
184 return user;
185 }
186
188 json_t *root = json_loads(buffer.data, 0, &error);
189
190 // Save buffer data before cleanup
191 char *buffer_data = buffer.data;
192
193 if (!root) {
194 (void)fprintf(stderr, "JSON parse error: %s\n", error.text);
195 free(buffer_data);
196 return user;
197 }
198
199 free(buffer_data); // Free buffer data after successful JSON parsing
200
201 json_t *login = json_object_get(root, "login");
202 json_t *name = json_object_get(root, "name");
203 json_t *company = json_object_get(root, "company");
204 json_t *location = json_object_get(root, "location");
205
206 // Dynamically allocate memory for the user fields
207 if (json_is_string(login)) {
208 user.login = strdup(
209 json_string_value(login)); // Using strdup for dynamic memory allocation
210 }
211 if (json_is_string(name)) {
212 user.name = strdup(json_string_value(name));
213 }
214 if (json_is_string(company)) {
215 user.company = strdup(json_string_value(company));
216 }
217 if (json_is_string(location)) {
218 user.location = strdup(json_string_value(location));
219 }
220
221 json_decref(root);
222 return user;
223}
#define snprintf
Definition civetweb.c:1543
void CURL
Definition curl.h:117
CURLcode
Definition curl.h:509
@ CURLE_OK
Definition curl.h:510
CURL_EXTERN const char * curl_easy_strerror(CURLcode)
CURL_EXTERN void curl_easy_cleanup(CURL *curl)
CURL_EXTERN CURLcode curl_easy_perform(CURL *curl)
CURL_EXTERN CURL * curl_easy_init(void)
#define json_is_string(json)
Definition jansson.h:83
const char * json_string_value(const json_t *string)
json_t * json_object_get(const json_t *object, const char *key) JANSSON_ATTRS((warn_unused_result))
json_t * json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result))
static JSON_INLINE void json_decref(json_t *json)
Definition jansson.h:131
const char * name
Definition lsqlite3.c:2154
static void error(LoadState *S, const char *why)
Buffer structure to hold incoming HTTP response data.
Definition user.c:11
Structure representing a GitHub user.
Definition user.h:9
const char * name
Full name.
Definition user.h:11
const char * login
GitHub username.
Definition user.h:10
const char * location
User's location.
Definition user.h:13
const char * company
Company name.
Definition user.h:12
#define curl_easy_setopt(handle, option, value)
void buffer_init(Buffer *buf)
Initialize a Buffer structure.
Definition user.c:22
void buffer_cleanup(Buffer *buf)
Free the memory held by a Buffer.
Definition user.c:36
static size_t write_callback(const void *contents, size_t size, size_t nmemb, void *userp)
Callback for libcurl to write response data into a Buffer.
Definition user.c:89

References buffer_cleanup(), buffer_init(), User::company, curl_easy_cleanup(), curl_easy_init(), curl_easy_perform(), curl_easy_setopt, curl_easy_strerror(), CURLE_OK, Buffer::data, error(), free, json_decref(), json_is_string, json_loads(), json_object_get(), json_string_value(), User::location, User::login, malloc, User::name, name, snprintf, and write_callback().

Referenced by main(), Test(), and user_handler().

◆ print_github_user()

void print_github_user ( const User * user)

Print a User's information to the console.

Print GitHub user information to standard output.

Parameters
userPointer to the User structure.

Definition at line 230 of file user.c.

230 {
231 if (!user) {
232 (void)fprintf(stderr, "NULL user pointer\n");
233 return;
234 }
235
236 printf("GitHub User:\n");
237 printf(" Login: %s\n", user->login ? user->login : "N/A");
238 printf(" Name: %s\n", user->name ? user->name : "N/A");
239 printf(" Company: %s\n", user->company ? user->company : "N/A");
240 printf(" Location: %s\n", user->location ? user->location : "N/A");
241}
#define printf

References User::company, User::location, User::login, User::name, and printf.

Referenced by BM_PrintUser(), and main().

◆ write_callback()

static size_t write_callback ( const void * contents,
size_t size,
size_t nmemb,
void * userp )
static

Callback for libcurl to write response data into a Buffer.

Parameters
contentsPointer to incoming data.
sizeSize of a single item.
nmembNumber of items.
userpPointer to Buffer structure.
Returns
Number of bytes handled.

Definition at line 89 of file user.c.

90 {
91 size_t total_size = size * nmemb;
92 Buffer *buf = (Buffer *)userp;
93
94 // Check for size_t overflow
95 if (total_size / size != nmemb) {
96 (void)fprintf(stderr, "Integer overflow in size calculation\n");
97 return 0;
98 }
99
100 // Check for overflow when adding to buffer size
101 if (total_size > SIZE_MAX - buf->size - 1) {
102 (void)fprintf(stderr, "Buffer size would overflow\n");
103 return 0;
104 }
105
106 // Ensure there's enough space for the new data
107 if (!buffer_ensure_capacity(buf, buf->size + total_size + 1)) {
108 return 0;
109 }
110
111 // Now we can safely copy the data
112 if (total_size > 0) {
113 memmove(buf->data + buf->size, contents,
114 total_size); // Using memmove instead of memcpy
115 }
116 buf->size += total_size;
117 buf->data[buf->size] = '\0'; // Null-terminate
118
119 return total_size;
120}
int buffer_ensure_capacity(Buffer *buf, size_t required_size)
Ensure that a Buffer has enough capacity for new data.
Definition user.c:52

References buffer_ensure_capacity(), Buffer::data, Buffer::size, and SIZE_MAX.

Referenced by fetch_github_user().