diff --git a/README.md b/README.md index e5eaecd..e6643f3 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ A necessary subset of `HTTP 1.0` with following options of request header being ### Code - 200 OK - 400 BAD REQUEST +- 403 Forbidden - 404 NOT FOUND - 500 Internal Server Error - 501 Method Not Implemented @@ -46,12 +47,14 @@ make install ## Command line usage ```bash -simple-http-server [-h] [-d] [-p ] [-r ] [-u ] +simple-http-server [-d] [-h] [-n host.name.com:port] [-p ] [-q 16] [-r ] [-u ] ``` -- **-h**: display this help. - **-d**: run as daemon. +- **-h**: display this help. +- **-n**: check hostname and port. - **-p**: if not set, we will choose a random port. +- **-q**: listen queue length (defalut is 16). - **-r**: http root dir. - **-u**: run as this uid. diff --git a/server.c b/server.c index f3a56bf..6f513c4 100644 --- a/server.c +++ b/server.c @@ -48,11 +48,14 @@ typedef struct HTTP_REQUEST HTTP_REQUEST; static int server_sock = -1; +static char* hostnameport; + static void accept_request(void *); static void bad_request(int); static void cat(int, FILE *); static void error_die(const char *); static void execute_cgi(int, int, const HTTP_REQUEST*); +static void forbidden(int); static uint32_t get_file_size(const char *, int); static int get_line(int, char *, int); static void handle_quit(int); @@ -156,9 +159,15 @@ static void accept_request(void *cli) { cgi &= ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)); while((numchars > 0) && strcmp("\n", buf)) { numchars = get_line(client, buf, sizeof(buf)); - if(!content_length && strcasestr(buf, "Content-Length: ")) { + if(!content_length && !strncasecmp(buf, "Content-Length: ", 16)) { content_length = atoi(buf + 16); } + else if(hostnameport && !strncasecmp(buf, "Host: ", 6)) { + if(strncasecmp(buf+6, hostnameport, strlen(hostnameport))) { + forbidden(client); + goto DISCARD_AND_CLOSE; + } + } } if(method_type == POST && content_length == -1) bad_request(client); else if(!cgi) serve_file(client, path); @@ -171,7 +180,7 @@ static void accept_request(void *cli) { execute_cgi(client, content_length, &request); } } while(0); - +DISCARD_AND_CLOSE: discard(client); close(client); } @@ -203,17 +212,7 @@ static void cat(int client, FILE *resource) { rewind(resource); sendfile(client, fileno(resource), &len, file_size); #endif - printf("Sendfile: %u bytes.\n", (unsigned int)len); -} - -/**********************************************************************/ -/* Inform the client that a CGI script could not be executed. - * Parameter: the client socket descriptor. */ -/**********************************************************************/ -#define HTTP500 "HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/html\r\n\r\n

Internal Server Error.\r\n" -static void internal_error(int client) { - send(client, HTTP500, sizeof(HTTP500)-1, 0); - puts("500 Internal Server Error."); + // printf("Sendfile: %u bytes.\n", (unsigned int)len); } /**********************************************************************/ @@ -321,6 +320,17 @@ CGI_CLOSE: waitpid(pid, NULL, 0); } +/**********************************************************************/ +/* Inform the client that the server understood + the request but refuses to authorize it + * Parameters: client socket */ +/**********************************************************************/ +#define HTTP403 "HTTP/1.0 403 Forbidden\r\nContent-Type: text/html\r\n\r\n

Your access is not allowed.\r\n" +static void forbidden(int client) { + send(client, HTTP403, sizeof(HTTP403)-1, 0); + puts("403 Forbidden."); +} + /**********************************************************************/ /* Returns the size of a file. */ /* Parameters: path of the file */ @@ -409,6 +419,16 @@ static int headers(int client, const char *filepath) { } else return 0; } +/**********************************************************************/ +/* Inform the client that a CGI script could not be executed. + * Parameter: the client socket descriptor. */ +/**********************************************************************/ +#define HTTP500 "HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/html\r\n\r\n

Internal Server Error.\r\n" +static void internal_error(int client) { + send(client, HTTP500, sizeof(HTTP500)-1, 0); + puts("500 Internal Server Error."); +} + /**********************************************************************/ /* Give a client a 404 not found status message. */ /**********************************************************************/ @@ -559,12 +579,12 @@ static int accept_client(int is_unix_sock) { } pthread_t accept_thread; if(pthread_create(&accept_thread, &attr, (void * (*)(void *))&accept_request, (void*)(uintptr_t)client_sock) != 0) perror("pthread_create"); - printf("Created new thread at %p\n", (void*)accept_thread); + // printf("Created new thread at %p\n", (void*)accept_thread); } } #define argequ(arg) (*(uint16_t*)argv[i] == *(uint16_t*)(arg)) -#define USAGE "Usage:\tsimple-http-server [-d] [-h] [-p ] [-q 16] [-r ] [-u ]\n -d:\trun as daemon.\n -h:\tdisplay this help.\n -p:\tif not set, we will choose a random port.\n -q: listen queue length (defalut is 16)\n -r:\thttp root dir.\n -u:\trun as this uid." +#define USAGE "Usage:\tsimple-http-server [-d] [-h] [-n host.name.com:port] [-p ] [-q 16] [-r ] [-u ]\n -d:\trun as daemon.\n -h:\tdisplay this help.\n -n:\tcheck hostname and port.\n -p:\tif not set, we will choose a random port.\n -q:\tlisten queue length (defalut is 16).\n -r:\thttp root dir.\n -u:\trun as this uid." int main(int argc, char **argv) { int as_daemon = 0; int queue_len = 16; @@ -585,6 +605,7 @@ int main(int argc, char **argv) { puts(USAGE); exit(EXIT_SUCCESS); } + else if(argequ("-n")) hostnameport = argv[++i]; else if(argequ("-p")) { i++; if(isdigit(argv[i][0])) port = (uint16_t)atoi(argv[i]);