Repository: LMFDB/lmfdb

Issue:
Limit download_qexp requests for elliptic curves
Requests like

https://www.lmfdb.org/EllipticCurve/Q/download_qexp/37.a1/9000000

(which showed up in the flasklog) put a heavy CPU load on the server and eventually lead to a 502.  I suggest capping these at 10^5.


Discussion:
I would be even harsher. This is *not* a download of stored data (we only store ap for p<100) but a request to compute ap.  It should probably be disabled.  Anyone in a position to use these ap would easily be able to compute them.
@JohnCremona I think we want to keep the download q-exp link, which gives the first 1000 an.  We could just remove the bound and always make it give 1000, but this would be less than the number we provide for the corresponding modular forms for N up to 10000 (we provide 3000), which seems a little weird.  For CMFs we always provide at least 30*sqrt(N), which matches the number of a_n we use when computing the L-function.  Allowing up to 10^5 would be well above this and still takes less time than it takes to render the page.
OK fair enough -- but then can we open a new issue to increase the number if ap and an stored?
I think this is the rare case where I would argue that its OK to compute them on the fly, since we are never searching on them and it can be done quickly and reliably.  @edgarcosta do you have an opinion about this?
I agree with you.
Indeed, is impressive how fast we return
https://www.lmfdb.org/EllipticCurve/Q/download_qexp/37.a1/10000

On Thu, Oct 29, 2020 at 5:17 AM Andrew Sutherland <notifications@github.com>
wrote:

> I think this is the rare case where I would argue that its OK to compute
> them on the fly, since we are never searching on them and it can be done
> quickly and reliably. @edgarcosta <https://github.com/edgarcosta> do you
> have an opinion about this?
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/LMFDB/lmfdb/issues/4194#issuecomment-718523002>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AACO2BTYBT3SEUMWSICHJJLSNEXILANCNFSM4TCER4WA>
> .
>

I submit! With the sensible cap of course.

Resolving patch:
diff --git a/lmfdb/elliptic_curves/elliptic_curve.py b/lmfdb/elliptic_curves/elliptic_curve.py
--- a/lmfdb/elliptic_curves/elliptic_curve.py
+++ b/lmfdb/elliptic_curves/elliptic_curve.py
@@ -585,13 +585,15 @@ def padic_data():
     return render_template("ec-padic-data.html", info=info)
 
 
-@ec_page.route("/download_qexp/<label>/<limit>")
+@ec_page.route("/download_qexp/<label>/<int:limit>")
 def download_EC_qexp(label, limit):
     N, iso, number = split_lmfdb_label(label)
     if number:
         ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_label')
     else:
         ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_iso')
+    if limit > 100000:
+        return redirect(url_for('.download_EC_qexp',label=label,limit=10000), 301)
     E = EllipticCurve(ainvs)
     response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True)))
     response.headers['Content-type'] = 'text/plain'
diff --git a/lmfdb/lfunctions/main.py b/lmfdb/lfunctions/main.py
--- a/lmfdb/lfunctions/main.py
+++ b/lmfdb/lfunctions/main.py
@@ -417,13 +417,13 @@ def l_function_hgm_page(label,t):
     return render_single_Lfunction(HypergeometricMotiveLfunction, args, request)
 
 # L-function of symmetric powers of Elliptic curve #############################
-@l_function_page.route("/SymmetricPower/<power>/EllipticCurve/Q/<conductor>/<isogeny>/")
+@l_function_page.route("/SymmetricPower/<int:power>/EllipticCurve/Q/<int:conductor>/<isogeny>/")
 def l_function_ec_sym_page(power, conductor, isogeny):
     args = {'power': power, 'underlying_type': 'EllipticCurve', 'field': 'Q',
             'conductor': conductor, 'isogeny': isogeny}
     return render_single_Lfunction(SymmetricPowerLfunction, args, request)
 
-@l_function_page.route("/SymmetricPower/<power>/EllipticCurve/Q/<label>/")
+@l_function_page.route("/SymmetricPower/<int:power>/EllipticCurve/Q/<label>/")
 def l_function_ec_sym_page_label(power, label):
     conductor, isogeny = getConductorIsogenyFromLabel(label)
     if conductor and isogeny:
@@ -797,24 +797,42 @@ def zerosLfunction(args):
 @l_function_page.route("/download_euler/<path:args>/")
 def download_euler(args):
     args = tuple(args.split('/'))
-    return generateLfunctionFromUrl(*args).download_euler_factors()
+    try:
+        L = generateLfunctionFromURL(*args)
+        assert L
+    except:
+        return abort(404)
+    return L.download_euler_factors()
 
 @l_function_page.route("/download_zeros/<path:args>/")
 def download_zeros(args):
     args = tuple(args.split('/'))
-    return generateLfunctionFromUrl(*args).download_zeros()
+    try:
+        L = generateLfunctionFromURL(*args)
+        assert L
+    except:
+        return abort(404)
+    return L.download_zeroes()
 
 @l_function_page.route("/download_dirichlet_coeff/<path:args>/")
 def download_dirichlet_coeff(args):
     args = tuple(args.split('/'))
-    return generateLfunctionFromUrl(*args).download_dirichlet_coeff()
+    try:
+        L = generateLfunctionFromURL(*args)
+        assert L
+    except:
+        return abort(404)
+    return L.download_dirichlet_coeff()
 
 @l_function_page.route("/download/<path:args>/")
 def download(args):
     args = tuple(args.split('/'))
-    return generateLfunctionFromUrl(*args).download()
-
-
+    try:
+        L = generateLfunctionFromURL(*args)
+        assert L
+    except:
+        return abort(404)
+    return L.download()
 
 
 ################################################################################
@@ -838,9 +856,12 @@ def render_plotLfunction(request, *args):
 
 
 def getLfunctionPlot(request, *args):
-    pythonL = generateLfunctionFromUrl(*args, **to_dict(request.args))
-    if not pythonL:
+    try:
+        pythonL = generateLfunctionFromUrl(*args, **to_dict(request.args))
+        assert pythonL
+    except:
         return ""
+
     plotrange = 30
     if hasattr(pythonL, 'plotpoints'):
         F = p2sage(pythonL.plotpoints)
@@ -896,9 +917,7 @@ def render_zerosLfunction(request, *args):
     try:
         L = generateLfunctionFromUrl(*args, **to_dict(request.args))
     except Exception as err:
-        raise
-        if not is_debug_mode():
-            return render_lfunction_exception(err)
+        return render_lfunction_exception(err)
 
     if not L:
         return abort(404)
@@ -1248,7 +1267,11 @@ def processSymPowerEllipticCurveNavigation(startCond, endCond, power):
 def reliability(prepath):
     t = 'Reliability of L-function data'
     args = tuple(prepath.split('/'))
-    L = generateLfunctionFromUrl(*args)
+    try:
+        L = generateLfunctionFromUrl(*args)
+        assert L
+    except:
+        return abort(404)
     info={'bread': ()}
     set_bread_and_friends(info, L, request)
     if L.fromDB:
@@ -1277,7 +1300,11 @@ def completeness():
 def source(prepath):
     t = 'Source of L-function data'
     args = tuple(prepath.split('/'))
-    L = generateLfunctionFromUrl(*args)
+    try:
+        L = generateLfunctionFromUrl(*args)
+        assert L
+    except:
+        return abort(404)
     info={'bread': ()}
     set_bread_and_friends(info, L, request)
     if L.fromDB:


Test patch: