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.
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.
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)
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.
@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
@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 :(
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ć.
@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()
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
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 :)
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ą.
eval
i troche nie ufam że nie da się tam przemycić jakiegoś reverse-shella w tych wyrażeniach...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.
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
@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 :(
A możesz podać przykład ryzykowne ewaluacji ?
Moje rozwiązanie blokowałoby obliczenie jeszcze przed ewaluacją (przy pomocy funkcji log10
)
eval('__import__("os").system("rm -rf $HOME")')
Ale jaki eval. Ja przekazuję wzór. Interpreter rzuca wyjątek jak są inne znaki niż +-*/^() oraz zmienne xyz i cyfry 0-9
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.
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/
Skoro sympy udostępnia live, to chyba nie jest to aż tak niebezpieczne ;)
https://live.sympy.org/
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.
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
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")