您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

201 行
5.5 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  3. # MIT License. See license.txt
  4. from __future__ import unicode_literals
  5. import os
  6. import MySQLdb
  7. from werkzeug.wrappers import Request
  8. from werkzeug.local import LocalManager
  9. from werkzeug.exceptions import HTTPException, NotFound
  10. from werkzeug.contrib.profiler import ProfilerMiddleware
  11. from werkzeug.wsgi import SharedDataMiddleware
  12. from werkzeug.serving import run_with_reloader
  13. import frappe
  14. import frappe.handler
  15. import frappe.auth
  16. import frappe.api
  17. import frappe.async
  18. import frappe.utils.response
  19. import frappe.website.render
  20. from frappe.utils import get_site_name, get_site_path
  21. from frappe.middlewares import StaticDataMiddleware
  22. from frappe.utils.error import make_error_snapshot
  23. from frappe.core.doctype.communication.comment import update_comments_in_parent_after_request
  24. local_manager = LocalManager([frappe.local])
  25. _site = None
  26. _sites_path = os.environ.get("SITES_PATH", ".")
  27. class RequestContext(object):
  28. def __init__(self, environ):
  29. self.request = Request(environ)
  30. def __enter__(self):
  31. init_request(self.request)
  32. def __exit__(self, type, value, traceback):
  33. frappe.destroy()
  34. @Request.application
  35. def application(request):
  36. response = None
  37. try:
  38. rollback = True
  39. init_request(request)
  40. if frappe.local.form_dict.cmd:
  41. response = frappe.handler.handle()
  42. elif frappe.request.path.startswith("/api/"):
  43. response = frappe.api.handle()
  44. elif frappe.request.path.startswith('/backups'):
  45. response = frappe.utils.response.download_backup(request.path)
  46. elif frappe.request.path.startswith('/private/files/'):
  47. response = frappe.utils.response.download_private_file(request.path)
  48. elif frappe.local.request.method in ('GET', 'HEAD'):
  49. response = frappe.website.render.render(request.path)
  50. else:
  51. raise NotFound
  52. except HTTPException, e:
  53. frappe.logger().error('Request Error', exc_info=True)
  54. return e
  55. except frappe.SessionStopped, e:
  56. response = frappe.utils.response.handle_session_stopped()
  57. except Exception, e:
  58. response = handle_exception(e)
  59. else:
  60. rollback = after_request(rollback)
  61. finally:
  62. if frappe.local.request.method in ("POST", "PUT") and frappe.db and rollback:
  63. frappe.db.rollback()
  64. # set cookies
  65. if response and hasattr(frappe.local, 'cookie_manager'):
  66. frappe.local.cookie_manager.flush_cookies(response=response)
  67. frappe.destroy()
  68. return response
  69. def init_request(request):
  70. frappe.local.request = request
  71. frappe.local.is_ajax = frappe.get_request_header("X-Requested-With")=="XMLHttpRequest"
  72. site = _site or request.headers.get('X-Frappe-Site-Name') or get_site_name(request.host)
  73. frappe.init(site=site, sites_path=_sites_path)
  74. if not (frappe.local.conf and frappe.local.conf.db_name):
  75. # site does not exist
  76. raise NotFound
  77. if frappe.local.conf.get('maintenance_mode'):
  78. raise frappe.SessionStopped
  79. make_form_dict(request)
  80. frappe.local.http_request = frappe.auth.HTTPRequest()
  81. def make_form_dict(request):
  82. frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
  83. for k, v in (request.form or request.args).iteritems() })
  84. if "_" in frappe.local.form_dict:
  85. # _ is passed by $.ajax so that the request is not cached by the browser. So, remove _ from form_dict
  86. frappe.local.form_dict.pop("_")
  87. def handle_exception(e):
  88. http_status_code = getattr(e, "http_status_code", 500)
  89. if (http_status_code==500
  90. and isinstance(e, MySQLdb.OperationalError)
  91. and e.args[0] in (1205, 1213)):
  92. # 1205 = lock wait timeout
  93. # 1213 = deadlock
  94. # code 409 represents conflict
  95. http_status_code = 508
  96. if frappe.local.is_ajax or 'application/json' in frappe.local.request.headers.get('Accept', ''):
  97. response = frappe.utils.response.report_error(http_status_code)
  98. else:
  99. traceback = "<pre>"+frappe.get_traceback()+"</pre>"
  100. if frappe.local.flags.disable_traceback:
  101. traceback = ""
  102. frappe.respond_as_web_page("Server Error",
  103. traceback,
  104. http_status_code=http_status_code)
  105. response = frappe.website.render.render("message", http_status_code=http_status_code)
  106. if e.__class__ == frappe.AuthenticationError:
  107. if hasattr(frappe.local, "login_manager"):
  108. frappe.local.login_manager.clear_cookies()
  109. if http_status_code >= 500:
  110. frappe.logger().error('Request Error', exc_info=True)
  111. make_error_snapshot(e)
  112. return response
  113. def after_request(rollback):
  114. if (frappe.local.request.method in ("POST", "PUT") or frappe.local.flags.commit) and frappe.db:
  115. if frappe.db.transaction_writes:
  116. frappe.db.commit()
  117. rollback = False
  118. # update session
  119. if getattr(frappe.local, "session_obj", None):
  120. updated_in_db = frappe.local.session_obj.update()
  121. if updated_in_db:
  122. frappe.db.commit()
  123. rollback = False
  124. update_comments_in_parent_after_request()
  125. return rollback
  126. application = local_manager.make_middleware(application)
  127. def serve(port=8000, profile=False, site=None, sites_path='.'):
  128. global application, _site, _sites_path
  129. _site = site
  130. _sites_path = sites_path
  131. from werkzeug.serving import run_simple
  132. if profile:
  133. application = ProfilerMiddleware(application, sort_by=('tottime', 'calls'))
  134. if not os.environ.get('NO_STATICS'):
  135. application = SharedDataMiddleware(application, {
  136. b'/assets': os.path.join(sites_path, 'assets').encode("utf-8"),
  137. })
  138. application = StaticDataMiddleware(application, {
  139. b'/files': os.path.abspath(sites_path).encode("utf-8")
  140. })
  141. application.debug = True
  142. application.config = {
  143. 'SERVER_NAME': 'localhost:8000'
  144. }
  145. run_simple('0.0.0.0', int(port), application, use_reloader=True,
  146. use_debugger=True, use_evalex=True, threaded=True)