added mio_svc_htts_dotxt()
This commit is contained in:
		| @ -937,6 +937,8 @@ if (mio_htre_getcontentlen(req) > 0) | ||||
| 			int x; | ||||
| 			if (mio_comp_bcstr_limited(qpath, "/thr/", 5, 1) == 0) | ||||
| 				x = mio_svc_htts_dothr(htts, csck, req, on_htts_thr_request, MIO_NULL); | ||||
| 			else if (mio_comp_bcstr_limited(qpath, "/txt/", 5, 1) == 0) | ||||
| 				x = mio_svc_htts_dotxt(htts, csck, req, 200, "text/plain", qpath); | ||||
| 			else | ||||
| 				x = mio_svc_htts_docgi(htts, csck, req, "", mio_htre_getqpath(req)); | ||||
| 			if (x <= -1) goto oops; | ||||
|  | ||||
| @ -59,6 +59,7 @@ libmio_la_SOURCES = \ | ||||
| 	http-cgi.c \ | ||||
| 	http-svr.c \ | ||||
| 	http-thr.c \ | ||||
| 	http-txt.c \ | ||||
| 	mio-prv.h \ | ||||
| 	mio.c \ | ||||
| 	nwif.c \ | ||||
|  | ||||
| @ -142,13 +142,13 @@ am_libmio_la_OBJECTS = libmio_la-chr.lo libmio_la-dns.lo \ | ||||
| 	libmio_la-dns-cli.lo libmio_la-ecs.lo libmio_la-err.lo \ | ||||
| 	libmio_la-fmt.lo libmio_la-htb.lo libmio_la-htrd.lo \ | ||||
| 	libmio_la-htre.lo libmio_la-http.lo libmio_la-http-cgi.lo \ | ||||
| 	libmio_la-http-svr.lo libmio_la-http-thr.lo libmio_la-mio.lo \ | ||||
| 	libmio_la-nwif.lo libmio_la-path.lo libmio_la-pipe.lo \ | ||||
| 	libmio_la-pro.lo libmio_la-sck.lo libmio_la-skad.lo \ | ||||
| 	libmio_la-sys.lo libmio_la-sys-ass.lo libmio_la-sys-err.lo \ | ||||
| 	libmio_la-sys-log.lo libmio_la-sys-mux.lo libmio_la-sys-tim.lo \ | ||||
| 	libmio_la-thr.lo libmio_la-tmr.lo libmio_la-utf8.lo \ | ||||
| 	libmio_la-utl.lo | ||||
| 	libmio_la-http-svr.lo libmio_la-http-thr.lo \ | ||||
| 	libmio_la-http-txt.lo libmio_la-mio.lo libmio_la-nwif.lo \ | ||||
| 	libmio_la-path.lo libmio_la-pipe.lo libmio_la-pro.lo \ | ||||
| 	libmio_la-sck.lo libmio_la-skad.lo libmio_la-sys.lo \ | ||||
| 	libmio_la-sys-ass.lo libmio_la-sys-err.lo libmio_la-sys-log.lo \ | ||||
| 	libmio_la-sys-mux.lo libmio_la-sys-tim.lo libmio_la-thr.lo \ | ||||
| 	libmio_la-tmr.lo libmio_la-utf8.lo libmio_la-utl.lo | ||||
| libmio_la_OBJECTS = $(am_libmio_la_OBJECTS) | ||||
| AM_V_lt = $(am__v_lt_@AM_V@) | ||||
| am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) | ||||
| @ -181,6 +181,7 @@ am__depfiles_remade = ./$(DEPDIR)/libmio_la-chr.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-http-cgi.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-http-svr.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-http-thr.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-http-txt.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-http.Plo ./$(DEPDIR)/libmio_la-mio.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-nwif.Plo ./$(DEPDIR)/libmio_la-path.Plo \ | ||||
| 	./$(DEPDIR)/libmio_la-pipe.Plo ./$(DEPDIR)/libmio_la-pro.Plo \ | ||||
| @ -449,6 +450,7 @@ libmio_la_SOURCES = \ | ||||
| 	http-cgi.c \ | ||||
| 	http-svr.c \ | ||||
| 	http-thr.c \ | ||||
| 	http-txt.c \ | ||||
| 	mio-prv.h \ | ||||
| 	mio.c \ | ||||
| 	nwif.c \ | ||||
| @ -580,6 +582,7 @@ distclean-compile: | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-http-cgi.Plo@am__quote@ # am--include-marker | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-http-svr.Plo@am__quote@ # am--include-marker | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-http-thr.Plo@am__quote@ # am--include-marker | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-http-txt.Plo@am__quote@ # am--include-marker | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-http.Plo@am__quote@ # am--include-marker | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio.Plo@am__quote@ # am--include-marker | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-nwif.Plo@am__quote@ # am--include-marker | ||||
| @ -720,6 +723,13 @@ libmio_la-http-thr.lo: http-thr.c | ||||
| @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||||
| @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-http-thr.lo `test -f 'http-thr.c' || echo '$(srcdir)/'`http-thr.c | ||||
|  | ||||
| libmio_la-http-txt.lo: http-txt.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-http-txt.lo -MD -MP -MF $(DEPDIR)/libmio_la-http-txt.Tpo -c -o libmio_la-http-txt.lo `test -f 'http-txt.c' || echo '$(srcdir)/'`http-txt.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-http-txt.Tpo $(DEPDIR)/libmio_la-http-txt.Plo | ||||
| @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http-txt.c' object='libmio_la-http-txt.lo' libtool=yes @AMDEPBACKSLASH@ | ||||
| @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||||
| @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-http-txt.lo `test -f 'http-txt.c' || echo '$(srcdir)/'`http-txt.c | ||||
|  | ||||
| libmio_la-mio.lo: mio.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-mio.lo -MD -MP -MF $(DEPDIR)/libmio_la-mio.Tpo -c -o libmio_la-mio.lo `test -f 'mio.c' || echo '$(srcdir)/'`mio.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-mio.Tpo $(DEPDIR)/libmio_la-mio.Plo | ||||
| @ -1006,6 +1016,7 @@ distclean: distclean-am | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-cgi.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-svr.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-thr.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-txt.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-mio.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-nwif.Plo | ||||
| @ -1082,6 +1093,7 @@ maintainer-clean: maintainer-clean-am | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-cgi.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-svr.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-thr.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http-txt.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-http.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-mio.Plo | ||||
| 	-rm -f ./$(DEPDIR)/libmio_la-nwif.Plo | ||||
|  | ||||
| @ -68,6 +68,7 @@ struct cgi_state_t | ||||
| 	unsigned int req_content_length_unlimited: 1; | ||||
| 	unsigned int ever_attempted_to_write_to_client: 1; | ||||
| 	unsigned int client_disconnected: 1; | ||||
| 	unsigned int client_htrd_recbs_changed: 1; | ||||
| 	mio_oow_t req_content_length; /* client request content length */ | ||||
| 	cgi_state_res_mode_t res_mode_to_cli; | ||||
|  | ||||
| @ -279,7 +280,11 @@ printf ("**** CGI_STATE_ON_KILL \n"); | ||||
| 		cgi_state->client_org_on_disconnect = MIO_NULL; | ||||
| 	} | ||||
|  | ||||
| 	mio_htrd_setrecbs (cgi_state->client->htrd, &cgi_state->client_htrd_org_recbs); /* restore the callbacks */ | ||||
| 	if (cgi_state->client_htrd_recbs_changed) | ||||
| 	{ | ||||
| 		/* restore the callbacks */ | ||||
| 		mio_htrd_setrecbs (cgi_state->client->htrd, &cgi_state->client_htrd_org_recbs); | ||||
| 	} | ||||
|  | ||||
| 	if (!cgi_state->client_disconnected) | ||||
| 	{ | ||||
| @ -1016,6 +1021,7 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | ||||
| 		cgi_state->client_htrd_org_recbs = *mio_htrd_getrecbs(cgi_state->client->htrd); | ||||
| 		cgi_client_htrd_recbs.peek = cgi_state->client_htrd_org_recbs.peek; | ||||
| 		mio_htrd_setrecbs (cgi_state->client->htrd, &cgi_client_htrd_recbs); | ||||
| 		cgi_state->client_htrd_recbs_changed = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -1026,6 +1032,7 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | ||||
| 			cgi_state->client_htrd_org_recbs = *mio_htrd_getrecbs(cgi_state->client->htrd); | ||||
| 			cgi_client_htrd_recbs.peek = cgi_state->client_htrd_org_recbs.peek; | ||||
| 			mio_htrd_setrecbs (cgi_state->client->htrd, &cgi_client_htrd_recbs); | ||||
| 			cgi_state->client_htrd_recbs_changed = 1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
|  | ||||
| @ -73,6 +73,7 @@ struct thr_state_t | ||||
| 	unsigned int req_content_length_unlimited: 1; | ||||
| 	unsigned int ever_attempted_to_write_to_client: 1; | ||||
| 	unsigned int client_disconnected: 1; | ||||
| 	unsigned int client_htrd_recbs_changed: 1; | ||||
| 	mio_oow_t req_content_length; /* client request content length */ | ||||
| 	thr_state_res_mode_t res_mode_to_cli; | ||||
|  | ||||
| @ -287,7 +288,11 @@ printf ("**** THR_STATE_ON_KILL \n"); | ||||
| 		thr_state->client_org_on_disconnect = MIO_NULL; | ||||
| 	} | ||||
|  | ||||
| 	mio_htrd_setrecbs (thr_state->client->htrd, &thr_state->client_htrd_org_recbs); /* restore the callbacks */ | ||||
| 	if (thr_state->client_htrd_recbs_changed) | ||||
| 	{ | ||||
| 		/* restore the callbacks */ | ||||
| 		mio_htrd_setrecbs (thr_state->client->htrd, &thr_state->client_htrd_org_recbs);  | ||||
| 	} | ||||
|  | ||||
| 	if (!thr_state->client_disconnected) | ||||
| 	{ | ||||
| @ -910,6 +915,7 @@ int mio_svc_htts_dothr (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | ||||
| 		thr_state->client_htrd_org_recbs = *mio_htrd_getrecbs(thr_state->client->htrd); | ||||
| 		thr_client_htrd_recbs.peek = thr_state->client_htrd_org_recbs.peek; | ||||
| 		mio_htrd_setrecbs (thr_state->client->htrd, &thr_client_htrd_recbs); | ||||
| 		thr_state->client_htrd_recbs_changed = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -920,6 +926,7 @@ int mio_svc_htts_dothr (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | ||||
| 			thr_state->client_htrd_org_recbs = *mio_htrd_getrecbs(thr_state->client->htrd); | ||||
| 			thr_client_htrd_recbs.peek = thr_state->client_htrd_org_recbs.peek; | ||||
| 			mio_htrd_setrecbs (thr_state->client->htrd, &thr_client_htrd_recbs); | ||||
| 			thr_state->client_htrd_recbs_changed = 1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
|  | ||||
| @ -24,36 +24,12 @@ | ||||
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #include "http-prv.h" | ||||
| #include <mio-txt.h> | ||||
| #include <mio-fmt.h> | ||||
| #include <mio-chr.h> | ||||
|  | ||||
| #define TXT_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH | ||||
|  | ||||
| enum txt_state_res_mode_t | ||||
| { | ||||
| 	TXT_STATE_RES_MODE_CHUNKED, | ||||
| 	TXT_STATE_RES_MODE_CLOSE, | ||||
| 	TXT_STATE_RES_MODE_LENGTH | ||||
| }; | ||||
| typedef enum txt_state_res_mode_t txt_state_res_mode_t; | ||||
|  | ||||
| #define TXT_STATE_PENDING_IO_TXTESHOLD 5 | ||||
|  | ||||
| #define TXT_STATE_OVER_READ_FROM_CLIENT (1 << 0) | ||||
| #define TXT_STATE_OVER_READ_FROM_PEER   (1 << 1) | ||||
| #define TXT_STATE_OVER_WRITE_TO_CLIENT  (1 << 2) | ||||
| #define TXT_STATE_OVER_WRITE_TO_PEER    (1 << 3) | ||||
| #define TXT_STATE_OVER_ALL (TXT_STATE_OVER_READ_FROM_CLIENT | TXT_STATE_OVER_READ_FROM_PEER | TXT_STATE_OVER_WRITE_TO_CLIENT | TXT_STATE_OVER_WRITE_TO_PEER) | ||||
|  | ||||
| struct txt_func_start_t | ||||
| { | ||||
| 	mio_t* mio; | ||||
| 	mio_svc_htts_txt_func_t txt_func; | ||||
| 	void* txt_ctx; | ||||
| 	mio_svc_htts_txt_func_info_t tfi; | ||||
| }; | ||||
| typedef struct txt_func_start_t txt_func_start_t; | ||||
| #define TXT_STATE_OVER_WRITE_TO_CLIENT  (1 << 1) | ||||
| #define TXT_STATE_OVER_ALL (TXT_STATE_OVER_READ_FROM_CLIENT | TXT_STATE_OVER_WRITE_TO_CLIENT) | ||||
|  | ||||
| struct txt_state_t | ||||
| { | ||||
| @ -63,21 +39,17 @@ struct txt_state_t | ||||
| 	mio_svc_htts_cli_t* client; | ||||
| 	mio_http_version_t req_version; /* client request */ | ||||
|  | ||||
| 	unsigned int over: 4; /* must be large enough to accomodate TXT_STATE_OVER_ALL */ | ||||
| 	unsigned int over: 2; /* must be large enough to accomodate TXT_STATE_OVER_ALL */ | ||||
| 	unsigned int keep_alive: 1; | ||||
| 	unsigned int req_content_length_unlimited: 1; | ||||
| 	unsigned int ever_attempted_to_write_to_client: 1; | ||||
| 	unsigned int client_disconnected: 1; | ||||
| 	unsigned int client_htrd_recbs_changed: 1; | ||||
| 	mio_oow_t req_content_length; /* client request content length */ | ||||
| 	txt_state_res_mode_t res_mode_to_cli; | ||||
|  | ||||
| 	mio_dev_sck_on_read_t client_org_on_read; | ||||
| 	mio_dev_sck_on_write_t client_org_on_write; | ||||
| 	mio_dev_sck_on_disconnect_t client_org_on_disconnect; | ||||
| 	mio_htrd_recbs_t client_htrd_org_recbs; | ||||
| 	 | ||||
|  | ||||
|  | ||||
| }; | ||||
| typedef struct txt_state_t txt_state_t; | ||||
|  | ||||
| @ -85,82 +57,63 @@ static void txt_state_halt_participating_devices (txt_state_t* txt_state) | ||||
| { | ||||
| 	MIO_ASSERT (txt_state->client->htts->mio, txt_state->client != MIO_NULL); | ||||
| 	MIO_ASSERT (txt_state->client->htts->mio, txt_state->client->sck != MIO_NULL); | ||||
|  | ||||
| 	MIO_DEBUG3 (txt_state->client->htts->mio, "HTTS(%p) - Halting participating devices in txt state %p(client=%p)\n", txt_state->client->htts, txt_state, txt_state->client->sck); | ||||
|  | ||||
|  | ||||
| 	mio_dev_sck_halt (txt_state->client->sck); | ||||
| } | ||||
|  | ||||
| static int txt_state_write_to_client (txt_state_t* txt_state, const void* data, mio_iolen_t dlen) | ||||
| { | ||||
| 	txt_state->ever_attempted_to_write_to_client = 1; | ||||
|  | ||||
| 	txt_state->num_pending_writes_to_client++; | ||||
| 	if (mio_dev_sck_write(txt_state->client->sck, data, dlen, MIO_NULL, MIO_NULL) <= -1)  | ||||
| 	{ | ||||
| 		txt_state->num_pending_writes_to_client--; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (txt_state->num_pending_writes_to_client > TXT_STATE_PENDING_IO_TXTESHOLD) | ||||
| 	{ | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| static int txt_state_writev_to_client (txt_state_t* txt_state, mio_iovec_t* iov, mio_iolen_t iovcnt) | ||||
| { | ||||
| 	txt_state->ever_attempted_to_write_to_client = 1; | ||||
|  | ||||
| 	txt_state->num_pending_writes_to_client++; | ||||
| 	if (mio_dev_sck_writev(txt_state->client->sck, iov, iovcnt, MIO_NULL, MIO_NULL) <= -1)  | ||||
| 	{ | ||||
| 		txt_state->num_pending_writes_to_client--; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (txt_state->num_pending_writes_to_client > TXT_STATE_PENDING_IO_TXTESHOLD) | ||||
| 	{ | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static int txt_state_send_final_status_to_client (txt_state_t* txt_state, int status_code, int force_close) | ||||
| static int txt_state_send_final_status_to_client (txt_state_t* txt_state, int status_code, const char* content_type, const char* content_text, int force_close) | ||||
| { | ||||
| 	mio_svc_htts_cli_t* cli = txt_state->client; | ||||
| 	mio_bch_t dtbuf[64]; | ||||
| 	mio_oow_t content_text_len = 0; | ||||
|  | ||||
| 	mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); | ||||
|  | ||||
| 	if (!force_close) force_close = !txt_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: 0\r\n\r\n", | ||||
|  | ||||
| 	if (mio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\n", | ||||
| 		txt_state->req_version.major, txt_state->req_version.minor, | ||||
| 		status_code, mio_http_status_to_bcstr(status_code), | ||||
| 		cli->htts->server_name, dtbuf, | ||||
| 		(force_close? "close": "keep-alive")) == (mio_oow_t)-1) return -1; | ||||
| 		(force_close? "close": "keep-alive"), | ||||
| 		(content_text? mio_count_bcstr(content_text): 0), (content_text? content_text: "")) == (mio_oow_t)-1) return -1; | ||||
|  | ||||
| 	if (content_text) | ||||
| 	{ | ||||
| 		content_text_len = mio_count_bcstr(content_text); | ||||
| 		if (content_type && mio_becs_fcat(cli->sbuf, "Content-Type: %hs\r\n", content_type) == (mio_oow_t)-1) return -1; | ||||
| 	} | ||||
| 	if (mio_becs_fcat(cli->sbuf, "Content-Length: %zu\r\n\r\n", content_text_len) == (mio_oow_t)-1) return -1; | ||||
|  | ||||
| 	return (txt_state_write_to_client(txt_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf)) <= -1 || | ||||
| 	        (content_text && txt_state_write_to_client(txt_state, content_text, content_text_len) <= -1) || | ||||
| 	        (force_close && txt_state_write_to_client(txt_state, MIO_NULL, 0) <= -1))? -1: 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int txt_state_write_last_chunk_to_client (txt_state_t* txt_state) | ||||
| { | ||||
| 	if (!txt_state->ever_attempted_to_write_to_client) | ||||
| 	{ | ||||
| 		if (txt_state_send_final_status_to_client(txt_state, 500, 0) <= -1) return -1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (txt_state->res_mode_to_cli == TXT_STATE_RES_MODE_CHUNKED && | ||||
| 		    txt_state_write_to_client(txt_state, "0\r\n\r\n", 5) <= -1) return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (!txt_state->keep_alive && txt_state_write_to_client(txt_state, MIO_NULL, 0) <= -1) return -1; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static MIO_INLINE void txt_state_mark_over (txt_state_t* txt_state, int over_bits) | ||||
| { | ||||
| 	unsigned int old_over; | ||||
| @ -215,14 +168,17 @@ printf ("**** TXT_STATE_ON_KILL \n"); | ||||
| 		txt_state->client_org_on_write = MIO_NULL; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	if (txt_state->client_org_on_disconnect) | ||||
| 	{ | ||||
| 		txt_state->client->sck->on_disconnect = txt_state->client_org_on_disconnect; | ||||
| 		txt_state->client_org_on_disconnect = MIO_NULL; | ||||
| 	} | ||||
|  | ||||
| 	mio_htrd_setrecbs (txt_state->client->htrd, &txt_state->client_htrd_org_recbs); /* restore the callbacks */ | ||||
| 	if (txt_state->client_htrd_recbs_changed) | ||||
| 	{ | ||||
| 		/* restore the callbacks */ | ||||
| 		mio_htrd_setrecbs (txt_state->client->htrd, &txt_state->client_htrd_org_recbs);  | ||||
| 	} | ||||
|  | ||||
| 	if (!txt_state->client_disconnected) | ||||
| 	{ | ||||
| @ -253,13 +209,7 @@ printf (">> CLIENT REQUEST COMPLETED\n"); | ||||
|  | ||||
| static int txt_client_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, const mio_bch_t* data, mio_oow_t dlen) | ||||
| { | ||||
| 	/* | ||||
| 	mio_svc_htts_cli_htrd_xtn_t* htrdxtn = (mio_svc_htts_cli_htrd_xtn_t*)mio_htrd_getxtn(htrd); | ||||
| 	mio_dev_sck_t* sck = htrdxtn->sck; | ||||
| 	mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); | ||||
| 	txt_state_t* txt_state = (txt_state_t*)cli->rsrc; | ||||
| 	MIO_ASSERT (sck->mio, cli->sck == sck); | ||||
| 	*/ | ||||
| 	/* discard all contents */ | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -351,10 +301,8 @@ static int txt_client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrc | ||||
| 	else | ||||
| 	{ | ||||
| 		MIO_ASSERT (mio, txt_state->num_pending_writes_to_client > 0); | ||||
|  | ||||
| 		txt_state->num_pending_writes_to_client--; | ||||
|  | ||||
| 		if ((txt_state->over & TXT_STATE_OVER_READ_FROM_PEER) && txt_state->num_pending_writes_to_client <= 0) | ||||
| 		if (txt_state->num_pending_writes_to_client <= 0) | ||||
| 		{ | ||||
| 			txt_state_mark_over (txt_state, TXT_STATE_OVER_WRITE_TO_CLIENT); | ||||
| 		} | ||||
| @ -367,43 +315,20 @@ oops: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int mio_svc_htts_dotxt (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, mio_svc_htts_txt_func_t func, void* ctx) | ||||
| int mio_svc_htts_dotxt (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, int status_code, const mio_bch_t* content_type, const mio_bch_t* content_text) | ||||
| { | ||||
| 	mio_t* mio = htts->mio; | ||||
| 	mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck); | ||||
| 	txt_state_t* txt_state = MIO_NULL; | ||||
| 	mio_dev_txt_make_t mi; | ||||
| 	txt_func_start_t* tfs; | ||||
|  | ||||
| 	/* ensure that you call this function before any contents is received */ | ||||
| 	MIO_ASSERT (mio, mio_htre_getcontentlen(req) == 0); | ||||
|  | ||||
| 	tfs = mio_callocmem(mio, MIO_SIZEOF(*tfs)); | ||||
| 	if (!tfs) goto oops; | ||||
|  | ||||
| 	tfs->mio = mio; | ||||
| 	tfs->txt_func = func; | ||||
| 	tfs->txt_ctx = ctx; | ||||
|  | ||||
| 	tfs->tfi.req_method = mio_htre_getqmethodtype(req); | ||||
| 	tfs->tfi.req_version = *mio_htre_getversion(req); | ||||
| 	tfs->tfi.req_path = mio_dupbcstr(mio, mio_htre_getqpath(req), MIO_NULL); | ||||
| 	if (!tfs->tfi.req_path) goto oops; | ||||
| 	if (mio_htre_getqparam(req)) | ||||
| 	{ | ||||
| 		tfs->tfi.req_param = mio_dupbcstr(mio, mio_htre_getqparam(req), MIO_NULL); | ||||
| 		if (!tfs->tfi.req_param) goto oops; | ||||
| 	} | ||||
| 	/* TODO: copy headers.. */ | ||||
| 	tfs->tfi.server_addr = cli->sck->localaddr; | ||||
| 	tfs->tfi.client_addr = cli->sck->remoteaddr; | ||||
|  | ||||
| 	txt_state = (txt_state_t*)mio_svc_htts_rsrc_make(htts, MIO_SIZEOF(*txt_state), txt_state_on_kill); | ||||
| 	if (MIO_UNLIKELY(!txt_state)) goto oops; | ||||
|  | ||||
| 	txt_state->client = cli; | ||||
| 	/*txt_state->num_pending_writes_to_client = 0; | ||||
| 	txt_state->num_pending_writes_to_peer = 0;*/ | ||||
| 	/*txt_state->num_pending_writes_to_client = 0;*/ | ||||
| 	txt_state->req_version = *mio_htre_getversion(req); | ||||
| 	txt_state->req_content_length_unlimited = mio_htre_getreqcontentlen(req, &txt_state->req_content_length); | ||||
|  | ||||
| @ -417,102 +342,43 @@ int mio_svc_htts_dotxt (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r | ||||
| 	MIO_ASSERT (mio, cli->rsrc == MIO_NULL); | ||||
| 	MIO_SVC_HTTS_RSRC_ATTACH (txt_state, cli->rsrc); | ||||
|  | ||||
| #if !defined(TXT_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) | ||||
| 	if (txt_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 (txt_state_send_final_status_to_client(txt_state, 411, 1) <= -1) goto oops; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	if (req->flags & MIO_HTRE_ATTR_EXPECT100) | ||||
| 	{ | ||||
| 		/* TODO: Expect: 100-continue? who should handle this? txt? or the http server? */ | ||||
| 		/* CAN I LET the txt SCRIPT handle this? */ | ||||
| 		if (mio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&  | ||||
| 		   (txt_state->req_content_length_unlimited || txt_state->req_content_length > 0))  | ||||
| 		{ | ||||
| 			/*  | ||||
| 			 * Don't send 100 Continue if http verions is lower than 1.1 | ||||
| 			 * [RFC7231]  | ||||
| 			 *  A server that receives a 100-continue expectation in an HTTP/1.0 | ||||
| 			 *  request MUST ignore that expectation. | ||||
| 			 * | ||||
| 			 * Don't send 100 Continue if expected content lenth is 0.  | ||||
| 			 * [RFC7231] | ||||
| 			 *  A server MAY omit sending a 100 (Continue) response if it has | ||||
| 			 *  already received some or all of the message body for the | ||||
| 			 *  corresponding request, or if the framing indicates that there is | ||||
| 			 *  no message body. | ||||
| 			 */ | ||||
| 			mio_bch_t msgbuf[64]; | ||||
| 			mio_oow_t msglen; | ||||
|  | ||||
| 			msglen = mio_fmttobcstr(mio, msgbuf, MIO_COUNTOF(msgbuf), "HTTP/%d.%d 100 Continue\r\n\r\n", txt_state->req_version.major, txt_state->req_version.minor); | ||||
| 			if (txt_state_write_to_client(txt_state, msgbuf, msglen) <= -1) goto oops; | ||||
| 			txt_state->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */ | ||||
| 		} | ||||
| 		/* don't send 100-Continue. If the client posts data regardless, ignore them later */ | ||||
| 	} | ||||
| 	else if (req->flags & MIO_HTRE_ATTR_EXPECT) | ||||
| 	{ | ||||
| 		/* 417 Expectation Failed */ | ||||
| 		txt_state_send_final_status_to_client(txt_state, 417, 1); | ||||
| 		txt_state_send_final_status_to_client(txt_state, 417, MIO_NULL, MIO_NULL, 1); | ||||
| 		goto oops; | ||||
| 	} | ||||
|  | ||||
| #if defined(TXT_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) | ||||
| 	if (txt_state->req_content_length_unlimited) | ||||
| 	if (txt_state->req_content_length_unlimited || txt_state->req_content_length > 0) | ||||
| 	{ | ||||
| 		/* change the callbacks to subscribe to contents to be uploaded */ | ||||
| 		txt_state->client_htrd_org_recbs = *mio_htrd_getrecbs(txt_state->client->htrd); | ||||
| 		txt_client_htrd_recbs.peek = txt_state->client_htrd_org_recbs.peek; | ||||
| 		mio_htrd_setrecbs (txt_state->client->htrd, &txt_client_htrd_recbs); | ||||
| 		txt_state->client_htrd_recbs_changed = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| #endif | ||||
| 		if (txt_state->req_content_length > 0) | ||||
| 		{ | ||||
| 			/* change the callbacks to subscribe to contents to be uploaded */ | ||||
| 			txt_state->client_htrd_org_recbs = *mio_htrd_getrecbs(txt_state->client->htrd); | ||||
| 			txt_client_htrd_recbs.peek = txt_state->client_htrd_org_recbs.peek; | ||||
| 			mio_htrd_setrecbs (txt_state->client->htrd, &txt_client_htrd_recbs); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* no content to be uploaded from the client */ | ||||
| 			/* indicate EOF to the peer and disable input wathching from the client */ | ||||
| 			txt_state_mark_over (txt_state, TXT_STATE_OVER_READ_FROM_CLIENT | TXT_STATE_OVER_WRITE_TO_PEER); | ||||
| 		} | ||||
| #if defined(TXT_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) | ||||
| 		/* no content to be uploaded from the client */ | ||||
| 		/* indicate EOF to the peer and disable input wathching from the client */ | ||||
| 		txt_state_mark_over (txt_state, TXT_STATE_OVER_READ_FROM_CLIENT); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/* this may change later if Content-Length is included in the txt output */ | ||||
| 	if (req->flags & MIO_HTRE_ATTR_KEEPALIVE) | ||||
| 	{ | ||||
| 		txt_state->keep_alive = 1; | ||||
| 		txt_state->res_mode_to_cli = TXT_STATE_RES_MODE_CHUNKED;  | ||||
| 		/* the mode still can get switched to TXT_STATE_RES_MODE_LENGTH if the txt script emits Content-Length */ | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		txt_state->keep_alive = 0; | ||||
| 		txt_state->res_mode_to_cli = TXT_STATE_RES_MODE_CLOSE; | ||||
| 	} | ||||
| 	txt_state->keep_alive = !!(req->flags & MIO_HTRE_ATTR_KEEPALIVE); | ||||
|  | ||||
| 	/* TODO: store current input watching state and use it when destroying the txt_state data */ | ||||
| 	if (mio_dev_sck_read(csck, !(txt_state->over & TXT_STATE_OVER_READ_FROM_CLIENT)) <= -1) goto oops; | ||||
|  | ||||
| 	if (txt_state_send_final_status_to_client(txt_state, status_code, content_type, content_text, 0) <= -1) goto oops; | ||||
| 	return 0; | ||||
|  | ||||
| oops: | ||||
| 	MIO_DEBUG2 (mio, "HTTS(%p) - FAILURE in dotxt - socket(%p)\n", htts, csck); | ||||
| 	if (tfs) free_txt_start_info (tfs); | ||||
| 	if (txt_state) txt_state_halt_participating_devices (txt_state); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| @ -284,6 +284,15 @@ MIO_EXPORT int mio_svc_htts_dothr ( | ||||
| 	void*                   ctx | ||||
| ); | ||||
|  | ||||
| MIO_EXPORT int mio_svc_htts_dotxt ( | ||||
| 	mio_svc_htts_t*     htts, | ||||
| 	mio_dev_sck_t*      csck, | ||||
| 	mio_htre_t*         req, | ||||
| 	int                 status_code, | ||||
| 	const mio_bch_t*    content_type, | ||||
| 	const mio_bch_t*    content_text | ||||
| ); | ||||
|  | ||||
| MIO_EXPORT mio_svc_htts_rsrc_t* mio_svc_htts_rsrc_make ( | ||||
| 	mio_svc_htts_t*              htts, | ||||
| 	mio_oow_t                    rsrc_size, | ||||
|  | ||||
		Reference in New Issue
	
	Block a user