mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	protocol-http: substantial modernizations
This commit is contained in:
		
							parent
							
								
									d8710711fb
								
							
						
					
					
						commit
						0b2d96d6c0
					
				
					 1 changed files with 394 additions and 103 deletions
				
			
		| 
						 | 
				
			
			@ -42,20 +42,39 @@
 | 
			
		|||
/* Don't allow more than this many concurrent connections */
 | 
			
		||||
#define MAX_CONNECTIONS 10
 | 
			
		||||
 | 
			
		||||
#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL)
 | 
			
		||||
 | 
			
		||||
#define URL_ROOT "/"
 | 
			
		||||
#define URL_CSS "/style"
 | 
			
		||||
#define URL_STATUS "/status"
 | 
			
		||||
#define URL_LISTEN "/listen"
 | 
			
		||||
#define URL_LISTEN_PREFIX "/listen/"
 | 
			
		||||
 | 
			
		||||
#define MIME_HTML "text/html; charset=utf-8"
 | 
			
		||||
#define MIME_TEXT "text/plain; charset=utf-8"
 | 
			
		||||
#define MIME_CSS "text/css"
 | 
			
		||||
 | 
			
		||||
#define HTML_HEADER(t)                                                  \
 | 
			
		||||
    "<?xml version=\"1.0\"?>\n"                                         \
 | 
			
		||||
    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" \
 | 
			
		||||
    "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"                   \
 | 
			
		||||
    "        <head>\n"                                                  \
 | 
			
		||||
    "                <title>"t"</title>\n"                              \
 | 
			
		||||
    "                <link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/>\n" \
 | 
			
		||||
    "        </head>\n"                                                 \
 | 
			
		||||
    "        <body>\n"
 | 
			
		||||
 | 
			
		||||
#define HTML_FOOTER                                                     \
 | 
			
		||||
    "        </body>\n"                                                 \
 | 
			
		||||
    "</html>\n"
 | 
			
		||||
enum state {
 | 
			
		||||
    STATE_REQUEST_LINE,
 | 
			
		||||
    STATE_MIME_HEADER,
 | 
			
		||||
    STATE_DATA
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct connection {
 | 
			
		||||
    pa_http_protocol *protocol;
 | 
			
		||||
    pa_ioline *line;
 | 
			
		||||
    enum {
 | 
			
		||||
        REQUEST_LINE,
 | 
			
		||||
        MIME_HEADER,
 | 
			
		||||
        DATA
 | 
			
		||||
    } state;
 | 
			
		||||
    enum state state;
 | 
			
		||||
    char *url;
 | 
			
		||||
    pa_module *module;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -67,14 +86,200 @@ struct pa_http_protocol {
 | 
			
		|||
    pa_idxset *connections;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void http_response(struct connection *c, int code, const char *msg, const char *mime) {
 | 
			
		||||
    char s[256];
 | 
			
		||||
 | 
			
		||||
static pa_bool_t is_mime_sample_spec(const pa_sample_spec *ss, const pa_channel_map *cm) {
 | 
			
		||||
 | 
			
		||||
    pa_assert(pa_channel_map_compatible(cm, ss));
 | 
			
		||||
 | 
			
		||||
    switch (ss->format) {
 | 
			
		||||
        case PA_SAMPLE_S16BE:
 | 
			
		||||
        case PA_SAMPLE_S24BE:
 | 
			
		||||
        case PA_SAMPLE_U8:
 | 
			
		||||
 | 
			
		||||
            if (ss->rate != 8000 &&
 | 
			
		||||
                ss->rate != 11025 &&
 | 
			
		||||
                ss->rate != 16000 &&
 | 
			
		||||
                ss->rate != 22050 &&
 | 
			
		||||
                ss->rate != 24000 &&
 | 
			
		||||
                ss->rate != 32000 &&
 | 
			
		||||
                ss->rate != 44100 &&
 | 
			
		||||
                ss->rate != 48000)
 | 
			
		||||
                return FALSE;
 | 
			
		||||
 | 
			
		||||
            if (ss->channels != 1 &&
 | 
			
		||||
                ss->channels != 2)
 | 
			
		||||
                return FALSE;
 | 
			
		||||
 | 
			
		||||
            if ((cm->channels == 1 && cm->map[0] != PA_CHANNEL_POSITION_MONO) ||
 | 
			
		||||
                (cm->channels == 2 && (cm->map[0] != PA_CHANNEL_POSITION_LEFT || cm->map[1] != PA_CHANNEL_POSITION_RIGHT)))
 | 
			
		||||
                return FALSE;
 | 
			
		||||
 | 
			
		||||
            return TRUE;
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_ULAW:
 | 
			
		||||
 | 
			
		||||
            if (ss->rate != 8000)
 | 
			
		||||
                return FALSE;
 | 
			
		||||
 | 
			
		||||
            if (ss->channels != 1)
 | 
			
		||||
                return FALSE;
 | 
			
		||||
 | 
			
		||||
            if (cm->map[0] != PA_CHANNEL_POSITION_MONO)
 | 
			
		||||
                return FALSE;
 | 
			
		||||
 | 
			
		||||
            return TRUE;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void mimefy_sample_spec(pa_sample_spec *ss, pa_channel_map *cm) {
 | 
			
		||||
 | 
			
		||||
    pa_assert(pa_channel_map_compatible(cm, ss));
 | 
			
		||||
 | 
			
		||||
    /* Turns the sample type passed in into the next 'better' one that
 | 
			
		||||
     * can be encoded for HTTP. If there is no 'better' one we pick
 | 
			
		||||
     * the 'best' one that is 'worse'. */
 | 
			
		||||
 | 
			
		||||
    if (ss->channels > 2)
 | 
			
		||||
        ss->channels = 2;
 | 
			
		||||
 | 
			
		||||
    if (ss->rate > 44100)
 | 
			
		||||
        ss->rate = 48000;
 | 
			
		||||
    else if (ss->rate > 32000)
 | 
			
		||||
        ss->rate = 44100;
 | 
			
		||||
    else if (ss->rate > 24000)
 | 
			
		||||
        ss->rate = 32000;
 | 
			
		||||
    else if (ss->rate > 22050)
 | 
			
		||||
        ss->rate = 24000;
 | 
			
		||||
    else if (ss->rate > 16000)
 | 
			
		||||
        ss->rate = 22050;
 | 
			
		||||
    else if (ss->rate > 11025)
 | 
			
		||||
        ss->rate = 16000;
 | 
			
		||||
    else if (ss->rate > 8000)
 | 
			
		||||
        ss->rate = 11025;
 | 
			
		||||
    else
 | 
			
		||||
        ss->rate = 8000;
 | 
			
		||||
 | 
			
		||||
    switch (ss->format) {
 | 
			
		||||
        case PA_SAMPLE_S24BE:
 | 
			
		||||
        case PA_SAMPLE_S24LE:
 | 
			
		||||
        case PA_SAMPLE_S24_32LE:
 | 
			
		||||
        case PA_SAMPLE_S24_32BE:
 | 
			
		||||
        case PA_SAMPLE_S32LE:
 | 
			
		||||
        case PA_SAMPLE_S32BE:
 | 
			
		||||
        case PA_SAMPLE_FLOAT32LE:
 | 
			
		||||
        case PA_SAMPLE_FLOAT32BE:
 | 
			
		||||
            ss->format = PA_SAMPLE_S24BE;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_S16BE:
 | 
			
		||||
        case PA_SAMPLE_S16LE:
 | 
			
		||||
            ss->format = PA_SAMPLE_S16BE;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_ULAW:
 | 
			
		||||
        case PA_SAMPLE_ALAW:
 | 
			
		||||
 | 
			
		||||
            if (ss->rate == 8000 && ss->channels == 1)
 | 
			
		||||
                ss->format = PA_SAMPLE_ULAW;
 | 
			
		||||
            else
 | 
			
		||||
                ss->format = PA_SAMPLE_S16BE;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_U8:
 | 
			
		||||
            ss->format = PA_SAMPLE_U8;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_MAX:
 | 
			
		||||
        case PA_SAMPLE_INVALID:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_channel_map_init_auto(cm, ss->channels, PA_CHANNEL_MAP_DEFAULT);
 | 
			
		||||
 | 
			
		||||
    pa_assert(is_mime_sample_spec(ss, cm));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *sample_spec_to_mime_type(const pa_sample_spec *ss, const pa_channel_map *cm) {
 | 
			
		||||
    pa_assert(pa_channel_map_compatible(cm, ss));
 | 
			
		||||
 | 
			
		||||
    if (!is_mime_sample_spec(ss, cm))
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    switch (ss->format) {
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_S16BE:
 | 
			
		||||
        case PA_SAMPLE_S24BE:
 | 
			
		||||
        case PA_SAMPLE_U8:
 | 
			
		||||
            return pa_sprintf_malloc("audio/%s; rate=%u; channels=%u",
 | 
			
		||||
                                     ss->format == PA_SAMPLE_S16BE ? "L16" :
 | 
			
		||||
                                     (ss->format == PA_SAMPLE_S24BE ? "L24" : "L8"),
 | 
			
		||||
                                     ss->rate, ss->channels);
 | 
			
		||||
 | 
			
		||||
        case PA_SAMPLE_ULAW:
 | 
			
		||||
            return pa_xstrdup("audio/basic");
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert(pa_sample_spec_valid(ss));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *mimefy_and_stringify_sample_spec(const pa_sample_spec *_ss, const pa_channel_map *_cm) {
 | 
			
		||||
    pa_sample_spec ss = *_ss;
 | 
			
		||||
    pa_channel_map cm = *_cm;
 | 
			
		||||
 | 
			
		||||
    mimefy_sample_spec(&ss, &cm);
 | 
			
		||||
 | 
			
		||||
    return sample_spec_to_mime_type(&ss, &cm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *escape_html(const char *t) {
 | 
			
		||||
    pa_strbuf *sb;
 | 
			
		||||
    const char *p, *e;
 | 
			
		||||
 | 
			
		||||
    sb = pa_strbuf_new();
 | 
			
		||||
 | 
			
		||||
    for (e = p = t; *p; p++) {
 | 
			
		||||
 | 
			
		||||
        if (*p == '>' || *p == '<' || *p == '&') {
 | 
			
		||||
 | 
			
		||||
            if (p > e) {
 | 
			
		||||
                pa_strbuf_putsn(sb, e, p-e);
 | 
			
		||||
                e = p + 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (*p == '>')
 | 
			
		||||
                pa_strbuf_puts(sb, ">");
 | 
			
		||||
            else if (*p == '<')
 | 
			
		||||
                pa_strbuf_puts(sb, "<");
 | 
			
		||||
            else
 | 
			
		||||
                pa_strbuf_puts(sb, "&");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (p > e)
 | 
			
		||||
        pa_strbuf_putsn(sb, e, p-e);
 | 
			
		||||
 | 
			
		||||
    return pa_strbuf_tostring_free(sb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void http_response(
 | 
			
		||||
        struct connection *c,
 | 
			
		||||
        int code,
 | 
			
		||||
        const char *msg,
 | 
			
		||||
        const char *mime) {
 | 
			
		||||
 | 
			
		||||
    char *s;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(mime);
 | 
			
		||||
 | 
			
		||||
    pa_snprintf(s, sizeof(s),
 | 
			
		||||
    s = pa_sprintf_malloc(
 | 
			
		||||
            "HTTP/1.0 %i %s\n"
 | 
			
		||||
            "Connection: close\n"
 | 
			
		||||
            "Content-Type: %s\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -82,30 +287,41 @@ static void http_response(struct connection *c, int code, const char *msg, const
 | 
			
		|||
            "Expires: 0\n"
 | 
			
		||||
            "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n"
 | 
			
		||||
            "\n", code, msg, mime);
 | 
			
		||||
 | 
			
		||||
    pa_ioline_puts(c->line, s);
 | 
			
		||||
    pa_xfree(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void http_message(struct connection *c, int code, const char *msg, const char *text) {
 | 
			
		||||
    char s[256];
 | 
			
		||||
static void html_response(
 | 
			
		||||
        struct connection *c,
 | 
			
		||||
        int code,
 | 
			
		||||
        const char *msg,
 | 
			
		||||
        const char *text) {
 | 
			
		||||
 | 
			
		||||
    char *s;
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    http_response(c, code, msg, "text/html");
 | 
			
		||||
    http_response(c, code, msg, MIME_HTML);
 | 
			
		||||
 | 
			
		||||
    if (!text)
 | 
			
		||||
        text = msg;
 | 
			
		||||
 | 
			
		||||
    pa_snprintf(s, sizeof(s),
 | 
			
		||||
             "<?xml version=\"1.0\"?>\n"
 | 
			
		||||
             "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
 | 
			
		||||
             "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>%s</title></head>\n"
 | 
			
		||||
             "<body>%s</body></html>\n",
 | 
			
		||||
    s = pa_sprintf_malloc(
 | 
			
		||||
            HTML_HEADER("%s")
 | 
			
		||||
            "%s"
 | 
			
		||||
            HTML_FOOTER,
 | 
			
		||||
            text, text);
 | 
			
		||||
 | 
			
		||||
    pa_ioline_puts(c->line, s);
 | 
			
		||||
    pa_xfree(s);
 | 
			
		||||
 | 
			
		||||
    pa_ioline_defer_close(c->line);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void internal_server_error(struct connection *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    html_response(c, 500, "Internal Server Error", NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void connection_unlink(struct connection *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
| 
						 | 
				
			
			@ -113,12 +329,153 @@ static void connection_unlink(struct connection *c) {
 | 
			
		|||
    if (c->url)
 | 
			
		||||
        pa_xfree(c->url);
 | 
			
		||||
 | 
			
		||||
    if (c->line)
 | 
			
		||||
        pa_ioline_unref(c->line);
 | 
			
		||||
 | 
			
		||||
    pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
 | 
			
		||||
 | 
			
		||||
    pa_ioline_unref(c->line);
 | 
			
		||||
    pa_xfree(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void html_print_field(pa_ioline *line, const char *left, const char *right) {
 | 
			
		||||
    char *eleft, *eright;
 | 
			
		||||
 | 
			
		||||
    eleft = escape_html(left);
 | 
			
		||||
    eright = escape_html(right);
 | 
			
		||||
 | 
			
		||||
    pa_ioline_printf(line,
 | 
			
		||||
                     "<tr><td><b>%s</b></td>"
 | 
			
		||||
                     "<td>%s</td></tr>\n", eleft, eright);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(eleft);
 | 
			
		||||
    pa_xfree(eright);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_url(struct connection *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_log_debug("Request for %s", c->url);
 | 
			
		||||
 | 
			
		||||
    if (pa_streq(c->url, URL_ROOT)) {
 | 
			
		||||
        char *t;
 | 
			
		||||
 | 
			
		||||
        http_response(c, 200, "OK", MIME_HTML);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_puts(c->line,
 | 
			
		||||
                       HTML_HEADER(PACKAGE_NAME" "PACKAGE_VERSION)
 | 
			
		||||
                       "<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
 | 
			
		||||
                       "<table>\n");
 | 
			
		||||
 | 
			
		||||
        t = pa_get_user_name_malloc();
 | 
			
		||||
        html_print_field(c->line, "User Name:", t);
 | 
			
		||||
        pa_xfree(t);
 | 
			
		||||
 | 
			
		||||
        t = pa_get_host_name_malloc();
 | 
			
		||||
        html_print_field(c->line, "Host name:", t);
 | 
			
		||||
        pa_xfree(t);
 | 
			
		||||
 | 
			
		||||
        t = pa_machine_id();
 | 
			
		||||
        html_print_field(c->line, "Machine ID:", t);
 | 
			
		||||
        pa_xfree(t);
 | 
			
		||||
 | 
			
		||||
        t = pa_uname_string();
 | 
			
		||||
        html_print_field(c->line, "System:", t);
 | 
			
		||||
        pa_xfree(t);
 | 
			
		||||
 | 
			
		||||
        t = pa_sprintf_malloc("%lu", (unsigned long) getpid());
 | 
			
		||||
        html_print_field(c->line, "Process ID:", t);
 | 
			
		||||
        pa_xfree(t);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_puts(c->line,
 | 
			
		||||
                       "</table>\n"
 | 
			
		||||
                       "<p><a href=\"/status\">Show an extensive server status report</a></p>\n"
 | 
			
		||||
                       "<p><a href=\"/listen\">Monitor sinks and sources</a></p>\n"
 | 
			
		||||
                       HTML_FOOTER);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_defer_close(c->line);
 | 
			
		||||
 | 
			
		||||
    } else if (pa_streq(c->url, URL_CSS)) {
 | 
			
		||||
        http_response(c, 200, "OK", MIME_CSS);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_puts(c->line,
 | 
			
		||||
                       "body { color: black; background-color: white; }\n"
 | 
			
		||||
                       "a:link, a:visited { color: #900000; }\n"
 | 
			
		||||
                       "div.news-date { font-size: 80%; font-style: italic; }\n"
 | 
			
		||||
                       "pre { background-color: #f0f0f0; padding: 0.4cm; }\n"
 | 
			
		||||
                       ".grey { color: #8f8f8f; font-size: 80%; }"
 | 
			
		||||
                       "table {  margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
 | 
			
		||||
                       "td { padding-left:10px; padding-right:10px; }\n");
 | 
			
		||||
 | 
			
		||||
        pa_ioline_defer_close(c->line);
 | 
			
		||||
 | 
			
		||||
    } else if (pa_streq(c->url, URL_STATUS)) {
 | 
			
		||||
        char *r;
 | 
			
		||||
 | 
			
		||||
        http_response(c, 200, "OK", MIME_TEXT);
 | 
			
		||||
        r = pa_full_status_string(c->protocol->core);
 | 
			
		||||
        pa_ioline_puts(c->line, r);
 | 
			
		||||
        pa_xfree(r);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_defer_close(c->line);
 | 
			
		||||
 | 
			
		||||
    } else if (pa_streq(c->url, URL_LISTEN)) {
 | 
			
		||||
        pa_source *source;
 | 
			
		||||
        pa_sink *sink;
 | 
			
		||||
        uint32_t idx;
 | 
			
		||||
 | 
			
		||||
        http_response(c, 200, "OK", MIME_HTML);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_puts(c->line,
 | 
			
		||||
                       HTML_HEADER("Listen")
 | 
			
		||||
                       "<h2>Sinks</h2>\n"
 | 
			
		||||
                       "<p>\n");
 | 
			
		||||
 | 
			
		||||
        PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
 | 
			
		||||
            char *t, *m;
 | 
			
		||||
 | 
			
		||||
            t = escape_html(pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
 | 
			
		||||
            m = mimefy_and_stringify_sample_spec(&sink->sample_spec, &sink->channel_map);
 | 
			
		||||
 | 
			
		||||
            pa_ioline_printf(c->line,
 | 
			
		||||
                             "<a href=\"/listen/%s\" title=\"%s\">%s</a><br/>\n",
 | 
			
		||||
                             sink->monitor_source->name, m, t);
 | 
			
		||||
 | 
			
		||||
            pa_xfree(t);
 | 
			
		||||
            pa_xfree(m);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pa_ioline_puts(c->line,
 | 
			
		||||
                       "</p>\n"
 | 
			
		||||
                       "<h2>Sources</h2>\n"
 | 
			
		||||
                       "<p>\n");
 | 
			
		||||
 | 
			
		||||
        PA_IDXSET_FOREACH(source, c->protocol->core->sources, idx) {
 | 
			
		||||
            char *t, *m;
 | 
			
		||||
 | 
			
		||||
            if (source->monitor_of)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            t = escape_html(pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
 | 
			
		||||
            m = mimefy_and_stringify_sample_spec(&source->sample_spec, &source->channel_map);
 | 
			
		||||
 | 
			
		||||
            pa_ioline_printf(c->line,
 | 
			
		||||
                             "<a href=\"/listen/%s\" title=\"%s\">%s</a><br/>\n",
 | 
			
		||||
                             source->name, m, t);
 | 
			
		||||
 | 
			
		||||
            pa_xfree(m);
 | 
			
		||||
            pa_xfree(t);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pa_ioline_puts(c->line,
 | 
			
		||||
                       "</p>\n"
 | 
			
		||||
                       HTML_FOOTER);
 | 
			
		||||
 | 
			
		||||
        pa_ioline_defer_close(c->line);
 | 
			
		||||
    } else
 | 
			
		||||
        html_response(c, 404, "Not Found", NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void line_callback(pa_ioline *line, const char *s, void *userdata) {
 | 
			
		||||
    struct connection *c = userdata;
 | 
			
		||||
    pa_assert(line);
 | 
			
		||||
| 
						 | 
				
			
			@ -131,93 +488,27 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    switch (c->state) {
 | 
			
		||||
        case REQUEST_LINE: {
 | 
			
		||||
            if (memcmp(s, "GET ", 4))
 | 
			
		||||
        case STATE_REQUEST_LINE: {
 | 
			
		||||
            if (!pa_startswith(s, "GET "))
 | 
			
		||||
                goto fail;
 | 
			
		||||
 | 
			
		||||
            s +=4;
 | 
			
		||||
 | 
			
		||||
            c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?"));
 | 
			
		||||
            c->state = MIME_HEADER;
 | 
			
		||||
            c->state = STATE_MIME_HEADER;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case MIME_HEADER: {
 | 
			
		||||
        case STATE_MIME_HEADER: {
 | 
			
		||||
 | 
			
		||||
            /* Ignore MIME headers */
 | 
			
		||||
            if (strcspn(s, " \r\n") != 0)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            /* We're done */
 | 
			
		||||
            c->state = DATA;
 | 
			
		||||
 | 
			
		||||
            pa_log_info("request for %s", c->url);
 | 
			
		||||
 | 
			
		||||
            if (!strcmp(c->url, URL_ROOT)) {
 | 
			
		||||
                char txt[256];
 | 
			
		||||
                pa_sink *def_sink;
 | 
			
		||||
                pa_source *def_source;
 | 
			
		||||
                http_response(c, 200, "OK", "text/html");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_puts(c->line,
 | 
			
		||||
                               "<?xml version=\"1.0\"?>\n"
 | 
			
		||||
                               "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
 | 
			
		||||
                               "<html xmlns=\"http://www.w3.org/1999/xhtml\"><title>"PACKAGE_NAME" "PACKAGE_VERSION"</title>\n"
 | 
			
		||||
                               "<link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/></head><body>\n");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_puts(c->line,
 | 
			
		||||
                               "<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
 | 
			
		||||
                               "<table>");
 | 
			
		||||
 | 
			
		||||
#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "<tr><td><b>%s</b></td><td>%s</td></tr>\n",(a),(b))
 | 
			
		||||
 | 
			
		||||
                PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt)));
 | 
			
		||||
                PRINTF_FIELD("Host name:", pa_get_host_name(txt, sizeof(txt)));
 | 
			
		||||
                PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec));
 | 
			
		||||
 | 
			
		||||
                def_sink = pa_namereg_get_default_sink(c->protocol->core);
 | 
			
		||||
                def_source = pa_namereg_get_default_source(c->protocol->core);
 | 
			
		||||
 | 
			
		||||
                PRINTF_FIELD("Default Sink:", def_sink ? def_sink->name : "n/a");
 | 
			
		||||
                PRINTF_FIELD("Default Source:", def_source ? def_source->name : "n/a");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_puts(c->line, "</table>");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_puts(c->line, "<p><a href=\"/status\">Click here</a> for an extensive server status report.</p>");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_puts(c->line, "</body></html>\n");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_defer_close(c->line);
 | 
			
		||||
            } else if (!strcmp(c->url, URL_CSS)) {
 | 
			
		||||
                http_response(c, 200, "OK", "text/css");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_puts(c->line,
 | 
			
		||||
                               "body { color: black; background-color: white; margin: 0.5cm; }\n"
 | 
			
		||||
                               "a:link, a:visited { color: #900000; }\n"
 | 
			
		||||
                               "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n"
 | 
			
		||||
                               "h1 { color: #00009F; }\n"
 | 
			
		||||
                               "h2 { color: #00009F; }\n"
 | 
			
		||||
                               "ul { margin-left: .5cm; }\n"
 | 
			
		||||
                               "ol { margin-left: .5cm; }\n"
 | 
			
		||||
                               "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n"
 | 
			
		||||
                               ".grey { color: #afafaf; }\n"
 | 
			
		||||
                               "table {  margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
 | 
			
		||||
                               "td { padding-left:10px; padding-right:10px;  }\n");
 | 
			
		||||
 | 
			
		||||
                pa_ioline_defer_close(c->line);
 | 
			
		||||
            } else if (!strcmp(c->url, URL_STATUS)) {
 | 
			
		||||
                char *r;
 | 
			
		||||
 | 
			
		||||
                http_response(c, 200, "OK", "text/plain");
 | 
			
		||||
                r = pa_full_status_string(c->protocol->core);
 | 
			
		||||
                pa_ioline_puts(c->line, r);
 | 
			
		||||
                pa_xfree(r);
 | 
			
		||||
 | 
			
		||||
                pa_ioline_defer_close(c->line);
 | 
			
		||||
            } else
 | 
			
		||||
                http_message(c, 404, "Not Found", NULL);
 | 
			
		||||
            c->state = STATE_DATA;
 | 
			
		||||
 | 
			
		||||
            handle_url(c);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -247,7 +538,7 @@ void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *
 | 
			
		|||
    c = pa_xnew(struct connection, 1);
 | 
			
		||||
    c->protocol = p;
 | 
			
		||||
    c->line = pa_ioline_new(io);
 | 
			
		||||
    c->state = REQUEST_LINE;
 | 
			
		||||
    c->state = STATE_REQUEST_LINE;
 | 
			
		||||
    c->url = NULL;
 | 
			
		||||
    c->module = m;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,12 +549,12 @@ void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *
 | 
			
		|||
 | 
			
		||||
void pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m) {
 | 
			
		||||
    struct connection *c;
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
 | 
			
		||||
    PA_IDXSET_FOREACH(c, p->connections, idx)
 | 
			
		||||
        if (c->module == m)
 | 
			
		||||
            connection_unlink(c);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue