Skip to content

Commit

Permalink
Merge pull request private-octopus#1703 from private-octopus/httpr2
Browse files Browse the repository at this point in the history
Implementation of range header
  • Loading branch information
huitema authored Jun 30, 2024
2 parents d141275 + 7b9ef4b commit 113d9bd
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 58 deletions.
47 changes: 44 additions & 3 deletions picohttp/democlient.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ int h09_demo_client_prepare_stream_open_command(

static int picoquic_demo_client_open_stream(picoquic_cnx_t* cnx,
picoquic_demo_callback_ctx_t* ctx,
uint64_t stream_id, char const* doc_name, char const* fname, uint64_t post_size, uint64_t nb_repeat)
uint64_t stream_id, char const* doc_name, char const* fname, char const* range, uint64_t post_size, uint64_t nb_repeat)
{
int ret = 0;
uint8_t buffer[1024];
Expand Down Expand Up @@ -315,8 +315,10 @@ static int picoquic_demo_client_open_stream(picoquic_cnx_t* cnx,

switch (ctx->alpn) {
case picoquic_alpn_http_3:
ret = h3zero_client_create_stream_request(
buffer, sizeof(buffer), path, path_len, post_size, cnx->sni, &request_length);
ret = h3zero_client_create_stream_request_ex(
buffer, sizeof(buffer), path, path_len,
range, (range == NULL)?0:strlen(range), post_size,
cnx->sni, &request_length);
break;
case picoquic_alpn_http_0_9:
default:
Expand Down Expand Up @@ -397,6 +399,7 @@ int picoquic_demo_client_start_streams(picoquic_cnx_t* cnx,
ret = picoquic_demo_client_open_stream(cnx, ctx, ctx->demo_stream[i].stream_id,
ctx->demo_stream[i].doc_name,
ctx->demo_stream[i].f_name,
ctx->demo_stream[i].range,
(size_t)ctx->demo_stream[i].post_size,
repeat_nb);
repeat_nb++;
Expand Down Expand Up @@ -871,10 +874,40 @@ char const * demo_client_parse_post_size(char const * text, uint64_t * post_size
return text;
}

char const * demo_client_parse_range(char const * text, char ** range)
{
if (text[0] != '#') {
*range = NULL;
}
else {
char const* range_start = ++text;
size_t l_range = 0;

while (*text != ':' && *text != ';' && *text != 0) {
text++;
}
l_range = text - range_start;
*range = malloc(l_range + 1);
if (*range == NULL) {
text = NULL;
} else {
memcpy(*range, range_start, l_range);
(*range)[l_range] = 0;

if (*text == ':') {
text++;
}
}
}

return text;
}

char const * demo_client_parse_stream_desc(char const * text, uint64_t default_stream, uint64_t default_previous,
picoquic_demo_stream_desc_t * desc)
{
memset(desc, 0, sizeof(picoquic_demo_stream_desc_t));

text = demo_client_parse_stream_repeat(text, &desc->repeat_count);

if (text != NULL) {
Expand All @@ -895,6 +928,10 @@ char const * demo_client_parse_stream_desc(char const * text, uint64_t default_s
text = demo_client_parse_post_size(demo_client_parse_stream_spaces(text), &desc->post_size);
}

if (text != NULL) {
text = demo_client_parse_range(demo_client_parse_stream_spaces(text), (char **)&desc->range);
}

/* Skip the final ';' */
if (text != NULL && *text == ';') {
text++;
Expand All @@ -914,6 +951,10 @@ void demo_client_delete_scenario_desc(size_t nb_streams, picoquic_demo_stream_de
free((char*)desc[i].doc_name);
*(char**)(&desc[i].doc_name) = NULL;
}
if (desc[i].range != NULL) {
free((char*)desc[i].range);
*(char**)(&desc[i].range) = NULL;
}
}
free(desc);
}
Expand Down
1 change: 1 addition & 0 deletions picohttp/democlient.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef struct st_picoquic_demo_stream_desc_t {
char const* doc_name;
char const* f_name;
uint64_t post_size;
char const* range;
} picoquic_demo_stream_desc_t;

#define PICOQUIC_DEMO_STREAM_LIST_MAX 16
Expand Down
41 changes: 33 additions & 8 deletions picohttp/h3zero.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,16 @@ uint8_t * h3zero_parse_qpack_header_value(uint8_t * bytes, uint8_t * bytes_max,
decoded_length, &parts->path, &parts->path_length);
}
break;
case http_header_range:
if (parts->range != NULL) {
/* Duplicate content type! */
bytes = 0;
}
else {
bytes = h3zero_parse_qpack_header_value_string(bytes, decoded,
decoded_length, &parts->range, &parts->range_length);
}
break;
case http_pseudo_header_protocol:
if (parts->protocol != NULL) {
/* Duplicate content type! */
Expand All @@ -493,11 +503,12 @@ uint8_t * h3zero_parse_qpack_header_value(uint8_t * bytes, uint8_t * bytes_max,
int h3zero_get_interesting_header_type(uint8_t * name, size_t name_length, int is_huffman)
{
char const * interesting_header_name[] = {
":method", ":path", ":status", "content-type", ":protocol", "origin", NULL};
":method", ":path", ":status", "content-type", ":protocol", "origin", "range", NULL};
const http_header_enum_t interesting_header[] = {
http_pseudo_header_method, http_pseudo_header_path,
http_pseudo_header_status, http_header_content_type,
http_pseudo_header_protocol, http_header_origin
http_pseudo_header_protocol, http_header_origin,
http_header_range
};
http_header_enum_t val = http_header_unknown;
uint8_t deHuff[256];
Expand Down Expand Up @@ -837,7 +848,7 @@ uint8_t* h3zero_create_connect_header_frame(uint8_t* bytes, uint8_t* bytes_max,
}

uint8_t * h3zero_create_post_header_frame_ex(uint8_t * bytes, uint8_t * bytes_max,
uint8_t const * path, size_t path_length, char const * host,
uint8_t const * path, size_t path_length, uint8_t const * range, size_t range_length, char const* host,
h3zero_content_type_enum content_type, char const* ua_string)
{
if (bytes == NULL || bytes + 2 > bytes_max) {
Expand All @@ -852,10 +863,14 @@ uint8_t * h3zero_create_post_header_frame_ex(uint8_t * bytes, uint8_t * bytes_ma
bytes = h3zero_qpack_code_encode(bytes, bytes_max, 0xC0, 0x3F, H3ZERO_QPACK_SCHEME_HTTPS);
/* Path: doc_name. Use literal plus reference format */
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_CODE_PATH, path, path_length);
/*Authority: host. Use literal plus reference format */
/* Authority: host. Use literal plus reference format */
if (host != NULL) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_AUTHORITY, (uint8_t const *)host, strlen(host));
}
/* Optional: range. Use literal plus reference format */
if (range_length > 0) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_RANGE, (uint8_t const *)range, range_length);
}
/* User Agent */
if (ua_string != NULL) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_USER_AGENT, (uint8_t const*)ua_string, strlen(ua_string));
Expand All @@ -869,12 +884,13 @@ uint8_t * h3zero_create_post_header_frame_ex(uint8_t * bytes, uint8_t * bytes_ma
uint8_t* h3zero_create_post_header_frame(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* host, h3zero_content_type_enum content_type)
{
return h3zero_create_post_header_frame_ex(bytes, bytes_max, path, path_length, host,
return h3zero_create_post_header_frame_ex(bytes, bytes_max, path, path_length, NULL, 0, host,
content_type, H3ZERO_USER_AGENT_STRING);
}

uint8_t * h3zero_create_request_header_frame_ex(uint8_t * bytes, uint8_t * bytes_max,
uint8_t const * path, size_t path_length, char const * host, char const* ua_string)
uint8_t const * path, size_t path_length, uint8_t const * range, size_t range_length,
char const * host, char const* ua_string)
{
if (bytes == NULL || bytes + 2 > bytes_max) {
return NULL;
Expand All @@ -888,10 +904,14 @@ uint8_t * h3zero_create_request_header_frame_ex(uint8_t * bytes, uint8_t * bytes
bytes = h3zero_qpack_code_encode(bytes, bytes_max, 0xC0, 0x3F, H3ZERO_QPACK_SCHEME_HTTPS);
/* Path: doc_name. Use literal plus reference format */
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_CODE_PATH, path, path_length);
/*Authority: host. Use literal plus reference format */
/* Authority: host. Use literal plus reference format */
if (host != NULL) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_AUTHORITY, (uint8_t const *)host, strlen(host));
}
/* Optional: range. Use literal plus reference format */
if (range_length > 0) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_RANGE, (uint8_t const *)range, range_length);
}
/* User Agent */
if (ua_string != NULL) {
bytes = h3zero_qpack_literal_plus_ref_encode(bytes, bytes_max, H3ZERO_QPACK_USER_AGENT, (uint8_t const*)ua_string, strlen(ua_string));
Expand All @@ -903,7 +923,7 @@ uint8_t* h3zero_create_request_header_frame(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* host)
{
return h3zero_create_request_header_frame_ex(bytes, bytes_max, path, path_length,
host, H3ZERO_USER_AGENT_STRING);
NULL, 0, host, H3ZERO_USER_AGENT_STRING);
}

uint8_t * h3zero_create_response_header_frame_ex(uint8_t * bytes, uint8_t * bytes_max,
Expand Down Expand Up @@ -1039,6 +1059,11 @@ void h3zero_release_header_parts(h3zero_header_parts_t* header)
*((uint8_t**)&header->path) = NULL;
header->path_length = 0;
}
if (header->range != NULL) {
free((uint8_t*)header->range);
*((uint8_t**)&header->range) = NULL;
header->range_length = 0;
}
if (header->protocol != NULL) {
free((uint8_t*)header->protocol);
*((uint8_t**)&header->protocol) = NULL;
Expand Down
12 changes: 10 additions & 2 deletions picohttp/h3zero.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ typedef enum {
#define H3ZERO_QPACK_AUTHORITY 0
#define H3ZERO_QPACK_SCHEME_HTTPS 23
#define H3ZERO_QPACK_TEXT_PLAIN 53
#define H3ZERO_QPACK_RANGE 55
#define H3ZERO_QPACK_USER_AGENT 95
#define H3ZERO_QPACK_ORIGIN 90
#define H3ZERO_QPACK_SERVER 92
Expand Down Expand Up @@ -183,6 +184,8 @@ typedef struct st_h3zero_header_parts_t {
h3zero_method_enum method;
uint8_t const * path;
size_t path_length;
uint8_t const * range;
size_t range_length;
int status;
h3zero_content_type_enum content_type;
uint8_t const * protocol;
Expand Down Expand Up @@ -225,15 +228,20 @@ uint8_t * h3zero_parse_qpack_header_frame(uint8_t * bytes, uint8_t * bytes_max,
uint8_t * h3zero_create_request_header_frame(uint8_t * bytes, uint8_t * bytes_max,
uint8_t const * path, size_t path_length, char const * host);
uint8_t* h3zero_create_request_header_frame_ex(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* host, char const* ua_string);
uint8_t const* path, size_t path_length, uint8_t const* range, size_t range_length,
char const* host, char const* ua_string);
uint8_t * h3zero_create_post_header_frame(uint8_t * bytes, uint8_t * bytes_max,
uint8_t const * path, size_t path_length, char const * host,
h3zero_content_type_enum content_type);
uint8_t* h3zero_create_request_header_frame_ex(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, uint8_t const* range, size_t range_length,
char const* host, char const* ua_string);
uint8_t* h3zero_create_connect_header_frame(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* protocol, char const* origin,
char const* ua_string);
uint8_t* h3zero_create_post_header_frame_ex(uint8_t* bytes, uint8_t* bytes_max,
uint8_t const* path, size_t path_length, char const* host, h3zero_content_type_enum content_type, char const* ua_string);
uint8_t const* path, size_t path_length, uint8_t const* range, size_t range_length,
char const* host, h3zero_content_type_enum content_type, char const* ua_string);
uint8_t * h3zero_create_response_header_frame(uint8_t * bytes, uint8_t * bytes_max,
h3zero_content_type_enum doc_type);
uint8_t* h3zero_create_error_frame(uint8_t* bytes, uint8_t* bytes_max, char const* error_code, char const* server_string);
Expand Down
13 changes: 9 additions & 4 deletions picohttp/h3zero_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
* but the client implementation is barebone.
*/

int h3zero_client_create_stream_request(
uint8_t * buffer, size_t max_bytes, uint8_t const * path, size_t path_len, uint64_t post_size, const char * host, size_t * consumed)
int h3zero_client_create_stream_request_ex(
uint8_t * buffer, size_t max_bytes, uint8_t const * path, size_t path_len, const char * range, size_t range_len, uint64_t post_size, const char * host, size_t * consumed)
{
int ret = 0;
uint8_t * o_bytes = buffer;
Expand All @@ -51,8 +51,8 @@ int h3zero_client_create_stream_request(
*o_bytes++ = h3zero_frame_header;
o_bytes += 2; /* reserve two bytes for frame length */
if (post_size == 0) {
o_bytes = h3zero_create_request_header_frame(o_bytes, o_bytes_max,
(const uint8_t *)path, path_len, host);
o_bytes = h3zero_create_request_header_frame_ex(o_bytes, o_bytes_max,
(const uint8_t *)path, path_len, (const uint8_t *)range, range_len, host, H3ZERO_USER_AGENT_STRING);
}
else {
o_bytes = h3zero_create_post_header_frame(o_bytes, o_bytes_max,
Expand Down Expand Up @@ -99,5 +99,10 @@ int h3zero_client_create_stream_request(
return ret;
}

int h3zero_client_create_stream_request(
uint8_t* buffer, size_t max_bytes, uint8_t const* path, size_t path_len, uint64_t post_size, const char* host, size_t* consumed)
{
return h3zero_client_create_stream_request_ex(buffer, max_bytes, path, path_len, NULL, 0, post_size, host, consumed);
}


2 changes: 2 additions & 0 deletions picohttp/h3zero_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ extern "C" {

/* CLIENT DEFINITIONS
*/
int h3zero_client_create_stream_request_ex(
uint8_t* buffer, size_t max_bytes, uint8_t const* path, size_t path_len, const char* range, size_t range_len, uint64_t post_size, const char* host, size_t* consumed);
int h3zero_client_create_stream_request(
uint8_t * buffer, size_t max_bytes, uint8_t const * path, size_t path_len, uint64_t post_size, const char * host, size_t * consumed);

Expand Down
Loading

0 comments on commit 113d9bd

Please sign in to comment.