<commit_before>package plugins.CENO.Bridge;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.minidev.json.JSONObject;
import net.minidev.json.parser.ParseException;

import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.server.Request;

import plugins.CENO.Bridge.BundleInserter.InsertCallback;
import plugins.CENO.Bridge.BundlerInterface.Bundle;
import plugins.CENO.Common.CENOJettyHandler;
import freenet.client.InsertException;
import freenet.client.async.BaseClientPutter;
import freenet.support.Logger;

/* ------------------------------------------------------------ */
/** CENOBridge Plugin handler for requests to cache bundles
 * 	
 * BundleInserterHandler listens to {@link CENOBridge#bundleInserterPort} port
 * and under the "/store" route for POST requests.
 * Those POST requests include the bundled page as well as the original url.
 * The handler caches the given bundle under its signed subspace.
 * Upon successful insertion, the handler replies with "stored".
 */
public class BundleInserterHandler extends CENOJettyHandler {

	/** The duration of time an insertion request times out */
	static final long insertionRequestTimeout = TimeUnit.MINUTES.toMillis(5);

	public class HandlerInsertCallback extends InsertCallback {
		private Request baseRequest;
		private Continuation continuation;
		private HttpServletResponse response;

		public HandlerInsertCallback(Request request, Continuation continuation, HttpServletResponse response) {
			super();
			this.baseRequest = request;
			this.continuation = continuation;
			this.response = response;
		}

		@Override
		public void onSuccess(BaseClientPutter state) {
			super.onSuccess(state);
			response.setContentType("text/html;charset=utf-8");
			response.setStatus(HttpServletResponse.SC_OK);
			try {
				response.getWriter().println("stored");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			baseRequest.setHandled(true);
			continuation.complete();
		}

		@Override
		public void onFailure(InsertException e, BaseClientPutter state) {
			super.onFailure(e, state);
			try {
				writeError(baseRequest, response, "not stored");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			continuation.complete();
		}

	}

	public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response)
			throws IOException, ServletException {
		// Only POST requests at /store route will be handled
		if (!request.getMethod().equals("POST")) {
			writeError(baseRequest, response, "Not a POST request at /store route");
			return;
		}

		// Get the data from the POST request
		//TODO Add support for multi-part POST requests
		JSONObject requestJSON;
		try {
			requestJSON = readJSONbody(request.getReader());
		} catch (ParseException e) {
			writeError(baseRequest, response, "Could not parse JSON");
			return;
		}
		if(!requestJSON.containsKey("url")) {
			writeError(baseRequest, response, "No url attribute in request body");
			return;
		}
		if(!requestJSON.containsKey("bundle")) {
			writeError(baseRequest, response, "No bundle attribute in request body");
			return;
		}

		String urlParam = requestJSON.get("url").toString();
		if((urlParam == null) || urlParam.isEmpty()) {
			writeError(baseRequest, response, "Invalid url attribute");
			return;
		}
		
		if (!CENOBridge.isMasterBridge() && urlParam.equals("CENO-RSS")) {
			Logger.normal(this, "Got request to insert CENO-RSS but won't handle since this is not the master bridge");
			writeMessage("Not a Master bridge,  won't insert", baseRequest, response, urlParam);
			return;
		}

		Bundle bundle = new Bundle(urlParam);
		if ((requestJSON.get("bundle") != null)) {
			bundle.setContent(requestJSON.get("bundle").toString());
		} else {
			writeError(baseRequest, response, "Bundle attribute was null");
			return;
		}

		if (!bundle.getContent().isEmpty()) {
			Continuation continuation = ContinuationSupport.getContinuation(baseRequest);
			continuation.setTimeout(insertionRequestTimeout);
			if (continuation.isExpired())
			{
				writeError(baseRequest, response, "Request timed out");
				return;
			}
			try {
				BundleInserter.insertBundle(urlParam, bundle, new HandlerInsertCallback(baseRequest, continuation, response));
			} catch (InsertException e) {
				writeError(baseRequest, response, "Error during insertion");
				return;
			} catch (Exception e1) {
				writeError(baseRequest, response, "Exception during insertion: " + e1.getMessage());
			}
			continuation.suspend();
		} else {
			writeError(baseRequest, response, urlParam);
		}
		writeError(baseRequest, response, "OK");
	}
}
<commit_msg>BundleInserterHandler validates the URL in the JSON body before preparing a bundle for it<commit_after>package plugins.CENO.Bridge;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.minidev.json.JSONObject;
import net.minidev.json.parser.ParseException;

import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.server.Request;

import plugins.CENO.Bridge.BundleInserter.InsertCallback;
import plugins.CENO.Bridge.BundlerInterface.Bundle;
import plugins.CENO.Common.CENOJettyHandler;
import plugins.CENO.Common.URLtoUSKTools;
import freenet.client.InsertException;
import freenet.client.async.BaseClientPutter;
import freenet.support.Logger;

/* ------------------------------------------------------------ */
/** CENOBridge Plugin handler for requests to cache bundles
 * 	
 * BundleInserterHandler listens to {@link CENOBridge#bundleInserterPort} port
 * and under the "/store" route for POST requests.
 * Those POST requests include the bundled page as well as the original url.
 * The handler caches the given bundle under its signed subspace.
 * Upon successful insertion, the handler replies with "stored".
 */
public class BundleInserterHandler extends CENOJettyHandler {

	/** The duration of time an insertion request times out */
	static final long insertionRequestTimeout = TimeUnit.MINUTES.toMillis(5);

	public class HandlerInsertCallback extends InsertCallback {
		private Request baseRequest;
		private Continuation continuation;
		private HttpServletResponse response;

		public HandlerInsertCallback(Request request, Continuation continuation, HttpServletResponse response) {
			super();
			this.baseRequest = request;
			this.continuation = continuation;
			this.response = response;
		}

		@Override
		public void onSuccess(BaseClientPutter state) {
			super.onSuccess(state);
			response.setContentType("text/html;charset=utf-8");
			response.setStatus(HttpServletResponse.SC_OK);
			try {
				response.getWriter().println("stored");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			baseRequest.setHandled(true);
			continuation.complete();
		}

		@Override
		public void onFailure(InsertException e, BaseClientPutter state) {
			super.onFailure(e, state);
			try {
				writeError(baseRequest, response, "not stored");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			continuation.complete();
		}

	}

	public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response)
			throws IOException, ServletException {
		// Only POST requests at /store route will be handled
		if (!request.getMethod().equals("POST")) {
			writeError(baseRequest, response, "Not a POST request at /store route");
			return;
		}

		// Get the data from the POST request
		//TODO Add support for multi-part POST requests
		JSONObject requestJSON;
		try {
			requestJSON = readJSONbody(request.getReader());
		} catch (ParseException e) {
			writeError(baseRequest, response, "Could not parse JSON");
			return;
		}
		if(!requestJSON.containsKey("url")) {
			writeError(baseRequest, response, "No url attribute in request body");
			return;
		}
		if(!requestJSON.containsKey("bundle")) {
			writeError(baseRequest, response, "No bundle attribute in request body");
			return;
		}

		String urlParam = requestJSON.get("url").toString();
		if((urlParam == null) || urlParam.isEmpty()) {
			writeError(baseRequest, response, "Invalid url attribute");
			return;
		}

		try {
			urlParam = URLtoUSKTools.validateURL(urlParam);
		} catch (MalformedURLException e) {
			writeError(baseRequest, response, "URL failed validation and a bundle will not be inserted");
		}
		
		if (!CENOBridge.isMasterBridge() && urlParam.equals("CENO-RSS")) {
			Logger.normal(this, "Got request to insert CENO-RSS but won't handle since this is not the master bridge");
			writeMessage("Not a Master bridge,  won't insert", baseRequest, response, urlParam);
			return;
		}

		Bundle bundle = new Bundle(urlParam);
		if ((requestJSON.get("bundle") != null)) {
			bundle.setContent(requestJSON.get("bundle").toString());
		} else {
			writeError(baseRequest, response, "Bundle attribute was null");
			return;
		}

		if (!bundle.getContent().isEmpty()) {
			Continuation continuation = ContinuationSupport.getContinuation(baseRequest);
			continuation.setTimeout(insertionRequestTimeout);
			if (continuation.isExpired())
			{
				writeError(baseRequest, response, "Request timed out");
				return;
			}
			try {
				BundleInserter.insertBundle(urlParam, bundle, new HandlerInsertCallback(baseRequest, continuation, response));
			} catch (InsertException e) {
				writeError(baseRequest, response, "Error during insertion");
				return;
			} catch (Exception e1) {
				writeError(baseRequest, response, "Exception during insertion: " + e1.getMessage());
			}
			continuation.suspend();
		} else {
			writeError(baseRequest, response, urlParam);
		}
		writeError(baseRequest, response, "OK");
	}
}

{'fraction_non_alphanumeric': 0.11603128054740958, 'fraction_numerical': 0.0011730205278592375, 'mean_word_length': 4.384736842105263, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5628027', 'n_tokens_mistral': 3251, 'n_tokens_neox': 2816, 'n_words': 757}