View Javadoc

1   /*
2    *  ginp - Java Web Application for Viewing Photo Collections
3    *  Copyright (C) 2004  Douglas John Culnane <doug@culnane.net>
4    *
5    *  This library is free software; you can redistribute it and/or
6    *  modify it under the terms of the GNU Lesser General Public
7    *  License as published by the Free Software Foundation; either
8    *  version 2.1 of the License, or any later version.
9    *
10   *  This library is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   *  Lesser General Public License for more details.
14   *
15   *  You should have received a copy of the GNU Lesser General Public
16   *  License along with this library; if not, write to the Free Software
17   *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18   */
19  package net.sf.ginp;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  
27  import javax.servlet.ServletOutputStream;
28  import javax.servlet.http.HttpServlet;
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletResponse;
31  
32  import net.sf.ginp.config.ModelUtil;
33  import net.sf.ginp.util.GinpUtil;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  /**
37   *  Servlet that delivers Images to the client's browser.
38   *
39   *@author     Doug Culnane
40   *@author     Justin Sher
41   *@version    $Revision: 303 $
42   */
43  public class GinpPictureServlet extends HttpServlet {
44  
45      /**
46  	 * 
47  	 */
48  	private static final long serialVersionUID = 1937043430753224685L;
49  	private Log log = LogFactory.getLog(GinpPictureServlet.class);
50  	
51      /**
52       *  Called by HTTP GET.
53       *
54       *@param  req                   HTTP GET Request
55       *@param  res                   HTTP Response
56       *@exception  IOException       Description of the Exception
57       */
58      public void doGet(HttpServletRequest req,
59              HttpServletResponse res)
60               throws IOException {
61          doHttpMethod(req, res);
62      }
63  
64  
65      /**
66       *  Called by HTTP POST.
67       *
68       *@param  req                   HTTP POST Request
69       *@param  res                   HTTP Response
70       *@exception  IOException       Description of the Exception
71       */
72      public void doPost(HttpServletRequest req,
73              HttpServletResponse res)
74               throws IOException {
75          doHttpMethod(req, res);
76      }
77  
78  
79  
80  
81      /**
82       *  Central Processor of HTTP GET and POST Methods. This method gets the
83       *  model for the users session, and returns the correctly sized picture
84       *  based on the command parameters in the request and the model state.
85       *
86       *@param  req                   HTTP Request
87       *@param  res                   HTTP Response
88       *@exception  IOException       Description of the Exception
89       */
90      void doHttpMethod(HttpServletRequest req, HttpServletResponse res) 
91              throws IOException {
92  
93          ServletOutputStream  sos    = res.getOutputStream();
94          GinpModel            model  = null;
95          //Retrieve the model for this web app
96          try {
97              model = ModelUtil.getModel(req);
98          } catch (Exception ex) {
99              log.error("Problem getting model", ex);
100             return;
101         }
102         String filename = req.getParameter("name");
103         String path     = req.getParameter("path");
104         
105         res.setContentType("image/jpeg");
106 		
107         //Only allow files below the given directory
108         if (filename!=null) { 
109         	filename=filename.replaceAll("\\.\\./","");
110         	filename=filename.replaceAll("\\.\\.\\\\","");
111             
112             // Only deliver JPEGs
113             if (!((filename.toLowerCase()).endsWith(".jpg")
114                     || (filename.toLowerCase()).endsWith(".jpeg"))) {
115                 filename = null;
116             }
117         }   
118         if (path!=null) { 
119         	path=path.replaceAll("\\.\\./","");
120         	path=path.replaceAll("\\.\\.\\\\","");
121         }
122 		
123         if (filename != null) {            
124 
125     		String absPath = getImagePath(model, path);
126                 
127                 int              maxSize  = 0;
128                 File             fl;                                
129                 
130                 if (req.getParameter("maxsize") != null) {
131                 	maxSize=GinpUtil.parseInteger(req,"maxsize",0);
132                     fl = getThumbnailPath(filename, absPath, maxSize);
133                 } else {
134                     fl = new File(absPath + filename);
135                 }
136 
137                 fl = handleMissingPicture(req, res, fl);
138                 
139                 FileInputStream  is       = new FileInputStream(fl);
140 
141                 String heightParm=req.getParameter("height");
142                 String widthParm=req.getParameter("width");
143 
144                 // debug output
145                 //if (log.isDebugEnabled()) {
146                     log.info("doHttpMethod filename=" + filename
147                             + " absPath=" + absPath
148                             + " path=" + path
149                             + " heightParm=" + heightParm
150                             + " widthParm=" + widthParm
151                             + " maxSize=" + maxSize
152                             + " ImageFile=" + fl.getPath());
153                 //}
154  
155                 if (heightParm != null
156                          || widthParm != null) {
157 
158                 	int width=GinpUtil.parseInteger(req,"width",0);
159                 	int height=GinpUtil.parseInteger(req,"height",0);
160                     GinpUtil.writeScaledImageToStream(sos, is, width, height);
161                 } else {
162                     // deliver raw image
163                     GinpUtil.writeInputStreamToOutputStream(sos, is);
164                 }
165         } else {
166             // is this a request to set client info
167             if (req.getParameter("cmd")!=null && req.getParameter("cmd").equals("setprops")) {
168         		if (req.getParameter("pagewidth")!= null) {
169                 	int i=GinpUtil.parseInteger(req,"pagewidth",0);
170                 	if (i>0){ model.setPageWidth(i); }
171         		}
172         		if (req.getParameter("pageheight")!= null) {
173                 	int i=GinpUtil.parseInteger(req,"pageheight",0);
174                 	if (i>0){ model.setPageHeight(i); }
175         		}
176             }
177             deliverSpacer(req, sos);
178         }
179         sos.flush();
180         sos.close();
181     }
182 
183 
184 	/**
185 	 * Handle missing picture handles the case where the image being linked to does not exist
186 	 * It returns the image "/img/nofile.jpg" and sets the image to not cache so that if the image
187 	 * does appear later the image will reload.  If the image exists it returns the origional image
188 	 * passed.
189 	 * @param req servlet request
190 	 * @param res servlet response
191 	 * @param fl file
192 	 * @return the file to use as the image source file
193 	 */
194 	private File handleMissingPicture(HttpServletRequest req, HttpServletResponse res, File fl) {
195 		if (!(fl.exists())) {
196 
197             log.info("File not found: " + fl.getAbsolutePath());
198             
199 		    fl = new File(req.getSession().getServletContext()
200 		            .getRealPath("/img/nofile.jpg"));
201 
202 		    // DO NOT cache this picture.
203 		    res.setHeader("Expires", "-1");
204 		    res.setHeader("Cache-Control",
205 		            "no-store, no-cache, must-revalidate");
206 		    res.addHeader("Cache-Control", "post-check=0, pre-check=0");
207 		    res.setHeader("Pragma", "no-cac`he");
208 
209 		}
210 		return fl;
211 	}
212 
213 
214 	/**
215 	 * Get the thumbnail path
216 	 * @param filename the name of the file
217 	 * @param absPath the path its located in
218 	 * @param maxSize the size it should be
219 	 * @return the file object for the path
220 	 */
221 	private File getThumbnailPath(String filename, String absPath, int maxSize) {
222 		File fl;
223 		if (filename.indexOf("/") != -1) {
224 		    fl = new File(absPath + filename.substring(0, filename.lastIndexOf("/"))
225 		             + "/.ginp/" + maxSize + "-"
226 		             + filename.substring(filename.lastIndexOf("/") + 1));
227 		} else {
228 		    fl = new File(absPath + ".ginp/" + maxSize + "-"
229 		             + filename);
230 		}
231 		return fl;
232 	}
233 
234 
235 
236 
237 
238 	/**
239 	 * Send the Spacer gif to the client
240 	 * @param req servlet request
241 	 * @param sos an output stream
242 	 * @throws FileNotFoundException if we can't find the spacer
243 	 * @throws IOException if there is a problem delivering it 
244 	 */
245 	private void deliverSpacer(HttpServletRequest req, OutputStream sos) throws FileNotFoundException, IOException {
246 		// deliver spacer.gif
247 		File                 fl    = new File(req.getSession().getServletContext()
248 		        							.getRealPath("/img/spacer.gif"));
249 		FileInputStream      is    = new FileInputStream(fl);
250 		GinpUtil.writeInputStreamToOutputStream(sos, is);
251 	}
252 
253 
254 	/**
255 	 * Returns the disk path to the directory of pictures
256 	 * that is currently being looked at.  
257 	 * @param model the Ginp Model
258 	 * @param path the path that the user has selected.
259 	 * @return the directory path
260 	 */
261 	private String getImagePath(GinpModel model, String path) {
262         if (path != null) {  
263 		    // check the path is the collections path
264 		    if (!(model.getCollection().getPath().equals(path))) {
265 		        // sync model with request
266 		        model.getCollection().setPath(path);
267 		    }
268 		}
269 		String           absPath  = 
270 			model.getCollection().getRoot()
271 			+ model.getCollection().getPath();
272 		return absPath;
273 	}
274     
275 }
276 
277