(django) ustawienie limitu czasu na ładowanie widoku, po tym czasie załadowanie innej strony

0

Dzień dobry.

Chciałbym, aby dany widok miał ustalony timeout, po którym, jeżeli strona się nie załaduje, pojawiała się inna, bardzo mała strona (w zasadzie plik tekstowy z jedno-linijkowym komunikatem). Jak to zrobić?

Dzięki
M.

1

Nie wiem czy Django ma takie timeouty z deafulta. Mozesz zrobic to js'em w stylu:

setTimeout(()=>{
    const ElementNaTymTemplate = document.querySelector("blabla")
    if(ElementNaTymTemplate === null){window.location = "nowy adres"}
},10000)
0

Nie wiem, jaki cel ma Twój kod, ale mi chodzi o timeout po stronie serwera, konkretnie o przerwanie skryptu jeżeli zbyt długo się wykonuje. W takim przypadku chcę aby pojawił się komunikat error x lub inny podobny.

3

@mpaw musisz w takim razie wykonywać ten swój skrypt asynchronicznie w osobnym wątku z jakimś timeoutem i jak go przekroczy to zwracać ten inny wynik. https://docs.python.org/2/library/threading.html#threading.Thread.join

0

@Shalom: czy ten wątek musi uruchamiać się całkowicie oddzielnie? Używam django, bo biblioteka której używam jest spora i długo się importuje. Więc jeżeli proces miałby się ładować od 0 to taka opcja niestety odpada :(

3

def fun(a, b, c):
    import time
    time.sleep(0.5) # będzie ok, dla 1 i więcej będzie timeout exception
    return a + b + c


with concurrent.futures.ThreadPoolExecutor() as executor:
    future = executor.submit(fun, 1, 2, 3)
    result = future.result(timeout=1) # seconds
    print(result)

To wątek a nie proces, więc nie będzie się nic drugi raz importować.

0

@mpaw: Można użyć https://django-q.readthedocs.io/en/latest/configure.html#retry albo ja kiedyś coś takiego znalazłem:

@celery.task(time_limit=50)
def foo():
    foo1()
    foo2()
0

Dziękuję.

@Shalom nie wiem co zrobiłem źle, wkleję kod:

from concurrent.futures import ThreadPoolExecutor

def latexResponse(code):
    sp = splitString(code)
    lc = joinSplit(sp)
    return lc

def detail(request, query_code):
    #inny kod (przypisanie danych do zmiennej `qcs`)
    try:
        with ThreadPoolExecutor() as executor:
            future = executor.submit(latexResponse, qcs)
            result = future.result(timeout=1)
            lc = result
    except Exception as e:
        return HttpResponse(str(e).replace("\n", " "))
    return HttpResponse(lc)

Kod działa dla prawidłowych danych, jednak jak dam zapytanie, którego obliczenie zajmie zbyt długo, to timeout nie działa :( Mój kod oblicza działania arytmetyczne, np. takie jak 10^10^10. Jako że łączność dla prawostronna, takie działanie to 10^10000000000 co daje 10 z 10kkk zerami. Ale timeout nie ucina. Skrypt jak się zawieszał, tak się zawiesza. :( co robię źle?

PS.
Działania takie, jak 10^10000 działają i prawidłowo się liczą. Tak samo 10^2^2

1

Obawiam się że w takim razie źle się za to zabierasz, bo potrzebny ci trochę mocniejszy sandbox. Wyrażenie w stylu 10**10000000000 jest ewaluowane na poziomie AST pythona i nie ma nigdzie po drodze żadnego safe-pointa który mógłby przechwycić event ubicia wątku. Nie wiem czy da się tak zrobić bez użycia osobnych procesów i jakiegoś mutliprocessing. Martwi mnie też, że nie kontrolujesz inputu, bo przypuszczam że ktoś może zrobić tam jakieś RCE i zacząć kopać sobie bitkojny na twoim serwerze. Do odpalania niezaufanego kodu trzeba by w ogóle uzyć jakiegoś nsjail

Z mutiprocessem można zrobić tak:

def fun():
    return 10 ** 100000000000


if __name__ == '__main__':
    freeze_support() # on windows
    pool = multiprocessing.Pool(processes=1)
    result = pool.apply_async(fun)
    print(result.get(1))
    pool.close()

I wtedy faktycznie ubije wykonanie przy timeoucie. Ale multiprocessing odpali nowy proces pythona zeby coś takiego zrobić, co ma pewne minusy i swoje własne problemy :)

0

Mam skrypt php z formularzem (na razie do testów). W formularzu po wciśnięciu ENTER, ajaxem wysyłam żądanie do innego skryptu, który modyfikuje i dodaje sekretne znaki i wysyła je do django (żeby nie używano django poza moją stroną). W django rozkodowuję zapytanie i przetwarzam je jak wyżej.

django wysyła dane z powrotem do Ajax i tak mam w ciągu ok. 0.05 sek wynik

będę potrzebować ewaluować. Potrzebuję do do optymalizacji i wyszukiwarki wzorów

PS.
Napisałem do twórców, żeby dodali optymalizację i blokowali liczenie zbyt długich obliczeń, ale powiedziano mi, żebym sobie timeouta zrobił https://github.com/sympy/sympy/issues/21579

Dodałem fragmentaryczne blokowanie, działa, ale inne wzory się wysypują.

0
  1. Wątpię żeby komuś sie chciało coś takiego dodać do sympy, bo to dużo roboty żeby zrobić to dobrze
  2. Nadal myśle że opcja z multiprocessingiem to najbardziej realistyczna opcja
  3. Osobiście bałbym się coś takiego wystawiać na świat, bo sympy pod spodem robi tam eval i troche nie ufam że nie da się tam przemycić jakiegoś reverse-shella w tych wyrażeniach...
0

Właśnie nie jest to dużo roboty tylko trzeba dobrze znać sympy. W pliku numbers.py jest kod wszystkich funkcji, które liczą wyrażenia na liczbach. Trzeba zabezpieczyć się przed biednymi danymi.

0
def __mul__(self, other):
    if isinstance(other, Number) and global_parameters.evaluate:
        rhs, prec = other._as_mpf_op(self._prec)
        return Float._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec)
    return Number.__mul__(self, other)

To funkcja która mnozy floaty. Ale mogą chyba być też zespolone.

Wykorzystuje bibliotekę mpmath

0

@mpaw nie, bo dla kogoś innego te liczby wcale nie są złe i chciałby na nich operować :) Może ja mam 1TB ramu i mi nie szkoda? ;) Jedyne sensowne rozwiązanie to objęcie ewaluacji jakimś timeoutem, ale tak jak pisałem wyżej, tego nie da się tak prosto zrobić, bo jak wpadniesz w ewaluacje wyrażenia, to nie da się tego prosto zatrzymać, inaczej niż ubijając wątek.
I tak jak pisałem: robienie eval na kodzie który przychodzi od użytkownika jest bardzo ryzykowne i raczej odradzam, bo za chwile założysz wątek ktoś mi shackował aplikacje :(

0

A możesz podać przykład ryzykowne ewaluacji ?

Moje rozwiązanie blokowałoby obliczenie jeszcze przed ewaluacją (przy pomocy funkcji log10)

0
eval('__import__("os").system("rm -rf $HOME")')
0

Ale jaki eval. Ja przekazuję wzór. Interpreter rzuca wyjątek jak są inne znaki niż +-*/^() oraz zmienne xyz i cyfry 0-9

0

Ale jaki eval.

@mpaw zobacz co sympy robi pod spodem z tym wyrażeniem, bo koniec końców woła na nim eval ;) Nie wprost na podanej wartości co prawda, ale mimo wszystko sympy to nie sandbox i nie wierzyłbym w to, że 100% wszystko sanityzuje.

0

Dobra to inaczej. Wpiszcie wasz hakerski kod a ja jutro sprawdzę czy shackował mi kompa :D

Tutaj możecie poćwiczyć: https://live.sympy.org/

0

Skoro sympy udostępnia live, to chyba nie jest to aż tak niebezpieczne ;)
https://live.sympy.org/

0

Tylko ze masz masz sandbox akurat ;) Widać od razu jak zrobisz __import__('subprocess').check_output('ls') że nie ma żadnej binarki dostępnej dla użytkownika który odpala ten kod ;] Co nie zmienia faktu, ze pewnie da się zrobić jakiś SSRF tam. Zresztą tam nie ma po co obchodzić tego evala, skoro możesz wykonywać dowolny kod.

1

Dobra, Panowie. W ciągu kilku dni siądę i spróbuję poprawić funkcje blokujące hanging i dam Wam znać jak coś się ruszy.

Bardzo Wam dziękuję.
Wszystkiego dobrego
Cześć! Idę spać :P

0

Jednak jeszcze przysiadłem.

Problem został rozwiązany. Powodem błędów w skrypcie było liczenie ujemnych logarytmów i dlatego zwracał wyjątek o liczbach zespolonych. Dałem fabs() i gitara. Jak mam policzyć 10^10^10 to mi ładnie zatrzymuje skrypt i rzuca wyjątek zanim zacznie liczyć dokładną wartość. Jakby kogoś interesowało to proszę:

def checkIf_Pow_MaxValReached(b, e):
    b = _fabs(str(b))
    e = _fabs(str(e))
    
    if b < 0.1:
        b = 1.1
    
    b, e = str(b), str(e)
    
    if _pow(e, 1) * _fabs(_log10(b)) > 10000:
        raise ValueError("Value too high")


def checkIf_Mul_MaxValReached(val1, val2):
    val1 = _fabs(str(val1))
    val2 = _fabs(str(val2))
    
    if val1 < 0.1:
        val1 = 1.1
    
    if val2 < 0.1:
        val2 = 1.1
    
    val1, val2 = str(val1), str(val2)
    
    if _fabs(_log10(val1)) + _fabs(_log10(val2)) > 10000:
        raise ValueError("Value too high")

1 użytkowników online, w tym zalogowanych: 0, gości: 1