Reformatted code, updated to new Analytics tags, fixed a problem with EmailAuthenticator
[zxing.git] / zxingorg / src / com / google / zxing / web / DecodeServlet.java
1 /*
2  * Copyright 2008 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.web;
18
19 import com.google.zxing.DecodeHintType;
20 import com.google.zxing.MultiFormatReader;
21 import com.google.zxing.Reader;
22 import com.google.zxing.ReaderException;
23 import com.google.zxing.Result;
24 import com.google.zxing.client.j2se.BufferedImageMonochromeBitmapSource;
25 import org.apache.commons.fileupload.FileItem;
26 import org.apache.commons.fileupload.FileUploadException;
27 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
28 import org.apache.commons.fileupload.servlet.ServletFileUpload;
29 import org.apache.http.Header;
30 import org.apache.http.HttpException;
31 import org.apache.http.HttpMessage;
32 import org.apache.http.HttpResponse;
33 import org.apache.http.HttpVersion;
34 import org.apache.http.client.HttpClient;
35 import org.apache.http.client.methods.HttpGet;
36 import org.apache.http.conn.PlainSocketFactory;
37 import org.apache.http.conn.Scheme;
38 import org.apache.http.conn.SchemeRegistry;
39 import org.apache.http.conn.ssl.SSLSocketFactory;
40 import org.apache.http.impl.client.DefaultHttpClient;
41 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
42 import org.apache.http.params.BasicHttpParams;
43 import org.apache.http.params.HttpParams;
44 import org.apache.http.params.HttpProtocolParams;
45
46 import javax.imageio.ImageIO;
47 import javax.mail.Authenticator;
48 import javax.servlet.ServletConfig;
49 import javax.servlet.ServletException;
50 import javax.servlet.http.HttpServlet;
51 import javax.servlet.http.HttpServletRequest;
52 import javax.servlet.http.HttpServletResponse;
53 import java.awt.image.BufferedImage;
54 import java.io.IOException;
55 import java.io.InputStream;
56 import java.io.OutputStreamWriter;
57 import java.io.Writer;
58 import java.net.URI;
59 import java.net.URISyntaxException;
60 import java.util.Hashtable;
61 import java.util.List;
62 import java.util.Timer;
63 import java.util.logging.Logger;
64
65 /**
66  * @author Sean Owen
67  */
68 public final class DecodeServlet extends HttpServlet {
69
70   private static final long MAX_IMAGE_SIZE = 500000L;
71   private static final long EMAIL_CHECK_INTERVAL = 60000L;
72
73   private static final Logger log = Logger.getLogger(DecodeServlet.class.getName());
74
75   static final Hashtable<DecodeHintType, Object> HINTS;
76
77   static {
78     HINTS = new Hashtable<DecodeHintType, Object>(3);
79     HINTS.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
80   }
81
82   private HttpClient client;
83   private DiskFileItemFactory diskFileItemFactory;
84   private Timer emailTimer;
85
86   @Override
87   public void init(ServletConfig servletConfig) throws ServletException {
88
89     Logger logger = Logger.getLogger("com.google.zxing");
90     logger.addHandler(new ServletContextLogHandler(servletConfig.getServletContext()));
91
92     String emailAddress = servletConfig.getInitParameter("emailAddress");
93     String emailPassword = servletConfig.getInitParameter("emailPassword");
94     if (emailAddress == null || emailPassword == null) {
95       throw new ServletException("emailAddress or emailPassword not specified");
96     }
97
98     HttpParams params = new BasicHttpParams();
99     HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
100
101     SchemeRegistry registry = new SchemeRegistry();
102     registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
103     registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
104
105     client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params);
106
107     diskFileItemFactory = new DiskFileItemFactory();
108
109     Authenticator emailAuthenticator = new EmailAuthenticator(emailAddress, emailPassword);
110     emailTimer = new Timer("Email decoder timer", true);
111     emailTimer.schedule(new DecodeEmailTask(emailAddress, emailAuthenticator), 0L, EMAIL_CHECK_INTERVAL);
112
113     log.info("DecodeServlet configured");
114   }
115
116   @Override
117   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
118
119     String imageURIString = request.getParameter("u");
120     if (imageURIString == null || imageURIString.length() == 0) {
121       response.sendRedirect("badurl.jspx");
122       return;
123     }
124
125     if (!(imageURIString.startsWith("http://") || imageURIString.startsWith("https://"))) {
126       imageURIString = "http://" + imageURIString;
127     }
128
129     URI imageURI;
130     try {
131       imageURI = new URI(imageURIString);
132     } catch (URISyntaxException urise) {
133       response.sendRedirect("badurl.jspx");
134       return;
135     }
136
137     HttpGet getRequest = new HttpGet(imageURI);
138
139     try {
140       HttpResponse getResponse = client.execute(getRequest);
141       if (getResponse.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK) {
142         response.sendRedirect("badurl.jspx");
143         return;
144       }
145       if (!isSizeOK(getResponse)) {
146         response.sendRedirect("badimage.jspx");
147         return;
148       }
149       log.info("Decoding " + imageURI);
150       InputStream is = getResponse.getEntity().getContent();
151       try {
152         processStream(is, response);
153       } finally {
154         is.close();
155       }
156     } catch (InterruptedException ie) {
157       getRequest.abort();
158       response.sendRedirect("badurl.jspx");
159     } catch (HttpException he) {
160       getRequest.abort();
161       response.sendRedirect("badurl.jspx");
162     }
163
164   }
165
166   @Override
167   protected void doPost(HttpServletRequest request, HttpServletResponse response)
168           throws ServletException, IOException {
169
170     if (!ServletFileUpload.isMultipartContent(request)) {
171       response.sendRedirect("badimage.jspx");
172       return;
173     }
174
175     ServletFileUpload upload = new ServletFileUpload(diskFileItemFactory);
176     upload.setFileSizeMax(MAX_IMAGE_SIZE);
177
178     // Parse the request
179     try {
180       for (FileItem item : (List<FileItem>) upload.parseRequest(request)) {
181         if (!item.isFormField()) {
182           if (item.getSize() <= MAX_IMAGE_SIZE) {
183             log.info("Decoding uploaded file");
184             InputStream is = item.getInputStream();
185             try {
186               processStream(is, response);
187             } finally {
188               is.close();
189             }
190           } else {
191             throw new ServletException("File is too large: " + item.getSize());
192           }
193           break;
194         }
195       }
196     } catch (FileUploadException fue) {
197       response.sendRedirect("badimage.jspx");
198     }
199
200   }
201
202   private static void processStream(InputStream is, HttpServletResponse response) throws IOException {
203     BufferedImage image = ImageIO.read(is);
204     if (image == null) {
205       response.sendRedirect("badimage.jspx");
206       return;
207     }
208
209     Reader reader = new MultiFormatReader();
210     Result result;
211     try {
212       result = reader.decode(new BufferedImageMonochromeBitmapSource(image), HINTS);
213     } catch (ReaderException re) {
214       log.info("DECODE FAILED: " + re.toString());
215       response.sendRedirect("notfound.jspx");
216       return;
217     }
218
219     response.setContentType("text/plain");
220     response.setCharacterEncoding("UTF-8");
221     Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
222     try {
223       out.write(result.getText());
224     } finally {
225       out.close();
226     }
227   }
228
229   private static boolean isSizeOK(HttpMessage getResponse) {
230     Header lengthHeader = getResponse.getLastHeader("Content-Length");
231     if (lengthHeader != null) {
232       long length = Long.parseLong(lengthHeader.getValue());
233       if (length > MAX_IMAGE_SIZE) {
234         return false;
235       }
236     }
237     return true;
238   }
239
240   @Override
241   public void destroy() {
242     log.config("DecodeServlet shutting down...");
243     emailTimer.cancel();
244   }
245
246 }