예제 #1
0
    def find_secrets(self, info: RequestInfo, words: List[str]):
        """ Проверяет изменения в ответе для заданного списка параметров `words` в URL-строке

        :param info:
        :param words: Названия заголовков
        :return:    dict([(`param`, `reasons`)]) - если найдено конкретное слово
                    int - если со словами требуется провести манипуляции
        """

        # Добавляем параметры в URL-строку
        request = info.copy_request()
        params = {
            k: v
            for k, v in zip(words, [info.url_param_value] * len(words))
        }
        param_type = ParamType.URL

        self.add_url_params(request, params)

        response = self.do_request(request)

        # Если не удалось получить ответ на запрос, то убираем слова из очереди
        if response is None:
            self.logger.error(
                f'[{info.origin_url}] Ошибка при выполнении запроса, '
                'порция удалена из учереди')
            return DISCARD_WORDS

        reasons = self.get_url_param_reasons(info, response)

        # Если есть изменения
        if reasons:
            # Если найден конкретный заголовок, то возвращаем его вместе с причинами
            if len(words) == 1:
                self.logger.success(
                    f'Найден {param_type}-параметр "{words[0]}" к {info.origin_url}'
                )
                self.logger.debug(
                    f'{param_type}-параметр "{words[0]}": reasons={reasons}')
                return {
                    words[0]: {
                        'url': info.origin_url,
                        'reasons': reasons,
                        'type': param_type,
                        'response': response
                    }
                }
            # Иначе где-то среди слов есть искомые
            else:
                return SPLIT_WORDS
        # Иначе отбросить
        else:
            return DISCARD_WORDS
예제 #2
0
    def find_secrets(self, info: RequestInfo, words: List[str]):
        """

        :param info:
        :param words:
        :return:
        """
        request = info.copy_request()
        headers = {k: v for k, v in zip(words, [info.header_value] * len(words))}
        param_type = ParamType.HEADER

        self.add_headers(request, headers)

        response = self.do_request(request)

        # Если не удалось получить ответ на запрос, то убираем слова из очереди
        if response is None:
            self.logger.error(
                f'[{info.origin_url}] Ошибка при выполнении запроса, '
                'порция удалена из учереди')
            return DISCARD_WORDS

        reasons = self.check_response(info, response)

        # Если есть изменения
        if reasons:
            # Если найден конкретный заголовок, то возвращаем его вместе с причинами
            if len(words) == 1:
                self.logger.success(f'Найден {param_type}-параметр "{words[0]}" к {info.origin_url}')
                self.logger.debug(f'{param_type}-параметр "{words[0]}": reasons={reasons}')
                return {words[0]: {'url': info.origin_url, 'reasons': reasons, 'type': param_type,
                                   'response': response}}
            # Иначе где-то среди слов есть искомые
            else:
                return SPLIT_WORDS
        # Иначе отбросить
        else:
            return DISCARD_WORDS
예제 #3
0
    def get_optimal_bucket(self, info: RequestInfo, min_chunk: int, add_random: Callable,
                           additional_size: Callable, logger: Logger) -> Union[int, None]:
        """ Ищет оптимальный размер порции параметров соотношение (Длина порции) / (время ответа)

        :param info:
        :return:
        """
        left, cur, right = 1024, 2048, 4096
        left_border = 0
        right_border = math.inf

        counter = 5

        optimal_size = None
        optimal_rate = 0

        # Ограничение на число циклов
        while counter:
            counter -= 1

            # Если левая граница обнулилась
            if left == 0:
                break

            # Если диапазон неделим, то прекратить цикл
            if right - cur < 2 or cur - left < 2:
                break

            # Подготавливаем запросы
            _requests = [info.copy_request() for _ in range(3)]
            for request, length in zip(_requests, [left, cur, right]):
                add_random(request, length)

            # Отправляем
            jobs = [gevent.spawn(self.do_request, request) for request in _requests]
            gevent.joinall(jobs)
            responses = [job.value for job in jobs]

            # Получаем результаты
            results = []
            # results = [response.status_code == info.response.status_code if response is not None else response
            #            for response in responses]

            for response in responses:
                if not response:
                    results.append(None)
                # Если совпадают коды ответа
                elif response.status_code == info.response.status_code:
                    results.append(True)
                # Если Payload Too Large/URI Too Long/Request Header Fields Too Large
                elif response.status_code in {413, 414, 431}:
                    results.append(False)
                # Если код ответа на отрезке  [500, 599], а оригинальный код не в этом отрезке
                elif 500 <= response.status_code < 600 and not 500 <= info.response.status_code < 600:
                    results.append(False)
                # Если код ответа на отрезке  [400, 499], а оригинальный код не в этом отрезке
                elif 400 <= response.status_code < 500 and not 400 <= info.response.status_code < 500:
                    results.append(False)
                else:
                    logger.debug(f'Необработанный случай: act_status_code={response.status_code}, orig_status_cod={info.response.status_code}')
                    results.append(True)

            # Если все запросы не получили ответа от сервера, то сдвигаемся влево
            if not any(results):
                right_border = left

                right = right_border
                cur = right >> 1
                left = cur >> 1

                continue

            # Иначе выбираем среди ответов оптимальный
            rates = []

            for response, size, result in zip([response for response in responses], [left, cur, right], results):
                # Рассматриваем только те случаи, когда мы не вышли за границы
                elapsed = response.elapsed.total_seconds() if (response is not None and result == True) else math.inf
                rate = round(size / elapsed, 1)
                rates.append(rate)

                if rate > optimal_rate and result:
                    optimal_rate = rate
                    optimal_size = size

            # Cмотрим, в какую сторону развивается динамика
            max_rate = max(rates)

            # Если все запросы не превысили границу, то двигаемся в сторону динамики
            if all(results):
                # Если динамика увеличивается слева
                if rates[0] == max_rate:
                    right_border = right

                    # То смещаемся влево
                    right = left - 1
                    cur = right >> 1
                    left = cur >> 1

                    # Если левый указатель меньше левой границы
                    if left < left_border:
                        # То пересчитываем указатели в пределах границ
                        left, cur, right = self.shift_bounds(left_border, right_border)

                # Если динамика увеличивается справа
                elif rates[2] == max_rate:
                    left_border = left

                    # То смещаемся вправо
                    left = right + 1
                    cur = left << 1
                    right = cur << 1

                    # Если правый указатель вышел за пределы правой границы
                    if right > right_border:
                        # То пересчитываем указатели в пределах границ
                        left, cur, right = self.shift_bounds(left_border, right_border)

                # Иначе рассматриваем окрестности центра
                else:
                    left_border = left if left > left_border else left_border
                    right_border = right if right < right_border else right_border

                    left = (left + cur) // 2
                    right = (cur + right) // 2
            # Если результаты [True, False|None, False|None]
            elif results[0] == True and all([not r for r in results[1:]]):
                right_border = cur if cur < right_border else right_border
                # То сдвигаемся влево
                right = left - 1
                cur = right >> 1
                left = cur >> 1
            # Если результаты [True, True, False|None]
            elif results[2] in {None, False} and all([r for r in results[:2]]):
                right_border = right if right < right_border else right_border
                # То смотрим на динамику слева и посередине

                # Если динамика увеличивается слева
                if rates[0] == max_rate:
                    # То сдвигаемся влево
                    right = left - 1  # Сдвигаем рассматриваемую правую границу на 1 от ранее рассматриваемой левой
                    cur = right >> 1
                    left = cur >> 1

                    # Если левый указатель меньше левой границы
                    if left < left_border:
                        # То пересчитываем указатели в пределах границ
                        left, cur, right = self.shift_bounds(left_border, right_border)
                # Иначе копаем в пределах cur
                else:
                    right = round((cur + right) / 2)
                    left = (left + cur) // 2
            else:
                # Сдвигаемся влево
                right = left - 1  # Сдвигаем рассматриваемую правую границу на 1 от ранее рассматриваемой левой
                cur = right >> 1
                left = cur >> 1

        # Если по итогу оптимальный размер меньше минимально требуемого, то вернуть минимально требуемый требуемый
        if optimal_size is not None:
            if optimal_size < min_chunk < right_border:
                return min_chunk + additional_size(info)

            return optimal_size + additional_size(info)

        return optimal_size