]>
code.delx.au - pulseaudio/blob - src/pulsecore/protocol-http.c
2 This file is part of PulseAudio.
4 Copyright 2005-2006 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <pulse/util.h>
31 #include <pulse/xmalloc.h>
33 #include <pulsecore/ioline.h>
34 #include <pulsecore/macro.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/namereg.h>
37 #include <pulsecore/cli-text.h>
38 #include <pulsecore/shared.h>
40 #include "protocol-http.h"
42 /* Don't allow more than this many concurrent connections */
43 #define MAX_CONNECTIONS 10
45 #define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL)
48 #define URL_CSS "/style"
49 #define URL_STATUS "/status"
52 pa_http_protocol
*protocol
;
63 struct pa_http_protocol
{
67 pa_idxset
*connections
;
70 static void http_response(struct connection
*c
, int code
, const char *msg
, const char *mime
) {
77 pa_snprintf(s
, sizeof(s
),
81 "Cache-Control: no-cache\n"
83 "Server: "PACKAGE_NAME
"/"PACKAGE_VERSION
"\n"
84 "\n", code
, msg
, mime
);
86 pa_ioline_puts(c
->line
, s
);
89 static void http_message(struct connection
*c
, int code
, const char *msg
, const char *text
) {
93 http_response(c
, code
, msg
, "text/html");
98 pa_snprintf(s
, sizeof(s
),
99 "<?xml version=\"1.0\"?>\n"
100 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
101 "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>%s</title></head>\n"
102 "<body>%s</body></html>\n",
105 pa_ioline_puts(c
->line
, s
);
106 pa_ioline_defer_close(c
->line
);
110 static void connection_unlink(struct connection
*c
) {
116 pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
);
118 pa_ioline_unref(c
->line
);
122 static void line_callback(pa_ioline
*line
, const char *s
, void *userdata
) {
123 struct connection
*c
= userdata
;
129 connection_unlink(c
);
135 if (memcmp(s
, "GET ", 4))
140 c
->url
= pa_xstrndup(s
, strcspn(s
, " \r\n\t?"));
141 c
->state
= MIME_HEADER
;
148 /* Ignore MIME headers */
149 if (strcspn(s
, " \r\n") != 0)
155 pa_log_info("request for %s", c
->url
);
157 if (!strcmp(c
->url
, URL_ROOT
)) {
160 pa_source
*def_source
;
161 http_response(c
, 200, "OK", "text/html");
163 pa_ioline_puts(c
->line
,
164 "<?xml version=\"1.0\"?>\n"
165 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
166 "<html xmlns=\"http://www.w3.org/1999/xhtml\"><title>"PACKAGE_NAME
" "PACKAGE_VERSION
"</title>\n"
167 "<link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/></head><body>\n");
169 pa_ioline_puts(c
->line
,
170 "<h1>"PACKAGE_NAME
" "PACKAGE_VERSION
"</h1>\n"
173 #define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "<tr><td><b>%s</b></td><td>%s</td></tr>\n",(a),(b))
175 PRINTF_FIELD("User Name:", pa_get_user_name(txt
, sizeof(txt
)));
176 PRINTF_FIELD("Host name:", pa_get_host_name(txt
, sizeof(txt
)));
177 PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt
, sizeof(txt
), &c
->protocol
->core
->default_sample_spec
));
179 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
180 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
182 PRINTF_FIELD("Default Sink:", def_sink
? def_sink
->name
: "n/a");
183 PRINTF_FIELD("Default Source:", def_source
? def_source
->name
: "n/a");
185 pa_ioline_puts(c
->line
, "</table>");
187 pa_ioline_puts(c
->line
, "<p><a href=\"/status\">Click here</a> for an extensive server status report.</p>");
189 pa_ioline_puts(c
->line
, "</body></html>\n");
191 pa_ioline_defer_close(c
->line
);
192 } else if (!strcmp(c
->url
, URL_CSS
)) {
193 http_response(c
, 200, "OK", "text/css");
195 pa_ioline_puts(c
->line
,
196 "body { color: black; background-color: white; margin: 0.5cm; }\n"
197 "a:link, a:visited { color: #900000; }\n"
198 "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n"
199 "h1 { color: #00009F; }\n"
200 "h2 { color: #00009F; }\n"
201 "ul { margin-left: .5cm; }\n"
202 "ol { margin-left: .5cm; }\n"
203 "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n"
204 ".grey { color: #afafaf; }\n"
205 "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
206 "td { padding-left:10px; padding-right:10px; }\n");
208 pa_ioline_defer_close(c
->line
);
209 } else if (!strcmp(c
->url
, URL_STATUS
)) {
212 http_response(c
, 200, "OK", "text/plain");
213 r
= pa_full_status_string(c
->protocol
->core
);
214 pa_ioline_puts(c
->line
, r
);
217 pa_ioline_defer_close(c
->line
);
219 http_message(c
, 404, "Not Found", NULL
);
231 internal_server_error(c
);
234 void pa_http_protocol_connect(pa_http_protocol
*p
, pa_iochannel
*io
, pa_module
*m
) {
235 struct connection
*c
;
241 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
242 pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
243 pa_iochannel_free(io
);
247 c
= pa_xnew(struct connection
, 1);
249 c
->line
= pa_ioline_new(io
);
250 c
->state
= REQUEST_LINE
;
254 pa_ioline_set_callback(c
->line
, line_callback
, c
);
256 pa_idxset_put(p
->connections
, c
, NULL
);
259 void pa_http_protocol_disconnect(pa_http_protocol
*p
, pa_module
*m
) {
260 struct connection
*c
;
266 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
268 connection_unlink(c
);
271 static pa_http_protocol
* http_protocol_new(pa_core
*c
) {
276 p
= pa_xnew(pa_http_protocol
, 1);
279 p
->connections
= pa_idxset_new(NULL
, NULL
);
281 pa_assert_se(pa_shared_set(c
, "http-protocol", p
) >= 0);
286 pa_http_protocol
* pa_http_protocol_get(pa_core
*c
) {
289 if ((p
= pa_shared_get(c
, "http-protocol")))
290 return pa_http_protocol_ref(p
);
292 return http_protocol_new(c
);
295 pa_http_protocol
* pa_http_protocol_ref(pa_http_protocol
*p
) {
297 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
304 void pa_http_protocol_unref(pa_http_protocol
*p
) {
305 struct connection
*c
;
308 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
310 if (PA_REFCNT_DEC(p
) > 0)
313 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
314 connection_unlink(c
);
316 pa_idxset_free(p
->connections
, NULL
, NULL
);
318 pa_assert_se(pa_shared_remove(p
->core
, "http-protocol") >= 0);