#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 #include #include #include #include #include #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; }