From 59fc7d23a0082fc776fa5d6478a8c9b5c0600e79 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 13 Jul 2020 10:01:42 +0000 Subject: [PATCH] wrote some code in http-fil.c --- mio/lib/fmt.c | 4 +- mio/lib/http-fil.c | 161 ++++++++++++++++++++++++++++++++------------- mio/lib/http.c | 8 +-- mio/lib/mio-http.h | 15 ++--- 4 files changed, 127 insertions(+), 61 deletions(-) diff --git a/mio/lib/fmt.c b/mio/lib/fmt.c index c45c28a..bf3220f 100644 --- a/mio/lib/fmt.c +++ b/mio/lib/fmt.c @@ -1088,7 +1088,7 @@ static int fmt_outv (mio_fmtout_t* fmtout, va_list ap) sign = 0; if (lm_flag & LF_J) { - #if defined(__GNUC__) && \ + #if 0 && defined(__GNUC__) && \ (MIO_SIZEOF_UINTMAX_T > MIO_SIZEOF_OOW_T) && \ (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \ (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG) @@ -1132,7 +1132,7 @@ static int fmt_outv (mio_fmtout_t* fmtout, va_list ap) handle_sign: if (lm_flag & LF_J) { - #if defined(__GNUC__) && \ + #if 0 && defined(__GNUC__) && \ (MIO_SIZEOF_INTMAX_T > MIO_SIZEOF_OOI_T) && \ (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \ (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG) diff --git a/mio/lib/http-fil.c b/mio/lib/http-fil.c index 3adf2da..bec4e9c 100644 --- a/mio/lib/http-fil.c +++ b/mio/lib/http-fil.c @@ -38,7 +38,6 @@ enum file_state_res_mode_t { - FILE_STATE_RES_MODE_CHUNKED, FILE_STATE_RES_MODE_CLOSE, FILE_STATE_RES_MODE_LENGTH }; @@ -58,8 +57,12 @@ struct file_state_t mio_oow_t num_pending_writes_to_client; mio_oow_t num_pending_writes_to_peer; + int peer; - mio_uintmax_t part_size; + mio_uintmax_t total_size; + mio_uintmax_t start_offset; + mio_uintmax_t end_offset; + mio_uintmax_t cur_offset; mio_svc_htts_cli_t* client; mio_http_version_t req_version; /* client request */ @@ -81,6 +84,8 @@ struct file_state_t }; typedef struct file_state_t file_state_t; +static int file_state_send_contents_to_client (file_state_t* file_state); + static void file_state_halt_participating_devices (file_state_t* file_state) { @@ -161,11 +166,6 @@ static int file_state_write_last_chunk_to_client (file_state_t* file_state) { if (file_state_send_final_status_to_client(file_state, 500, 0) <= -1) return -1; } - else - { - if (file_state->res_mode_to_cli == FILE_STATE_RES_MODE_CHUNKED && - file_state_write_to_client(file_state, "0\r\n\r\n", 5) <= -1) return -1; - } if (!file_state->keep_alive && file_state_write_to_client(file_state, MIO_NULL, 0) <= -1) return -1; return 0; @@ -385,7 +385,6 @@ static int file_client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wr { /* if the connect is keep-alive, this part may not be called */ file_state->num_pending_writes_to_client--; -printf ("QQQQQQQQQQQQQ %lu\n", (long)file_state->num_pending_writes_to_client); MIO_ASSERT (mio, file_state->num_pending_writes_to_client == 0); MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to client %p(%d)\n", file_state->client->htts, sck, (int)sck->hnd); /* since EOF has been indicated to the client, it must not write to the client any further. @@ -407,6 +406,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX mio_dev_pro_read(file_state->peer, MIO_DEV_PRO_OUT, 1) <= -1) goto oops; } #endif + file_state_send_contents_to_client (file_state); if ((file_state->over & FILE_STATE_OVER_READ_FROM_PEER) && file_state->num_pending_writes_to_client <= 0) { @@ -461,17 +461,24 @@ static int file_state_send_header_to_client (file_state_t* file_state, int statu { mio_svc_htts_cli_t* cli = file_state->client; mio_bch_t dtbuf[64]; + mio_uintmax_t content_length; mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); if (!force_close) force_close = !file_state->keep_alive; - if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\nContent-Length: %ju\r\n\r\n", + content_length = file_state->end_offset - file_state->start_offset + 1; + if (status_code == 200 && file_state->total_size != content_length) status_code = 206; + + if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\nAccept-Ranges: bytes\r\n", file_state->req_version.major, file_state->req_version.minor, status_code, mio_http_status_to_bcstr(status_code), cli->htts->server_name, dtbuf, (force_close? "close": "keep-alive"), - file_state->part_size) == (mio_oow_t)-1) return -1; + content_length) == (mio_oow_t)-1) return -1; + + if (status_code == 206 && mio_becs_fcat(cli->sbuf, "Content-Ranges: bytes %ju-%ju/%ju\r\n", file_state->start_offset, file_state->end_offset, file_state->total_size) == (mio_oow_t)-1) return -1; + if (mio_becs_fcat(cli->sbuf, "Content-Length: %ju\r\n\r\n", content_length) == (mio_oow_t)-1) return -1; return file_state_write_to_client(file_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf)); } @@ -485,34 +492,50 @@ static int file_state_send_contents_to_client (file_state_t* file_state) */ mio_bch_t buf[8192]; /* TODO: declare this in file_state?? */ - int i; + mio_uintmax_t lim; ssize_t n; + - for (i = 0; i < FILE_STATE_PENDING_IO_THRESHOLD; i++) + if (file_state->cur_offset > file_state->end_offset) { - n = read(file_state->peer, buf, MIO_SIZEOF(buf)); - if (n == -1) - { - if (errno == EAGAIN) - { - } - else if (errno == EINTR) - { - } - } - else if (n == 0) - { - /* no more data to read */ - file_state_mark_over (file_state, FILE_STATE_OVER_READ_FROM_CLIENT); - break; - } - - if (file_state_write_to_client(file_state, buf, n) <= -1) - { - return -1; - } + /* reached the end */ + file_state_mark_over (file_state, FILE_STATE_OVER_READ_FROM_PEER); + return 0; } + lim = file_state->end_offset - file_state->cur_offset + 1; + n = read(file_state->peer, buf, (lim < MIO_SIZEOF(buf)? lim: MIO_SIZEOF(buf))); + if (n == -1) + { + if (errno == EAGAIN || errno == EINTR) + { +/* TODO: arrange to invoke on data writable? */ + /*mio_dev_sck_watch (file_state->client->sck, MIO_DEV_WATCH_UPDATE, */ + return 0; + } + else if (errno == EINTR) + { + return 0; /* interrupted */ + } + + return -1; + } + else if (n == 0) + { + /* no more data to read - this must not happend unless file size changed while the file is open. */ +/* TODO: I probably must close the connection by force??? */ + file_state_mark_over (file_state, FILE_STATE_OVER_READ_FROM_PEER); + return -1; + } + + if (file_state_write_to_client(file_state, buf, n) <= -1) + { + return -1; + } + + file_state->cur_offset += n; +/* if (file_state->cur_offset > file_state->end_offset) + file_state_mark_over (file_state, FILE_STATE_OVER_READ_FROM_PEER);*/ return 0; } @@ -557,20 +580,69 @@ int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* /* TODO: if method is for download... open it in the read mode. if PUT or POST, open it in RDWR mode? */ file_state->peer = open(actual_file, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (MIO_UNLIKELY(file_state->peer <= -1)) goto oops; - + if (MIO_UNLIKELY(file_state->peer <= -1)) + { + file_state_send_final_status_to_client (file_state, 500, 1); + goto oops; + } { struct stat st; - if (fstat(file_state->peer, &st) <= -1) goto oops; - file_state->part_size = st.st_size; -file_state->part_size = MIO_TYPE_MAX(mio_intmax_t); - } + const mio_htre_hdrval_t* tmp; -/* - file_peer = mio_dev_pro_getxtn(file_state->peer); - MIO_SVC_HTTS_RSRC_ATTACH (file_state, file_peer->state); -*/ + if (fstat(file_state->peer, &st) <= -1) goto oops; + file_state->end_offset = st.st_size; + + tmp = mio_htre_getheaderval(req, "Range"); /* TODO: support multiple ranges? */ + if (tmp) + { + mio_http_range_t range; + + + if (mio_parse_http_range_bcstr(tmp->ptr, &range) <= -1) + { + range_not_satisifiable: + file_state_send_final_status_to_client (file_state, 416, 1); /* 406 Requested Range Not Satisfiable */ + goto oops; + } + + switch (range.type) + { + case MIO_HTTP_RANGE_PROPER: + /* Range XXXX-YYYY */ + if (range.to >= st.st_size) goto range_not_satisifiable; + file_state->start_offset = range.from; + file_state->end_offset = range.to; + break; + + case MIO_HTTP_RANGE_PREFIX: + /* Range: XXXX- */ + if (range.from >= st.st_size) goto range_not_satisifiable; + file_state->start_offset = range.from; + file_state->end_offset = st.st_size - 1; + break; + + case MIO_HTTP_RANGE_SUFFIX: + /* Range: -XXXX */ + if (range.to >= st.st_size) goto range_not_satisifiable; + file_state->start_offset = st.st_size - range.to; + file_state->end_offset = st.st_size - 1; + break; + } + + if (file_state->start_offset > 0) + lseek(file_state->peer, file_state->start_offset, SEEK_SET); + + } + else + { + file_state->start_offset = 0; + file_state->end_offset = st.st_size - 1; + } + + file_state->cur_offset = file_state->start_offset; + file_state->total_size = st.st_size; + } #if !defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) @@ -661,8 +733,7 @@ XXXXXXXXXXXX if (req->flags & MIO_HTRE_ATTR_KEEPALIVE) { file_state->keep_alive = 1; - file_state->res_mode_to_cli = FILE_STATE_RES_MODE_CHUNKED; - /* the mode still can get switched to FILE_STATE_RES_MODE_LENGTH if the file emits Content-Length */ + file_state->res_mode_to_cli = FILE_STATE_RES_MODE_LENGTH; } else { diff --git a/mio/lib/http.c b/mio/lib/http.c index f4c4710..cec9ef1 100644 --- a/mio/lib/http.c +++ b/mio/lib/http.c @@ -225,7 +225,7 @@ int mio_parse_http_range_bcstr (const mio_bch_t* str, mio_http_range_t* range) str += 6; - from = 0; + from = to = 0; if (mio_is_bch_digit(*str)) { do @@ -249,10 +249,10 @@ int mio_parse_http_range_bcstr (const mio_bch_t* str, mio_http_range_t* range) str++; } while (mio_is_bch_digit(*str)); - } - else to = MIO_TYPE_MAX(mio_http_range_int_t); - if (from > to) return -1; + if (from > to) return -1; + } + else type = MIO_HTTP_RANGE_PREFIX; range->type = type; range->from = from; diff --git a/mio/lib/mio-http.h b/mio/lib/mio-http.h index d5dc6fe..e151565 100644 --- a/mio/lib/mio-http.h +++ b/mio/lib/mio-http.h @@ -47,8 +47,8 @@ typedef mio_uintmax_t mio_http_range_int_t; enum mio_http_range_type_t { - MIO_HTTP_RANGE_NONE, MIO_HTTP_RANGE_PROPER, + MIO_HTTP_RANGE_PREFIX, MIO_HTTP_RANGE_SUFFIX }; typedef enum mio_http_range_type_t mio_http_range_type_t; @@ -56,19 +56,14 @@ typedef enum mio_http_range_type_t mio_http_range_type_t; * The mio_http_range_t type defines a structure that can represent * a value for the \b Range: http header. * - * If type is #MIO_HTTP_RANGE_NONE, this range is not valid. + * If type is #MIO_HTTP_RANGE_PREFIX, 'to' is meaningless and 'from' indicates + * the number of bytes from the start. + * - 500- => from the 501st bytes all the way to the back. * - * If type is #MIO_HTTP_RANGE_SUFFIX, 'from' is meaningleass and 'to' indicates + * If type is #MIO_HTTP_RANGE_SUFFIX, 'from' is meaningless and 'to' indicates * the number of bytes from the back. * - -500 => last 500 bytes * - * You should adjust a range when the size that this range belongs to is - * made known. See this code: - * \code - * range.from = total_size - range.to; - * range.to = range.to + range.from - 1; - * \endcode - * * If type is #MIO_HTTP_RANGE_PROPER, 'from' and 'to' represents a proper range * where the value of 0 indicates the first byte. This doesn't require any * adjustment.