2 * Sone - JsonPage.java - Copyright © 2010–2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sone.web.ajax;
20 import static java.util.logging.Logger.getLogger;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.PrintWriter;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
30 import net.pterodactylus.sone.data.LocalSone;
31 import net.pterodactylus.sone.web.WebInterface;
32 import net.pterodactylus.sone.web.page.FreenetPage;
33 import net.pterodactylus.sone.web.page.FreenetRequest;
34 import net.pterodactylus.util.io.Closer;
35 import net.pterodactylus.util.web.Page;
36 import net.pterodactylus.util.web.Response;
38 import com.fasterxml.jackson.databind.ObjectMapper;
39 import com.google.common.base.Optional;
41 import freenet.clients.http.ToadletContext;
44 * A JSON page is a specialized {@link Page} that will always return a JSON
45 * object to the browser, e.g. for use with AJAX or other scripting frameworks.
47 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
49 public abstract class JsonPage implements FreenetPage {
52 private static final Logger logger = getLogger("Sone.Web.Ajax");
54 /** The JSON serializer. */
55 private static final ObjectMapper objectMapper = new ObjectMapper();
57 /** The path of the page. */
58 private final String path;
60 /** The Sone web interface. */
61 protected final WebInterface webInterface;
64 * Creates a new JSON page at the given path.
67 * The path of the page
69 * The Sone web interface
71 public JsonPage(String path, WebInterface webInterface) {
73 this.webInterface = webInterface;
80 protected Optional<LocalSone> getCurrentSone(ToadletContext toadletContext) {
81 return webInterface.getCurrentSone(toadletContext);
84 protected Optional<LocalSone> getCurrentSone(ToadletContext toadletContext, boolean createSession) {
85 return webInterface.getCurrentSone(toadletContext, createSession);
89 // METHODS FOR SUBCLASSES TO OVERRIDE
93 * This method is called to create the JSON object that is returned back to
97 * The request to handle
98 * @return The created JSON object
100 protected abstract JsonReturnObject createJsonObject(FreenetRequest request);
103 * Returns whether this command needs the form password for authentication
104 * and to prevent abuse.
106 * @return {@code true} if the form password (given as “formPassword”) is
107 * required, {@code false} otherwise
109 @SuppressWarnings("static-method")
110 protected boolean needsFormPassword() {
115 * Returns whether this page requires the user to be logged in.
117 * @return {@code true} if the user needs to be logged in to use this page,
118 * {@code false} otherwise
120 @SuppressWarnings("static-method")
121 protected boolean requiresLogin() {
130 * Creates a success reply.
132 * @return A reply signaling success
134 protected static JsonReturnObject createSuccessJsonObject() {
135 return new JsonReturnObject(true);
139 * Creates an error reply.
142 * The error that has occured
143 * @return The JSON object, signalling failure and the error code
145 protected static JsonReturnObject createErrorJsonObject(String error) {
146 return new JsonErrorReturnObject(error);
157 public String getPath() {
165 public boolean isPrefixPage() {
173 public Response handleRequest(FreenetRequest request, Response response) throws IOException {
174 if (webInterface.getCore().getPreferences().isRequireFullAccess() && !request.getToadletContext().isAllowedFullAccess()) {
175 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required")));
177 if (needsFormPassword()) {
178 String formPassword = request.getHttpRequest().getParam("formPassword");
179 if (!webInterface.getFormPassword().equals(formPassword)) {
180 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required")));
183 if (requiresLogin()) {
184 if (!getCurrentSone(request.getToadletContext(), false).isPresent()) {
185 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required")));
189 JsonReturnObject jsonObject = createJsonObject(request);
190 return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(objectMapper.writeValueAsString(jsonObject));
191 } catch (Exception e1) {
192 logger.log(Level.WARNING, "Error executing JSON page!", e1);
193 return response.setStatusCode(500).setStatusText(e1.getMessage()).setContentType("text/plain").write(dumpStackTrace(e1));
201 public boolean isLinkExcepted(URI link) {
210 * Returns a byte array containing the stack trace of the given throwable.
213 * The throwable whose stack trace to dump into an array
214 * @return The array with the stack trace, or an empty array if the stack
215 * trace could not be dumped
217 private static byte[] dumpStackTrace(Throwable t) {
218 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
219 OutputStreamWriter writer = null;
220 PrintWriter printWriter = null;
222 writer = new OutputStreamWriter(byteArrayOutputStream, "uTF-8");
223 printWriter = new PrintWriter(writer);
224 t.printStackTrace(printWriter);
225 byteArrayOutputStream.flush();
226 return byteArrayOutputStream.toByteArray();
227 } catch (IOException ioe1) {
228 /* quite not possible. */
231 Closer.close(printWriter);
232 Closer.close(writer);
233 Closer.close(byteArrayOutputStream);