Added source code to zxing.org
[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   static {
77     HINTS = new Hashtable<DecodeHintType, Object>(3);
78     HINTS.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
79   }
80
81   private HttpClient client;
82         private DiskFileItemFactory diskFileItemFactory;
83   private Timer emailTimer;
84
85   @Override
86         public void init(ServletConfig servletConfig) throws ServletException {
87
88     Logger logger = Logger.getLogger("com.google.zxing");
89     logger.addHandler(new ServletContextLogHandler(servletConfig.getServletContext()));
90
91     String emailAddress = servletConfig.getInitParameter("emailAddress");
92     String emailPassword = servletConfig.getInitParameter("emailPassword");
93     if (emailAddress == null || emailPassword == null) {
94       throw new ServletException("emailAddress or emailPassword not specified");
95     }
96
97     HttpParams params = new BasicHttpParams();
98     HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
99
100     SchemeRegistry registry = new SchemeRegistry();
101     registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
102     registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
103
104     client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params);
105
106     diskFileItemFactory = new DiskFileItemFactory();
107
108     Authenticator emailAuthenticator = new EmailAuthenticator(emailAddress, emailPassword);
109     emailTimer = new Timer("Email decoder timer", true);
110     emailTimer.schedule(new DecodeEmailTask(emailAuthenticator), 0L, EMAIL_CHECK_INTERVAL);
111
112     log.info("DecodeServlet configured");
113   }
114
115         @Override
116         protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
117
118                 String imageURIString = request.getParameter("u");
119                 if (imageURIString == null || imageURIString.length() == 0) {
120                         response.sendRedirect("badurl.jspx");
121                         return;
122                 }
123
124                 if (!(imageURIString.startsWith("http://") || imageURIString.startsWith("https://"))) {
125                         imageURIString = "http://" + imageURIString;
126                 }
127
128                 URI imageURI;
129                 try {
130                         imageURI = new URI(imageURIString);
131                 } catch (URISyntaxException urise) {
132                         response.sendRedirect("badurl.jspx");
133                         return;
134                 }
135
136     HttpGet getRequest = new HttpGet(imageURI);
137
138                 try {
139       HttpResponse getResponse = client.execute(getRequest);
140       if (getResponse.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK) {
141                                 response.sendRedirect("badurl.jspx");
142                                 return;
143                         }
144                         if (!isSizeOK(getResponse)) {
145                                 response.sendRedirect("badimage.jspx");
146                                 return;
147                         }
148       log.info("Decoding " + imageURI);
149       InputStream is = getResponse.getEntity().getContent();
150                         try {
151                                 processStream(is, response);
152                         } finally {
153                                 is.close();
154                         }
155     } catch (InterruptedException ie) {
156       getRequest.abort();
157       response.sendRedirect("badurl.jspx");
158     } catch (HttpException he) {
159       getRequest.abort();
160       response.sendRedirect("badurl.jspx");
161                 }
162
163         }
164
165         @Override
166         protected void doPost(HttpServletRequest request, HttpServletResponse response)
167                 throws ServletException, IOException {
168
169                 if (!ServletFileUpload.isMultipartContent(request)) {
170                         response.sendRedirect("badimage.jspx");
171                         return;
172                 }
173
174                 ServletFileUpload upload = new ServletFileUpload(diskFileItemFactory);
175                 upload.setFileSizeMax(MAX_IMAGE_SIZE);
176
177                 // Parse the request
178                 try {
179                         for (FileItem item : (List<FileItem>) upload.parseRequest(request)) {
180                                 if (!item.isFormField()) {
181                                         if (item.getSize() <= MAX_IMAGE_SIZE) {
182             log.info("Decoding uploaded file");
183                                                 InputStream is = item.getInputStream();
184                                                 try {
185                                                         processStream(is, response);
186                                                 } finally {
187                                                         is.close();
188                                                 }
189                                         } else {
190                                                 throw new ServletException("File is too large: " + item.getSize());
191                                         }
192                                         break;
193                                 }
194                         }
195                 } catch (FileUploadException fue) {
196                         response.sendRedirect("badimage.jspx");
197                 }
198                 
199         }
200
201         private static void processStream(InputStream is, HttpServletResponse response) throws IOException {
202                 BufferedImage image = ImageIO.read(is);
203                 if (image == null) {
204                         response.sendRedirect("badimage.jspx");
205                         return;
206                 }
207
208                 Reader reader = new MultiFormatReader();
209                 Result result;
210                 try {
211                         result = reader.decode(new BufferedImageMonochromeBitmapSource(image), HINTS);
212                 } catch (ReaderException re) {
213                         log.info("DECODE FAILED: " + re.toString());
214                         response.sendRedirect("notfound.jspx");
215                         return;
216                 }
217
218                 response.setContentType("text/plain");
219                 response.setCharacterEncoding("UTF-8");
220                 Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
221                 try {
222                         out.write(result.getText());
223                 } finally {
224                         out.close();
225                 }
226         }
227
228         private static boolean isSizeOK(HttpMessage getResponse) {
229     Header lengthHeader = getResponse.getLastHeader("Content-Length");
230                 if (lengthHeader != null) {
231                         long length = Long.parseLong(lengthHeader.getValue());
232                         if (length > MAX_IMAGE_SIZE) {
233                                 return false;
234                         }
235                 }
236                 return true;
237         }
238
239         @Override
240         public void destroy() {
241     log.config("DecodeServlet shutting down...");    
242     emailTimer.cancel();
243   }
244
245 }