|
|
|
@ -6,6 +6,7 @@
|
|
|
|
|
#include "json/json.h"
|
|
|
|
|
#include "http/query.h"
|
|
|
|
|
#include "ffdb/fs_list.h"
|
|
|
|
|
#include "format.h"
|
|
|
|
|
|
|
|
|
|
#include "model/status.h"
|
|
|
|
|
#include "model/account.h"
|
|
|
|
@ -80,6 +81,126 @@ success:
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t getline_stripped( char** restrict lineptr, size_t* restrict n, FILE* restrict stream);
|
|
|
|
|
|
|
|
|
|
bool http_request_write_multipart_to_FILE( struct http_request* req, FILE* f )
|
|
|
|
|
{
|
|
|
|
|
char* line = NULL;
|
|
|
|
|
char* boundary = NULL;
|
|
|
|
|
FILE* data = http_request_get_request_data( req );
|
|
|
|
|
|
|
|
|
|
size_t n;
|
|
|
|
|
// lineptr should match the contents of the Content-Type boundary= parametera
|
|
|
|
|
ssize_t res = getline_stripped( &line, &n, data );
|
|
|
|
|
boundary = aformat( "\r\n%s", line );
|
|
|
|
|
|
|
|
|
|
int boundary_size = strlen(boundary);
|
|
|
|
|
|
|
|
|
|
struct ring_buffer {
|
|
|
|
|
char* data;
|
|
|
|
|
int count;
|
|
|
|
|
int limit;
|
|
|
|
|
int head;
|
|
|
|
|
};
|
|
|
|
|
struct ring_buffer buffer = {
|
|
|
|
|
.data = malloc(boundary_size + 20),
|
|
|
|
|
.count = 0,
|
|
|
|
|
.limit = boundary_size + 20,
|
|
|
|
|
.head = 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool ring_buffer_push_back( struct ring_buffer* rb, char ch )
|
|
|
|
|
{
|
|
|
|
|
if( rb->count >= rb->limit ) { return false; }
|
|
|
|
|
rb->data[ ( rb->head + rb->count ) % rb->limit ] = ch;
|
|
|
|
|
rb->count += 1;
|
|
|
|
|
}
|
|
|
|
|
bool ring_buffer_pop_front( struct ring_buffer* rb, char* ch )
|
|
|
|
|
{
|
|
|
|
|
if( rb->count == 0 ) { return false; }
|
|
|
|
|
*ch = rb->data[ rb->head ];
|
|
|
|
|
rb->head = ( rb->head + 1 ) % rb->limit;
|
|
|
|
|
rb->count -= 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool ring_buffer_compare_prefix( struct ring_buffer* rb, const char* str )
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
for( int i = 0; i < rb->count; ++i, ++str ) {
|
|
|
|
|
if( !*str ) {
|
|
|
|
|
// String matches start of buffer
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char ch = rb->data[ ( i + rb->head ) % rb->limit ];
|
|
|
|
|
if( *str != ch ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset( buffer.data, 0, boundary_size );
|
|
|
|
|
int pos = 0;
|
|
|
|
|
bool filled = false;
|
|
|
|
|
|
|
|
|
|
// Eat all header data
|
|
|
|
|
char* content_type = NULL;
|
|
|
|
|
while( getline_stripped( &line, &n, data ) > 0 ) {
|
|
|
|
|
if( 0 == strncasecmp( line, "Content-Type: ", 14 ) ) {
|
|
|
|
|
content_type = strdup( &line[14] );
|
|
|
|
|
printf( "content_type=%s\n", content_type );
|
|
|
|
|
} else {
|
|
|
|
|
printf( "Header: %s\n", line );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(line);
|
|
|
|
|
|
|
|
|
|
// Read the line
|
|
|
|
|
int filesize = 0;
|
|
|
|
|
int ch;
|
|
|
|
|
do {
|
|
|
|
|
ch = fgetc(data);
|
|
|
|
|
if( ch != EOF ) {
|
|
|
|
|
ring_buffer_push_back(&buffer,ch );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( ring_buffer_compare_prefix(&buffer,boundary) ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( buffer.count > boundary_size || ch == EOF ) {
|
|
|
|
|
char c;
|
|
|
|
|
if( ring_buffer_pop_front( &buffer, &c ) ) {
|
|
|
|
|
filesize += 1;
|
|
|
|
|
fputc( c, f );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while( buffer.count > 0 );
|
|
|
|
|
|
|
|
|
|
//printf( "%d bytes uploaded\n", filesize );
|
|
|
|
|
|
|
|
|
|
free(content_type);
|
|
|
|
|
free(boundary);
|
|
|
|
|
free(buffer.data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handle_media( struct http_request* req )
|
|
|
|
|
{
|
|
|
|
|
char filename[512];
|
|
|
|
|
|
|
|
|
|
int id = fs_list_get( "data/media/HEAD" );
|
|
|
|
|
|
|
|
|
|
FILE* f = fopen(format(filename,sizeof(filename), "data/media/%d.blob",id), "w" );
|
|
|
|
|
bool result = http_request_write_multipart_to_FILE( req, f );
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
if( !result ) { return false; }
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool route_mastodon_api( struct http_request* req )
|
|
|
|
|
{
|
|
|
|
|
if( http_request_route_term( req, "apps" ) ) {
|
|
|
|
@ -116,6 +237,8 @@ bool route_mastodon_api( struct http_request* req )
|
|
|
|
|
} else if( http_request_route( req, "public" ) ) {
|
|
|
|
|
return handle_timeline( req, tli_public );
|
|
|
|
|
}
|
|
|
|
|
} else if( http_request_route_term( req, "media" ) ) {
|
|
|
|
|
return handle_media(req);
|
|
|
|
|
} else if( http_request_route( req, "apps/" ) ) {
|
|
|
|
|
|
|
|
|
|
if( http_request_route( req, "verify_credentials" ) ) {
|
|
|
|
|