Pull to refresh

Comments 18

Спасибо, классная статья, тоже люблю Graphopper)

А как на примере Postgres данные по трафику задавать?

Спасибо за отзыв.
Можно поподробнее "трафик", это что? Какой у него аналог в тегах OSM? highway?

Если я правильно понял вопрос, то общий подход такой:

  1. Вы можете создавать в таблице любые поля. Главное добавить их во вьюшку см. Подготовка данных

  2. Затем эти данные можно считывать из БД таким образом см. graphhopper-reader-postgis

for (String tag : tagsToCopy) {                             
    Object val = road.getAttribute(tag);                             
    if (val != null) {                             
        way.setTag(tag, val);                             
    }                             
 }  


highway там вот так обрабатывается:

// Тип дороги                             
Object type = road.getAttribute("fclass");                             
if (type != null) {                             
    way.setTag("highway", type.toString());                             
}


т.е. здесь могут быть любые атрибуты, какие пожелаете.

Encoder обрабатывает этот тег например как в CarFlagEncoder

нет, не совсем, трафик это информация по пробкам, вот есть пример реализации

я так полагаю, данные по трафику так же можно валить в БД и далее учитывать при построении маршрута, например меняя maxspeed (мое предположение)

Пример реализации ещё не смотрел. Интересно как они реализовали, посмотрю обязательно.

Я бы так реализовывал: в БД я бы хранил только редко меняемые или постоянные параметры, информация о пробках меняется динамически, - в БД её хранить не оптимально, - потребует постоянной перезаписи. По крайней мере не в той же базе, которая используется для построителя.

Я бы обработку вынес в класс в связанный с определением веса см. weighting. Уже в момент обработки ребра при маршрутиации смотрел какая на нём нагрузка - возможно получая её из стороннего сервиса, и использовал бы полученные данные для расчёта веса переопределив calcEdgeWeight изAbstractWeighting

В БД я бы все-таки валил инфу по трафику, потому что это статистика и прогнозы в будущем. На крайний случай, если фид данных отвалится - можно будет строить маршрут исходя из статистики.

Посмотрел пример. Их задумка оказалась не сложной, всё в классе DataUpdater:

  1. Есть у них какой-то волшебный сервис http://www.stadt-koeln.de/externe-dienste/open-data/traffic.php. Он возвращает загруженность дорог, и с координатами.

  2. Они получают LocationIndex locationIndex = hopper.getLocationIndex(); и находят в нём рёбра по координатам.

  3. В найденном ребре подменяют скорость см. lockedFeed

if (oldSpeed != value) {
    updates++;
    // TODO use different speed for the different directions (see e.g. Bike2WeightFlagEncoder)
    logger.info("Speed change at " + entry.getId() + " (" + point + "). Old: " + oldSpeed + ", new:" + value);
    edge.setFlags(carEncoder.setSpeed(edge.getFlags(), value));
}

Этот locationIndex потом в классе Router применяется.

Но в целом они тоже используют внешний источник для информации по трафику

я только не понимаю, какой speed они меняют, который maxspeed?

Обратите внимание на строки

if (oldSpeed != value) {
    updates++;
    // TODO use different speed for the different directions (see e.g. Bike2WeightFlagEncoder)
    logger.info("Speed change at " + entry.getId() + " (" + point + "). Old: " + oldSpeed + ", new:" + value);
    edge.setFlags(carEncoder.setSpeed(edge.getFlags(), value));
}

Они не оперируют такими понятиями как скорость максимальная/минимальная/средняя. Есть просто "скорость", и graphhopper при построении самого быстрого маршрута полагается на неё, это видно из класса FastestWeighting, в методе calcEdgeWeight.


Понятие maxSpeed там скорее стоит воспринимать как "максимальная скорость с которой можно ехать превозмогая всё (пробки, качество дорог, сопротивление воздуха) кроме правил дорожного движения".

String sql = String.format("DELETE FROM %s WHERE gid IN (%s)", layerName, StringUtils.join(deletesIds, ','));

Ням-ням. В одном из айдишников может быть значение:

"1);DROP DATABASE;--"

И начнётся развлекательная программа. Где ваш продакшн?

Ээээ. Вы про вот этот метод что ли:

private void deleteFromTemp(List<Long> deletesIds) {
    if (!deletesIds.isEmpty()) {
        String sql = String.format("DELETE FROM %s WHERE gid IN (%s)", layerName, StringUtils.join(deletesIds, ','));
        jdbcTemplate.update(sql);
    }
}

Вы уверены что в одном из этих List<Long> deletesIds айдишников может быть что-то пободное DROP DATABASE ?

Ну ладно, но одумайтесь, сегодня вы превращаете List<Long> в DROP DATABASE, завтра свинец в золото, а послезавтра сожгут на костре.

Джунам раз за разом объясняют -- конкатенация и форматирование SQL зло, И раз за разом одни и те же SQL инъекции. В одном из примеров инъекцию вы точно прошляпили. Поэтому и спрашиваю про прод -- человеческий язык не все понимают. То ли дело язык упавшего прода

Мы всё про тот же самый пример, в котором вы утверждаете что что среди айдишников может быть DROP DATABASE?

Если да, то это найденная SQL инъекция основана на аксиоме о том, что в List<Long> можно написать "1);DROP DATABASE;--".

Боюсь что это не так. Если же действительно можно, то объясните каким образом, а не ходите вокруг да около с "человеческий язык не все понимают", - постараюсь всё-таки понять, для того мы здесь и пишем.

И рассматривать одну строку:

String sql = String.format("DELETE FROM %s WHERE gid IN (%s)", layerName, StringUtils.join(deletesIds, ','));

в отрыве от остального метода - не комильфо.

Мы всё про тот же самый пример, в котором вы утверждаете что что среди айдишников может быть DROP DATABASE?

Нет, я бегло проверил другие примеры и нашёл подходящий. Я о том и говорю, что многие люди не понимают языка человеческого. Поэтому начнём с дропнутой БД, а потом плавно перейдём к работе над ошибками

БД есть в контейнере на DockerHub, исходник есть на GitHub. Не знаю что Вас останавливает

Позвольте вмешаться, про инъекции с вами согласен, но не в этом конкретном примере. У автора метод принимает коллекцию из различных Long и скорее всего в этом случае не найдется никакого long значения = «1);DROP DATABASE;--».

Да, в данном случае согласен. Java не динамический язык -- и тут сюрпризов не будет. Сюрпризы пораждает сам джуновский подход -- и я вижу как раз одно подходящее место в другом запросе. А вообще мне любопытно пощупать, как оно работает

Не хотел Вас расстраивать, но если Вы внимательно посмотрите на сервис в GitHub gist то увидите, что публичные методы принимают либо параметры типа Long, либо org.postgis.Geometry, с Long Вы уже поспешили засунуть туда SQL инъекцию, теперь видимо пытаетесь с Geometry, ну если вам известен способ как в org.postgis.Geometry засунуть не пойми что, то соглашусь что инъекция возможна.
Да есть ещё layerName, но к нему не предусмотрен публичный доступ (см. GitHub gist), перекомпилировать разве что.

В общем, хватит бравировать, все найденные вами инъекции основаны на невнимательности, поспешности и попытке рассмотреть строку в отрыве от метода.


Если хотите пощупать, то ещё раз сообщаю что БД есть в контейнере, а исходный код я ни от кого, так же, не утаиваю - хотите щупайте.

Тем более непонятно, если бы Вы ошибку нашли, то давно бы её озвучили, но Вы продолжаете пускать пыль в глаза, что как бы наводит на мысль, что это блеф, чтобы не выглядеть нелепо после поспешно найденной инъекции.

И теперь вместо того чтобы обсуждать предмет публикации я вынужден реагировать на ваш комплекс учителя.

Sign up to leave a comment.

Articles