diff --git a/src/httpd.c b/src/httpd.c index ed9372f1..f6d272b5 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -49,15 +49,19 @@ /* * HTTP client quirks by User-Agent, from mt-daapd * - * - Roku: - * + Does not encode space as + in query string * - iTunes: - * + Does not encode space as + in query string * + Connection: Keep-Alive on HTTP error 401 * - Hifidelio: * + Connection: Keep-Alive for streaming (Connection: close not honoured) * * These quirks are not implemented. Implement as needed. + * + * Implemented quirks: + * + * - Roku: + * + Does not encode space as + in query string + * - iTunes: + * + Does not encode space as + in query string */ @@ -715,6 +719,84 @@ exit_cb(int fd, short event, void *arg) httpd_exit = 1; } +char * +httpd_fixup_uri(struct evhttp_request *req) +{ + const char *ua; + const char *uri; + const char *u; + const char *q; + char *fixed; + char *f; + int len; + + uri = evhttp_request_uri(req); + if (!uri) + return NULL; + + /* No query string, nothing to do */ + q = strchr(uri, '?'); + if (!q) + return strdup(uri); + + ua = evhttp_find_header(req->input_headers, "User-Agent"); + if (!ua) + return strdup(uri); + + if ((strncmp(ua, "iTunes", strlen("iTunes")) != 0) + && (strncmp(ua, "Roku", strlen("Roku")) != 0)) + return strdup(uri); + + /* Reencode + as %2B and space as + in the query, + which iTunes and Roku devices don't do */ + len = strlen(uri); + + u = q; + while (*u) + { + if (*u == '+') + len += 2; + + u++; + } + + fixed = (char *)malloc(len + 1); + if (!fixed) + return NULL; + + strncpy(fixed, uri, q - uri); + + f = fixed + (q - uri); + while (*q) + { + switch (*q) + { + case '+': + *f = '%'; + f++; + *f = '2'; + f++; + *f = 'B'; + break; + + case ' ': + *f = '+'; + break; + + default: + *f = *q; + break; + } + + q++; + f++; + } + + *f = '\0'; + + return fixed; +} + static char *http_reply_401 = "401 UnauthorizedAuthorization required"; int diff --git a/src/httpd.h b/src/httpd.h index 34dc1e65..f7826617 100644 --- a/src/httpd.h +++ b/src/httpd.h @@ -9,6 +9,9 @@ void httpd_stream_file(struct evhttp_request *req, int id); +char * +httpd_fixup_uri(struct evhttp_request *req); + int httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *realm); diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 0ce8ff95..1d225d81 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -1782,7 +1782,6 @@ static struct uri_map daap_handlers[] = void daap_request(struct evhttp_request *req) { - const char *req_uri; char *full_uri; char *uri; char *ptr; @@ -1796,23 +1795,27 @@ daap_request(struct evhttp_request *req) int ret; int i; - req_uri = evhttp_request_uri(req); - - full_uri = strdup(req_uri); + full_uri = httpd_fixup_uri(req); + if (!full_uri) + { + evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request"); + return; + } ptr = strchr(full_uri, '?'); if (ptr) *ptr = '\0'; uri = strdup(full_uri); + if (!uri) + { + evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request"); + return; + } if (ptr) *ptr = '?'; - ptr = full_uri; - full_uri = evhttp_decode_uri(full_uri); - free(ptr); - ptr = uri; uri = evhttp_decode_uri(uri); free(ptr); diff --git a/src/httpd_rsp.c b/src/httpd_rsp.c index 302c939f..45c38c34 100644 --- a/src/httpd_rsp.c +++ b/src/httpd_rsp.c @@ -897,7 +897,6 @@ static struct uri_map rsp_handlers[] = void rsp_request(struct evhttp_request *req) { - const char *req_uri; char *full_uri; char *uri; char *ptr; @@ -910,23 +909,27 @@ rsp_request(struct evhttp_request *req) int i; int ret; - req_uri = evhttp_request_uri(req); - - full_uri = strdup(req_uri); + full_uri = httpd_fixup_uri(req); + if (!full_uri) + { + rsp_send_error(req, "Server error"); + return; + } ptr = strchr(full_uri, '?'); if (ptr) *ptr = '\0'; uri = strdup(full_uri); + if (!uri) + { + rsp_send_error(req, "Server error"); + return; + } if (ptr) *ptr = '?'; - ptr = full_uri; - full_uri = evhttp_decode_uri(full_uri); - free(ptr); - ptr = uri; uri = evhttp_decode_uri(uri); free(ptr);