You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
3.1 KiB
C

#define _GNU_SOURCE
#include "inbox_envelope.h"
// Submodules
#include "json/json.h"
#include "json/layout.h"
#include "http/server/request.h"
#include "http/server/header.h"
#include "ffdb/fs_list.h"
#include "collections/collection.h"
#include "collections/array.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#define OBJ_TYPE struct http_header
static struct json_object_field http_header_layout[] = {
JSON_FIELD_STRING( key, true ),
JSON_FIELD_STRING( value, true ),
JSON_FIELD_END,
};
#undef OBJ_TYPE
JSON_FIELD_TYPE_COMPOSITE( http_header )
#define OBJ_TYPE struct ap_envelope
static struct json_object_field envelope_layout[] = {
JSON_FIELD_STRING( when, true ),
JSON_FIELD_ARRAY_OF_TYPE( headers, true, http_header_composite_type ),
JSON_FIELD_BOOL( validated, false ),
JSON_FIELD_STRING( body, true ),
JSON_FIELD_END,
};
#undef OBJ_TYPE
struct ap_envelope* ap_envelope_from_id( int id )
{
char filename[512];
snprintf( filename, 512, "data/inbox/%d.json", id );
struct ap_envelope* env = malloc(sizeof(struct ap_envelope));
memset(env,0,sizeof(struct ap_envelope));
if( !json_read_object_layout_from_file_ex( filename, envelope_layout, env, jrol_flag_dont_ignore_unhandled ) ) {
ap_envelope_free(env);
return NULL;
}
return env;
}
void ap_envelope_free_composite( struct ap_envelope* env )
{
free(env->body);
for( int i = 0; i < env->headers.count; ++i ) {
struct http_header* h = &env->headers.items[i];
free( h->key );
free( h->value );
}
free(env->headers.items);
free(env->when);
}
void ap_envelope_free( struct ap_envelope* env )
{
if( !env ) { return; }
ap_envelope_free_composite(env);
free(env);
}
static void io_copy( FILE* in, FILE* out )
{
char buffer[512];
for(;;) {
int count = fread( buffer, 1, 512, in );
if( count == 0 ) { return; }
fwrite( buffer, 1, count, out );
}
}
bool envelope_create_from_request( struct http_request* req )
{
struct ap_envelope env;
memset( &env, 0, sizeof(env) );
// Read body in
FILE* body = http_request_get_request_data(req);
size_t s;
FILE* mem = open_memstream(&env.body, &s);
io_copy(body,mem);
fclose(mem);
env.body = realloc(env.body,s+1);
env.body[s] = '\0';
// Create timestamp
uint64_t time_ns;
struct timespec ts;
clock_gettime( CLOCK_REALTIME, &ts );
time_ns = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
asprintf( &env.when, "%lu", time_ns );
// Get request headers
struct collection c = {
.ptr = &env.headers,
.vtable = &array_vtable,
.itable = &http_header_itable,
};
http_request_copy_headers( req, c );
// Deep copy header values
for( int i = 0; i < env.headers.count; ++i ) {
struct http_header* h = & env.headers.items[i];
h->key = strdup(h->key);
h->value = strdup(h->value);
}
// Get a space in the inbox
int head = fs_list_get( "data/inbox/HEAD" );
head += 1;
fs_list_set( "data/inbox/HEAD", head );
// Setup filenames
char filename[512];
snprintf( filename, 512, "data/inbox/%d.json", head );
json_write_object_layout_to_file( filename, "\t", envelope_layout, &env );
ap_envelope_free_composite(&env);
return true;
}