Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

h3zero get GET content types by path #1729

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions UnitTest1/unittest1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2825,6 +2825,12 @@ namespace UnitTest1
Assert::AreEqual(ret, 0);
}

TEST_METHOD(h3zero_get_content_type_by_path) {
int ret = h3zero_get_content_type_by_path_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(http_drop) {
int ret = http_drop_test();

Expand Down
10 changes: 5 additions & 5 deletions picohttp/h3zero.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,14 @@ h3zero_qpack_static_t qpack_static[] = {
{ 41, http_header_cache_control, "public, max-age=31536000", 0},
{ 42, http_header_content_encoding, "br", 0},
{ 43, http_header_content_encoding, "gzip", 0},
{ 44, http_header_content_type, "application/dns-message", 0},
{ 45, http_header_content_type, "application/javascript", 0},
{ 46, http_header_content_type, "application/json", 0},
{ 47, http_header_content_type, "application/x-www-form-urlencoded", 0},
{ 44, http_header_content_type, "application/dns-message", h3zero_content_type_dns_message},
{ 45, http_header_content_type, "application/javascript", h3zero_content_type_javascript},
{ 46, http_header_content_type, "application/json", h3zero_content_type_json},
{ 47, http_header_content_type, "application/x-www-form-urlencoded", h3zero_content_type_www_form_urlencoded},
{ 48, http_header_content_type, "image/gif", h3zero_content_type_image_gif},
{ 49, http_header_content_type, "image/jpeg", h3zero_content_type_image_jpeg},
{ 50, http_header_content_type, "image/png", h3zero_content_type_image_png},
{ 51, http_header_content_type, "text/css", 0},
{ 51, http_header_content_type, "text/css", h3zero_content_type_text_css},
{ 52, http_header_content_type, "text/html; charset=utf-8", h3zero_content_type_text_html},
{ 53, http_header_content_type, "text/plain", h3zero_content_type_text_plain},
{ 54, http_header_content_type, "text/plain;charset=utf-8", h3zero_content_type_text_plain},
Expand Down
53 changes: 52 additions & 1 deletion picohttp/h3zero_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,54 @@ int h3zero_find_path_item(const uint8_t * path, size_t path_length, const picoht
return -1;
}

/* TODO find a better place. */
h3zero_content_type_enum h3zero_get_content_type_by_path(const char *path) {
if (path != NULL) {
/* Dots in paths allowed.
* https://datatracker.ietf.org/doc/html/rfc1738
* path -> segment -> xpalphas -> xalpha -> alpha | digit | safe | extra | escape -> safe = $ | - | _ | @ | . |
*/

const char *dot = strrchr(path, '.'); /* recursive to get the last occuraence. */
/* if dot is found. */
if(dot && dot != path) {
const char *ext = dot + 1;

/*
* h3zero_content_type_none = 0,
* h3zero_content_type_not_supported,
* h3zero_content_type_text_html,
* h3zero_content_type_text_plain,
* h3zero_content_type_image_gif,
* h3zero_content_type_image_jpeg,
* h3zero_content_type_image_png,
* h3zero_content_type_dns_message,
* h3zero_content_type_javascript,
* h3zero_content_type_json,
* h3zero_content_type_www_form_urlencoded,
* h3zero_content_type_text_css
*/
if (strcmp(ext, "html") == 0 || strcmp(ext, "htm") == 0) {
return h3zero_content_type_text_html;
} else if (strcmp(ext, "gif") == 0) {
return h3zero_content_type_image_gif;
} else if (strcmp(ext, "jpg") == 0 || strcmp(ext, "jpeg") == 0) {
return h3zero_content_type_image_jpeg;
} else if (strcmp(ext, "png") == 0) {
return h3zero_content_type_image_png;
} else if (strcmp(ext, "js") == 0) {
return h3zero_content_type_javascript;
} else if (strcmp(ext, "json") == 0) {
return h3zero_content_type_json;
} else if (strcmp(ext, "css") == 0) {
return h3zero_content_type_text_css;
}
}
}

/* PATH == NULL OR dot not found OR unknown extension. */
return h3zero_content_type_text_plain;
}

/* Processing of the request frame.
* This function is called after the client's stream is closed,
Expand Down Expand Up @@ -953,7 +1001,10 @@ int h3zero_process_request_frame(
strlen(h3zero_server_default_page) : stream_ctx->echo_length;
o_bytes = h3zero_create_response_header_frame(o_bytes, o_bytes_max,
(stream_ctx->echo_length == 0) ? h3zero_content_type_text_html :
h3zero_content_type_text_plain);
h3zero_get_content_type_by_path(stream_ctx->file_path));
/* TODO handle query string
* Currently picoquic doesn't support query strings.
*/
}
}
else if (stream_ctx->ps.stream_state.header.method == h3zero_method_post) {
Expand Down
2 changes: 2 additions & 0 deletions picohttp/h3zero_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ extern "C" {

void h3zero_forget_stream(picoquic_cnx_t* cnx, h3zero_stream_ctx_t* stream_ctx);

h3zero_content_type_enum h3zero_get_content_type_by_path(const char *path);

int h3zero_set_datagram_ready(picoquic_cnx_t* cnx, uint64_t stream_id);
uint8_t* h3zero_provide_datagram_buffer(void* context, size_t length, int ready_to_send);

Expand Down
1 change: 1 addition & 0 deletions picohttp_t/picohttp_t.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ static const picoquic_test_def_t test_table[] = {
{ "h09_multi_file_loss", h09_multi_file_loss_test },
{ "h09_multi_file_preemptive", h09_multi_file_preemptive_test },
{ "h3zero_settings", h3zero_settings_test },
{ "h3zero_get_content_type_by_path", h3zero_get_content_type_by_path_test },
{ "http_stress", http_stress_test },
{ "http_corrupt", http_corrupt_test},
{ "http_corrupt_rdpn", http_corrupt_rdpn_test},
Expand Down
79 changes: 79 additions & 0 deletions picoquictest/h3zerotest.c
Original file line number Diff line number Diff line change
Expand Up @@ -3290,6 +3290,85 @@ int h3zero_settings_test()
ret = h3zero_settings_encode_test(h3zero_default_setting_frame + 1, h3zero_default_setting_frame_size - 1, &default_setting_expected);
}

return ret;
}

/*
* h3zero_content_type_none = 0,
* h3zero_content_type_not_supported,
* h3zero_content_type_text_html,
* h3zero_content_type_text_plain,
* h3zero_content_type_image_gif,
* h3zero_content_type_image_jpeg,
* h3zero_content_type_image_png,
* h3zero_content_type_dns_message,
* h3zero_content_type_javascript,
* h3zero_content_type_json,
* h3zero_content_type_www_form_urlencoded,
* h3zero_content_type_text_css
*/

typedef struct st_h3zero_string_content_type_compar_list_t {
const char *path;
const h3zero_content_type_enum content_type;
} h3zero_string_content_type_compare_list_t;

char const root_path_str[] = { '/' , 0 };
char const no_ext_path_str[] = { '/', 'n', 'o', 'e', 'x', 't' , 0 };
char const htm_path_str[] = { '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'h', 't', 'm', 0 };
char const html_path_str[] = { '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'h', 't', 'm', 'l', 0 };
char const txt_path_str[] = { '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 't', 'x', 't', 0 };
char const gif_path_str[] = { '/', 'i', 'm', 'g', '.', 'g', 'i', 'f', 0 };
char const jpg_path_str[] = { '/', 'i', 'm', 'g', '.', 'j', 'p', 'g', 0 };
char const jpeg_path_str[] = { '/', 'i', 'm', 'g', '.', 'j', 'p', 'e', 'g', 0 };
char const png_path_str[] = { '/', 'i', 'm', 'g', '.', 'p', 'n', 'g', 0 };
char const js_path_str[] = { '/', 's', 'c', 'r', 'i', 'p', 't', '.', 'j', 's', 0 };
char const json_path_str[] = { '/', 'd', 'a', 't', 'a', '.', 'j', 's', 'o', 'n', 0 };
char const css_path_str[] = { '/', 's', 't', 'y', 'l', 'e', '.', 'c', 's', 's', 0 };

char const double_dot_path_str[] = { '/', 's', 't', 'y', 'l', 'e', '.', 'e', 'x', 't', '.', 'h', 't', 'm', 'l', 0 };

static const h3zero_string_content_type_compare_list_t h3zero_string_content_type_compare_list[] = {
/* Invalid paths and paths without extensions. */
{ NULL, h3zero_content_type_text_plain },
{ root_path_str, h3zero_content_type_text_plain },
{ no_ext_path_str, h3zero_content_type_text_plain },
{ txt_path_str, h3zero_content_type_text_plain },

/* Valid paths with extensions. */
{ htm_path_str, h3zero_content_type_text_html },
{ html_path_str, h3zero_content_type_text_html },
{ gif_path_str, h3zero_content_type_image_gif },
{ jpg_path_str, h3zero_content_type_image_jpeg },
{ jpeg_path_str, h3zero_content_type_image_jpeg },
{ png_path_str, h3zero_content_type_image_png },
{ js_path_str, h3zero_content_type_javascript },
{ json_path_str, h3zero_content_type_json },
{ css_path_str, h3zero_content_type_text_css },

/* Special cases but valid. */
{ double_dot_path_str, h3zero_content_type_text_html }
/* TODO Add more test cases.
* e.g. query string?
*/
};

static size_t nb_h3zero_string_content_type_compare = sizeof(h3zero_string_content_type_compare_list) / sizeof(h3zero_string_content_type_compare_list_t);

int h3zero_get_content_type_by_path_test() {
int ret = 0;

for (size_t i = 0; i < nb_h3zero_string_content_type_compare; i++) {
h3zero_string_content_type_compare_list_t item = h3zero_string_content_type_compare_list[i];

h3zero_content_type_enum ct_res;
if ((ct_res = h3zero_get_content_type_by_path(item.path)) != item.content_type) {
fprintf(stdout, "Path %s expects content type %d, but got %d. \n", item.path, item.content_type, ct_res);
ret = -1;
break;
}
}

return ret;
}

Expand Down
1 change: 1 addition & 0 deletions picoquictest/picoquictest.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ int h09_multi_file_test();
int h09_multi_file_loss_test();
int h09_multi_file_preemptive_test();
int h3zero_settings_test();
int h3zero_get_content_type_by_path_test();
int picowt_baton_basic_test();
int picowt_baton_error_test();
int picowt_baton_long_test();
Expand Down
Loading