diff --git a/ajaxui/ajaxui.c b/ajaxui/ajaxui.c index 72652986..0da4b569 100644 --- a/ajaxui/ajaxui.c +++ b/ajaxui/ajaxui.c @@ -268,16 +268,15 @@ ajax_a_jsfunc(tcp_queue_t *tq, const char *innerhtml, const char *func, * Titlebar AJAX page */ static int -ajax_page_titlebar(http_connection_t *hc, const char *remain, void *opaque) +ajax_page_titlebar(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; - if(remain == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); - ajax_menu_bar_from_array(&tq, "top", ajax_tabnames, AJAX_TABS, atoi(remain)); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + ajax_menu_bar_from_array(&hr->hr_tq, "top", + ajax_tabnames, AJAX_TABS, atoi(remain)); + http_output_html(hc, hr); return 0; } @@ -287,20 +286,18 @@ ajax_page_titlebar(http_connection_t *hc, const char *remain, void *opaque) * About */ static int -ajax_about_tab(http_connection_t *hc) +ajax_about_tab(http_connection_t *hc, http_reply_t *hr) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; - tcp_init_queue(&tq, -1); + tcp_qprintf(tq, "
"); + tcp_qprintf(tq, "
"); - tcp_qprintf(&tq, "
"); - tcp_qprintf(&tq, "
"); + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "About"); - ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, "About"); + tcp_qprintf(tq, "
"); - tcp_qprintf(&tq, "
"); - - tcp_qprintf(&tq, + tcp_qprintf(tq, "

HTS / Tvheadend

" "

(c) 2006-2008 Andreas \303\226man

" "

Latest release and information is available at:

" @@ -317,12 +314,12 @@ ajax_about_tab(http_connection_t *hc) "

FFmpeg

" ); - tcp_qprintf(&tq, "
"); - ajax_box_end(&tq, AJAX_BOX_SIDEBOX); - tcp_qprintf(&tq, "
"); - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); + tcp_qprintf(tq, ""); + tcp_qprintf(tq, "
"); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -334,7 +331,8 @@ ajax_about_tab(http_connection_t *hc) * Find the 'tab' id and continue with tab specific code */ static int -ajax_page_tab(http_connection_t *hc, const char *remain, void *opaque) +ajax_page_tab(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { int tab; @@ -345,13 +343,13 @@ ajax_page_tab(http_connection_t *hc, const char *remain, void *opaque) switch(tab) { case AJAX_TAB_CHANNELS: - return ajax_channelgroup_tab(hc); + return ajax_channelgroup_tab(hc, hr); case AJAX_TAB_CONFIGURATION: - return ajax_config_tab(hc); + return ajax_config_tab(hc, hr); case AJAX_TAB_ABOUT: - return ajax_about_tab(hc); + return ajax_about_tab(hc, hr); default: return HTTP_STATUS_NOT_FOUND; @@ -365,13 +363,12 @@ ajax_page_tab(http_connection_t *hc, const char *remain, void *opaque) * Root page */ static int -ajax_page_root(http_connection_t *hc, const char *remain, void *opaque) +ajax_page_root(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; - tcp_init_queue(&tq, -1); - - tcp_qprintf(&tq, + tcp_qprintf(tq, "" /* @@ -388,110 +385,50 @@ ajax_page_root(http_connection_t *hc, const char *remain, void *opaque) "content=\"text/html; charset=utf-8\">\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "\r\n"); - tcp_qprintf(&tq, + tcp_qprintf(tq, ""); - tcp_qprintf(&tq, + tcp_qprintf(tq, ""); - ajax_box_begin(&tq, AJAX_BOX_FILLED, "topmenu", NULL, NULL); - ajax_box_end(&tq, AJAX_BOX_FILLED); + ajax_box_begin(tq, AJAX_BOX_FILLED, "topmenu", NULL, NULL); + ajax_box_end(tq, AJAX_BOX_FILLED); - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); - ajax_js(&tq, "switchtab('top', '0')"); + ajax_js(tq, "switchtab('top', '0')"); - tcp_qprintf(&tq, ""); + tcp_qprintf(tq, ""); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } -#if 0 -void blah(void) { - tcp_qprintf(&tq, - "" - "\r\n" - "

\r\n"); - - - tcp_qprintf(&tq, - "\r\n"); - - - tcp_qprintf(&tq, - "
\r\n" - "
\n" - "
\r\n" - "
\r\n" - "\r\n" - "
\r\n"); - - - for(i = 0; i < 40; i++) { - tcp_qprintf(&tq, - "
\r\n" - "

Discovery

\r\n" - "
" - "

Idag e det bra saker pa TV

" - "

Imorgon vet vi inte

" - "
"); - } - - tcp_qprintf(&tq, - ""); - - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); - return 0; -} - -#endif /** diff --git a/ajaxui/ajaxui.h b/ajaxui/ajaxui.h index 42fe3c64..61b4813d 100644 --- a/ajaxui/ajaxui.h +++ b/ajaxui/ajaxui.h @@ -54,13 +54,13 @@ void ajax_menu_bar_from_array(tcp_queue_t *tq, const char *name, void ajax_a_jsfunc(tcp_queue_t *tq, const char *innerhtml, const char *func, const char *trailer); -int ajax_channelgroup_tab(http_connection_t *hc); -int ajax_config_tab(http_connection_t *hc); +int ajax_channelgroup_tab(http_connection_t *hc, http_reply_t *hr); +int ajax_config_tab(http_connection_t *hc, http_reply_t *hr); -int ajax_config_channels_tab(http_connection_t *hc); +int ajax_config_channels_tab(http_connection_t *hc, http_reply_t *hr); void ajax_config_channels_init(void); -int ajax_config_dvb_tab(http_connection_t *hc); +int ajax_config_dvb_tab(http_connection_t *hc, http_reply_t *hr); void ajax_config_dvb_init(void); void ajax_config_transport_init(void); diff --git a/ajaxui/ajaxui_channels.c b/ajaxui/ajaxui_channels.c index e968f73f..b37434f3 100644 --- a/ajaxui/ajaxui_channels.c +++ b/ajaxui/ajaxui_channels.c @@ -58,17 +58,16 @@ ajax_channelgroupmenu_content(tcp_queue_t *tq, int current) * Channelgroup menu bar */ static int -ajax_channelgroup_menu(http_connection_t *hc, const char *remain, void *opaque) +ajax_channelgroup_menu(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; if(remain == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); - - ajax_channelgroupmenu_content(&tq, atoi(remain)); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + ajax_channelgroupmenu_content(tq, atoi(remain)); + http_output_html(hc, hr); return 0; } @@ -82,9 +81,10 @@ ajax_channelgroup_menu(http_connection_t *hc, const char *remain, void *opaque) * Group is given by 'tag' as an ASCII string in remain */ int -ajax_channel_tab(http_connection_t *hc, const char *remain, void *opaque) +ajax_channel_tab(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + // tcp_queue_t *tq = &hr->hr_tq; th_channel_t *ch; th_channel_group_t *tcg; @@ -94,8 +94,6 @@ ajax_channel_tab(http_connection_t *hc, const char *remain, void *opaque) if((tcg = channel_group_by_tag(atoi(remain))) == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); - TAILQ_FOREACH(ch, &tcg->tcg_channels, ch_group_link) { if(LIST_FIRST(&ch->ch_transports) == NULL) continue; @@ -108,7 +106,7 @@ ajax_channel_tab(http_connection_t *hc, const char *remain, void *opaque) #endif } - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -121,23 +119,21 @@ ajax_channel_tab(http_connection_t *hc, const char *remain, void *opaque) * This is the top level menu for this c-file */ int -ajax_channelgroup_tab(http_connection_t *hc) +ajax_channelgroup_tab(http_connection_t *hc, http_reply_t *hr) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; - tcp_init_queue(&tq, -1); + ajax_box_begin(tq, AJAX_BOX_FILLED, "channelgroupmenu", NULL, NULL); + ajax_box_end(tq, AJAX_BOX_FILLED); - ajax_box_begin(&tq, AJAX_BOX_FILLED, "channelgroupmenu", NULL, NULL); - ajax_box_end(&tq, AJAX_BOX_FILLED); + tcp_qprintf(tq, "
"); - tcp_qprintf(&tq, "
"); - - tcp_qprintf(&tq, + tcp_qprintf(tq, ""); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } diff --git a/ajaxui/ajaxui_config.c b/ajaxui/ajaxui_config.c index 5806ad27..e6075a9d 100644 --- a/ajaxui/ajaxui_config.c +++ b/ajaxui/ajaxui_config.c @@ -43,18 +43,18 @@ const char *ajax_config_tabnames[] = { * Titlebar AJAX page */ static int -ajax_config_menu(http_connection_t *hc, const char *remain, void *opaque) +ajax_config_menu(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; if(remain == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); - ajax_menu_bar_from_array(&tq, "config", + ajax_menu_bar_from_array(tq, "config", ajax_config_tabnames, AJAX_CONFIG_TABS, atoi(remain)); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -64,7 +64,8 @@ ajax_config_menu(http_connection_t *hc, const char *remain, void *opaque) * Switch to different tabs */ static int -ajax_config_dispatch(http_connection_t *hc, const char *remain, void *opaque) +ajax_config_dispatch(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { int tab; @@ -75,9 +76,9 @@ ajax_config_dispatch(http_connection_t *hc, const char *remain, void *opaque) switch(tab) { case AJAX_CONFIG_TAB_CHANNELS: - return ajax_config_channels_tab(hc); + return ajax_config_channels_tab(hc, hr); case AJAX_CONFIG_TAB_DVB: - return ajax_config_dvb_tab(hc); + return ajax_config_dvb_tab(hc, hr); default: return HTTP_STATUS_NOT_FOUND; @@ -94,23 +95,21 @@ ajax_config_dispatch(http_connection_t *hc, const char *remain, void *opaque) * This is the top level menu for this c-file */ int -ajax_config_tab(http_connection_t *hc) +ajax_config_tab(http_connection_t *hc, http_reply_t *hr) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; - tcp_init_queue(&tq, -1); + ajax_box_begin(tq, AJAX_BOX_FILLED, "configmenu", NULL, NULL); + ajax_box_end(tq, AJAX_BOX_FILLED); - ajax_box_begin(&tq, AJAX_BOX_FILLED, "configmenu", NULL, NULL); - ajax_box_end(&tq, AJAX_BOX_FILLED); + tcp_qprintf(tq, "
"); - tcp_qprintf(&tq, "
"); - - tcp_qprintf(&tq, + tcp_qprintf(tq, ""); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } diff --git a/ajaxui/ajaxui_config_channels.c b/ajaxui/ajaxui_config_channels.c index 799ac6e8..7d8b8534 100644 --- a/ajaxui/ajaxui_config_channels.c +++ b/ajaxui/ajaxui_config_channels.c @@ -71,15 +71,13 @@ ajax_chgroup_build(tcp_queue_t *tq, th_channel_group_t *tcg) * Update order of channel groups */ static int -ajax_chgroup_updateorder(http_connection_t *hc, const char *remain, - void *opaque) +ajax_chgroup_updateorder(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { th_channel_group_t *tcg; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; http_arg_t *ra; - tcp_init_queue(&tq, -1); - TAILQ_FOREACH(ra, &hc->hc_req_args, link) { if(strcmp(ra->key, "channelgrouplist[]") || (tcg = channel_group_by_tag(atoi(ra->val))) == NULL) @@ -91,9 +89,9 @@ ajax_chgroup_updateorder(http_connection_t *hc, const char *remain, channel_group_settings_write(); - tcp_qprintf(&tq, "Updated on server"); - ajax_js(&tq, "Effect.Fade('updatedok')"); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + tcp_qprintf(tq, "Updated on server"); + ajax_js(tq, "Effect.Fade('updatedok')"); + http_output_html(hc, hr); return 0; } @@ -103,14 +101,13 @@ ajax_chgroup_updateorder(http_connection_t *hc, const char *remain, * Add a new channel group */ static int -ajax_chgroup_add(http_connection_t *hc, const char *remain, void *opaque) +ajax_chgroup_add(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { th_channel_group_t *tcg; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; const char *name; - tcp_init_queue(&tq, -1); - if((name = http_arg_get(&hc->hc_req_args, "name")) != NULL) { TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) @@ -120,13 +117,13 @@ ajax_chgroup_add(http_connection_t *hc, const char *remain, void *opaque) if(tcg == NULL) { tcg = channel_group_find(name, 1); - ajax_chgroup_build(&tq, tcg); + ajax_chgroup_build(tq, tcg); /* We must recreate the Sortable object */ - ajax_js(&tq, "Sortable.destroy(\"channelgrouplist\")"); + ajax_js(tq, "Sortable.destroy(\"channelgrouplist\")"); - ajax_js(&tq, "Sortable.create(\"channelgrouplist\", " + ajax_js(tq, "Sortable.create(\"channelgrouplist\", " "{onUpdate:function(){updatelistonserver(" "'channelgrouplist', " "'/ajax/chgroup_updateorder', " @@ -134,7 +131,7 @@ ajax_chgroup_add(http_connection_t *hc, const char *remain, void *opaque) ")}});"); } } - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -144,10 +141,11 @@ ajax_chgroup_add(http_connection_t *hc, const char *remain, void *opaque) * Delete a channel group */ static int -ajax_chgroup_del(http_connection_t *hc, const char *remain, void *opaque) +ajax_chgroup_del(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { th_channel_group_t *tcg; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; const char *id; if((id = http_arg_get(&hc->hc_req_args, "id")) == NULL) @@ -156,12 +154,10 @@ ajax_chgroup_del(http_connection_t *hc, const char *remain, void *opaque) if((tcg = channel_group_by_tag(atoi(id))) == NULL) return HTTP_STATUS_BAD_REQUEST; - tcp_init_queue(&tq, -1); - tcp_qprintf(&tq, "$('chgrp_%d').remove();", tcg->tcg_tag); - http_output_queue(hc, &tq, "text/javascript; charset=UTF-8", 0); + tcp_qprintf(tq, "$('chgrp_%d').remove();", tcg->tcg_tag); + http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); channel_group_destroy(tcg); - return 0; } @@ -171,32 +167,30 @@ ajax_chgroup_del(http_connection_t *hc, const char *remain, void *opaque) * Channel group & channel configuration */ int -ajax_config_channels_tab(http_connection_t *hc) +ajax_config_channels_tab(http_connection_t *hc, http_reply_t *hr) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_channel_group_t *tcg; - tcp_init_queue(&tq, -1); - - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); - ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, "channelgroups", + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, "channelgroups", NULL, "Channel groups"); - tcp_qprintf(&tq, "
"); - tcp_qprintf(&tq, ""); - ajax_js(&tq, "Sortable.create(\"channelgrouplist\", " + ajax_js(tq, "Sortable.create(\"channelgrouplist\", " "{onUpdate:function(){updatelistonserver(" "'channelgrouplist', " "'/ajax/chgroup_updateorder', " @@ -206,9 +200,9 @@ ajax_config_channels_tab(http_connection_t *hc) /** * Add new group */ - ajax_box_begin(&tq, AJAX_BOX_BORDER, NULL, NULL, NULL); + ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL); - tcp_qprintf(&tq, + tcp_qprintf(tq, "
" "
" "" @@ -220,21 +214,18 @@ ajax_config_channels_tab(http_connection_t *hc) "Add
" "
"); - ajax_box_end(&tq, AJAX_BOX_BORDER); + ajax_box_end(tq, AJAX_BOX_BORDER); - ajax_box_end(&tq, AJAX_BOX_SIDEBOX); - tcp_qprintf(&tq, "
"); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); + tcp_qprintf(tq, "
"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "
"); - - tcp_qprintf(&tq, "
"); - - - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + tcp_qprintf(tq, ""); + http_output_html(hc, hr); return 0; } @@ -242,46 +233,45 @@ ajax_config_channels_tab(http_connection_t *hc) * Display all channels within the group */ static int -ajax_chgroup_editor(http_connection_t *hc, const char *remain, void *opaque) +ajax_chgroup_editor(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_channel_t *ch; th_channel_group_t *tcg; if(remain == NULL || (tcg = channel_group_by_tag(atoi(remain))) == NULL) return HTTP_STATUS_BAD_REQUEST; - tcp_init_queue(&tq, -1); + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, tcg->tcg_name); - ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, tcg->tcg_name); - - tcp_qprintf(&tq, ""); - ajax_box_end(&tq, AJAX_BOX_SIDEBOX); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } diff --git a/ajaxui/ajaxui_config_dvb.c b/ajaxui/ajaxui_config_dvb.c index 3c8a8413..0d73dbaf 100644 --- a/ajaxui/ajaxui_config_dvb.c +++ b/ajaxui/ajaxui_config_dvb.c @@ -68,38 +68,37 @@ tdmi_displayname(th_dvb_mux_instance_t *tdmi, char *buf, size_t len) * Adapter summary */ static int -ajax_adaptersummary(http_connection_t *hc, const char *remain, void *opaque) +ajax_adaptersummary(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_dvb_adapter_t *tda; char dispname[20]; if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); - snprintf(dispname, sizeof(dispname), "%s", tda->tda_displayname); strcpy(dispname + sizeof(dispname) - 4, "..."); - ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, dispname); + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, dispname); - tcp_qprintf(&tq, "
Status:
" + tcp_qprintf(tq, "
Status:
" "
%s
", val2str(tda->tda_state, adapterstatus) ?: "invalid"); - tcp_qprintf(&tq, "
Type:
" + tcp_qprintf(tq, "
Type:
" "
%s
", dvb_adaptertype_to_str(tda->tda_fe_info->type)); - tcp_qprintf(&tq, "
" + tcp_qprintf(tq, "
" "Edit
", tda->tda_identifier); - ajax_box_end(&tq, AJAX_BOX_SIDEBOX); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -108,29 +107,27 @@ ajax_adaptersummary(http_connection_t *hc, const char *remain, void *opaque) * DVB configuration */ int -ajax_config_dvb_tab(http_connection_t *hc) +ajax_config_dvb_tab(http_connection_t *hc, http_reply_t *hr) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_dvb_adapter_t *tda; - tcp_init_queue(&tq, -1); - - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); LIST_FOREACH(tda, &dvb_adapters, tda_global_link) { - tcp_qprintf(&tq, "
", tda->tda_identifier); - ajax_js(&tq, "new Ajax.Updater('summary_%s', " + ajax_js(tq, "new Ajax.Updater('summary_%s', " "'/ajax/dvbadaptersummary/%s', {method: 'get'})", tda->tda_identifier, tda->tda_identifier); } - tcp_qprintf(&tq, "
"); - tcp_qprintf(&tq, "
"); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + tcp_qprintf(tq, "
"); + tcp_qprintf(tq, "
"); + http_output_html(hc, hr); return 0; } @@ -159,28 +156,27 @@ dvb_make_add_link(tcp_queue_t *tq, th_dvb_adapter_t *tda, const char *result) * DVB adapter editor pane */ static int -ajax_adaptereditor(http_connection_t *hc, const char *remain, void *opaque) +ajax_adaptereditor(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_dvb_adapter_t *tda; float a, b, c; if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); + ajax_box_begin(tq, AJAX_BOX_FILLED, NULL, NULL, NULL); - ajax_box_begin(&tq, AJAX_BOX_FILLED, NULL, NULL, NULL); - - tcp_qprintf(&tq, + tcp_qprintf(tq, "
%s
", tda->tda_displayname); - ajax_box_end(&tq, AJAX_BOX_FILLED); + ajax_box_end(tq, AJAX_BOX_FILLED); /* Type */ - tcp_qprintf(&tq, "
Model:
" + tcp_qprintf(tq, "
Model:
" "
%s (%s)
", tda->tda_fe_info->name, dvb_adaptertype_to_str(tda->tda_fe_info->type)); @@ -200,13 +196,13 @@ ajax_adaptereditor(http_connection_t *hc, const char *remain, void *opaque) break; } - tcp_qprintf(&tq, "
Freq. Range:
" + tcp_qprintf(tq, "
Freq. Range:
" "
%.2f - %.2f kHz, in steps of %.2f kHz
", a, b, c); if(tda->tda_fe_info->symbol_rate_min) { - tcp_qprintf(&tq, "
Symbolrate:
" + tcp_qprintf(tq, "
Symbolrate:
" "
%d - %d BAUD
", tda->tda_fe_info->symbol_rate_min, tda->tda_fe_info->symbol_rate_max); @@ -216,34 +212,34 @@ ajax_adaptereditor(http_connection_t *hc, const char *remain, void *opaque) /* Capabilities */ - // tcp_qprintf(&tq, "
Capabilities:
"); + // tcp_qprintf(tq, "
Capabilities:
"); - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); - ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Multiplexes"); + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Multiplexes"); - tcp_qprintf(&tq, "
", + tcp_qprintf(tq, "
", tda->tda_identifier); - ajax_js(&tq, + ajax_js(tq, "new Ajax.Updater('dvbmuxlist%s', " "'/ajax/dvbadaptermuxlist/%s', {method: 'get'}) ", tda->tda_identifier, tda->tda_identifier); - tcp_qprintf(&tq, "
"); - dvb_make_add_link(&tq, tda, NULL); - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); + dvb_make_add_link(tq, tda, NULL); + tcp_qprintf(tq, "
"); - ajax_box_end(&tq, AJAX_BOX_SIDEBOX); - tcp_qprintf(&tq, "
"); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); + tcp_qprintf(tq, "
"); /* Div for displaying services */ - tcp_qprintf(&tq, "
"); - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -252,9 +248,10 @@ ajax_adaptereditor(http_connection_t *hc, const char *remain, void *opaque) * DVB adapter add mux */ static int -ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) +ajax_adapteraddmux(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_dvb_adapter_t *tda; int caps; int fetype; @@ -266,13 +263,11 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) caps = tda->tda_fe_info->caps; fetype = tda->tda_fe_info->type; - tcp_init_queue(&tq, -1); - - tcp_qprintf(&tq, "
" + tcp_qprintf(tq, "
" "Add new %s mux
", dvb_adaptertype_to_str(tda->tda_fe_info->type)); - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Frequency (%s):
" "
" "" @@ -287,7 +282,7 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) if(fetype == FE_QAM || fetype == FE_QPSK) { - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Symbolrate:
" "
" "" @@ -300,15 +295,15 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) /* Bandwidth */ if(fetype == FE_OFDM) { - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Bandwidth:
" "
"); + add_option(tq, caps & FE_CAN_BANDWIDTH_AUTO, "AUTO"); + add_option(tq, 1 , "8MHz"); + add_option(tq, 1 , "7MHz"); + add_option(tq, 1 , "6MHz"); + tcp_qprintf(tq, "
"); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", bw: $F('bw')"); @@ -318,19 +313,19 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) /* Constellation */ if(fetype == FE_QAM || fetype == FE_OFDM) { - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Constellation:
" "
"); + tcp_qprintf(tq, "
"); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", const: $F('const')"); @@ -340,33 +335,33 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) /* FEC */ if(fetype == FE_QAM || fetype == FE_QPSK) { - tcp_qprintf(&tq, + tcp_qprintf(tq, "
FEC:
" "
"); + add_option(tq, caps & FE_CAN_FEC_AUTO, "AUTO"); + add_option(tq, caps & FE_CAN_FEC_1_2, "1/2"); + add_option(tq, caps & FE_CAN_FEC_2_3, "2/3"); + add_option(tq, caps & FE_CAN_FEC_3_4, "3/4"); + add_option(tq, caps & FE_CAN_FEC_4_5, "4/5"); + add_option(tq, caps & FE_CAN_FEC_5_6, "5/6"); + add_option(tq, caps & FE_CAN_FEC_6_7, "6/7"); + add_option(tq, caps & FE_CAN_FEC_7_8, "7/8"); + add_option(tq, caps & FE_CAN_FEC_8_9, "8/9"); + tcp_qprintf(tq, "
"); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", fec: $F('fec')"); } if(fetype == FE_QPSK) { - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Polarisation:
" "
"); + add_option(tq, 1, "Vertical"); + add_option(tq, 1, "Horizontal"); + tcp_qprintf(tq, ""); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", pol: $F('pol')"); @@ -376,44 +371,44 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) if(fetype == FE_OFDM) { - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Transmission mode:
" "
"); + add_option(tq, caps & FE_CAN_TRANSMISSION_MODE_AUTO, "AUTO"); + add_option(tq, 1 , "2k"); + add_option(tq, 1 , "8k"); + tcp_qprintf(tq, ""); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", tmode: $F('tmode')"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Guard interval:
" "
"); + add_option(tq, caps & FE_CAN_GUARD_INTERVAL_AUTO, "AUTO"); + add_option(tq, 1 , "1/32"); + add_option(tq, 1 , "1/16"); + add_option(tq, 1 , "1/8"); + add_option(tq, 1 , "1/4"); + tcp_qprintf(tq, ""); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", guard: $F('guard')"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "
Hierarchy:
" "
"); + add_option(tq, caps & FE_CAN_HIERARCHY_AUTO, "AUTO"); + add_option(tq, 1 , "1"); + add_option(tq, 1 , "2"); + add_option(tq, 1 , "4"); + add_option(tq, 1 , "NONE"); + tcp_qprintf(tq, ""); snprintf(params + strlen(params), sizeof(params) - strlen(params), @@ -421,45 +416,45 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) - tcp_qprintf(&tq, + tcp_qprintf(tq, "
FEC Hi:
" "
"); + add_option(tq, caps & FE_CAN_FEC_AUTO, "AUTO"); + add_option(tq, caps & FE_CAN_FEC_1_2, "1/2"); + add_option(tq, caps & FE_CAN_FEC_2_3, "2/3"); + add_option(tq, caps & FE_CAN_FEC_3_4, "3/4"); + add_option(tq, caps & FE_CAN_FEC_4_5, "4/5"); + add_option(tq, caps & FE_CAN_FEC_5_6, "5/6"); + add_option(tq, caps & FE_CAN_FEC_6_7, "6/7"); + add_option(tq, caps & FE_CAN_FEC_7_8, "7/8"); + add_option(tq, caps & FE_CAN_FEC_8_9, "8/9"); + tcp_qprintf(tq, ""); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", fechi: $F('fechi')"); - tcp_qprintf(&tq, + tcp_qprintf(tq, "
FEC Low:
" "
"); + add_option(tq, caps & FE_CAN_FEC_AUTO, "AUTO"); + add_option(tq, caps & FE_CAN_FEC_1_2, "1/2"); + add_option(tq, caps & FE_CAN_FEC_2_3, "2/3"); + add_option(tq, caps & FE_CAN_FEC_3_4, "3/4"); + add_option(tq, caps & FE_CAN_FEC_4_5, "4/5"); + add_option(tq, caps & FE_CAN_FEC_5_6, "5/6"); + add_option(tq, caps & FE_CAN_FEC_6_7, "6/7"); + add_option(tq, caps & FE_CAN_FEC_7_8, "7/8"); + add_option(tq, caps & FE_CAN_FEC_8_9, "8/9"); + tcp_qprintf(tq, ""); snprintf(params + strlen(params), sizeof(params) - strlen(params), ", feclo: $F('feclo')"); } - tcp_qprintf(&tq, + tcp_qprintf(tq, "
" "" "
", tda->tda_identifier, params); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -476,13 +471,12 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque) * */ static int -ajax_adaptercreatemux_fail(http_connection_t *hc, th_dvb_adapter_t *tda, - const char *errmsg) +ajax_adaptercreatemux_fail(http_connection_t *hc, http_reply_t *hr, + th_dvb_adapter_t *tda, const char *errmsg) { - tcp_queue_t tq; - tcp_init_queue(&tq, -1); - dvb_make_add_link(&tq, tda, errmsg); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + tcp_queue_t *tq = &hr->hr_tq; + dvb_make_add_link(tq, tda, errmsg); + http_output_html(hc, hr); return 0; } @@ -490,9 +484,10 @@ ajax_adaptercreatemux_fail(http_connection_t *hc, th_dvb_adapter_t *tda, * DVB adapter create mux (come here on POST after addmux query) */ static int -ajax_adaptercreatemux(http_connection_t *hc, const char *remain, void *opaque) +ajax_adaptercreatemux(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { - tcp_queue_t tq; + tcp_queue_t *tq; th_dvb_adapter_t *tda; const char *v; @@ -514,17 +509,17 @@ ajax_adaptercreatemux(http_connection_t *hc, const char *remain, void *opaque) http_arg_get(&hc->hc_req_args, "port"), 1); if(v != NULL) - return ajax_adaptercreatemux_fail(hc, tda, v); + return ajax_adaptercreatemux_fail(hc, hr, tda, v); - tcp_init_queue(&tq, -1); - dvb_make_add_link(&tq, tda, "Successfully created"); + tq = &hr->hr_tq; + dvb_make_add_link(tq, tda, "Successfully created"); - ajax_js(&tq, + ajax_js(tq, "new Ajax.Updater('dvbmuxlist%s', " "'/ajax/dvbadaptermuxlist/%s', {method: 'get'}) ", tda->tda_identifier, tda->tda_identifier); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -533,10 +528,11 @@ ajax_adaptercreatemux(http_connection_t *hc, const char *remain, void *opaque) * Return a list of all muxes on the given adapter */ static int -ajax_adaptermuxlist(http_connection_t *hc, const char *remain, void *opaque) +ajax_adaptermuxlist(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { th_dvb_mux_instance_t *tdmi; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; th_dvb_adapter_t *tda; char buf[50], buf2[500], buf3[20]; const char *txt; @@ -555,32 +551,30 @@ ajax_adaptermuxlist(http_connection_t *hc, const char *remain, void *opaque) fetype = tda->tda_fe_info->type; - tcp_init_queue(&tq, -1); - /* List of muxes */ LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) nmuxes++; - ajax_table_header(hc, &tq, + ajax_table_header(hc, tq, (const char *[]) {"Freq", "Status", "State", "Name", "Services", NULL}, (int[]){3,3,2,4,2}, nmuxes > displines, csize); - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); v = displines; if(nmuxes < displines) v = nmuxes; - tcp_qprintf(&tq, "
", tda->tda_identifier, v * 14); if(nmuxes == 0) { - tcp_qprintf(&tq, "
" + tcp_qprintf(tq, "
" "No muxes configured
"); } else LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { @@ -620,12 +614,12 @@ ajax_adaptermuxlist(http_connection_t *hc, const char *remain, void *opaque) cells[4] = buf3; cells[5] = NULL; - ajax_table_row(&tq, cells, csize, &o); + ajax_table_row(tq, cells, csize, &o); } - tcp_qprintf(&tq, "
"); + tcp_qprintf(tq, "
"); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } @@ -642,10 +636,11 @@ dvbsvccmp(th_transport_t *a, th_transport_t *b) * Display detailes about a mux */ static int -ajax_dvbmuxeditor(http_connection_t *hc, const char *remain, void *opaque) +ajax_dvbmuxeditor(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { th_dvb_mux_instance_t *tdmi; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; char buf[1000]; th_transport_t *t; struct th_transport_list head; @@ -654,8 +649,6 @@ ajax_dvbmuxeditor(http_connection_t *hc, const char *remain, void *opaque) if(remain == NULL || (tdmi = dvb_mux_find_by_identifier(remain)) == NULL) return HTTP_STATUS_NOT_FOUND; - tcp_init_queue(&tq, -1); - tdmi_displayname(tdmi, buf, sizeof(buf)); LIST_INIT(&head); @@ -667,11 +660,11 @@ ajax_dvbmuxeditor(http_connection_t *hc, const char *remain, void *opaque) } } - ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, buf); - ajax_transport_build_list(hc, &tq, &head, n); - ajax_box_end(&tq, AJAX_BOX_SIDEBOX); + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, buf); + ajax_transport_build_list(hc, tq, &head, n); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); return 0; } diff --git a/ajaxui/ajaxui_config_transport.c b/ajaxui/ajaxui_config_transport.c index 33d165af..aae34d97 100644 --- a/ajaxui/ajaxui_config_transport.c +++ b/ajaxui/ajaxui_config_transport.c @@ -282,12 +282,12 @@ ajax_transport_build_list(http_connection_t *hc, tcp_queue_t *tq, * Rename of unmapped channel */ static int -ajax_transport_rename_channel(http_connection_t *hc, +ajax_transport_rename_channel(http_connection_t *hc, http_reply_t *hr, const char *remain, void *opaque) { th_transport_t *t; const char *newname, *v; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; char buf[1000]; if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) @@ -299,8 +299,6 @@ ajax_transport_rename_channel(http_connection_t *hc, free((void *)t->tht_channelname); t->tht_channelname = strdup(newname); - tcp_init_queue(&tq, -1); - v = newname; snprintf(buf, sizeof(buf), @@ -308,9 +306,9 @@ ajax_transport_rename_channel(http_connection_t *hc, "'/ajax/transport_rename_channel/%s', '%s')", t->tht_identifier, t->tht_identifier, v); - ajax_a_jsfunc(&tq, v, buf, ""); + ajax_a_jsfunc(tq, v, buf, ""); - http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0); + http_output_html(hc, hr); t->tht_config_change(t); return 0; } @@ -361,10 +359,11 @@ dvb_unmap_channel(th_transport_t *t, tcp_queue_t *tq) * */ int -ajax_transport_op(http_connection_t *hc, const char *remain, void *opaque) +ajax_transport_op(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { th_transport_t *t; - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; const char *op; if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) @@ -373,20 +372,18 @@ ajax_transport_op(http_connection_t *hc, const char *remain, void *opaque) if((op = http_arg_get(&hc->hc_req_args, "action")) == NULL) return HTTP_STATUS_BAD_REQUEST; - tcp_init_queue(&tq, -1); - if(!strcmp(op, "toggle")) { if(t->tht_channel) - dvb_unmap_channel(t, &tq); + dvb_unmap_channel(t, tq); else - dvb_map_channel(t, &tq); + dvb_map_channel(t, tq); } else if(!strcmp(op, "map") && t->tht_channel == NULL) { - dvb_map_channel(t, &tq); + dvb_map_channel(t, tq); } else if(!strcmp(op, "unmap") && t->tht_channel != NULL) { - dvb_unmap_channel(t, &tq); + dvb_unmap_channel(t, tq); } - http_output_queue(hc, &tq, "text/javascript; charset=UTF-8", 0); + http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); t->tht_config_change(t); return 0; diff --git a/http.c b/http.c index 4b1df713..6704c5da 100644 --- a/http.c +++ b/http.c @@ -149,218 +149,269 @@ static const char *cachemonths[12] = { }; /** - * If current version mandates it, send a HTTP reply header back + * */ static void -http_output_reply_header(http_connection_t *hc, int rc, int maxage) +http_destroy_reply(http_connection_t *hc, http_reply_t *hr) +{ + if(hr->hr_destroy != NULL) + hr->hr_destroy(hr, hr->hr_opaque); + + TAILQ_REMOVE(&hc->hc_replies, hr, hr_link); + free(hr->hr_location); + tcp_flush_queue(&hr->hr_tq); + free(hr); +} + +/** + * Transmit a HTTP reply + * + * Return non-zero if we should disconnect (no more keep-alive) + */ +static int +http_send_reply(http_connection_t *hc, http_reply_t *hr) { struct tm tm0, *tm; time_t t; + tcp_queue_t *tq = &hr->hr_tq; + int r; - if(hc->hc_version < HTTP_VERSION_1_0) - return; - - http_printf(hc, "%s %d %s\r\n", val2str(hc->hc_version, HTTP_versiontab), - rc, http_rc2str(rc)); + if(hr->hr_version > HTTP_VERSION_1_0) { + http_printf(hc, "%s %d %s\r\n", val2str(hr->hr_version, HTTP_versiontab), + hr->hr_rc, http_rc2str(hr->hr_rc)); - if(maxage == 0) { - http_printf(hc, "Cache-Control: no-cache\r\n"); - } else { - t = dispatch_clock; + http_printf(hc, "Server: HTS/tvheadend\r\n"); + + if(hr->hr_maxage == 0) { + http_printf(hc, "Cache-Control: no-cache\r\n"); + } else { + t = dispatch_clock; + + tm = gmtime_r(&t, &tm0); + http_printf(hc, + "Last-Modified: %s, %02d %s %d %02d:%02d:%02d GMT\r\n", + cachedays[tm->tm_wday], tm->tm_year + 1900, + cachemonths[tm->tm_mon], tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + t += hr->hr_maxage; + + tm = gmtime_r(&t, &tm0); + http_printf(hc, + "Expires: %s, %02d %s %d %02d:%02d:%02d GMT\r\n", + cachedays[tm->tm_wday], tm->tm_year + 1900, + cachemonths[tm->tm_mon], tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + http_printf(hc, "Cache-Control: max-age=%d\r\n", hr->hr_maxage); + } + + http_printf(hc, "Connection: %s\r\n", + hr->hr_keep_alive ? "Keep-Alive" : "Close"); + + if(hr->hr_rc == HTTP_STATUS_UNAUTHORIZED) + http_printf(hc, "WWW-Authenticate: Basic realm=\"tvheadend\"\r\n"); + + if(hr->hr_encoding != NULL) + http_printf(hc, "Content-Encoding: %s\r\n", hr->hr_encoding); + + if(hr->hr_location != NULL) + http_printf(hc, "Location: %s\r\n", hr->hr_location); - tm = gmtime_r(&t, &tm0); http_printf(hc, - "Last-Modified: %s, %02d %s %d %02d:%02d:%02d GMT\r\n", - cachedays[tm->tm_wday], tm->tm_year + 1900, - cachemonths[tm->tm_mon], tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - t += maxage; - - tm = gmtime_r(&t, &tm0); - http_printf(hc, - "Expires: %s, %02d %s %d %02d:%02d:%02d GMT\r\n", - cachedays[tm->tm_wday], tm->tm_year + 1900, - cachemonths[tm->tm_mon], tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - http_printf(hc, "Cache-Control: max-age=%d\r\n", maxage); + "Content-Type: %s\r\n" + "Content-Length: %d\r\n" + "\r\n", + hr->hr_content, tq->tq_depth); } + tcp_output_queue(&hc->hc_tcp_session, NULL, tq); - http_printf(hc, "Server: HTS/tvheadend\r\n"); - http_printf(hc, "Connection: %s\r\n", - hc->hc_keep_alive ? "Keep-Alive" : "Close"); + r = !hr->hr_keep_alive; + + http_destroy_reply(hc, hr); + return r; } +/** + * Send HTTP replies + * + * Return non-zero if we should disconnect + */ +static int +http_xmit_queue(http_connection_t *hc) +{ + http_reply_t *hr; + + while((hr = TAILQ_FIRST(&hc->hc_replies)) != NULL) { + if(hr->hr_destroy != NULL) + break; /* Pending reply, cannot send this yet */ + if(http_send_reply(hc, hr)) + return 1; + } + return 0; +} + + + /** * Send HTTP error back */ void -http_error(http_connection_t *hc, int error) +http_error(http_connection_t *hc, http_reply_t *hr, int error) { - char ret[300]; const char *errtxt = http_rc2str(error); + tcp_queue_t *tq = &hr->hr_tq; - http_output_reply_header(hc, error, 0); + tcp_flush_queue(tq); - snprintf(ret, sizeof(ret), - "\r\n" - "\r\n" - "%d %s\r\n" - "\r\n" - "

%d %s

\r\n" - "\r\n", - error, errtxt, - error, errtxt); + tcp_qprintf(tq, + "\r\n" + "\r\n" + "%d %s\r\n" + "\r\n" + "

%d %s

\r\n" + "\r\n", + error, errtxt, error, errtxt); - if(hc->hc_version >= HTTP_VERSION_1_0) { - if(error == HTTP_STATUS_UNAUTHORIZED) - http_printf(hc, "WWW-Authenticate: Basic realm=\"tvheadend\"\r\n"); - - http_printf(hc, "Content-Type: text/html\r\n"); - http_printf(hc, "Content-Length: %d\r\n", strlen(ret)); - http_printf(hc, "\r\n"); - } - http_printf(hc, "%s", ret); + hr->hr_destroy = NULL; + hr->hr_rc = error; + hr->hr_content = "text/html"; } /** - * Send an HTTP OK and post data from a tcp queue + * Send an HTTP OK */ void -http_output_queue(http_connection_t *hc, tcp_queue_t *tq, const char *content, - int maxage) +http_output(http_connection_t *hc, http_reply_t *hr, const char *content, + const char *encoding, int maxage) { - http_output_reply_header(hc, 200, maxage); - - if(hc->hc_version >= HTTP_VERSION_1_0) { - http_printf(hc, - "Content-Type: %s\r\n" - "Content-Length: %d\r\n" - "\r\n", - content, tq->tq_depth); - } - - tcp_output_queue(&hc->hc_tcp_session, NULL, tq); + hr->hr_encoding = encoding; + hr->hr_content = content; + hr->hr_maxage = maxage; } /** - * Send an HTTP OK and post data from a tcp queue + * Send an HTTP OK, simple version for text/html */ -static void -http_output_queue_encoding(http_connection_t *hc, tcp_queue_t *tq, - const char *content, int maxage, - const char *encoding) +void +http_output_html(http_connection_t *hc, http_reply_t *hr) { - http_output_reply_header(hc, 200, maxage); - - if(hc->hc_version >= HTTP_VERSION_1_0) { - http_printf(hc, - "Content-Encoding: %s\r\n" - "Content-Type: %s\r\n" - "Content-Length: %d\r\n" - "\r\n", - encoding, content, tq->tq_depth); - } - - tcp_output_queue(&hc->hc_tcp_session, NULL, tq); + hr->hr_content = "text/html; charset=UTF-8"; } + /** * Send an HTTP REDIRECT */ -int -http_redirect(http_connection_t *hc, const char *location) +void +http_redirect(http_connection_t *hc, http_reply_t *hr, const char *location) { - tcp_queue_t tq; + tcp_queue_t *tq = &hr->hr_tq; - http_output_reply_header(hc, 303, 0); + tcp_qprintf(tq, + "\r\n" + "\r\n" + "Redirect\r\n" + "\r\n" + "Please follow %s\r\n" + "\r\n", + location, location); - if(hc->hc_version < HTTP_VERSION_1_0) - return -1; - - tcp_init_queue(&tq, -1); - - tcp_qprintf(&tq, "Please follow ", location); - - http_printf(hc, - "Location: %s\r\n" - "Content-Type: text/html\r\n" - "Content-Length: %d\r\n" - "\r\n", location, tq.tq_depth); - tcp_output_queue(&hc->hc_tcp_session, NULL, &tq); - return 0; + hr->hr_location = strdup(location); + hr->hr_rc = 303; + hr->hr_content = "text/html"; } +/** + * Execute url callback + * + * Returns 1 if we should disconnect + * + */ +static int +http_exec(http_connection_t *hc, http_path_t *hp, char *remain, int err) +{ + http_reply_t *hr = calloc(1, sizeof(http_reply_t)); + + /* Insert reply in order */ + TAILQ_INSERT_TAIL(&hc->hc_replies, hr, hr_link); + + tcp_init_queue(&hr->hr_tq, -1); + hr->hr_version = hc->hc_version; + hr->hr_keep_alive = hc->hc_keep_alive; + + if(!err) + err = hp->hp_callback(hc, hr, remain, hp->hp_opaque); + + if(err) + http_error(hc, hr, err); + + if(hr->hr_destroy != NULL) + return 0; /* New entry is delayed, do not transmit anything */ + + return http_xmit_queue(hc); +} + + + /** * HTTP GET */ -static void +static int http_cmd_get(http_connection_t *hc) { http_path_t *hp; char *remain; char *args; - int err; hp = http_resolve(hc, &remain, &args); - if(hp == NULL) { - http_error(hc, HTTP_STATUS_NOT_FOUND); - return; - } + if(hp == NULL) + return http_exec(hc, NULL, NULL, HTTP_STATUS_NOT_FOUND); if(args != NULL) http_parse_get_args(hc, args); - err = hp->hp_callback(hc, remain, hp->hp_opaque); - if(err) - http_error(hc, err); + return http_exec(hc, hp, remain, 0); } /** * Check if a HTTP POST is fully received, and if so, continue processing + * + * Return non-zero if we should disconnect */ -static void +static int http_post_check(http_connection_t *hc) { http_path_t *hp; char *remain, *args, *v, *argv[2]; - int err, n; + int n; if(hc->hc_post_ptr != hc->hc_post_len) - return; + return 0; hc->hc_state = HTTP_CON_WAIT_REQUEST; /* Parse content-type */ v = http_arg_get(&hc->hc_args, "Content-Type"); - if(v == NULL) { - http_error(hc, HTTP_STATUS_BAD_REQUEST); - return; - } + if(v == NULL) + return http_exec(hc, NULL, NULL, HTTP_STATUS_BAD_REQUEST); n = http_tokenize(v, argv, 2, ';'); - if(n == 0) { - http_error(hc, HTTP_STATUS_BAD_REQUEST); - return; - } + if(n == 0) + return http_exec(hc, NULL, NULL, HTTP_STATUS_BAD_REQUEST); if(!strcmp(argv[0], "application/x-www-form-urlencoded")) http_parse_get_args(hc, hc->hc_post_data); hp = http_resolve(hc, &remain, &args); - if(hp == NULL) { - http_error(hc, HTTP_STATUS_NOT_FOUND); - return; - } + if(hp == NULL) + return http_exec(hc, NULL, NULL, HTTP_STATUS_NOT_FOUND); - err = hp->hp_callback(hc, remain, hp->hp_opaque); - if(err) - http_error(hc, err); + return http_exec(hc, hp, remain, 0); } @@ -368,27 +419,23 @@ http_post_check(http_connection_t *hc) /** - * HTTP POST + * Initial processing of HTTP POST + * + * Return non-zero if we should disconnect */ -static void +static int http_cmd_post(http_connection_t *hc) { char *v; /* Set keep-alive status */ v = http_arg_get(&hc->hc_args, "Content-Length"); - if(v == NULL) { - /* No content length in POST, make us disconnect */ - hc->hc_keep_alive = 0; - return; - } + if(v == NULL) + return 1; /* No content length in POST, make us disconnect */ hc->hc_post_len = atoi(v); - if(hc->hc_post_len > 16 * 1024 * 1024) { - /* Bail out if POST data > 16 Mb */ - hc->hc_keep_alive = 0; - return; - } + if(hc->hc_post_len > 16 * 1024 * 1024) + return 1; /* Bail out if POST data > 16 Mb */ hc->hc_state = HTTP_CON_POST_DATA; @@ -404,8 +451,7 @@ http_cmd_post(http_connection_t *hc) hc->hc_post_ptr = tcp_line_drain(&hc->hc_tcp_session, hc->hc_post_data, hc->hc_post_len); - - http_post_check(hc); + return http_post_check(hc); } @@ -426,25 +472,23 @@ http_consume_post_data(http_connection_t *hc) } hc->hc_post_ptr += r; - http_post_check(hc); + if(http_post_check(hc)) + tcp_disconnect(tcp, 0); } /** * Process a HTTP request */ -static void +static int http_process_request(http_connection_t *hc) { switch(hc->hc_cmd) { default: - http_error(hc, HTTP_STATUS_BAD_REQUEST); - break; + return http_exec(hc, NULL, NULL, HTTP_STATUS_BAD_REQUEST); case HTTP_CMD_GET: - http_cmd_get(hc); - break; + return http_cmd_get(hc); case HTTP_CMD_POST: - http_cmd_post(hc); - break; + return http_cmd_post(hc); } } @@ -518,22 +562,22 @@ process_request(http_connection_t *hc) switch(hc->hc_version) { case RTSP_VERSION_1_0: rtsp_process_request(hc); - break; + return 0; case HTTP_VERSION_0_9: case HTTP_VERSION_1_0: case HTTP_VERSION_1_1: - http_process_request(hc); - break; + return http_process_request(hc) ? -1 : 0; } - - return hc->hc_keep_alive == 0 ? -1 : 0; + return -1; } /* * HTTP connection state machine & parser + * + * If we return non zero we will disconnect */ static int http_con_parse(void *aux, char *buf) @@ -615,6 +659,11 @@ http_con_parse(void *aux, char *buf) static void http_disconnect(http_connection_t *hc) { + http_reply_t *hr; + + while((hr = TAILQ_FIRST(&hc->hc_replies)) != NULL) + http_destroy_reply(hc, hr); + free(hc->hc_post_data); free(hc->hc_username); free(hc->hc_password); @@ -636,6 +685,7 @@ http_tcp_callback(tcpevent_t event, void *tcpsession) switch(event) { case TCP_CONNECT: + TAILQ_INIT(&hc->hc_replies); TAILQ_INIT(&hc->hc_args); TAILQ_INIT(&hc->hc_req_args); break; @@ -865,14 +915,13 @@ typedef struct http_resource { } http_resource_t; static int -deliver_resource(http_connection_t *hc, const char *remain, void *opaque) +deliver_resource(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) { http_resource_t *hres = opaque; - tcp_queue_t tq; - tcp_init_queue(&tq, -1); - tcp_qput(&tq, hres->data, hres->len); - http_output_queue_encoding(hc, &tq, hres->content, 15, hres->encoding); + tcp_qput(&hr->hr_tq, hres->data, hres->len); + http_output(hc, hr, hres->content, hres->encoding, 15); return 0; } diff --git a/http.h b/http.h index f0f1b080..b8aaf754 100644 --- a/http.h +++ b/http.h @@ -42,11 +42,37 @@ typedef struct http_arg { } http_arg_t; +TAILQ_HEAD(http_reply_queue, http_reply); + +typedef struct http_reply { + TAILQ_ENTRY(http_reply) hr_link; + + void *hr_opaque; + + void (*hr_destroy)(struct http_reply *hr, void *opaque); + + int hr_version; /* HTTP version */ + int hr_keep_alive; + + char *hr_location; + + int hr_rc; /* Return code */ + int hr_maxage; + const char *hr_encoding; + const char *hr_content; + + tcp_queue_t hr_tq; + +} http_reply_t; + + typedef struct http_connection { tcp_session_t hc_tcp_session; /* Must be first */ char *hc_url; int hc_keep_alive; + struct http_reply_queue hc_replies; + struct http_arg_list hc_args; struct http_arg_list hc_req_args; /* Argumets from GET or POST request */ @@ -103,15 +129,18 @@ void http_arg_set(struct http_arg_list *list, char *key, char *val); int http_tokenize(char *buf, char **vec, int vecsize, int delimiter); -void http_error(http_connection_t *hc, int error); +void http_error(http_connection_t *hc, http_reply_t *hr, int error); -void http_output_queue(http_connection_t *hc, tcp_queue_t *tq, - const char *content, int maxage); +void http_output(http_connection_t *hc, http_reply_t *hr, + const char *content, const char *encoding, int maxage); -int http_redirect(http_connection_t *hc, const char *location); +void http_output_html(http_connection_t *hc, http_reply_t *hr); -typedef int (http_callback_t)(http_connection_t *hc, const char *remain, - void *opaque); +void http_redirect(http_connection_t *hc, http_reply_t *hr, + const char *location); + +typedef int (http_callback_t)(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque); typedef struct http_path { LIST_ENTRY(http_path) hp_link; diff --git a/tcp.c b/tcp.c index e7e9319f..c77c808c 100644 --- a/tcp.c +++ b/tcp.c @@ -351,7 +351,7 @@ tcp_output_queue(tcp_session_t *ses, tcp_queue_t *dst, tcp_queue_t *src) dst->tq_depth += s; } - if(!ses->tcp_blocked) + if(ses != NULL && !ses->tcp_blocked) tcp_transmit(ses); src->tq_depth = 0;