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 java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStreamWriter;
23 import java.io.PrintWriter;
26 import net.pterodactylus.sone.data.Sone;
27 import net.pterodactylus.sone.web.WebInterface;
28 import net.pterodactylus.sone.web.page.FreenetPage;
29 import net.pterodactylus.sone.web.page.FreenetRequest;
30 import net.pterodactylus.util.io.Closer;
31 import net.pterodactylus.util.json.JsonObject;
32 import net.pterodactylus.util.json.JsonUtils;
33 import net.pterodactylus.util.web.Page;
34 import net.pterodactylus.util.web.Response;
35 import freenet.clients.http.SessionManager.Session;
36 import freenet.clients.http.ToadletContext;
39 * A JSON page is a specialized {@link Page} that will always return a JSON
40 * object to the browser, e.g. for use with AJAX or other scripting frameworks.
42 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
44 public abstract class JsonPage implements FreenetPage {
46 /** The path of the page. */
47 private final String path;
49 /** The Sone web interface. */
50 protected final WebInterface webInterface;
53 * Creates a new JSON page at the given path.
56 * The path of the page
58 * The Sone web interface
60 public JsonPage(String path, WebInterface webInterface) {
62 this.webInterface = webInterface;
70 * Returns the current session, creating a new session if there is no
73 * @param toadletContenxt
75 * @return The current session, or {@code null} if there is no current
78 protected Session getCurrentSession(ToadletContext toadletContenxt) {
79 return webInterface.getCurrentSession(toadletContenxt);
83 * Returns the current session, creating a new session if there is no
84 * current session and {@code create} is {@code true}.
86 * @param toadletContenxt
89 * {@code true} to create a new session if there is no current
90 * session, {@code false} otherwise
91 * @return The current session, or {@code null} if there is no current
94 protected Session getCurrentSession(ToadletContext toadletContenxt, boolean create) {
95 return webInterface.getCurrentSession(toadletContenxt, create);
99 * Returns the currently logged in Sone.
101 * @param toadletContext
102 * The toadlet context
103 * @return The currently logged in Sone, or {@code null} if no Sone is
104 * currently logged in
106 protected Sone getCurrentSone(ToadletContext toadletContext) {
107 return webInterface.getCurrentSone(toadletContext);
111 * Returns the currently logged in Sone.
113 * @param toadletContext
114 * The toadlet context
116 * {@code true} to create a new session if no session exists,
117 * {@code false} to not create a new session
118 * @return The currently logged in Sone, or {@code null} if no Sone is
119 * currently logged in
121 protected Sone getCurrentSone(ToadletContext toadletContext, boolean create) {
122 return webInterface.getCurrentSone(toadletContext, create);
126 // METHODS FOR SUBCLASSES TO OVERRIDE
130 * This method is called to create the JSON object that is returned back to
134 * The request to handle
135 * @return The created JSON object
137 protected abstract JsonObject createJsonObject(FreenetRequest request);
140 * Returns whether this command needs the form password for authentication
141 * and to prevent abuse.
143 * @return {@code true} if the form password (given as “formPassword”) is
144 * required, {@code false} otherwise
146 @SuppressWarnings("static-method")
147 protected boolean needsFormPassword() {
152 * Returns whether this page requires the user to be logged in.
154 * @return {@code true} if the user needs to be logged in to use this page,
155 * {@code false} otherwise
157 @SuppressWarnings("static-method")
158 protected boolean requiresLogin() {
167 * Creates a success reply.
169 * @return A reply signaling success
171 protected static JsonObject createSuccessJsonObject() {
172 return new JsonObject().put("success", true);
176 * Creates an error reply.
179 * The error that has occured
180 * @return The JSON object, signalling failure and the error code
182 protected static JsonObject createErrorJsonObject(String error) {
183 return new JsonObject().put("success", false).put("error", error);
194 public String getPath() {
202 public boolean isPrefixPage() {
210 public Response handleRequest(FreenetRequest request, Response response) throws IOException {
211 if (webInterface.getCore().getPreferences().isRequireFullAccess() && !request.getToadletContext().isAllowedFullAccess()) {
212 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required")));
214 if (needsFormPassword()) {
215 String formPassword = request.getHttpRequest().getParam("formPassword");
216 if (!webInterface.getFormPassword().equals(formPassword)) {
217 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required")));
220 if (requiresLogin()) {
221 if (getCurrentSone(request.getToadletContext(), false) == null) {
222 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required")));
226 JsonObject jsonObject = createJsonObject(request);
227 return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(JsonUtils.format(jsonObject));
228 } catch (Exception e1) {
229 return response.setStatusCode(500).setStatusText(e1.getMessage()).setContentType("text/plain").write(dumpStackTrace(e1));
237 public boolean isLinkExcepted(URI link) {
246 * Returns a byte array containing the stack trace of the given throwable.
249 * The throwable whose stack trace to dump into an array
250 * @return The array with the stack trace, or an empty array if the stack
251 * trace could not be dumped
253 private static byte[] dumpStackTrace(Throwable t) {
254 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
255 OutputStreamWriter writer = null;
256 PrintWriter printWriter = null;
258 writer = new OutputStreamWriter(byteArrayOutputStream, "uTF-8");
259 printWriter = new PrintWriter(writer);
260 t.printStackTrace(printWriter);
261 byteArrayOutputStream.flush();
262 return byteArrayOutputStream.toByteArray();
263 } catch (IOException ioe1) {
264 /* quite not possible. */
267 Closer.close(printWriter);
268 Closer.close(writer);
269 Closer.close(byteArrayOutputStream);