From 0e2b9dae2b3c1119ebde0c3befdf4e04b67db595 Mon Sep 17 00:00:00 2001 From: Jonathan Hodgson Date: Wed, 5 Jan 2022 21:12:11 +0000 Subject: [PATCH] Work on requests This commit adds tests for a request and the implementation. The first line of a request should now be decoded correctly --- src/request.c | 59 ++++++++++++++-- src/request.h | 12 ++-- tests/all.test.c | 2 + tests/request.test.c | 162 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 11 deletions(-) create mode 100644 tests/request.test.c diff --git a/src/request.c b/src/request.c index 00452e2..ffec9fd 100644 --- a/src/request.c +++ b/src/request.c @@ -47,23 +47,72 @@ Request* newRequest(){ return request; } +void requestFirstLine( Request *req, char line[] ){ + char method[20] = {'\0'}; //Get, post, etc. + char *url = malloc(sizeof(char) *2048); // This may contain the method, the path, the domain and so on + memset(url, '\0', sizeof(char) * 2048); + char *currentPos; + float version = 0; + char protocol[6] = {'\0'}; + char host[254] = {'\0'}; + //https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + char path[2000] = {'\0'}; + + sscanf( line, "%20s %2048s HTTP/%f", method, url, &version ); + req->method = method; + req->version = version; + + //We've pulled out the easy bits. Now to go through the url and pull out what we need + currentPos = url; + sscanf( currentPos, "%5[^:/]", protocol ); + if ( strlen( protocol ) > 0 ){ + currentPos = currentPos + strlen(protocol) + 3; + } + + sscanf( currentPos, "%253[^:/]", host ); + if ( strlen( host ) > 0 ){ + currentPos = currentPos + strlen(host); + } + + + sscanf( currentPos, "%2000[^? ]", path ); + if ( strlen( path ) > 0 ){ + currentPos = currentPos + strlen(path); + } + + req->protocol = malloc(sizeof(char) * strlen(protocol)); + strcpy(req->protocol, protocol); + req->host = malloc(sizeof(char) * strlen(host)); + strcpy(req->host, host); + req->path = malloc(sizeof(char) * strlen(path)); + strcpy(req->path, path); + + //The query string is anything left + req->queryString = malloc(sizeof(char) * strlen(currentPos)); + strcpy(req->queryString, currentPos); + + + free(url); +} + Request* newRequestFromSocket(int socket){ Request *req = newRequest(); int valread; char line[1024] = {0}; - valread = fdReadLine( socket , line, 1024); - char hello[] = "this is a test"; - // The first line will give us some important information + //valread = fdReadLine( socket, line, 1024); + char hello[] = "this is a test"; + + printf("HERE\nLine is %s\n", line); //a length of 2 will indicate an empty line which will split the headers //from the body (if there is a body) while ( valread > 2 ){ printf("%s",line ); - valread = fdReadLine( socket , line, 1024); + //valread = fdReadLine( socket , line, 1024); } - send(socket , hello , strlen(hello) , 0 ); + send(socket , "this is a test" , 15 , 0 ); printf("Hello message sent\n"); return req; } diff --git a/src/request.h b/src/request.h index df065fc..3b7735a 100644 --- a/src/request.h +++ b/src/request.h @@ -7,8 +7,6 @@ #include "readline.h" #include -typedef enum {HTTP,HTTPS} HTTPProtocol; -typedef enum {GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH} HTTPMethod; /* * A struct reperesenting an http header @@ -33,9 +31,9 @@ struct HeaderList { */ typedef struct { // Common versions are: 0.9, 1.0, 1.1, 2.0 - double version; - HTTPMethod method; - HTTPProtocol protocol; + float version; + char *method; + char *protocol; char *host; char *path; HeaderList *headers; @@ -45,8 +43,10 @@ typedef struct { Header* newHeader(); Request* newRequest(); +void requestFirstLine( Request *req, char line[] ); Request* newRequestFromSocket(int socket); -void* addHeader(Request *req); +void* addHeader(Request *req, char line[]); +void* interpretLine1(Request *req, char line[]); diff --git a/tests/all.test.c b/tests/all.test.c index d413b3b..6d10b4d 100644 --- a/tests/all.test.c +++ b/tests/all.test.c @@ -3,6 +3,7 @@ #include "munit/munit.h" #include "config.test.c" +#include "request.test.c" #include #include @@ -13,6 +14,7 @@ int main (int argc, char* argv[]) { MunitSuite all_suites[] = { config_test_suite, + request_test_suite, { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } }; diff --git a/tests/request.test.c b/tests/request.test.c new file mode 100644 index 0000000..0f1ee0a --- /dev/null +++ b/tests/request.test.c @@ -0,0 +1,162 @@ +#include "munit/munit.h" +#include "../src/request.c" + +typedef struct { + char *fullLine; + char *method; + char *host; + char *protocol; + double version; + char *path; + char *queryString; +} firstLine; + + +static firstLine line1Examples[] = { + //Full Line, Method Host Protocol Version Path + { "GET /search?q=test HTTP/2", "GET", "", "", 2, "/search", "?q=test"}, + { "POST http://example.com/test HTTP/1.1", "POST", "example.com", "http", 1.1, "/test", "" }, + { "POST https://example.com/test/test2/test3 HTTP/1.1", "POST", "example.com", "https", 1.1, "/test/test2/test3", ""}, + { NULL, NULL, NULL, NULL, 0, NULL, NULL } +}; + + + + +MunitResult testFirstLineProtocols(const MunitParameter params[], + void* user_data_or_fixture){ + Request *req; + for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ + req = newRequest(); + requestFirstLine( req, line->fullLine ); + munit_assert_string_equal( req->protocol, line->protocol ); + free( req ); + } + return MUNIT_OK; +} + +MunitResult testFirstLineMethod(const MunitParameter params[], + void* user_data_or_fixture){ + Request *req; + for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ + req = newRequest(); + requestFirstLine( req, line->fullLine ); + munit_assert_string_equal( req->method, line->method ); + free( req ); + } + return MUNIT_OK; +} + +MunitResult testFirstLineHosts(const MunitParameter params[], + void* user_data_or_fixture){ + Request *req; + for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ + req = newRequest(); + requestFirstLine( req, line->fullLine ); + munit_assert_string_equal( req->host, line->host ); + free( req ); + } + return MUNIT_OK; +} + +MunitResult testFirstLinePaths(const MunitParameter params[], + void* user_data_or_fixture){ + Request *req; + for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ + req = newRequest(); + requestFirstLine( req, line->fullLine ); + munit_assert_string_equal( req->path, line->path ); + free( req ); + } + return MUNIT_OK; +} + +MunitResult testFirstLineVersions(const MunitParameter params[], + void* user_data_or_fixture){ + Request *req; + for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ + req = newRequest(); + requestFirstLine( req, line->fullLine ); + munit_assert_float( req->version, ==, line->version ); + free( req ); + } + return MUNIT_OK; +} + +MunitResult testFirstLineQueryString(const MunitParameter params[], + void* user_data_or_fixture){ + Request *req; + for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ + req = newRequest(); + requestFirstLine( req, line->fullLine ); + munit_assert_string_equal( req->queryString, line->queryString ); + free( req ); + } + return MUNIT_OK; +} + +static MunitTest request_tests[] = { + { + "/line1/versions", /* name */ + testFirstLineVersions, /* test */ + NULL, /* setup */ + NULL, /* tear_down */ + MUNIT_TEST_OPTION_NONE, /* options */ + NULL /* parameters */ + }, { + "/line1/methods", /* name */ + testFirstLineMethod, /* test */ + NULL, /* setup */ + NULL, /* tear_down */ + MUNIT_TEST_OPTION_NONE, /* options */ + NULL /* parameters */ + },{ + "/line1/protocols", /* name */ + testFirstLineProtocols, /* test */ + NULL, /* setup */ + NULL, /* tear_down */ + MUNIT_TEST_OPTION_NONE, /* options */ + NULL /* parameters */ + },{ + "/line1/hosts", /* name */ + testFirstLineHosts, /* test */ + NULL, /* setup */ + NULL, /* tear_down */ + MUNIT_TEST_OPTION_NONE, /* options */ + NULL /* parameters */ + },{ + "/line1/paths", /* name */ + testFirstLinePaths, /* test */ + NULL, /* setup */ + NULL, /* tear_down */ + MUNIT_TEST_OPTION_NONE, /* options */ + NULL /* parameters */ + },{ + "/line1/queryStrings", /* name */ + testFirstLineQueryString, /* test */ + NULL, /* setup */ + NULL, /* tear_down */ + MUNIT_TEST_OPTION_NONE, /* options */ + NULL /* parameters */ + }, +/* Mark the end of the array with an entry where the test +* function is NULL */ + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; + +MunitSuite request_test_suite = { + "/request", /* name */ + request_tests, /* tests */ + NULL, /* suites */ + 1, /* iterations */ + MUNIT_SUITE_OPTION_NONE /* options */ +}; + +#ifndef MAINTEST +#define MAINTEST + +int main (int argc, char* argv[]) { + return munit_suite_main(&request_test_suite, NULL, argc, argv); +} + +#endif /* ifndef MAINTEST */