001: /*
002: Copyright (C) 2003 Know Gate S.L. All rights reserved.
003: C/Oña, 107 1º2 28050 Madrid (Spain)
004:
005: Redistribution and use in source and binary forms, with or without
006: modification, are permitted provided that the following conditions
007: are met:
008:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011:
012: 2. The end-user documentation included with the redistribution,
013: if any, must include the following acknowledgment:
014: "This product includes software parts from hipergate
015: (http://www.hipergate.org/)."
016: Alternately, this acknowledgment may appear in the software itself,
017: if and wherever such third-party acknowledgments normally appear.
018:
019: 3. The name hipergate must not be used to endorse or promote products
020: derived from this software without prior written permission.
021: Products derived from this software may not be called hipergate,
022: nor may hipergate appear in their name, without prior written
023: permission.
024:
025: This library is distributed in the hope that it will be useful,
026: but WITHOUT ANY WARRANTY; without even the implied warranty of
027: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
028:
029: You should have received a copy of hipergate License with this code;
030: if not, visit http://www.hipergate.org or mail to info@hipergate.org
031: */
032:
033: package com.knowgate.http;
034:
035: import java.io.*;
036: import javax.servlet.*;
037: import javax.servlet.http.*;
038:
039: import java.lang.System;
040: import java.util.Properties;
041:
042: import java.sql.DriverManager;
043: import java.sql.SQLException;
044: import java.sql.Connection;
045: import java.sql.PreparedStatement;
046: import java.sql.ResultSet;
047:
048: import com.knowgate.debug.DebugFile;
049: import com.knowgate.acl.ACL;
050: import com.knowgate.dataobjs.DB;
051: import com.knowgate.hipergate.*;
052: import com.knowgate.misc.Environment;
053:
054: import com.enterprisedt.net.ftp.*;
055:
056: /**
057: * <p>Send Disk Binary File To HttpServletResponse OutputStream</p>
058: * @author Sergio Montoro ten
059: * @version 2.1
060: */
061: public class HttpBinaryServlet extends HttpServlet {
062:
063: public static long pipe(InputStream in, OutputStream out,
064: int chunkSize) throws IOException {
065: if (chunkSize < 1)
066: throw new IOException("Invalid chunk size.");
067:
068: byte[] buf = new byte[chunkSize];
069: long tot = 0;
070: int n;
071: while ((n = in.read(buf)) != -1) {
072: out.write(buf, 0, n);
073: tot += n;
074: }
075: out.flush();
076:
077: return tot;
078: } // pipe()
079:
080: // -----------------------------------------------------------
081:
082: private boolean isVoid(String sParam) {
083: if (null == sParam)
084: return true;
085: else
086: return (sParam.length() == 0);
087: }
088:
089: /**
090: * <p>Initialize Servlet Parameters</p>
091: * Take Database Driver, Conenction URL and User from /WEB-INF/web.xml.<br>
092: * If any parameter is not found then look it up at hipergate.cnf Properties
093: * file using Environment singleton.
094: * @throws ServletException
095: * @throws UnavailableException If jdbcDriverClassName parameter is not found
096: * and driver property at hipergate.cnf is not found or if jdbcURL parameter
097: * is not found and dburl property at hipergate.cnf is not found.
098: * @see com.knowgate.misc.Environment
099: */
100: public void init() throws ServletException {
101:
102: ServletConfig config = getServletConfig();
103:
104: jdbcDriverClassName = config
105: .getInitParameter("jdbcDriverClassName");
106:
107: jdbcURL = config.getInitParameter("jdbcURL");
108: dbUserName = config.getInitParameter("dbUserName");
109: dbUserPassword = config.getInitParameter("dbUserPassword");
110:
111: if (isVoid(jdbcDriverClassName) || isVoid(jdbcURL)
112: || isVoid(dbUserName) || isVoid(dbUserPassword)) {
113: Properties env = Environment.getProfile("hipergate");
114:
115: if (isVoid(jdbcDriverClassName))
116: jdbcDriverClassName = env.getProperty("driver");
117:
118: if (isVoid(jdbcURL))
119: jdbcURL = env.getProperty("dburl");
120:
121: if (isVoid(dbUserName))
122: dbUserName = env.getProperty("dbuser");
123:
124: if (isVoid(dbUserPassword))
125: dbUserPassword = env.getProperty("dbpassword");
126: }
127:
128: if (jdbcDriverClassName == null || jdbcURL == null)
129: throw new UnavailableException("Init params missing");
130: } // init()
131:
132: // -----------------------------------------------------------
133:
134: /**
135: * <p>Send disk binary file held in a Product to HttpServletResponse OutputStream</p>
136: * @param id_user Requester User GUID.
137: * @param id_product GUID of Requested Product.
138: * @param id_location GUID of Requested ProductLocation.
139: * @param id_category (Optional) GUID from Category that contains the Product to serve.
140: * If a Category is provided then the User permissions over that Category are checked
141: * before serving the file.
142: * @return Throught response.sendError()<br>
143: * <table border=1 cellpadding=4>
144: * <tr><td><b>HttpServletResponse Error Code</b></td><td><b>Description</b></td></tr>
145: * <tr><td>SC_INTERNAL_SERVER_ERROR</td><td>Database driver not found</td></tr>
146: * <tr><td>SC_FORBIDDEN</td><td>User does not have read permissions for requested file</td></tr>
147: * <tr><td>SC_NOT_FOUND</td><td>Cannot find file</td></tr>
148: * </table>
149: * @throws IOException
150: * @throws FileNotFoundException
151: * @throws ServletException
152: * @see com.knowgate.acl.ACLUser
153: * @see com.knowgate.hipergate.Product
154: * @see com.knowgate.hipergate.Category
155: */
156: public void doGet(HttpServletRequest request,
157: HttpServletResponse response) throws IOException,
158: FileNotFoundException, ServletException {
159: int iACLMask;
160: boolean bFound;
161: Class oDriver;
162: Connection oConn = null;
163: PreparedStatement oStmt;
164: ResultSet oRSet;
165: File myFile;
166: Category oCatg;
167: String gu_category;
168: String id_location;
169: String xprotocol = "file://";
170: String xpath = null;
171: String xfile = null;
172: String xoriginalfile = null;
173: String mimetype = null;
174:
175: if (DebugFile.trace) {
176: DebugFile.writeln("Begin HttpBinaryServlet.doGet()");
177: DebugFile.incIdent();
178: }
179:
180: try {
181: oDriver = Class.forName(jdbcDriverClassName);
182: } catch (ClassNotFoundException ignore) {
183: oDriver = null;
184: if (DebugFile.trace)
185: DebugFile.writeln("Class.forName("
186: + jdbcDriverClassName + ") : "
187: + ignore.getMessage());
188: response.sendError(
189: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
190: "Database driver not found");
191: }
192:
193: if (null == oDriver)
194: return;
195:
196: try {
197: if (DebugFile.trace)
198: DebugFile.writeln("DriverManager.getConnection("
199: + jdbcURL + "," + dbUserName + ", ...)");
200:
201: oConn = DriverManager.getConnection(jdbcURL, dbUserName,
202: dbUserPassword);
203:
204: // Si el archivo a recuperar está contenido dentro de una categoría,
205: // verificar los permisos del usuario sobre dicha categoría
206: gu_category = request.getParameter("id_category");
207: if (gu_category != null)
208: if (gu_category.length() > 0) {
209: oCatg = new Category();
210: oCatg.put(DB.gu_category, gu_category);
211: iACLMask = oCatg.getUserPermissions(oConn, request
212: .getParameter("id_user"));
213: oCatg = null;
214: } else
215: iACLMask = ACL.PERMISSION_LIST
216: | ACL.PERMISSION_READ | ACL.PERMISSION_ADD
217: | ACL.PERMISSION_MODIFY
218: | ACL.PERMISSION_SEND;
219: else
220: iACLMask = ACL.PERMISSION_LIST | ACL.PERMISSION_READ
221: | ACL.PERMISSION_ADD | ACL.PERMISSION_MODIFY
222: | ACL.PERMISSION_SEND;
223:
224: if ((iACLMask & ACL.PERMISSION_READ) == 0) {
225: bFound = false;
226: response
227: .sendError(HttpServletResponse.SC_FORBIDDEN,
228: "User does not have read permissions for requested file");
229: } else {
230: id_location = request.getParameter("id_location");
231: if (DebugFile.trace)
232: DebugFile
233: .writeln("Connection.prepareStatement(SELECT l."
234: + DB.xprotocol
235: + ", l."
236: + DB.xhost
237: + ", l."
238: + DB.xport
239: + ", l."
240: + DB.xpath
241: + ", l."
242: + DB.xfile
243: + ", l."
244: + DB.xoriginalfile
245: + ", t."
246: + DB.mime_type
247: + ",l."
248: + DB.gu_location
249: + ",l."
250: + DB.dt_uploaded
251: + " FROM "
252: + DB.k_prod_locats
253: + " l, "
254: + DB.k_lu_prod_types
255: + " t WHERE l."
256: + DB.gu_product
257: + "='"
258: + request
259: .getParameter("id_product")
260: + "' AND l."
261: + DB.id_prod_type
262: + "=t."
263: + DB.id_prod_type
264: + " ORDER BY l."
265: + DB.dt_uploaded
266: + " DESC");
267:
268: oStmt = oConn.prepareStatement("SELECT l."
269: + DB.xprotocol + ", l." + DB.xhost + ", l."
270: + DB.xport + ", l." + DB.xpath + ", l."
271: + DB.xfile + ", l." + DB.xoriginalfile + ", t."
272: + DB.mime_type + ",l." + DB.gu_location + ",l."
273: + DB.dt_uploaded + " FROM " + DB.k_prod_locats
274: + " l, " + DB.k_lu_prod_types + " t WHERE l."
275: + DB.gu_product + "=? AND l." + DB.id_prod_type
276: + "=t." + DB.id_prod_type + " ORDER BY l."
277: + DB.dt_uploaded + " DESC",
278: ResultSet.TYPE_FORWARD_ONLY,
279: ResultSet.CONCUR_READ_ONLY);
280: oStmt.setString(1, request.getParameter("id_product"));
281: oRSet = oStmt.executeQuery();
282: bFound = oRSet.next();
283:
284: if (DebugFile.trace) {
285: if (bFound)
286: DebugFile.writeln("found product "
287: + request.getParameter("id_product"));
288: else
289: DebugFile.writeln("product "
290: + request.getParameter("id_product")
291: + " not found");
292: }
293:
294: if ((null != id_location) && bFound) {
295: bFound = false;
296: do {
297: if (id_location.equals(oRSet.getString(8))) {
298: bFound = true;
299: break;
300: } // fi (id_location==oRSet.get(gu_location))
301: } while (oRSet.next());
302:
303: if (DebugFile.trace) {
304: if (bFound)
305: DebugFile.writeln("found location "
306: + id_location);
307: else
308: DebugFile.writeln("location " + id_location
309: + " not found");
310: }
311: } // fi (id_location)
312:
313: if (bFound) {
314: xprotocol = oRSet.getString(1).toLowerCase();
315: xpath = oRSet.getString(4);
316:
317: if (xprotocol.equalsIgnoreCase("ftp://")) {
318: if (!xpath.endsWith("/"))
319: xpath += "/";
320: } else {
321: if (!xpath.endsWith(java.io.File.separator))
322: xpath += java.io.File.separator;
323: }
324:
325: xfile = oRSet.getString(5);
326: xoriginalfile = oRSet.getString(6);
327: mimetype = oRSet.getString(7);
328:
329: if (DebugFile.trace)
330: DebugFile.writeln(xoriginalfile + " "
331: + (mimetype == null ? "" : mimetype));
332: } // fi (bFound)
333:
334: oRSet.close();
335: oRSet = null;
336: oStmt.close();
337: oStmt = null;
338:
339: if (!bFound) {
340: response.sendError(
341: HttpServletResponse.SC_NOT_FOUND,
342: "Cannot find requested file");
343: }
344: }
345:
346: oConn.close();
347: oConn = null;
348: } catch (SQLException e) {
349: if (DebugFile.trace)
350: DebugFile.writeln(e.getMessage());
351: bFound = false;
352: response.sendError(
353: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
354: .getMessage());
355: }
356: try {
357: if (null != oConn)
358: if (!oConn.isClosed())
359: oConn.close();
360: } catch (SQLException e) {
361: if (DebugFile.trace)
362: DebugFile.writeln(e.getMessage());
363: }
364:
365: if (!bFound) {
366: if (DebugFile.trace)
367: DebugFile.decIdent();
368: return;
369: }
370:
371: // Do initial test to see if we need to send a 404 error.
372:
373: if (DebugFile.trace)
374: DebugFile.writeln("new File(" + xpath + xfile + ")");
375:
376: if (xprotocol.equals("ftp://")) {
377: if (null != mimetype)
378: response.setContentType(mimetype);
379: response.setHeader("Content-Disposition",
380: "attachment; filename=\""
381: + (xoriginalfile == null ? xfile
382: : xoriginalfile) + "\"");
383:
384: boolean bLogged = false;
385: FTPClient oFTP = null;
386:
387: try {
388: oFTP = new FTPClient(Environment.getProfileVar(
389: "hipergate", "fileserver", "localhost"));
390:
391: oFTP
392: .login(Environment.getProfileVar("hipergate",
393: "fileuser", "anonymous"), Environment
394: .getProfileVar("hipergate",
395: "filepassword", ""));
396:
397: bLogged = true;
398:
399: oFTP.get(response.getOutputStream(), xpath + xfile);
400:
401: oFTP.quit();
402:
403: bLogged = false;
404: } catch (FTPException ftpe) {
405: if (oFTP != null && bLogged) {
406: try {
407: oFTP.quit();
408: } catch (Exception ignore) {
409: }
410: }
411: response.sendError(
412: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
413: ftpe.getMessage());
414: if (DebugFile.trace)
415: DebugFile.decIdent();
416: return;
417: }
418: } else {
419: myFile = new File(xpath + xfile);
420: if (!myFile.canRead()) {
421: response.sendError(HttpServletResponse.SC_NOT_FOUND,
422: "Cannot find file " + xfile);
423: if (DebugFile.trace)
424: DebugFile.decIdent();
425: return;
426: } // fi(myFile.canRead)
427:
428: // Send some basic http headers to support binary d/l.
429: if (DebugFile.trace)
430: DebugFile.writeln("setContentLength(" + myFile.length()
431: + ")");
432:
433: response.setContentLength((int) myFile.length());
434:
435: if (DebugFile.trace && null != mimetype)
436: DebugFile.writeln("setContentType(" + mimetype + ")");
437:
438: if (null != mimetype)
439: response.setContentType(mimetype);
440:
441: if (DebugFile.trace)
442: DebugFile
443: .writeln("setHeader(Content-Disposition,attachment; filename="
444: + xoriginalfile);
445:
446: response.setHeader("Content-Disposition",
447: "attachment; filename=\"" + xoriginalfile + "\"");
448:
449: // Copy the file's bytes to the servlet output stream,
450: // being absolutely sure NOT to leak file handles even
451: // in the face of an exception (thus the try/finally block).
452: InputStream in = null;
453: try {
454: in = new BufferedInputStream(
455: new FileInputStream(myFile));
456: pipe(in, response.getOutputStream(), 2048);
457: } finally {
458: if (in != null)
459: try {
460: in.close();
461: } catch (IOException ignore) {
462: if (DebugFile.trace)
463: DebugFile.writeln("IOException "
464: + ignore.getMessage());
465: }
466: }
467: } // fi (xprotocol)
468:
469: if (DebugFile.trace) {
470: DebugFile.decIdent();
471: DebugFile.writeln("End HttpBinaryServlet.doGet()");
472: }
473: } // doGet()
474:
475: private String jdbcDriverClassName;
476: private String jdbcURL;
477: private String dbUserName;
478: private String dbUserPassword;
479: }
|