| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |