allow custom-logic json routes

This commit is contained in:
Daniel Zapata
2022-09-11 11:03:17 -05:00
parent 00852704c7
commit 321e4541bb
3 changed files with 87 additions and 48 deletions
+1 -1
View File
@@ -4,4 +4,4 @@ server
# Ignore any text editor backups # Ignore any text editor backups
*~ *~
*.swp
+15
View File
@@ -0,0 +1,15 @@
typedef struct {
char* (*routeFnPtr)(int);
char *routename;
} route;
char* state(int a)
{
return "{\"status\":1}";
}
const int routeCount = 1;
route stateR = { .routeFnPtr = &state, .routename = "/state.json"};
const route *routes[routeCount] = {
&stateR
};
+63 -39
View File
@@ -11,6 +11,7 @@
#include <sys/mman.h> // mmap library #include <sys/mman.h> // mmap library
#include <sys/stat.h> // more constants #include <sys/stat.h> // more constants
#include <sys/time.h> #include <sys/time.h>
#include "routes.c"
// global constants // global constants
#define PORT 2001 // port to connect on #define PORT 2001 // port to connect on
@@ -21,12 +22,16 @@ int list_s; // listening socket
typedef struct { typedef struct {
int returncode; int returncode;
char *filename; char *filename;
char *content;
} httpRequest; } httpRequest;
// headers to send to clients // headers to send to clients
char *header200 = "HTTP/1.0 200 OK\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n"; char *header200 = "HTTP/1.0 200 OK\nServer: C-Serv v0.2\nContent-Type: %s\n\n";
char *header400 = "HTTP/1.0 400 Bad Request\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n"; char *header400 = "HTTP/1.0 400 Bad Request\nServer: C-Serv v0.2\nContent-Type: %s\n\n";
char *header404 = "HTTP/1.0 404 Not Found\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n"; char *header404 = "HTTP/1.0 404 Not Found\nServer: C-Serv v0.2\nContent-Type: %s\n\n";
// public directory
char* publicDir = "public_html";
// get a message from the socket until a blank line is recieved // get a message from the socket until a blank line is recieved
char *getMessage(int fd) { char *getMessage(int fd) {
@@ -102,46 +107,46 @@ int sendMessage(int fd, char *msg) {
} }
// Extracts the filename needed from a GET request and adds public_html to the front of it // Extracts the filename needed from a GET request and adds public_html to the front of it
char * getFileName(char* msg) char * getRequestPath(char* msg)
{ {
// Variable to store the filename in // Variable to store the filename in
char * file; char * file;
// Allocate some memory for the filename and check it went OK // Allocate some memory for the filename and check it went OK
if( (file = malloc(sizeof(char) * strlen(msg))) == NULL) if( (file = malloc(sizeof(char) * strlen(msg))) == NULL)
{ {
fprintf(stderr, "Error allocating memory to file in getFileName()\n"); fprintf(stderr, "Error allocating memory to file in getRequestPath()\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Get the filename from the header // Get the filename from the header
sscanf(msg, "GET %s HTTP/1.1", file); sscanf(msg, "GET %s HTTP/1.1", file);
return file;
}
char * publicFilePath(char* file) {
// Allocate some memory not in read only space to store "public_html" // Allocate some memory not in read only space to store "public_html"
char *base; char *base;
if( (base = malloc(sizeof(char) * (strlen(file) + 18))) == NULL) if( (base = malloc(sizeof(char) * (strlen(file) + 18))) == NULL)
{ {
fprintf(stderr, "Error allocating memory to base in getFileName()\n"); fprintf(stderr, "Error allocating memory to base in publicFilePath()\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
char* ph = "public_html";
// Copy public_html to the non read only memory // Copy public_html to the non read only memory
strcpy(base, ph); strcpy(base, publicDir);
// Append the filename after public_html // Append the filename after public_html
strcat(base, file); strcat(base, file);
// Free file as we now have the file name in base
free(file);
// Return public_html/filetheywant.html
return base; return base;
} }
// parse a HTTP request and return an object with return code and filename // parse a HTTP request and return an object with return code and filename
httpRequest parseRequest(char *msg){ httpRequest parseRequest(char *msg){
httpRequest ret; httpRequest ret;
ret.filename = NULL;
ret.content = NULL;
// A variable to store the name of the file they want // A variable to store the name of the file they want
char* filename; char* filename;
@@ -152,28 +157,23 @@ httpRequest parseRequest(char *msg){
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Find out what page they want // Find out what page they want
filename = getFileName(msg); filename = getRequestPath(msg);
printf("request for %s ",filename);
// Check if the public page they want exists
FILE *exists = fopen(publicFilePath(filename), "r" );
// Check if its a directory traversal attack // Check if its a directory traversal attack
char *badstring = ".."; if( strstr(filename, "..") != NULL )
char *test = strstr(filename, badstring);
// Check if they asked for / and give them index.html
int test2 = strcmp(filename, "public_html/");
// Check if the page they want exists
FILE *exists = fopen(filename, "r" );
// If the badstring is found in the filename
if( test != NULL )
{ {
printf("go away hacker\n");
// Return a 400 header and 400.html // Return a 400 header and 400.html
ret.returncode = 400; ret.returncode = 400;
ret.filename = "400.html"; ret.filename = "400.html";
} }
// If they asked for / return index.html // If they asked for / return index.html
else if(test2 == 0) else if(strcmp(filename, "/") == 0)
{ {
ret.returncode = 200; ret.returncode = 200;
ret.filename = "public_html/index.html"; ret.filename = "public_html/index.html";
@@ -182,16 +182,22 @@ httpRequest parseRequest(char *msg){
// If they asked for a specific page and it exists because we opened it sucessfully return it // If they asked for a specific page and it exists because we opened it sucessfully return it
else if( exists != NULL ) else if( exists != NULL )
{ {
ret.returncode = 200; ret.returncode = 200;
ret.filename = filename; ret.filename = publicFilePath(filename);
// Close the file stream // Close the file stream
fclose(exists); fclose(exists);
} }
// If we get here the file they want doesn't exist so return a 404 // If we get here the file they want doesn't exist so return a 404
else else {
{ for (int i = 0; i < routeCount; i++) {
if (strcmp(routes[i]->routename, filename) == 0) {
// TODO do the custom route action
ret.returncode = 200;
ret.content = (routes[i]->routeFnPtr)(10);
return ret;
}
}
ret.returncode = 404; ret.returncode = 404;
ret.filename = "404.html"; ret.filename = "404.html";
} }
@@ -265,27 +271,32 @@ void cleanup(int sig) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
int printHeader(int fd, int returncode) int printHeader(int fd, int returncode, char* contentType)
{ {
char* header;
// Print the header based on the return code // Print the header based on the return code
switch (returncode) switch (returncode)
{ {
case 200: case 200:
sendMessage(fd, header200); header = header200;
return strlen(header200);
break; break;
case 400: case 400:
sendMessage(fd, header400); header = header400;
return strlen(header400);
break; break;
case 404: case 404:
sendMessage(fd, header404); header = header404;
return strlen(header404);
break; break;
} }
if (header != NULL) {
char interpolatedHeader[ strlen(header) + strlen(contentType) ];
sprintf( interpolatedHeader, header, contentType );
sendMessage(fd, interpolatedHeader);
return strlen(interpolatedHeader);
} else {
return -1; return -1;
}
} }
@@ -385,15 +396,28 @@ int main(int argc, char *argv[]) {
free(header); free(header);
// Print out the correct header // Print out the correct header
headersize = printHeader(conn_s, details.returncode); char * contentType;
if (details.filename != NULL) {
contentType = "text/html";
} else {
contentType = "application/json";
}
headersize = printHeader(conn_s, details.returncode, contentType);
free(contentType);
if (details.filename != NULL) {
// Print out the file they wanted // Print out the file they wanted
pagesize = printFile(conn_s, details.filename); pagesize = printFile(conn_s, details.filename);
} else {
pagesize = strlen(details.content);
sendMessage(conn_s, details.content);
sendMessage(conn_s, "\n");
}
struct timeval endtime; struct timeval endtime;
gettimeofday(&endtime,NULL); gettimeofday(&endtime,NULL);
// Print out which process handled the request and how much data was sent // Print out which process handled the request and how much data was sent
printf("Process %d served a request of %d bytes in %d usec\n", getpid(), headersize+pagesize, endtime.tv_usec - start.tv_usec); printf("served by process %d for %d bytes in %d usec\n", getpid(), headersize+pagesize, endtime.tv_usec - start.tv_usec);
// Close the connection now were done // Close the connection now were done
close(conn_s); close(conn_s);