Rewrite HTTP server so it can defer replies

This commit is contained in:
Andreas Öman 2008-04-14 18:59:31 +00:00
parent 186e1b8c6a
commit 2d700d2901
10 changed files with 530 additions and 540 deletions

View file

@ -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, "<center>");
tcp_qprintf(tq, "<div style=\"padding: auto; width: 400px\">");
tcp_qprintf(&tq, "<center>");
tcp_qprintf(&tq, "<div style=\"padding: auto; width: 400px\">");
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "About");
ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, "About");
tcp_qprintf(tq, "<div style=\"text-align: center\">");
tcp_qprintf(&tq, "<div style=\"text-align: center\">");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<p>HTS / Tvheadend</p>"
"<p>(c) 2006-2008 Andreas \303\226man</p>"
"<p>Latest release and information is available at:</p>"
@ -317,12 +314,12 @@ ajax_about_tab(http_connection_t *hc)
"<p><a href=\"http://www.ffmpeg.org/\">FFmpeg</a></p>"
);
tcp_qprintf(&tq, "</div>");
ajax_box_end(&tq, AJAX_BOX_SIDEBOX);
tcp_qprintf(&tq, "</div>");
tcp_qprintf(&tq, "</center>");
tcp_qprintf(tq, "</div>");
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
tcp_qprintf(tq, "</div>");
tcp_qprintf(tq, "</center>");
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,
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\r\n"
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
/*
@ -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,
"<link href=\"/ajax/ajaxui.css\" rel=\"stylesheet\" "
"type=\"text/css\">\r\n");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script src=\"/ajax/prototype.js\" type=\"text/javascript\">"
"</script>\r\n");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script src=\"/ajax/effects.js\" type=\"text/javascript\">"
"</script>\r\n");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script src=\"/ajax/dragdrop.js\" type=\"text/javascript\">"
"</script>\r\n");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script src=\"/ajax/controls.js\" type=\"text/javascript\">"
"</script>\r\n");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script src=\"/ajax/tvheadend.js\" type=\"text/javascript\">"
"</script>\r\n");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"</head>");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<body>");
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, "<div id=\"topdeck\"></div>");
tcp_qprintf(tq, "<div id=\"topdeck\"></div>");
ajax_js(&tq, "switchtab('top', '0')");
ajax_js(tq, "switchtab('top', '0')");
tcp_qprintf(&tq, "</body></html>");
tcp_qprintf(tq, "</body></html>");
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,
"<ul id=\"list\">"
"<li id=\"item_1\">I'm number 1 <a href=\"/\">a link</a></li>"
"<li id=\"item_2\">");
ajax_box_top(&tq, NULL, NULL);
tcp_qprintf(&tq,
"I'm number 2");
ajax_box_bottom(&tq);
tcp_qprintf(&tq,
"</li>"
"<li id=\"item_3\">I'm number 3</li>"
"<li id=\"item_4\">I'm number 4</li>"
"</ul>"
"\r\n"
"<p id=\"list-info\"></p>\r\n");
tcp_qprintf(&tq,
"<script type=\"text/javascript\">\r\n"
"//<![CDATA[\r\n"
"Sortable.create(\"list\", {onUpdate:function(){new Ajax.Updater('list-info', '/ajax/order', {asynchronous:true, evalScripts:true, onComplete:function(request){new Effect.Highlight(\"list\",{});}, parameters:Sortable.serialize(\"list\")})}})\r\n"
"//]]>\r\n"
"</script>\r\n");
tcp_qprintf(&tq,
"<div id=\"updateDiv\"></div>\r\n"
"<form id=\"testform\">\n"
"<input name=\"name\" type=\"text\"><br>\r\n"
"<textarea name=\"comment\" cols=\"20\" rows=\"3\">"
"</textarea><br>\r\n"
"<input name=\"sendbutton\" type=\"button\" value=\"Send\""
" onClick=\"new Ajax.Updater('updateDiv', '/ajax/formupdate', "
"{asynchronous:true, "
" parameters:Form.serialize($('testform'))})\">\r\n"
"</form>\r\n");
for(i = 0; i < 40; i++) {
tcp_qprintf(&tq,
"<div style=\"float: left\" class=\"sidebox\">\r\n"
" <div class=\"boxhead\"><h2>Discovery</h2></div>\r\n"
" <div class=\"boxbody\">"
" <p>Idag e det bra saker pa TV</p>"
" <p>Imorgon vet vi inte</p>"
"</div></div>");
}
tcp_qprintf(&tq,
"</body></html>");
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
return 0;
}
#endif
/**

View file

@ -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);

View file

@ -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, "<div id=\"channelgroupdeck\"></div>");
tcp_qprintf(&tq, "<div id=\"channelgroupdeck\"></div>");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script type=\"text/javascript\">"
"switchtab('channelgroup', '0')"
"</script>");
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
http_output_html(hc, hr);
return 0;
}

View file

@ -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, "<div id=\"configdeck\"></div>");
tcp_qprintf(&tq, "<div id=\"configdeck\"></div>");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<script type=\"text/javascript\">"
"switchtab('config', '0')"
"</script>");
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
http_output_html(hc, hr);
return 0;
}

View file

@ -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, "<span id=\"updatedok\">Updated on server</span>");
ajax_js(&tq, "Effect.Fade('updatedok')");
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
tcp_qprintf(tq, "<span id=\"updatedok\">Updated on server</span>");
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, "<div style=\"float: left; width: 40%\">");
tcp_qprintf(tq, "<div style=\"float: left; width: 40%\">");
ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, "channelgroups",
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, "channelgroups",
NULL, "Channel groups");
tcp_qprintf(&tq, "<div style=\"height:15px; text-align:center\" "
tcp_qprintf(tq, "<div style=\"height:15px; text-align:center\" "
"id=\"list-info\"></div>");
tcp_qprintf(&tq, "<ul id=\"channelgrouplist\" class=\"draglist\">");
tcp_qprintf(tq, "<ul id=\"channelgrouplist\" class=\"draglist\">");
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
if(tcg->tcg_hidden)
continue;
ajax_chgroup_build(&tq, tcg);
ajax_chgroup_build(tq, tcg);
}
tcp_qprintf(&tq, "</ul>");
tcp_qprintf(tq, "</ul>");
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,
"<div style=\"height: 20px\">"
"<div style=\"float: left\">"
"<input class=\"textinput\" type=\"text\" id=\"newchgrp\">"
@ -220,21 +214,18 @@ ajax_config_channels_tab(http_connection_t *hc)
"Add</a></div>"
"</div>");
ajax_box_end(&tq, AJAX_BOX_BORDER);
ajax_box_end(tq, AJAX_BOX_BORDER);
ajax_box_end(&tq, AJAX_BOX_SIDEBOX);
tcp_qprintf(&tq, "</div>");
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
tcp_qprintf(tq, "</div>");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div id=\"groupeditortab\" "
"style=\"height: 600px; overflow: auto; "
"float: left; width: 60%\">");
tcp_qprintf(&tq, "</div>");
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
tcp_qprintf(tq, "</div>");
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, "<ul id=\"channellist\" class=\"draglist\">");
tcp_qprintf(tq, "<ul id=\"channellist\" class=\"draglist\">");
TAILQ_FOREACH(ch, &tcg->tcg_channels, ch_group_link) {
tcp_qprintf(&tq, "<li id=\"ch_%d\">", ch->ch_tag);
tcp_qprintf(tq, "<li id=\"ch_%d\">", ch->ch_tag);
ajax_box_begin(&tq, AJAX_BOX_BORDER, NULL, NULL, NULL);
ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL);
tcp_qprintf(&tq, "<div style=\"overflow: auto; width: 100%\">");
tcp_qprintf(tq, "<div style=\"overflow: auto; width: 100%\">");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div style=\"float: left; width: 100%\">"
"<a href=\"javascript:void(0)\" >"
"%s</a>"
"</div>",
ch->ch_name);
tcp_qprintf(&tq, "</div>");
ajax_box_end(&tq, AJAX_BOX_BORDER);
tcp_qprintf(&tq, "</li>");
tcp_qprintf(tq, "</div>");
ajax_box_end(tq, AJAX_BOX_BORDER);
tcp_qprintf(tq, "</li>");
}
tcp_qprintf(&tq, "</ul>");
tcp_qprintf(tq, "</ul>");
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;
}

View file

@ -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, "<div class=\"infoprefix\">Status:</div>"
tcp_qprintf(tq, "<div class=\"infoprefix\">Status:</div>"
"<div>%s</div>",
val2str(tda->tda_state, adapterstatus) ?: "invalid");
tcp_qprintf(&tq, "<div class=\"infoprefix\">Type:</div>"
tcp_qprintf(tq, "<div class=\"infoprefix\">Type:</div>"
"<div>%s</div>",
dvb_adaptertype_to_str(tda->tda_fe_info->type));
tcp_qprintf(&tq, "<div style=\"text-align: center\">"
tcp_qprintf(tq, "<div style=\"text-align: center\">"
"<a href=\"javascript:void(0);\" "
"onClick=\"new Ajax.Updater('dvbadaptereditor', "
"'/ajax/dvbadaptereditor/%s', "
"{method: 'get', evalScripts: true})\""
"\">Edit</a></div>", 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, "<div style=\"overflow: auto; width: 100%\">");
tcp_qprintf(tq, "<div style=\"overflow: auto; width: 100%\">");
LIST_FOREACH(tda, &dvb_adapters, tda_global_link) {
tcp_qprintf(&tq, "<div id=\"summary_%s\" "
tcp_qprintf(tq, "<div id=\"summary_%s\" "
"style=\"float:left; width: 250px\"></div>",
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, "</div>");
tcp_qprintf(&tq, "<div id=\"dvbadaptereditor\"></div>");
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
tcp_qprintf(tq, "</div>");
tcp_qprintf(tq, "<div id=\"dvbadaptereditor\"></div>");
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,
"<div style=\"text-align: center; font-weight: bold\">%s</div>",
tda->tda_displayname);
ajax_box_end(&tq, AJAX_BOX_FILLED);
ajax_box_end(tq, AJAX_BOX_FILLED);
/* Type */
tcp_qprintf(&tq, "<div class=\"infoprefixwide\">Model:</div>"
tcp_qprintf(tq, "<div class=\"infoprefixwide\">Model:</div>"
"<div>%s (%s)</div>",
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, "<div class=\"infoprefixwide\">Freq. Range:</div>"
tcp_qprintf(tq, "<div class=\"infoprefixwide\">Freq. Range:</div>"
"<div>%.2f - %.2f kHz, in steps of %.2f kHz</div>",
a, b, c);
if(tda->tda_fe_info->symbol_rate_min) {
tcp_qprintf(&tq, "<div class=\"infoprefixwide\">Symbolrate:</div>"
tcp_qprintf(tq, "<div class=\"infoprefixwide\">Symbolrate:</div>"
"<div>%d - %d BAUD</div>",
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, "<div class=\"infoprefixwide\">Capabilities:</div>");
// tcp_qprintf(tq, "<div class=\"infoprefixwide\">Capabilities:</div>");
tcp_qprintf(&tq, "<div style=\"float: left; width:45%\">");
tcp_qprintf(tq, "<div style=\"float: left; width:45%\">");
ajax_box_begin(&tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Multiplexes");
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Multiplexes");
tcp_qprintf(&tq, "<div id=\"dvbmuxlist%s\"></div>",
tcp_qprintf(tq, "<div id=\"dvbmuxlist%s\"></div>",
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, "<hr><div id=\"addmux\">");
dvb_make_add_link(&tq, tda, NULL);
tcp_qprintf(&tq, "</div>");
tcp_qprintf(tq, "<hr><div id=\"addmux\">");
dvb_make_add_link(tq, tda, NULL);
tcp_qprintf(tq, "</div>");
ajax_box_end(&tq, AJAX_BOX_SIDEBOX);
tcp_qprintf(&tq, "</div>");
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
tcp_qprintf(tq, "</div>");
/* Div for displaying services */
tcp_qprintf(&tq, "<div id=\"servicepane\" "
tcp_qprintf(tq, "<div id=\"servicepane\" "
"style=\"float: left; width:55%\">");
tcp_qprintf(&tq, "</div>");
tcp_qprintf(tq, "</div>");
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, "<div style=\"text-align: center; font-weight: bold\">"
tcp_qprintf(tq, "<div style=\"text-align: center; font-weight: bold\">"
"Add new %s mux</div>",
dvb_adaptertype_to_str(tda->tda_fe_info->type));
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div class=\"infoprefixwidefat\">Frequency (%s):</div>"
"<div>"
"<input class=\"textinput\" type=\"text\" id=\"freq\">"
@ -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,
"<div class=\"infoprefixwidefat\">Symbolrate:</div>"
"<div>"
"<input class=\"textinput\" type=\"text\" id=\"symrate\">"
@ -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,
"<div class=\"infoprefixwidefat\">Bandwidth:</div>"
"<div><select id=\"bw\" class=\"textinput\">");
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, "</select></div>");
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, "</select></div>");
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,
"<div class=\"infoprefixwidefat\">Constellation:</div>"
"<div><select id=\"const\" class=\"textinput\">");
add_option(&tq, caps & FE_CAN_QAM_AUTO, "AUTO");
add_option(&tq, caps & FE_CAN_QPSK, "QPSK");
add_option(&tq, caps & FE_CAN_QAM_16, "QAM16");
add_option(&tq, caps & FE_CAN_QAM_32, "QAM32");
add_option(&tq, caps & FE_CAN_QAM_64, "QAM64");
add_option(&tq, caps & FE_CAN_QAM_128, "QAM128");
add_option(&tq, caps & FE_CAN_QAM_256, "QAM256");
add_option(tq, caps & FE_CAN_QAM_AUTO, "AUTO");
add_option(tq, caps & FE_CAN_QPSK, "QPSK");
add_option(tq, caps & FE_CAN_QAM_16, "QAM16");
add_option(tq, caps & FE_CAN_QAM_32, "QAM32");
add_option(tq, caps & FE_CAN_QAM_64, "QAM64");
add_option(tq, caps & FE_CAN_QAM_128, "QAM128");
add_option(tq, caps & FE_CAN_QAM_256, "QAM256");
tcp_qprintf(&tq, "</select></div>");
tcp_qprintf(tq, "</select></div>");
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,
"<div class=\"infoprefixwidefat\">FEC:</div>"
"<div><select id=\"fec\" class=\"textinput\">");
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, "</select></div>");
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, "</select></div>");
snprintf(params + strlen(params), sizeof(params) - strlen(params),
", fec: $F('fec')");
}
if(fetype == FE_QPSK) {
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div class=\"infoprefixwidefat\">Polarisation:</div>"
"<div><select id=\"pol\" class=\"textinput\">");
add_option(&tq, 1, "Vertical");
add_option(&tq, 1, "Horizontal");
tcp_qprintf(&tq, "</select></div>");
add_option(tq, 1, "Vertical");
add_option(tq, 1, "Horizontal");
tcp_qprintf(tq, "</select></div>");
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,
"<div class=\"infoprefixwidefat\">Transmission mode:</div>"
"<div><select id=\"tmode\" class=\"textinput\">");
add_option(&tq, caps & FE_CAN_TRANSMISSION_MODE_AUTO, "AUTO");
add_option(&tq, 1 , "2k");
add_option(&tq, 1 , "8k");
tcp_qprintf(&tq, "</select></div>");
add_option(tq, caps & FE_CAN_TRANSMISSION_MODE_AUTO, "AUTO");
add_option(tq, 1 , "2k");
add_option(tq, 1 , "8k");
tcp_qprintf(tq, "</select></div>");
snprintf(params + strlen(params), sizeof(params) - strlen(params),
", tmode: $F('tmode')");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div class=\"infoprefixwidefat\">Guard interval:</div>"
"<div><select id=\"guard\" class=\"textinput\">");
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, "</select></div>");
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, "</select></div>");
snprintf(params + strlen(params), sizeof(params) - strlen(params),
", guard: $F('guard')");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div class=\"infoprefixwidefat\">Hierarchy:</div>"
"<div><select id=\"hier\" class=\"textinput\">");
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, "</select></div>");
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, "</select></div>");
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,
"<div class=\"infoprefixwidefat\">FEC Hi:</div>"
"<div><select id=\"fechi\" class=\"textinput\">");
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, "</select></div>");
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, "</select></div>");
snprintf(params + strlen(params), sizeof(params) - strlen(params),
", fechi: $F('fechi')");
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div class=\"infoprefixwidefat\">FEC Low:</div>"
"<div><select id=\"feclo\" class=\"textinput\">");
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, "</select></div>");
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, "</select></div>");
snprintf(params + strlen(params), sizeof(params) - strlen(params),
", feclo: $F('feclo')");
}
tcp_qprintf(&tq,
tcp_qprintf(tq,
"<div style=\"text-align: center\">"
"<input type=\"button\" value=\"Create\" "
"onClick=\"new Ajax.Updater('addmux', "
@ -468,7 +463,7 @@ ajax_adapteraddmux(http_connection_t *hc, const char *remain, void *opaque)
"\">"
"</div>", 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, "<hr>");
tcp_qprintf(tq, "<hr>");
v = displines;
if(nmuxes < displines)
v = nmuxes;
tcp_qprintf(&tq, "<div id=\"dvbmuxlist%s\" "
tcp_qprintf(tq, "<div id=\"dvbmuxlist%s\" "
"style=\"height: %dpx; overflow: auto\" class=\"normallist\">",
tda->tda_identifier, v * 14);
if(nmuxes == 0) {
tcp_qprintf(&tq, "<div style=\"text-align: center\">"
tcp_qprintf(tq, "<div style=\"text-align: center\">"
"No muxes configured</div>");
} 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, "</div>");
tcp_qprintf(tq, "</div>");
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;
}

View file

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

367
http.c
View file

@ -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),
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
"<HTML><HEAD>\r\n"
"<TITLE>%d %s</TITLE>\r\n"
"</HEAD><BODY>\r\n"
"<H1>%d %s</H1>\r\n"
"</BODY></HTML>\r\n",
error, errtxt,
error, errtxt);
tcp_qprintf(tq,
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
"<HTML><HEAD>\r\n"
"<TITLE>%d %s</TITLE>\r\n"
"</HEAD><BODY>\r\n"
"<H1>%d %s</H1>\r\n"
"</BODY></HTML>\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,
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
"<HTML><HEAD>\r\n"
"<TITLE>Redirect</TITLE>\r\n"
"</HEAD><BODY>\r\n"
"Please follow <a href=\"%s\">%s</a>\r\n"
"</BODY></HTML>\r\n",
location, location);
if(hc->hc_version < HTTP_VERSION_1_0)
return -1;
tcp_init_queue(&tq, -1);
tcp_qprintf(&tq, "Please follow <a href=\"%s\"\"></a>", 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;
}

41
http.h
View file

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

2
tcp.c
View file

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