|  |  |  | @ -10,6 +10,7 @@ | 
		
	
		
			
				|  |  |  |  | #include <sys/stat.h> | 
		
	
		
			
				|  |  |  |  | #include <pthread.h> | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #define CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | typedef struct mio_svc_htts_cli_t mio_svc_htts_cli_t; | 
		
	
		
			
				|  |  |  |  | struct mio_svc_htts_cli_t | 
		
	
	
		
			
				
					
					|  |  |  | @ -120,7 +121,7 @@ static int test_func_handler (int rfd, int wfd) | 
		
	
		
			
				|  |  |  |  | 	return -1; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, int peek) | 
		
	
		
			
				|  |  |  |  | static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	//server_xtn_t* server_xtn = GET_SERVER_XTN(htts, client->server); | 
		
	
		
			
				|  |  |  |  | 	//mio_htts_task_t* task; | 
		
	
	
		
			
				
					
					|  |  |  | @ -133,18 +134,13 @@ static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_ | 
		
	
		
			
				|  |  |  |  | 	 * any more. once it's decoded in the peek mode, | 
		
	
		
			
				|  |  |  |  | 	 * the decoded query path is made available in the | 
		
	
		
			
				|  |  |  |  | 	 * non-peek mode as well */ | 
		
	
		
			
				|  |  |  |  | 	if (peek)  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		mio_htre_perdecqpath(req); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	mio_htre_perdecqpath(req); | 
		
	
		
			
				|  |  |  |  | 	/* TODO: proper request logging */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG2 (htts->mio, "[PEEK] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | else | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	MIO_DEBUG2 (htts->mio, "[NOPEEK] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 	MIO_DEBUG2 (htts->mio, "[REQ] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | mio_printf (MIO_T("================================\n")); | 
		
	
	
		
			
				
					
					|  |  |  | @ -168,8 +164,6 @@ if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	mth = mio_htre_getqmethodtype(req); | 
		
	
		
			
				|  |  |  |  | 	if (peek) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 	/* determine what to do once the header fields are all received. | 
		
	
		
			
				|  |  |  |  | 	 * i don't want to delay this until the contents are received. | 
		
	
		
			
				|  |  |  |  | 	 * if you don't like this behavior, you must implement your own | 
		
	
	
		
			
				
					
					|  |  |  | @ -187,6 +181,7 @@ if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | 	if (mth == MIO_HTTP_CONNECT) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* CONNECT method must not have content set.  | 
		
	
	
		
			
				
					
					|  |  |  | @ -198,6 +193,9 @@ if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | /* this part can be check in actual mio_svc_htts_doXXX() functions. | 
		
	
		
			
				|  |  |  |  |  * some doXXX handlers may not require length for POST. | 
		
	
		
			
				|  |  |  |  |  * it may be able to simply accept till EOF? or  treat as if CONTENT_LENGTH is 0*/ | 
		
	
		
			
				|  |  |  |  | 		if (mth == MIO_HTTP_POST && !(req->flags & (MIO_HTRE_ATTR_LENGTH | MIO_HTRE_ATTR_CHUNKED))) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* POST without Content-Length nor not chunked */ | 
		
	
	
		
			
				
					
					|  |  |  | @ -207,7 +205,9 @@ if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | 			if (mio_svc_htts_sendstatus(htts, csck, req, 411, MIO_NULL) <= -1) mio_dev_sck_halt (csck); /*TODO: redo this sendstatus */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  | 			const mio_bch_t* qpath = mio_htre_getqpath(req); | 
		
	
		
			
				|  |  |  |  | 			if (mio_svc_htts_docgi(htts, csck, req, "") <= -1) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
	
		
			
				
					
					|  |  |  | @ -228,33 +228,7 @@ if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | 				mio_htre_discardcontent (req); | 
		
	
		
			
				|  |  |  |  | 				mio_dev_sck_halt (csck); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* contents are all received */ | 
		
	
		
			
				|  |  |  |  | 		if (mth == MIO_HTTP_CONNECT) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			MIO_DEBUG1 (htts->mio, "Switching HTRD to DUMMY for [%hs]\n", mio_htre_getqpath(req)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			/* Switch the http reader to a dummy mode so that the subsqeuent | 
		
	
		
			
				|  |  |  |  | 			 * input(request) is just treated as data to the request just  | 
		
	
		
			
				|  |  |  |  | 			 * completed */ | 
		
	
		
			
				|  |  |  |  | 			mio_htrd_dummify (cli->htrd); | 
		
	
		
			
				|  |  |  |  | 			/* connect is not handled in the peek mode. create a proxy resource here */ | 
		
	
		
			
				|  |  |  |  | 			/* TODO: arrange to forward all raw bytes */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else if (req->flags & MIO_HTRE_ATTR_PROXIED) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* the contents should be proxied.  | 
		
	
		
			
				|  |  |  |  | 			 * do nothing locally */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* when the request is handled locally,  | 
		
	
		
			
				|  |  |  |  | 			 * there's nothing special to do here */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -266,6 +240,7 @@ if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | ////			if (MIO_UNLIKELY(!task)) goto oops; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -278,20 +253,15 @@ static int client_htrd_peek_request (mio_htrd_t* htrd, mio_htre_t* req) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	htrd_xtn_t* htrdxtn = (htrd_xtn_t*)mio_htrd_getxtn(htrd); | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* sckxtn = (mio_svc_htts_cli_t*)mio_dev_sck_getxtn(htrdxtn->sck); | 
		
	
		
			
				|  |  |  |  | 	return process_request(sckxtn->htts, htrdxtn->sck, req, 1); | 
		
	
		
			
				|  |  |  |  | 	return process_request(sckxtn->htts, htrdxtn->sck, req); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int client_htrd_poke_request (mio_htrd_t* htrd, mio_htre_t* req) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	htrd_xtn_t* htrdxtn = (htrd_xtn_t*)mio_htrd_getxtn(htrd); | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* sckxtn = (mio_svc_htts_cli_t*)mio_dev_sck_getxtn(htrdxtn->sck); | 
		
	
		
			
				|  |  |  |  | 	return process_request(sckxtn->htts, htrdxtn->sck, req, 0); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static mio_htrd_recbs_t client_htrd_recbs = | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	client_htrd_peek_request, | 
		
	
		
			
				|  |  |  |  | 	client_htrd_poke_request | 
		
	
		
			
				|  |  |  |  | 	MIO_NULL, | 
		
	
		
			
				|  |  |  |  | 	MIO_NULL | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int init_client (mio_svc_htts_cli_t* cli, mio_dev_sck_t* sck) | 
		
	
	
		
			
				
					
					|  |  |  | @ -728,10 +698,11 @@ struct cgi_state_t | 
		
	
		
			
				|  |  |  |  | 	mio_htrd_t* peer_htrd; | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* cli; | 
		
	
		
			
				|  |  |  |  | 	mio_http_version_t req_version; /* client request */ | 
		
	
		
			
				|  |  |  |  | 	mio_oow_t req_content_length; /* client request content length */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	cgi_state_res_mode_t res_mode_to_cli; | 
		
	
		
			
				|  |  |  |  | 	unsigned int req_content_length_unlimited: 1; | 
		
	
		
			
				|  |  |  |  | 	unsigned int peer_eof: 1; | 
		
	
		
			
				|  |  |  |  | 	mio_oow_t req_content_length; /* client request content length */ | 
		
	
		
			
				|  |  |  |  | 	cgi_state_res_mode_t res_mode_to_cli; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	mio_dev_sck_on_read_t cli_org_on_read; | 
		
	
		
			
				|  |  |  |  | 	mio_dev_sck_on_write_t cli_org_on_write; | 
		
	
	
		
			
				
					
					|  |  |  | @ -759,6 +730,71 @@ static void cgi_state_halt (cgi_state_t* cgi_state) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_state_write_to_client (cgi_state_t* cgi_state, const void* data, mio_iolen_t dlen) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	cgi_state->num_pending_writes_to_client++; | 
		
	
		
			
				|  |  |  |  | 	if (mio_dev_sck_write(cgi_state->cli->sck, data, dlen, MIO_NULL, MIO_NULL) <= -1)  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->num_pending_writes_to_client > CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_pro_read(cgi_state->peer, MIO_DEV_PRO_OUT, 0) <= -1) return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_state_writev_to_client (cgi_state_t* cgi_state, mio_iovec_t* iov, mio_iolen_t iovcnt) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	cgi_state->num_pending_writes_to_client++; | 
		
	
		
			
				|  |  |  |  | 	if (mio_dev_sck_writev(cgi_state->cli->sck, iov, iovcnt, MIO_NULL, MIO_NULL) <= -1)  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->num_pending_writes_to_client > CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_pro_read(cgi_state->peer, MIO_DEV_PRO_OUT, 0) <= -1) return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_state_write_to_peer (cgi_state_t* cgi_state, const void* data, mio_iolen_t dlen) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	cgi_state->num_pending_writes_to_peer++; | 
		
	
		
			
				|  |  |  |  | 	if (mio_dev_pro_write(cgi_state->peer, data, dlen, MIO_NULL) <= -1)  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_peer--; | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: check if it's already finished or something.. */ | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->num_pending_writes_to_peer > CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_sck_read(cgi_state->cli->sck, 0) <= -1) return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_state_send_final_status_to_client (cgi_state_t* cgi_state, int status_code) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* cli = cgi_state->cli; | 
		
	
		
			
				|  |  |  |  | 	mio_bch_t dtbuf[64]; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", | 
		
	
		
			
				|  |  |  |  | 		cgi_state->req_version.major, cgi_state->req_version.minor, | 
		
	
		
			
				|  |  |  |  | 		status_code, mio_http_status_to_bcstr(status_code), | 
		
	
		
			
				|  |  |  |  | 		cli->htts->server_name, dtbuf) == (mio_oow_t)-1) return -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return cgi_state_write_to_client(cgi_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf)); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void cgi_state_on_kill (cgi_state_t* cgi_state) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | printf ("**** CGI_STATE_ON_KILL \n"); | 
		
	
	
		
			
				
					
					|  |  |  | @ -792,7 +828,7 @@ printf ("**** CGI_STATE_ON_KILL \n"); | 
		
	
		
			
				|  |  |  |  | 		cgi_state->cli_org_on_write = MIO_NULL; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	cgi_state->cli->htrd->recbs.push_content = MIO_NULL; | 
		
	
		
			
				|  |  |  |  | 	mio_htrd_setrecbs (cgi_state->cli->htrd, &client_htrd_recbs); /* restore the callbacks */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (MIO_BECS_LEN(&cgi_state->cli->rbuf) > 0) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
	
		
			
				
					
					|  |  |  | @ -806,21 +842,6 @@ printf ("**** CGI_STATE_ON_KILL \n"); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_send_simple_status_to_client (cgi_state_t* cgi_state, int status_code) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* cli = cgi_state->cli; | 
		
	
		
			
				|  |  |  |  | 	mio_bch_t dtbuf[64]; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", | 
		
	
		
			
				|  |  |  |  | 		cgi_state->req_version.major, cgi_state->req_version.minor, | 
		
	
		
			
				|  |  |  |  | 		status_code, mio_http_status_to_bcstr(status_code), | 
		
	
		
			
				|  |  |  |  | 		cli->htts->server_name, dtbuf) == (mio_oow_t)-1) return -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return mio_dev_sck_write(cli->sck, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf), MIO_NULL, MIO_NULL); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	mio_t* mio = pro->mio; | 
		
	
	
		
			
				
					
					|  |  |  | @ -829,6 +850,7 @@ static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (!cgi_state) return; /* cgi state already gone */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf (">>>>>>>>> PEER ON CLOSE sid=%d\n", (int)sid); | 
		
	
		
			
				|  |  |  |  | printf (">> cgi_state %p\n", cgi_state); | 
		
	
		
			
				|  |  |  |  | printf (">> cgi_state->peer %p\n", cgi_state->peer); | 
		
	
		
			
				|  |  |  |  | printf (">> cgi_state->cli %p\n", cgi_state->cli); | 
		
	
	
		
			
				
					
					|  |  |  | @ -844,9 +866,15 @@ printf (">> cgi_state->cli->htts %p\n", cgi_state->cli->htts); | 
		
	
		
			
				|  |  |  |  | 		MIO_ASSERT (mio, cgi_state->peer == pro); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG4 (mio, "HTTS(%p) - peer %p(pid=%d) closing slave[%d]\n", cgi_state->cli->htts, pro, (int)pro->child_pid, sid); | 
		
	
		
			
				|  |  |  |  | 		if (sid == MIO_DEV_PRO_OUT) | 
		
	
		
			
				|  |  |  |  | 		if (sid == MIO_DEV_PRO_OUT && !cgi_state->peer_eof) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | /* check if it's sending... */ | 
		
	
		
			
				|  |  |  |  | 			cgi_state->peer_eof = 1; | 
		
	
		
			
				|  |  |  |  | 			if (cgi_state->res_mode_to_cli == CGI_STATE_RES_MODE_CHUNKED && | 
		
	
		
			
				|  |  |  |  | 			    cgi_state_write_to_client(cgi_state, "0\r\n\r\n", 5) <= -1)  | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				cgi_state_halt (cgi_state); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @ -859,6 +887,7 @@ static int cgi_peer_on_read (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid, const vo | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	MIO_ASSERT (mio, sid == MIO_DEV_PRO_OUT); /* since MIO_DEV_PRO_ERRTONUL is used, there should be no input from MIO_DEV_PRO_ERR */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf (">>>>>>>>> PEER ON READ %d\n", dlen); | 
		
	
		
			
				|  |  |  |  | 	if (dlen <= -1) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTPS(%p) - read error from peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (unsigned int)pro->child_pid); | 
		
	
	
		
			
				
					
					|  |  |  | @ -872,9 +901,8 @@ static int cgi_peer_on_read (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid, const vo | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTPS(%p) - EOF from peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (unsigned int)pro->child_pid); | 
		
	
		
			
				|  |  |  |  | 		cgi_state->peer_eof = 1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		/* don't care about cgi_state->num_pending_writes_to_client since this is the last read */ | 
		
	
		
			
				|  |  |  |  | 		if (cgi_state->res_mode_to_cli == CGI_STATE_RES_MODE_CHUNKED && | 
		
	
		
			
				|  |  |  |  | 		    mio_dev_sck_write(cgi_state->cli->sck, "0\r\n\r\n", 5, MIO_NULL, MIO_NULL) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 		    cgi_state_write_to_client(cgi_state, "0\r\n\r\n", 5) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
	
		
			
				
					
					|  |  |  | @ -883,7 +911,7 @@ printf ( "QQQQQQQQQQQQQQQQQQ>>>>>>>>>>>>>>>>>> feeding to peer htrd.... dlen => | 
		
	
		
			
				|  |  |  |  | 		if (mio_htrd_feed(cgi_state->peer_htrd, data, dlen, &rem) <= -1)  | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | printf ( "FEEDING FAILURE TO PEER HTDDRD.. dlen => %d\n", (int)dlen); | 
		
	
		
			
				|  |  |  |  | 			cgi_send_simple_status_to_client (cgi_state, 500); /* don't care about error */ | 
		
	
		
			
				|  |  |  |  | 			cgi_state_send_final_status_to_client (cgi_state, 500); /* don't care about error */ | 
		
	
		
			
				|  |  |  |  | 			goto oops; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		if (rem > 0)  | 
		
	
	
		
			
				
					
					|  |  |  | @ -980,7 +1008,17 @@ printf ("CGI PEER HTRD PEEK...\n"); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (mio_becs_cat(cli->sbuf, "\r\n") == (mio_oow_t)-1) return -1; | 
		
	
		
			
				|  |  |  |  | 	return mio_dev_sck_write(cli->sck, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf), MIO_NULL, MIO_NULL); | 
		
	
		
			
				|  |  |  |  | 	return cgi_state_write_to_client(cgi_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf)); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_peer_htrd_poke (mio_htrd_t* htrd, mio_htre_t* req) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	/* client request got completed */ | 
		
	
		
			
				|  |  |  |  | 	cgi_peer_xtn_t* cgi_peer = mio_htrd_getxtn(htrd); | 
		
	
		
			
				|  |  |  |  | 	cgi_state_t* cgi_state = cgi_peer->state; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* indicate EOF to the client */ | 
		
	
		
			
				|  |  |  |  | 	return cgi_state_write_to_client(cgi_state, MIO_NULL, 0); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_peer_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, const mio_bch_t* data, mio_oow_t dlen) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1009,23 +1047,14 @@ static int cgi_peer_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, const | 
		
	
		
			
				|  |  |  |  | 			iov[2].iov_ptr = "\r\n"; | 
		
	
		
			
				|  |  |  |  | 			iov[2].iov_len = 2; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			cgi_state->num_pending_writes_to_client++; | 
		
	
		
			
				|  |  |  |  | 			if (mio_dev_sck_writev(cgi_state->cli->sck, iov, MIO_COUNTOF(iov), MIO_NULL, MIO_NULL) <= -1) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 				goto oops; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if (cgi_state_writev_to_client(cgi_state, iov, MIO_COUNTOF(iov)) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		case CGI_STATE_RES_MODE_CLOSE: | 
		
	
		
			
				|  |  |  |  | 		case CGI_STATE_RES_MODE_LENGTH: | 
		
	
		
			
				|  |  |  |  | 			cgi_state->num_pending_writes_to_client++; | 
		
	
		
			
				|  |  |  |  | 			if (mio_dev_sck_write(cgi_state->cli->sck, data, dlen, MIO_NULL, MIO_NULL) <= -1) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 				goto oops; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if (cgi_state_write_to_client(cgi_state, data, dlen) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->num_pending_writes_to_client > CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1042,10 +1071,22 @@ oops: | 
		
	
		
			
				|  |  |  |  | static mio_htrd_recbs_t cgi_peer_htrd_recbs = | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	cgi_peer_htrd_peek, | 
		
	
		
			
				|  |  |  |  | 	MIO_NULL, | 
		
	
		
			
				|  |  |  |  | 	cgi_peer_htrd_poke, | 
		
	
		
			
				|  |  |  |  | 	cgi_peer_htrd_push_content | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_client_htrd_poke (mio_htrd_t* htrd, mio_htre_t* req) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	/* client request got completed */ | 
		
	
		
			
				|  |  |  |  | 	htrd_xtn_t* htrdxtn = mio_htrd_getxtn(htrd); | 
		
	
		
			
				|  |  |  |  | 	mio_dev_sck_t* sck = htrdxtn->sck; | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); | 
		
	
		
			
				|  |  |  |  | 	cgi_state_t* cgi_state = RSRCL_FIRST_RSRC(&cli->rsrc); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* indicate EOF to the client peer */ | 
		
	
		
			
				|  |  |  |  | 	return cgi_state_write_to_peer(cgi_state, MIO_NULL, 0); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_client_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, const mio_bch_t* data, mio_oow_t dlen) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	htrd_xtn_t* htrdxtn = mio_htrd_getxtn(htrd); | 
		
	
	
		
			
				
					
					|  |  |  | @ -1054,25 +1095,7 @@ static int cgi_client_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, cons | 
		
	
		
			
				|  |  |  |  | 	cgi_state_t* cgi_state = RSRCL_FIRST_RSRC(&cli->rsrc); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	MIO_ASSERT (sck->mio, cli->sck == sck); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	cgi_state->num_pending_writes_to_peer++; | 
		
	
		
			
				|  |  |  |  | 	if (mio_dev_pro_write(cgi_state->peer, data, dlen, MIO_NULL) <= -1)  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_peer--; | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->num_pending_writes_to_peer > CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_sck_read(cli->sck, 0) <= -1) goto oops; /* disable input watching */ | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | oops: | 
		
	
		
			
				|  |  |  |  | 	return -1; | 
		
	
		
			
				|  |  |  |  | 	return cgi_state_write_to_peer(cgi_state, data, dlen); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1088,6 +1111,19 @@ static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTS(%p) - unable to write to peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (int)pro->child_pid); | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if (wrlen == 0) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* indicated EOF */ | 
		
	
		
			
				|  |  |  |  | 		/* do nothing here as i didn't incremented num_pending_writes_to_peer when making the write request */ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_peer--; | 
		
	
		
			
				|  |  |  |  | 		MIO_ASSERT (mio, cgi_state->num_pending_writes_to_peer == 0); | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (int)pro->child_pid); | 
		
	
		
			
				|  |  |  |  | 		/* indicated EOF to the peer side. i need no more data from the client side. | 
		
	
		
			
				|  |  |  |  | 		 * i don't need to enable input watching in the client side either */ | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		MIO_ASSERT (mio, cgi_state->num_pending_writes_to_peer > 0); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_peer--; | 
		
	
		
			
				|  |  |  |  | 		if (cgi_state->num_pending_writes_to_peer == CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1095,6 +1131,8 @@ static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx | 
		
	
		
			
				|  |  |  |  | 			// TODO: check if (cli has anything to read...) if so ... | 
		
	
		
			
				|  |  |  |  | 			if (mio_dev_sck_read(cgi_state->cli->sck, 1) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | oops: | 
		
	
	
		
			
				
					
					|  |  |  | @ -1130,7 +1168,8 @@ printf ("** HTTS - cgi client read   %p  %d -> htts:%p\n", sck, (int)len, cli->h | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* EOF on the client side. arrange to close */ | 
		
	
		
			
				|  |  |  |  | printf ("asking pro to close...\n"); | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_pro_write(cgi_state->peer, MIO_NULL, 0, MIO_NULL) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | /* HAVE I ALREADY CLOSED IT??? Check conflict is the poke handler */ | 
		
	
		
			
				|  |  |  |  | 		return cgi_state_write_to_peer(cgi_state, MIO_NULL, 0); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
	
		
			
				
					
					|  |  |  | @ -1164,10 +1203,24 @@ static int cgi_client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrc | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (wrlen <= -1) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTPS(%p) - unable to write to client socket %p(%d)\n", sck->mio, sck, (int)sck->hnd); | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTPS(%p) - unable to write to client %p(%d)\n", sck->mio, sck, (int)sck->hnd); | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (wrlen == 0) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* if the connect is keep-alive, this part may not be called */ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 		MIO_ASSERT (mio, cgi_state->num_pending_writes_to_client == 0); | 
		
	
		
			
				|  |  |  |  | 		MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to client %p(%d)\n", cgi_state->cli->htts, sck, (int)sck->hnd); | 
		
	
		
			
				|  |  |  |  | 		/* since EOF has been indicated to the client, it must not write to the client any further. | 
		
	
		
			
				|  |  |  |  | 		 * this also means that i don't need any data from the peer side either. | 
		
	
		
			
				|  |  |  |  | 		 * i don't need to enable input watching on the peer side */ | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		MIO_ASSERT (mio, cgi_state->num_pending_writes_to_client > 0); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	printf ("MANAGED TO WRITE TO CLIENT>... %d\n", (int)wrlen); | 
		
	
		
			
				|  |  |  |  | 		cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 		if (cgi_state->peer && cgi_state->num_pending_writes_to_client == CGI_STATE_PENDING_IO_THRESHOLD) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1183,6 +1236,7 @@ printf ("MANAGED TO WRITE TO CLIENT>... %d\n", (int)wrlen); | 
		
	
		
			
				|  |  |  |  | 			cgi_state_halt (cgi_state); // must not use this... must kill the state ...  | 
		
	
		
			
				|  |  |  |  | 			/* finished writing all */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -1193,12 +1247,7 @@ oops: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int get_request_content_length (mio_htre_t* req, mio_oow_t* len) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	if (req->state & (MIO_HTRE_COMPLETED | MIO_HTRE_DISCARDED)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* no more content to receive */ | 
		
	
		
			
				|  |  |  |  | 		*len = mio_htre_getcontentlen(req); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if (req->flags & MIO_HTRE_ATTR_CHUNKED) | 
		
	
		
			
				|  |  |  |  | 	if (req->flags & MIO_HTRE_ATTR_CHUNKED) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* "Transfer-Encoding: chunked" take precedence over "Content-Length: XXX".  | 
		
	
		
			
				|  |  |  |  | 		 * | 
		
	
	
		
			
				
					
					|  |  |  | @ -1206,7 +1255,6 @@ static int get_request_content_length (mio_htre_t* req, mio_oow_t* len) | 
		
	
		
			
				|  |  |  |  | 		 *  If a message is received with both a Transfer-Encoding and a | 
		
	
		
			
				|  |  |  |  | 		 *  Content-Length header field, the Transfer-Encoding overrides the | 
		
	
		
			
				|  |  |  |  | 		 *  Content-Length. */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		return -1; /* unable to determine content-length in advance */ | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if (req->flags & MIO_HTRE_ATTR_LENGTH) | 
		
	
	
		
			
				
					
					|  |  |  | @ -1215,7 +1263,7 @@ static int get_request_content_length (mio_htre_t* req, mio_oow_t* len) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* no content */ | 
		
	
		
			
				|  |  |  |  | 		/* If no Content-Length is specified in a request, it's Content-Length: 0 */ | 
		
	
		
			
				|  |  |  |  | 		*len = 0; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
	
		
			
				
					
					|  |  |  | @ -1227,19 +1275,11 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck); | 
		
	
		
			
				|  |  |  |  | 	cgi_state_t* cgi_state = MIO_NULL; | 
		
	
		
			
				|  |  |  |  | 	cgi_peer_xtn_t* cgi_peer; | 
		
	
		
			
				|  |  |  |  | 	mio_oow_t req_content_length; | 
		
	
		
			
				|  |  |  |  | 	mio_dev_pro_make_t mi; | 
		
	
		
			
				|  |  |  |  | 	int enable_input; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (get_request_content_length(req, &req_content_length) <= -1) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* chunked - the length is not know in advance */ | 
		
	
		
			
				|  |  |  |  | 		/* don't start the process yet. */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		/* option 1. send 411 Length Required */ | 
		
	
		
			
				|  |  |  |  | 		/* option 2. support chunked message box in the request */ | 
		
	
		
			
				|  |  |  |  | 		/* option 3[non standard]. set CONTENT_LENGTH to -1 and indicate the end of INPUT by sending EOF */ | 
		
	
		
			
				|  |  |  |  | 		req_content_length = MIO_TYPE_MAX(mio_oow_t); /* TODO: change type or add another variable ? */ | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	/* ensure that you call this function before any contents is received */ | 
		
	
		
			
				|  |  |  |  | 	MIO_ASSERT (mio, mio_htre_getcontentlen(req) == 0); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	MIO_MEMSET (&mi, 0, MIO_SIZEOF(mi)); | 
		
	
		
			
				|  |  |  |  | 	mi.flags = MIO_DEV_PRO_READOUT | MIO_DEV_PRO_ERRTONUL | MIO_DEV_PRO_WRITEIN /*| MIO_DEV_PRO_FORGET_CHILD*/; | 
		
	
	
		
			
				
					
					|  |  |  | @ -1258,7 +1298,9 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | 
		
	
		
			
				|  |  |  |  | 	/*cgi_state->num_pending_writes_to_client = 0; | 
		
	
		
			
				|  |  |  |  | 	cgi_state->num_pending_writes_to_peer = 0;*/ | 
		
	
		
			
				|  |  |  |  | 	cgi_state->req_version = *mio_htre_getversion(req); | 
		
	
		
			
				|  |  |  |  | 	cgi_state->req_content_length = req_content_length; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	cgi_state->req_content_length_unlimited = 0; | 
		
	
		
			
				|  |  |  |  | 	if (get_request_content_length(req, &cgi_state->req_content_length) <= -1) cgi_state->req_content_length_unlimited = 1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	cgi_state->cli_org_on_read = csck->on_read; | 
		
	
		
			
				|  |  |  |  | 	cgi_state->cli_org_on_write = csck->on_write; | 
		
	
	
		
			
				
					
					|  |  |  | @ -1283,14 +1325,27 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	cgi_peer = mio_htrd_getxtn(cgi_state->peer_htrd); | 
		
	
		
			
				|  |  |  |  | 	cgi_peer->state = cgi_state; | 
		
	
		
			
				|  |  |  |  | /* TODO: any other handling before this? */ | 
		
	
		
			
				|  |  |  |  | /* I CAN't SIMPLY WRITE LIKE THIS, the cgi must require this. | 
		
	
		
			
				|  |  |  |  |  * send contents depending how cgi want Expect: continue handling to be handled */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if !defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->req_content_length_unlimited) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* Transfer-Encoding is chunked. no content-length is known in advance. */ | 
		
	
		
			
				|  |  |  |  | 		 | 
		
	
		
			
				|  |  |  |  | 		/* option 1. buffer contents. if it gets too large, send 413 Request Entity Too Large. | 
		
	
		
			
				|  |  |  |  | 		 * option 2. send 411 Length Required immediately | 
		
	
		
			
				|  |  |  |  | 		 * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (cgi_state_send_final_status_to_client(cgi_state, 411) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (req->flags & MIO_HTRE_ATTR_EXPECT100) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* TODO: Expect: 100-continue? who should handle this? cgi? or the http server? */ | 
		
	
		
			
				|  |  |  |  | 		if (mio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && req_content_length > 0) | 
		
	
		
			
				|  |  |  |  | 		/* CAN I LET the cgi SCRIPT handle this? */ | 
		
	
		
			
				|  |  |  |  | 		if (mio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&  | 
		
	
		
			
				|  |  |  |  | 		   (cgi_state->req_content_length_unlimited || cgi_state->req_content_length > 0))  | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/*  | 
		
	
		
			
				|  |  |  |  | 			 * Don't send 100 Continue if http verions is lower than 1.1 | 
		
	
	
		
			
				
					
					|  |  |  | @ -1309,47 +1364,55 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | 
		
	
		
			
				|  |  |  |  | 			mio_oow_t msglen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			msglen = mio_fmttobcstr(mio, msgbuf, MIO_COUNTOF(msgbuf), "HTTP/%d.%d 100 Continue\r\n\r\n", cgi_state->req_version.major, cgi_state->req_version.minor); | 
		
	
		
			
				|  |  |  |  | 			cgi_state->num_pending_writes_to_client++; | 
		
	
		
			
				|  |  |  |  | 			if (mio_dev_sck_write(csck, msgbuf, msglen, MIO_NULL, MIO_NULL) <= -1) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				cgi_state->num_pending_writes_to_client--; | 
		
	
		
			
				|  |  |  |  | 				goto oops; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if (cgi_state_write_to_client(cgi_state, msgbuf, msglen) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if (req->flags & MIO_HTRE_ATTR_EXPECT) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		mio_htre_discardcontent (req); | 
		
	
		
			
				|  |  |  |  | 		req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */ | 
		
	
		
			
				|  |  |  |  | 		if (mio_svc_htts_sendstatus(htts, csck, req, 417, MIO_NULL) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (req_content_length > 0) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (mio_htre_getcontentlen(req) > 0) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* this means that it's called from the peek context */ | 
		
	
		
			
				|  |  |  |  | 			cgi_state->num_pending_writes_to_peer++; | 
		
	
		
			
				|  |  |  |  | 			if (mio_dev_pro_write(cgi_state->peer, mio_htre_getcontentptr(req), mio_htre_getcontentlen(req), MIO_NULL) <= -1)  | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				cgi_state->num_pending_writes_to_peer--; | 
		
	
		
			
				|  |  |  |  | 		/* 417 Expectation Failed */ | 
		
	
		
			
				|  |  |  |  | 		cgi_state_send_final_status_to_client(cgi_state, 417); | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (req->state & (MIO_HTRE_COMPLETED | MIO_HTRE_DISCARDED)) | 
		
	
		
			
				|  |  |  |  | 	enable_input = 1; | 
		
	
		
			
				|  |  |  |  | #if defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) | 
		
	
		
			
				|  |  |  |  | 	if (cgi_state->req_content_length_unlimited) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* disable input watching from the client */ | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_sck_read(csck, 0) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 		/* Transfer-Encoding is chunked. no content-length is known in advance. */ | 
		
	
		
			
				|  |  |  |  | 		 | 
		
	
		
			
				|  |  |  |  | 		/* option 1. buffer contents. if it gets too large, send 413 Request Entity Too Large. | 
		
	
		
			
				|  |  |  |  | 		 * option 2. send 411 Length Required immediately | 
		
	
		
			
				|  |  |  |  | 		 * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: must set CONTENT-LENGTH to -1 before start the process */ | 
		
	
		
			
				|  |  |  |  | 		/* change the callbacks to subscribe to contents to be uploaded */ | 
		
	
		
			
				|  |  |  |  | 		cgi_state->cli->htrd->recbs.poke = cgi_client_htrd_poke; | 
		
	
		
			
				|  |  |  |  | 		cgi_state->cli->htrd->recbs.push_content = cgi_client_htrd_push_content; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (req_content_length > 0) | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  | 		if (cgi_state->req_content_length > 0) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 		 | 
		
	
		
			
				|  |  |  |  | 			/* change the callbacks to subscribe to contents to be uploaded */ | 
		
	
		
			
				|  |  |  |  | 			cgi_state->cli->htrd->recbs.poke = cgi_client_htrd_poke; | 
		
	
		
			
				|  |  |  |  | 			cgi_state->cli->htrd->recbs.push_content = cgi_client_htrd_push_content; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* no content to be uploaded from the client */ | 
		
	
		
			
				|  |  |  |  | 			/* indicate EOF to the peer and disable input wathching from the client */ | 
		
	
		
			
				|  |  |  |  | 			if (cgi_state_write_to_peer(cgi_state, MIO_NULL, 0) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 			enable_input = 0; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | #if defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* TODO: store current input watching state and use it when destroying the cgi_state data */ | 
		
	
		
			
				|  |  |  |  | 	if (mio_dev_sck_read(csck, enable_input) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* this may change later if Content-Length is included in the cgi output */ | 
		
	
		
			
				|  |  |  |  | 	cgi_state->res_mode_to_cli = (req->flags & MIO_HTRE_ATTR_KEEPALIVE)? CGI_STATE_RES_MODE_CHUNKED: CGI_STATE_RES_MODE_CLOSE; | 
		
	
	
		
			
				
					
					|  |  |  | @ -1357,6 +1420,8 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | oops: | 
		
	
		
			
				|  |  |  |  | 	MIO_DEBUG2 (mio, "HTTS(%p) - FAILURE in docgi - socket(%p)\n", htts, csck); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: can i call cgi_state_halt??? */ | 
		
	
		
			
				|  |  |  |  | 	cgi_state->on_kill (cgi_state); /* TODO: call rsrc_free... */ | 
		
	
		
			
				|  |  |  |  | 	mio_dev_sck_halt (csck); | 
		
	
		
			
				|  |  |  |  | 	return -1; | 
		
	
	
		
			
				
					
					|  |  |  | @ -1534,100 +1599,6 @@ oops: | 
		
	
		
			
				|  |  |  |  | 	return -1; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | int mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, int status_code, void* extra) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | /* TODO: change this to use send status */ | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck); | 
		
	
		
			
				|  |  |  |  | 	mio_bch_t text[1024]; /* TODO: make this buffer dynamic or scalable */ | 
		
	
		
			
				|  |  |  |  | 	mio_bch_t dtbuf[64]; | 
		
	
		
			
				|  |  |  |  | 	mio_oow_t x; | 
		
	
		
			
				|  |  |  |  | 	mio_http_version_t* version = mio_htre_getversion(req); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	const mio_bch_t* extrapre = "";  | 
		
	
		
			
				|  |  |  |  | 	const mio_bch_t* extrapst = ""; | 
		
	
		
			
				|  |  |  |  | 	const mio_bch_t* extraval = ""; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	text[0] = '\0'; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	switch (status_code) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | 		case 301: /* Moved Permanently */  | 
		
	
		
			
				|  |  |  |  | 		case 302: /* Found */ | 
		
	
		
			
				|  |  |  |  | 		case 303: /* See Other (since HTTP/1.1) */ | 
		
	
		
			
				|  |  |  |  | 		case 307: /* Temporary Redirect (since HTTP/1.1) */ | 
		
	
		
			
				|  |  |  |  | 		case 308: /* Permanent Redirect (Experimental RFC; RFC 7238) */ | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			mio_svc_htts_rsrc_reloc_t* reloc; | 
		
	
		
			
				|  |  |  |  | 			reloc = (mio_htts_rsrc_reloc_t*)extra; | 
		
	
		
			
				|  |  |  |  | 			extrapre = "Location: "; | 
		
	
		
			
				|  |  |  |  | 			extrapst = (reloc->flags & MIO_SVC_HTTS_RSRC_RELOC_APPENDSLASH)? "/\r\n": "\r\n"; | 
		
	
		
			
				|  |  |  |  | 			extraval = reloc->target; | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		case 304: | 
		
	
		
			
				|  |  |  |  | 		case 200: | 
		
	
		
			
				|  |  |  |  | 		case 201: | 
		
	
		
			
				|  |  |  |  | 		case 202: | 
		
	
		
			
				|  |  |  |  | 		case 203: | 
		
	
		
			
				|  |  |  |  | 		case 204: | 
		
	
		
			
				|  |  |  |  | 		case 205: | 
		
	
		
			
				|  |  |  |  | 		case 206: | 
		
	
		
			
				|  |  |  |  | 			/* nothing to do */ | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		default: | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | 			if (method != MIO_HTTP_HEAD && | 
		
	
		
			
				|  |  |  |  | 			    htts->opt.rcb.fmterr(htts, client, code, text, MIO_COUNTOF(text)) <= -1) return QSE_NULL; | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			if (status_code == 401) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				extrapre = "WWW-Authenticate: Basic realm=\""; | 
		
	
		
			
				|  |  |  |  | 				extrapst = "\"\r\n"; | 
		
	
		
			
				|  |  |  |  | 				extraval = (const mio_bch_t*)extra; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			break; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	mio_svc_htts_fmtgmtime(htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	x = mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %u\r\n%s%s%s\r\n%s", | 
		
	
		
			
				|  |  |  |  | 		version->major, version->minor, status_code, mio_http_status_to_bcstr(status_code),  | 
		
	
		
			
				|  |  |  |  | 		htts->server_name, | 
		
	
		
			
				|  |  |  |  | 		dtbuf, /* DATE */ | 
		
	
		
			
				|  |  |  |  | 		((req->flags & MIO_HTRE_ATTR_KEEPALIVE)? "keep-alive": "close"), /* connection */ | 
		
	
		
			
				|  |  |  |  | 		mio_count_bcstr(text), /* content length */ | 
		
	
		
			
				|  |  |  |  | 		extrapre, extraval, extraval, text | 
		
	
		
			
				|  |  |  |  | 	); | 
		
	
		
			
				|  |  |  |  | 	if (MIO_UNLIKELY(x == (mio_oow_t)-1)) return -1; | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: use timedwrite? */ | 
		
	
		
			
				|  |  |  |  | 	if (mio_dev_sck_write(csck, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf), MIO_NULL, MIO_NULL) <= -1) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		mio_dev_sck_halt (csck); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (!(req->flags & MIO_HTRE_ATTR_KEEPALIVE)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* arrange to close the writing end */ | 
		
	
		
			
				|  |  |  |  | 		if (mio_dev_sck_write(csck, MIO_NULL, 0, MIO_NULL, MIO_NULL) <= -1)  | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			mio_dev_sck_halt (csck); | 
		
	
		
			
				|  |  |  |  | 			return -1; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void mio_svc_htts_fmtgmtime (mio_svc_htts_t* htts, const mio_ntime_t* nt, mio_bch_t* buf, mio_oow_t len) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	mio_ntime_t now; | 
		
	
	
		
			
				
					
					|  |  |  | 
 |