diff --git a/src/html_cache.c b/src/html_cache.c index 7d04da4..cbf5f17 100644 --- a/src/html_cache.c +++ b/src/html_cache.c @@ -14,14 +14,73 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. +// Standard library includes. +#include +#include +#include + // Third-party includes. -//#include +#include +#include + +// Local includes. +#include "http.h" +#include "helpers.h" char *c_simple_http_path_to_cache_filename(const char *path) { -// SDArchiverLinkedList *parts = simple_archiver_list_init(); - // TODO + __attribute__((cleanup(simple_archiver_helper_cleanup_c_string))) + char *stripped_path = c_simple_http_strip_path(path, strlen(path)); - return 0; + if (!stripped_path) { + return NULL; + } + + if (strcmp(stripped_path, "/") == 0) { + char *buf = malloc(5); + memcpy(buf, "ROOT", 5); + return buf; + } + + __attribute__((cleanup(simple_archiver_list_free))) + SDArchiverLinkedList *parts = simple_archiver_list_init(); + + size_t idx = 0; + size_t prev_idx = 0; + const size_t path_len = strlen(stripped_path); + size_t size; + + for (; idx < path_len && stripped_path[idx] != 0; ++idx) { + if (stripped_path[idx] == '/') { + size = idx - prev_idx + 1; + char *temp_buf = malloc(size); + memcpy(temp_buf, stripped_path + prev_idx, size - 1); + temp_buf[size - 1] = 0; + c_simple_http_add_string_part(parts, temp_buf, 0); + free(temp_buf); + + temp_buf = malloc(5); + memcpy(temp_buf, "0x2F", 5); + c_simple_http_add_string_part(parts, temp_buf, 0); + free(temp_buf); + + prev_idx = idx + 1; + } + } + + if (idx > prev_idx) { + size = idx - prev_idx + 1; + char *temp_buf = malloc(size); + memcpy(temp_buf, stripped_path + prev_idx, size - 1); + temp_buf[size - 1] = 0; + c_simple_http_add_string_part(parts, temp_buf, 0); + free(temp_buf); + } + + if (prev_idx == 0) { + return stripped_path; + } else { + return c_simple_http_combine_string_parts(parts); + } } int c_simple_http_cache_path( diff --git a/src/http.c b/src/http.c index 08165db..ceccbcd 100644 --- a/src/http.c +++ b/src/http.c @@ -23,8 +23,10 @@ // Third party includes. #include +#include // Local includes +#include "SimpleArchiver/src/data_structures/priority_heap.h" #include "constants.h" #include "http_template.h" #include "helpers.h" @@ -193,6 +195,14 @@ char *c_simple_http_request_response( } char *c_simple_http_strip_path(const char *path, size_t path_size) { + if (path_size == 1 && path[0] == '/') { + // Edge case: root path. + char *buf = malloc(2); + buf[0] = '/'; + buf[1] = 0; + return buf; + } + size_t idx = 0; for (; idx < path_size && path[idx] != 0; ++idx) { if (path[idx] == '?' || path[idx] == '#') { @@ -204,7 +214,72 @@ char *c_simple_http_strip_path(const char *path, size_t path_size) { memcpy(stripped_path, path, idx); stripped_path[idx] = 0; + // Strip multiple '/' into one. + __attribute((cleanup(simple_archiver_list_free))) + SDArchiverLinkedList *parts = simple_archiver_list_init(); + + idx = 0; + size_t prev_idx = 0; + size_t size; + char *buf; + uint_fast8_t slash_visited = 0; + + for (; stripped_path[idx] != 0; ++idx) { + if (stripped_path[idx] == '/') { + if (slash_visited) { + // Intentionally left blank. + } else { + slash_visited = 1; + + if (idx > prev_idx) { + size = idx - prev_idx + 1; + buf = malloc(size); + memcpy(buf, stripped_path + prev_idx, size - 1); + buf[size - 1] = 0; + + c_simple_http_add_string_part(parts, buf, 0); + free(buf); + } + } + } else { + if (slash_visited) { + buf = malloc(2); + buf[0] = '/'; + buf[1] = 0; + + c_simple_http_add_string_part(parts, buf, 0); + free(buf); + + prev_idx = idx; + } + + slash_visited = 0; + } + } + + if (!slash_visited && idx > prev_idx) { + size = idx - prev_idx + 1; + buf = malloc(size); + memcpy(buf, stripped_path + prev_idx, size - 1); + buf[size - 1] = 0; + + c_simple_http_add_string_part(parts, buf, 0); + free(buf); + } else if (slash_visited && prev_idx == 0) { + buf = malloc(2); + buf[0] = '/'; + buf[1] = 0; + + c_simple_http_add_string_part(parts, buf, 0); + free(buf); + } + + free(stripped_path); + + stripped_path = c_simple_http_combine_string_parts(parts); + // Strip trailing '/'. + idx = strlen(stripped_path); while (idx-- > 1) { if (stripped_path[idx] == '/' || stripped_path[idx] == 0) { stripped_path[idx] = 0; diff --git a/src/test.c b/src/test.c index afcc0c9..86cc92a 100644 --- a/src/test.c +++ b/src/test.c @@ -9,6 +9,7 @@ #include "helpers.h" #include "http_template.h" #include "http.h" +#include "html_cache.h" // Third party includes. #include @@ -308,7 +309,7 @@ int main(void) { buf = c_simple_http_path_to_generated( "/", &config, &output_buf_size, &filenames_list); ASSERT_TRUE(buf != NULL); - printf("%s\n", buf); + //printf("%s\n", buf); ASSERT_TRUE( strcmp( buf, @@ -374,7 +375,7 @@ int main(void) { buf = c_simple_http_path_to_generated( "/", &config, &output_buf_size, &filenames_list); ASSERT_TRUE(buf != NULL); - printf("%s\n", buf); + //printf("%s\n", buf); ASSERT_TRUE( strcmp( buf, @@ -465,7 +466,7 @@ int main(void) { buf = c_simple_http_path_to_generated( "/", &config, &output_buf_size, &filenames_list); ASSERT_TRUE(buf != NULL); - printf("%s\n", buf); + //printf("%s\n", buf); ASSERT_TRUE( strcmp( buf, @@ -519,28 +520,39 @@ int main(void) { free(stripped_path_buf); stripped_path_buf = c_simple_http_strip_path("/someurl/", 9); + //printf("stripped path: %s\n", stripped_path_buf); CHECK_STREQ(stripped_path_buf, "/someurl"); free(stripped_path_buf); stripped_path_buf = c_simple_http_strip_path("/someurl/////", 13); + //printf("stripped path: %s\n", stripped_path_buf); CHECK_STREQ(stripped_path_buf, "/someurl"); free(stripped_path_buf); stripped_path_buf = c_simple_http_strip_path("/someurl?key=value", 18); + //printf("stripped path: %s\n", stripped_path_buf); CHECK_STREQ(stripped_path_buf, "/someurl"); free(stripped_path_buf); stripped_path_buf = c_simple_http_strip_path("/someurl#client_data", 20); + //printf("stripped path: %s\n", stripped_path_buf); CHECK_STREQ(stripped_path_buf, "/someurl"); free(stripped_path_buf); stripped_path_buf = c_simple_http_strip_path("/someurl////?key=value", 22); + //printf("stripped path: %s\n", stripped_path_buf); CHECK_STREQ(stripped_path_buf, "/someurl"); free(stripped_path_buf); stripped_path_buf = c_simple_http_strip_path("/someurl///#client_data", 23); + //printf("stripped path: %s\n", stripped_path_buf); CHECK_STREQ(stripped_path_buf, "/someurl"); free(stripped_path_buf); + + stripped_path_buf = c_simple_http_strip_path("/someurl/////inner", 18); + //printf("stripped path: %s\n", stripped_path_buf); + CHECK_STREQ(stripped_path_buf, "/someurl/inner"); + free(stripped_path_buf); } // Test helpers. @@ -558,6 +570,37 @@ int main(void) { ASSERT_TRUE(strcmp(buf, "one\ntwo\nthree\n") == 0); } + // Test html_cache. + { + char *ret = c_simple_http_path_to_cache_filename("/"); + CHECK_TRUE(strcmp(ret, "ROOT") == 0); + free(ret); + + ret = c_simple_http_path_to_cache_filename("////"); + CHECK_TRUE(strcmp(ret, "ROOT") == 0); + free(ret); + + ret = c_simple_http_path_to_cache_filename("/inner"); + CHECK_TRUE(strcmp(ret, "0x2Finner") == 0); + free(ret); + + ret = c_simple_http_path_to_cache_filename("/inner////"); + CHECK_TRUE(strcmp(ret, "0x2Finner") == 0); + free(ret); + + ret = c_simple_http_path_to_cache_filename("/outer/inner"); + CHECK_TRUE(strcmp(ret, "0x2Fouter0x2Finner") == 0); + free(ret); + + ret = c_simple_http_path_to_cache_filename("/outer/inner////"); + CHECK_TRUE(strcmp(ret, "0x2Fouter0x2Finner") == 0); + free(ret); + + ret = c_simple_http_path_to_cache_filename("/outer///inner"); + CHECK_TRUE(strcmp(ret, "0x2Fouter0x2Finner") == 0); + free(ret); + } + RETURN() }