/* 
 * Qlue Web Application Framework
 * Copyright 2009-2011 Ivan Ristic <ivanr@webkreator.com>
 *
 * 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 com.webkreator.qlue.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletResponse;

/**
 * This utility class can send a file from the filesystem, either
 * inline or as an attachment. 
 */
public class DownloadUtil {

	/**
	 * Send file inline.
	 * 
	 * @param response
	 * @param f
	 * @throws Exception
	 */
	public static void sendInlineFile(HttpServletResponse response, File f)
			throws Exception {
		// Set MIME type
		if (f.getName().endsWith(".png")) {
			response.setContentType("image/png");
		} else if (f.getName().endsWith(".pdf")) {
			response.setContentType("application/pdf");
		}

		// Set size
		response.setContentLength((int) f.length());

		// Send data
		OutputStream os = response.getOutputStream();
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(f));
		byte b[] = new byte[1024];

		while (bis.read(b) > 0) {
			os.write(b);
		}

		bis.close();
		os.close();
	}

	/**
	 * Send file as attachment.
	 * 
	 * @param response
	 * @param f
	 * @param name
	 * @param isAttachment
	 * @throws Exception
	 */
	public static void sendAttachment(HttpServletResponse response, File f,
			String name, boolean isAttachment) throws Exception {
		// Set MIME type
		if (f.getName().endsWith(".txt")) {
			response.setContentType("text/plain");
		} else if (f.getName().endsWith(".png")) {
			response.setContentType("image/png");
		} else if (f.getName().endsWith(".pdf")) {
			response.setContentType("application/pdf");
		}

		// Set name
		// TODO Validate name
		if (isAttachment) {
			response.setHeader("Content-Disposition", "attachment; filename="
					+ name);
		} else {
			response.setHeader("Content-Disposition", "inline; filename="
					+ name);
		}

		// Set size
		response.setContentLength((int) f.length());

		// Send data
		OutputStream os = response.getOutputStream();
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(f));
		byte b[] = new byte[1024];

		while (bis.read(b) > 0) {
			os.write(b);
		}

		bis.close();
		os.close();
	}
}

@@ -825,16 +825,96 @@
 Stream;%0D
+%0Aimport java.text.CharacterIterator;%0D%0Aimport java.text.StringCharacterIterator;%0D
 %0A%0D%0Aimpor
@@ -1028,20 +1028,16 @@
 , either
-%0D%0A *
  inline 
@@ -1041,16 +1041,20 @@
 ne or as
+%0D%0A *
  an atta
@@ -1060,17 +1060,16 @@
 achment.
- 
 %0D%0A */%0D%0Ap
@@ -2412,36 +2412,513 @@
 %09// 
-Set 
+Do not allow control characters in the name%0D%0A%09%09StringBuffer sb = new StringBuffer();%0D%0A%09%09CharacterIterator it = new StringCharacterIterator(
 name
+);
 %0D%0A%09%09
-// TODO Validate
+for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) %7B%0D%0A%09%09%09if (c %3C 0x20) %7B%0D%0A%09%09%09%09throw new SecurityException(%22Invalid character in filename: %22%0D%0A%09%09%09%09%09%09+ c);%0D%0A%09%09%09%7D%0D%0A%09%09%09%0D%0A%09%09%09if ((c == '%5C%5C')%7C%7C(c == '%22')) %7B%0D%0A%09%09%09%09sb.append('%5C%5C');%0D%0A%09%09%09%09sb.append(c);%0D%0A%09%09%09%7D else %7B%0D%0A%09%09%09%09sb.append(c);%0D%0A%09%09%09%7D%0D%0A%09%09%7D%0D%0A%09%09%0D%0A%09%09String escapedName = sb.toString();%0D%0A%0D%0A%09%09// Set
  nam
@@ -3012,33 +3012,40 @@
 ename=%22%0D%0A%09%09%09%09%09+ 
-n
+escapedN
 ame);%0D%0A%09%09%7D else 
@@ -3120,17 +3120,24 @@
 %0A%09%09%09%09%09+ 
-n
+escapedN
 ame);%0D%0A%09

Check filename because using it in the Content-Disposition header.