source: subversion/sites/tile.openstreetmap.org/cgi-bin/export @ 19818

Last change on this file since 19818 was 16117, checked in by jonb, 11 years ago

Reject /export requests if the load average on tile is too high

  • Property svn:executable set to *
File size: 4.4 KB
Line 
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4import cairo
5import cgi
6import mapnik
7import os
8import shutil
9import sys
10import tempfile
11import resource
12
13# Limit maximum CPU time
14# The Postscript output format can sometimes take hours
15resource.setrlimit(resource.RLIMIT_CPU,(300,300))
16
17# Limit memory usage
18# Some odd requests can cause extreme memory usage
19resource.setrlimit(resource.RLIMIT_AS,(4000000000, 4000000000))
20
21# Routine to output HTTP headers
22def output_headers(content_type, filename = "", length = 0):
23  print "Content-Type: %s" % content_type
24  if filename:
25    print "Content-Disposition: attachment; filename=\"%s\"" % filename
26  if length:
27    print "Content-Length: %d" % length
28  print ""
29
30# Routine to output the contents of a file
31def output_file(file):
32  file.seek(0)
33  shutil.copyfileobj(file, sys.stdout)
34
35# Routine to get the size of a file
36def file_size(file):
37  return os.fstat(file.fileno()).st_size
38
39# Routine to report an error
40def output_error(message):
41  output_headers("text/html")
42  print "<html>"
43  print "<head>"
44  print "<title>Error</title>"
45  print "</head>"
46  print "<body>"
47  print "<h1>Error</h1>"
48  print "<p>%s</p>" % message
49  print "</body>"
50  print "</html>"
51
52# Parse CGI parameters
53form = cgi.FieldStorage()
54
55# Abort if the load average on the machine is too high
56loadavg = float(open("/proc/loadavg").readline().split(" ")[0])
57if loadavg > 40.0:
58  print "Status: 503 Service Unavailable"
59  output_error("The load average on the server is too high at the moment. Please wait a few minutes before trying again.")
60 
61# Validate the parameters
62elif not form.has_key("bbox"):
63  # No bounding box specified
64  output_error("No bounding box specified")
65elif not form.has_key("scale"):
66  # No scale specified
67  output_error("No scale specified")
68elif not form.has_key("format"):
69  # No format specified
70  output_error("No format specified")
71else:
72  # Create projection object
73  prj = mapnik.Projection("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over");
74
75  # Get the bounds of the area to render
76  bbox = [float(x) for x in form.getvalue("bbox").split(",")]
77
78  if bbox[0] >= bbox[2] or bbox[1] >= bbox[3]:
79    # Bogus bounding box
80    output_error("Invalid bounding box")
81  else:
82    # Project the bounds to the map projection
83    bbox = mapnik.forward_(mapnik.Envelope(*bbox), prj)
84
85    # Calculate the size of the final rendered image
86    scale = float(form.getvalue("scale"))
87    width = int(bbox.width() / scale / 0.00028)
88    height = int(bbox.height() / scale / 0.00028)
89
90    # Limit the size of map we are prepared to produce
91    if width * height > 4000000:
92      # Map is too large (limit is approximately A2 size)
93      output_error("Map too large")
94    else:
95      # Create map
96      map = mapnik.Map(width, height)
97
98      # Load map configuration
99      mapnik.load_map(map, "/home/jburgess/live/osm.xml")
100
101      # Zoom the map to the bounding box
102      map.zoom_to_box(bbox)
103
104      # Render the map
105      if form.getvalue("format") == "png":
106        image = mapnik.Image(map.width, map.height)
107        mapnik.render(map, image)
108        png = image.tostring("png") 
109        output_headers("image/png", "map.png", len(png))
110        print png
111      elif form.getvalue("format") == "jpeg":
112        image = mapnik.Image(map.width, map.height)
113        mapnik.render(map, image)
114        jpeg = image.tostring("jpeg") 
115        output_headers("image/jpeg", "map.jpg", len(jpeg))
116        print jpeg
117      elif form.getvalue("format") == "svg":
118        file = tempfile.NamedTemporaryFile()
119        surface = cairo.SVGSurface(file.name, map.width, map.height)
120        mapnik.render(map, surface)
121        surface.finish()
122        output_headers("image/svg+xml", "map.svg", file_size(file))
123        output_file(file)
124      elif form.getvalue("format") == "pdf":
125        file = tempfile.NamedTemporaryFile()
126        surface = cairo.PDFSurface(file.name, map.width, map.height)
127        mapnik.render(map, surface)
128        surface.finish()
129        output_headers("application/pdf", "map.pdf", file_size(file))
130        output_file(file)
131      elif form.getvalue("format") == "ps":
132        file = tempfile.NamedTemporaryFile()
133        surface = cairo.PSSurface(file.name, map.width, map.height)
134        mapnik.render(map, surface)
135        surface.finish()
136        output_headers("application/postscript", "map.ps", file_size(file))
137        output_file(file)
138      else:
139        output_error("Unknown format '%s'" % form.getvalue("format"))
Note: See TracBrowser for help on using the repository browser.