wrote some code in http-fil.c

This commit is contained in:
hyung-hwan 2020-07-13 10:01:42 +00:00
parent 953dbd730b
commit 59fc7d23a0
4 changed files with 127 additions and 61 deletions

View File

@ -1088,7 +1088,7 @@ static int fmt_outv (mio_fmtout_t* fmtout, va_list ap)
sign = 0; sign = 0;
if (lm_flag & LF_J) 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_OOW_T) && \
(MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \ (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \
(MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_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: handle_sign:
if (lm_flag & LF_J) if (lm_flag & LF_J)
{ {
#if defined(__GNUC__) && \ #if 0 && defined(__GNUC__) && \
(MIO_SIZEOF_INTMAX_T > MIO_SIZEOF_OOI_T) && \ (MIO_SIZEOF_INTMAX_T > MIO_SIZEOF_OOI_T) && \
(MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \ (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \
(MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG) (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG)

View File

@ -38,7 +38,6 @@
enum file_state_res_mode_t enum file_state_res_mode_t
{ {
FILE_STATE_RES_MODE_CHUNKED,
FILE_STATE_RES_MODE_CLOSE, FILE_STATE_RES_MODE_CLOSE,
FILE_STATE_RES_MODE_LENGTH 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_client;
mio_oow_t num_pending_writes_to_peer; mio_oow_t num_pending_writes_to_peer;
int 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_svc_htts_cli_t* client;
mio_http_version_t req_version; /* client request */ mio_http_version_t req_version; /* client request */
@ -81,6 +84,8 @@ struct file_state_t
}; };
typedef struct file_state_t 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) 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; 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; if (!file_state->keep_alive && file_state_write_to_client(file_state, MIO_NULL, 0) <= -1) return -1;
return 0; 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 */ /* if the connect is keep-alive, this part may not be called */
file_state->num_pending_writes_to_client--; 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_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); 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. /* 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; mio_dev_pro_read(file_state->peer, MIO_DEV_PRO_OUT, 1) <= -1) goto oops;
} }
#endif #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) 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_svc_htts_cli_t* cli = file_state->client;
mio_bch_t dtbuf[64]; mio_bch_t dtbuf[64];
mio_uintmax_t content_length;
mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf));
if (!force_close) force_close = !file_state->keep_alive; 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, file_state->req_version.major, file_state->req_version.minor,
status_code, mio_http_status_to_bcstr(status_code), status_code, mio_http_status_to_bcstr(status_code),
cli->htts->server_name, dtbuf, cli->htts->server_name, dtbuf,
(force_close? "close": "keep-alive"), (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)); 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?? */ mio_bch_t buf[8192]; /* TODO: declare this in file_state?? */
int i; mio_uintmax_t lim;
ssize_t n; 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)); /* 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 (n == -1)
{ {
if (errno == EAGAIN) 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) else if (errno == EINTR)
{ {
return 0; /* interrupted */
} }
return -1;
} }
else if (n == 0) else if (n == 0)
{ {
/* no more data to read */ /* no more data to read - this must not happend unless file size changed while the file is open. */
file_state_mark_over (file_state, FILE_STATE_OVER_READ_FROM_CLIENT); /* TODO: I probably must close the connection by force??? */
break; 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) if (file_state_write_to_client(file_state, buf, n) <= -1)
{ {
return -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; 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? */ /* 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); 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; struct stat st;
const mio_htre_hdrval_t* tmp;
if (fstat(file_state->peer, &st) <= -1) goto oops; if (fstat(file_state->peer, &st) <= -1) goto oops;
file_state->part_size = st.st_size; file_state->end_offset = st.st_size;
file_state->part_size = MIO_TYPE_MAX(mio_intmax_t);
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)
file_peer = mio_dev_pro_getxtn(file_state->peer); {
MIO_SVC_HTTS_RSRC_ATTACH (file_state, file_peer->state); 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) #if !defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
@ -661,8 +733,7 @@ XXXXXXXXXXXX
if (req->flags & MIO_HTRE_ATTR_KEEPALIVE) if (req->flags & MIO_HTRE_ATTR_KEEPALIVE)
{ {
file_state->keep_alive = 1; file_state->keep_alive = 1;
file_state->res_mode_to_cli = FILE_STATE_RES_MODE_CHUNKED; file_state->res_mode_to_cli = FILE_STATE_RES_MODE_LENGTH;
/* the mode still can get switched to FILE_STATE_RES_MODE_LENGTH if the file emits Content-Length */
} }
else else
{ {

View File

@ -225,7 +225,7 @@ int mio_parse_http_range_bcstr (const mio_bch_t* str, mio_http_range_t* range)
str += 6; str += 6;
from = 0; from = to = 0;
if (mio_is_bch_digit(*str)) if (mio_is_bch_digit(*str))
{ {
do do
@ -249,10 +249,10 @@ int mio_parse_http_range_bcstr (const mio_bch_t* str, mio_http_range_t* range)
str++; str++;
} }
while (mio_is_bch_digit(*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->type = type;
range->from = from; range->from = from;

View File

@ -47,8 +47,8 @@ typedef mio_uintmax_t mio_http_range_int_t;
enum mio_http_range_type_t enum mio_http_range_type_t
{ {
MIO_HTTP_RANGE_NONE,
MIO_HTTP_RANGE_PROPER, MIO_HTTP_RANGE_PROPER,
MIO_HTTP_RANGE_PREFIX,
MIO_HTTP_RANGE_SUFFIX MIO_HTTP_RANGE_SUFFIX
}; };
typedef enum mio_http_range_type_t mio_http_range_type_t; 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 * The mio_http_range_t type defines a structure that can represent
* a value for the \b Range: http header. * 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. * the number of bytes from the back.
* - -500 => last 500 bytes * - -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 * 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 * where the value of 0 indicates the first byte. This doesn't require any
* adjustment. * adjustment.