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.
210 lines
5.3 KiB
C
210 lines
5.3 KiB
C
|
|
// Submodules
|
|
#include "http/server/request.h"
|
|
#include "util/format.h"
|
|
|
|
// Model
|
|
#include "model/media.h"
|
|
|
|
// Controller
|
|
#include "controller/mastodon_api.h"
|
|
#include "controller/pleroma_api.h"
|
|
#include "controller/oauth.h"
|
|
#include "controller/webfinger.h"
|
|
#include "controller/nodeinfo.h"
|
|
#include "controller/owner.h"
|
|
#include "controller/inbox.h"
|
|
#include "controller/activity_pub.h"
|
|
#include "controller/api/emoji.h"
|
|
|
|
// Standard Library
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
const char* mime_type_for_filename( const char* filename )
|
|
{
|
|
// determine MIME type
|
|
int len = strlen(filename);
|
|
|
|
struct {
|
|
const char* extension;
|
|
const char* mime_type;
|
|
} extensions[] = {
|
|
{ ".html", "text/html" },
|
|
{ ".js", "application/javascript" },
|
|
{ ".png", "image/png" },
|
|
{ ".jpg", "image/jpg" },
|
|
{ ".css", "text/css" },
|
|
{ ".json", "application/json" },
|
|
{ ".svg", "image/svg+xml" },
|
|
{ ".woff", "font/woff" },
|
|
{ ".woff2", "font/woff2" },
|
|
{ ".mp3", "audio/mp3" },
|
|
{ ".ogg", "audio/ogg" },
|
|
{ ".oga", "audio/ogg" },
|
|
{ ".jsonld", "application/ld+json" },
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
for( int i = 0; extensions[i].extension; ++i ) {
|
|
int s = strlen( extensions[i].extension );
|
|
if( ( len - s >= 0 ) && ( 0 == strcmp( extensions[i].extension, &filename[len-s] ) ) ) {
|
|
return extensions[i].mime_type;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool send_asset( struct http_request* req, const char* fs_path )
|
|
{
|
|
const char* mime_type = mime_type_for_filename(fs_path);
|
|
if( !mime_type ) {
|
|
printf( "Unable to determine MIME type for %s\n", fs_path );
|
|
|
|
return false;
|
|
}
|
|
|
|
if( 0 == strcmp( mime_type, "application/ld+json" ) ) {
|
|
http_request_add_header( req, "Access-Control-Allow-Origin", "*" );
|
|
}
|
|
return http_request_send_file( req, fs_path, mime_type );
|
|
}
|
|
|
|
bool route_asset( struct http_request* req )
|
|
{
|
|
bool result = false;
|
|
char* full_path = NULL;
|
|
|
|
// Don't allow ".." in the path
|
|
full_path = strdup(http_request_get_full_path( req ));
|
|
if( strstr( full_path, ".." ) ) { goto failed; }
|
|
|
|
// Cut off the query string
|
|
char* res;
|
|
strtok_r( full_path, "?", &res );
|
|
|
|
// Handle index
|
|
if( full_path[ strlen(full_path)-1 ] == '/' ) {
|
|
free(full_path);
|
|
return send_asset( req, "assets/soapbox/index.html" );
|
|
}
|
|
|
|
struct {
|
|
const char* fs_path;
|
|
const char* where;
|
|
} fs_mounts[] = {
|
|
{ "assets/soapbox", "/" },
|
|
{ "data/config/assets", "/" },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
char filename[512];
|
|
for( int i = 0; fs_mounts[i].fs_path; ++i ) {
|
|
int ws = strlen( fs_mounts[i].where );
|
|
if( 0 == strncmp( fs_mounts[i].where, full_path, ws ) ) {
|
|
snprintf( filename, sizeof(filename), "%s/%s", fs_mounts[i].fs_path, &full_path[ws] );
|
|
printf( "Trying %s\n", filename );
|
|
FILE* f = fopen(filename,"r");
|
|
if( f ) {
|
|
fclose(f);
|
|
|
|
if( send_asset( req, filename ) ) {
|
|
goto success;
|
|
} else {
|
|
goto failed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto failed;
|
|
|
|
failed:
|
|
printf( "failed to process asset: %s\n", full_path );
|
|
result = false;
|
|
goto cleanup;
|
|
success:
|
|
result = true;
|
|
goto cleanup;
|
|
cleanup:
|
|
free(full_path);
|
|
return result;
|
|
}
|
|
|
|
// Route: /media/
|
|
bool route_media( struct http_request* req )
|
|
{
|
|
char* id_str = http_request_route_get_dir_or_file(req);
|
|
if( !id_str || !*id_str ) { return false; }
|
|
|
|
// Route: /media/%d{id}/
|
|
int id = -1;
|
|
if( 1 != sscanf( id_str, "%d", &id ) ) { return false; }
|
|
free(id_str);
|
|
|
|
struct media* m = media_from_id( id );
|
|
if( !m ) { return false; }
|
|
|
|
bool subroute( struct http_request* req, struct media* m ) {
|
|
char filename[512];
|
|
|
|
if( http_request_route_term( req, "blob" ) ) {
|
|
return http_request_send_file( req, format(filename,sizeof(filename),"data/media/%d.blob",m->id), m->content_type );
|
|
} else if( http_request_route_term( req, "preview" ) ) {
|
|
return http_request_send_file( req, format(filename,sizeof(filename),"data/media/%d.blob.preview",m->id), m->content_type );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool res = subroute( req, m );
|
|
media_free(m);
|
|
return res;
|
|
}
|
|
|
|
bool route_request( struct http_request* req )
|
|
{
|
|
bool inner( struct http_request* req ) {
|
|
if( http_request_route( req, "/oauth" ) ) {
|
|
return route_oauth( req );
|
|
} else if( http_request_route( req, "/owner" ) ) {
|
|
return route_owner( req );
|
|
} else if( http_request_route( req, "/inbox" ) ) {
|
|
return route_inbox( req );
|
|
} else if( http_request_route( req, "/outbox" ) ) {
|
|
return route_ap_outbox( req );
|
|
} else if( http_request_route( req, "/note/" ) ) {
|
|
return route_ap_note( req );
|
|
} else if( http_request_route( req, "/activity/" ) ){
|
|
return route_ap_activity(req);
|
|
} else if( http_request_route( req, "/media/" ) ) {
|
|
return route_media( req );
|
|
} else if( http_request_route( req, "/emoji/" ) ) {
|
|
return route_emoji_asset( req );
|
|
} else if( http_request_route( req, "/.well-known" ) ) {
|
|
if( http_request_route( req, "/webfinger?" ) ) {
|
|
return route_wellknown_webfinger( req );
|
|
} else if( http_request_route( req, "/nodeinfo" ) ) {
|
|
printf( "Nodeinfo\n" );
|
|
return route_wellknown_nodeinfo( req );
|
|
}
|
|
} else if( http_request_route( req, "/nodeinfo" ) ) {
|
|
return route_nodeinfo(req);
|
|
} else {
|
|
return route_asset(req);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if( http_request_route( req, "/api/v1/" ) ) {
|
|
return route_mastodon_api( req );
|
|
} else if( http_request_route( req, "/api/pleroma" ) ) {
|
|
return route_pleroma_api2( req );
|
|
} else if( inner( req ) ) {
|
|
return true;
|
|
} else {
|
|
return send_asset( req, "assets/soapbox/index.html" );
|
|
}
|
|
}
|
|
|