def f(_action=action, _self=self, *a, **b): self.is_restful = True method = _self.env.request_method if len(_self.args) and '.' in _self.args[-1]: _self.args[-1], _self.extension = _self.args[-1].rsplit( '.', 1) current.response.headers['Content-Type'] = \ contenttype(_self.extension.lower()) if not method in ['GET', 'POST', 'DELETE', 'PUT']: raise HTTP(400, "invalid method") rest_action = _action().get(method, None) if not rest_action: raise HTTP(400, "method not supported") try: return rest_action(*_self.args, **_self.vars) except TypeError, e: exc_type, exc_value, exc_traceback = sys.exc_info() if len(traceback.extract_tb(exc_traceback)) == 1: raise HTTP(400, "invalid arguments") else: raise e
def callback(self): if self.keyword in self.request.vars: field = self.fields[0] rows = self.db(field.like(self.request.vars[self.keyword]+'%'))\ .select(orderby=self.orderby,limitby=self.limitby,*self.fields) if rows: if self.is_reference: id_field = self.fields[1] raise HTTP(200,SELECT(_id=self.keyword,_class='autocomplete', _size=len(rows),_multiple=(len(rows)==1), *[OPTION(s[field.name],_value=s[id_field.name], _selected=(k==0)) \ for k,s in enumerate(rows)]).xml()) else: raise HTTP(200,SELECT(_id=self.keyword,_class='autocomplete', _size=len(rows),_multiple=(len(rows)==1), *[OPTION(s[field.name], _selected=(k==0)) \ for k,s in enumerate(rows)]).xml()) else: raise HTTP(200, '')
def check_credentials(request, other_application='admin'): """ checks that user is authorized to access other_application""" if request.env.web2py_runtime_gae: from google.appengine.api import users if users.is_current_user_admin(): return True else: login_html = '<a href="%s">Sign in with your google account</a>.' \ % users.create_login_url(request.env.path_info) raise HTTP(200, '<html><body>%s</body></html>' % login_html) else: return get_session(request, other_application).authorized
def map_controller(self): "identify controller" # handle controller # arg0 = self.harg0 # map hyphens if not arg0 or (self.controllers and arg0 not in self.controllers): self.controller = self.default_controller or '' else: self.controller = arg0 self.pop_arg_if(arg0 == self.controller) log_rewrite("route: controller=%s" % self.controller) if not self.router._acfe_match.match(self.controller): raise HTTP(400, thread.routes.error_message % 'invalid request', web2py_error='invalid controller')
def download(self, request, db, chunk_size=DEFAULT_CHUNK_SIZE, attachment=True, download_filename=None): """ example of usage in controller:: def download(): return response.download(request, db) downloads from http://..../download/filename """ current.session.forget(current.response) if not request.args: raise HTTP(404) name = request.args[-1] items = re.compile('(?P<table>.*?)\.(?P<field>.*?)\..*')\ .match(name) if not items: raise HTTP(404) (t, f) = (items.group('table'), items.group('field')) try: field = db[t][f] except AttributeError: raise HTTP(404) try: (filename, stream) = field.retrieve(name,nameonly=True) except IOError: raise HTTP(404) headers = self.headers headers['Content-Type'] = contenttype(name) if download_filename == None: download_filename = filename if attachment: headers['Content-Disposition'] = \ 'attachment; filename="%s"' % download_filename.replace('"','\"') return self.stream(stream, chunk_size=chunk_size, request=request)
def __call__(self, i, default=None, cast=None, url_onerror=None): if 0<=i<len(self): value = self[i] else: value = default if cast: try: value = cast(value) except (ValueError, TypeError): from http import HTTP, redirect if url_onerror: redirect(url_onerror) else: raise HTTP(404) return value
def copystream_progress(request, chunk_size=10**5): """ copies request.env.wsgi_input into request.body and stores progress upload status in cache_ram X-Progress-ID:length and X-Progress-ID:uploaded """ env = request.env if not env.get('CONTENT_LENGTH', None): return cStringIO.StringIO() source = env['wsgi.input'] try: size = int(env['CONTENT_LENGTH']) except ValueError: raise HTTP(400, "Invalid Content-Length header") try: # Android requires this dest = tempfile.NamedTemporaryFile() except NotImplementedError: # and GAE this dest = tempfile.TemporaryFile() if not 'X-Progress-ID' in request.get_vars: copystream(source, dest, size, chunk_size) return dest cache_key = 'X-Progress-ID:' + request.get_vars['X-Progress-ID'] cache_ram = CacheInRam(request) # same as cache.ram because meta_storage cache_ram(cache_key + ':length', lambda: size, 0) cache_ram(cache_key + ':uploaded', lambda: 0, 0) while size > 0: if size < chunk_size: data = source.read(size) cache_ram.increment(cache_key + ':uploaded', size) else: data = source.read(chunk_size) cache_ram.increment(cache_key + ':uploaded', chunk_size) length = len(data) if length > size: (data, length) = (data[:size], size) size -= length if length == 0: break dest.write(data) if length < chunk_size: break dest.seek(0) cache_ram(cache_key + ':length', None) cache_ram(cache_key + ':uploaded', None) return dest
def serve_controller(request, response, session): """ this function is used to generate a dynamic page. It first runs all models, then runs the function in the controller, and then tries to render the output using a view/template. this function must run from the [application] folder. A typical example would be the call to the url /[application]/[controller]/[function] that would result in a call to [function]() in applications/[application]/[controller].py rendered by applications/[application]/views/[controller]/[function].html """ # ################################################## # build environment for controller and view # ################################################## environment = build_environment(request, response, session) # set default view, controller can override it response.view = '%s/%s.%s' % (request.controller, request.function, request.extension) # also, make sure the flash is passed through # ################################################## # process models, controller and view (if required) # ################################################## run_models_in(environment) response._view_environment = copy.copy(environment) page = run_controller_in(request.controller, request.function, environment) if isinstance(page, dict): response._vars = page for key in page: response._view_environment[key] = page[key] run_view_in(response._view_environment) page = response.body.getvalue() # logic to garbage collect after exec, not always, once every 100 requests global requests requests = ('requests' in globals()) and (requests+1) % 100 or 0 if not requests: gc.collect() # end garbage collection logic raise HTTP(response.status, page, **response.headers)
def __call__(self, i, default=DEFAULT, cast=None, otherwise=None): """Allows to use a special syntax for fast-check of `request.args()` validity. :params: i: index default: use this value if arg not found cast: type cast otherwise: will be executed when: - casts fail - value not found, dont have default and otherwise is especified can be: - None: results in a 404 - str: redirect to this address - callable: calls the function (nothing is passed) Example: You can use:: request.args(0,default=0,cast=int,otherwise='http://error_url') request.args(0,default=0,cast=int,otherwise=lambda:...) """ n = len(self) if 0 <= i < n or -n <= i < 0: value = self[i] elif default is DEFAULT: value = None else: value, cast, otherwise = default, False, False try: if cast: value = cast(value) if not value and otherwise: raise ValueError('Otherwise will raised.') except (ValueError, TypeError): from http import HTTP, redirect if otherwise is None: raise HTTP(404) elif isinstance(otherwise, str): redirect(otherwise) elif callable(otherwise): return otherwise() else: raise RuntimeError("invalid otherwise") return value
def check_credentials(request, other_application='admin', expiration=60 * 60, gae_login=True): """ checks that user is authorized to access other_application""" if request.env.web2py_runtime_gae: from google.appengine.api import users if users.is_current_user_admin(): return True elif gae_login: login_html = '<a href="%s">Sign in with your google account</a>.' \ % users.create_login_url(request.env.path_info) raise HTTP(200, '<html><body>%s</body></html>' % login_html) else: return False else: dt = time.time() - expiration s = get_session(request, other_application) return (s.authorized and s.last_time and s.last_time > dt)
def get_client(env): """ guess the client address from the environment variables first tries 'http_x_forwarded_for', secondly 'remote_addr' if all fails assume '127.0.0.1' (running locally) """ g = regex_client.search(env.get('http_x_forwarded_for', '')) if g: client = g.group() else: g = regex_client.search(env.get('remote_addr', '')) if g: client = g.group() else: client = '127.0.0.1' if not is_valid_ip_address(client): raise HTTP(400, "Bad Request (request.client=%s)" % client) return client
def try_rewrite_on_error(http_response, request, environ, ticket=None): """ called from main.wsgibase to rewrite the http response. """ status = int(str(http_response.status).split()[0]) if status >= 399 and thread.routes.routes_onerror: keys = set(('%s/%s' % (request.application, status), '%s/*' % (request.application), '*/%s' % (status), '*/*')) for (key, uri) in thread.routes.routes_onerror: if key in keys: if uri == '!': # do nothing! return http_response, environ elif '?' in uri: path_info, query_string = uri.split('?', 1) query_string += '&' else: path_info, query_string = uri, '' query_string += \ 'code=%s&ticket=%s&requested_uri=%s&request_url=%s' % \ (status,ticket,request.env.request_uri,request.url) if uri.startswith('http://') or uri.startswith('https://'): # make up a response url = path_info + '?' + query_string message = 'You are being redirected <a href="%s">here</a>' return HTTP(303, message % url, Location=url), environ else: error_raising_path = environ['PATH_INFO'] # Rewrite routes_onerror path. path_info = '/' + path_info.lstrip( '/') # add leading '/' if missing environ['PATH_INFO'] = path_info error_handling_path = url_in(request, environ)[1]['PATH_INFO'] # Avoid infinite loop. if error_handling_path != error_raising_path: # wsgibase will be called recursively with the routes_onerror path. environ['PATH_INFO'] = path_info environ['QUERY_STRING'] = query_string return None, environ # do nothing! return http_response, environ
def copystream_progress(request, chunk_size=10**5): """ copies request.env.wsgi_input into request.body and stores progress upload status in cache.ram X-Progress-ID:length and X-Progress-ID:uploaded """ env = request.env if not env.content_length: return cStringIO.StringIO() source = env.wsgi_input try: size = int(env.content_length) except ValueError: raise HTTP(400, "Invalid Content-Length header") dest = tempfile.TemporaryFile() if not 'X-Progress-ID' in request.vars: copystream(source, dest, size, chunk_size) return dest cache_key = 'X-Progress-ID:' + request.vars['X-Progress-ID'] cache = Cache(request) cache.ram(cache_key + ':length', lambda: size, 0) cache.ram(cache_key + ':uploaded', lambda: 0, 0) while size > 0: if size < chunk_size: data = source.read(size) cache.ram.increment(cache_key + ':uploaded', size) else: data = source.read(chunk_size) cache.ram.increment(cache_key + ':uploaded', chunk_size) length = len(data) if length > size: (data, length) = (data[:size], size) size -= length if length == 0: break dest.write(data) if length < chunk_size: break dest.seek(0) cache.ram(cache_key + ':length', None) cache.ram(cache_key + ':uploaded', None) return dest
def get_client(env): """ guess the client address from the environment variables first tries 'http_x_forwarded_for', secondly 'remote_addr' if all fails, assume '127.0.0.1' or '::1' (running locally) """ g = regex_client.search(env.get('http_x_forwarded_for', '')) client = (g.group() or '').split(',')[0] if g else None if client in (None, '', 'unknown'): g = regex_client.search(env.get('remote_addr', '')) if g: client = g.group() elif env.http_host.startswith('['): # IPv6 client = '::1' else: client = '127.0.0.1' # IPv4 if not is_valid_ip_address(client): raise HTTP(400, "Bad Request (request.client=%s)" % client) return client
def try_redirect_on_error(http_object, request, ticket=None): status = int(str(http_object.status).split()[0]) if status > 399 and params.routes_onerror: keys = set(('%s/%s' % (request.application, status), '%s/*' % (request.application), '*/%s' % (status), '*/*')) for (key, redir) in params.routes_onerror: if key in keys: if redir == '!': break elif '?' in redir: url = redir + '&' + 'code=%s&ticket=%s&requested_uri=%s' % ( status, ticket, request.env.request_uri) else: url = redir + '?' + 'code=%s&ticket=%s&requested_uri=%s' % ( status, ticket, request.env.request_uri) return HTTP(303, 'You are being redirected <a href="%s">here</a>' % url, Location=url) return http_object
def try_redirect_on_error(http_object, request, ticket=None): "called from main.wsgibase to rewrite the http response" status = int(str(http_object.status).split()[0]) if status > 399 and thread.routes.routes_onerror: keys = set(('%s/%s' % (request.application, status), '%s/*' % (request.application), '*/%s' % (status), '*/*')) for (key, redir) in thread.routes.routes_onerror: if key in keys: if redir == '!': break elif '?' in redir: url = '%s&code=%s&ticket=%s&requested_uri=%s&request_url=%s' % \ (redir,status,ticket,request.env.request_uri,request.url) else: url = '%s?code=%s&ticket=%s&requested_uri=%s&request_url=%s' % \ (redir,status,ticket,request.env.request_uri,request.url) return HTTP(303, 'You are being redirected <a href="%s">here</a>' % url, Location=url) return http_object
def stream_file_or_304_or_206( static_file, chunk_size=10**6, request=None, headers={}, error_message=error_message, ): if not os.path.exists(static_file): raise HTTP(404, error_message, web2py_error='invalid file') stat_file = os.stat(static_file) fsize = stat_file[stat.ST_SIZE] mtime = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stat_file[stat.ST_MTIME])) headers['Content-Type'] = contenttype(static_file) headers['Last-Modified'] = mtime headers['Pragma'] = 'cache' headers['Cache-Control'] = 'private' if request and request.env.http_if_modified_since == mtime: raise HTTP(304) elif request and request.env.http_range: start_items = regex_start_range.findall(request.env.http_range) if not start_items: start_items = [0] stop_items = regex_stop_range.findall(request.env.http_range) if not stop_items or int(stop_items[0]) > fsize - 1: stop_items = [fsize - 1] part = (int(start_items[0]), int(stop_items[0]), fsize) bytes = part[1] - part[0] + 1 try: stream = open(static_file, 'rb') except IOError: raise HTTP(404) stream.seek(part[0]) headers['Content-Range'] = 'bytes %i-%i/%i' % part headers['Content-Length'] = '%i' % bytes raise HTTP(206, streamer(stream, chunk_size=chunk_size, bytes=bytes), **headers) else: try: stream = open(static_file, 'rb') except IOError: raise HTTP(404) headers['Content-Length'] = fsize raise HTTP(200, streamer(stream, chunk_size=chunk_size), **headers)
def serve_controller(request, response, session): """ this function is used to generate a dynmaic page. It first runs all models, then runs the function in the controller, and then tries to render the output using a view/template. this function must run from the [applciation] folder. A typical examples would be the call to the url /[applicaiton]/[controller]/[function] that would result in a call to [function]() in applications/[application]/[controller].py renedred by applications/[application]/[controller]/[view].html """ # ################################################## # build evnironment for controller and view # ################################################## environment = build_environment(request, response, session) # set default view, controller can override it response.view = '%s/%s.html' % (request.controller, request.function) # also, make sure the flash is passed through # ################################################## # process models, controller and view (if required) # ################################################## run_models_in(environment) response._view_environment = copy.copy(environment) run_controller_in(request.controller, request.function, environment) if not type(response.body) in [types.StringType, types.GeneratorType]: for (key, value) in response._vars.items(): response._view_environment[key] = value run_view_in(response._view_environment) response.body = response.body.getvalue() raise HTTP(200, response.body, **response.headers)
def __call__(self, i, default=None, cast=None, otherwise=None): """ request.args(0,default=0,cast=int,otherwise='http://error_url') request.args(0,default=0,cast=int,otherwise=lambda:...) """ n = len(self) if 0 <= i < n or -n <= i < 0: value = self[i] else: value = default if cast: try: value = cast(value) except (ValueError, TypeError): from http import HTTP, redirect if otherwise is None: raise HTTP(404) elif isinstance(otherwise, str): redirect(otherwise) elif callable(otherwise): return otherwise() else: raise RuntimeError, "invalid otherwise" return value
raise HTTP(403, error_message, web2py_error='inaccessible file') else: raise HTTP(404, error_message, web2py_error='invalid file') else: fp.close() stat_file = os.stat(static_file) fsize = stat_file[stat.ST_SIZE] mtime = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stat_file[stat.ST_MTIME])) headers['Content-Type'] = contenttype(static_file) headers['Last-Modified'] = mtime headers['Pragma'] = 'cache' headers['Cache-Control'] = 'private' if request and request.env.http_if_modified_since == mtime: raise HTTP(304) elif request and request.env.http_range: start_items = regex_start_range.findall(request.env.http_range) if not start_items: start_items = [0] stop_items = regex_stop_range.findall(request.env.http_range) if not stop_items or int(stop_items[0]) > fsize - 1: stop_items = [fsize - 1] part = (int(start_items[0]), int(stop_items[0]), fsize) bytes = part[1] - part[0] + 1 try: stream = open(static_file, 'rb') except IOError, e: if e[0] in (errno.EISDIR, errno.EACCES): raise HTTP(403) else:
def __init__(self, table, record=None, deletable=False, linkto=None, upload=None, fields=None, labels=None, col3={}, submit_button='Submit', delete_label='Check to delete:', showid=True, readonly=False, comments=True, keepopts=[], ignore_rw=False, record_id=None, formstyle='table3cols', **attributes): """ SQLFORM(db.table, record=None, fields=['name'], labels={'name': 'Your name'}, linkto=URL(r=request, f='table/db/') """ self.ignore_rw = ignore_rw self.formstyle = formstyle nbsp = XML(' ') # Firefox2 does not display fields with blanks FORM.__init__(self, *[], **attributes) ofields = fields keyed = hasattr(table, '_primarykey') # if no fields are provided, build it from the provided table # will only use writable or readable fields, unless forced to ignore if fields == None: fields = [ f.name for f in table if (ignore_rw or f.writable or f.readable) and not f.compute ] self.fields = fields # make sure we have an id if self.fields[0] != table.fields[0] and \ isinstance(table,Table) and not keyed: self.fields.insert(0, table.fields[0]) self.table = table # try to retrieve the indicated record using its id # otherwise ignore it if record and isinstance(record, (int, long, str, unicode)): if not str(record).isdigit(): raise HTTP(404, "Object not found") record = table._db(table.id == record).select().first() if not record: raise HTTP(404, "Object not found") self.record = record self.record_id = record_id if keyed: if record: self.record_id = dict([(k, record[k]) for k in table._primarykey]) else: self.record_id = dict([(k, None) for k in table._primarykey]) self.field_parent = {} xfields = [] self.fields = fields self.custom = Storage() self.custom.dspval = Storage() self.custom.inpval = Storage() self.custom.label = Storage() self.custom.comment = Storage() self.custom.widget = Storage() self.custom.linkto = Storage() for fieldname in self.fields: if fieldname.find('.') >= 0: continue field = self.table[fieldname] comment = None if comments: comment = col3.get(fieldname, field.comment) if comment == None: comment = '' self.custom.comment[fieldname] = comment if labels != None and fieldname in labels: label = labels[fieldname] colon = '' else: label = field.label colon = ': ' self.custom.label[fieldname] = label field_id = '%s_%s' % (table._tablename, fieldname) label = LABEL(label, colon, _for=field_id, _id=field_id + SQLFORM.ID_LABEL_SUFFIX) row_id = field_id + SQLFORM.ID_ROW_SUFFIX if field.type == 'id': self.custom.dspval.id = nbsp self.custom.inpval.id = '' widget = '' if record: if showid and 'id' in fields and field.readable: v = record['id'] widget = SPAN(v, _id=field_id) self.custom.dspval.id = str(v) xfields.append((row_id, label, widget, comment)) self.record_id = str(record['id']) self.custom.widget.id = widget continue if readonly and not ignore_rw and not field.readable: continue if record: default = record[fieldname] else: default = field.default cond = readonly or \ (not ignore_rw and not field.writable and field.readable) if default and not cond: default = field.formatter(default) dspval = default inpval = default if cond: # ## if field.represent is available else # ## ignore blob and preview uploaded images # ## format everything else if field.represent: inp = field.represent(default) elif field.type in ['blob']: continue elif field.type == 'upload': inp = UploadWidget.represent(field, default, upload) else: inp = field.formatter(default) elif hasattr(field, 'widget') and field.widget: inp = field.widget(field, default) elif field.type == 'upload': inp = self.widgets.upload.widget(field, default, upload) elif field.type == 'boolean': inp = self.widgets.boolean.widget(field, default) if default: inpval = 'checked' else: inpval = '' elif OptionsWidget.has_options(field): if not field.requires.multiple: inp = self.widgets.options.widget(field, default) else: inp = self.widgets.multiple.widget(field, default) if fieldname in keepopts: inpval = TAG[''](*inp.components) elif str(field.type).startswith('list'): inp = self.widgets.list.widget(field, default) elif field.type == 'text': inp = self.widgets.text.widget(field, default) elif field.type == 'password': inp = self.widgets.password.widget(field, default) if self.record: dspval = PasswordWidget.DEFAULT_PASSWORD_DISPLAY else: dspval = '' elif field.type == 'blob': continue else: inp = self.widgets.string.widget(field, default) xfields.append((row_id, label, inp, comment)) self.custom.dspval[fieldname] = dspval or nbsp self.custom.inpval[fieldname] = inpval or '' self.custom.widget[fieldname] = inp # if a record is provided and found, as is linkto # build a link if record and linkto: for (rtable, rfield) in table._referenced_by: if keyed: rfld = table._db[rtable][rfield] query = urllib.quote( str(rfld == record[rfld.type[10:].split('.')[1]])) else: # <block> query = urllib.quote( str(table._db[rtable][rfield] == record.id)) lname = olname = '%s.%s' % (rtable, rfield) if ofields and not olname in ofields: continue if labels and lname in labels: lname = labels[lname] widget = A(lname, _class='reference', _href='%s/%s?query=%s' % (linkto, rtable, query)) xfields.append( (olname.replace('.', '__') + SQLFORM.ID_ROW_SUFFIX, '', widget, col3.get(olname, ''))) self.custom.linkto[olname.replace('.', '__')] = widget # </block> # when deletable, add delete? checkbox self.custom.deletable = '' if record and deletable: widget = INPUT( _type='checkbox', _class='delete', _id=self.FIELDKEY_DELETE_RECORD, _name=self.FIELDNAME_REQUEST_DELETE, ) xfields.append( (self.FIELDKEY_DELETE_RECORD + SQLFORM.ID_ROW_SUFFIX, LABEL(delete_label, _for=self.FIELDKEY_DELETE_RECORD, _id=self.FIELDKEY_DELETE_RECORD + SQLFORM.ID_LABEL_SUFFIX), widget, col3.get(self.FIELDKEY_DELETE_RECORD, ''))) self.custom.deletable = widget # when writable, add submit button self.custom.submit = '' if not readonly: widget = INPUT(_type='submit', _value=submit_button) xfields.append( ('submit_record' + SQLFORM.ID_ROW_SUFFIX, '', widget, col3.get('submit_button', ''))) self.custom.submit = widget # if a record is provided and found # make sure it's id is stored in the form if record: if not self['hidden']: self['hidden'] = {} if not keyed: self['hidden']['id'] = record['id'] (begin, end) = self._xml() self.custom.begin = XML("<%s %s>" % (self.tag, begin)) self.custom.end = XML("%s</%s>" % (end, self.tag)) if formstyle == 'table3cols': table = TABLE() for id, a, b, c in xfields: td_b = self.field_parent[id] = TD(b, _class='w2p_fw') table.append( TR(TD(a, _class='w2p_fl'), td_b, TD(c, _class='w2p_fc'), _id=id)) elif formstyle == 'table2cols': table = TABLE() for id, a, b, c in xfields: td_b = self.field_parent[id] = TD(b, _class='w2p_fw', _colspan="2") table.append( TR(TD(a, _class='w2p_fl'), TD(c, _class='w2p_fc'), _id=id + '1', _class='even')) table.append(TR(td_b, _id=id + '2', _class='odd')) elif formstyle == 'divs': table = TAG['']() for id, a, b, c in xfields: div_b = self.field_parent[id] = DIV(b, _class='w2p_fw') table.append( DIV(DIV(a, _class='w2p_fl'), div_b, DIV(c, _class='w2p_fc'), _id=id)) elif formstyle == 'ul': table = UL() for id, a, b, c in xfields: div_b = self.field_parent[id] = DIV(b, _class='w2p_fw') table.append( LI(DIV(a, _class='w2p_fl'), div_b, DIV(c, _class='w2p_fc'), _id=id)) elif type(formstyle) == type(lambda: None): table = TABLE() for id, a, b, c in xfields: td_b = self.field_parent[id] = TD(b, _class='w2p_fw') newrows = formstyle(id, a, td_b, c) if type(newrows).__name__ != "tuple": newrows = [newrows] for newrow in newrows: table.append(newrow) else: raise RuntimeError, 'formsyle not supported' self.components = [table]
def parse_get_post_vars(request, environ): # always parse variables in URL for GET, POST, PUT, DELETE, etc. in get_vars env = request.env dget = cgi.parse_qsl(env.query_string or '', keep_blank_values=1) for (key, value) in dget: if key in request.get_vars: if isinstance(request.get_vars[key], list): request.get_vars[key] += [value] else: request.get_vars[key] = [request.get_vars[key]] + [value] else: request.get_vars[key] = value request.vars[key] = request.get_vars[key] # parse POST variables on POST, PUT, BOTH only in post_vars try: request.body = body = copystream_progress(request) except IOError: raise HTTP(400, "Bad Request - HTTP body is incomplete") if (body and env.request_method in ('POST', 'PUT', 'BOTH')): dpost = cgi.FieldStorage(fp=body, environ=environ, keep_blank_values=1) # The same detection used by FieldStorage to detect multipart POSTs is_multipart = dpost.type[:10] == 'multipart/' body.seek(0) isle25 = sys.version_info[1] <= 5 def listify(a): return (not isinstance(a, list) and [a]) or a try: keys = sorted(dpost) except TypeError: keys = [] for key in keys: if key is None: continue # not sure why cgi.FieldStorage returns None key dpk = dpost[key] # if en element is not a file replace it with its value else leave it alone if isinstance(dpk, list): value = [] for _dpk in dpk: if not _dpk.filename: value.append(_dpk.value) else: value.append(_dpk) elif not dpk.filename: value = dpk.value else: value = dpk pvalue = listify(value) if key in request.vars: gvalue = listify(request.vars[key]) if isle25: value = pvalue + gvalue elif is_multipart: pvalue = pvalue[len(gvalue):] else: pvalue = pvalue[:-len(gvalue)] request.vars[key] = value if len(pvalue): request.post_vars[key] = (len(pvalue) > 1 and pvalue) or pvalue[0]
def run_view_in(environment): """ Executes the view for the requested action. The view is the one specified in `response.view` or determined by the url or `view/generic.extension` It tries the pre-compiled views_controller_function.pyc before compiling it. """ request = environment['request'] response = environment['response'] view = response.view folder = request.folder path = pjoin(folder, 'compiled') badv = 'invalid view (%s)' % view if response.generic_patterns: patterns = response.generic_patterns regex = re_compile('|'.join(map(fnmatch.translate, patterns))) short_action = '%(controller)s/%(function)s.%(extension)s' % request allow_generic = regex.search(short_action) else: allow_generic = False if not isinstance(view, str): ccode = parse_template(view, pjoin(folder, 'views'), context=environment) restricted(ccode, environment, 'file stream') elif os.path.exists(path): x = view.replace('/', '_') files = ['views_%s.pyc' % x] if allow_generic: files.append('views_generic.%s.pyc' % request.extension) # for backward compatibility if request.extension == 'html': files.append('views_%s.pyc' % x[:-5]) if allow_generic: files.append('views_generic.pyc') # end backward compatibility code for f in files: filename = pjoin(path,f) if os.path.exists(filename): code = read_pyc(filename) restricted(code, environment, layer=filename) return raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badv, web2py_error=badv) else: filename = pjoin(folder, 'views', view) if not os.path.exists(filename) and allow_generic: view = 'generic.' + request.extension filename = pjoin(folder, 'views', view) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badv, web2py_error=badv) layer = filename if is_gae: ccode = getcfs(layer, filename, lambda: compile2(parse_template(view, pjoin(folder, 'views'), context=environment),layer)) else: ccode = parse_template(view, pjoin(folder, 'views'), context=environment) restricted(ccode, environment, layer)
def run_controller_in(controller, function, environment): """ Runs the controller.function() (for the app specified by the current folder). It tries pre-compiled controller_function.pyc first before compiling it. """ # if compiled should run compiled! folder = environment['request'].folder path = pjoin(folder, 'compiled') badc = 'invalid controller (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function) if os.path.exists(path): filename = pjoin(path, 'controllers_%s_%s.pyc' % (controller, function)) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) restricted(read_pyc(filename), environment, layer=filename) elif function == '_TEST': # TESTING: adjust the path to include site packages from settings import global_settings from admin import abspath, add_path_first paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths] # TESTING END filename = pjoin(folder, 'controllers/%s.py' % controller) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) environment['__symbols__'] = environment.keys() code = read_file(filename) code += TEST_CODE restricted(code, environment, layer=filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) code = read_file(filename) exposed = regex_expose.findall(code) if not function in exposed: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function) if is_gae: layer = filename + ':' + function code = getcfs(layer, filename, lambda: compile2(code,layer)) restricted(code, environment, filename) response = environment['response'] vars=response._vars if response.postprocessing: vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars) if isinstance(vars,unicode): vars = vars.encode('utf8') elif hasattr(vars,'xml') and callable(vars.xml): vars = vars.xml() return vars
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() env = request.env env.web2py_path = global_settings.applications_parent env.web2py_version = web2py_version env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## fixup_missing_path_info(environ) (static_file, version, environ) = url_in(request, environ) response.status = env.web2py_status_code or response.status if static_file: if environ.get('QUERY_STRING', '').startswith('attachment'): response.headers['Content-Disposition'] \ = 'attachment' if version: response.headers['Cache-Control'] = 'max-age=315360000' response.headers[ 'Expires'] = 'Thu, 31 Dec 2037 23:59:59 GMT' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## app = request.application # must go after url_in! if not global_settings.local_hosts: local_hosts = set(['127.0.0.1', '::ffff:127.0.0.1', '::1']) if not global_settings.web2py_runtime_gae: try: fqdn = socket.getfqdn() local_hosts.add(socket.gethostname()) local_hosts.add(fqdn) local_hosts.update([ addrinfo[4][0] for addrinfo in getipaddrinfo(fqdn) ]) if env.server_name: local_hosts.add(env.server_name) local_hosts.update([ addrinfo[4][0] for addrinfo in getipaddrinfo(env.server_name) ]) except (socket.gaierror, TypeError): pass global_settings.local_hosts = list(local_hosts) else: local_hosts = global_settings.local_hosts client = get_client(env) x_req_with = str(env.http_x_requested_with).lower() request.update( client = client, folder = abspath('applications', app) + os.sep, ajax = x_req_with == 'xmlhttprequest', cid = env.http_web2py_component_element, is_local = env.remote_addr in local_hosts, is_https = env.wsgi_url_scheme in HTTPS_SCHEMES or \ request.env.http_x_forwarded_proto in HTTPS_SCHEMES \ or env.https == 'on') request.compute_uuid() # requires client request.url = environ['PATH_INFO'] # ################################################## # access the requested application # ################################################## if not exists(request.folder): if app == rwthread.routes.default_application \ and app != 'welcome': redirect(URL('welcome', 'default', 'index')) elif rwthread.routes.error_handler: _handler = rwthread.routes.error_handler redirect( URL(_handler['application'], _handler['controller'], _handler['function'], args=app)) else: raise HTTP(404, rwthread.routes.error_message % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ exists(pjoin(request.folder, 'DISABLED')): raise HTTP( 503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>" ) # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ, request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request, response, *a) # ################################################## # load cookies # ################################################## if env.http_cookie: try: request.cookies.load(env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## if not env.web2py_disable_session: session.connect(request, response) # ################################################## # run controller # ################################################## if global_settings.debugging and app != "admin": import gluon.debug # activate the debugger gluon.debug.dbg.do_debug(mainpyfile=request.folder) serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder, env=env) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) # elif response._custom_commit: # response._custom_commit() elif response.custom_commit: BaseAdapter.close_all_instances(response.custom_commit) else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_in_cookie_or_file(request, response) if request.cid: if response.flash: http_response.headers['web2py-component-flash'] = \ urllib2.quote(xmlescape(response.flash)\ .replace('\n','')) if response.js: http_response.headers['web2py-component-command'] = \ urllib2.quote(response.js.replace('\n','')) # ################################################## # store cookies in headers # ################################################## rcookies = response.cookies if session._forget and response.session_id_name in rcookies: del rcookies[response.session_id_name] elif session._secure: rcookies[response.session_id_name]['secure'] = True http_response.cookies2headers(rcookies) ticket = None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rwthread.routes.error_message_ticket % dict(ticket=ticket), web2py_error='ticket %s' % ticket)
def parse_get_post_vars(request, environ): # always parse variables in URL for GET, POST, PUT, DELETE, etc. in get_vars env = request.env dget = cgi.parse_qsl(env.query_string or '', keep_blank_values=1) for (key, value) in dget: if key in request.get_vars: if isinstance(request.get_vars[key], list): request.get_vars[key] += [value] else: request.get_vars[key] = [request.get_vars[key]] + [value] else: request.get_vars[key] = value request.vars[key] = request.get_vars[key] try: request.body = body = copystream_progress(request) except IOError: raise HTTP(400, "Bad Request - HTTP body is incomplete") #if content-type is application/json, we must read the body is_json = env.get('http_content_type', '')[:16] == 'application/json' if is_json: try: json_vars = sj.load(body) body.seek(0) except: # incoherent request bodies can still be parsed "ad-hoc" json_vars = {} pass # update vars and get_vars with what was posted as json request.get_vars.update(json_vars) request.vars.update(json_vars) # parse POST variables on POST, PUT, BOTH only in post_vars if (body and env.request_method in ('POST', 'PUT', 'DELETE', 'BOTH')): dpost = cgi.FieldStorage(fp=body, environ=environ, keep_blank_values=1) # The same detection used by FieldStorage to detect multipart POSTs is_multipart = dpost.type[:10] == 'multipart/' body.seek(0) def listify(a): return (not isinstance(a, list) and [a]) or a try: keys = sorted(dpost) except TypeError: keys = [] for key in keys: if key is None: continue # not sure why cgi.FieldStorage returns None key dpk = dpost[key] # if en element is not a file replace it with its value else leave it alone if isinstance(dpk, list): value = [] for _dpk in dpk: if not _dpk.filename: value.append(_dpk.value) else: value.append(_dpk) elif not dpk.filename: value = dpk.value else: value = dpk pvalue = listify(value) if key in request.vars: gvalue = listify(request.vars[key]) if ISLE25: value = pvalue + gvalue elif is_multipart: pvalue = pvalue[len(gvalue):] else: pvalue = pvalue[:-len(gvalue)] request.vars[key] = value if len(pvalue): request.post_vars[key] = (len(pvalue) > 1 and pvalue) or pvalue[0] if is_json: # update post_vars with what was posted as json request.post_vars.update(json_vars)
# ################################################## # on application error, rollback database # ################################################## try: if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') except: pass e = RestrictedError('Framework', '', '', locals()) ticket = e.log(request) or 'unrecoverable' http_response = \ HTTP(500, rwthread.routes.error_message_ticket % dict(ticket=ticket), web2py_error='ticket %s' % ticket) finally: if response and hasattr(response, 'session_file') \ and response.session_file: response.session_file.close() session._unlock(response) http_response, new_environ = try_rewrite_on_error(http_response, request, environ, ticket) if not http_response: return wsgibase(new_environ, responder) if global_settings.web2py_crontype == 'soft': newcron.softcron(global_settings.applications_parent).start() return http_response.to(responder, env=env)
__/ | |___/ _) (_ _) \ /\%/\ /\%/\ /\%/\ /\%/\ / (_ _) \\(0 0) (0 0) (0 0) (0 0)// (_ )_ -- \(oo) (oo) (oo) (oo)/-- _( )_ / / \_,__/ \__,__/ \_,__/ \ \ _( )_ / --;-- --;- --;-- --;-- \ _( *. ( )) () (( () ) .* '...(___)z z(__)z(__)z(__)z z(__)....' """ exploits = { 'ssh': SSH(), 'http': HTTP(), 'postgres': postgresql(), 'ldap': LDAP() } def read_lines(filename): with open(filename, 'r') as f: lines = f.read_lines() return lines def main(): import argparse parser = argparse.ArgumentParser(description="Automate Hydra attacks against a specified network range.") parser.add_argument("-i", "--host_ips", metavar="<i>", type=str, help="IP address range to search", dest='host_ips') parser.add_argument("-u", "--usernames", metavar="<u>", type=str,
raise HTTP(403, error_message, web2py_error='inaccessible file') else: raise HTTP(404, error_message, web2py_error='invalid file') else: fp.close() stat_file = os.stat(static_file) fsize = stat_file[stat.ST_SIZE] mtime = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stat_file[stat.ST_MTIME])) headers['Content-Type'] = contenttype(static_file) headers['Last-Modified'] = mtime headers['Pragma'] = 'cache' headers['Cache-Control'] = 'private' if request and request.env.http_if_modified_since == mtime: raise HTTP(304, **{'Content-Type': headers['Content-Type']}) elif request and request.env.http_range: start_items = regex_start_range.findall(request.env.http_range) if not start_items: start_items = [0] stop_items = regex_stop_range.findall(request.env.http_range) if not stop_items or int(stop_items[0]) > fsize - 1: stop_items = [fsize - 1] part = (int(start_items[0]), int(stop_items[0]), fsize) bytes = part[1] - part[0] + 1 try: stream = open(static_file, 'rb') except IOError, e: if e[0] in (errno.EISDIR, errno.EACCES): raise HTTP(403)
def regex_url_in(request, environ): "rewrite and parse incoming URL" # ################################################## # select application # rewrite URL if routes_in is defined # update request.env # ################################################## regex_select(env=environ, request=request) if thread.routes.routes_in: environ = regex_filter_in(environ) for (key, value) in environ.items(): request.env[key.lower().replace('.', '_')] = value path = request.env.path_info.replace('\\', '/') # ################################################## # serve if a static file # ################################################## match = regex_static.match(regex_space.sub('_', path)) if match and match.group('x'): static_file = os.path.join(request.env.applications_parent, 'applications', match.group('b'), 'static', match.group('x')) return (static_file, environ) # ################################################## # parse application, controller and function # ################################################## path = re.sub('%20', ' ', path) match = regex_url.match(path) if not match or match.group('c') == 'static': raise HTTP(400, thread.routes.error_message % 'invalid request', web2py_error='invalid path') request.application = \ regex_space.sub('_', match.group('a') or thread.routes.default_application) request.controller = \ regex_space.sub('_', match.group('c') or thread.routes.default_controller) request.function = \ regex_space.sub('_', match.group('f') or thread.routes.default_function) group_e = match.group('e') request.raw_extension = group_e and regex_space.sub('_', group_e) or None request.extension = request.raw_extension or 'html' request.raw_args = match.group('r') request.args = List([]) if request.application in thread.routes.routes_apps_raw: # application is responsible for parsing args request.args = None elif request.raw_args: match = regex_args.match(request.raw_args.replace(' ', '_')) if match: group_s = match.group('s') request.args = \ List((group_s and group_s.split('/')) or []) if request.args and request.args[-1] == '': request.args.pop() # adjust for trailing empty arg else: raise HTTP(400, thread.routes.error_message % 'invalid request', web2py_error='invalid path (args)') return (None, environ)