<commit_before>/**
 * Copyright (C) 2011-2012 Turn, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.turn.ttorrent.tracker;

import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.common.LoggerUtils;
import com.turn.ttorrent.common.Peer;
import com.turn.ttorrent.common.PeerUID;
import com.turn.ttorrent.common.Torrent;
import com.turn.ttorrent.common.protocol.TrackerMessage.AnnounceRequestMessage;
import com.turn.ttorrent.common.protocol.TrackerMessage.ErrorMessage;
import com.turn.ttorrent.common.protocol.TrackerMessage.MessageValidationException;
import com.turn.ttorrent.common.protocol.http.HTTPAnnounceRequestMessage;
import com.turn.ttorrent.common.protocol.http.HTTPAnnounceResponseMessage;
import com.turn.ttorrent.common.protocol.http.HTTPTrackerErrorMessage;
import org.simpleframework.http.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;


/**
 * Tracker service to serve the tracker's announce requests.
 *
 * <p>
 * It only serves announce requests on /announce, and only serves torrents the
 * {@link Tracker} it serves knows about.
 * </p>
 *
 * <p>
 * The list of torrents {@see #requestHandler.getTorrentsMap()} is a map of torrent hashes to their
 * corresponding Torrent objects, and is maintained by the {@link Tracker} this
 * service is part of. The TrackerRequestProcessor only has a reference to this map, and
 * does not modify it.
 * </p>
 *
 * @author mpetazzoni
 * @see <a href="http://wiki.theory.org/BitTorrentSpecification">BitTorrent protocol specification</a>
 */
public class TrackerRequestProcessor {

	private static final Logger logger =
		LoggerFactory.getLogger(TrackerRequestProcessor.class);

	/**
	 * The list of announce request URL fields that need to be interpreted as
	 * numeric and thus converted as such in the request message parsing.
	 */
	private static final String[] NUMERIC_REQUEST_FIELDS =
		new String[] {
			"port", "uploaded", "downloaded", "left",
			"compact", "no_peer_id", "numwant"
		};
  private static final int SEEDER_ANNOUNCE_INTERVAL = 150;

  private boolean myAcceptForeignTorrents=true; //default to true
  private int myAnnounceInterval = 60; //default value
	private final AddressChecker myAddressChecker;


	/**
	 * Create a new TrackerRequestProcessor serving the given torrents.
	 *
	 */
	public TrackerRequestProcessor() {
		this(new AddressChecker() {
			@Override
			public boolean isBadAddress(String ip) {
				return false;
			}
		});
	}

	public TrackerRequestProcessor(AddressChecker addressChecker) {
		myAddressChecker = addressChecker;
	}

	/**
	 * Process the announce request.
	 *
	 * <p>
	 * This method attemps to read and parse the incoming announce request into
	 * an announce request message, then creates the appropriate announce
	 * response message and sends it back to the client.
	 * </p>
	 *
	 */
	public void process(final String uri, final String hostAddress, RequestHandler requestHandler)
          throws IOException {
		// Prepare the response headers.

		/**
		 * Parse the query parameters into an announce request message.
		 *
		 * We need to rely on our own query parsing function because
		 * SimpleHTTP's Query map will contain UTF-8 decoded parameters, which
		 * doesn't work well for the byte-encoded strings we expect.
		 */
		HTTPAnnounceRequestMessage announceRequest = null;
		try {
			announceRequest = this.parseQuery(uri, hostAddress);
		} catch (MessageValidationException mve) {
			LoggerUtils.warnAndDebugDetails(logger, "Unable to parse request message. Request url is ", uri, mve);
      serveError(Status.BAD_REQUEST, mve.getMessage(), requestHandler);
			return;
		}

    // The requested torrent must be announced by the tracker if and only if myAcceptForeignTorrents is false
    final ConcurrentMap<String, TrackedTorrent> torrentsMap = requestHandler.getTorrentsMap();
    TrackedTorrent torrent = torrentsMap.get(announceRequest.getHexInfoHash());
    if (!this.myAcceptForeignTorrents && torrent == null) {
      logger.warn("Requested torrent hash was: {}", announceRequest.getHexInfoHash());
      serveError(Status.BAD_REQUEST, ErrorMessage.FailureReason.UNKNOWN_TORRENT, requestHandler);
      return;
    }

    if (torrent == null) {
      torrent = new TrackedTorrent(announceRequest.getInfoHash());
      TrackedTorrent oldTorrent = requestHandler.getTorrentsMap().putIfAbsent(torrent.getHexInfoHash(), torrent);
      if (oldTorrent != null) {
        torrent = oldTorrent;
      }
    }

		AnnounceRequestMessage.RequestEvent event = announceRequest.getEvent();
		PeerUID peerUID = new PeerUID(new InetSocketAddress(announceRequest.getIp(), announceRequest.getPort()), announceRequest.getHexInfoHash());

		// When no event is specified, it's a periodic update while the client
		// is operating. If we don't have a peer for this announce, it means<commit_msg>fixed skipping parameter in log message<commit_after>/**
 * Copyright (C) 2011-2012 Turn, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.turn.ttorrent.tracker;

import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.common.LoggerUtils;
import com.turn.ttorrent.common.Peer;
import com.turn.ttorrent.common.PeerUID;
import com.turn.ttorrent.common.Torrent;
import com.turn.ttorrent.common.protocol.TrackerMessage.AnnounceRequestMessage;
import com.turn.ttorrent.common.protocol.TrackerMessage.ErrorMessage;
import com.turn.ttorrent.common.protocol.TrackerMessage.MessageValidationException;
import com.turn.ttorrent.common.protocol.http.HTTPAnnounceRequestMessage;
import com.turn.ttorrent.common.protocol.http.HTTPAnnounceResponseMessage;
import com.turn.ttorrent.common.protocol.http.HTTPTrackerErrorMessage;
import org.simpleframework.http.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;


/**
 * Tracker service to serve the tracker's announce requests.
 *
 * <p>
 * It only serves announce requests on /announce, and only serves torrents the
 * {@link Tracker} it serves knows about.
 * </p>
 *
 * <p>
 * The list of torrents {@see #requestHandler.getTorrentsMap()} is a map of torrent hashes to their
 * corresponding Torrent objects, and is maintained by the {@link Tracker} this
 * service is part of. The TrackerRequestProcessor only has a reference to this map, and
 * does not modify it.
 * </p>
 *
 * @author mpetazzoni
 * @see <a href="http://wiki.theory.org/BitTorrentSpecification">BitTorrent protocol specification</a>
 */
public class TrackerRequestProcessor {

	private static final Logger logger =
		LoggerFactory.getLogger(TrackerRequestProcessor.class);

	/**
	 * The list of announce request URL fields that need to be interpreted as
	 * numeric and thus converted as such in the request message parsing.
	 */
	private static final String[] NUMERIC_REQUEST_FIELDS =
		new String[] {
			"port", "uploaded", "downloaded", "left",
			"compact", "no_peer_id", "numwant"
		};
  private static final int SEEDER_ANNOUNCE_INTERVAL = 150;

  private boolean myAcceptForeignTorrents=true; //default to true
  private int myAnnounceInterval = 60; //default value
	private final AddressChecker myAddressChecker;


	/**
	 * Create a new TrackerRequestProcessor serving the given torrents.
	 *
	 */
	public TrackerRequestProcessor() {
		this(new AddressChecker() {
			@Override
			public boolean isBadAddress(String ip) {
				return false;
			}
		});
	}

	public TrackerRequestProcessor(AddressChecker addressChecker) {
		myAddressChecker = addressChecker;
	}

	/**
	 * Process the announce request.
	 *
	 * <p>
	 * This method attemps to read and parse the incoming announce request into
	 * an announce request message, then creates the appropriate announce
	 * response message and sends it back to the client.
	 * </p>
	 *
	 */
	public void process(final String uri, final String hostAddress, RequestHandler requestHandler)
          throws IOException {
		// Prepare the response headers.

		/**
		 * Parse the query parameters into an announce request message.
		 *
		 * We need to rely on our own query parsing function because
		 * SimpleHTTP's Query map will contain UTF-8 decoded parameters, which
		 * doesn't work well for the byte-encoded strings we expect.
		 */
		HTTPAnnounceRequestMessage announceRequest = null;
		try {
			announceRequest = this.parseQuery(uri, hostAddress);
		} catch (MessageValidationException mve) {
			LoggerUtils.warnAndDebugDetails(logger, "Unable to parse request message. Request url is {}", uri, mve);
      serveError(Status.BAD_REQUEST, mve.getMessage(), requestHandler);
			return;
		}

    // The requested torrent must be announced by the tracker if and only if myAcceptForeignTorrents is false
    final ConcurrentMap<String, TrackedTorrent> torrentsMap = requestHandler.getTorrentsMap();
    TrackedTorrent torrent = torrentsMap.get(announceRequest.getHexInfoHash());
    if (!this.myAcceptForeignTorrents && torrent == null) {
      logger.warn("Requested torrent hash was: {}", announceRequest.getHexInfoHash());
      serveError(Status.BAD_REQUEST, ErrorMessage.FailureReason.UNKNOWN_TORRENT, requestHandler);
      return;
    }

    if (torrent == null) {
      torrent = new TrackedTorrent(announceRequest.getInfoHash());
      TrackedTorrent oldTorrent = requestHandler.getTorrentsMap().putIfAbsent(torrent.getHexInfoHash(), torrent);
      if (oldTorrent != null) {
        torrent = oldTorrent;
      }
    }

		AnnounceRequestMessage.RequestEvent event = announceRequest.getEvent();
		PeerUID peerUID = new PeerUID(new InetSocketAddress(announceRequest.getIp(), announceRequest.getPort()), announceRequest.getHexInfoHash());

		// When no event is specified, it's a periodic update while the client
		// is operating. If we don't have a peer for this announce, it means
{'fraction_non_alphanumeric': 0.0898308041165184, 'fraction_numerical': 0.0034885749171463458, 'mean_word_length': 4.414069877242682, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3316635', 'n_tokens_mistral': 3363, 'n_tokens_neox': 3154, 'n_words': 1026}