/* * Digital Audio Access Protocol (DAAP) Library * Copyright (C) 2004-2010 Roger Kapsi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ardverk.daap; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import org.apache.http.Header; import org.apache.http.message.BasicHeader; /** * A helper class to create easily misc DAAP response header * * @author Roger Kapsi */ public class DaapHeaderConstructor { // private static final Logger LOG = // LoggerFactory.getLogger(DaapHeaderConstructor.class); private static final String HTTP_OK = "HTTP/1.1 200 OK"; private static final String HTTP_NO_CONTENT = "HTTP/1.1 204 No Content"; private static final String HTTP_PARTIAL_CONTENT = "HTTP/1.1 206 Partial Content"; private static final String HTTP_AUTH = "HTTP/1.1 401 Authorization Required"; // private static final String BAD_REQUEST = "HTTP/1.1 400 Bad Request"; // private static final String HTTP_FORBIDDEN = "HTTP/1.1 403 Forbidden"; // private static final String HTTP_SERVICE_UNAVAILABLE = // "HTTP/1.1 503 Service Unavailable"; /** * Creates a new Chunk Header * * @param request * @param contentLength * @return */ public static byte[] createChunkHeader(DaapRequest request, long contentLength) { /* * if (request.isLoginRequest()) { return * createServiceUnavialable(request); } */ try { DaapConnection connection = request.getConnection(); String serverName = connection.getServer().getConfig() .getServerName(); List<Header> headers = new ArrayList<Header>(); headers.add(new BasicHeader("Date", DaapUtil.now())); headers.add(new BasicHeader("DAAP-Server", serverName)); headers.add(new BasicHeader("Content-Type", "application/x-dmap-tagged")); headers.add(new BasicHeader("Content-Length", Long .toString(contentLength))); headers.add(new BasicHeader("Connection", "Keep-Alive")); if (DaapUtil.COMPRESS && request.isGZIPSupported()) { headers.add(new BasicHeader("Content-Encoding", "gzip")); } return toByteArray(HTTP_OK, headers.toArray(new Header[0])); } catch (IOException err) { // Should never happen throw new RuntimeException(err); } } /** * Creates an Audio Header * * @param request * @param contentLength * @return */ public static byte[] createAudioHeader(DaapRequest request, long pos, long end, long contentLength) { try { DaapConnection connection = request.getConnection(); int version = connection.getProtocolVersion(); if (version == DaapUtil.NULL) throw new IOException("Client Protocol Version is unknown"); String serverName = connection.getServer().getConfig() .getServerName(); String statusLine = null; List<Header> headers = new ArrayList<Header>(); headers.add(new BasicHeader("Date", DaapUtil.now())); headers.add(new BasicHeader("DAAP-Server", serverName)); headers.add(new BasicHeader("Content-Type", "application/x-dmap-tagged")); headers.add(new BasicHeader("Connection", "close")); // if (pos == 0 || version <= DaapUtil.DAAP_VERSION_2) { statusLine = HTTP_OK; headers.add(new BasicHeader("Content-Length", Long .toString(contentLength))); } else { statusLine = HTTP_PARTIAL_CONTENT; String cotentLengthStr = Long.toString(contentLength - pos); String contentRange = "bytes " + pos + "-" + (contentLength - 1) + "/" + contentLength; headers.add(new BasicHeader("Content-Length", cotentLengthStr)); headers.add(new BasicHeader("Content-Range", contentRange)); } headers.add(new BasicHeader("Accept-Ranges", "bytes")); return toByteArray(statusLine, headers.toArray(new Header[0])); } catch (IOException err) { // Should never happen throw new RuntimeException(err); } } /** * Creates a new Basic Authentication Header * * @param request * @return */ public static byte[] createBasicAuthHeader(DaapRequest request) { try { DaapConnection connection = request.getConnection(); String serverName = connection.getServer().getConfig() .getServerName(); Header[] headers = { new BasicHeader("Date", DaapUtil.now()), new BasicHeader("DAAP-Server", serverName), new BasicHeader("Content-Type", "text/html"), new BasicHeader("Content-Length", "0"), new BasicHeader("WWW-Authenticate", "Basic realm=\"" + DaapUtil.DAAP_REALM + "\""), new BasicHeader("Connection", "Keep-Alive") }; return toByteArray(HTTP_AUTH, headers); } catch (IOException err) { // Should never happen throw new RuntimeException(err); } } /** * Creates a Digest Authentication Header */ public static byte[] createDigestAuthHeader(DaapRequest request) { try { DaapConnection connection = request.getConnection(); String serverName = connection.getServer().getConfig() .getServerName(); String nonce = connection.createNonce(); Header[] headers = { new BasicHeader("Date", DaapUtil.now()), new BasicHeader("DAAP-Server", serverName), new BasicHeader("Content-Type", "text/html"), new BasicHeader("Content-Length", "0"), new BasicHeader("WWW-Authenticate", "Digest realm=\"" + DaapUtil.DAAP_REALM + "\", nonce=\"" + nonce + "\""), new BasicHeader("Connection", "Keep-Alive") }; return toByteArray(HTTP_AUTH, headers); } catch (IOException err) { // Should never happen throw new RuntimeException(err); } } /** * Creates a new No Content Header * * @param request * @return */ public static byte[] createNoContentHeader(DaapRequest request) { try { DaapConnection connection = request.getConnection(); String serverName = connection.getServer().getConfig() .getServerName(); Header[] headers = { new BasicHeader("Date", DaapUtil.now()), new BasicHeader("DAAP-Server", serverName), new BasicHeader("Content-Type", "application/x-dmap-tagged"), new BasicHeader("Content-Length", "0"), new BasicHeader("Connection", request.isLogoutRequest() ? "close" : "Keep-Alive") }; return toByteArray(HTTP_NO_CONTENT, headers); } catch (IOException err) { // Should never happen throw new RuntimeException(err); } } /* * public static byte[] createForbidden(DaapRequest request) { try { * * DaapServer server = request.getServer(); DaapConfig config = * server.getConfig(); String serverName = config.getServerName(); * * Header[] headers = { new Header("Date", DaapUtil.now()), new * Header("DAAP-Server", serverName), new Header("Content-Type", * "application/x-dmap-tagged"), new Header("Content-Length", "0") }; * * return toByteArray(HTTP_FORBIDDEN, headers); * * } catch (IOException err) { // Should never happen throw new * RuntimeException(err); } } */ /** * As a response to /login this will produce two types of error messages on * the client side. * * 1) if max connections is equal to iTunes five unique connections per day * limit you'll get the following message: * * "The shared music library "The WIRED CD" accepts only five different * users each day. Please try again later." * * 2) if max connections is something else you'll get this message: * * "The shared music library "The WIRED CD" is not accepting connections at * this time. Please try again later." */ /* * public static byte[] createServiceUnavialable(DaapRequest request) { try * { * * DaapServer server = request.getServer(); DaapConfig config = * server.getConfig(); String serverName = config.getServerName(); * * // Contents is the max number of connections // encoded as binary string. * * String max = ""; if (config.getMaxConnections() > 0) { max = * Integer.toBinaryString(config.getMaxConnections()); } * * byte[] maxBinString = DaapUtil.getBytes(max, DaapUtil.ISO_8859_1); * * Header[] headers = { new Header("Date", DaapUtil.now()), new * Header("DAAP-Server", serverName), new Header("Content-Type", * "text/html"), new Header("Content-Length", * Integer.toString(maxBinString.length)) }; * * ByteArrayOutputStream out = new ByteArrayOutputStream(); toByteArray(out, * HTTP_SERVICE_UNAVAILABLE, headers); out.write(maxBinString); out.close(); * return out.toByteArray(); * * } catch (IOException err) { // Should never happen throw new * RuntimeException(err); } } */ /** * Converts statusLine and headers to an byte-Array */ private static byte[] toByteArray(String statusLine, Header[] headers) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); toByteArray(out, statusLine, headers).close(); return out.toByteArray(); } /** * Converts statusLine and headers to an byte-Array */ private static OutputStream toByteArray(OutputStream out, String statusLine, Header[] headers) throws IOException { out.write(DaapUtil.getBytes(statusLine, DaapUtil.ISO_8859_1)); out.write(DaapUtil.CRLF); for (int i = 0; i < headers.length; i++) { out.write(DaapUtil.getBytes(headers[i].toString() + "\r\n", DaapUtil.ISO_8859_1)); } out.write(DaapUtil.CRLF); return out; } /** Creates a new instance of DaapHeaderConstructor */ private DaapHeaderConstructor() { } }