Data Stoor vir HTTP Bediener in C: Globale Sleutelwaarde Stoor met Hanteerders
Inleiding
In die vorige artikel het ons gekyk na hoe om HTTP liggame te hanteer. Hier implementeer ons ‘n basiese data stoor waar ons dinamies teks waardes teen teks sleutels kan stoor en stel dit dan bloot as HTTP koppelvlakke. Die oorspronklike artikel kan hier gelees word.
Stappe
Skep ./src/cache.h soos volg:
#ifndef CACHE_H
#define CACHE_H
#include <pthread.h>
typedef struct CacheEntry {
char *key;
char *value;
struct CacheEntry *next;
} CacheEntry;
typedef struct Cache {
CacheEntry **buckets;
int size;
pthread_mutex_t lock;
} Cache;
Cache* cache_create(int size);
void cache_set(Cache *cache, const char *key, const char *value);
// gee kopie terug, onthou om geheue te deallokeer met free
char* cache_get(Cache *cache, const char *key);
void cache_delete(Cache *cache, const char *key);
void cache_destroy(Cache *cache);
#endifSkep ./src/cache.c:
#include "cache.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
static unsigned long hash(const char *str) {
unsigned long hash = 5381;
int c;
while ((c = *str++)) hash = ((hash << 5) + hash) + c;
return hash;
}
Cache* cache_create(int size) {
Cache *cache = malloc(sizeof(Cache));
cache->size = size;
cache->buckets = calloc(size, sizeof(CacheEntry*));
pthread_mutex_init(&cache->lock, NULL);
return cache;
}
void cache_set(Cache *cache, const char *key, const char *value) {
pthread_mutex_lock(&cache->lock);
unsigned int idx = hash(key) % cache->size;
// soek sleutel op
CacheEntry *entry = cache->buckets[idx];
while (entry) {
if (strcmp(entry->key, key) == 0) {
free(entry->value);
entry->value = strdup(value);
pthread_mutex_unlock(&cache->lock);
return;
}
entry = entry->next;
}
// voeg nuwe item by
CacheEntry *new_entry = malloc(sizeof(CacheEntry));
new_entry->key = strdup(key);
new_entry->value = strdup(value);
new_entry->next = cache->buckets[idx];
cache->buckets[idx] = new_entry;
pthread_mutex_unlock(&cache->lock);
}
char* cache_get(Cache *cache, const char *key) {
pthread_mutex_lock(&cache->lock);
unsigned int idx = hash(key) % cache->size;
CacheEntry *entry = cache->buckets[idx];
while (entry) {
if (strcmp(entry->key, key) == 0) {
char *val = strdup(entry->value);
pthread_mutex_unlock(&cache->lock);
return val;
}
entry = entry->next;
}
pthread_mutex_unlock(&cache->lock);
return NULL;
}
void cache_destroy(Cache *cache) {
for (int i = 0; i < cache->size; i++) {
CacheEntry *entry = cache->buckets[i];
while (entry) {
CacheEntry *temp = entry;
entry = entry->next;
free(temp->key);
free(temp->value);
free(temp);
}
}
free(cache->buckets);
pthread_mutex_destroy(&cache->lock);
free(cache);
}Hier gebruik ons die DJB2 hutsfunksie. Ons gebruik ‘n muteks om te beskerm teen gelyktydige lees en skryf van en na die stoor.
Volgende pas on ./src/server.h se datastruktuur aan om ‘n verwysing na die sleutelwaarde stoor in te sluit:
#ifndef SERVER_H
#define SERVER_H
...
#include "cache.h" // nuwe insluting
...
typedef struct Server {
...
Cache *global_cache; // nuwe veld
} Server;
...
#endifVolgende pas ons die server_create implementasie in ./src/server.c aan:
...
#include "cache.h" // nuut ingesluit
Server* server_create() {
...
server->global_cache = cache_create(1024); // 1024 spasies
return server;
}
...
void server_cleanup(Server *server) {
if (server) {
server_stop(server);
...
if (server->global_cache) {
cache_destroy(server->global_cache);
}
free(server);
}
}
...Om die stoor funksionaliteit te toets kan ons die volgende hanteerder funksies definieer in ./src/routes.h:
char* handle_cache_set(int client_fd, HTTPRequest *req);
char* handle_cache_get(int client_fd, HTTPRequest *req);Hierdie funksies kan as volg implementeer word in ./src/routes.c:
...
#include "cache.h"
char* handle_cache_set(int client_fd, HTTPRequest *req) {
// moet POST wees
if (strcmp(req->method, "POST") != 0) {
return "{\"error\": \"invalid operation\"}";
}
char body_buffer[2048];
char *body = req_get_body(req, client_fd, body_buffer, sizeof(body_buffer));
// moet application/x-www-form-urlencoded wees
char content_type[128];
get_header_value(req->raw_header, "Content-Type", content_type, sizeof(content_type));
if (strstr(content_type, "application/x-www-form-urlencoded") == NULL) {
return "{\"error\": \"invalid mime-type\"}";
}
// kry k en v parameters in HTTP liggaam
char key[128], val[128];
if (get_query_param(body, "k", key, sizeof(key)) &&
get_query_param(body, "v", val, sizeof(val))
) {
cache_set(req->server->global_cache, key, val);
// bou JSON antwoord
char *key_encoded= json_escape(key);
char *val_encoded= json_escape(val);
char response_json[512];
snprintf(response_json, sizeof(response_json),
"{"
"\"status\":\"success\","
"\"key\":%s,"
"\"value\":%s"
"}",
key_encoded,
val_encoded
);
// bou HTTP antwoord
char response[512];
// boue HTTP antwoord
build_http_response(
response,
sizeof(response),
200, "OK",
"Content-Type", "application/json",
"Connection", "close",
NULL,
response_json
);
// stuur HTTP antwoord
send(client_fd, response, strlen(response), 0);
// maak geheue skoon
free(key_encoded);
free(val_encoded);
return NULL;
}
return "{\"error\": \"invalid form data\"}";
}
char* handle_cache_get(int client_fd, HTTPRequest *req) {
char key[128];
static char response_json[512];
// moet GET wees
if (strcmp(req->method, "GET") != 0) {
return "{\"error\": \"invalid operation\"}";
}
// kry die sleutel uit die URL parameters
if (!get_query_param(req->query, "k", key, sizeof(key))) {
return "{\"error\": \"Missing key parameter 'k'\"}";
}
// haal waarde uit die globale stoor (kopie)
char *val = cache_get(req->server->global_cache, key);
if (val == NULL) {
return "{\"error\": \"Key not found in cache\"}";
}
char *key_encoded=json_escape(key);
char *val_encoded=json_escape(val);
// bou die JSON antwoord
snprintf(response_json, sizeof(response_json),
"{\"key\": %s, \"value\": %s}",
key_encoded, val_encoded);
free(key_encoded);
free(val_encoded);
// deallokeer
free(val);
return response_json;
}Die implementasie volg die standaard HTTP operasie semantiek waar jy ‘n POST operasie gebruik as jy iets op die bediener skep en ‘n GET operasie gebruik as jy iets van die bediener af lees.
Registreer dan die HTTP roetes teenoor hierdie nuwe funksies in ./src/main.c soos volg:
route_add(app_server, "/cache/set", handle_cache_set);
route_add(app_server, "/cache/get", handle_cache_get);
Toets
‘n Waarde kan gestoor word soos volg:
curl \
-X POST http://localhost:8081/cache/set\
-H "Content-Type: application/x-www-form-urlencoded"\
-d 'k=user&v=john doe'‘n Gestoorde waarde kan verkry word soos volg:
curl "http://localhost:8080/cache/get?k=user"Opsomming
Ons het hier ‘n basiese sleutelwaarde stoor implementeer. In die volgende artikel sal ons daarna kyk om dit te gebruik om gebruiker sessies te implementeer.
(Afrikaanse artikel)


Comments
Post a Comment